Merge branch 'dev' into unified-target

This commit is contained in:
Theodore Tsirpanis
2024-02-28 01:25:15 +02:00
78 changed files with 5036 additions and 2733 deletions
+1 -1
View File
@@ -2,8 +2,8 @@ task:
name: FreeBSD (shortest) name: FreeBSD (shortest)
freebsd_instance: freebsd_instance:
matrix: matrix:
image_family: freebsd-14-0
image_family: freebsd-13-2 image_family: freebsd-13-2
image_family: freebsd-12-4
install_script: pkg install -y gmake coreutils install_script: pkg install -y gmake coreutils
script: | script: |
MOREFLAGS="-Werror" gmake -j all MOREFLAGS="-Werror" gmake -j all
+2 -2
View File
@@ -247,7 +247,7 @@ jobs:
shell: msys2 {0} shell: msys2 {0}
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
- uses: msys2/setup-msys2@5beef6d11f48bba68b9eb503e3adc60b23c0cc36 # tag=v2 - uses: msys2/setup-msys2@cc11e9188b693c2b100158c3322424c4cc1dadea # tag=v2.22.0
with: with:
msystem: MINGW64 msystem: MINGW64
install: make install: make
@@ -290,7 +290,7 @@ jobs:
dry-run: false dry-run: false
sanitizer: ${{ matrix.sanitizer }} sanitizer: ${{ matrix.sanitizer }}
- name: Upload Crash - 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' if: failure() && steps.build.outcome == 'success'
with: with:
name: ${{ matrix.sanitizer }}-artifacts name: ${{ matrix.sanitizer }}-artifacts
+35 -35
View File
@@ -80,19 +80,16 @@ jobs:
make clean make clean
LDFLAGS=-Wl,--no-undefined make -C lib libzstd-mt 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 # LDFLAGS=-Wl,--no-undefined : will make the linker fail if dll is underlinked
cmake-build-and-test-check: cmake-build-and-test-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
- name: cmake build and test check - name: cmake build and test
run: | run: |
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild V=1
cp -r ./ "../zstd source"
cd "../zstd source"
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild
cpp-gnu90-c99-compatibility: cpp-gnu90-c99-compatibility:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -246,14 +243,12 @@ jobs:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
- name: Install packages - name: Install packages
run: pip install --pre meson run: pip install --pre meson
- name: Initialize the MSVC dev command prompt
uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89
- name: Configure with Meson - name: Configure with Meson
run: | 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 - name: Build with Meson
run: | run: |
ninja -C builddir/ meson compile -C builddir/
- name: Test with Meson - name: Test with Meson
run: | run: |
meson test -C builddir/ --print-errorlogs meson test -C builddir/ --print-errorlogs
@@ -276,7 +271,7 @@ jobs:
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
- name: Add MSBuild to PATH - name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # tag=v1.3 uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0
- name: Build - name: Build
working-directory: ${{env.GITHUB_WORKSPACE}} working-directory: ${{env.GITHUB_WORKSPACE}}
run: | run: |
@@ -303,7 +298,7 @@ jobs:
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
- name: Add MSBuild to PATH - 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}} - name: Build ${{matrix.name}}
working-directory: ${{env.GITHUB_WORKSPACE}} working-directory: ${{env.GITHUB_WORKSPACE}}
# See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference # 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: 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: 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: 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 env: # Set environment variables
XCC: ${{ matrix.xcc }} XCC: ${{ matrix.xcc }}
@@ -432,6 +428,10 @@ jobs:
if: ${{ matrix.name == 'M68K' }} if: ${{ matrix.name == 'M68K' }}
run: | run: |
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check 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: mingw-short-test:
runs-on: windows-latest runs-on: windows-latest
@@ -448,7 +448,7 @@ jobs:
shell: msys2 {0} shell: msys2 {0}
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
- uses: msys2/setup-msys2@5beef6d11f48bba68b9eb503e3adc60b23c0cc36 # tag=v2 - uses: msys2/setup-msys2@cc11e9188b693c2b100158c3322424c4cc1dadea # tag=v2.22.0
with: with:
msystem: ${{ matrix.msystem }} msystem: ${{ matrix.msystem }}
install: make diffutils install: make diffutils
@@ -485,7 +485,7 @@ jobs:
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
- name: Add MSBuild to PATH - 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 - name: Build and run tests
working-directory: ${{env.GITHUB_WORKSPACE}} working-directory: ${{env.GITHUB_WORKSPACE}}
env: env:
@@ -526,25 +526,6 @@ jobs:
make -C tests fuzzer && make -C tests fuzzer &&
./tests/fuzzer.exe -v -T1m ./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: pkg-config:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@@ -601,10 +582,29 @@ jobs:
make -C programs zstd-pgo make -C programs zstd-pgo
./programs/zstd -b ./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 # icc tests are currently failing on Github Actions, likely to issues during installation stage
# To be fixed later
# #
# icc: # icc:
# name: icc-check # name: icc-check
+2 -2
View File
@@ -51,7 +51,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab. # format to the repository Actions tab.
- name: "Upload artifact" - name: "Upload artifact"
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3.1.3 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
with: with:
name: SARIF file name: SARIF file
path: results.sarif path: results.sarif
@@ -59,6 +59,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard. # Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning" - 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: with:
sarif_file: results.sarif sarif_file: results.sarif
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
cd .. cd ..
- name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
with: with:
path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip
name: zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip name: zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip
+7 -2
View File
@@ -27,6 +27,8 @@ tmp*
dictionary. dictionary.
dictionary dictionary
NUL NUL
cmakebuild/
install/
# Build artefacts # Build artefacts
contrib/linux-kernel/linux/ contrib/linux-kernel/linux/
@@ -37,12 +39,15 @@ buck-out/
build-* build-*
*.gcda *.gcda
# IDE
.clang_complete
compile_flags.txt
.clang-format
# Other files # Other files
.directory .directory
_codelite/ _codelite/
_zstdbench/ _zstdbench/
.clang_complete
compile_flags.txt
*.idea *.idea
*.swp *.swp
.DS_Store .DS_Store
+21 -16
View File
@@ -145,7 +145,7 @@ clean:
$(Q)$(MAKE) -C contrib/largeNbDicts $@ > $(VOID) $(Q)$(MAKE) -C contrib/largeNbDicts $@ > $(VOID)
$(Q)$(MAKE) -C contrib/externalSequenceProducer $@ > $(VOID) $(Q)$(MAKE) -C contrib/externalSequenceProducer $@ > $(VOID)
$(Q)$(RM) zstd$(EXT) zstdmt$(EXT) tmp* $(Q)$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
$(Q)$(RM) -r lz4 $(Q)$(RM) -r lz4 cmakebuild install
@echo Cleaning completed @echo Cleaning completed
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@@ -328,8 +328,9 @@ asan-%: clean
msan: 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 $(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 msan-%:
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 $* $(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 asan32: clean
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address $(MOREFLAGS)" $(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address $(MOREFLAGS)"
@@ -389,28 +390,32 @@ lz4install:
endif 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))) ifneq (,$(filter MSYS%,$(shell uname)))
HOST_OS = MSYS 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 endif
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# target specific tests # target specific tests
#------------------------------------------------------------------------ #------------------------------------------------------------------------
ifneq (,$(filter $(HOST_OS),MSYS POSIX)) 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 c89build: clean
$(CC) -v $(CC) -v
CFLAGS="-std=c89 -Werror -Wno-attributes -Wpedantic -Wno-long-long -Wno-variadic-macros -O0" $(MAKE) lib zstd CFLAGS="-std=c89 -Werror -Wno-attributes -Wpedantic -Wno-long-long -Wno-variadic-macros -O0" $(MAKE) lib zstd
+4
View File
@@ -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. 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/`. 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 ## Testing
You can run quick local smoke tests by running `make check`. You can run quick local smoke tests by running `make check`.
+15
View File
@@ -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). -->
+4
View File
@@ -356,6 +356,10 @@
RelativePath="..\..\..\programs\dibio.c" RelativePath="..\..\..\programs\dibio.c"
> >
</File> </File>
<File
RelativePath="..\..\..\programs\lorem.c"
>
</File>
<File <File
RelativePath="..\..\..\lib\dictBuilder\cover.c" RelativePath="..\..\..\lib\dictBuilder\cover.c"
> >
+2
View File
@@ -157,6 +157,8 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\programs\util.c" /> <ClCompile Include="..\..\..\programs\util.c" />
<ClCompile Include="..\..\..\programs\datagen.c" /> <ClCompile Include="..\..\..\programs\datagen.c" />
<ClCompile Include="..\..\..\programs\lorem.c" />
<ClCompile Include="..\..\..\tests\loremOut.c" />
<ClCompile Include="..\..\..\tests\datagencli.c" /> <ClCompile Include="..\..\..\tests\datagencli.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+1
View File
@@ -63,6 +63,7 @@
<ClCompile Include="..\..\..\programs\dibio.c" /> <ClCompile Include="..\..\..\programs\dibio.c" />
<ClCompile Include="..\..\..\programs\fileio.c" /> <ClCompile Include="..\..\..\programs\fileio.c" />
<ClCompile Include="..\..\..\programs\fileio_asyncio.c" /> <ClCompile Include="..\..\..\programs\fileio_asyncio.c" />
<ClCompile Include="..\..\..\programs\lorem.c" />
<ClCompile Include="..\..\..\programs\zstdcli.c" /> <ClCompile Include="..\..\..\programs\zstdcli.c" />
<ClCompile Include="..\..\..\programs\zstdcli_trace.c" /> <ClCompile Include="..\..\..\programs\zstdcli_trace.c" />
</ItemGroup> </ItemGroup>
+10 -23
View File
@@ -7,16 +7,14 @@
# in the COPYING file in the root directory of this source tree). # 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. # 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 and use the newest cmake policies that are validated to work
set(ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION "3") set(ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION "3")
set(ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION "13") #Policies never changed at PATCH level set(ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION "13") #Policies never changed at PATCH level
if("${CMAKE_MAJOR_VERSION}" LESS 3) if("${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}") "${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}")
elseif( "${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}") set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
else() else()
set(ZSTD_CMAKE_POLICY_VERSION "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}.${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}.0") 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) include(GetZstdLibraryVersion)
GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH) GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH)
if( CMAKE_MAJOR_VERSION LESS 3 ) project(zstd
## Provide cmake 3+ behavior for older versions of cmake VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}"
project(zstd) LANGUAGES C # Main library is in C
set(PROJECT_VERSION_MAJOR ${zstd_VERSION_MAJOR}) ASM # And ASM
set(PROJECT_VERSION_MINOR ${zstd_VERSION_MINOR}) CXX # Testing contributed code also utilizes CXX
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()
message(STATUS "ZSTD VERSION: ${zstd_VERSION}") message(STATUS "ZSTD VERSION: ${zstd_VERSION}")
set(zstd_HOMEPAGE_URL "https://facebook.github.io/zstd") set(zstd_HOMEPAGE_URL "https://facebook.github.io/zstd")
set(zstd_DESCRIPTION "Zstandard is a real-time compression algorithm, providing high compression ratios.") set(zstd_DESCRIPTION "Zstandard is a real-time compression algorithm, providing high compression ratios.")
+1
View File
@@ -18,6 +18,7 @@ set(PZSTD_DIR ${ZSTD_SOURCE_DIR}/contrib/pzstd)
include_directories(${PROGRAMS_DIR} ${LIBRARY_DIR} ${LIBRARY_DIR}/common ${PZSTD_DIR}) 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) 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_DEFINITIONS "NDEBUG")
set_property(TARGET pzstd APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow") set_property(TARGET pzstd APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow")
+6 -2
View File
@@ -38,11 +38,15 @@ include_directories(${LIBRARY_DIR} ${LIBRARY_DIR}/common)
file(GLOB CommonSources ${LIBRARY_DIR}/common/*.c) file(GLOB CommonSources ${LIBRARY_DIR}/common/*.c)
file(GLOB CompressSources ${LIBRARY_DIR}/compress/*.c) file(GLOB CompressSources ${LIBRARY_DIR}/compress/*.c)
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c)
if (MSVC) if (MSVC)
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c)
add_compile_options(-DZSTD_DISABLE_ASM) add_compile_options(-DZSTD_DISABLE_ASM)
else () 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 () endif ()
file(GLOB DictBuilderSources ${LIBRARY_DIR}/dictBuilder/*.c) file(GLOB DictBuilderSources ${LIBRARY_DIR}/dictBuilder/*.c)
file(GLOB DeprecatedSources ${LIBRARY_DIR}/deprecated/*.c) file(GLOB DeprecatedSources ${LIBRARY_DIR}/deprecated/*.c)
+1 -6
View File
@@ -32,12 +32,7 @@ if (MSVC)
set(PlatformDependResources ${MSVC_RESOURCE_DIR}/zstd.rc) set(PlatformDependResources ${MSVC_RESOURCE_DIR}/zstd.rc)
endif () endif ()
set(ZSTD_PROGRAM_SRCS ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c file(GLOB ZSTD_PROGRAM_SRCS "${PROGRAMS_DIR}/*.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})
if (MSVC AND ZSTD_PROGRAMS_LINK_SHARED) if (MSVC AND ZSTD_PROGRAMS_LINK_SHARED)
list(APPEND ZSTD_PROGRAM_SRCS ${LIBRARY_DIR}/common/pool.c ${LIBRARY_DIR}/common/threading.c) list(APPEND ZSTD_PROGRAM_SRCS ${LIBRARY_DIR}/common/pool.c ${LIBRARY_DIR}/common/threading.c)
endif () endif ()
+3 -3
View File
@@ -50,13 +50,13 @@ set(PROGRAMS_DIR ${ZSTD_SOURCE_DIR}/programs)
set(TESTS_DIR ${ZSTD_SOURCE_DIR}/tests) set(TESTS_DIR ${ZSTD_SOURCE_DIR}/tests)
include_directories(${TESTS_DIR} ${PROGRAMS_DIR} ${LIBRARY_DIR} ${LIBRARY_DIR}/common ${LIBRARY_DIR}/compress ${LIBRARY_DIR}/dictBuilder) 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) target_link_libraries(datagen libzstd_static)
# #
# fullbench # 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) if (NOT MSVC)
target_compile_options(fullbench PRIVATE "-Wno-deprecated-declarations") target_compile_options(fullbench PRIVATE "-Wno-deprecated-declarations")
endif() endif()
@@ -110,7 +110,7 @@ endif()
# Label the "Medium" set of tests (see TESTING.md) # Label the "Medium" set of tests (see TESTING.md)
set_property(TEST fuzzer zstreamtest playTests APPEND PROPERTY LABELS Medium) 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) if (UNIX)
target_link_libraries(paramgrill libzstd_static m) #m is math library target_link_libraries(paramgrill libzstd_static m) #m is math library
else() else()
+1
View File
@@ -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/benchfn.c'),
join_paths(zstd_rootdir, 'programs/benchzstd.c'), join_paths(zstd_rootdir, 'programs/benchzstd.c'),
join_paths(zstd_rootdir, 'programs/datagen.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/dibio.c'),
join_paths(zstd_rootdir, 'programs/zstdcli_trace.c')] join_paths(zstd_rootdir, 'programs/zstdcli_trace.c')]
+3 -1
View File
@@ -29,6 +29,7 @@ DECODECORPUS_TESTTIME = '-T30'
test_includes = [ include_directories(join_paths(zstd_rootdir, 'programs')) ] test_includes = [ include_directories(join_paths(zstd_rootdir, 'programs')) ]
testcommon_sources = [join_paths(zstd_rootdir, 'programs/datagen.c'), 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/util.c'),
join_paths(zstd_rootdir, 'programs/timefn.c'), join_paths(zstd_rootdir, 'programs/timefn.c'),
join_paths(zstd_rootdir, 'programs/benchfn.c'), join_paths(zstd_rootdir, 'programs/benchfn.c'),
@@ -43,7 +44,8 @@ testcommon_dep = declare_dependency(link_with: testcommon,
dependencies: libzstd_deps, dependencies: libzstd_deps,
include_directories: libzstd_includes) 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 = executable('datagen',
datagen_sources, datagen_sources,
c_args: [ '-DNDEBUG' ], c_args: [ '-DNDEBUG' ],
@@ -77,7 +77,7 @@ EXPORT_SYMBOL(zstd_init_dstream);
size_t zstd_reset_dstream(zstd_dstream *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); EXPORT_SYMBOL(zstd_reset_dstream);
+1 -5
View File
@@ -115,11 +115,7 @@ static uint64_t ZSTD_div64(uint64_t dividend, uint32_t divisor) {
#ifndef ZSTD_DEPS_STDINT #ifndef ZSTD_DEPS_STDINT
#define ZSTD_DEPS_STDINT #define ZSTD_DEPS_STDINT
/* /* intptr_t already provided by ZSTD_DEPS_COMMON */
* The Linux Kernel doesn't provide intptr_t, only uintptr_t, which
* is an unsigned long.
*/
typedef long intptr_t;
#endif /* ZSTD_DEPS_STDINT */ #endif /* ZSTD_DEPS_STDINT */
#endif /* ZSTD_DEPS_NEED_STDINT */ #endif /* ZSTD_DEPS_NEED_STDINT */
+9 -1
View File
@@ -1124,6 +1124,9 @@ When last symbol reaches cumulated total of `1 << Accuracy_Log`,
decoding is complete. decoding is complete.
If the last symbol makes cumulated total go above `1 << Accuracy_Log`, If the last symbol makes cumulated total go above `1 << Accuracy_Log`,
distribution is considered corrupted. 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, Then the decoder can tell how many bytes were used in this process,
and how many symbols are present. 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. When a literal value is not present, it receives a `Weight` of 0.
The least frequent symbol receives a `Weight` of 1. 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 most frequent symbol receives a `Weight` anywhere between 1 and 11 (max).
The last symbol's `Weight` is deduced from previously retrieved Weights, The last symbol's `Weight` is deduced from previously retrieved Weights,
by completing to the nearest power of 2. It's necessarily non 0. 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, 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. 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 #### Conversion from weights to Huffman prefix codes
All present symbols shall now have a `Weight` value. All present symbols shall now have a `Weight` value.
+44 -23
View File
@@ -156,7 +156,7 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
* for example to size a static array on stack. * for example to size a static array on stack.
* Will produce constant value 0 if srcSize too large. * 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> #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> size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case single-pass scenario */<b>
</b>/* ZSTD_isError() :<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_forceIgnoreChecksum
* ZSTD_d_refMultipleDDicts * ZSTD_d_refMultipleDDicts
* ZSTD_d_disableHuffmanAssembly * ZSTD_d_disableHuffmanAssembly
* ZSTD_d_maxBlockSize
* Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
* note : never ever use experimentalParam? names directly * 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_experimentalParam2=1001,
ZSTD_d_experimentalParam3=1002, ZSTD_d_experimentalParam3=1002,
ZSTD_d_experimentalParam4=1003, ZSTD_d_experimentalParam4=1003,
ZSTD_d_experimentalParam5=1004 ZSTD_d_experimentalParam5=1004,
ZSTD_d_experimentalParam6=1005
} ZSTD_dParameter; } ZSTD_dParameter;
</b></pre><BR> </b></pre><BR>
@@ -1386,25 +1388,29 @@ ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize,
<a name="Chapter16"></a><h2>Memory management</h2><pre></pre> <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_usingCParams(ZSTD_compressionParameters cParams);
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void);
</b><p> These functions make it possible to estimate memory usage </b><p> These functions make it possible to estimate memory usage
of a future {D,C}Ctx, before its creation. 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 ZSTD_estimateCCtxSize() will provide a memory budget large enough
for any compression level up to selected one. to compress data of any size using one-shot compression ZSTD_compressCCtx() or ZSTD_compress2()
Note : Unlike ZSTD_estimateCStreamSize*(), this estimate associated with any compression level up to max specified one.
does not include space for a window buffer.
Therefore, the estimation is only guaranteed for single-shot compressions, not streaming.
The estimate will assume the input may be arbitrarily large, The estimate will assume the input may be arbitrarily large,
which is the worst case. 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, When srcSize can be bound by a known and rather "small" value,
this fact can be used to provide a tighter estimation this knowledge can be used to provide a tighter budget estimation
because the CCtx compression context will need less memory. because the ZSTD_CCtx* state will need less memory for small inputs.
This tighter estimation can be provided by more advanced functions This tighter estimation can be provided by employing more advanced functions
ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), 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(). 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. Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits.
@@ -1412,32 +1418,31 @@ ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void);
Note : only single-threaded compression is supported. Note : only single-threaded compression is supported.
ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. 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> </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_usingCParams(ZSTD_compressionParameters cParams);
ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); 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); 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. </b><p> ZSTD_estimateCStreamSize() will provide a memory budget large enough for streaming compression
It will also consider src size to be arbitrarily "large", which is worst case. 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. 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_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. 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. 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, This information can be passed manually, using ZSTD_estimateDStreamSize,
or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); 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(), Note : if streaming is init with function ZSTD_init?Stream_usingDict(),
an internal ?Dict will be created, which additional size is not estimated here. an internal ?Dict will be created, which additional size is not estimated here.
In this case, get total size by adding ZSTD_estimate?DictSize 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> </p></pre><BR>
@@ -1926,7 +1931,7 @@ ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
ZSTD_registerSequenceProducer( ZSTD_registerSequenceProducer(
ZSTD_CCtx* cctx, ZSTD_CCtx* cctx,
void* sequenceProducerState, void* sequenceProducerState,
ZSTD_sequenceProducer_F* sequenceProducer ZSTD_sequenceProducer_F sequenceProducer
); );
</b><p> Instruct zstd to use a block-level external sequence producer function. </b><p> Instruct zstd to use a block-level external sequence producer function.
@@ -1948,6 +1953,22 @@ ZSTD_registerSequenceProducer(
calling this function. calling this function.
</p></pre><BR> </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> <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. This API is deprecated, and will be removed in a future version.
It allows streaming (de)compression with user allocated buffers. It allows streaming (de)compression with user allocated buffers.
+4
View File
@@ -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 `ZSTDERRORLIB_VSIBILITY`, and `ZDICTLIB_VISIBILITY` if unset, for backwards compatibility
with the old macro names. 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 #### Windows : using MinGW+MSYS to create DLL
DLL can be created using MinGW+MSYS with the `make libzstd` command. DLL can be created using MinGW+MSYS with the `make libzstd` command.
+17 -16
View File
@@ -132,8 +132,8 @@
/* prefetch /* prefetch
* can be disabled, by declaring NO_PREFETCH build macro */ * can be disabled, by declaring NO_PREFETCH build macro */
#if defined(NO_PREFETCH) #if defined(NO_PREFETCH)
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ # define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ # define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
#else #else
# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && !defined(_M_ARM64EC) /* _mm_prefetch() is not defined outside of x86/x64 */ # 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 */ # 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_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
# elif defined(__aarch64__) # elif defined(__aarch64__)
# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) # define PREFETCH_L1(ptr) do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0)
# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) # define PREFETCH_L2(ptr) do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0)
# else # else
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ # define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ # define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
# endif # endif
#endif /* NO_PREFETCH */ #endif /* NO_PREFETCH */
#define CACHELINE_SIZE 64 #define CACHELINE_SIZE 64
#define PREFETCH_AREA(p, s) { \ #define PREFETCH_AREA(p, s) \
const char* const _ptr = (const char*)(p); \ do { \
size_t const _size = (size_t)(s); \ const char* const _ptr = (const char*)(p); \
size_t _pos; \ size_t const _size = (size_t)(s); \
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ size_t _pos; \
PREFETCH_L2(_ptr + _pos); \ for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
} \ PREFETCH_L2(_ptr + _pos); \
} } \
} while (0)
/* vectorization /* vectorization
* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
@@ -189,9 +190,9 @@
#endif #endif
#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) #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 #else
# define ZSTD_UNREACHABLE { assert(0); } # define ZSTD_UNREACHABLE do { assert(0); } while (0)
#endif #endif
/* disable warnings */ /* disable warnings */
+6
View File
@@ -21,4 +21,10 @@
#include "debug.h" #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; int g_debuglevel = DEBUGLEVEL;
#endif
+16 -11
View File
@@ -85,18 +85,23 @@ extern int g_debuglevel; /* the variable is only declared,
It's useful when enabling very verbose levels It's useful when enabling very verbose levels
on selective conditions (such as position in src) */ on selective conditions (such as position in src) */
# define RAWLOG(l, ...) { \ # define RAWLOG(l, ...) \
if (l<=g_debuglevel) { \ do { \
ZSTD_DEBUG_PRINT(__VA_ARGS__); \ if (l<=g_debuglevel) { \
} } ZSTD_DEBUG_PRINT(__VA_ARGS__); \
# define DEBUGLOG(l, ...) { \ } \
if (l<=g_debuglevel) { \ } while (0)
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
ZSTD_DEBUG_PRINT(" \n"); \ # define DEBUGLOG(l, ...) \
} } do { \
if (l<=g_debuglevel) { \
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
ZSTD_DEBUG_PRINT(" \n"); \
} \
} while (0)
#else #else
# define RAWLOG(l, ...) {} /* disabled */ # define RAWLOG(l, ...) do { } while (0) /* disabled */
# define DEBUGLOG(l, ...) {} /* disabled */ # define DEBUGLOG(l, ...) do { } while (0) /* disabled */
#endif #endif
+45 -36
View File
@@ -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); } 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 */ /* check and forward error code */
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e #define CHECK_V_F(e, f) \
#define CHECK_F(f) { CHECK_V_F(_var_err__, 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 want to force this function invocation to be syntactically correct, but
* we don't want to force runtime evaluation of its arguments. * we don't want to force runtime evaluation of its arguments.
*/ */
#define _FORCE_HAS_FORMAT_STRING(...) \ #define _FORCE_HAS_FORMAT_STRING(...) \
if (0) { \ do { \
_force_has_format_string(__VA_ARGS__); \ if (0) { \
} _force_has_format_string(__VA_ARGS__); \
} \
} while (0)
#define ERR_QUOTE(str) #str #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), * In order to do that (particularly, printing the conditional that failed),
* this can't just wrap RETURN_ERROR(). * this can't just wrap RETURN_ERROR().
*/ */
#define RETURN_ERROR_IF(cond, err, ...) \ #define RETURN_ERROR_IF(cond, err, ...) \
if (cond) { \ do { \
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ if (cond) { \
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
RAWLOG(3, ": " __VA_ARGS__); \ _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
RAWLOG(3, "\n"); \ RAWLOG(3, ": " __VA_ARGS__); \
return ERROR(err); \ RAWLOG(3, "\n"); \
} return ERROR(err); \
} \
} while (0)
/** /**
* Unconditionally return the specified error. * Unconditionally return the specified error.
* *
* In debug modes, prints additional information. * In debug modes, prints additional information.
*/ */
#define RETURN_ERROR(err, ...) \ #define RETURN_ERROR(err, ...) \
do { \ do { \
RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
__FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
RAWLOG(3, ": " __VA_ARGS__); \ RAWLOG(3, ": " __VA_ARGS__); \
RAWLOG(3, "\n"); \ RAWLOG(3, "\n"); \
return ERROR(err); \ return ERROR(err); \
} while(0); } while(0)
/** /**
* If the provided expression evaluates to an error code, returns that error code. * If the provided expression evaluates to an error code, returns that error code.
* *
* In debug modes, prints additional information. * In debug modes, prints additional information.
*/ */
#define FORWARD_IF_ERROR(err, ...) \ #define FORWARD_IF_ERROR(err, ...) \
do { \ do { \
size_t const err_code = (err); \ size_t const err_code = (err); \
if (ERR_isError(err_code)) { \ if (ERR_isError(err_code)) { \
RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
__FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
RAWLOG(3, ": " __VA_ARGS__); \ RAWLOG(3, ": " __VA_ARGS__); \
RAWLOG(3, "\n"); \ RAWLOG(3, "\n"); \
return err_code; \ return err_code; \
} \ } \
} while(0); } while(0)
#if defined (__cplusplus) #if defined (__cplusplus)
} }
+1 -1
View File
@@ -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); { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
if (!threadPool) return 1; if (!threadPool) return 1;
/* replace existing thread pool */ /* 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); ZSTD_customFree(ctx->threads, ctx->customMem);
ctx->threads = threadPool; ctx->threads = threadPool;
/* Initialize additional threads */ /* Initialize additional threads */
+5 -11
View File
@@ -1,24 +1,18 @@
/* /*
* xxHash - Fast Hash algorithm * xxHash - Extremely Fast Hash algorithm
* Copyright (c) Meta Platforms, Inc. and affiliates. * Copyright (c) Yann Collet - Meta Platforms, Inc
*
* You can contact the author at :
* - xxHash homepage: https://cyan4973.github.io/xxHash/
* - xxHash source repository : https://github.com/Cyan4973/xxHash
* *
* This source code is licensed under both the BSD-style license (found in the * 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 * 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). * in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
/* /*
* xxhash.c instantiates functions defined in xxhash.h * xxhash.c instantiates functions defined in xxhash.h
*/ */
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ #define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
#define XXH_IMPLEMENTATION /* access definitions */ #define XXH_IMPLEMENTATION /* access definitions */
#include "xxhash.h" #include "xxhash.h"
+2295 -990
View File
@@ -1,17 +1,15 @@
/* /*
* xxHash - Fast Hash algorithm * xxHash - Extremely Fast Hash algorithm
* Copyright (c) Meta Platforms, Inc. and affiliates. * Header File
* * Copyright (c) Yann Collet - Meta Platforms, Inc
* You can contact the author at :
* - xxHash homepage: https://cyan4973.github.io/xxHash/
* - xxHash source repository : https://github.com/Cyan4973/xxHash
* *
* This source code is licensed under both the BSD-style license (found in the * 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 * 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). * in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
/* Local adaptations for Zstandard */
#ifndef XXH_NO_XXH3 #ifndef XXH_NO_XXH3
# define XXH_NO_XXH3 # define XXH_NO_XXH3
@@ -24,46 +22,210 @@
/*! /*!
* @mainpage xxHash * @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 * @file xxhash.h
* xxHash prototypes and implementation * 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) #if defined (__cplusplus)
extern "C" { extern "C" {
@@ -73,21 +235,80 @@ extern "C" {
* INLINE mode * 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. * Use these build macros to inline xxhash into the target unit.
* Inlining improves performance on small inputs, especially when the length is * Inlining improves performance on small inputs, especially when the length is
* expressed as a compile-time constant: * 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. * It also keeps xxHash symbols private to the unit, so they are not exported.
* *
* Usage: * Usage:
* @code{.c}
* #define XXH_INLINE_ALL * #define XXH_INLINE_ALL
* #include "xxhash.h" * #include "xxhash.h"
* * @endcode
* Do not compile and link xxhash.o as a separate object, as it is not useful. * 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)) \ #if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \
&& !defined(XXH_INLINE_ALL_31684351384) && !defined(XXH_INLINE_ALL_31684351384)
/* this section should be traversed only once */ /* this section should be traversed only once */
@@ -202,21 +423,13 @@ extern "C" {
# undef XXHASH_H_STATIC_13879238742 # undef XXHASH_H_STATIC_13879238742
#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ #endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */
/* **************************************************************** /* ****************************************************************
* Stable API * Stable API
*****************************************************************/ *****************************************************************/
#ifndef XXHASH_H_5627135585666179 #ifndef XXHASH_H_5627135585666179
#define XXHASH_H_5627135585666179 1 #define XXHASH_H_5627135585666179 1
/*! @brief Marks a global symbol. */
/*!
* @defgroup public Public API
* Contains details on the public xxHash functions.
* @{
*/
/* specific declaration modes for Windows */
#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)
# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) # if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))
# ifdef XXH_EXPORT # ifdef XXH_EXPORT
@@ -229,24 +442,6 @@ extern "C" {
# endif # endif
#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 #ifdef XXH_NAMESPACE
# define XXH_CAT(A,B) A##B # define XXH_CAT(A,B) A##B
# define XXH_NAME2(A,B) XXH_CAT(A,B) # define XXH_NAME2(A,B) XXH_CAT(A,B)
@@ -306,12 +501,40 @@ extern "C" {
#endif #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 * Version
***************************************/ ***************************************/
#define XXH_VERSION_MAJOR 0 #define XXH_VERSION_MAJOR 0
#define XXH_VERSION_MINOR 8 #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) #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, * 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. * 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 * Common basic types
******************************/ ******************************/
#include <stddef.h> /* size_t */ #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> # include <limits.h>
# if UINT_MAX == 0xFFFFFFFFUL # if UINT_MAX == 0xFFFFFFFFUL
typedef unsigned int XXH32_hash_t; typedef unsigned int XXH32_hash_t;
# elif ULONG_MAX == 0xFFFFFFFFUL
typedef unsigned long XXH32_hash_t;
# else # else
# if ULONG_MAX == 0xFFFFFFFFUL # error "unsupported platform: need a 32-bit type"
typedef unsigned long XXH32_hash_t;
# else
# error "unsupported platform: need a 32-bit type"
# endif
# endif # endif
#endif #endif
/*! /*!
* @} * @}
* *
* @defgroup xxh32_family XXH32 family * @defgroup XXH32_family XXH32 family
* @ingroup public * @ingroup public
* Contains functions used in the classic 32-bit xxHash algorithm. * Contains functions used in the classic 32-bit xxHash algorithm.
* *
* @note * @note
* XXH32 is useful for older platforms, with no or poor 64-bit performance. * XXH32 is useful for older platforms, with no or poor 64-bit performance.
* Note that @ref xxh3_family provides competitive speed * Note that the @ref XXH3_family provides competitive speed for both 32-bit
* for both 32-bit and 64-bit systems, and offers true 64/128 bit hash results. * and 64-bit systems, and offers true 64/128 bit hash results.
* *
* @see @ref xxh64_family, @ref xxh3_family : Other xxHash families * @see @ref XXH64_family, @ref XXH3_family : Other xxHash families
* @see @ref xxh32_impl for implementation details * @see @ref XXH32_impl for implementation details
* @{ * @{
*/ */
/*! /*!
* @brief Calculates the 32-bit hash of @p input using xxHash32. * @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 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 length The length of @p input, in bytes.
* @param seed The 32-bit seed to alter the hash's output predictably. * @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 * readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*. * `NULL`. In C++, this also must be *TriviallyCopyable*.
* *
* @return The calculated 32-bit hash value. * @return The calculated 32-bit xxHash32 value.
* *
* @see * @see @ref single_shot_example "Single Shot Example" for an example.
* 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
*/ */
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 * @typedef struct XXH32_state_s XXH32_state_t
* @brief The opaque state struct for the XXH32 streaming API. * @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. * @brief Allocates an @ref XXH32_state_t.
* *
* Must be freed with XXH32_freeState(). * @return An allocated pointer of @ref XXH32_state_t on success.
* @return An allocated XXH32_state_t on success, `NULL` on failure. * @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. * @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(). * @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); 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. * @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 statePtr The state struct to reset.
* @param seed The 32-bit seed to alter the hash result predictably. * @param seed The 32-bit seed to alter the hash result predictably.
* *
* @pre * @pre
* @p statePtr must not be `NULL`. * @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); 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. * @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 statePtr The state struct to update.
* @param input The block of data to be hashed, at least @p length bytes in size. * @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 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 * readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*. * `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); 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. * @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. * @param statePtr The state struct to calculate the hash from.
* *
* @pre * @pre
* @p statePtr must not be `NULL`. * @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 *******/ /******* 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. * @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. * @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. * @param hash The @ref XXH32_hash_t to be converted.
* *
* @pre * @pre
* @p dst must not be `NULL`. * @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); 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`. * @p src must not be `NULL`.
* *
* @return The converted hash. * @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 #ifdef __has_attribute
# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) # define XXH_HAS_ATTRIBUTE(x) __has_attribute(x)
#else #else
# define XXH_HAS_ATTRIBUTE(x) 0 # define XXH_HAS_ATTRIBUTE(x) 0
#endif #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. */ /* 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) # define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
#else #else
# define XXH_HAS_C_ATTRIBUTE(x) 0 # define XXH_HAS_C_ATTRIBUTE(x) 0
#endif #endif
/*! @endcond */
/*! @cond Doxygen ignores this part */
#if defined(__cplusplus) && defined(__has_cpp_attribute) #if defined(__cplusplus) && defined(__has_cpp_attribute)
# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) # define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else #else
# define XXH_HAS_CPP_ATTRIBUTE(x) 0 # define XXH_HAS_CPP_ATTRIBUTE(x) 0
#endif #endif
/*! @endcond */
/*! @cond Doxygen ignores this part */
/* /*
Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute * Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute
introduced in CPP17 and C23. * introduced in CPP17 and C23.
CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough * CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough
C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough * C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough
*/ */
#if XXH_HAS_C_ATTRIBUTE(x) #if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough)
# define XXH_FALLTHROUGH [[fallthrough]]
#elif XXH_HAS_CPP_ATTRIBUTE(x)
# define XXH_FALLTHROUGH [[fallthrough]] # define XXH_FALLTHROUGH [[fallthrough]]
#elif XXH_HAS_ATTRIBUTE(__fallthrough__) #elif XXH_HAS_ATTRIBUTE(__fallthrough__)
# define XXH_FALLTHROUGH __attribute__ ((fallthrough)) # define XXH_FALLTHROUGH __attribute__ ((__fallthrough__))
#else #else
# define XXH_FALLTHROUGH # define XXH_FALLTHROUGH /* fallthrough */
#endif #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 * @ingroup public
* @{ * @{
* Contains functions used in the classic 64-bit xxHash algorithm. * 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. * It provides better speed for systems with vector processing capabilities.
*/ */
/*! /*!
* @brief Calculates the 64-bit hash of @p input using xxHash64. * @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 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 length The length of @p input, in bytes.
* @param seed The 64-bit seed to alter the hash's output predictably. * @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 * readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*. * `NULL`. In C++, this also must be *TriviallyCopyable*.
* *
* @return The calculated 64-bit hash. * @return The calculated 64-bit xxHash64 value.
* *
* @see * @see @ref single_shot_example "Single Shot Example" for an example.
* 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.
*/ */
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 *******/ /******* Streaming *******/
#ifndef XXH_NO_STREAM
/*! /*!
* @brief The opaque state struct for the XXH64 streaming API. * @brief The opaque state struct for the XXH64 streaming API.
* *
* @see XXH64_state_s for details. * @see XXH64_state_s for details.
*/ */
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ 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 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); * @brief Copies one @ref XXH64_state_t to another.
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); *
* @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 *******/ /******* Canonical representation *******/
/*!
* @brief Canonical (big endian) representation of @ref XXH64_hash_t.
*/
typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_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 #ifndef XXH_NO_XXH3
/*! /*!
* @} * @}
* ************************************************************************ * ************************************************************************
* @defgroup xxh3_family XXH3 family * @defgroup XXH3_family XXH3 family
* @ingroup public * @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, * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic,
* but does not require it. * but does not require it.
* Any 32-bit and 64-bit targets that can run XXH32 smoothly * Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3
* can run XXH3 at competitive speeds, even without vector support. * at competitive speeds, even without vector support. Further details are
* Further details are explained in the implementation. * explained in the implementation.
* *
* Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8, * XXH3 has a fast scalar implementation, but it also includes accelerated SIMD
* ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro. * 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: * XXH3 implementation is portable:
* it has a generic C90 formulation that can be compiled on any platform, * 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 * Starting from v0.8.0, it's also labelled "stable", meaning that
* any future version will also generate the same hash value. * 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. * The API supports one-shot hashing, streaming mode, and custom secrets.
*/ */
/*-********************************************************************** /*-**********************************************************************
* XXH3 64-bit variant * XXH3 64-bit variant
************************************************************************/ ************************************************************************/
/* XXH3_64bits(): /*!
* default 64-bit variant, using default secret and default seed of 0. * @brief Calculates 64-bit unseeded variant of XXH3 hash of @p input.
* It's the fastest variant. */ *
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); * @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.
/* *
* XXH3_64bits_withSeed(): * @pre
* This variant generates a custom secret on the fly * The memory between @p input and @p input + @p length must be valid,
* based on default secret altered using the `seed` value. * readable, contiguous memory. However, if @p length is `0`, @p input may be
* While this operation is decently fast, note that it's not completely free. * `NULL`. In C++, this also must be *TriviallyCopyable*.
* Note: seed==0 produces the same results as XXH3_64bits(). *
* @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. * 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 #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. * 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. * 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. * However, the quality of the secret impacts the dispersion of the hash algorithm.
* Therefore, the secret _must_ look like a bunch of random bytes. * Therefore, the secret _must_ look like a bunch of random bytes.
* Avoid "trivial" or structured data such as repeated sequences or a text document. * Avoid "trivial" or structured data such as repeated sequences or a text document.
* Whenever in doubt about the "randomness" of the blob of bytes, * 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. * It will generate a proper high entropy secret derived from the blob of bytes.
* Another advantage of using XXH3_generateSecret() is that * Another advantage of using XXH3_generateSecret() is that
* it guarantees that all bits within the initial blob of bytes * it guarantees that all bits within the initial blob of bytes
* will impact every bit of the output. * will impact every bit of the output.
* This is not necessarily the case when using the blob of bytes directly * 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. * 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 *******/ /******* Streaming *******/
#ifndef XXH_NO_STREAM
/* /*
* Streaming requires state maintenance. * Streaming requires state maintenance.
* This operation costs memory and CPU. * 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. * @see XXH3_state_s for details.
*/ */
typedef struct XXH3_state_s XXH3_state_t; 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 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(): * @brief Copies one @ref XXH3_state_t to another.
* Initialize with default parameters. *
* digest will be equivalent to `XXH3_64bits()`. * @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); XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state);
/*
* XXH3_64bits_reset_withSeed(): /*!
* Generate a custom secret from `seed`, and store it into `statePtr`. * @brief Resets an @ref XXH3_state_t to begin a new hash.
* digest will be equivalent to `XXH3_64bits_withSeed()`. *
* @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); XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr);
/*
* XXH3_64bits_reset_withSecret(): /*!
* `secret` is referenced, it _must outlive_ the hash streaming session. * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash.
* Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, *
* @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 * and the quality of produced hash values depends on secret's entropy
* (secret's content should look like a bunch of random bytes). * (secret's content should look like a bunch of random bytes).
* When in doubt about the randomness of a candidate `secret`, * When in doubt about the randomness of a candidate `secret`,
* consider employing `XXH3_generateSecret()` instead (see below). * 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 /* note : canonical representation of XXH3 is the same as XXH64
* since they both produce XXH64_hash_t values */ * since they both produce XXH64_hash_t values */
@@ -873,11 +1312,76 @@ typedef struct {
XXH64_hash_t high64; /*!< `value >> 64` */ XXH64_hash_t high64; /*!< `value >> 64` */
} XXH128_hash_t; } 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); * @brief Calculates 128-bit unseeded variant of XXH3 of @p data.
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); *
* @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 *******/ /******* Streaming *******/
#ifndef XXH_NO_STREAM
/* /*
* Streaming requires state maintenance. * Streaming requires state maintenance.
* This operation costs memory and CPU. * 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. * 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); * @brief Resets an @ref XXH3_state_t to begin a new hash.
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); *
* @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. /* 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. * 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 */ * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */
/*! /*!
* XXH128_isEqual(): * @brief Check equality of two XXH128_hash_t values
* Return: 1 if `h1` and `h2` are equal, 0 if they are not. *
* @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()`. * This comparator is compatible with stdlib's `qsort()`/`bsearch()`.
* *
* return: >0 if *h128_1 > *h128_2 * @param h128_1 Left-hand side value
* =0 if *h128_1 == *h128_2 * @param h128_2 Right-hand side value
* <0 if *h128_1 < *h128_2 *
* @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 *******/ /******* Canonical representation *******/
typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; 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 */ #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. */ XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */
}; /* typedef'd to XXH64_state_t */ }; /* typedef'd to XXH64_state_t */
#ifndef XXH_NO_XXH3 #ifndef XXH_NO_XXH3
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */
@@ -1032,6 +1659,7 @@ struct XXH64_state_s {
#define XXH3_INTERNALBUFFER_SIZE 256 #define XXH3_INTERNALBUFFER_SIZE 256
/*! /*!
* @internal
* @brief Default size of the secret buffer (and @ref XXH3_kSecret). * @brief Default size of the secret buffer (and @ref XXH3_kSecret).
* *
* This is the size used in @ref XXH3_kSecret and the seeded functions. * 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 { struct XXH3_state_s {
XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); 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]); XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]);
/*!< Used to store a custom secret generated from a seed. */ /*!< Used to store a custom secret generated from a seed. */
XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); 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, * Note that this doesn't prepare the state for a streaming operation,
* it's still necessary to use XXH3_NNbits_reset*() afterwards. * 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 === */ /* === Experimental API === */
/* Symbols defined below must be considered tied to a specific library version. */ /* 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 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, * The `_withSecret()` variants are useful to provide a higher level of protection
* as it becomes much more difficult for an external actor to guess how to impact the calculation logic. * 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, * 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 * and derives from it a high-entropy secret of length @p secretSize into an
* into an already allocated buffer @secretBuffer. * already allocated buffer @p secretBuffer.
* @secretSize must be >= XXH3_SECRET_SIZE_MIN
* *
* The generated secret can then be used with any `*_withSecret()` variant. * The generated secret can then be used with any `*_withSecret()` variant.
* Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`, * The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(),
* `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()` * @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret()
* are part of this list. They all accept a `secret` parameter * 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). * _and_ feature very high entropy (consist of random-looking bytes).
* These conditions can be a high bar to meet, so * These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can
* XXH3_generateSecret() can be employed to ensure proper quality. * be employed to ensure proper quality.
* *
* customSeed can be anything. It can have any size, even small ones, * @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. * and its content can be anything, even "poor entropy" sources such as a bunch
* The resulting `secret` will nonetheless provide all required qualities. * 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);
/*!
/* * @brief Generate the same secret as the _withSeed() variants.
* XXH3_generateSecret_fromSeed():
* *
* Generate the same secret as the _withSeed() variants. * @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 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.
* *
* The generated secret can be used in combination with * The generated secret can be used in combination with
*`*_withSecret()` and `_withSecretandSeed()` variants. *`*_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 * These variants generate hash values using either
* @seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) * @p seed for "short" keys (< @ref XXH3_MIDSIZE_MAX = 240 bytes)
* or @secret for "large" keys (>= XXH3_MIDSIZE_MAX). * or @p secret for "large" keys (>= @ref XXH3_MIDSIZE_MAX).
* *
* This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`.
* `_withSeed()` has to generate the secret on the fly for "large" keys. * `_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. * which requires more instructions than _withSeed() variants.
* Therefore, _withSecretandSeed variant combines the best of both worlds. * 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, * this variant produces *exactly* the same results as `_withSeed()` variant,
* hence offering only a pure speed benefit on "large" input, * hence offering only a pure speed benefit on "large" input,
* by skipping the need to regenerate the secret for every 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, * for example with XXH3_64bits(), which then becomes the seed,
* and then employ both the seed and the secret in _withSecretandSeed(). * 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 * 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, * has a 50% chance to swap each bit in the output, via its impact to the seed.
* via its impact to the seed. *
* This is not guaranteed when using the secret directly in "small data" scenarios, * This is not guaranteed when using the secret directly in "small data" scenarios,
* because only portions of the secret are employed for small data. * because only portions of the secret are employed for small data.
*/ */
XXH_PUBLIC_API XXH64_hash_t XXH_PUBLIC_API XXH_PUREF XXH64_hash_t
XXH3_64bits_withSecretandSeed(const void* data, size_t len, XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len,
const void* secret, size_t secretSize, XXH_NOESCAPE const void* secret, size_t secretSize,
XXH64_hash_t seed); XXH64_hash_t seed);
/*!
XXH_PUBLIC_API XXH128_hash_t * @brief Calculates 128-bit seeded variant of XXH3 hash of @p data.
XXH3_128bits_withSecretandSeed(const void* data, size_t len, *
const void* secret, size_t secretSize, * @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); 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 XXH_PUBLIC_API XXH_errorcode
XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,
const void* secret, size_t secretSize, XXH_NOESCAPE const void* secret, size_t secretSize,
XXH64_hash_t seed64); 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 XXH_PUBLIC_API XXH_errorcode
XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,
const void* secret, size_t secretSize, XXH_NOESCAPE const void* secret, size_t secretSize,
XXH64_hash_t seed64); XXH64_hash_t seed64);
#endif /* !XXH_NO_STREAM */
#endif /* !XXH_NO_XXH3 */
#endif /* XXH_NO_XXH3 */
#endif /* XXH_NO_LONG_LONG */ #endif /* XXH_NO_LONG_LONG */
#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
# define XXH_IMPLEMENTATION # define XXH_IMPLEMENTATION
@@ -1264,7 +2009,7 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
/*! /*!
* @brief Define this to disable 64-bit code. * @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 # define XXH_NO_LONG_LONG
# undef XXH_NO_LONG_LONG /* don't actually */ # 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 * Use `memcpy()`. Safe and portable. Note that most modern compilers will
* eliminate the function call and treat it as an unaligned access. * 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 * @par
* Depends on compiler extensions and is therefore not portable. * Depends on compiler extensions and is therefore not portable.
* This method is safe _if_ your compiler supports it, * 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 * inline small `memcpy()` calls, and it might also be faster on big-endian
* systems which lack a native byteswap instruction. However, some compilers * systems which lack a native byteswap instruction. However, some compilers
* will emit literal byteshifts even if the target supports unaligned access. * will emit literal byteshifts even if the target supports unaligned access.
* . *
* *
* @warning * @warning
* Methods 1 and 2 rely on implementation-defined behavior. Use these with * 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 # 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 * @def XXH_FORCE_ALIGN_CHECK
* @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() * @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. * In these cases, the alignment check can be removed by setting this macro to 0.
* Then the code will always use unaligned memory access. * 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. * 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). * This option does not affect XXH3 (only XXH32 and XXH64).
*/ */
# define XXH_FORCE_ALIGN_CHECK 0 # 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 * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the
* compiler full control on whether to inline or not. * compiler full control on whether to inline or not.
* *
* When not optimizing (-O0), optimizing for size (-Os, -Oz), or using * When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if
* -fno-inline with GCC or Clang, this will automatically be defined. * @ref XXH_SIZE_OPT >= 1, this will automatically be defined.
*/ */
# define XXH_NO_INLINE_HINTS 0 # 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 * @def XXH32_ENDJMP
* @brief Whether to use a jump for `XXH32_finalize`. * @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 # define XXH_OLD_NAMES
# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ # 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 */ #endif /* XXH_DOXYGEN */
/*! /*!
* @} * @}
*/ */
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ #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 */ /* prefer __packed__ structures (method 1) for GCC
# if !defined(__clang__) && \ * < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy
( \ * which for some reason does unaligned loads. */
(defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ # if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED))
( \
defined(__GNUC__) && ( \
(defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \
( \
defined(__mips__) && \
(__mips <= 5 || __mips_isa_rev < 6) && \
(!defined(__mips16) || defined(__mips_mips16e2)) \
) \
) \
) \
)
# define XXH_FORCE_MEMORY_ACCESS 1 # define XXH_FORCE_MEMORY_ACCESS 1
# endif # endif
#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 */ #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ /* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */
|| defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ # 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 # define XXH_FORCE_ALIGN_CHECK 0
# else # else
# define XXH_FORCE_ALIGN_CHECK 1 # define XXH_FORCE_ALIGN_CHECK 1
@@ -1426,14 +2229,22 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
#endif #endif
#ifndef XXH_NO_INLINE_HINTS #ifndef XXH_NO_INLINE_HINTS
# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ # if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__) /* -O0, -fno-inline */
|| defined(__NO_INLINE__) /* -O0, -fno-inline */
# define XXH_NO_INLINE_HINTS 1 # define XXH_NO_INLINE_HINTS 1
# else # else
# define XXH_NO_INLINE_HINTS 0 # define XXH_NO_INLINE_HINTS 0
# endif # endif
#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 #ifndef XXH32_ENDJMP
/* generally preferable for performance */ /* generally preferable for performance */
# define XXH32_ENDJMP 0 # define XXH32_ENDJMP 0
@@ -1448,13 +2259,56 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
/* ************************************* /* *************************************
* Includes & Memory related functions * Includes & Memory related functions
***************************************/ ***************************************/
/* Modify the local functions below should you wish to use some other memory routines */ #if defined(XXH_NO_STREAM)
/* for ZSTD_malloc(), ZSTD_free() */ /* nothing */
#define ZSTD_DEPS_NEED_MALLOC #elif defined(XXH_NO_STDLIB)
#include "zstd_deps.h" /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */
static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); } /* When requesting to disable any mention of stdlib,
static void XXH_free (void* p) { ZSTD_free(p); } * the library loses the ability to invoked malloc / free.
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); } * 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 # define XXH_NO_INLINE static
#endif #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 */ # include <assert.h> /* note: can still be disabled with NDEBUG */
# define XXH_ASSERT(c) assert(c) # define XXH_ASSERT(c) assert(c)
#else #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 #endif
/* note: use after variable declarations */ /* note: use after variable declarations */
#ifndef XXH_STATIC_ASSERT #ifndef XXH_STATIC_ASSERT
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ # 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 */ # elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */
# 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)
# else # 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. * @brief Used to prevent unwanted optimizations for @p var.
* *
* It uses an empty GCC inline assembly statement with a register constraint * 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. * on x86) and marks it as modified.
* *
* This is used in a few places to avoid unwanted autovectorization (e.g. * 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(). * XXH3_initCustomSecret_scalar().
*/ */
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
# define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r" (var)) # define XXH_COMPILER_GUARD(var) __asm__("" : "+r" (var))
#else #else
# define XXH_COMPILER_GUARD(var) ((void)0) # define XXH_COMPILER_GUARD(var) ((void)0)
#endif #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 * 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; typedef XXH32_hash_t xxh_u32;
#ifdef XXH_OLD_NAMES #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 BYTE xxh_u8
# define U8 xxh_u8 # define U8 xxh_u8
# define U32 xxh_u32 # 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)) #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* /*
* __pack instructions are safer but compiler specific, hence potentially * __attribute__((aligned(1))) is supported by gcc and clang. Originally the
* problematic for some compilers. * documentation claimed that it only increased the alignment, but actually it
* * can decrease it on gcc, clang, and icc:
* Currently only defined for GCC and ICC. * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,
* https://gcc.godbolt.org/z/xYez1j67Y.
*/ */
#ifdef XXH_OLD_NAMES #ifdef XXH_OLD_NAMES
typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; typedef union { xxh_u32 u32; } __attribute__((packed)) unalign;
#endif #endif
static xxh_u32 XXH_read32(const void* ptr) static xxh_u32 XXH_read32(const void* ptr)
{ {
typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; typedef __attribute__((aligned(1))) xxh_u32 xxh_unalign32;
return ((const xxh_unalign*)ptr)->u32; return *((const xxh_unalign32*)ptr);
} }
#else #else
@@ -1731,6 +2603,51 @@ static int XXH_isLittleEndian(void)
# define XXH_HAS_BUILTIN(x) 0 # define XXH_HAS_BUILTIN(x) 0
#endif #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 * @internal
* @def XXH_rotl32(x,r) * @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 * @ingroup impl
*
* Details on the XXH32 implementation.
* @{ * @{
*/ */
/* #define instead of static const, to be used as initializers */ /* #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 += input * XXH_PRIME32_2;
acc = XXH_rotl32(acc, 13); acc = XXH_rotl32(acc, 13);
acc *= XXH_PRIME32_1; 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: * UGLY HACK:
* A compiler fence is the only thing that prevents GCC and Clang from * 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 * can load data, while v3 can multiply. SSE forces them to operate
* together. * together.
* *
* This is also enabled on AArch64, as Clang autovectorizes it incorrectly * This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing
* and it is pointless writing a NEON implementation that is basically the * the loop. NEON is only faster on the A53, and with the newer cores, it is less
* same speed as scalar for XXH32. * 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); XXH_COMPILER_GUARD(acc);
#endif #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 final mix ensures that all input bits have a chance to impact any bit in
* the output digest, resulting in an unbiased distribution. * the output digest, resulting in an unbiased distribution.
* *
* @param h32 The hash to avalanche. * @param hash The hash to avalanche.
* @return The avalanched hash. * @return The avalanched hash.
*/ */
static xxh_u32 XXH32_avalanche(xxh_u32 h32) static xxh_u32 XXH32_avalanche(xxh_u32 hash)
{ {
h32 ^= h32 >> 15; hash ^= hash >> 15;
h32 *= XXH_PRIME32_2; hash *= XXH_PRIME32_2;
h32 ^= h32 >> 13; hash ^= hash >> 13;
h32 *= XXH_PRIME32_3; hash *= XXH_PRIME32_3;
h32 ^= h32 >> 16; hash ^= hash >> 16;
return(h32); return hash;
} }
#define XXH_get32bits(p) XXH_readLE32_align(p, align) #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 * This final stage will digest them to ensure that all input bytes are present
* in the final mix. * 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 ptr The pointer to the remaining input.
* @param len The remaining length, modulo 16. * @param len The remaining length, modulo 16.
* @param align Whether @p ptr is aligned. * @param align Whether @p ptr is aligned.
* @return The finalized hash. * @return The finalized hash.
* @see XXH64_finalize().
*/ */
static xxh_u32 static XXH_PUREF xxh_u32
XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) XXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align)
{ {
#define XXH_PROCESS1 do { \ #define XXH_PROCESS1 do { \
h32 += (*ptr++) * XXH_PRIME32_5; \ hash += (*ptr++) * XXH_PRIME32_5; \
h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \ hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; \
} while (0) } while (0)
#define XXH_PROCESS4 do { \ #define XXH_PROCESS4 do { \
h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \ hash += XXH_get32bits(ptr) * XXH_PRIME32_3; \
ptr += 4; \ ptr += 4; \
h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \ hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; \
} while (0) } while (0)
if (ptr==NULL) XXH_ASSERT(len == 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; XXH_PROCESS1;
--len; --len;
} }
return XXH32_avalanche(h32); return XXH32_avalanche(hash);
} else { } else {
switch(len&15) /* or switch(bEnd - p) */ { switch(len&15) /* or switch(bEnd - p) */ {
case 12: XXH_PROCESS4; case 12: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 8: XXH_PROCESS4; case 8: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 4: XXH_PROCESS4; case 4: XXH_PROCESS4;
return XXH32_avalanche(h32); return XXH32_avalanche(hash);
case 13: XXH_PROCESS4; case 13: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 9: XXH_PROCESS4; case 9: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 5: XXH_PROCESS4; case 5: XXH_PROCESS4;
XXH_PROCESS1; XXH_PROCESS1;
return XXH32_avalanche(h32); return XXH32_avalanche(hash);
case 14: XXH_PROCESS4; case 14: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 10: XXH_PROCESS4; case 10: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 6: XXH_PROCESS4; case 6: XXH_PROCESS4;
XXH_PROCESS1; XXH_PROCESS1;
XXH_PROCESS1; XXH_PROCESS1;
return XXH32_avalanche(h32); return XXH32_avalanche(hash);
case 15: XXH_PROCESS4; case 15: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 11: XXH_PROCESS4; case 11: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 7: XXH_PROCESS4; case 7: XXH_PROCESS4;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 3: XXH_PROCESS1; case 3: XXH_PROCESS1;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 2: XXH_PROCESS1; case 2: XXH_PROCESS1;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 1: XXH_PROCESS1; case 1: XXH_PROCESS1;
XXH_FALLTHROUGH; XXH_FALLTHROUGH; /* fallthrough */
case 0: return XXH32_avalanche(h32); case 0: return XXH32_avalanche(hash);
} }
XXH_ASSERT(0); 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. * @param align Whether @p input is aligned.
* @return The calculated hash. * @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) XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align)
{ {
xxh_u32 h32; 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); 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) 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 */ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH32_state_t state; XXH32_state_t state;
XXH32_reset(&state, seed); 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 *******/ /******* Hash streaming *******/
/*! #ifndef XXH_NO_STREAM
* @ingroup xxh32_family /*! @ingroup XXH32_family */
*/
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
{ {
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); 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_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
{ {
XXH_free(statePtr); XXH_free(statePtr);
return XXH_OK; 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_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
{ {
XXH_memcpy(dstState, srcState, sizeof(*dstState)); 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_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed)
{ {
XXH_ASSERT(statePtr != NULL); 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 XXH_PUBLIC_API XXH_errorcode
XXH32_update(XXH32_state_t* state, const void* input, size_t len) 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_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state)
{ {
xxh_u32 h32; 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); return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned);
} }
#endif /* !XXH_NO_STREAM */
/******* Canonical representation *******/ /******* Canonical representation *******/
/*! /*! @ingroup XXH32_family */
* @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.
*/
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) 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); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
XXH_memcpy(dst, &hash, sizeof(*dst)); 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) XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
{ {
return XXH_readBE32(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)) #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* /*
* __pack instructions are safer, but compiler specific, hence potentially * __attribute__((aligned(1))) is supported by gcc and clang. Originally the
* problematic for some compilers. * documentation claimed that it only increased the alignment, but actually it
* * can decrease it on gcc, clang, and icc:
* Currently only defined for GCC and ICC. * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,
* https://gcc.godbolt.org/z/xYez1j67Y.
*/ */
#ifdef XXH_OLD_NAMES #ifdef XXH_OLD_NAMES
typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64;
#endif #endif
static xxh_u64 XXH_read64(const void* ptr) static xxh_u64 XXH_read64(const void* ptr)
{ {
typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; typedef __attribute__((aligned(1))) xxh_u64 xxh_unalign64;
return ((const xxh_unalign64*)ptr)->u64; return *((const xxh_unalign64*)ptr);
} }
#else #else
@@ -2380,8 +3290,10 @@ XXH_readLE64_align(const void* ptr, XXH_alignment align)
/******* xxh64 *******/ /******* xxh64 *******/
/*! /*!
* @} * @}
* @defgroup xxh64_impl XXH64 implementation * @defgroup XXH64_impl XXH64 implementation
* @ingroup impl * @ingroup impl
*
* Details on the XXH64 implementation.
* @{ * @{
*/ */
/* #define rather that static const, to be used as initializers */ /* #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 # define PRIME64_5 XXH_PRIME64_5
#endif #endif
/*! @copydoc XXH32_round */
static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input)
{ {
acc += input * XXH_PRIME64_2; acc += input * XXH_PRIME64_2;
@@ -2415,43 +3328,59 @@ static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val)
return acc; return acc;
} }
static xxh_u64 XXH64_avalanche(xxh_u64 h64) /*! @copydoc XXH32_avalanche */
static xxh_u64 XXH64_avalanche(xxh_u64 hash)
{ {
h64 ^= h64 >> 33; hash ^= hash >> 33;
h64 *= XXH_PRIME64_2; hash *= XXH_PRIME64_2;
h64 ^= h64 >> 29; hash ^= hash >> 29;
h64 *= XXH_PRIME64_3; hash *= XXH_PRIME64_3;
h64 ^= h64 >> 32; hash ^= hash >> 32;
return h64; return hash;
} }
#define XXH_get64bits(p) XXH_readLE64_align(p, align) #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); if (ptr==NULL) XXH_ASSERT(len == 0);
len &= 31; len &= 31;
while (len >= 8) { while (len >= 8) {
xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr));
ptr += 8; ptr += 8;
h64 ^= k1; hash ^= k1;
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; hash = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
len -= 8; len -= 8;
} }
if (len >= 4) { if (len >= 4) {
h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1;
ptr += 4; 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; len -= 4;
} }
while (len > 0) { while (len > 0) {
h64 ^= (*ptr++) * XXH_PRIME64_5; hash ^= (*ptr++) * XXH_PRIME64_5;
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1;
--len; --len;
} }
return XXH64_avalanche(h64); return XXH64_avalanche(hash);
} }
#ifdef XXH_OLD_NAMES #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 # undef XXH_PROCESS8_64
#endif #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) XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align)
{ {
xxh_u64 h64; 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 */ /*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t len, XXH64_hash_t seed) 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 */ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH64_state_t state; XXH64_state_t state;
XXH64_reset(&state, seed); 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 *******/ /******* Hash Streaming *******/
#ifndef XXH_NO_STREAM
/*! @ingroup xxh64_family*/ /*! @ingroup XXH64_family*/
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
{ {
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); 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_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
{ {
XXH_free(statePtr); XXH_free(statePtr);
return XXH_OK; return XXH_OK;
} }
/*! @ingroup xxh64_family */ /*! @ingroup XXH64_family */
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState) XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState)
{ {
XXH_memcpy(dstState, srcState, sizeof(*dstState)); XXH_memcpy(dstState, srcState, sizeof(*dstState));
} }
/*! @ingroup xxh64_family */ /*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t seed) XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed)
{ {
XXH_ASSERT(statePtr != NULL); XXH_ASSERT(statePtr != NULL);
memset(statePtr, 0, sizeof(*statePtr)); 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; return XXH_OK;
} }
/*! @ingroup xxh64_family */ /*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH_errorcode 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) { if (input==NULL) {
XXH_ASSERT(len == 0); XXH_ASSERT(len == 0);
@@ -2605,8 +3542,8 @@ XXH64_update (XXH64_state_t* state, const void* input, size_t len)
} }
/*! @ingroup xxh64_family */ /*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state) XXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state)
{ {
xxh_u64 h64; 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); return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned);
} }
#endif /* !XXH_NO_STREAM */
/******* Canonical representation *******/ /******* Canonical representation *******/
/*! @ingroup xxh64_family */ /*! @ingroup XXH64_family */
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) 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); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
XXH_memcpy(dst, &hash, sizeof(*dst)); XXH_memcpy(dst, &hash, sizeof(*dst));
} }
/*! @ingroup xxh64_family */ /*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src)
{ {
return XXH_readBE64(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 * @ingroup impl
* @{ * @{
*/ */
@@ -2658,11 +3595,19 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
/* === Compiler specifics === */ /* === Compiler specifics === */
#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ #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 */ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */
# define XXH_RESTRICT restrict # 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 #else
/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */
# define XXH_RESTRICT /* disable */ # define XXH_RESTRICT /* disable */
#endif #endif
@@ -2676,10 +3621,26 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
# define XXH_unlikely(x) (x) # define XXH_unlikely(x) (x)
#endif #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(__GNUC__) || defined(__clang__)
# if defined(__ARM_FEATURE_SVE)
# include <arm_sve.h>
# endif
# if defined(__ARM_NEON__) || defined(__ARM_NEON) \ # if defined(__ARM_NEON__) || defined(__ARM_NEON) \
|| defined(__aarch64__) || defined(_M_ARM) \ || (defined(_M_ARM) && _M_ARM >= 7) \
|| defined(_M_ARM64) || defined(_M_ARM64EC) || 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 */ # define inline __inline__ /* circumvent a clang bug */
# include <arm_neon.h> # include <arm_neon.h>
# undef inline # 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. * Note that these are actually implemented as macros.
* *
* If this is not defined, it is detected automatically. * 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 */ { enum XXH_VECTOR_TYPE /* fake enum */ {
XXH_SCALAR = 0, /*!< Portable scalar version */ 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_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */
XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ 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_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */
XXH_SVE = 6, /*!< SVE for some ARMv8-A and ARMv9-A */
}; };
/*! /*!
* @ingroup tuning * @ingroup tuning
@@ -2825,12 +3791,16 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
# define XXH_AVX512 3 # define XXH_AVX512 3
# define XXH_NEON 4 # define XXH_NEON 4
# define XXH_VSX 5 # define XXH_VSX 5
# define XXH_SVE 6
#endif #endif
#ifndef XXH_VECTOR /* can be defined on command line */ #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(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \
|| defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ || 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(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \
@@ -2851,6 +3821,17 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
# endif # endif
#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, * Controls the alignment of the accumulator,
* for compatibility with aligned vector loads, which are usually faster. * 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 # define XXH_ACC_ALIGN 16
# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ # elif XXH_VECTOR == XXH_AVX512 /* avx512 */
# define XXH_ACC_ALIGN 64 # define XXH_ACC_ALIGN 64
# elif XXH_VECTOR == XXH_SVE /* sve */
# define XXH_ACC_ALIGN 64
# endif # endif
#endif #endif
#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ #if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \
|| XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512
# define XXH_SEC_ALIGN XXH_ACC_ALIGN # define XXH_SEC_ALIGN XXH_ACC_ALIGN
#elif XXH_VECTOR == XXH_SVE
# define XXH_SEC_ALIGN XXH_ACC_ALIGN
#else #else
# define XXH_SEC_ALIGN 8 # define XXH_SEC_ALIGN 8
#endif #endif
#if defined(__GNUC__) || defined(__clang__)
# define XXH_ALIASING __attribute__((may_alias))
#else
# define XXH_ALIASING /* nothing */
#endif
/* /*
* UGLY HACK: * UGLY HACK:
* GCC usually generates the best code with -O3 for xxHash. * 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 */ \ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
&& defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && 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 push_options
# pragma GCC optimize("-O2") # pragma GCC optimize("-O2")
#endif #endif
#if XXH_VECTOR == XXH_NEON #if XXH_VECTOR == XXH_NEON
/* /*
* NEON's setup for vmlal_u32 is a little more complicated than it is on * UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3
* SSE2, AVX2, and VSX. * optimizes out the entire hashLong loop because of the aliasing violation.
* *
* While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast. * However, GCC is also inefficient at load-store optimization with vld1q/vst1q,
* * so the only option is to mark it as aliasing.
* 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.
*/ */
typedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING;
/*! /*!
* Function-like macro: * @internal
* void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi) * @brief `vld1q_u64` but faster and alignment-safe.
* { *
* outLo = (uint32x2_t)(in & 0xFFFFFFFF); * On AArch64, unaligned access is always safe, but on ARMv7-a, it is only
* outHi = (uint32x2_t)(in >> 32); * *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86).
* in = UNDEFINED; *
* } * 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 */ \ #if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__)
&& (defined(__GNUC__) || defined(__clang__)) \ XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */
&& (defined(__arm__) || defined(__thumb__) || defined(_M_ARM)) {
# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ return *(xxh_aliasing_uint64x2_t const *)ptr;
do { \ }
/* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ #else
/* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr)
/* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ {
__asm__("vzip.32 %e0, %f0" : "+w" (in)); \ return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr));
(outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ }
(outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ #endif
} while (0)
# else /*!
# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ * @internal
do { \ * @brief `vmlal_u32` on low and high halves of a vector.
(outLo) = vmovn_u64 (in); \ *
(outHi) = vshrn_n_u64 ((in), 32); \ * This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with
} while (0) * inline assembly and were therefore incapable of merging the `vget_{low, high}_u32`
# endif * 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 * @ingroup tuning
* @brief Controls the NEON to scalar ratio for XXH3 * @brief Controls the NEON to scalar ratio for XXH3
* *
* On AArch64 when not optimizing for size, XXH3 will run 6 lanes using NEON and * This can be set to 2, 4, 6, or 8.
* 2 lanes on scalar by default.
* *
* This can be set to 2, 4, 6, or 8. ARMv7 will default to all 8 NEON lanes, as the * ARM Cortex CPUs are _very_ sensitive to how their pipelines are used.
* emulated 64-bit arithmetic is too slow.
* *
* 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 * This is even more noticeable on the more advanced cores like the Cortex-A76 which
* 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
* can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. * 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 * Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes
* remaining lanes will use scalar instructions. This improves the bandwidth * and 2 scalar lanes, which is chosen by default.
* and also gives the integer pipelines something to do besides twiddling loop *
* counters and pointers. * 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 * 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. | * | 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 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% | * | 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% | * | 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. * 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() * @see XXH3_accumulate_512_neon()
*/ */
# ifndef XXH3_NEON_LANES # ifndef XXH3_NEON_LANES
# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ # 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 # define XXH3_NEON_LANES 6
# else # else
# define XXH3_NEON_LANES XXH_ACC_NB # define XXH3_NEON_LANES XXH_ACC_NB
@@ -3066,27 +4030,42 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
* inconsistent intrinsics, spotty coverage, and multiple endiannesses. * inconsistent intrinsics, spotty coverage, and multiple endiannesses.
*/ */
#if XXH_VECTOR == XXH_VSX #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__) # if defined(__s390x__)
# include <s390intrin.h> # include <s390intrin.h>
# else # 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> # include <altivec.h>
# endif # 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 long long xxh_u64x2;
typedef __vector unsigned char xxh_u8x16; typedef __vector unsigned char xxh_u8x16;
typedef __vector unsigned xxh_u32x4; 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 # ifndef XXH_VSX_BE
# if defined(__BIG_ENDIAN__) \ # if defined(__BIG_ENDIAN__) \
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_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 */ /* s390x is always big endian, no issue on this platform */
# define XXH_vec_mulo vec_mulo # define XXH_vec_mulo vec_mulo
# define XXH_vec_mule vec_mule # 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. */ /* 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_mulo __builtin_altivec_vmulouw
# define XXH_vec_mule __builtin_altivec_vmuleuw # define XXH_vec_mule __builtin_altivec_vmuleuw
# else # 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_vec_mulo, XXH_vec_mule */
#endif /* XXH_VECTOR == XXH_VSX */ #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 /* prefetch
* can be disabled, by declaring XXH_NO_PREFETCH build macro */ * can be disabled, by declaring XXH_NO_PREFETCH build macro */
#if defined(XXH_NO_PREFETCH) #if defined(XXH_NO_PREFETCH)
# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */
#else #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 */ # 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) # define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # 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, 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 #ifdef XXH_OLD_NAMES
# define kSecret XXH3_kSecret # 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. */ /*! 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); XXH_ASSERT(0 <= shift && shift < 64);
return v64 ^ (v64 >> shift); 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) static XXH64_hash_t XXH3_avalanche(xxh_u64 h64)
{ {
h64 = XXH_xorshift64(h64, 37); h64 = XXH_xorshift64(h64, 37);
h64 *= 0x165667919E3779F9ULL; h64 *= PRIME_MX1;
h64 = XXH_xorshift64(h64, 32); h64 = XXH_xorshift64(h64, 32);
return h64; 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 */ /* this mix is inspired by Pelle Evensen's rrmxmx */
h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24);
h64 *= 0x9FB21C651E98DF25ULL; h64 *= PRIME_MX2;
h64 ^= (h64 >> 35) + len ; h64 ^= (h64 >> 35) + len ;
h64 *= 0x9FB21C651E98DF25ULL; h64 *= PRIME_MX2;
return XXH_xorshift64(h64, 28); 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. * 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) XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{ {
XXH_ASSERT(input != NULL); 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) XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{ {
XXH_ASSERT(input != NULL); 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) XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{ {
XXH_ASSERT(input != NULL); 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) XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{ {
XXH_ASSERT(len <= 16); 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. */ /* 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, XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize, const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed) 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_ASSERT(16 < len && len <= 128);
{ xxh_u64 acc = len * XXH_PRIME64_1; { 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 > 32) {
if (len > 64) { if (len > 64) {
if (len > 96) { 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+0, secret+0, seed);
acc += XXH3_mix16B(input+len-16, secret+16, seed); acc += XXH3_mix16B(input+len-16, secret+16, seed);
#endif
return XXH3_avalanche(acc); return XXH3_avalanche(acc);
} }
} }
/*!
* @brief Maximum size of "short" key in bytes.
*/
#define XXH3_MIDSIZE_MAX 240 #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, XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize, const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed) 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 #define XXH3_MIDSIZE_LASTOFFSET 17
{ xxh_u64 acc = len * XXH_PRIME64_1; { xxh_u64 acc = len * XXH_PRIME64_1;
int const nbRounds = (int)len / 16; xxh_u64 acc_end;
int i; 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++) { for (i=0; i<8; i++) {
acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); 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); XXH_ASSERT(nbRounds >= 8);
acc = XXH3_avalanche(acc);
#if defined(__clang__) /* Clang */ \ #if defined(__clang__) /* Clang */ \
&& (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \
&& !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ && !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) #pragma clang loop vectorize(disable)
#endif #endif
for (i=8 ; i < nbRounds; i++) { 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 */ return XXH3_avalanche(acc + acc_end);
acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
return XXH3_avalanche(acc);
} }
} }
@@ -3681,6 +4695,47 @@ XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
# define ACC_NB XXH_ACC_NB # define ACC_NB XXH_ACC_NB
#endif #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) XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64)
{ {
if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(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; */ /* data_key = data_vec ^ key_vec; */
__m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec);
/* data_key_lo = data_key >> 32; */ /* 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); */ /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
__m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo);
/* xacc[0] += swap(data_vec); */ /* xacc[0] += swap(data_vec); */
@@ -3759,6 +4814,7 @@ XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc,
*xacc = _mm512_add_epi64(product, sum); *xacc = _mm512_add_epi64(product, sum);
} }
} }
XXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512)
/* /*
* XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. * 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) */ /* xacc[0] ^= (xacc[0] >> 47) */
__m512i const acc_vec = *xacc; __m512i const acc_vec = *xacc;
__m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47);
__m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted);
/* xacc[0] ^= secret; */ /* xacc[0] ^= secret; */
__m512i const key_vec = _mm512_loadu_si512 (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; */ /* 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_lo = _mm512_mul_epu32 (data_key, prime32);
__m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32);
*xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); *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); XXH_ASSERT(((size_t)customSecret & 63) == 0);
(void)(&XXH_writeLE64); (void)(&XXH_writeLE64);
{ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); { 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); const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret);
__m512i* const dest = ( __m512i*) customSecret; __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)src & 63) == 0); /* control alignment */
XXH_ASSERT(((size_t)dest & 63) == 0); XXH_ASSERT(((size_t)dest & 63) == 0);
for (i=0; i < nbRounds; ++i) { for (i=0; i < nbRounds; ++i) {
/* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed);
* 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);
} } } }
} }
@@ -3864,7 +4913,7 @@ XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc,
/* data_key = data_vec ^ key_vec; */ /* data_key = data_vec ^ key_vec; */
__m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec);
/* data_key_lo = data_key >> 32; */ /* 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); */ /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
__m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo);
/* xacc[i] += swap(data_vec); */ /* xacc[i] += swap(data_vec); */
@@ -3874,6 +4923,7 @@ XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc,
xacc[i] = _mm256_add_epi64(product, sum); xacc[i] = _mm256_add_epi64(product, sum);
} } } }
} }
XXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2)
XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH_FORCE_INLINE XXH_TARGET_AVX2 void
XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) 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); __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec);
/* xacc[i] *= XXH_PRIME32_1; */ /* 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_lo = _mm256_mul_epu32 (data_key, prime32);
__m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, 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)); 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); XXH_ASSERT(((size_t)dest & 31) == 0);
/* GCC -O2 need unroll loop manually */ /* GCC -O2 need unroll loop manually */
dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed);
dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed);
dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed);
dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed);
dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed);
dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), 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); xacc[i] = _mm_add_epi64(product, sum);
} } } }
} }
XXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2)
XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH_FORCE_INLINE XXH_TARGET_SSE2 void
XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
@@ -4058,14 +5109,28 @@ XXH3_scalarScrambleRound(void* XXH_RESTRICT acc,
/*! /*!
* @internal * @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 * 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 * is to optimize the pipelining and can have up to 15% speedup depending on the
* CPU, and it also mitigates some GCC codegen issues. * CPU, and it also mitigates some GCC codegen issues.
* *
* @see XXH3_NEON_LANES for configuring this and details about this optimization. * @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 XXH_FORCE_INLINE void
XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, XXH3_accumulate_512_neon( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input, 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_ASSERT((((size_t)acc) & 15) == 0);
XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0);
{ { /* GCC for darwin arm64 does not like aliasing here */
uint64x2_t* const xacc = (uint64x2_t *) acc; 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. */ /* 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* xinput = (const uint8_t *) input;
uint8_t const* const xsecret = (const uint8_t *) secret; uint8_t const* xsecret = (const uint8_t *) secret;
size_t i; size_t i;
/* NEON for the first few lanes (these loops are normally interleaved) */ #ifdef __wasm_simd128__
for (i=0; i < XXH3_NEON_LANES / 2; i++) { /*
/* data_vec = xinput[i]; */ * On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret
uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); * is constant propagated, which results in it converting it to this
/* key_vec = xsecret[i]; */ * inside the loop:
uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); *
uint64x2_t data_key; * a = v128.load(XXH3_kSecret + 0 + $secret_offset, offset = 0)
uint32x2_t data_key_lo, data_key_hi; * b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0)
/* xacc[i] += swap(data_vec); */ * ...
uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); *
uint64x2_t const swapped = vextq_u64(data64, data64, 1); * This requires a full 32-bit address immediate (and therefore a 6 byte
xacc[i] = vaddq_u64 (xacc[i], swapped); * instruction) as well as an add for each offset.
/* data_key = data_vec ^ key_vec; */ *
data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); * Putting an asm guard prevents it from folding (at the cost of losing
/* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); * the alignment hint), and uses the free offset in `v128.load` instead
* data_key_hi = (uint32x2_t) (data_key >> 32); * of adding secret_offset each time which overall reduces code size by
* data_key = UNDEFINED; */ * about a kilobyte and improves performance.
XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); */
/* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ XXH_COMPILER_GUARD(xsecret);
xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); #endif
/* Scalar lanes use the normal scalarRound routine */
}
/* Scalar for the remainder. This may be a zero iteration loop. */
for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {
XXH3_scalarRound(acc, input, secret, 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 XXH_FORCE_INLINE void
XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{ {
XXH_ASSERT((((size_t)acc) & 15) == 0); 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; uint8_t const* xsecret = (uint8_t const*) secret;
uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1);
size_t i; size_t i;
/* NEON for the first few lanes (these loops are normally interleaved) */ /* WASM uses operator overloads and doesn't need these. */
for (i=0; i < XXH3_NEON_LANES / 2; i++) { #ifndef __wasm_simd128__
/* xacc[i] ^= (xacc[i] >> 47); */ /* { prime32_1, prime32_1 } */
uint64x2_t acc_vec = xacc[i]; uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1);
uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); /* { 0, prime32_1, 0, prime32_1 } */
uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32));
#endif
/* xacc[i] ^= xsecret[i]; */ /* AArch64 uses both scalar and neon at the same time */
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. */
for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {
XXH3_scalarScrambleRound(acc, secret, 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 #endif
#if (XXH_VECTOR == XXH_VSX) #if (XXH_VECTOR == XXH_VSX)
@@ -4178,23 +5324,23 @@ XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT secret) const void* XXH_RESTRICT secret)
{ {
/* presumed aligned */ /* presumed aligned */
unsigned int* const xacc = (unsigned int*) acc; xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;
xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ xxh_u8 const* const xinput = (xxh_u8 const*) input; /* no alignment restriction */
xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ xxh_u8 const* const xsecret = (xxh_u8 const*) secret; /* no alignment restriction */
xxh_u64x2 const v32 = { 32, 32 }; xxh_u64x2 const v32 = { 32, 32 };
size_t i; size_t i;
for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
/* data_vec = xinput[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]; */ /* 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; xxh_u64x2 const data_key = data_vec ^ key_vec;
/* shuffled = (data_key << 32) | (data_key >> 32); */ /* shuffled = (data_key << 32) | (data_key >> 32); */
xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32);
/* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */
xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled);
/* acc_vec = xacc[i]; */ /* 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; acc_vec += product;
/* swap high and low halves */ /* swap high and low halves */
@@ -4203,18 +5349,18 @@ XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc,
#else #else
acc_vec += vec_xxpermdi(data_vec, data_vec, 2); acc_vec += vec_xxpermdi(data_vec, data_vec, 2);
#endif #endif
/* xacc[i] = acc_vec; */ xacc[i] = acc_vec;
vec_xst((xxh_u32x4)acc_vec, 0, xacc + 4 * i);
} }
} }
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx)
XXH_FORCE_INLINE void XXH_FORCE_INLINE void
XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{ {
XXH_ASSERT((((size_t)acc) & 15) == 0); XXH_ASSERT((((size_t)acc) & 15) == 0);
{ xxh_u64x2* const xacc = (xxh_u64x2*) acc; { xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;
const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; const xxh_u8* const xsecret = (const xxh_u8*) secret;
/* constants */ /* constants */
xxh_u64x2 const v32 = { 32, 32 }; xxh_u64x2 const v32 = { 32, 32 };
xxh_u64x2 const v47 = { 47, 47 }; 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); xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47);
/* xacc[i] ^= xsecret[i]; */ /* 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; xxh_u64x2 const data_key = data_vec ^ key_vec;
/* xacc[i] *= XXH_PRIME32_1 */ /* xacc[i] *= XXH_PRIME32_1 */
@@ -4240,8 +5386,148 @@ XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
#endif #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 */ /* 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 * @internal
* @brief Scalar round for @ref XXH3_accumulate_512_scalar(). * @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_val = XXH_readLE64(xinput + lane * 8);
xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8);
xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ 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) const void* XXH_RESTRICT secret)
{ {
size_t i; 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++) { for (i=0; i < XXH_ACC_NB; i++) {
XXH3_scalarRound(acc, input, secret, i); XXH3_scalarRound(acc, input, secret, i);
} }
} }
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar)
/*! /*!
* @internal * @internal
@@ -4333,10 +5627,10 @@ XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
const xxh_u8* kSecretPtr = XXH3_kSecret; const xxh_u8* kSecretPtr = XXH3_kSecret;
XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
#if defined(__clang__) && defined(__aarch64__) #if defined(__GNUC__) && defined(__aarch64__)
/* /*
* UGLY HACK: * 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. * placed sequentially, in order, at the top of the unrolled loop.
* *
* While MOVK is great for generating constants (2 cycles for a 64-bit * 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 * ADD
* SUB STR * SUB STR
* 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 * that XXH3_kSecretPtr has been changed), the pipelines are used more
* efficiently: * efficiently:
* I L S * I L S
@@ -4368,17 +5662,11 @@ XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
*/ */
XXH_COMPILER_GUARD(kSecretPtr); XXH_COMPILER_GUARD(kSecretPtr);
#endif #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 const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16;
int i; int i;
for (i=0; i < nbRounds; 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 * customSecret, and on aarch64, this prevented LDP from merging two
* loads together for free. Putting the loads together before the stores * loads together for free. Putting the loads together before the stores
* properly generates LDP. * 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_scrambleAcc)(void* XXH_RESTRICT, const void*);
typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); 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) #if (XXH_VECTOR == XXH_AVX512)
#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 #define XXH3_accumulate_512 XXH3_accumulate_512_avx512
#define XXH3_accumulate XXH3_accumulate_avx512
#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx512
#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx512
#elif (XXH_VECTOR == XXH_AVX2) #elif (XXH_VECTOR == XXH_AVX2)
#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 #define XXH3_accumulate_512 XXH3_accumulate_512_avx2
#define XXH3_accumulate XXH3_accumulate_avx2
#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx2
#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx2
#elif (XXH_VECTOR == XXH_SSE2) #elif (XXH_VECTOR == XXH_SSE2)
#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 #define XXH3_accumulate_512 XXH3_accumulate_512_sse2
#define XXH3_accumulate XXH3_accumulate_sse2
#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 #define XXH3_scrambleAcc XXH3_scrambleAcc_sse2
#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 #define XXH3_initCustomSecret XXH3_initCustomSecret_sse2
#elif (XXH_VECTOR == XXH_NEON) #elif (XXH_VECTOR == XXH_NEON)
#define XXH3_accumulate_512 XXH3_accumulate_512_neon #define XXH3_accumulate_512 XXH3_accumulate_512_neon
#define XXH3_accumulate XXH3_accumulate_neon
#define XXH3_scrambleAcc XXH3_scrambleAcc_neon #define XXH3_scrambleAcc XXH3_scrambleAcc_neon
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#elif (XXH_VECTOR == XXH_VSX) #elif (XXH_VECTOR == XXH_VSX)
#define XXH3_accumulate_512 XXH3_accumulate_512_vsx #define XXH3_accumulate_512 XXH3_accumulate_512_vsx
#define XXH3_accumulate XXH3_accumulate_vsx
#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx #define XXH3_scrambleAcc XXH3_scrambleAcc_vsx
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #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 */ #else /* scalar */
#define XXH3_accumulate_512 XXH3_accumulate_512_scalar #define XXH3_accumulate_512 XXH3_accumulate_512_scalar
#define XXH3_accumulate XXH3_accumulate_scalar
#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#endif #endif
#if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */
# undef XXH3_initCustomSecret
#ifndef XXH_PREFETCH_DIST # define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
# ifdef __clang__ #endif
# 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);
}
}
XXH_FORCE_INLINE void XXH_FORCE_INLINE void
XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc,
const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize, 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) XXH3_f_scrambleAcc f_scramble)
{ {
size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; 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); XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
for (n = 0; n < nb_blocks; n++) { 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); 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); XXH_ASSERT(len > XXH_STRIPE_LEN);
{ size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN;
XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); 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 */ /* last stripe */
{ const xxh_u8* const p = input + len - XXH_STRIPE_LEN; { 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 */ #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 XXH_FORCE_INLINE XXH64_hash_t
XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len,
const void* XXH_RESTRICT secret, size_t secretSize, const void* XXH_RESTRICT secret, size_t secretSize,
XXH3_f_accumulate_512 f_acc512, XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble) XXH3_f_scrambleAcc f_scramble)
{ {
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; 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 */ /* converge into final hash */
XXH_STATIC_ASSERT(sizeof(acc) == 64); 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) * It's important for performance to transmit secret's size (when it's static)
* so that the compiler can properly optimize the vectorized loop. * 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. * 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, 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) XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
{ {
(void)seed64; (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, * 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. * 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, 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) XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
{ {
(void)seed64; (void)secret; (void)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 XXH_FORCE_INLINE XXH64_hash_t
XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len,
XXH64_hash_t seed, XXH64_hash_t seed,
XXH3_f_accumulate_512 f_acc512, XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble, XXH3_f_scrambleAcc f_scramble,
XXH3_f_initCustomSecret f_initSec) XXH3_f_initCustomSecret f_initSec)
{ {
#if XXH_SIZE_OPT <= 0
if (seed == 0) if (seed == 0)
return XXH3_hashLong_64b_internal(input, len, return XXH3_hashLong_64b_internal(input, len,
XXH3_kSecret, sizeof(XXH3_kSecret), 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]; { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
f_initSec(secret, seed); f_initSec(secret, seed);
return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), 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. * It's important for performance that XXH3_hashLong is not inlined.
*/ */
XXH_NO_INLINE XXH64_hash_t XXH_NO_INLINE XXH64_hash_t
XXH3_hashLong_64b_withSeed(const void* input, size_t len, XXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen) XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
{ {
(void)secret; (void)secretLen; (void)secret; (void)secretLen;
return XXH3_hashLong_64b_withSeed_internal(input, len, seed, 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 === */ /* === Public entry point === */
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) 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 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 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 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) if (length <= XXH3_MIDSIZE_MAX)
return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);
return XXH3_hashLong_64b_withSecret(input, len, seed, (const xxh_u8*)secret, secretSize); return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize);
} }
/* === XXH3 streaming === */ /* === XXH3 streaming === */
#ifndef XXH_NO_STREAM
/* /*
* Malloc's a pointer that is always aligned to align. * 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. * 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 <= 128 && align >= 8); /* range check */
XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */
@@ -4752,7 +6025,15 @@ static void XXH_alignedFree(void* p)
XXH_free(base); 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) XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void)
{ {
XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); 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; 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_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr)
{ {
XXH_alignedFree(statePtr); XXH_alignedFree(statePtr);
return XXH_OK; return XXH_OK;
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API void 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)); 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; statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE;
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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; if (statePtr == NULL) return XXH_ERROR;
XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
return XXH_OK; return XXH_OK;
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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; if (statePtr == NULL) return XXH_ERROR;
XXH3_reset_internal(statePtr, 0, secret, secretSize); 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; return XXH_OK;
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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 (statePtr == NULL) return XXH_ERROR;
if (seed==0) return XXH3_64bits_reset(statePtr); 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; return XXH_OK;
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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 (statePtr == NULL) return XXH_ERROR;
if (secret == 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; 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 * @internal
* so that the function can blindly consume all stripes using the "normal" secret segment */ * @brief Processes a large input for XXH3_update() and XXH3_digest_long().
XXH_FORCE_INLINE void *
* 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, XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,
size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock,
const xxh_u8* XXH_RESTRICT input, size_t nbStripes, const xxh_u8* XXH_RESTRICT input, size_t nbStripes,
const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, 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) XXH3_f_scrambleAcc f_scramble)
{ {
XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE;
XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); /* Process full blocks */
if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) {
/* need a scrambling operation */ /* Process the initial partial block... */
size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr;
size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock;
XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); do {
f_scramble(acc, secret + secretLimit); /* Accumulate and scramble */
XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); f_acc(acc, input, initialSecret, nbStripesThisIter);
*nbStripesSoFarPtr = nbStripesAfterBlock; f_scramble(acc, secret + secretLimit);
} else { input += nbStripesThisIter * XXH_STRIPE_LEN;
XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); 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; *nbStripesSoFarPtr += nbStripes;
} }
/* Return end pointer */
return input;
} }
#ifndef XXH3_STREAM_USE_STACK #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 # define XXH3_STREAM_USE_STACK 1
# endif # endif
#endif #endif
@@ -4884,7 +6200,7 @@ XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,
XXH_FORCE_INLINE XXH_errorcode XXH_FORCE_INLINE XXH_errorcode
XXH3_update(XXH3_state_t* XXH_RESTRICT const state, XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
const xxh_u8* XXH_RESTRICT input, size_t len, 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) XXH3_f_scrambleAcc f_scramble)
{ {
if (input==NULL) { if (input==NULL) {
@@ -4900,7 +6216,8 @@ XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
* when operating accumulators directly into state. * when operating accumulators directly into state.
* Operating into stack space seems to enable proper optimization. * Operating into stack space seems to enable proper optimization.
* clang, on the other hand, doesn't seem to need this trick */ * 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 #else
xxh_u64* XXH_RESTRICT const acc = state->acc; xxh_u64* XXH_RESTRICT const acc = state->acc;
#endif #endif
@@ -4908,7 +6225,7 @@ XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE);
/* small input : just fill in tmp buffer */ /* 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); XXH_memcpy(state->buffer + state->bufferedSize, input, len);
state->bufferedSize += (XXH32_hash_t)len; state->bufferedSize += (XXH32_hash_t)len;
return XXH_OK; return XXH_OK;
@@ -4930,57 +6247,20 @@ XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
&state->nbStripesSoFar, state->nbStripesPerBlock, &state->nbStripesSoFar, state->nbStripesPerBlock,
state->buffer, XXH3_INTERNALBUFFER_STRIPES, state->buffer, XXH3_INTERNALBUFFER_STRIPES,
secret, state->secretLimit, secret, state->secretLimit,
f_acc512, f_scramble); f_acc, f_scramble);
state->bufferedSize = 0; state->bufferedSize = 0;
} }
XXH_ASSERT(input < bEnd); XXH_ASSERT(input < bEnd);
if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) {
/* large input to consume : ingest per full block */
if ((size_t)(bEnd - input) > state->nbStripesPerBlock * XXH_STRIPE_LEN) {
size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN;
XXH_ASSERT(state->nbStripesPerBlock >= state->nbStripesSoFar); input = XXH3_consumeStripes(acc,
/* 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,
&state->nbStripesSoFar, state->nbStripesPerBlock, &state->nbStripesSoFar, state->nbStripesPerBlock,
input, XXH3_INTERNALBUFFER_STRIPES, input, nbStripes,
secret, state->secretLimit, secret, state->secretLimit,
f_acc512, f_scramble); f_acc, f_scramble);
input += XXH3_INTERNALBUFFER_SIZE; XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
} 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);
}
}
}
/* Some remaining input (always) : buffer it */ /* Some remaining input (always) : buffer it */
XXH_ASSERT(input < bEnd); XXH_ASSERT(input < bEnd);
XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); 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); state->bufferedSize = (XXH32_hash_t)(bEnd-input);
#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 #if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1
/* save stack accumulators into state */ /* save stack accumulators into state */
memcpy(state->acc, acc, sizeof(acc)); XXH_memcpy(state->acc, acc, sizeof(acc));
#endif #endif
} }
return XXH_OK; return XXH_OK;
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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, 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 XXH3_state_t* state,
const unsigned char* secret) 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 * Digest on a local copy. This way, the state remains unaltered, and it can
* continue ingesting more input afterwards. * continue ingesting more input afterwards.
*/ */
XXH_memcpy(acc, state->acc, sizeof(state->acc)); XXH_memcpy(acc, state->acc, sizeof(state->acc));
if (state->bufferedSize >= XXH_STRIPE_LEN) { 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 const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN;
size_t nbStripesSoFar = state->nbStripesSoFar; size_t nbStripesSoFar = state->nbStripesSoFar;
XXH3_consumeStripes(acc, XXH3_consumeStripes(acc,
&nbStripesSoFar, state->nbStripesPerBlock, &nbStripesSoFar, state->nbStripesPerBlock,
state->buffer, nbStripes, state->buffer, nbStripes,
secret, state->secretLimit, secret, state->secretLimit,
XXH3_accumulate_512, XXH3_scrambleAcc); XXH3_accumulate, XXH3_scrambleAcc);
/* last stripe */ lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN;
XXH3_accumulate_512(acc,
state->buffer + state->bufferedSize - XXH_STRIPE_LEN,
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
} else { /* 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; size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize;
XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */
XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize);
XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize);
XXH3_accumulate_512(acc, lastStripePtr = lastStripe;
lastStripe,
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
} }
/* Last stripe */
XXH3_accumulate_512(acc,
lastStripePtr,
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) 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; const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
if (state->totalLen > XXH3_MIDSIZE_MAX) { 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), return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen),
secret, state->secretLimit + XXH_STRIPE_LEN); 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). * 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) 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. */ /* 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) XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{ {
XXH_ASSERT(input != NULL); 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 ^= (m128.high64 >> 3);
m128.low64 = XXH_xorshift64(m128.low64, 35); m128.low64 = XXH_xorshift64(m128.low64, 35);
m128.low64 *= 0x9FB21C651E98DF25ULL; m128.low64 *= PRIME_MX2;
m128.low64 = XXH_xorshift64(m128.low64, 28); m128.low64 = XXH_xorshift64(m128.low64, 28);
m128.high64 = XXH3_avalanche(m128.high64); m128.high64 = XXH3_avalanche(m128.high64);
return m128; 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) XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{ {
XXH_ASSERT(input != NULL); 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 * 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) XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{ {
XXH_ASSERT(len <= 16); 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, XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize, const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed) 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; { XXH128_hash_t acc;
acc.low64 = len * XXH_PRIME64_1; acc.low64 = len * XXH_PRIME64_1;
acc.high64 = 0; 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 > 32) {
if (len > 64) { if (len > 64) {
if (len > 96) { 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+16, input+len-32, secret+32, seed);
} }
acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); acc = XXH128_mix32B(acc, input, input+len-16, secret, seed);
#endif
{ XXH128_hash_t h128; { XXH128_hash_t h128;
h128.low64 = acc.low64 + acc.high64; h128.low64 = acc.low64 + acc.high64;
h128.high64 = (acc.low64 * XXH_PRIME64_1) 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, XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize, const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed) 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); XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
{ XXH128_hash_t acc; { XXH128_hash_t acc;
int const nbRounds = (int)len / 32; unsigned i;
int i;
acc.low64 = len * XXH_PRIME64_1; acc.low64 = len * XXH_PRIME64_1;
acc.high64 = 0; 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, acc = XXH128_mix32B(acc,
input + (32 * i), input + i - 32,
input + (32 * i) + 16, input + i - 16,
secret + (32 * i), secret + i - 32,
seed); seed);
} }
acc.low64 = XXH3_avalanche(acc.low64); acc.low64 = XXH3_avalanche(acc.low64);
acc.high64 = XXH3_avalanche(acc.high64); 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, acc = XXH128_mix32B(acc,
input + (32 * i), input + i - 32,
input + (32 * i) + 16, input + i - 16,
secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), secret + XXH3_MIDSIZE_STARTOFFSET + i - 160,
seed); seed);
} }
/* last bytes */ /* last bytes */
@@ -5306,7 +6609,7 @@ XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
input + len - 16, input + len - 16,
input + len - 32, input + len - 32,
secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16,
0ULL - seed); (XXH64_hash_t)0 - seed);
{ XXH128_hash_t h128; { XXH128_hash_t h128;
h128.low64 = acc.low64 + acc.high64; 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 XXH_FORCE_INLINE XXH128_hash_t
XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize, 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) XXH3_f_scrambleAcc f_scramble)
{ {
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; 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 */ /* converge into final hash */
XXH_STATIC_ASSERT(sizeof(acc) == 64); 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, XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64, XXH64_hash_t seed64,
const void* XXH_RESTRICT secret, size_t secretLen) const void* XXH_RESTRICT secret, size_t secretLen)
{ {
(void)seed64; (void)secret; (void)secretLen; (void)seed64; (void)secret; (void)secretLen;
return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), 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. * 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, XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64, XXH64_hash_t seed64,
const void* XXH_RESTRICT secret, size_t secretLen) const void* XXH_RESTRICT secret, size_t secretLen)
{ {
(void)seed64; (void)seed64;
return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, 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 XXH_FORCE_INLINE XXH128_hash_t
XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64, XXH64_hash_t seed64,
XXH3_f_accumulate_512 f_acc512, XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble, XXH3_f_scrambleAcc f_scramble,
XXH3_f_initCustomSecret f_initSec) XXH3_f_initCustomSecret f_initSec)
{ {
if (seed64 == 0) if (seed64 == 0)
return XXH3_hashLong_128b_internal(input, len, return XXH3_hashLong_128b_internal(input, len,
XXH3_kSecret, sizeof(XXH3_kSecret), 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]; { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
f_initSec(secret, seed64); f_initSec(secret, seed64);
return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), 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; (void)secret; (void)secretLen;
return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, 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, 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 === */ /* === Public XXH128 API === */
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len)
{ {
return XXH3_128bits_internal(input, len, 0, return XXH3_128bits_internal(input, len, 0,
XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_kSecret, sizeof(XXH3_kSecret),
XXH3_hashLong_128b_default); XXH3_hashLong_128b_default);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t 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, return XXH3_128bits_internal(input, len, 0,
(const xxh_u8*)secret, secretSize, (const xxh_u8*)secret, secretSize,
XXH3_hashLong_128b_withSecret); XXH3_hashLong_128b_withSecret);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t 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, return XXH3_128bits_internal(input, len, seed,
XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_kSecret, sizeof(XXH3_kSecret),
XXH3_hashLong_128b_withSeed); XXH3_hashLong_128b_withSeed);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t 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) if (len <= XXH3_MIDSIZE_MAX)
return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);
return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t 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); return XXH3_128bits_withSeed(input, len, seed);
} }
/* === XXH3 128-bit streaming === */ /* === XXH3 128-bit streaming === */
#ifndef XXH_NO_STREAM
/* /*
* All initialization and update functions are identical to 64-bit streaming variant. * All initialization and update functions are identical to 64-bit streaming variant.
* The only difference is the finalization routine. * The only difference is the finalization routine.
*/ */
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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); return XXH3_64bits_reset(statePtr);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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); return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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); return XXH3_64bits_reset_withSeed(statePtr, seed);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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); return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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, return XXH3_64bits_update(state, input, len);
XXH3_accumulate_512, XXH3_scrambleAcc);
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) 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; const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
if (state->totalLen > XXH3_MIDSIZE_MAX) { 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), return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen),
secret, state->secretLimit + XXH_STRIPE_LEN); secret, state->secretLimit + XXH_STRIPE_LEN);
} }
#endif /* !XXH_NO_STREAM */
/* 128-bit utility functions */ /* 128-bit utility functions */
#include <string.h> /* memcmp, memcpy */ #include <string.h> /* memcmp, memcpy */
/* return : 1 is equal, 0 if different */ /* 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) 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 */ /* 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(). /* This prototype is compatible with stdlib's qsort().
* return : >0 if *h128_1 > *h128_2 * @return : >0 if *h128_1 > *h128_2
* <0 if *h128_1 < *h128_2 * <0 if *h128_1 < *h128_2
* =0 if *h128_1 == *h128_2 */ * =0 if *h128_1 == *h128_2 */
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) 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 h1 = *(const XXH128_hash_t*)h128_1;
XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; 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 ======*/ /*====== Canonical representation ======*/
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API void 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)); XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) { 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)); XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t 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; XXH128_hash_t h;
h.high64 = XXH_readBE64(src); 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 ); XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 );
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode 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) #if (XXH_DEBUGLEVEL >= 1)
XXH_ASSERT(secretBuffer != NULL); XXH_ASSERT(secretBuffer != NULL);
@@ -5652,9 +6957,9 @@ XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSee
return XXH_OK; return XXH_OK;
} }
/*! @ingroup xxh3_family */ /*! @ingroup XXH3_family */
XXH_PUBLIC_API void 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]; XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
XXH3_initCustomSecret(secret, seed); XXH3_initCustomSecret(secret, seed);
@@ -5667,7 +6972,7 @@ XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed)
/* Pop our optimization override from above */ /* Pop our optimization override from above */
#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
&& defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && 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 # pragma GCC pop_options
#endif #endif
@@ -5682,5 +6987,5 @@ XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed)
#if defined (__cplusplus) #if defined (__cplusplus)
} } /* extern "C" */
#endif #endif
+3 -3
View File
@@ -178,7 +178,7 @@ static void ZSTD_copy8(void* dst, const void* src) {
ZSTD_memcpy(dst, src, 8); ZSTD_memcpy(dst, src, 8);
#endif #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 /* 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 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); ZSTD_memcpy(dst, copy16_buf, 16);
#endif #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_OVERLENGTH 32
#define WILDCOPY_VECLEN 16 #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) { if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
/* Handle short offset copies. */ /* Handle short offset copies. */
do { do {
COPY8(op, ip) COPY8(op, ip);
} while (op < oend); } while (op < oend);
} else { } else {
assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
+9 -7
View File
@@ -1062,12 +1062,12 @@ HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
const BYTE* ip = (const BYTE*) src; const BYTE* ip = (const BYTE*) src;
BYTE* const ostart = (BYTE*)dst; BYTE* const ostart = (BYTE*)dst;
BYTE* const oend = ostart + dstSize; BYTE* const oend = ostart + dstSize;
BYTE* op = ostart;
HUF_CStream_t bitC; HUF_CStream_t bitC;
/* init */ /* init */
if (dstSize < 8) return 0; /* not enough space to compress */ 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 (HUF_isError(initErr)) return 0; }
if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11) if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11)
@@ -1288,7 +1288,7 @@ unsigned HUF_optimalTableLog(
{ BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp); { BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp);
size_t dstSize = wkspSize - 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 symbolCardinality = HUF_cardinality(count, maxSymbolValue);
const unsigned minTableLog = HUF_minTableLog(symbolCardinality); const unsigned minTableLog = HUF_minTableLog(symbolCardinality);
size_t optSize = ((size_t) ~0) - 1; size_t optSize = ((size_t) ~0) - 1;
@@ -1299,12 +1299,14 @@ unsigned HUF_optimalTableLog(
/* Search until size increases */ /* Search until size increases */
for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) { for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) {
DEBUGLOG(7, "checking for huffLog=%u", 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; if (ERR_isError(hSize)) continue;
+61 -54
View File
@@ -650,10 +650,11 @@ static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value)
return 0; return 0;
} }
#define BOUNDCHECK(cParam, val) { \ #define BOUNDCHECK(cParam, val) \
RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ do { \
parameter_outOfBound, "Param out of bounds"); \ RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
} parameter_outOfBound, "Param out of bounds"); \
} while (0)
static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 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, RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
"Reset parameters is only possible during init stage."); "Reset parameters is only possible during init stage.");
ZSTD_clearAllDicts(cctx); ZSTD_clearAllDicts(cctx);
ZSTD_memset(&cctx->externalMatchCtx, 0, sizeof(cctx->externalMatchCtx));
return ZSTD_CCtxParams_reset(&cctx->requestedParams); return ZSTD_CCtxParams_reset(&cctx->requestedParams);
} }
return 0; return 0;
@@ -1392,11 +1392,12 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
static ZSTD_compressionParameters static ZSTD_compressionParameters
ZSTD_clampCParams(ZSTD_compressionParameters cParams) ZSTD_clampCParams(ZSTD_compressionParameters cParams)
{ {
# define CLAMP_TYPE(cParam, val, type) { \ # define CLAMP_TYPE(cParam, val, type) \
ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ do { \
if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \ ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ 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) # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned)
CLAMP(ZSTD_c_windowLog, cParams.windowLog); CLAMP(ZSTD_c_windowLog, cParams.windowLog);
CLAMP(ZSTD_c_chainLog, cParams.chainLog); 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((MaxLL+1) * sizeof(U32))
+ ZSTD_cwksp_aligned_alloc_size((MaxOff+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((1<<Litbits) * sizeof(U32))
+ ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t)) + ZSTD_cwksp_aligned_alloc_size(ZSTD_OPT_SIZE * 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_optimal_t));
size_t const lazyAdditionalSpace = ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder) size_t const lazyAdditionalSpace = ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)
? ZSTD_cwksp_aligned_alloc_size(hSize) ? ZSTD_cwksp_aligned_alloc_size(hSize)
: 0; : 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 * be needed. However, we still allocate two 0-sized buffers, which can
* take space under ASAN. */ * take space under ASAN. */
return ZSTD_estimateCCtxSize_usingCCtxParams_internal( return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
&cParams, &params->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, params->useSequenceProducer, params->maxBlockSize); &cParams, &params->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize);
} }
size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 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( return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
&cParams, &params->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, &cParams, &params->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.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.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.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.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_NUM+1) * sizeof(ZSTD_optimal_t)); ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t));
} }
ms->cParams = *cParams; 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 windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize));
size_t const blockSize = MIN(params->maxBlockSize, windowSize); 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) size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered)
? ZSTD_compressBound(blockSize) + 1 ? ZSTD_compressBound(blockSize) + 1
: 0; : 0;
@@ -2134,8 +2135,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
size_t const neededSpace = size_t const neededSpace =
ZSTD_estimateCCtxSize_usingCCtxParams_internal( ZSTD_estimateCCtxSize_usingCCtxParams_internal(
&params->cParams, &params->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, &params->cParams, &params->ldmParams, zc->staticSize != 0, params->useRowMatchFinder,
buffInSize, buffOutSize, pledgedSrcSize, params->useSequenceProducer, params->maxBlockSize); buffInSize, buffOutSize, pledgedSrcSize, ZSTD_hasExtSeqProd(params), params->maxBlockSize);
int resizeWorkspace;
FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); 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 */ { /* Check if workspace is large enough, alloc a new one if needed */
int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
int const workspaceWasteful = ZSTD_cwksp_check_wasteful(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, "Need %zu B workspace", neededSpace);
DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); 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 */ /* reserve space for block-level external sequences */
if (params->useSequenceProducer) { if (ZSTD_hasExtSeqProd(params)) {
size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize);
zc->externalMatchCtx.seqBufferCapacity = maxNbExternalSeq; zc->extSeqBufCapacity = maxNbExternalSeq;
zc->externalMatchCtx.seqBuffer = zc->extSeqBuf =
(ZSTD_Sequence*)ZSTD_cwksp_reserve_aligned(ws, maxNbExternalSeq * sizeof(ZSTD_Sequence)); (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. /* External matchfinder + LDM is technically possible, just not implemented yet.
* We need to revisit soon and implement it. */ * We need to revisit soon and implement it. */
RETURN_ERROR_IF( RETURN_ERROR_IF(
zc->appliedParams.useSequenceProducer, ZSTD_hasExtSeqProd(&zc->appliedParams),
parameter_combination_unsupported, parameter_combination_unsupported,
"Long-distance matching with external sequence producer enabled is not currently supported." "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. /* External matchfinder + LDM is technically possible, just not implemented yet.
* We need to revisit soon and implement it. */ * We need to revisit soon and implement it. */
RETURN_ERROR_IF( RETURN_ERROR_IF(
zc->appliedParams.useSequenceProducer, ZSTD_hasExtSeqProd(&zc->appliedParams),
parameter_combination_unsupported, parameter_combination_unsupported,
"Long-distance matching with external sequence producer enabled is not currently supported." "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, zc->appliedParams.useRowMatchFinder,
src, srcSize); src, srcSize);
assert(ldmSeqStore.pos == ldmSeqStore.size); assert(ldmSeqStore.pos == ldmSeqStore.size);
} else if (zc->appliedParams.useSequenceProducer) { } else if (ZSTD_hasExtSeqProd(&zc->appliedParams)) {
assert( 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; { U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog;
size_t const nbExternalSeqs = (zc->externalMatchCtx.mFinder)( size_t const nbExternalSeqs = (zc->appliedParams.extSeqProdFunc)(
zc->externalMatchCtx.mState, zc->appliedParams.extSeqProdState,
zc->externalMatchCtx.seqBuffer, zc->extSeqBuf,
zc->externalMatchCtx.seqBufferCapacity, zc->extSeqBufCapacity,
src, srcSize, src, srcSize,
NULL, 0, /* dict and dictSize, currently not supported */ NULL, 0, /* dict and dictSize, currently not supported */
zc->appliedParams.compressionLevel, 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( size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult(
zc->externalMatchCtx.seqBuffer, zc->extSeqBuf,
nbExternalSeqs, nbExternalSeqs,
zc->externalMatchCtx.seqBufferCapacity, zc->extSeqBufCapacity,
srcSize srcSize
); );
/* Return early if there is no error, since we don't need to worry about last literals */ /* Return early if there is no error, since we don't need to worry about last literals */
if (!ZSTD_isError(nbPostProcessedSeqs)) { if (!ZSTD_isError(nbPostProcessedSeqs)) {
ZSTD_sequencePosition seqPos = {0,0,0}; 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!"); RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid, "External sequences imply too large a block!");
FORWARD_IF_ERROR( FORWARD_IF_ERROR(
ZSTD_copySequencesToSeqStoreExplicitBlockDelim( ZSTD_copySequencesToSeqStoreExplicitBlockDelim(
zc, &seqPos, zc, &seqPos,
zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs, zc->extSeqBuf, nbPostProcessedSeqs,
src, srcSize, src, srcSize,
zc->appliedParams.searchForExternalRepcodes 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* const ostart = (BYTE*)dst;
BYTE* op = ostart; BYTE* op = ostart;
size_t fhSize = 0;
DEBUGLOG(4, "ZSTD_writeEpilogue"); DEBUGLOG(4, "ZSTD_writeEpilogue");
RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing");
/* special case : empty frame */ /* special case : empty frame */
if (cctx->stage == ZSTDcs_init) { 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"); FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
dstCapacity -= fhSize; dstCapacity -= fhSize;
op += fhSize; op += fhSize;
@@ -5524,7 +5523,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced2(
cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch, cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch,
customMem); customMem);
if (ZSTD_isError( ZSTD_initCDict_internal(cdict, if (!cdict || ZSTD_isError( ZSTD_initCDict_internal(cdict,
dict, dictSize, dict, dictSize,
dictLoadMethod, dictContentType, dictLoadMethod, dictContentType,
cctxParams) )) { cctxParams) )) {
@@ -6207,7 +6206,7 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
#ifdef ZSTD_MULTITHREAD #ifdef ZSTD_MULTITHREAD
/* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */ /* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */
RETURN_ERROR_IF( RETURN_ERROR_IF(
params.useSequenceProducer == 1 && params.nbWorkers >= 1, ZSTD_hasExtSeqProd(&params) && params.nbWorkers >= 1,
parameter_combination_unsupported, parameter_combination_unsupported,
"External sequence producer isn't supported with nbWorkers >= 1" "External sequence producer isn't supported with nbWorkers >= 1"
); );
@@ -6499,7 +6498,7 @@ ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx,
if (cctx->appliedParams.validateSequences) { if (cctx->appliedParams.validateSequences) {
seqPos->posInSrc += litLength + matchLength; seqPos->posInSrc += litLength + matchLength;
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, 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"); "Sequence validation failed");
} }
RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, 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) { if (cctx->appliedParams.validateSequences) {
seqPos->posInSrc += litLength + matchLength; seqPos->posInSrc += litLength + matchLength;
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, 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"); "Sequence validation failed");
} }
DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); 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( void ZSTD_registerSequenceProducer(
ZSTD_CCtx* zc, void* mState, ZSTD_CCtx* zc,
ZSTD_sequenceProducer_F* mFinder void* extSeqProdState,
ZSTD_sequenceProducer_F extSeqProdFunc
) { ) {
if (mFinder != NULL) { assert(zc != NULL);
ZSTD_externalMatchCtx emctx; ZSTD_CCtxParams_registerSequenceProducer(
emctx.mState = mState; &zc->requestedParams, extSeqProdState, extSeqProdFunc
emctx.mFinder = mFinder; );
emctx.seqBuffer = NULL; }
emctx.seqBufferCapacity = 0;
zc->externalMatchCtx = emctx; void ZSTD_CCtxParams_registerSequenceProducer(
zc->requestedParams.useSequenceProducer = 1; ZSTD_CCtx_params* params,
void* extSeqProdState,
ZSTD_sequenceProducer_F extSeqProdFunc
) {
assert(params != NULL);
if (extSeqProdFunc != NULL) {
params->extSeqProdFunc = extSeqProdFunc;
params->extSeqProdState = extSeqProdState;
} else { } else {
ZSTD_memset(&zc->externalMatchCtx, 0, sizeof(zc->externalMatchCtx)); params->extSeqProdFunc = NULL;
zc->requestedParams.useSequenceProducer = 0; params->extSeqProdState = NULL;
} }
} }
+20 -21
View File
@@ -159,23 +159,24 @@ typedef struct {
UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0}; UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0};
typedef struct { typedef struct {
int price; int price; /* price from beginning of segment to this position */
U32 off; U32 off; /* offset of previous match */
U32 mlen; U32 mlen; /* length of previous match */
U32 litlen; U32 litlen; /* nb of literals since previous match */
U32 rep[ZSTD_REP_NUM]; U32 rep[ZSTD_REP_NUM]; /* offset history after previous match */
} ZSTD_optimal_t; } ZSTD_optimal_t;
typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e; typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
#define ZSTD_OPT_SIZE (ZSTD_OPT_NUM+3)
typedef struct { typedef struct {
/* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */ /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
unsigned* litFreq; /* table of literals statistics, of size 256 */ unsigned* litFreq; /* table of literals statistics, of size 256 */
unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */ unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */ unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+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_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_NUM+1 */ ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_SIZE */
U32 litSum; /* nb of literals */ U32 litSum; /* nb of literals */
U32 litLengthSum; /* nb of litLength codes */ U32 litLengthSum; /* nb of litLength codes */
@@ -360,10 +361,11 @@ struct ZSTD_CCtx_params_s {
* if the external matchfinder returns an error code. */ * if the external matchfinder returns an error code. */
int enableMatchFinderFallback; int enableMatchFinderFallback;
/* Indicates whether an external matchfinder has been referenced. /* Parameters for the external sequence producer API.
* Users can't set this externally. * Users set these parameters through ZSTD_registerSequenceProducer().
* It is set internally in ZSTD_registerSequenceProducer(). */ * It is not possible to set these parameters individually through the public API. */
int useSequenceProducer; void* extSeqProdState;
ZSTD_sequenceProducer_F extSeqProdFunc;
/* Adjust the max block size*/ /* Adjust the max block size*/
size_t maxBlockSize; size_t maxBlockSize;
@@ -401,14 +403,6 @@ typedef struct {
ZSTD_entropyCTablesMetadata_t entropyMetadata; ZSTD_entropyCTablesMetadata_t entropyMetadata;
} ZSTD_blockSplitCtx; } 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 { struct ZSTD_CCtx_s {
ZSTD_compressionStage_e stage; 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. */ 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 */ /* Workspace for block splitter */
ZSTD_blockSplitCtx blockSplitCtx; ZSTD_blockSplitCtx blockSplitCtx;
/* Workspace for external matchfinder */ /* Buffer for output from external sequence producer */
ZSTD_externalMatchCtx externalMatchCtx; ZSTD_Sequence* extSeqBuf;
size_t extSeqBufCapacity;
}; };
typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; 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 ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); 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 * Deprecated definitions that are still used internally to avoid
+223 -110
View File
@@ -76,8 +76,8 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
} }
{ int const flags = bmi2 ? HUF_flags_bmi2 : 0; { int const flags = bmi2 ? HUF_flags_bmi2 : 0;
const size_t cSize = singleStream ? HUF_compress1X_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, oend-op, literals, litSize, hufTable, flags); : HUF_compress4X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags);
op += cSize; op += cSize;
cLitSize += cSize; cLitSize += cSize;
if (cSize == 0 || ERR_isError(cSize)) { if (cSize == 0 || ERR_isError(cSize)) {
@@ -102,7 +102,7 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
switch(lhSize) switch(lhSize)
{ {
case 3: /* 2 - 2 - 10 - 10 */ 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); MEM_writeLE24(ostart, lhc);
break; break;
} }
@@ -122,30 +122,30 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
} }
*entropyWritten = 1; *entropyWritten = 1;
DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart)); DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));
return op-ostart; return (size_t)(op-ostart);
} }
static size_t static size_t
ZSTD_seqDecompressedSize(seqStore_t const* seqStore, ZSTD_seqDecompressedSize(seqStore_t const* seqStore,
const seqDef* sequences, size_t nbSeq, const seqDef* sequences, size_t nbSeqs,
size_t litSize, int lastSequence) 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 matchLengthSum = 0;
size_t litLengthSum = 0; size_t litLengthSum = 0;
(void)(litLengthSum); /* suppress unused variable warning on some environments */ size_t n;
while (send-sp > 0) { for (n=0; n<nbSeqs; n++) {
ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp); const ZSTD_sequenceLength seqLen = ZSTD_getSequenceLength(seqStore, sequences+n);
litLengthSum += seqLen.litLength; litLengthSum += seqLen.litLength;
matchLengthSum += seqLen.matchLength; matchLengthSum += seqLen.matchLength;
sp++;
} }
assert(litLengthSum <= litSize); DEBUGLOG(5, "ZSTD_seqDecompressedSize: %u sequences from %p: %u literals + %u matchlength",
if (!lastSequence) { (unsigned)nbSeqs, (const void*)sequences,
(unsigned)litLengthSum, (unsigned)matchLengthSum);
if (!lastSubBlock)
assert(litLengthSum == litSize); assert(litLengthSum == litSize);
} else
assert(litLengthSum <= litSize);
(void)litLengthSum;
return matchLengthSum + litSize; return matchLengthSum + litSize;
} }
@@ -187,7 +187,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
else else
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
if (nbSeq==0) { if (nbSeq==0) {
return op - ostart; return (size_t)(op - ostart);
} }
/* seqHead : flags for FSE encoding type */ /* seqHead : flags for FSE encoding type */
@@ -209,7 +209,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
} }
{ size_t const bitstreamSize = ZSTD_encodeSequences( { size_t const bitstreamSize = ZSTD_encodeSequences(
op, oend - op, op, (size_t)(oend - op),
fseTables->matchlengthCTable, mlCode, fseTables->matchlengthCTable, mlCode,
fseTables->offcodeCTable, ofCode, fseTables->offcodeCTable, ofCode,
fseTables->litlengthCTable, llCode, fseTables->litlengthCTable, llCode,
@@ -253,7 +253,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
#endif #endif
*entropyWritten = 1; *entropyWritten = 1;
return op - ostart; return (size_t)(op - ostart);
} }
/** ZSTD_compressSubBlock() : /** ZSTD_compressSubBlock() :
@@ -279,7 +279,8 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock); litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);
{ size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable, { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,
&entropyMetadata->hufMetadata, literals, litSize, &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"); FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");
if (cLitSize == 0) return 0; if (cLitSize == 0) return 0;
op += cLitSize; op += cLitSize;
@@ -289,18 +290,18 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
sequences, nbSeq, sequences, nbSeq,
llCode, mlCode, ofCode, llCode, mlCode, ofCode,
cctxParams, cctxParams,
op, oend-op, op, (size_t)(oend-op),
bmi2, writeSeqEntropy, seqEntropyWritten); bmi2, writeSeqEntropy, seqEntropyWritten);
FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed"); FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");
if (cSeqSize == 0) return 0; if (cSeqSize == 0) return 0;
op += cSeqSize; op += cSeqSize;
} }
/* Write block header */ /* 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); U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
MEM_writeLE24(ostart, cBlockHeader24); MEM_writeLE24(ostart, cBlockHeader24);
} }
return op-ostart; return (size_t)(op-ostart);
} }
static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize, 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; 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* ofCodeTable,
const BYTE* llCodeTable, const BYTE* llCodeTable,
const BYTE* mlCodeTable, 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_entropyCTables_t* entropy,
const ZSTD_entropyCTablesMetadata_t* entropyMetadata, const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
void* workspace, size_t wkspSize, void* workspace, size_t wkspSize,
int writeLitEntropy, int writeSeqEntropy) { int writeLitEntropy, int writeSeqEntropy)
size_t cSizeEstimate = 0; {
cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize, EstimatedBlockSize ebs;
&entropy->huf, &entropyMetadata->hufMetadata, ebs.estLitSize = ZSTD_estimateSubBlockSize_literal(literals, litSize,
workspace, wkspSize, writeLitEntropy); &entropy->huf, &entropyMetadata->hufMetadata,
cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, workspace, wkspSize, writeLitEntropy);
ebs.estBlockSize = ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
workspace, wkspSize, writeSeqEntropy); workspace, wkspSize, writeSeqEntropy);
return cSizeEstimate + ZSTD_blockHeaderSize; ebs.estBlockSize += ebs.estLitSize + ZSTD_blockHeaderSize;
return ebs;
} }
static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata) static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)
@@ -419,13 +426,58 @@ static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMe
return 0; 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() : /** ZSTD_compressSubBlock_multi() :
* Breaks super-block into multiple sub-blocks and compresses them. * Breaks super-block into multiple sub-blocks and compresses them.
* Entropy will be written to the first block. * Entropy will be written into the first block.
* The following blocks will use repeat mode to compress. * The following blocks use repeat_mode to compress.
* All sub-blocks are compressed blocks (no raw or rle blocks). * Sub-blocks are all compressed, except the last one when beneficial.
* @return : compressed size of the super block (which is multiple ZSTD blocks) * @return : compressed size of the super block (which features multiple ZSTD blocks)
* Or 0 if it failed to compress. */ * or 0 if it failed to compress. */
static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
const ZSTD_compressedBlockState_t* prevCBlock, const ZSTD_compressedBlockState_t* prevCBlock,
ZSTD_compressedBlockState_t* nextCBlock, 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 sstart = seqStorePtr->sequencesStart;
const seqDef* const send = seqStorePtr->sequences; 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 lstart = seqStorePtr->litStart;
const BYTE* const lend = seqStorePtr->lit; const BYTE* const lend = seqStorePtr->lit;
const BYTE* lp = lstart; const BYTE* lp = lstart;
size_t const nbLiterals = (size_t)(lend - lstart);
BYTE const* ip = (BYTE const*)src; BYTE const* ip = (BYTE const*)src;
BYTE const* const iend = ip + srcSize; BYTE const* const iend = ip + srcSize;
BYTE* const ostart = (BYTE*)dst; 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* llCodePtr = seqStorePtr->llCode;
const BYTE* mlCodePtr = seqStorePtr->mlCode; const BYTE* mlCodePtr = seqStorePtr->mlCode;
const BYTE* ofCodePtr = seqStorePtr->ofCode; const BYTE* ofCodePtr = seqStorePtr->ofCode;
size_t targetCBlockSize = cctxParams->targetCBlockSize; size_t const minTarget = CBLOCK_TARGET_SIZE_MIN; /* enforce minimum size, to reduce undesirable side effects */
size_t litSize, seqCount; size_t const targetCBlockSize = MAX(minTarget, cctxParams->targetCBlockSize);
int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed; int writeLitEntropy = (entropyMetadata->hufMetadata.hType == set_compressed);
int writeSeqEntropy = 1; int writeSeqEntropy = 1;
int lastSequence = 0;
DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)", DEBUGLOG(5, "ZSTD_compressSubBlock_multi (srcSize=%u, litSize=%u, nbSeq=%u)",
(unsigned)(lend-lp), (unsigned)(send-sstart)); (unsigned)srcSize, (unsigned)(lend-lstart), (unsigned)(send-sstart));
litSize = 0; /* let's start by a general estimation for the full block */
seqCount = 0; if (nbSeqs > 0) {
do { EstimatedBlockSize const ebs =
size_t cBlockSizeEstimate = 0; ZSTD_estimateSubBlockSize(lp, nbLiterals,
if (sstart == send) { ofCodePtr, llCodePtr, mlCodePtr, nbSeqs,
lastSequence = 1; &nextCBlock->entropy, entropyMetadata,
} else { workspace, wkspSize,
const seqDef* const sequence = sp + seqCount; writeLitEntropy, writeSeqEntropy);
lastSequence = sequence == send - 1; /* quick estimation */
litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength; size_t const avgLitCost = nbLiterals ? (ebs.estLitSize * BYTESCALE) / nbLiterals : BYTESCALE;
seqCount++; 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) { } /* if (nbSeqs > 0) */
assert(lp <= lend);
assert(litSize <= (size_t)(lend - lp)); /* write last block */
litSize = (size_t)(lend - lp); DEBUGLOG(2, "Generate last sub-block: %u sequences remaining", (unsigned)(send - sp));
} { int litEntropyWritten = 0;
/* I think there is an optimization opportunity here. int seqEntropyWritten = 0;
* Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful size_t litSize = (size_t)(lend - lp);
* since it recalculates estimate from scratch. size_t seqCount = (size_t)(send - sp);
* For example, it would recount literal distribution and symbol codes every time. const size_t decompressedSize =
*/ ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 1);
cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount, size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
&nextCBlock->entropy, entropyMetadata, sp, seqCount,
workspace, wkspSize, writeLitEntropy, writeSeqEntropy); lp, litSize,
if (cBlockSizeEstimate > targetCBlockSize || lastSequence) { llCodePtr, mlCodePtr, ofCodePtr,
int litEntropyWritten = 0; cctxParams,
int seqEntropyWritten = 0; op, (size_t)(oend-op),
const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence); bmi2, writeLitEntropy, writeSeqEntropy,
const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, &litEntropyWritten, &seqEntropyWritten,
sp, seqCount, lastBlock);
lp, litSize, FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
llCodePtr, mlCodePtr, ofCodePtr,
cctxParams, /* update pointers, the nb of literals borrowed from next sequence must be preserved */
op, oend-op, if (cSize > 0 && cSize < decompressedSize) {
bmi2, writeLitEntropy, writeSeqEntropy, DEBUGLOG(2, "Last sub-block compressed %u bytes => %u bytes",
&litEntropyWritten, &seqEntropyWritten, (unsigned)decompressedSize, (unsigned)cSize);
lastBlock && lastSequence); assert(ip + decompressedSize <= iend);
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); ip += decompressedSize;
if (cSize > 0 && cSize < decompressedSize) { lp += litSize;
DEBUGLOG(5, "Committed the sub-block"); op += cSize;
assert(ip + decompressedSize <= iend); llCodePtr += seqCount;
ip += decompressedSize; mlCodePtr += seqCount;
sp += seqCount; ofCodePtr += seqCount;
lp += litSize; /* Entropy only needs to be written once */
op += cSize; if (litEntropyWritten) {
llCodePtr += seqCount; writeLitEntropy = 0;
mlCodePtr += seqCount;
ofCodePtr += seqCount;
litSize = 0;
seqCount = 0;
/* Entropy only needs to be written once */
if (litEntropyWritten) {
writeLitEntropy = 0;
}
if (seqEntropyWritten) {
writeSeqEntropy = 0;
}
} }
if (seqEntropyWritten) {
writeSeqEntropy = 0;
}
sp += seqCount;
} }
} while (!lastSequence); }
if (writeLitEntropy) { 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)); ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
} }
if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) { if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
/* If we haven't written our entropy tables, then we've violated our contract and /* If we haven't written our entropy tables, then we've violated our contract and
* must emit an uncompressed block. * 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; return 0;
} }
if (ip < iend) { if (ip < iend) {
size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock); /* some data left : last part of the block sent uncompressed */
DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip)); 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"); FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
assert(cSize != 0); assert(cSize != 0);
op += cSize; op += cSize;
/* We have to regenerate the repcodes because we've skipped some sequences */ /* We have to regenerate the repcodes because we've skipped some sequences */
if (sp < send) { if (sp < send) {
seqDef const* seq; const seqDef* seq;
repcodes_t rep; repcodes_t rep;
ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep)); ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));
for (seq = sstart; seq < sp; ++seq) { 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)); 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, size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
void* dst, size_t dstCapacity, void* dst, size_t dstCapacity,
void const* src, size_t srcSize, const void* src, size_t srcSize,
unsigned lastBlock) { unsigned lastBlock)
{
ZSTD_entropyCTablesMetadata_t entropyMetadata; ZSTD_entropyCTablesMetadata_t entropyMetadata;
FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore, FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,
+2 -2
View File
@@ -356,8 +356,8 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
if (ms->prefetchCDictTables) { if (ms->prefetchCDictTables) {
size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32);
size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32); size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32);
PREFETCH_AREA(dictHashLong, hashTableBytes) PREFETCH_AREA(dictHashLong, hashTableBytes);
PREFETCH_AREA(dictHashSmall, chainTableBytes) PREFETCH_AREA(dictHashSmall, chainTableBytes);
} }
/* init */ /* init */
+1 -1
View File
@@ -508,7 +508,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
if (ms->prefetchCDictTables) { if (ms->prefetchCDictTables) {
size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32);
PREFETCH_AREA(dictHashTable, hashTableBytes) PREFETCH_AREA(dictHashTable, hashTableBytes);
} }
/* init */ /* init */
+1 -1
View File
@@ -695,7 +695,6 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
/* maybeSplitSequence updates rawSeqStore->pos */ /* maybeSplitSequence updates rawSeqStore->pos */
rawSeq const sequence = maybeSplitSequence(rawSeqStore, rawSeq const sequence = maybeSplitSequence(rawSeqStore,
(U32)(iend - ip), minMatch); (U32)(iend - ip), minMatch);
int i;
/* End signal */ /* End signal */
if (sequence.offset == 0) if (sequence.offset == 0)
break; break;
@@ -708,6 +707,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
/* Run the block compressor */ /* Run the block compressor */
DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength); DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
{ {
int i;
size_t const newLitLength = size_t const newLitLength =
blockCompressor(ms, seqStore, rep, ip, sequence.litLength); blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
ip += sequence.litLength; ip += sequence.litLength;
+171 -95
View File
@@ -267,6 +267,7 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
const optState_t* const optPtr, const optState_t* const optPtr,
int optLevel) int optLevel)
{ {
DEBUGLOG(8, "ZSTD_rawLiteralsCost (%u literals)", litLength);
if (litLength == 0) return 0; if (litLength == 0) return 0;
if (!ZSTD_compressedLiterals(optPtr)) if (!ZSTD_compressedLiterals(optPtr))
@@ -566,7 +567,7 @@ void ZSTD_updateTree_internal(
const BYTE* const base = ms->window.base; const BYTE* const base = ms->window.base;
U32 const target = (U32)(ip - base); U32 const target = (U32)(ip - base);
U32 idx = ms->nextToUpdate; 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); idx, target, dictMode);
while(idx < target) { while(idx < target) {
@@ -1047,11 +1048,6 @@ ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm,
* Optimal parser * Optimal parser
*********************************/ *********************************/
static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
{
return sol.litlen + sol.mlen;
}
#if 0 /* debug */ #if 0 /* debug */
static void static void
@@ -1069,6 +1065,10 @@ listStats(const U32* table, int lastEltID)
#endif #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 FORCE_INLINE_TEMPLATE
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
size_t size_t
@@ -1097,10 +1097,10 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
ZSTD_optimal_t* const opt = optStatePtr->priceTable; ZSTD_optimal_t* const opt = optStatePtr->priceTable;
ZSTD_match_t* const matches = optStatePtr->matchTable; ZSTD_match_t* const matches = optStatePtr->matchTable;
ZSTD_optimal_t lastSequence; ZSTD_optimal_t lastStretch;
ZSTD_optLdm_t optLdm; 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.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore;
optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0; optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0;
@@ -1122,19 +1122,31 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
U32 const ll0 = !litlen; U32 const ll0 = !litlen;
U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch); U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch);
ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches,
(U32)(ip-istart), (U32)(iend - ip)); (U32)(ip-istart), (U32)(iend-ip));
if (!nbMatches) { ip++; continue; } 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] */ /* initialize opt[0] */
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; } opt[0].mlen = 0; /* there are only literals so far */
opt[0].mlen = 0; /* means is_a_literal */
opt[0].litlen = litlen; opt[0].litlen = litlen;
/* We don't need to include the actual price of the literals because /* No need to include the actual price of the literals before the first match
* it is static for the duration of the forward pass, and is included * 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 * in every subsequent price. But, we include the literal length because
* prices when we subtract the previous literal length. * 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 */ /* large match -> immediate encoding */
{ U32 const maxML = matches[nbMatches-1].len; { 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)); nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart));
if (maxML > sufficient_len) { if (maxML > sufficient_len) {
lastSequence.litlen = litlen; lastStretch.litlen = 0;
lastSequence.mlen = maxML; lastStretch.mlen = maxML;
lastSequence.off = maxOffBase; lastStretch.off = maxOffBase;
DEBUGLOG(6, "large match (%u>%u), immediate encoding", DEBUGLOG(6, "large match (%u>%u) => immediate encoding",
maxML, sufficient_len); maxML, sufficient_len);
cur = 0; cur = 0;
last_pos = ZSTD_totalLen(lastSequence); last_pos = maxML;
goto _shortestPath; goto _shortestPath;
} } } }
/* set prices for first matches starting position == 0 */ /* set prices for first matches starting position == 0 */
assert(opt[0].price >= 0); assert(opt[0].price >= 0);
{ U32 const literalsPrice = (U32)opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); { U32 pos;
U32 pos;
U32 matchNb; U32 matchNb;
for (pos = 1; pos < minMatch; pos++) { 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++) { for (matchNb = 0; matchNb < nbMatches; matchNb++) {
U32 const offBase = matches[matchNb].off; U32 const offBase = matches[matchNb].off;
U32 const end = matches[matchNb].len; U32 const end = matches[matchNb].len;
for ( ; pos <= end ; pos++ ) { for ( ; pos <= end ; pos++ ) {
U32 const matchPrice = ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel); int const matchPrice = (int)ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel);
U32 const sequencePrice = literalsPrice + matchPrice; int const sequencePrice = opt[0].price + matchPrice;
DEBUGLOG(7, "rPos:%u => set initial price : %.2f", DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
pos, ZSTD_fCost((int)sequencePrice)); pos, ZSTD_fCost(sequencePrice));
opt[pos].mlen = pos; opt[pos].mlen = pos;
opt[pos].off = offBase; opt[pos].off = offBase;
opt[pos].litlen = litlen; opt[pos].litlen = 0; /* end of match */
opt[pos].price = (int)sequencePrice; opt[pos].price = sequencePrice + LL_PRICE(0);
} } }
}
last_pos = pos-1; last_pos = pos-1;
opt[pos].price = ZSTD_MAX_PRICE;
} }
} }
/* check further positions */ /* check further positions */
for (cur = 1; cur <= last_pos; cur++) { for (cur = 1; cur <= last_pos; cur++) {
const BYTE* const inr = ip + cur; const BYTE* const inr = ip + cur;
assert(cur < ZSTD_OPT_NUM); assert(cur <= ZSTD_OPT_NUM);
DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur) DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur);
/* Fix current position with one literal if cheaper */ /* 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 const price = opt[cur-1].price
+ (int)ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) + LIT_PRICE(ip+cur-1)
+ (int)ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) + LL_INCPRICE(litlen);
- (int)ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
assert(price < 1000000000); /* overflow check */ assert(price < 1000000000); /* overflow check */
if (price <= opt[cur].price) { 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)", 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, 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-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
opt[cur].mlen = 0; opt[cur] = opt[cur-1];
opt[cur].off = 0;
opt[cur].litlen = litlen; opt[cur].litlen = litlen;
opt[cur].price = price; 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 { } else {
DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)", DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f)",
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price));
opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
} }
} }
/* Set the repcodes of the current position. We must do it here /* Offset history is not updated during match comparison.
* because we rely on the repcodes of the 2nd to last sequence being * Do it here, now that the match is selected and confirmed.
* correct to set the next chunks repcodes during the backward
* traversal.
*/ */
ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t)); ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t));
assert(cur >= opt[cur].mlen); 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; 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)); 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 */ /* 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*/ if ( (optLevel==0) /*static_test*/
&& (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) { && (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 */ continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
} }
assert(opt[cur].price >= 0); assert(opt[cur].price >= 0);
{ U32 const ll0 = (opt[cur].mlen != 0); { U32 const ll0 = (opt[cur].litlen == 0);
U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0; int const previousPrice = opt[cur].price;
U32 const previousPrice = (U32)opt[cur].price; int const basePrice = previousPrice + LL_PRICE(0);
U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch); U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch);
U32 matchNb; U32 matchNb;
@@ -1248,18 +1283,17 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
continue; continue;
} }
{ U32 const maxML = matches[nbMatches-1].len; { U32 const longestML = matches[nbMatches-1].len;
DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u", DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of longest ML=%u",
inr-istart, cur, nbMatches, maxML); inr-istart, cur, nbMatches, longestML);
if ( (maxML > sufficient_len) if ( (longestML > sufficient_len)
|| (cur + maxML >= ZSTD_OPT_NUM) ) { || (cur + longestML >= ZSTD_OPT_NUM)
lastSequence.mlen = maxML; || (ip + cur + longestML >= iend) ) {
lastSequence.off = matches[nbMatches-1].off; lastStretch.mlen = longestML;
lastSequence.litlen = litlen; lastStretch.off = matches[nbMatches-1].off;
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 */ lastStretch.litlen = 0;
last_pos = cur + ZSTD_totalLen(lastSequence); last_pos = cur + longestML;
if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */
goto _shortestPath; goto _shortestPath;
} } } }
@@ -1271,19 +1305,24 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
U32 mlen; U32 mlen;
DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u", 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 */ for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
U32 const pos = cur + mlen; 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)) { if ((pos > last_pos) || (price < opt[pos].price)) {
DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)", DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price)); 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].mlen = mlen;
opt[pos].off = offset; opt[pos].off = offset;
opt[pos].litlen = litlen; opt[pos].litlen = 0;
opt[pos].price = price; opt[pos].price = price;
} else { } else {
DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)", 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 */ 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++) */ } /* for (cur = 1; cur <= last_pos; cur++) */
lastSequence = opt[last_pos]; lastStretch = opt[last_pos];
cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */ assert(cur >= lastStretch.mlen);
assert(cur < ZSTD_OPT_NUM); /* control overflow*/ cur = last_pos - lastStretch.mlen;
_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
assert(opt[0].mlen == 0); 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 if (lastStretch.mlen==0) {
* of the last match, and the last sequence. This avoids us having to /* no solution : all matches have been converted into literals */
* update them while traversing the sequences. assert(lastStretch.litlen == (ip - anchor) + last_pos);
*/ ip += last_pos;
if (lastSequence.mlen != 0) { continue;
repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0); }
ZSTD_memcpy(rep, &reps, sizeof(reps)); 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 { } 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 storeStart = storeEnd;
U32 seqPos = cur; U32 stretchPos = cur;
DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)", DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
last_pos, cur); (void)last_pos; last_pos, cur); (void)last_pos;
assert(storeEnd < ZSTD_OPT_NUM); assert(storeEnd < ZSTD_OPT_SIZE);
DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", DEBUGLOG(6, "last stretch copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off); storeEnd, lastStretch.litlen, lastStretch.mlen, lastStretch.off);
opt[storeEnd] = lastSequence; if (lastStretch.litlen > 0) {
while (seqPos > 0) { /* last "sequence" is unfinished: just a bunch of literals */
U32 const backDist = ZSTD_totalLen(opt[seqPos]); 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--; storeStart--;
DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", opt[storeStart] = nextStretch; /* note: litlen will be fixed */
seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off); assert(nextStretch.litlen + nextStretch.mlen <= stretchPos);
opt[storeStart] = opt[seqPos]; stretchPos -= nextStretch.litlen + nextStretch.mlen;
seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
} }
/* save sequences */ /* save sequences */
DEBUGLOG(6, "sending selected sequences into seqStore") DEBUGLOG(6, "sending selected sequences into seqStore");
{ U32 storePos; { U32 storePos;
for (storePos=storeStart; storePos <= storeEnd; storePos++) { for (storePos=storeStart; storePos <= storeEnd; storePos++) {
U32 const llen = opt[storePos].litlen; U32 const llen = opt[storePos].litlen;
@@ -1353,6 +1426,9 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
anchor += advance; anchor += advance;
ip = anchor; ip = anchor;
} } } }
DEBUGLOG(7, "new offset history : %u, %u, %u", rep[0], rep[1], rep[2]);
/* update all costs */
ZSTD_setBasePrices(optStatePtr, optLevel); ZSTD_setBasePrices(optStatePtr, optLevel);
} }
} /* while (ip < ilimit) */ } /* 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, * Consequently, this can only work if no data has been previously loaded in tables,
* aka, no dictionary, no prefix, no ldm preprocessing. * aka, no dictionary, no prefix, no ldm preprocessing.
* The compression ratio gain is generally small (~0.5% on first block), * 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); assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
if ( (ms->opt.litLengthSum==0) /* first block */ if ( (ms->opt.litLengthSum==0) /* first block */
&& (seqStore->sequences == seqStore->sequencesStart) /* no ldm */ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
+35 -30
View File
@@ -40,12 +40,13 @@
# include <unistd.h> # include <unistd.h>
# include <sys/times.h> # include <sys/times.h>
# define DEBUG_PRINTHEX(l,p,n) { \ # define DEBUG_PRINTHEX(l,p,n) \
unsigned debug_u; \ do { \
for (debug_u=0; debug_u<(n); debug_u++) \ unsigned debug_u; \
RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \ for (debug_u=0; debug_u<(n); debug_u++) \
RAWLOG(l, " \n"); \ RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
} RAWLOG(l, " \n"); \
} while (0)
static unsigned long long GetCurrentClockTimeMicroseconds(void) static unsigned long long GetCurrentClockTimeMicroseconds(void)
{ {
@@ -57,25 +58,28 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void)
} } } }
#define MUTEX_WAIT_TIME_DLEVEL 6 #define MUTEX_WAIT_TIME_DLEVEL 6
#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) { \ #define ZSTD_PTHREAD_MUTEX_LOCK(mutex) \
if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \ do { \
unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \ if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \
ZSTD_pthread_mutex_lock(mutex); \ unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
{ unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \ ZSTD_pthread_mutex_lock(mutex); \
unsigned long long const elapsedTime = (afterTime-beforeTime); \ { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \ unsigned long long const elapsedTime = (afterTime-beforeTime); \
DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \ if (elapsedTime > 1000) { \
elapsedTime, #mutex); \ /* or whatever threshold you like; I'm using 1 millisecond here */ \
} } \ DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, \
} else { \ "Thread took %llu microseconds to acquire mutex %s \n", \
ZSTD_pthread_mutex_lock(mutex); \ elapsedTime, #mutex); \
} \ } } \
} } else { \
ZSTD_pthread_mutex_lock(mutex); \
} \
} while (0)
#else #else
# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m) # 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 #endif
@@ -101,10 +105,10 @@ typedef struct ZSTDMT_bufferPool_s {
static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
{ {
unsigned u;
DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool); DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool);
if (!bufPool) return; /* compatibility with free on NULL */ if (!bufPool) return; /* compatibility with free on NULL */
if (bufPool->buffers) { if (bufPool->buffers) {
unsigned u;
for (u=0; u<bufPool->totalBuffers; u++) { for (u=0; u<bufPool->totalBuffers; u++) {
DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->buffers[u].start); DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->buffers[u].start);
ZSTD_customFree(bufPool->buffers[u].start, bufPool->cMem); 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 */ /* 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) static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
{ {
int cid;
if (!pool) return; if (!pool) return;
ZSTD_pthread_mutex_destroy(&pool->poolMutex); ZSTD_pthread_mutex_destroy(&pool->poolMutex);
if (pool->cctxs) { if (pool->cctxs) {
int cid;
for (cid=0; cid<pool->totalCCtx; cid++) for (cid=0; cid<pool->totalCCtx; cid++)
ZSTD_freeCCtx(pool->cctxs[cid]); /* free compatible with NULL */ ZSTD_freeCCtx(pool->cctxs[cid]); /* free compatible with NULL */
ZSTD_customFree(pool->cctxs, pool->cMem); ZSTD_customFree(pool->cctxs, pool->cMem);
@@ -667,12 +671,13 @@ typedef struct {
unsigned frameChecksumNeeded; /* used only by mtctx */ unsigned frameChecksumNeeded; /* used only by mtctx */
} ZSTDMT_jobDescription; } ZSTDMT_jobDescription;
#define JOB_ERROR(e) { \ #define JOB_ERROR(e) \
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \ do { \
job->cSize = e; \ ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \
ZSTD_pthread_mutex_unlock(&job->job_mutex); \ job->cSize = e; \
goto _endJob; \ ZSTD_pthread_mutex_unlock(&job->job_mutex); \
} goto _endJob; \
} while (0)
/* ZSTDMT_compressionJob() is a POOL_function type */ /* ZSTDMT_compressionJob() is a POOL_function type */
static void ZSTDMT_compressionJob(void* jobDescription) static void ZSTDMT_compressionJob(void* jobDescription)
@@ -1101,7 +1106,7 @@ ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
{ unsigned jobNb; { unsigned jobNb;
unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1); unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1);
DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)", 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++) { for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) {
unsigned const wJobID = jobNb & mtctx->jobIDMask; unsigned const wJobID = jobNb & mtctx->jobIDMask;
ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID]; ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID];
+179 -119
View File
@@ -34,6 +34,12 @@
* Macros * 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 /* These two optional macros force the use one way or another of the two
* Huffman decompression implementations. You can't force in both directions * Huffman decompression implementations. You can't force in both directions
* at the same time. * 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. * 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. * bits [in/out] - The bitstream containers, must be updated to reflect the current state.
* dt [in] - The decoding table. * 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. * 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], * 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 { typedef struct {
BYTE const* ip[4]; BYTE const* ip[4];
BYTE* op[4]; BYTE* op[4];
U64 bits[4]; U64 bits[4];
void const* dt; void const* dt;
BYTE const* ilimit; BYTE const* ilowest;
BYTE* oend; BYTE* oend;
BYTE const* iend[4]; BYTE const* iend[4];
} HUF_DecompressFastArgs; } HUF_DecompressFastArgs;
@@ -186,7 +193,7 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
void const* dt = DTable + 1; void const* dt = DTable + 1;
U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; 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); 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()) if (!MEM_isLittleEndian() || MEM_32bits())
return 0; return 0;
/* Avoid nullptr addition */
if (dstSize == 0)
return 0;
assert(dst != NULL);
/* strict minimum : jump table + 1 byte per stream */ /* strict minimum : jump table + 1 byte per stream */
if (srcSize < 10) if (srcSize < 10)
return ERROR(corruption_detected); return ERROR(corruption_detected);
@@ -209,7 +221,6 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
/* Read the jump table. */ /* Read the jump table. */
{ {
const BYTE* const istart = (const BYTE*)src;
size_t const length1 = MEM_readLE16(istart); size_t const length1 = MEM_readLE16(istart);
size_t const length2 = MEM_readLE16(istart+2); size_t const length2 = MEM_readLE16(istart+2);
size_t const length3 = MEM_readLE16(istart+4); 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 /* HUF_initFastDStream() requires this, and this small of an input
* won't benefit from the ASM loop anyways. * 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; return 0;
if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ 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[2] = HUF_initFastDStream(args->ip[2]);
args->bits[3] = HUF_initFastDStream(args->ip[3]); args->bits[3] = HUF_initFastDStream(args->ip[3]);
/* If ip[] >= ilimit, it is guaranteed to be safe to /* The decoders must be sure to never read beyond ilowest.
* reload bits[]. It may be beyond its section, but is * This is lower than iend[0], but allowing decoders to read
* guaranteed to be valid (>= istart). * down to ilowest can allow an extra iteration or two in the
*/ * fast loop.
args->ilimit = ilimit; */
args->ilowest = istart;
args->oend = oend; args->oend = oend;
args->dt = dt; args->dt = dt;
@@ -285,13 +295,31 @@ static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArg
assert(sizeof(size_t) == 8); assert(sizeof(size_t) == 8);
bit->bitContainer = MEM_readLEST(args->ip[stream]); bit->bitContainer = MEM_readLEST(args->ip[stream]);
bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[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->limitPtr = bit->start + sizeof(size_t);
bit->ptr = (const char*)args->ip[stream]; bit->ptr = (const char*)args->ip[stream];
return 0; 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 #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) \ #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) \ #define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ do { \
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \
} while (0)
#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ #define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
if (MEM_64bits()) \ do { \
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) if (MEM_64bits()) \
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \
} while (0)
HINT_INLINE size_t HINT_INLINE size_t
HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog) 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]; BYTE* op[4];
U16 const* const dtable = (U16 const*)args->dt; U16 const* const dtable = (U16 const*)args->dt;
BYTE* const oend = args->oend; BYTE* const oend = args->oend;
BYTE const* const ilimit = args->ilimit; BYTE const* const ilowest = args->ilowest;
/* Copy the arguments to local variables */ /* Copy the arguments to local variables */
ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); ZSTD_memcpy(&bits, &args->bits, sizeof(bits));
@@ -706,13 +738,12 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
for (;;) { for (;;) {
BYTE* olimit; BYTE* olimit;
int stream; int stream;
int symbol;
/* Assert loop preconditions */ /* Assert loop preconditions */
#ifndef NDEBUG #ifndef NDEBUG
for (stream = 0; stream < 4; ++stream) { for (stream = 0; stream < 4; ++stream) {
assert(op[stream] <= (stream == 3 ? oend : op[stream + 1])); assert(op[stream] <= (stream == 3 ? oend : op[stream + 1]));
assert(ip[stream] >= ilimit); assert(ip[stream] >= ilowest);
} }
#endif #endif
/* Compute olimit */ /* 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 /* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes
* per stream. * 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 */ /* We can safely run iters iterations before running bounds checks */
size_t const iters = MIN(oiters, iiters); size_t const iters = MIN(oiters, iiters);
size_t const symbols = iters * 5; size_t const symbols = iters * 5;
@@ -733,8 +764,8 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
*/ */
olimit = op[3] + symbols; olimit = op[3] + symbols;
/* Exit fast decoding loop once we get close to the end. */ /* Exit fast decoding loop once we reach the end. */
if (op[3] + 20 > olimit) if (op[3] == olimit)
break; break;
/* Exit the decoding loop if any input pointer has crossed the /* 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 #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 { do {
/* Decode 5 symbols in each of the 4 streams */ /* Decode 5 symbols in each of the 4 streams */
for (symbol = 0; symbol < 5; ++symbol) { HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 0);
for (stream = 0; stream < 4; ++stream) { HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 1);
int const index = (int)(bits[stream] >> 53); HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 2);
int const entry = (int)dtable[index]; HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 3);
bits[stream] <<= (entry & 63); HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 4);
op[stream][symbol] = (BYTE)((entry >> 8) & 0xFF);
} /* Reload each of the 4 the bitstreams */
} HUF_4X_FOR_EACH_STREAM(HUF_4X1_RELOAD_STREAM);
/* 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;
}
} while (op[3] < olimit); } while (op[3] < olimit);
#undef HUF_4X1_DECODE_SYMBOL
#undef HUF_4X1_RELOAD_STREAM
} }
_out: _out:
@@ -798,7 +844,7 @@ HUF_decompress4X1_usingDTable_internal_fast(
HUF_DecompressFastLoopFn loopFn) HUF_DecompressFastLoopFn loopFn)
{ {
void const* dt = DTable + 1; 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); BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
HUF_DecompressFastArgs args; HUF_DecompressFastArgs args;
{ size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); { size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable);
@@ -807,18 +853,22 @@ HUF_decompress4X1_usingDTable_internal_fast(
return 0; return 0;
} }
assert(args.ip[0] >= args.ilimit); assert(args.ip[0] >= args.ilowest);
loopFn(&args); 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[]. * overwritten any op[].
*/ */
assert(args.ip[0] >= iend); assert(args.ip[0] >= ilowest);
assert(args.ip[1] >= iend); assert(args.ip[0] >= ilowest);
assert(args.ip[2] >= iend); assert(args.ip[1] >= ilowest);
assert(args.ip[3] >= iend); assert(args.ip[2] >= ilowest);
assert(args.ip[3] >= ilowest);
assert(args.op[3] <= oend); 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. */ /* finish bit streams one by one. */
{ size_t const segmentSize = (dstSize+3) / 4; { size_t const segmentSize = (dstSize+3) / 4;
@@ -869,7 +919,7 @@ static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize,
} }
#endif #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); size_t const ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
if (ret != 0) if (ret != 0)
return ret; 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) \ #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) \ #define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ do { \
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \
} while (0)
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ #define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
if (MEM_64bits()) \ do { \
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) if (MEM_64bits()) \
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \
} while (0)
HINT_INLINE size_t HINT_INLINE size_t
HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, 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* op[4];
BYTE* oend[4]; BYTE* oend[4];
HUF_DEltX2 const* const dtable = (HUF_DEltX2 const*)args->dt; 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. */ /* Copy the arguments to local registers. */
ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); ZSTD_memcpy(&bits, &args->bits, sizeof(bits));
@@ -1492,13 +1546,12 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
for (;;) { for (;;) {
BYTE* olimit; BYTE* olimit;
int stream; int stream;
int symbol;
/* Assert loop preconditions */ /* Assert loop preconditions */
#ifndef NDEBUG #ifndef NDEBUG
for (stream = 0; stream < 4; ++stream) { for (stream = 0; stream < 4; ++stream) {
assert(op[stream] <= oend[stream]); assert(op[stream] <= oend[stream]);
assert(ip[stream] >= ilimit); assert(ip[stream] >= ilowest);
} }
#endif #endif
/* Compute olimit */ /* 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 * We also know that each input pointer is >= ip[0]. So we can run
* iters loops before running out of input. * 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 iteration can produce up to 10 bytes of output per stream.
* Each output stream my advance at different rates. So take the * Each output stream my advance at different rates. So take the
* minimum number of safe iterations among all the output streams. * 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); olimit = op[3] + (iters * 5);
/* Exit the fast decoding loop if we are too close to the end. */ /* Exit the fast decoding loop once we reach the end. */
if (op[3] + 10 > olimit) if (op[3] == olimit)
break; break;
/* Exit the decoding loop if any input pointer has crossed the /* 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 #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 {
/* Do 5 table lookups for each of the first 3 streams */ /* Decode 5 symbols from each of the first 3 streams.
for (symbol = 0; symbol < 5; ++symbol) { * The final stream will be decoded during the reload phase
for (stream = 0; stream < 3; ++stream) { * to reduce register pressure.
int const index = (int)(bits[stream] >> 53); */
HUF_DEltX2 const entry = dtable[index]; HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
MEM_write16(op[stream], entry.sequence); HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
bits[stream] <<= (entry.nbBits); HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
op[stream] += (entry.length); HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
} HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
}
/* Do 1 table lookup from the final stream */ /* Decode one symbol from the final stream */
{ HUF_4X2_DECODE_SYMBOL(3, 1);
int const index = (int)(bits[3] >> 53);
HUF_DEltX2 const entry = dtable[index]; /* Decode 4 symbols from the final stream & reload bitstreams.
MEM_write16(op[3], entry.sequence); * The final stream is reloaded last, meaning that all 5 symbols
bits[3] <<= (entry.nbBits); * are decoded from the final stream before it is reloaded.
op[3] += (entry.length); */
} HUF_4X_FOR_EACH_STREAM(HUF_4X2_RELOAD_STREAM);
/* 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;
}
}
} while (op[3] < olimit); } while (op[3] < olimit);
} }
#undef HUF_4X2_DECODE_SYMBOL
#undef HUF_4X2_RELOAD_STREAM
_out: _out:
/* Save the final values of each of the state variables back to args. */ /* 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, const HUF_DTable* DTable,
HUF_DecompressFastLoopFn loopFn) { HUF_DecompressFastLoopFn loopFn) {
void const* dt = DTable + 1; 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); BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
HUF_DecompressFastArgs args; HUF_DecompressFastArgs args;
{ {
@@ -1623,16 +1680,19 @@ HUF_decompress4X2_usingDTable_internal_fast(
return 0; return 0;
} }
assert(args.ip[0] >= args.ilimit); assert(args.ip[0] >= args.ilowest);
loopFn(&args); loopFn(&args);
/* note : op4 already verified within main loop */ /* note : op4 already verified within main loop */
assert(args.ip[0] >= iend); assert(args.ip[0] >= ilowest);
assert(args.ip[1] >= iend); assert(args.ip[1] >= ilowest);
assert(args.ip[2] >= iend); assert(args.ip[2] >= ilowest);
assert(args.ip[3] >= iend); assert(args.ip[3] >= ilowest);
assert(args.op[3] <= oend); assert(args.op[3] <= oend);
(void)iend;
assert(ilowest == args.ilowest);
assert(ilowest + 6 == args.iend[0]);
(void)ilowest;
/* finish bitStreams one by one */ /* finish bitStreams one by one */
{ {
@@ -1681,7 +1741,7 @@ static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize,
} }
#endif #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); size_t const ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
if (ret != 0) if (ret != 0)
return ret; return ret;
+16 -18
View File
@@ -131,7 +131,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
movq 88(%rax), %bits3 movq 88(%rax), %bits3
movq 96(%rax), %dtable movq 96(%rax), %dtable
push %rax /* argument */ push %rax /* argument */
push 104(%rax) /* ilimit */ push 104(%rax) /* ilowest */
push 112(%rax) /* oend */ push 112(%rax) /* oend */
push %olimit /* olimit space */ push %olimit /* olimit space */
@@ -156,11 +156,11 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
shrq $2, %r15 shrq $2, %r15
movq %ip0, %rax /* rax = ip0 */ movq %ip0, %rax /* rax = ip0 */
movq 40(%rsp), %rdx /* rdx = ilimit */ movq 40(%rsp), %rdx /* rdx = ilowest */
subq %rdx, %rax /* rax = ip0 - ilimit */ subq %rdx, %rax /* rax = ip0 - ilowest */
movq %rax, %rbx /* rbx = ip0 - ilimit */ movq %rax, %rbx /* rbx = ip0 - ilowest */
/* rdx = (ip0 - ilimit) / 7 */ /* rdx = (ip0 - ilowest) / 7 */
movabsq $2635249153387078803, %rdx movabsq $2635249153387078803, %rdx
mulq %rdx mulq %rdx
subq %rdx, %rbx subq %rdx, %rbx
@@ -183,9 +183,8 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
/* If (op3 + 20 > olimit) */ /* If (op3 + 20 > olimit) */
movq %op3, %rax /* rax = op3 */ movq %op3, %rax /* rax = op3 */
addq $20, %rax /* rax = op3 + 20 */ cmpq %rax, %olimit /* op3 == olimit */
cmpq %rax, %olimit /* op3 + 20 > olimit */ je .L_4X1_exit
jb .L_4X1_exit
/* If (ip1 < ip0) go to exit */ /* If (ip1 < ip0) go to exit */
cmpq %ip0, %ip1 cmpq %ip0, %ip1
@@ -316,7 +315,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
/* Restore stack (oend & olimit) */ /* Restore stack (oend & olimit) */
pop %rax /* olimit */ pop %rax /* olimit */
pop %rax /* oend */ pop %rax /* oend */
pop %rax /* ilimit */ pop %rax /* ilowest */
pop %rax /* arg */ pop %rax /* arg */
/* Save ip / op / bits */ /* Save ip / op / bits */
@@ -387,7 +386,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
movq 96(%rax), %dtable movq 96(%rax), %dtable
push %rax /* argument */ push %rax /* argument */
push %rax /* olimit */ push %rax /* olimit */
push 104(%rax) /* ilimit */ push 104(%rax) /* ilowest */
movq 112(%rax), %rax movq 112(%rax), %rax
push %rax /* oend3 */ push %rax /* oend3 */
@@ -414,9 +413,9 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
/* We can consume up to 7 input bytes each iteration. */ /* We can consume up to 7 input bytes each iteration. */
movq %ip0, %rax /* rax = ip0 */ movq %ip0, %rax /* rax = ip0 */
movq 40(%rsp), %rdx /* rdx = ilimit */ movq 40(%rsp), %rdx /* rdx = ilowest */
subq %rdx, %rax /* rax = ip0 - ilimit */ subq %rdx, %rax /* rax = ip0 - ilowest */
movq %rax, %r15 /* r15 = ip0 - ilimit */ movq %rax, %r15 /* r15 = ip0 - ilowest */
/* rdx = rax / 7 */ /* rdx = rax / 7 */
movabsq $2635249153387078803, %rdx movabsq $2635249153387078803, %rdx
@@ -426,7 +425,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
addq %r15, %rdx addq %r15, %rdx
shrq $2, %rdx shrq $2, %rdx
/* r15 = (ip0 - ilimit) / 7 */ /* r15 = (ip0 - ilowest) / 7 */
movq %rdx, %r15 movq %rdx, %r15
/* r15 = min(r15, min(oend0 - op0, oend1 - op1, oend2 - op2, oend3 - op3) / 10) */ /* 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) */ /* If (op3 + 10 > olimit) */
movq %op3, %rax /* rax = op3 */ movq %op3, %rax /* rax = op3 */
addq $10, %rax /* rax = op3 + 10 */ cmpq %rax, %olimit /* op3 == olimit */
cmpq %rax, %olimit /* op3 + 10 > olimit */ je .L_4X2_exit
jb .L_4X2_exit
/* If (ip1 < ip0) go to exit */ /* If (ip1 < ip0) go to exit */
cmpq %ip0, %ip1 cmpq %ip0, %ip1
@@ -537,7 +535,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
pop %rax /* oend1 */ pop %rax /* oend1 */
pop %rax /* oend2 */ pop %rax /* oend2 */
pop %rax /* oend3 */ pop %rax /* oend3 */
pop %rax /* ilimit */ pop %rax /* ilowest */
pop %rax /* olimit */ pop %rax /* olimit */
pop %rax /* arg */ pop %rax /* arg */
+11 -8
View File
@@ -55,18 +55,19 @@
/*-******************************************************* /*-*******************************************************
* Dependencies * Dependencies
*********************************************************/ *********************************************************/
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ #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/mem.h" /* low level memory routines */
#include "../common/bits.h" /* ZSTD_highbit32 */
#define FSE_STATIC_LINKING_ONLY #define FSE_STATIC_LINKING_ONLY
#include "../common/fse.h" #include "../common/fse.h"
#include "../common/huf.h" #include "../common/huf.h"
#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ #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_decompress_internal.h" /* ZSTD_DCtx */
#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd_ddict.h" /* ZSTD_DDictDictContent */
#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ #include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
#include "../common/bits.h" /* ZSTD_highbit32 */
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
# include "../legacy/zstd_legacy.h" # include "../legacy/zstd_legacy.h"
@@ -1023,12 +1024,14 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
default: default:
RETURN_ERROR(corruption_detected, "invalid block type"); RETURN_ERROR(corruption_detected, "invalid block type");
} }
FORWARD_IF_ERROR(decodedSize, "Block decompression failure");
if (ZSTD_isError(decodedSize)) return decodedSize; DEBUGLOG(5, "Decompressed block of dSize = %u", (unsigned)decodedSize);
if (dctx->validateChecksum) if (dctx->validateChecksum) {
XXH64_update(&dctx->xxhState, op, decodedSize); XXH64_update(&dctx->xxhState, op, decodedSize);
if (decodedSize != 0) }
if (decodedSize) /* support dst = NULL,0 */ {
op += decodedSize; op += decodedSize;
}
assert(ip != NULL); assert(ip != NULL);
ip += cBlockSize; ip += cBlockSize;
remainingSrcSize -= cBlockSize; remainingSrcSize -= cBlockSize;
@@ -2173,7 +2176,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
/* shortcut : using single-pass mode */ /* shortcut : using single-pass mode */
size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds)); size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
if (ZSTD_isError(decompressedSize)) return decompressedSize; 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); assert(istart != NULL);
ip = istart + cSize; ip = istart + cSize;
op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */ op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */
+12 -7
View File
@@ -1585,7 +1585,8 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx,
/* last literal segment */ /* last literal segment */
if (dctx->litBufferLocation == ZSTD_split) { if (dctx->litBufferLocation == ZSTD_split) {
/* split hasn't been reached yet, first get dst then copy litExtraBuffer */ /* 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, ""); RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, "");
if (op != NULL) { if (op != NULL) {
ZSTD_memmove(op, litPtr, lastLLSize); ZSTD_memmove(op, litPtr, lastLLSize);
@@ -1596,14 +1597,16 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx,
dctx->litBufferLocation = ZSTD_not_in_dst; dctx->litBufferLocation = ZSTD_not_in_dst;
} }
/* copy last literals from internal buffer */ /* 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, ""); RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
if (op != NULL) { if (op != NULL) {
ZSTD_memcpy(op, litPtr, lastLLSize); ZSTD_memcpy(op, litPtr, lastLLSize);
op += 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 FORCE_INLINE_TEMPLATE size_t
@@ -1673,14 +1676,16 @@ ZSTD_decompressSequences_body(ZSTD_DCtx* dctx,
} }
/* last literal segment */ /* 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, ""); RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
if (op != NULL) { if (op != NULL) {
ZSTD_memcpy(op, litPtr, lastLLSize); ZSTD_memcpy(op, litPtr, lastLLSize);
op += 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 static size_t
@@ -1878,7 +1883,7 @@ ZSTD_decompressSequencesLong_body(
} }
} }
return op-ostart; return (size_t)(op - ostart);
} }
static size_t static size_t
@@ -2068,7 +2073,7 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
const void* src, size_t srcSize, const streaming_operation streaming) const void* src, size_t srcSize, const streaming_operation streaming)
{ /* blockType == blockCompressed */ { /* blockType == blockCompressed */
const BYTE* ip = (const BYTE*)src; 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 /* Note : the wording of the specification
* allows compressed block to be sized exactly ZSTD_blockSizeMax(dctx). * allows compressed block to be sized exactly ZSTD_blockSizeMax(dctx).
+12 -6
View File
@@ -74,9 +74,9 @@ static const U32 g_selectivity_default = 9;
* Console display * Console display
***************************************/ ***************************************/
#undef DISPLAY #undef DISPLAY
#define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } #define DISPLAY(...) do { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } while (0)
#undef DISPLAYLEVEL #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; } 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; clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10;
# undef DISPLAYUPDATE # undef DISPLAYUPDATE
# define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \ # define DISPLAYUPDATE(l, ...) \
if (ZDICT_clockSpan(displayClock) > refreshRate) \ do { \
{ displayClock = clock(); DISPLAY(__VA_ARGS__); \ if (notificationLevel>=l) { \
if (notificationLevel>=4) fflush(stderr); } } if (ZDICT_clockSpan(displayClock) > refreshRate) { \
displayClock = clock(); \
DISPLAY(__VA_ARGS__); \
} \
if (notificationLevel>=4) fflush(stderr); \
} \
} while (0)
/* init */ /* init */
DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */
+18 -5
View File
@@ -1665,9 +1665,6 @@ ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size);
* *
* Note : only single-threaded compression is supported. * Note : only single-threaded compression is supported.
* ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. * 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(int maxCompressionLevel);
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); 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)) #define ZSTD_SEQUENCE_PRODUCER_ERROR ((size_t)(-1))
typedef size_t ZSTD_sequenceProducer_F ( typedef size_t (*ZSTD_sequenceProducer_F) (
void* sequenceProducerState, void* sequenceProducerState,
ZSTD_Sequence* outSeqs, size_t outSeqsCapacity, ZSTD_Sequence* outSeqs, size_t outSeqsCapacity,
const void* src, size_t srcSize, const void* src, size_t srcSize,
@@ -2821,7 +2818,23 @@ ZSTDLIB_STATIC_API void
ZSTD_registerSequenceProducer( ZSTD_registerSequenceProducer(
ZSTD_CCtx* cctx, ZSTD_CCtx* cctx,
void* sequenceProducerState, 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
View File
@@ -108,7 +108,6 @@ static BMK_runOutcome_t BMK_setValid_runTime(BMK_runTime_t runTime)
BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t p, BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t p,
unsigned nbLoops) unsigned nbLoops)
{ {
size_t dstSize = 0;
nbLoops += !nbLoops; /* minimum nbLoops is 1 */ nbLoops += !nbLoops; /* minimum nbLoops is 1 */
/* init */ /* init */
@@ -118,7 +117,8 @@ BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t p,
} } } }
/* benchmark */ /* benchmark */
{ UTIL_time_t const clockStart = UTIL_getTime(); { size_t dstSize = 0;
UTIL_time_t const clockStart = UTIL_getTime();
unsigned loopNb, blockNb; unsigned loopNb, blockNb;
if (p.initFn != NULL) p.initFn(p.initPayload); if (p.initFn != NULL) p.initFn(p.initPayload);
for (loopNb = 0; loopNb < nbLoops; loopNb++) { for (loopNb = 0; loopNb < nbLoops; loopNb++) {
+768 -418
View File
@@ -8,197 +8,286 @@
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
/* ************************************** /* **************************************
* Tuning parameters * Tuning parameters
****************************************/ ****************************************/
#ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */ #ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */
# define BMK_TIMETEST_DEFAULT_S 3 # define BMK_TIMETEST_DEFAULT_S 3
#endif #endif
/* ************************************* /* *************************************
* Includes * Includes
***************************************/ ***************************************/
#include "platform.h" /* Large Files support */ /* this must be included first */
#include "util.h" /* UTIL_getFileSize, UTIL_sleep */ #include "platform.h" /* Large Files support, compiler specifics */
#include <stdlib.h> /* malloc, free */
#include <string.h> /* memset, strerror */
#include <stdio.h> /* fprintf, fopen */
#include <errno.h>
#include <assert.h> /* assert */
#include "timefn.h" /* UTIL_time_t */ /* then following system includes */
#include "benchfn.h" #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 "../lib/common/mem.h"
#include "benchfn.h"
#include "timefn.h" /* UTIL_time_t */
#ifndef ZSTD_STATIC_LINKING_ONLY #ifndef ZSTD_STATIC_LINKING_ONLY
#define ZSTD_STATIC_LINKING_ONLY # define ZSTD_STATIC_LINKING_ONLY
#endif #endif
#include "../lib/zstd.h" #include "../lib/zstd.h"
#include "datagen.h" /* RDG_genBuffer */ #include "datagen.h" /* RDG_genBuffer */
#include "lorem.h" /* LOREM_genBuffer */
#ifndef XXH_INLINE_ALL #ifndef XXH_INLINE_ALL
#define XXH_INLINE_ALL # define XXH_INLINE_ALL
#endif #endif
#include "../lib/common/xxhash.h" #include "../lib/common/xxhash.h"
#include "benchzstd.h"
#include "../lib/zstd_errors.h" #include "../lib/zstd_errors.h"
#include "benchzstd.h"
/* ************************************* /* *************************************
* Constants * Constants
***************************************/ ***************************************/
#ifndef ZSTD_GIT_COMMIT #ifndef ZSTD_GIT_COMMIT
# define ZSTD_GIT_COMMIT_STRING "" # define ZSTD_GIT_COMMIT_STRING ""
#else #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 #endif
#define TIMELOOP_MICROSEC (1*1000000ULL) /* 1 second */ #define TIMELOOP_MICROSEC (1 * 1000000ULL) /* 1 second */
#define TIMELOOP_NANOSEC (1*1000000000ULL) /* 1 second */ #define TIMELOOP_NANOSEC (1 * 1000000000ULL) /* 1 second */
#define ACTIVEPERIOD_MICROSEC (70*TIMELOOP_MICROSEC) /* 70 seconds */ #define ACTIVEPERIOD_MICROSEC (70 * TIMELOOP_MICROSEC) /* 70 seconds */
#define COOLPERIOD_SEC 10 #define COOLPERIOD_SEC 10
#define KB *(1 <<10) #define KB *(1 << 10)
#define MB *(1 <<20) #define MB *(1 << 20)
#define GB *(1U<<30) #define GB *(1U << 30)
#define BMK_RUNTEST_DEFAULT_MS 1000 #define BMK_RUNTEST_DEFAULT_MS 1000
static const size_t maxMemory = (sizeof(size_t)==4) ? 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)); /* 32-bit */ (2 GB - 64 MB)
:
/* 64-bit */ (size_t)(1ULL << ((sizeof(size_t) * 8) - 31));
/* ************************************* /* *************************************
* console display * console display
***************************************/ ***************************************/
#define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush(NULL); } #define DISPLAY(...) \
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } { \
/* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */ fprintf(stderr, __VA_ARGS__); \
#define OUTPUT(...) { fprintf(stdout, __VA_ARGS__); fflush(NULL); } fflush(NULL); \
#define OUTPUTLEVEL(l, ...) if (displayLevel>=l) { OUTPUT(__VA_ARGS__); } }
#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 #ifndef DEBUG
# define DEBUG 0 # define DEBUG 0
#endif #endif
#define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); } #define DEBUGOUTPUT(...) \
{ \
if (DEBUG) \
DISPLAY(__VA_ARGS__); \
}
#define RETURN_ERROR_INT(errorNum, ...) { \ #define RETURN_ERROR_INT(errorNum, ...) \
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \ { \
DISPLAYLEVEL(1, "Error %i : ", errorNum); \ DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
DISPLAYLEVEL(1, __VA_ARGS__); \ DISPLAYLEVEL(1, "Error %i : ", errorNum); \
DISPLAYLEVEL(1, " \n"); \ DISPLAYLEVEL(1, __VA_ARGS__); \
return errorNum; \ 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_advancedParams_t const res = {
BMK_both, /* mode */ BMK_both, /* mode */
BMK_TIMETEST_DEFAULT_S, /* nbSeconds */ BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
0, /* blockSize */ 0, /* blockSize */
0, /* nbWorkers */ 0, /* targetCBlockSize */
0, /* realTime */ 0, /* nbWorkers */
0, /* additionalParam */ 0, /* realTime */
0, /* ldmFlag */ 0, /* additionalParam */
0, /* ldmMinMatch */ 0, /* ldmFlag */
0, /* ldmHashLog */ 0, /* ldmMinMatch */
0, /* ldmBuckSizeLog */ 0, /* ldmHashLog */
0, /* ldmHashRateLog */ 0, /* ldmBuckSizeLog */
ZSTD_ps_auto, /* literalCompressionMode */ 0, /* ldmHashRateLog */
0 /* useRowMatchFinder */ ZSTD_ps_auto, /* literalCompressionMode */
0 /* useRowMatchFinder */
}; };
return res; return res;
} }
/* ******************************************************** /* ********************************************************
* Bench functions * Bench functions
**********************************************************/ **********************************************************/
typedef struct { typedef struct {
const void* srcPtr; const void* srcPtr;
size_t srcSize; size_t srcSize;
void* cPtr; void* cPtr;
size_t cRoom; size_t cRoom;
size_t cSize; size_t cSize;
void* resPtr; void* resPtr;
size_t resSize; size_t resSize;
} blockParam_t; } blockParam_t;
#undef MIN #undef MIN
#undef MAX #undef MAX
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b))
static void static void BMK_initCCtx(
BMK_initCCtx(ZSTD_CCtx* ctx, ZSTD_CCtx* ctx,
const void* dictBuffer, size_t dictBufferSize, const void* dictBuffer,
int cLevel, size_t dictBufferSize,
const ZSTD_compressionParameters* comprParams, int cLevel,
const BMK_advancedParams_t* adv) const ZSTD_compressionParameters* comprParams,
const BMK_advancedParams_t* adv)
{ {
ZSTD_CCtx_reset(ctx, ZSTD_reset_session_and_parameters); 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)); CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, 0));
} else { } else {
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, adv->nbWorkers)); 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_compressionLevel, cLevel));
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_useRowMatchFinder, adv->useRowMatchFinder)); CHECK_Z(ZSTD_CCtx_setParameter(
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag)); 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_ldmMinMatch, adv->ldmMinMatch));
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashLog, adv->ldmHashLog)); 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(
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog)); ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_windowLog, (int)comprParams->windowLog)); CHECK_Z(ZSTD_CCtx_setParameter(
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_hashLog, (int)comprParams->hashLog)); ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_chainLog, (int)comprParams->chainLog)); CHECK_Z(ZSTD_CCtx_setParameter(
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_searchLog, (int)comprParams->searchLog)); ctx, ZSTD_c_windowLog, (int)comprParams->windowLog));
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_minMatch, (int)comprParams->minMatch)); CHECK_Z(ZSTD_CCtx_setParameter(
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_targetLength, (int)comprParams->targetLength)); ctx, ZSTD_c_hashLog, (int)comprParams->hashLog));
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_literalCompressionMode, (int)adv->literalCompressionMode)); CHECK_Z(ZSTD_CCtx_setParameter(
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_strategy, (int)comprParams->strategy)); 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)); CHECK_Z(ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize));
} }
static void BMK_initDCtx(ZSTD_DCtx* dctx, static void
const void* dictBuffer, size_t dictBufferSize) { 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_reset(dctx, ZSTD_reset_session_and_parameters));
CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize)); CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize));
} }
typedef struct { typedef struct {
ZSTD_CCtx* cctx; ZSTD_CCtx* cctx;
const void* dictBuffer; const void* dictBuffer;
@@ -208,9 +297,16 @@ typedef struct {
const BMK_advancedParams_t* adv; const BMK_advancedParams_t* adv;
} BMK_initCCtxArgs; } BMK_initCCtxArgs;
static size_t local_initCCtx(void* payload) { static size_t local_initCCtx(void* payload)
{
BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)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; return 0;
} }
@@ -220,18 +316,20 @@ typedef struct {
size_t dictBufferSize; size_t dictBufferSize;
} BMK_initDCtxArgs; } BMK_initDCtxArgs;
static size_t local_initDCtx(void* payload) { static size_t local_initDCtx(void* payload)
{
BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload; BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize); BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
return 0; return 0;
} }
/* `addArgs` is the context */ /* `addArgs` is the context */
static size_t local_defaultCompress( static size_t local_defaultCompress(
const void* srcBuffer, size_t srcSize, const void* srcBuffer,
void* dstBuffer, size_t dstSize, size_t srcSize,
void* addArgs) void* dstBuffer,
size_t dstSize,
void* addArgs)
{ {
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs; ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize); return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize);
@@ -239,18 +337,24 @@ static size_t local_defaultCompress(
/* `addArgs` is the context */ /* `addArgs` is the context */
static size_t local_defaultDecompress( static size_t local_defaultDecompress(
const void* srcBuffer, size_t srcSize, const void* srcBuffer,
void* dstBuffer, size_t dstCapacity, size_t srcSize,
void* addArgs) void* dstBuffer,
size_t dstCapacity,
void* addArgs)
{ {
size_t moreToFlush = 1; size_t moreToFlush = 1;
ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs; ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
ZSTD_inBuffer in; ZSTD_inBuffer in;
ZSTD_outBuffer out; ZSTD_outBuffer out;
in.src = srcBuffer; in.size = srcSize; in.pos = 0; in.src = srcBuffer;
out.dst = dstBuffer; out.size = dstCapacity; out.pos = 0; in.size = srcSize;
in.pos = 0;
out.dst = dstBuffer;
out.size = dstCapacity;
out.pos = 0;
while (moreToFlush) { while (moreToFlush) {
if(out.pos == out.size) { if (out.pos == out.size) {
return (size_t)-ZSTD_error_dstSize_tooSmall; return (size_t)-ZSTD_error_dstSize_tooSmall;
} }
moreToFlush = ZSTD_decompressStream(dctx, &out, &in); moreToFlush = ZSTD_decompressStream(dctx, &out, &in);
@@ -259,10 +363,8 @@ static size_t local_defaultDecompress(
} }
} }
return out.pos; return out.pos;
} }
/* ================================================================= */ /* ================================================================= */
/* Benchmark Zstandard, mem-to-mem scenarios */ /* Benchmark Zstandard, mem-to-mem scenarios */
/* ================================================================= */ /* ================================================================= */
@@ -286,104 +388,145 @@ static BMK_benchOutcome_t BMK_benchOutcome_error(void)
return b; 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; BMK_benchOutcome_t b;
b.tag = 0; b.tag = 0;
b.internal_never_use_directly = result; b.internal_never_use_directly = result;
return b; return b;
} }
/* benchMem with no allocation */ /* benchMem with no allocation */
static BMK_benchOutcome_t static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc(
BMK_benchMemAdvancedNoAlloc( const void** srcPtrs,
const void** srcPtrs, size_t* srcSizes, size_t* srcSizes,
void** cPtrs, size_t* cCapacities, size_t* cSizes, void** cPtrs,
void** resPtrs, size_t* resSizes, size_t* cCapacities,
void** resultBufferPtr, void* compressedBuffer, size_t* cSizes,
size_t maxCompressedSize, void** resPtrs,
BMK_timedFnState_t* timeStateCompress, size_t* resSizes,
BMK_timedFnState_t* timeStateDecompress, void** resultBufferPtr,
void* compressedBuffer,
size_t maxCompressedSize,
BMK_timedFnState_t* timeStateCompress,
BMK_timedFnState_t* timeStateDecompress,
const void* srcBuffer, size_t srcSize, const void* srcBuffer,
const size_t* fileSizes, unsigned nbFiles, size_t srcSize,
const int cLevel, const size_t* fileSizes,
const ZSTD_compressionParameters* comprParams, unsigned nbFiles,
const void* dictBuffer, size_t dictBufferSize, const int cLevel,
ZSTD_CCtx* cctx, ZSTD_DCtx* dctx, const ZSTD_compressionParameters* comprParams,
int displayLevel, const char* displayName, const void* dictBuffer,
const BMK_advancedParams_t* adv) 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; BMK_benchResult_t benchResult;
size_t const loadedCompressedSize = srcSize; size_t const loadedCompressedSize = srcSize;
size_t cSize = 0; size_t cSize = 0;
double ratio = 0.; double ratio = 0.;
U32 nbBlocks; U32 nbBlocks;
assert(cctx != NULL); assert(dctx != NULL); assert(cctx != NULL);
assert(dctx != NULL);
/* init */ /* init */
memset(&benchResult, 0, sizeof(benchResult)); 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) { if (adv->mode == BMK_decodeOnly) {
/* benchmark only decompression : source must be already compressed */ /* benchmark only decompression : source must be already compressed */
const char* srcPtr = (const char*)srcBuffer; const char* srcPtr = (const char*)srcBuffer;
U64 totalDSize64 = 0; U64 totalDSize64 = 0;
U32 fileNb; U32 fileNb;
for (fileNb=0; fileNb<nbFiles; fileNb++) { for (fileNb = 0; fileNb < nbFiles; fileNb++) {
U64 const fSize64 = ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]); U64 const fSize64 =
ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
if (fSize64 == ZSTD_CONTENTSIZE_UNKNOWN) { 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) { 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; totalDSize64 += fSize64;
srcPtr += fileSizes[fileNb]; 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); free(*resultBufferPtr);
if (totalDSize64 > decodedSize) { /* size_t overflow */ if (totalDSize64 > decodedSize) { /* size_t overflow */
RETURN_ERROR(32, BMK_benchOutcome_t, "decompressed size is too large for local system"); RETURN_ERROR(
32,
BMK_benchOutcome_t,
"decompressed size is too large for local system");
} }
*resultBufferPtr = malloc(decodedSize); *resultBufferPtr = malloc(decodedSize);
if (!(*resultBufferPtr)) { 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; srcSize = decodedSize;
ratio = (double)srcSize / (double)cSize; ratio = (double)srcSize / (double)cSize;
} }
} }
/* Init data blocks */ /* Init data blocks */
{ const char* srcPtr = (const char*)srcBuffer; {
char* cPtr = (char*)compressedBuffer; const char* srcPtr = (const char*)srcBuffer;
char* resPtr = (char*)(*resultBufferPtr); char* cPtr = (char*)compressedBuffer;
char* resPtr = (char*)(*resultBufferPtr);
U32 fileNb; U32 fileNb;
for (nbBlocks=0, fileNb=0; fileNb<nbFiles; fileNb++) { for (nbBlocks = 0, fileNb = 0; fileNb < nbFiles; fileNb++) {
size_t remaining = fileSizes[fileNb]; size_t remaining = fileSizes[fileNb];
U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly) ? 1 : (U32)((remaining + (blockSize-1)) / blockSize); U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly)
U32 const blockEnd = nbBlocks + nbBlocksforThisFile; ? 1
for ( ; nbBlocks<blockEnd; nbBlocks++) { : (U32)((remaining + (blockSize - 1)) / blockSize);
U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
for (; nbBlocks < blockEnd; nbBlocks++) {
size_t const thisBlockSize = MIN(remaining, blockSize); size_t const thisBlockSize = MIN(remaining, blockSize);
srcPtrs[nbBlocks] = srcPtr; srcPtrs[nbBlocks] = srcPtr;
srcSizes[nbBlocks] = thisBlockSize; srcSizes[nbBlocks] = thisBlockSize;
cPtrs[nbBlocks] = cPtr; cPtrs[nbBlocks] = cPtr;
cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly) ? thisBlockSize : ZSTD_compressBound(thisBlockSize); cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly)
resPtrs[nbBlocks] = resPtr; ? thisBlockSize
resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly) ? (size_t) ZSTD_findDecompressedSize(srcPtr, thisBlockSize) : thisBlockSize; : ZSTD_compressBound(thisBlockSize);
resPtrs[nbBlocks] = resPtr;
resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly)
? (size_t)ZSTD_findDecompressedSize(
srcPtr, thisBlockSize)
: thisBlockSize;
srcPtr += thisBlockSize; srcPtr += thisBlockSize;
cPtr += cCapacities[nbBlocks]; cPtr += cCapacities[nbBlocks];
resPtr += thisBlockSize; resPtr += thisBlockSize;
remaining -= thisBlockSize; remaining -= thisBlockSize;
if (adv->mode == BMK_decodeOnly) { if (adv->mode == BMK_decodeOnly) {
cSizes[nbBlocks] = thisBlockSize; cSizes[nbBlocks] = thisBlockSize;
benchResult.cSize = thisBlockSize; benchResult.cSize = thisBlockSize;
} } } } }
}
}
}
/* warming up `compressedBuffer` */ /* warming up `compressedBuffer` */
if (adv->mode == BMK_decodeOnly) { if (adv->mode == BMK_decodeOnly) {
@@ -393,236 +536,329 @@ BMK_benchMemAdvancedNoAlloc(
} }
if (!UTIL_support_MT_measurements() && adv->nbWorkers > 1) { 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 */ /* 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] = { " |", " /", " =", " \\" }; const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
U32 markNb = 0; U32 markNb = 0;
int compressionCompleted = (adv->mode == BMK_decodeOnly); int compressionCompleted = (adv->mode == BMK_decodeOnly);
int decompressionCompleted = (adv->mode == BMK_compressOnly); int decompressionCompleted = (adv->mode == BMK_compressOnly);
BMK_benchParams_t cbp, dbp; BMK_benchParams_t cbp, dbp;
BMK_initCCtxArgs cctxprep; BMK_initCCtxArgs cctxprep;
BMK_initDCtxArgs dctxprep; BMK_initDCtxArgs dctxprep;
cbp.benchFn = local_defaultCompress; /* ZSTD_compress2 */ cbp.benchFn = local_defaultCompress; /* ZSTD_compress2 */
cbp.benchPayload = cctx; cbp.benchPayload = cctx;
cbp.initFn = local_initCCtx; /* BMK_initCCtx */ cbp.initFn = local_initCCtx; /* BMK_initCCtx */
cbp.initPayload = &cctxprep; cbp.initPayload = &cctxprep;
cbp.errorFn = ZSTD_isError; cbp.errorFn = ZSTD_isError;
cbp.blockCount = nbBlocks; cbp.blockCount = nbBlocks;
cbp.srcBuffers = srcPtrs; cbp.srcBuffers = srcPtrs;
cbp.srcSizes = srcSizes; cbp.srcSizes = srcSizes;
cbp.dstBuffers = cPtrs; cbp.dstBuffers = cPtrs;
cbp.dstCapacities = cCapacities; cbp.dstCapacities = cCapacities;
cbp.blockResults = cSizes; cbp.blockResults = cSizes;
cctxprep.cctx = cctx; cctxprep.cctx = cctx;
cctxprep.dictBuffer = dictBuffer; cctxprep.dictBuffer = dictBuffer;
cctxprep.dictBufferSize = dictBufferSize; cctxprep.dictBufferSize = dictBufferSize;
cctxprep.cLevel = cLevel; cctxprep.cLevel = cLevel;
cctxprep.comprParams = comprParams; cctxprep.comprParams = comprParams;
cctxprep.adv = adv; cctxprep.adv = adv;
dbp.benchFn = local_defaultDecompress; dbp.benchFn = local_defaultDecompress;
dbp.benchPayload = dctx; dbp.benchPayload = dctx;
dbp.initFn = local_initDCtx; dbp.initFn = local_initDCtx;
dbp.initPayload = &dctxprep; dbp.initPayload = &dctxprep;
dbp.errorFn = ZSTD_isError; dbp.errorFn = ZSTD_isError;
dbp.blockCount = nbBlocks; dbp.blockCount = nbBlocks;
dbp.srcBuffers = (const void* const *) cPtrs; dbp.srcBuffers = (const void* const*)cPtrs;
dbp.srcSizes = cSizes; dbp.srcSizes = cSizes;
dbp.dstBuffers = resPtrs; dbp.dstBuffers = resPtrs;
dbp.dstCapacities = resSizes; dbp.dstCapacities = resSizes;
dbp.blockResults = NULL; dbp.blockResults = NULL;
dctxprep.dctx = dctx; dctxprep.dctx = dctx;
dctxprep.dictBuffer = dictBuffer; dctxprep.dictBuffer = dictBuffer;
dctxprep.dictBufferSize = dictBufferSize; dctxprep.dictBufferSize = dictBufferSize;
OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */ OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */
assert(srcSize < UINT_MAX); 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)) { while (!(compressionCompleted && decompressionCompleted)) {
if (!compressionCompleted) { 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)) { if (!BMK_isSuccessful_runOutcome(cOutcome)) {
RETURN_ERROR(30, BMK_benchOutcome_t, "compression error"); 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; 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; benchResult.cSize = cSize;
if (newResult.cSpeed > benchResult.cSpeed) if (newResult.cSpeed > benchResult.cSpeed)
benchResult.cSpeed = newResult.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) { if (!decompressionCompleted) {
BMK_runOutcome_t const dOutcome = BMK_benchTimedFn(timeStateDecompress, dbp); 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"); 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) if (newDSpeed > benchResult.dSpeed)
benchResult.dSpeed = newDSpeed; 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", int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
marks[markNb], displayName, OUTPUTLEVEL(
(unsigned)srcSize, (unsigned)cSize, 2,
ratioAccuracy, ratio, "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s, %6.1f MB/s\r",
benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT, 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); (double)benchResult.dSpeed / MB_UNIT);
} }
decompressionCompleted = BMK_isCompleted_TimedFn(timeStateDecompress); decompressionCompleted =
BMK_isCompleted_TimedFn(timeStateDecompress);
} }
markNb = (markNb+1) % NB_MARKS; markNb = (markNb + 1) % NB_MARKS;
} /* while (!(compressionCompleted && decompressionCompleted)) */ } /* while (!(compressionCompleted && decompressionCompleted)) */
/* CRC Checking */ /* CRC Checking */
{ const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr); {
U64 const crcCheck = XXH64(resultBuffer, srcSize, 0); const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) { U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
if ((adv->mode == BMK_both) && (crcOrig != crcCheck)) {
size_t u; size_t u;
DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n", DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n",
displayName, (unsigned)crcOrig, (unsigned)crcCheck); displayName,
for (u=0; u<srcSize; u++) { (unsigned)crcOrig,
(unsigned)crcCheck);
for (u = 0; u < srcSize; u++) {
if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) { if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
unsigned segNb, bNb, pos; unsigned segNb, bNb, pos;
size_t bacc = 0; size_t bacc = 0;
DISPLAY("Decoding error at pos %u ", (unsigned)u); DISPLAY("Decoding error at pos %u ", (unsigned)u);
for (segNb = 0; segNb < nbBlocks; segNb++) { for (segNb = 0; segNb < nbBlocks; segNb++) {
if (bacc + srcSizes[segNb] > u) break; if (bacc + srcSizes[segNb] > u)
break;
bacc += srcSizes[segNb]; bacc += srcSizes[segNb];
} }
pos = (U32)(u - bacc); pos = (U32)(u - bacc);
bNb = pos / (128 KB); bNb = pos / (128 KB);
DISPLAY("(sample %u, block %u, pos %u) \n", segNb, bNb, pos); DISPLAY("(sample %u, block %u, pos %u) \n",
{ size_t const lowest = (u>5) ? 5 : u; segNb,
bNb,
pos);
{
size_t const lowest = (u > 5) ? 5 : u;
size_t n; size_t n;
DISPLAY("origin: "); DISPLAY("origin: ");
for (n=lowest; n>0; n--) for (n = lowest; n > 0; n--)
DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u-n]); DISPLAY("%02X ",
((const BYTE*)srcBuffer)[u - n]);
DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]); DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]);
for (n=1; n<3; n++) for (n = 1; n < 3; n++)
DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]); DISPLAY("%02X ",
((const BYTE*)srcBuffer)[u + n]);
DISPLAY(" \n"); DISPLAY(" \n");
DISPLAY("decode: "); DISPLAY("decode: ");
for (n=lowest; n>0; n--) for (n = lowest; n > 0; n--)
DISPLAY("%02X ", resultBuffer[u-n]); DISPLAY("%02X ", resultBuffer[u - n]);
DISPLAY(" :%02X: ", resultBuffer[u]); DISPLAY(" :%02X: ", resultBuffer[u]);
for (n=1; n<3; n++) for (n = 1; n < 3; n++)
DISPLAY("%02X ", resultBuffer[u+n]); DISPLAY("%02X ", resultBuffer[u + n]);
DISPLAY(" \n"); DISPLAY(" \n");
} }
break; break;
} }
if (u==srcSize-1) { /* should never happen */ if (u == srcSize - 1) { /* should never happen */
DISPLAY("no difference detected\n"); DISPLAY("no difference detected\n");
} }
} /* for (u=0; u<srcSize; u++) */ } /* for (u=0; u<srcSize; u++) */
} /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */ } /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */
} /* CRC Checking */ } /* 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 cSpeed = (double)benchResult.cSpeed / MB_UNIT;
double const dSpeed = (double)benchResult.dSpeed / MB_UNIT; double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
if (adv->additionalParam) { 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 { } 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); 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); return BMK_benchOutcome_setValidResult(benchResult);
} }
BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize, BMK_benchOutcome_t BMK_benchMemAdvanced(
void* dstBuffer, size_t dstCapacity, const void* srcBuffer,
const size_t* fileSizes, unsigned nbFiles, size_t srcSize,
int cLevel, const ZSTD_compressionParameters* comprParams, void* dstBuffer,
const void* dictBuffer, size_t dictBufferSize, size_t dstCapacity,
int displayLevel, const char* displayName, const BMK_advancedParams_t* adv) 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 */ ; size_t const blockSize =
U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles; ((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 */ /* 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)); size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
void** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
void ** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*)); size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
size_t* const cCapacities = (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)); 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* timeStateCompress = BMK_createTimedFnState(
BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS); 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_CCtx* const cctx = ZSTD_createCCtx();
ZSTD_DCtx* const dctx = ZSTD_createDCtx(); 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; 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; void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs || int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs || !cSizes
!cSizes || !cCapacities || !resPtrs || !resSizes || || !cCapacities || !resPtrs || !resSizes || !timeStateCompress
!timeStateCompress || !timeStateDecompress || || !timeStateDecompress || !cctx || !dctx || !compressedBuffer
!cctx || !dctx || || !resultBuffer;
!compressedBuffer || !resultBuffer;
if (!allocationincomplete && !dstParamsError) { if (!allocationincomplete && !dstParamsError) {
outcome = BMK_benchMemAdvancedNoAlloc(srcPtrs, srcSizes, outcome = BMK_benchMemAdvancedNoAlloc(
cPtrs, cCapacities, cSizes, srcPtrs,
resPtrs, resSizes, srcSizes,
&resultBuffer, cPtrs,
compressedBuffer, maxCompressedSize, cCapacities,
timeStateCompress, timeStateDecompress, cSizes,
srcBuffer, srcSize, resPtrs,
fileSizes, nbFiles, resSizes,
cLevel, comprParams, &resultBuffer,
dictBuffer, dictBufferSize, compressedBuffer,
cctx, dctx, maxCompressedSize,
displayLevel, displayName, adv); timeStateCompress,
timeStateDecompress,
srcBuffer,
srcSize,
fileSizes,
nbFiles,
cLevel,
comprParams,
dictBuffer,
dictBufferSize,
cctx,
dctx,
displayLevel,
displayName,
adv);
} }
/* clean up */ /* clean up */
@@ -643,66 +879,104 @@ BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
free(resPtrs); free(resPtrs);
free(resSizes); free(resSizes);
if(allocationincomplete) { if (allocationincomplete) {
RETURN_ERROR(31, BMK_benchOutcome_t, "allocation error : not enough memory"); 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_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
} }
return outcome; return outcome;
} }
BMK_benchOutcome_t BMK_benchMem(const void* srcBuffer, size_t srcSize, BMK_benchOutcome_t BMK_benchMem(
const size_t* fileSizes, unsigned nbFiles, const void* srcBuffer,
int cLevel, const ZSTD_compressionParameters* comprParams, size_t srcSize,
const void* dictBuffer, size_t dictBufferSize, const size_t* fileSizes,
int displayLevel, const char* displayName) { 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(); BMK_advancedParams_t const adv = BMK_initAdvancedParams();
return BMK_benchMemAdvanced(srcBuffer, srcSize, return BMK_benchMemAdvanced(
NULL, 0, srcBuffer,
fileSizes, nbFiles, srcSize,
cLevel, comprParams, NULL,
dictBuffer, dictBufferSize, 0,
displayLevel, displayName, &adv); fileSizes,
nbFiles,
cLevel,
comprParams,
dictBuffer,
dictBufferSize,
displayLevel,
displayName,
&adv);
} }
static BMK_benchOutcome_t BMK_benchCLevel(const void* srcBuffer, size_t benchedSize, static BMK_benchOutcome_t BMK_benchCLevel(
const size_t* fileSizes, unsigned nbFiles, const void* srcBuffer,
int cLevel, const ZSTD_compressionParameters* comprParams, size_t benchedSize,
const void* dictBuffer, size_t dictBufferSize, const size_t* fileSizes,
int displayLevel, const char* displayName, unsigned nbFiles,
BMK_advancedParams_t const * const adv) 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 */ const char* pch = strrchr(displayName, '\\'); /* Windows */
if (!pch) pch = strrchr(displayName, '/'); /* Linux */ if (!pch)
if (pch) displayName = pch+1; pch = strrchr(displayName, '/'); /* Linux */
if (pch)
displayName = pch + 1;
if (adv->realTime) { if (adv->realTime) {
DISPLAYLEVEL(2, "Note : switching to real-time priority \n"); DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
SET_REALTIME_PRIORITY; 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", OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, ZSTD_VERSION_STRING,
(unsigned)benchedSize, adv->nbSeconds, (unsigned)(adv->blockSize>>10)); ZSTD_GIT_COMMIT_STRING,
(unsigned)benchedSize,
adv->nbSeconds,
(unsigned)(adv->blockSize >> 10));
return BMK_benchMemAdvanced(srcBuffer, benchedSize, return BMK_benchMemAdvanced(
NULL, 0, srcBuffer,
fileSizes, nbFiles, benchedSize,
cLevel, comprParams, NULL,
dictBuffer, dictBufferSize, 0,
displayLevel, displayName, adv); fileSizes,
nbFiles,
cLevel,
comprParams,
dictBuffer,
dictBufferSize,
displayLevel,
displayName,
adv);
} }
int BMK_syntheticTest(int cLevel, double compressibility, int BMK_syntheticTest(
const ZSTD_compressionParameters* compressionParams, int cLevel,
int displayLevel, const BMK_advancedParams_t* adv) double compressibility,
const ZSTD_compressionParameters* compressionParams,
int displayLevel,
const BMK_advancedParams_t* adv)
{ {
char name[20] = {0}; char nameBuff[20] = { 0 };
size_t const benchedSize = 10000000; const char* name = nameBuff;
size_t const benchedSize = adv->blockSize ? adv->blockSize : 10000000;
void* srcBuffer; void* srcBuffer;
BMK_benchOutcome_t res; BMK_benchOutcome_t res;
@@ -719,15 +993,31 @@ int BMK_syntheticTest(int cLevel, double compressibility,
} }
/* Fill input buffer */ /* 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 */ /* Bench */
snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100)); res = BMK_benchCLevel(
res = BMK_benchCLevel(srcBuffer, benchedSize, srcBuffer,
&benchedSize /* ? */, 1 /* ? */, benchedSize,
cLevel, compressionParams, &benchedSize /* ? */,
NULL, 0, /* dictionary */ 1 /* ? */,
displayLevel, name, adv); cLevel,
compressionParams,
NULL,
0, /* dictionary */
displayLevel,
name,
adv);
/* clean up */ /* clean up */
free(srcBuffer); free(srcBuffer);
@@ -735,16 +1025,15 @@ int BMK_syntheticTest(int cLevel, double compressibility,
return !BMK_isSuccessful_benchOutcome(res); return !BMK_isSuccessful_benchOutcome(res);
} }
static size_t BMK_findMaxMem(U64 requiredMem) static size_t BMK_findMaxMem(U64 requiredMem)
{ {
size_t const step = 64 MB; size_t const step = 64 MB;
BYTE* testmem = NULL; BYTE* testmem = NULL;
requiredMem = (((requiredMem >> 26) + 1) << 26); requiredMem = (((requiredMem >> 26) + 1) << 26);
requiredMem += step; requiredMem += step;
if (requiredMem > maxMemory) requiredMem = maxMemory; if (requiredMem > maxMemory)
requiredMem = maxMemory;
do { do {
testmem = (BYTE*)malloc((size_t)requiredMem); testmem = (BYTE*)malloc((size_t)requiredMem);
@@ -758,53 +1047,75 @@ static size_t BMK_findMaxMem(U64 requiredMem)
/*! BMK_loadFiles() : /*! BMK_loadFiles() :
* Loads `buffer` with content of files listed within `fileNamesTable`. * Loads `buffer` with content of files listed within `fileNamesTable`.
* At most, fills `buffer` entirely. */ * At most, fills `buffer` entirely. */
static int BMK_loadFiles(void* buffer, size_t bufferSize, static int BMK_loadFiles(
size_t* fileSizes, void* buffer,
const char* const * fileNamesTable, unsigned nbFiles, size_t bufferSize,
int displayLevel) size_t* fileSizes,
const char* const* fileNamesTable,
unsigned nbFiles,
int displayLevel)
{ {
size_t pos = 0, totalSize = 0; size_t pos = 0, totalSize = 0;
unsigned n; unsigned n;
for (n=0; n<nbFiles; n++) { for (n = 0; n < nbFiles; n++) {
U64 fileSize = UTIL_getFileSize(fileNamesTable[n]); /* last file may be shortened */ U64 fileSize = UTIL_getFileSize(
fileNamesTable[n]); /* last file may be shortened */
if (UTIL_isDirectory(fileNamesTable[n])) { if (UTIL_isDirectory(fileNamesTable[n])) {
DISPLAYLEVEL(2, "Ignoring %s directory... \n", fileNamesTable[n]); DISPLAYLEVEL(
2, "Ignoring %s directory... \n", fileNamesTable[n]);
fileSizes[n] = 0; fileSizes[n] = 0;
continue; continue;
} }
if (fileSize == UTIL_FILESIZE_UNKNOWN) { 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; fileSizes[n] = 0;
continue; 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]); OUTPUTLEVEL(2, "Loading %s... \r", fileNamesTable[n]);
if (fileSize > bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */ if (fileSize > bufferSize - pos)
{ size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f); fileSize = bufferSize - pos,
if (readSize != (size_t)fileSize) RETURN_ERROR_INT(11, "could not read %s", fileNamesTable[n]); 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; pos += readSize;
} }
fileSizes[n] = (size_t)fileSize; fileSizes[n] = (size_t)fileSize;
totalSize += (size_t)fileSize; totalSize += (size_t)fileSize;
fclose(f); 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; return 0;
} }
int BMK_benchFilesAdvanced( int BMK_benchFilesAdvanced(
const char* const * fileNamesTable, unsigned nbFiles, const char* const* fileNamesTable,
const char* dictFileName, int cLevel, unsigned nbFiles,
const ZSTD_compressionParameters* compressionParams, const char* dictFileName,
int displayLevel, const BMK_advancedParams_t* adv) int cLevel,
const ZSTD_compressionParameters* compressionParams,
int displayLevel,
const BMK_advancedParams_t* adv)
{ {
void* srcBuffer = NULL; void* srcBuffer = NULL;
size_t benchedSize; size_t benchedSize;
void* dictBuffer = NULL; void* dictBuffer = NULL;
size_t dictBufferSize = 0; size_t dictBufferSize = 0;
size_t* fileSizes = NULL; size_t* fileSizes = NULL;
BMK_benchOutcome_t res; BMK_benchOutcome_t res;
U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles); U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
@@ -833,7 +1144,11 @@ int BMK_benchFilesAdvanced(
if (dictFileName != NULL) { if (dictFileName != NULL) {
U64 const dictFileSize = UTIL_getFileSize(dictFileName); U64 const dictFileSize = UTIL_getFileSize(dictFileName);
if (dictFileSize == UTIL_FILESIZE_UNKNOWN) { 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); free(fileSizes);
DISPLAYLEVEL(1, "benchmark aborted"); DISPLAYLEVEL(1, "benchmark aborted");
return 17; return 17;
@@ -844,28 +1159,38 @@ int BMK_benchFilesAdvanced(
return 18; return 18;
} }
dictBufferSize = (size_t)dictFileSize; dictBufferSize = (size_t)dictFileSize;
dictBuffer = malloc(dictBufferSize); dictBuffer = malloc(dictBufferSize);
if (dictBuffer==NULL) { if (dictBuffer == NULL) {
free(fileSizes); free(fileSizes);
DISPLAYLEVEL(1, "not enough memory for dictionary (%u bytes)", DISPLAYLEVEL(
(unsigned)dictBufferSize); 1,
"not enough memory for dictionary (%u bytes)",
(unsigned)dictBufferSize);
return 19; return 19;
} }
{ int const errorCode = BMK_loadFiles(dictBuffer, dictBufferSize, {
fileSizes, &dictFileName /*?*/, int const errorCode = BMK_loadFiles(
1 /*?*/, displayLevel); dictBuffer,
dictBufferSize,
fileSizes,
&dictFileName /*?*/,
1 /*?*/,
displayLevel);
if (errorCode) { if (errorCode) {
res = BMK_benchOutcome_error(); res = BMK_benchOutcome_error();
goto _cleanUp; goto _cleanUp;
} } }
}
} }
/* Memory allocation & restrictions */ /* Memory allocation & restrictions */
benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3; 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) 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; srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
if (!srcBuffer) { if (!srcBuffer) {
@@ -876,25 +1201,41 @@ int BMK_benchFilesAdvanced(
} }
/* Load input buffer */ /* Load input buffer */
{ int const errorCode = BMK_loadFiles(srcBuffer, benchedSize, {
fileSizes, fileNamesTable, nbFiles, int const errorCode = BMK_loadFiles(
displayLevel); srcBuffer,
benchedSize,
fileSizes,
fileNamesTable,
nbFiles,
displayLevel);
if (errorCode) { if (errorCode) {
res = BMK_benchOutcome_error(); res = BMK_benchOutcome_error();
goto _cleanUp; goto _cleanUp;
} } }
}
/* Bench */ /* Bench */
{ char mfName[20] = {0}; {
snprintf (mfName, sizeof(mfName), " %u files", nbFiles); char mfName[20] = { 0 };
{ const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0]; formatString_u(mfName, sizeof(mfName), " %u files", nbFiles);
res = BMK_benchCLevel(srcBuffer, benchedSize, {
fileSizes, nbFiles, const char* const displayName =
cLevel, compressionParams, (nbFiles > 1) ? mfName : fileNamesTable[0];
dictBuffer, dictBufferSize, res = BMK_benchCLevel(
displayLevel, displayName, srcBuffer,
adv); benchedSize,
} } fileSizes,
nbFiles,
cLevel,
compressionParams,
dictBuffer,
dictBufferSize,
displayLevel,
displayName,
adv);
}
}
_cleanUp: _cleanUp:
free(srcBuffer); free(srcBuffer);
@@ -903,12 +1244,21 @@ _cleanUp:
return !BMK_isSuccessful_benchOutcome(res); return !BMK_isSuccessful_benchOutcome(res);
} }
int BMK_benchFiles(
int BMK_benchFiles(const char* const * fileNamesTable, unsigned nbFiles, const char* const* fileNamesTable,
const char* dictFileName, unsigned nbFiles,
int cLevel, const ZSTD_compressionParameters* compressionParams, const char* dictFileName,
int displayLevel) int cLevel,
const ZSTD_compressionParameters* compressionParams,
int displayLevel)
{ {
BMK_advancedParams_t const adv = BMK_initAdvancedParams(); 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);
} }
+7 -5
View File
@@ -100,6 +100,7 @@ typedef struct {
BMK_mode_t mode; /* 0: all, 1: compress only 2: decode only */ BMK_mode_t mode; /* 0: all, 1: compress only 2: decode only */
unsigned nbSeconds; /* default timing is in nbSeconds */ unsigned nbSeconds; /* default timing is in nbSeconds */
size_t blockSize; /* Maximum size of each block*/ size_t blockSize; /* Maximum size of each block*/
size_t targetCBlockSize;/* Approximative size of compressed blocks */
int nbWorkers; /* multithreading */ int nbWorkers; /* multithreading */
unsigned realTime; /* real time priority */ unsigned realTime; /* real time priority */
int additionalParam; /* used by python speed benchmark */ int additionalParam; /* used by python speed benchmark */
@@ -126,11 +127,12 @@ int BMK_benchFilesAdvanced(
/*! BMK_syntheticTest() -- called from zstdcli */ /*! BMK_syntheticTest() -- called from zstdcli */
/* Generates a sample with datagen, using compressibility argument */ /* Generates a sample with datagen, using compressibility argument */
/* cLevel - compression level to benchmark, errors if invalid /* @cLevel - compression level to benchmark, errors if invalid
* compressibility - determines compressibility of sample * @compressibility - determines compressibility of sample, range [0.0 - 1.0]
* compressionParams - basic compression Parameters * if @compressibility < 0.0, uses the lorem ipsum generator
* displayLevel - see benchFiles * @compressionParams - basic compression Parameters
* adv - see advanced_Params_t * @displayLevel - see benchFiles
* @adv - see advanced_Params_t
* @return: 0 on success, !0 on error * @return: 0 on success, !0 on error
*/ */
int BMK_syntheticTest(int cLevel, double compressibility, int BMK_syntheticTest(int cLevel, double compressibility,
+11 -11
View File
@@ -1096,15 +1096,15 @@ static void FIO_adjustParamsForPatchFromMode(FIO_prefs_t* const prefs,
comprParams->windowLog = MAX(ZSTD_WINDOWLOG_MIN, MIN(ZSTD_WINDOWLOG_MAX, fileWindowLog)); comprParams->windowLog = MAX(ZSTD_WINDOWLOG_MIN, MIN(ZSTD_WINDOWLOG_MAX, fileWindowLog));
if (fileWindowLog > ZSTD_cycleLog(cParams.chainLog, cParams.strategy)) { if (fileWindowLog > ZSTD_cycleLog(cParams.chainLog, cParams.strategy)) {
if (!prefs->ldmFlag) if (!prefs->ldmFlag)
DISPLAYLEVEL(1, "long mode automatically triggered\n"); DISPLAYLEVEL(2, "long mode automatically triggered\n");
FIO_setLdmFlag(prefs, 1); FIO_setLdmFlag(prefs, 1);
} }
if (cParams.strategy >= ZSTD_btopt) { if (cParams.strategy >= ZSTD_btopt) {
DISPLAYLEVEL(1, "[Optimal parser notes] Consider the following to improve patch size at the cost of speed:\n"); DISPLAYLEVEL(3, "[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(3, "- Use --single-thread mode in the zstd cli\n");
DISPLAYLEVEL(1, "- Set a larger targetLength (e.g. --zstd=targetLength=4096)\n"); DISPLAYLEVEL(3, "- 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(3, "- 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, "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 closeDstFile = 0;
int result; int result;
int transferStat = 0; int transferStat = 0;
FILE *dstFile;
int dstFd = -1; int dstFd = -1;
assert(AIO_ReadPool_getFile(ress.readCtx) != NULL); assert(AIO_ReadPool_getFile(ress.readCtx) != NULL);
@@ -1854,10 +1853,11 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx,
closeDstFile = 1; closeDstFile = 1;
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName); DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName);
dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFileInitialPermissions); { FILE *dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFileInitialPermissions);
if (dstFile==NULL) return 1; /* could not open dstFileName */ if (dstFile==NULL) return 1; /* could not open dstFileName */
dstFd = fileno(dstFile); dstFd = fileno(dstFile);
AIO_WritePool_setFile(ress.writeCtx, dstFile); AIO_WritePool_setFile(ress.writeCtx, dstFile);
}
/* Must only be added after FIO_openDstFile() succeeds. /* Must only be added after FIO_openDstFile() succeeds.
* Otherwise we may delete the destination file if it already exists, * Otherwise we may delete the destination file if it already exists,
* and the user presses Ctrl-C when asked if they wish to overwrite. * and the user presses Ctrl-C when asked if they wish to overwrite.
+2 -2
View File
@@ -453,8 +453,8 @@ static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ReadPoolCt
/* AIO_ReadPool_numReadsInFlight: /* AIO_ReadPool_numReadsInFlight:
* Returns the number of IO read jobs currently in flight. */ * Returns the number of IO read jobs currently in flight. */
static size_t AIO_ReadPool_numReadsInFlight(ReadPoolCtx_t* ctx) { static size_t AIO_ReadPool_numReadsInFlight(ReadPoolCtx_t* ctx) {
const size_t jobsHeld = (ctx->currentJobHeld==NULL ? 0 : 1); const int jobsHeld = (ctx->currentJobHeld==NULL ? 0 : 1);
return ctx->base.totalIoJobs - (ctx->base.availableJobsCount + ctx->completedJobsCount + jobsHeld); return (size_t)(ctx->base.totalIoJobs - (ctx->base.availableJobsCount + ctx->completedJobsCount + jobsHeld));
} }
/* AIO_ReadPool_getNextCompletedJob: /* AIO_ReadPool_getNextCompletedJob:
+285
View File
@@ -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);
}
+32
View File
@@ -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
View File
@@ -660,7 +660,6 @@ UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
size_t nbFiles = 0; size_t nbFiles = 0;
char* buf; char* buf;
size_t bufSize; size_t bufSize;
size_t pos = 0;
stat_t statbuf; stat_t statbuf;
if (!UTIL_stat(inputFileName, &statbuf) || !UTIL_isRegularFileStat(&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)); { const char** filenamesTable = (const char**) malloc(nbFiles * sizeof(*filenamesTable));
CONTROL(filenamesTable != NULL); CONTROL(filenamesTable != NULL);
{ size_t fnb; { size_t fnb, pos = 0;
for (fnb = 0, pos = 0; fnb < nbFiles; fnb++) { for (fnb = 0; fnb < nbFiles; fnb++) {
filenamesTable[fnb] = buf+pos; filenamesTable[fnb] = buf+pos;
pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */ pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */
} } }
assert(pos <= bufSize); assert(pos <= bufSize);
}
return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf); return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf);
} }
@@ -753,7 +753,7 @@ void UTIL_refFilename(FileNamesTable* fnt, const char* filename)
static size_t getTotalTableSize(FileNamesTable* table) 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) { 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 */ totalSize += strlen(table->fileNames[fnb]) + 1; /* +1 to add '\0' at the end of each fileName */
} }
+7
View File
@@ -218,6 +218,13 @@ the last one takes effect.
expected. This feature allows for controlling the guess when needed. expected. This feature allows for controlling the guess when needed.
Exact guesses result in better compression ratios. Overestimates result in slightly Exact guesses result in better compression ratios. Overestimates result in slightly
degraded compression ratios, while underestimates may result in significant degradation. 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`: * `-o FILE`:
save result into `FILE`. save result into `FILE`.
* `-f`, `--force`: * `-f`, `--force`:
+30 -22
View File
@@ -138,8 +138,8 @@ static int exeNameMatch(const char* exeName, const char* test)
* Command Line * Command Line
**************************************/ **************************************/
/* print help either in `stderr` or `stdout` depending on originating request /* print help either in `stderr` or `stdout` depending on originating request
* error (badusage) => stderr * error (badUsage) => stderr
* help (usage_advanced) => stdout * help (usageAdvanced) => stdout
*/ */
static void usage(FILE* f, const char* programName) static void usage(FILE* f, const char* programName)
{ {
@@ -175,7 +175,7 @@ static void usage(FILE* f, const char* programName)
DISPLAY_F(f, "\n"); DISPLAY_F(f, "\n");
} }
static void usage_advanced(const char* programName) static void usageAdvanced(const char* programName)
{ {
DISPLAYOUT(WELCOME_MESSAGE); DISPLAYOUT(WELCOME_MESSAGE);
DISPLAYOUT("\n"); 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); if (g_displayLevel >= 2) usage(stderr, programName);
} }
@@ -589,7 +589,7 @@ static ZDICT_fastCover_params_t defaultFastCoverParams(void)
/** parseAdaptParameters() : /** 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. * Both adaptMinPtr and adaptMaxPtr must be already allocated and correctly initialized.
* There is no guarantee that any of these values will be updated. * There is no guarantee that any of these values will be updated.
* @return 1 means that parsing was successful, * @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; ZSTD_paramSwitch_e useRowMatchFinder = ZSTD_ps_auto;
FIO_compressionType_t cType = FIO_zstdCompression; FIO_compressionType_t cType = FIO_zstdCompression;
unsigned nbWorkers = 0; 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 */ unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */
size_t blockSize = 0; size_t blockSize = 0;
@@ -933,6 +933,7 @@ int main(int argCount, const char* argv[])
/* command switches */ /* command switches */
for (argNb=1; argNb<argCount; argNb++) { for (argNb=1; argNb<argCount; argNb++) {
const char* argument = argv[argNb]; const char* argument = argv[argNb];
const char* const originalArgument = argument;
if (!argument) continue; /* Protection if argument empty */ if (!argument) continue; /* Protection if argument empty */
if (nextArgumentsAreFiles) { if (nextArgumentsAreFiles) {
@@ -958,7 +959,7 @@ int main(int argCount, const char* argv[])
if (!strcmp(argument, "--uncompress")) { operation=zom_decompress; continue; } 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, "--force")) { FIO_overwriteMode(prefs); forceStdin=1; forceStdout=1; followLinks=1; allowBlockDevices=1; continue; }
if (!strcmp(argument, "--version")) { printVersion(); CLEAN_RETURN(0); } 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, "--verbose")) { g_displayLevel++; continue; }
if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; } if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; }
if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; removeSrcFile=0; 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, "--adapt")) { adapt = 1; continue; }
if (!strcmp(argument, "--no-row-match-finder")) { useRowMatchFinder = ZSTD_ps_disable; 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 (!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, "--single-thread")) { nbWorkers = 0; singleThread = 1; continue; }
if (!strcmp(argument, "--format=zstd")) { suffix = ZSTD_EXTENSION; cType = FIO_zstdCompression; continue; } if (!strcmp(argument, "--format=zstd")) { suffix = ZSTD_EXTENSION; cType = FIO_zstdCompression; continue; }
if (!strcmp(argument, "--mmap-dict")) { mmapDict = ZSTD_ps_enable; continue; } if (!strcmp(argument, "--mmap-dict")) { mmapDict = ZSTD_ps_enable; continue; }
@@ -1022,8 +1023,8 @@ int main(int argCount, const char* argv[])
dict = cover; dict = cover;
/* Allow optional arguments following an = */ /* Allow optional arguments following an = */
if (*argument == 0) { memset(&coverParams, 0, sizeof(coverParams)); } if (*argument == 0) { memset(&coverParams, 0, sizeof(coverParams)); }
else if (*argument++ != '=') { badusage(programName); CLEAN_RETURN(1); } else if (*argument++ != '=') { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
else if (!parseCoverParameters(argument, &coverParams)) { badusage(programName); CLEAN_RETURN(1); } else if (!parseCoverParameters(argument, &coverParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
continue; continue;
} }
if (longCommandWArg(&argument, "--train-fastcover")) { if (longCommandWArg(&argument, "--train-fastcover")) {
@@ -1033,8 +1034,8 @@ int main(int argCount, const char* argv[])
dict = fastCover; dict = fastCover;
/* Allow optional arguments following an = */ /* Allow optional arguments following an = */
if (*argument == 0) { memset(&fastCoverParams, 0, sizeof(fastCoverParams)); } if (*argument == 0) { memset(&fastCoverParams, 0, sizeof(fastCoverParams)); }
else if (*argument++ != '=') { badusage(programName); CLEAN_RETURN(1); } else if (*argument++ != '=') { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
else if (!parseFastCoverParameters(argument, &fastCoverParams)) { badusage(programName); CLEAN_RETURN(1); } else if (!parseFastCoverParameters(argument, &fastCoverParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
continue; continue;
} }
if (longCommandWArg(&argument, "--train-legacy")) { if (longCommandWArg(&argument, "--train-legacy")) {
@@ -1044,8 +1045,8 @@ int main(int argCount, const char* argv[])
dict = legacy; dict = legacy;
/* Allow optional arguments following an = */ /* Allow optional arguments following an = */
if (*argument == 0) { continue; } if (*argument == 0) { continue; }
else if (*argument++ != '=') { badusage(programName); CLEAN_RETURN(1); } else if (*argument++ != '=') { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
else if (!parseLegacyParameters(argument, &dictSelect)) { badusage(programName); CLEAN_RETURN(1); } else if (!parseLegacyParameters(argument, &dictSelect)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
continue; continue;
} }
#endif #endif
@@ -1056,7 +1057,7 @@ int main(int argCount, const char* argv[])
if (longCommandWArg(&argument, "--block-size")) { NEXT_TSIZE(blockSize); continue; } if (longCommandWArg(&argument, "--block-size")) { NEXT_TSIZE(blockSize); continue; }
if (longCommandWArg(&argument, "--maxdict")) { NEXT_UINT32(maxDictSize); continue; } if (longCommandWArg(&argument, "--maxdict")) { NEXT_UINT32(maxDictSize); continue; }
if (longCommandWArg(&argument, "--dictID")) { NEXT_UINT32(dictID); 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, "--stream-size")) { NEXT_TSIZE(streamSrcSize); continue; }
if (longCommandWArg(&argument, "--target-compressed-block-size")) { NEXT_TSIZE(targetCBlockSize); continue; } if (longCommandWArg(&argument, "--target-compressed-block-size")) { NEXT_TSIZE(targetCBlockSize); continue; }
if (longCommandWArg(&argument, "--size-hint")) { NEXT_TSIZE(srcSizeHint); continue; } if (longCommandWArg(&argument, "--size-hint")) { NEXT_TSIZE(srcSizeHint); continue; }
@@ -1098,7 +1099,7 @@ int main(int argCount, const char* argv[])
ldmWindowLog = readU32FromChar(&argument); ldmWindowLog = readU32FromChar(&argument);
} else if (*argument != 0) { } else if (*argument != 0) {
/* Invalid character following --long */ /* Invalid character following --long */
badusage(programName); badUsage(programName, originalArgument);
CLEAN_RETURN(1); CLEAN_RETURN(1);
} else { } else {
ldmWindowLog = g_defaultMaxWindowLog; ldmWindowLog = g_defaultMaxWindowLog;
@@ -1120,12 +1121,12 @@ int main(int argCount, const char* argv[])
if (fastLevel) { if (fastLevel) {
dictCLevel = cLevel = -(int)fastLevel; dictCLevel = cLevel = -(int)fastLevel;
} else { } else {
badusage(programName); badUsage(programName, originalArgument);
CLEAN_RETURN(1); CLEAN_RETURN(1);
} }
} else if (*argument != 0) { } else if (*argument != 0) {
/* Invalid character following --fast */ /* Invalid character following --fast */
badusage(programName); badUsage(programName, originalArgument);
CLEAN_RETURN(1); CLEAN_RETURN(1);
} else { } else {
cLevel = -1; /* default for --fast */ cLevel = -1; /* default for --fast */
@@ -1141,7 +1142,8 @@ int main(int argCount, const char* argv[])
continue; continue;
} }
/* fall-through, will trigger bad_usage() later on */ badUsage(programName, originalArgument);
CLEAN_RETURN(1);
} }
argument++; argument++;
@@ -1159,7 +1161,7 @@ int main(int argCount, const char* argv[])
{ {
/* Display help */ /* Display help */
case 'V': printVersion(); CLEAN_RETURN(0); /* Version Only */ 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); case 'h': usage(stdout, programName); CLEAN_RETURN(0);
/* Compress */ /* Compress */
@@ -1277,7 +1279,12 @@ int main(int argCount, const char* argv[])
break; break;
/* unknown command */ /* 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; continue;
@@ -1368,6 +1375,7 @@ int main(int argCount, const char* argv[])
CLEAN_RETURN(1); CLEAN_RETURN(1);
} }
benchParams.blockSize = blockSize; benchParams.blockSize = blockSize;
benchParams.targetCBlockSize = targetCBlockSize;
benchParams.nbWorkers = (int)nbWorkers; benchParams.nbWorkers = (int)nbWorkers;
benchParams.realTime = (unsigned)setRealTimePrio; benchParams.realTime = (unsigned)setRealTimePrio;
benchParams.nbSeconds = bench_nbSeconds; benchParams.nbSeconds = bench_nbSeconds;
+6 -5
View File
@@ -203,10 +203,10 @@ zstreamtest-dll : $(ZSTREAM_LOCAL_FILES)
CLEAN += paramgrill CLEAN += paramgrill
paramgrill : DEBUGFLAGS = # turn off debug for speed measurements paramgrill : DEBUGFLAGS = # turn off debug for speed measurements
paramgrill : LDLIBS += -lm 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 CLEAN += datagen
datagen : $(PRGDIR)/datagen.c datagencli.c datagen : $(PRGDIR)/datagen.c $(PRGDIR)/lorem.c loremOut.c datagencli.c
$(LINK.c) $^ -o $@$(EXT) $(LINK.c) $^ -o $@$(EXT)
CLEAN += roundTripCrash CLEAN += roundTripCrash
@@ -251,8 +251,9 @@ checkTag.o : $(ZSTDDIR)/zstd.h
clean: clean:
$(MAKE) -C $(ZSTDDIR) clean $(MAKE) -C $(ZSTDDIR) clean
$(MAKE) -C $(PRGDIR) clean $(MAKE) -C $(PRGDIR) clean
$(RM) -fR $(TESTARTEFACT) $(MAKE) -C fuzz clean
$(RM) -rf tmp* # some test directories are named tmp* $(RM) -R $(TESTARTEFACT)
$(RM) -r tmp* # some test directories are named tmp*
$(RM) $(CLEAN) core *.o *.tmp result* *.gcda dictionary *.zst \ $(RM) $(CLEAN) core *.o *.tmp result* *.gcda dictionary *.zst \
$(PRGDIR)/zstd$(EXT) $(PRGDIR)/zstd32$(EXT) \ $(PRGDIR)/zstd$(EXT) $(PRGDIR)/zstd32$(EXT) \
fullbench-dll$(EXT) fuzzer-dll$(EXT) zstreamtest-dll$(EXT) fullbench-dll$(EXT) fuzzer-dll$(EXT) zstreamtest-dll$(EXT)
@@ -313,7 +314,7 @@ check: shortest
fuzztest: test-fuzzer test-zstream test-decodecorpus fuzztest: test-fuzzer test-zstream test-decodecorpus
.PHONY: test .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),) ifeq ($(QEMU_SYS),)
test: test-pool test: test-pool
endif endif
+10
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
1
+28
View File
@@ -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
View File
@@ -8,122 +8,141 @@
* You may select, at your option, one of the above-listed licenses. * 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 * Constants
**************************************/ **************************************/
#include "util.h" /* Compiler options */ #define KB *(1 << 10)
#include <stdio.h> /* fprintf, stderr */ #define MB *(1 << 20)
#include "datagen.h" /* RDG_generate */ #define GB *(1U << 30)
/*-************************************
* Constants
**************************************/
#define KB *(1 <<10)
#define MB *(1 <<20)
#define GB *(1U<<30)
#define SIZE_DEFAULT ((64 KB) + 1) #define SIZE_DEFAULT ((64 KB) + 1)
#define SEED_DEFAULT 0 #define SEED_DEFAULT 0
#define COMPRESSIBILITY_DEFAULT 50 #define COMPRESSIBILITY_DEFAULT 9999
/*-************************************ /*-************************************
* Macros * Macros
**************************************/ **************************************/
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } #define DISPLAYLEVEL(l, ...) \
if (displayLevel >= l) { \
DISPLAY(__VA_ARGS__); \
}
static unsigned displayLevel = 2; static unsigned displayLevel = 2;
/*-******************************************************* /*-*******************************************************
* Command line * Command line
*********************************************************/ *********************************************************/
static int usage(const char* programName) static int usage(const char* programName)
{ {
DISPLAY( "Compressible data generator\n"); DISPLAY("Compressible data generator\n");
DISPLAY( "Usage :\n"); DISPLAY("Usage :\n");
DISPLAY( " %s [args]\n", programName); DISPLAY(" %s [args]\n", programName);
DISPLAY( "\n"); DISPLAY("\n");
DISPLAY( "Arguments :\n"); DISPLAY("Arguments :\n");
DISPLAY( " -g# : generate # data (default:%i)\n", SIZE_DEFAULT); DISPLAY(" -g# : generate # data (default:%i)\n", SIZE_DEFAULT);
DISPLAY( " -s# : Select seed (default:%i)\n", SEED_DEFAULT); DISPLAY(" -s# : Select seed (default:%i)\n", SEED_DEFAULT);
DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", DISPLAY(" -P# : Select compressibility in %% (range [0-100])\n");
COMPRESSIBILITY_DEFAULT); DISPLAY(" -h : display help and exit\n");
DISPLAY( " -h : display help and exit\n");
return 0; return 0;
} }
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
unsigned probaU32 = COMPRESSIBILITY_DEFAULT; unsigned probaU32 = COMPRESSIBILITY_DEFAULT;
double litProba = 0.0; double litProba = 0.0;
U64 size = SIZE_DEFAULT; U64 size = SIZE_DEFAULT;
U32 seed = SEED_DEFAULT; U32 seed = SEED_DEFAULT;
const char* const programName = argv[0]; const char* const programName = argv[0];
int argNb; int argNb;
for(argNb=1; argNb<argc; argNb++) { for (argNb = 1; argNb < argc; argNb++) {
const char* argument = argv[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 */ /* Handle commands. Aggregated commands are allowed */
if (*argument=='-') { if (*argument == '-') {
argument++; argument++;
while (*argument!=0) { while (*argument != 0) {
switch(*argument) switch (*argument) {
{ case 'h':
case 'h': return usage(programName);
return usage(programName); case 'g':
case 'g': argument++;
argument++; size = 0;
size=0; while ((*argument >= '0') && (*argument <= '9'))
while ((*argument>='0') && (*argument<='9')) size *= 10, size += (U64)(*argument++ - '0');
size *= 10, size += *argument++ - '0'; if (*argument == 'K') {
if (*argument=='K') { size <<= 10; argument++; } size <<= 10;
if (*argument=='M') { size <<= 20; argument++; } argument++;
if (*argument=='G') { size <<= 30; argument++; } }
if (*argument=='B') { argument++; } if (*argument == 'M') {
break; size <<= 20;
case 's': argument++;
argument++; }
seed=0; if (*argument == 'G') {
while ((*argument>='0') && (*argument<='9')) size <<= 30;
seed *= 10, seed += *argument++ - '0'; argument++;
break; }
case 'P': if (*argument == 'B') {
argument++; argument++;
probaU32 = 0; }
while ((*argument>='0') && (*argument<='9')) break;
probaU32 *= 10, probaU32 += *argument++ - '0'; case 's':
if (probaU32>100) probaU32 = 100; argument++;
break; seed = 0;
case 'L': /* hidden argument : Literal distribution probability */ while ((*argument >= '0') && (*argument <= '9'))
argument++; seed *= 10, seed += (U32)(*argument++ - '0');
litProba=0.; break;
while ((*argument>='0') && (*argument<='9')) case 'P':
litProba *= 10, litProba += *argument++ - '0'; argument++;
if (litProba>100.) litProba=100.; probaU32 = 0;
litProba /= 100.; while ((*argument >= '0') && (*argument <= '9'))
break; probaU32 *= 10,
case 'v': probaU32 += (U32)(*argument++ - '0');
displayLevel = 4; if (probaU32 > 100)
argument++; probaU32 = 100;
break; break;
default: case 'L': /* hidden argument : Literal distribution
return usage(programName); 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"); DISPLAYLEVEL(4, "Compressible data Generator \n");
if (probaU32!=COMPRESSIBILITY_DEFAULT)
DISPLAYLEVEL(3, "Compressibility : %i%%\n", probaU32);
DISPLAYLEVEL(3, "Seed = %u \n", (unsigned)seed); 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"); DISPLAYLEVEL(3, "\n");
return 0; return 0;
+1 -1
View File
@@ -257,7 +257,7 @@ corpora: $(patsubst %,corpora/%,$(FUZZ_TARGETS))
seedcorpora: $(patsubst %,corpora/%_seed_corpus.zip,$(FUZZ_TARGETS)) seedcorpora: $(patsubst %,corpora/%_seed_corpus.zip,$(FUZZ_TARGETS))
regressiontest: corpora 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 $(PYTHON) ./fuzz.py regression all
clean: clean:
+6 -6
View File
@@ -23,13 +23,13 @@
#include "fuzz_data_producer.h" #include "fuzz_data_producer.h"
#include "fuzz_third_party_seq_prod.h" #include "fuzz_third_party_seq_prod.h"
static ZSTD_CCtx *cctx = NULL; static ZSTD_CCtx* cctx = NULL;
static ZSTD_DCtx *dctx = NULL; static ZSTD_DCtx* dctx = NULL;
static size_t roundTripTest(void *result, size_t resultCapacity, static size_t roundTripTest(void* result, size_t resultCapacity,
void *compressed, size_t compressedCapacity, void* compressed, size_t compressedCapacity,
const void *src, size_t srcSize, const void* src, size_t srcSize,
FUZZ_dataProducer_t *producer) FUZZ_dataProducer_t* producer)
{ {
ZSTD_dictContentType_e dictContentType = ZSTD_dct_auto; ZSTD_dictContentType_e dictContentType = ZSTD_dct_auto;
FUZZ_dict_t dict = FUZZ_train(src, srcSize, producer); FUZZ_dict_t dict = FUZZ_train(src, srcSize, producer);
+1
View File
@@ -492,6 +492,7 @@ def build(args):
subprocess.check_call(clean_cmd) subprocess.check_call(clean_cmd)
build_cmd = [ build_cmd = [
'make', 'make',
'-j',
cc_str, cc_str,
cxx_str, cxx_str,
cppflags_str, cppflags_str,
+1 -1
View File
@@ -1374,7 +1374,7 @@ static int basicUnitTests(U32 const seed, double compressibility)
} }
DISPLAYLEVEL(3, "OK \n"); 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(); ZSTD_CCtx* const cctx = ZSTD_createCCtx();
const BYTE* src = (BYTE*)CNBuffer; BYTE* dst = (BYTE*)compressedBuffer; const BYTE* src = (BYTE*)CNBuffer; BYTE* dst = (BYTE*)compressedBuffer;
+50
View File
@@ -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);
}
+15
View File
@@ -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
View File
@@ -1,6 +1,7 @@
#!/bin/sh #!/bin/sh
set -e set -e # exit immediately on error
# set -x # print commands before execution (debug)
unset ZSTD_CLEVEL unset ZSTD_CLEVEL
unset ZSTD_NBTHREADS unset ZSTD_NBTHREADS
@@ -91,7 +92,13 @@ fi
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
PRGDIR="$SCRIPT_DIR/../programs" PRGDIR="$SCRIPT_DIR/../programs"
TESTDIR="$SCRIPT_DIR/../tests" 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 detectedTerminal=false
if [ -t 0 ] && [ -t 1 ] if [ -t 0 ] && [ -t 1 ]
@@ -151,11 +158,6 @@ assertSamePermissions() {
[ "$STAT1" = "$STAT2" ] || die "permissions on $1 don't match those on $2 ($STAT1 != $STAT2)" [ "$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 # check if ZSTD_BIN is defined. if not, use the default value
if [ -z "${ZSTD_BIN}" ]; then 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. " [ -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'" 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 then
hasMT="" hasMT=""
else else
@@ -253,8 +255,8 @@ println "test : null-length file roundtrip"
println -n '' | zstd - --stdout | zstd -d --stdout println -n '' | zstd - --stdout | zstd -d --stdout
println "test : ensure small file doesn't add 3-bytes null block" println "test : ensure small file doesn't add 3-bytes null block"
datagen -g1 > tmp1 datagen -g1 > tmp1
zstd tmp1 -c | wc -c | grep "14" zstd tmp1 -c | wc -c | $GREP "14"
zstd < tmp1 | wc -c | grep "14" zstd < tmp1 | wc -c | $GREP "14"
println "test : decompress file with wrong suffix (must fail)" println "test : decompress file with wrong suffix (must fail)"
zstd -d tmpCompressed && die "wrong suffix error not detected!" zstd -d tmpCompressed && die "wrong suffix error not detected!"
zstd -df tmp && die "should have refused : wrong extension" 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 -c --no-progress | zstd -d -f -o "$INTOVOID" --no-progress
zstd tmpro -cv --no-progress | zstd -dv -f -o "$INTOVOID" --no-progress zstd tmpro -cv --no-progress | zstd -dv -f -o "$INTOVOID" --no-progress
println "test: --progress flag" 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 -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 -E "[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 -E "[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 rm -f tmpro tmpro.zst
println "test: overwrite input file (must fail)" println "test: overwrite input file (must fail)"
zstd tmp -fo tmp && die "zstd compression overwrote the input file" 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 [ "$isWindows" = false ] && [ "$UNAME" != "AIX" ]; then
if [ -n "$(which readelf)" ]; then if [ -n "$(which readelf)" ]; then
println "test: check if binary has executable stack (#2963)" 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
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 "test : should quietly not remove non-regular file"
println hello > tmp println hello > tmp
zstd tmp -f -o "$DEVDEVICE" 2>tmplog > "$INTOVOID" 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 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 "test : --rm on stdin"
println a | zstd --rm > $INTOVOID # --rm should remain silent println a | zstd --rm > $INTOVOID # --rm should remain silent
rm -f tmp rm -f tmp
@@ -615,7 +617,7 @@ if [ -n "$DEVNULLRIGHTS" ] ; then
zstd tmp -f -o tmp.zst zstd tmp -f -o tmp.zst
sudoZstd -d tmp.zst -c > $INTOVOID sudoZstd -d tmp.zst -c > $INTOVOID
sudoZstd -d tmp.zst -o $INTOVOID sudoZstd -d tmp.zst -o $INTOVOID
ls -las $INTOVOID | grep "rw-rw-rw-" ls -las $INTOVOID | $GREP "rw-rw-rw-"
fi fi
if [ -n "$READFROMBLOCKDEVICE" ] ; then if [ -n "$READFROMBLOCKDEVICE" ] ; then
@@ -625,7 +627,7 @@ if [ -n "$READFROMBLOCKDEVICE" ] ; then
println "\n===> checking that zstd can read from a block device" println "\n===> checking that zstd can read from a block device"
datagen -g65536 > tmp.img datagen -g65536 > tmp.img
sudo losetup -fP 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" [ -z "$LOOP_DEV" ] && die "failed to get loopback device"
sudoZstd $LOOP_DEV -c > tmp.img.zst && die "should fail without -f" sudoZstd $LOOP_DEV -c > tmp.img.zst && die "should fail without -f"
sudoZstd -f $LOOP_DEV -c > tmp.img.zst sudoZstd -f $LOOP_DEV -c > tmp.img.zst
@@ -774,13 +776,13 @@ println "\n===> --[no-]content-size tests"
datagen > tmp_contentsize datagen > tmp_contentsize
zstd -f 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 -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 -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 -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* rm -rf tmp*
println "test : show-default-cparams regular" println "test : show-default-cparams regular"
@@ -800,8 +802,7 @@ rm -rf tmp*
println "test : show compression parameters in verbose mode" println "test : show compression parameters in verbose mode"
datagen > tmp datagen > tmp
zstd -vv tmp 2>&1 | \ zstd -vv tmp 2>&1 | \
grep -q -E -- "--zstd=wlog=[[:digit:]]+,clog=[[:digit:]]+,hlog=[[: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]*"
slog=[[:digit:]]+,mml=[[:digit:]]+,tlen=[[:digit:]]+,strat=[[:digit:]]+"
rm -rf tmp* rm -rf tmp*
println "\n===> Advanced compression parameters " println "\n===> Advanced compression parameters "
@@ -1098,8 +1099,8 @@ println "- Test --memory for dictionary compression"
datagen -g12M -P90 > tmpCorpusHighCompress 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=10K && die "Dictionary training should fail : --memory too low (10K)"
zstd --train -B2K tmpCorpusHighCompress -o tmpDictHighCompress --memory=5MB 2> zstTrainWithMemLimitStdErr 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 "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 "Training samples set too large (12 MB); training on 5 MB only..."
rm zstTrainWithMemLimitStdErr rm zstTrainWithMemLimitStdErr
println "\n===> fastCover dictionary builder : advanced options " println "\n===> fastCover dictionary builder : advanced options "
@@ -1385,16 +1386,16 @@ println "\n===> suffix list test"
! zstd -d tmp.abc 2> tmplg ! zstd -d tmp.abc 2> tmplg
if [ $GZIPMODE -ne 1 ]; then if [ $GZIPMODE -ne 1 ]; then
grep ".gz" tmplg > $INTOVOID && die "Unsupported suffix listed" $GREP ".gz" tmplg > $INTOVOID && die "Unsupported suffix listed"
fi fi
if [ $LZMAMODE -ne 1 ]; then if [ $LZMAMODE -ne 1 ]; then
grep ".lzma" tmplg > $INTOVOID && die "Unsupported suffix listed" $GREP ".lzma" tmplg > $INTOVOID && die "Unsupported suffix listed"
grep ".xz" tmplg > $INTOVOID && die "Unsupported suffix listed" $GREP ".xz" tmplg > $INTOVOID && die "Unsupported suffix listed"
fi fi
if [ $LZ4MODE -ne 1 ]; then if [ $LZ4MODE -ne 1 ]; then
grep ".lz4" tmplg > $INTOVOID && die "Unsupported suffix listed" $GREP ".lz4" tmplg > $INTOVOID && die "Unsupported suffix listed"
fi fi
touch tmp1 touch tmp1
@@ -1523,7 +1524,7 @@ datagen > tmp2
datagen > tmp3 datagen > tmp3
zstd tmp* zstd tmp*
zstd -l ./*.zst 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 ./*.zst
zstd --list -v ./*.zst zstd --list -v ./*.zst
@@ -1566,13 +1567,13 @@ datagen -g0 > tmp5
zstd tmp5 zstd tmp5
zstd -l tmp5.zst zstd -l tmp5.zst
zstd -l tmp5* && die "-l must fail on non-zstd file" 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" zstd -lv tmp5* && die "-l must fail on non-zstd file"
println "\n===> zstd --list/-l test with no content size field " println "\n===> zstd --list/-l test with no content size field "
datagen -g513K | zstd > tmp6.zst datagen -g513K | zstd > tmp6.zst
zstd -l 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 " println "\n===> zstd --list/-l test with no checksum "
zstd -f --no-check tmp1 zstd -f --no-check tmp1
@@ -1723,7 +1724,7 @@ else
datagen -g5000000 > tmp_dict datagen -g5000000 > tmp_dict
datagen -g5000000 > tmp_patch datagen -g5000000 > tmp_patch
fi 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* rm -rf tmp*
println "\n===> patch-from very large dictionary and file test" println "\n===> patch-from very large dictionary and file test"
+132 -132
View File
@@ -11,10 +11,10 @@ silesia.tar, level 6, compress
silesia.tar, level 7, compress simple, 4579828 silesia.tar, level 7, compress simple, 4579828
silesia.tar, level 9, compress simple, 4555448 silesia.tar, level 9, compress simple, 4555448
silesia.tar, level 13, compress simple, 4502956 silesia.tar, level 13, compress simple, 4502956
silesia.tar, level 16, compress simple, 4360546 silesia.tar, level 16, compress simple, 4360385
silesia.tar, level 19, compress simple, 4265911 silesia.tar, level 19, compress simple, 4260939
silesia.tar, uncompressed literals, compress simple, 4854086 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 silesia.tar, huffman literals, compress simple, 6179047
github.tar, level -5, compress simple, 52115 github.tar, level -5, compress simple, 52115
github.tar, level -3, compress simple, 45678 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 9, compress simple, 36723
github.tar, level 13, compress simple, 35501 github.tar, level 13, compress simple, 35501
github.tar, level 16, compress simple, 40466 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, 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 github.tar, huffman literals, compress simple, 42560
silesia, level -5, compress cctx, 6857372 silesia, level -5, compress cctx, 6857372
silesia, level -3, compress cctx, 6503412 silesia, level -3, compress cctx, 6503412
@@ -45,8 +45,8 @@ silesia, level 6, compress
silesia, level 7, compress cctx, 4570271 silesia, level 7, compress cctx, 4570271
silesia, level 9, compress cctx, 4545850 silesia, level 9, compress cctx, 4545850
silesia, level 13, compress cctx, 4493990 silesia, level 13, compress cctx, 4493990
silesia, level 16, compress cctx, 4360041 silesia, level 16, compress cctx, 4359652
silesia, level 19, compress cctx, 4296055 silesia, level 19, compress cctx, 4266582
silesia, long distance mode, compress cctx, 4842075 silesia, long distance mode, compress cctx, 4842075
silesia, multithreaded, compress cctx, 4842075 silesia, multithreaded, compress cctx, 4842075
silesia, multithreaded long distance mode, 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, small chain log, compress cctx, 4912197
silesia, explicit params, compress cctx, 4794318 silesia, explicit params, compress cctx, 4794318
silesia, uncompressed literals, compress cctx, 4842075 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, huffman literals, compress cctx, 6172202
silesia, multithreaded with advanced params, compress cctx, 4842075 silesia, multithreaded with advanced params, compress cctx, 4842075
github, level -5, compress cctx, 204407 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, compress cctx, 132878
github, level 13 with dict, compress cctx, 39948 github, level 13 with dict, compress cctx, 39948
github, level 16, compress cctx, 133209 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, 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, long distance mode, compress cctx, 141069
github, multithreaded, compress cctx, 141069 github, multithreaded, compress cctx, 141069
github, multithreaded long distance mode, 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 7, zstdcli, 4570319
silesia, level 9, zstdcli, 4545898 silesia, level 9, zstdcli, 4545898
silesia, level 13, zstdcli, 4494038 silesia, level 13, zstdcli, 4494038
silesia, level 16, zstdcli, 4360089 silesia, level 16, zstdcli, 4359700
silesia, level 19, zstdcli, 4296103 silesia, level 19, zstdcli, 4266630
silesia, long distance mode, zstdcli, 4833785 silesia, long distance mode, zstdcli, 4833785
silesia, multithreaded, zstdcli, 4842123 silesia, multithreaded, zstdcli, 4842123
silesia, multithreaded long distance mode, zstdcli, 4833785 silesia, multithreaded long distance mode, zstdcli, 4833785
@@ -119,7 +119,7 @@ silesia, small hash log, zstdcli,
silesia, small chain log, zstdcli, 4912245 silesia, small chain log, zstdcli, 4912245
silesia, explicit params, zstdcli, 4795840 silesia, explicit params, zstdcli, 4795840
silesia, uncompressed literals, zstdcli, 5120614 silesia, uncompressed literals, zstdcli, 5120614
silesia, uncompressed literals optimal, zstdcli, 4319566 silesia, uncompressed literals optimal, zstdcli, 4316928
silesia, huffman literals, zstdcli, 5321417 silesia, huffman literals, zstdcli, 5321417
silesia, multithreaded with advanced params, zstdcli, 5120614 silesia, multithreaded with advanced params, zstdcli, 5120614
silesia.tar, level -5, zstdcli, 6862049 silesia.tar, level -5, zstdcli, 6862049
@@ -134,8 +134,8 @@ silesia.tar, level 6, zstdcli,
silesia.tar, level 7, zstdcli, 4581791 silesia.tar, level 7, zstdcli, 4581791
silesia.tar, level 9, zstdcli, 4555452 silesia.tar, level 9, zstdcli, 4555452
silesia.tar, level 13, zstdcli, 4502960 silesia.tar, level 13, zstdcli, 4502960
silesia.tar, level 16, zstdcli, 4360550 silesia.tar, level 16, zstdcli, 4360389
silesia.tar, level 19, zstdcli, 4265915 silesia.tar, level 19, zstdcli, 4260943
silesia.tar, no source size, zstdcli, 4854160 silesia.tar, no source size, zstdcli, 4854160
silesia.tar, long distance mode, zstdcli, 4845745 silesia.tar, long distance mode, zstdcli, 4845745
silesia.tar, multithreaded, zstdcli, 4854164 silesia.tar, multithreaded, zstdcli, 4854164
@@ -145,7 +145,7 @@ silesia.tar, small hash log, zstdcli,
silesia.tar, small chain log, zstdcli, 4917022 silesia.tar, small chain log, zstdcli, 4917022
silesia.tar, explicit params, zstdcli, 4821112 silesia.tar, explicit params, zstdcli, 4821112
silesia.tar, uncompressed literals, zstdcli, 5122571 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, huffman literals, zstdcli, 5342074
silesia.tar, multithreaded with advanced params, zstdcli, 5122571 silesia.tar, multithreaded with advanced params, zstdcli, 5122571
github, level -5, zstdcli, 206407 github, level -5, zstdcli, 206407
@@ -173,9 +173,9 @@ github, level 9 with dict, zstdcli,
github, level 13, zstdcli, 134878 github, level 13, zstdcli, 134878
github, level 13 with dict, zstdcli, 41900 github, level 13 with dict, zstdcli, 41900
github, level 16, zstdcli, 135209 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, zstdcli, 134879
github, level 19 with dict, zstdcli, 39576 github, level 19 with dict, zstdcli, 39916
github, long distance mode, zstdcli, 138332 github, long distance mode, zstdcli, 138332
github, multithreaded, zstdcli, 138332 github, multithreaded, zstdcli, 138332
github, multithreaded long distance mode, 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, zstdcli, 35505
github.tar, level 13 with dict, zstdcli, 37134 github.tar, level 13 with dict, zstdcli, 37134
github.tar, level 16, zstdcli, 40470 github.tar, level 16, zstdcli, 40470
github.tar, level 16 with dict, zstdcli, 33378 github.tar, level 16 with dict, zstdcli, 33379
github.tar, level 19, zstdcli, 32280 github.tar, level 19, zstdcli, 32266
github.tar, level 19 with dict, zstdcli, 32716 github.tar, level 19 with dict, zstdcli, 32705
github.tar, no source size, zstdcli, 38832 github.tar, no source size, zstdcli, 38832
github.tar, no source size with dict, zstdcli, 38004 github.tar, no source size with dict, zstdcli, 38004
github.tar, long distance mode, zstdcli, 40236 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, small chain log, zstdcli, 41673
github.tar, explicit params, zstdcli, 41385 github.tar, explicit params, zstdcli, 41385
github.tar, uncompressed literals, zstdcli, 41529 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, huffman literals, zstdcli, 38857
github.tar, multithreaded with advanced params, zstdcli, 41529 github.tar, multithreaded with advanced params, zstdcli, 41529
silesia, level -5, advanced one pass, 6857372 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 1, advanced one pass, 4505658
silesia, level 12 row 2, advanced one pass, 4503429 silesia, level 12 row 2, advanced one pass, 4503429
silesia, level 13, advanced one pass, 4493990 silesia, level 13, advanced one pass, 4493990
silesia, level 16, advanced one pass, 4360041 silesia, level 16, advanced one pass, 4359652
silesia, level 19, advanced one pass, 4296055 silesia, level 19, advanced one pass, 4266582
silesia, no source size, advanced one pass, 4842075 silesia, no source size, advanced one pass, 4842075
silesia, long distance mode, advanced one pass, 4833710 silesia, long distance mode, advanced one pass, 4833710
silesia, multithreaded, advanced one pass, 4842075 silesia, multithreaded, advanced one pass, 4842075
@@ -259,7 +259,7 @@ silesia, small hash log, advanced
silesia, small chain log, advanced one pass, 4912197 silesia, small chain log, advanced one pass, 4912197
silesia, explicit params, advanced one pass, 4795840 silesia, explicit params, advanced one pass, 4795840
silesia, uncompressed literals, advanced one pass, 5120566 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, huffman literals, advanced one pass, 5321369
silesia, multithreaded with advanced params, advanced one pass, 5120566 silesia, multithreaded with advanced params, advanced one pass, 5120566
silesia.tar, level -5, advanced one pass, 6861055 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 1, advanced one pass, 4514517
silesia.tar, level 12 row 2, advanced one pass, 4514007 silesia.tar, level 12 row 2, advanced one pass, 4514007
silesia.tar, level 13, advanced one pass, 4502956 silesia.tar, level 13, advanced one pass, 4502956
silesia.tar, level 16, advanced one pass, 4360546 silesia.tar, level 16, advanced one pass, 4360385
silesia.tar, level 19, advanced one pass, 4265911 silesia.tar, level 19, advanced one pass, 4260939
silesia.tar, no source size, advanced one pass, 4854086 silesia.tar, no source size, advanced one pass, 4854086
silesia.tar, long distance mode, advanced one pass, 4840452 silesia.tar, long distance mode, advanced one pass, 4840452
silesia.tar, multithreaded, advanced one pass, 4854160 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, small chain log, advanced one pass, 4917041
silesia.tar, explicit params, advanced one pass, 4807274 silesia.tar, explicit params, advanced one pass, 4807274
silesia.tar, uncompressed literals, advanced one pass, 5122473 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, huffman literals, advanced one pass, 5341705
silesia.tar, multithreaded with advanced params, advanced one pass, 5122567 silesia.tar, multithreaded with advanced params, advanced one pass, 5122567
github, level -5, advanced one pass, 204407 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 copy, advanced one pass, 39948
github, level 13 with dict load, advanced one pass, 42624 github, level 13 with dict load, advanced one pass, 42624
github, level 16, advanced one pass, 133209 github, level 16, advanced one pass, 133209
github, level 16 with dict, advanced one pass, 37577 github, level 16 with dict, advanced one pass, 37902
github, level 16 with dict dms, advanced one pass, 37577 github, level 16 with dict dms, advanced one pass, 37902
github, level 16 with dict dds, advanced one pass, 37577 github, level 16 with dict dds, advanced one pass, 37902
github, level 16 with dict copy, advanced one pass, 37568 github, level 16 with dict copy, advanced one pass, 37892
github, level 16 with dict load, advanced one pass, 42338 github, level 16 with dict load, advanced one pass, 42402
github, level 19, advanced one pass, 132879 github, level 19, advanced one pass, 132879
github, level 19 with dict, advanced one pass, 37576 github, level 19 with dict, advanced one pass, 37916
github, level 19 with dict dms, advanced one pass, 37576 github, level 19 with dict dms, advanced one pass, 37916
github, level 19 with dict dds, advanced one pass, 37576 github, level 19 with dict dds, advanced one pass, 37916
github, level 19 with dict copy, advanced one pass, 37567 github, level 19 with dict copy, advanced one pass, 37906
github, level 19 with dict load, advanced one pass, 39613 github, level 19 with dict load, advanced one pass, 39770
github, no source size, advanced one pass, 136332 github, no source size, advanced one pass, 136332
github, no source size with dict, advanced one pass, 41148 github, no source size with dict, advanced one pass, 41148
github, long distance mode, advanced one pass, 136332 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 copy, advanced one pass, 37130
github.tar, level 13 with dict load, advanced one pass, 36010 github.tar, level 13 with dict load, advanced one pass, 36010
github.tar, level 16, advanced one pass, 40466 github.tar, level 16, advanced one pass, 40466
github.tar, level 16 with dict, advanced one pass, 33374 github.tar, level 16 with dict, advanced one pass, 33375
github.tar, level 16 with dict dms, advanced one pass, 33206 github.tar, level 16 with dict dms, advanced one pass, 33207
github.tar, level 16 with dict dds, advanced one pass, 33206 github.tar, level 16 with dict dds, advanced one pass, 33207
github.tar, level 16 with dict copy, advanced one pass, 33374 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 16 with dict load, advanced one pass, 39081
github.tar, level 19, advanced one pass, 32276 github.tar, level 19, advanced one pass, 32262
github.tar, level 19 with dict, advanced one pass, 32712 github.tar, level 19 with dict, advanced one pass, 32701
github.tar, level 19 with dict dms, advanced one pass, 32555 github.tar, level 19 with dict dms, advanced one pass, 32565
github.tar, level 19 with dict dds, advanced one pass, 32555 github.tar, level 19 with dict dds, advanced one pass, 32565
github.tar, level 19 with dict copy, advanced one pass, 32712 github.tar, level 19 with dict copy, advanced one pass, 32701
github.tar, level 19 with dict load, advanced one pass, 32479 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, advanced one pass, 38831
github.tar, no source size with dict, advanced one pass, 37995 github.tar, no source size with dict, advanced one pass, 37995
github.tar, long distance mode, advanced one pass, 40252 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, small chain log, advanced one pass, 41669
github.tar, explicit params, advanced one pass, 41385 github.tar, explicit params, advanced one pass, 41385
github.tar, uncompressed literals, advanced one pass, 41525 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, huffman literals, advanced one pass, 38853
github.tar, multithreaded with advanced params, advanced one pass, 41525 github.tar, multithreaded with advanced params, advanced one pass, 41525
silesia, level -5, advanced one pass small out, 6857372 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 1, advanced one pass small out, 4505658
silesia, level 12 row 2, advanced one pass small out, 4503429 silesia, level 12 row 2, advanced one pass small out, 4503429
silesia, level 13, advanced one pass small out, 4493990 silesia, level 13, advanced one pass small out, 4493990
silesia, level 16, advanced one pass small out, 4360041 silesia, level 16, advanced one pass small out, 4359652
silesia, level 19, advanced one pass small out, 4296055 silesia, level 19, advanced one pass small out, 4266582
silesia, no source size, advanced one pass small out, 4842075 silesia, no source size, advanced one pass small out, 4842075
silesia, long distance mode, advanced one pass small out, 4833710 silesia, long distance mode, advanced one pass small out, 4833710
silesia, multithreaded, advanced one pass small out, 4842075 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, small chain log, advanced one pass small out, 4912197
silesia, explicit params, advanced one pass small out, 4795840 silesia, explicit params, advanced one pass small out, 4795840
silesia, uncompressed literals, advanced one pass small out, 5120566 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, huffman literals, advanced one pass small out, 5321369
silesia, multithreaded with advanced params, advanced one pass small out, 5120566 silesia, multithreaded with advanced params, advanced one pass small out, 5120566
silesia.tar, level -5, advanced one pass small out, 6861055 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 1, advanced one pass small out, 4514517
silesia.tar, level 12 row 2, advanced one pass small out, 4514007 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 13, advanced one pass small out, 4502956
silesia.tar, level 16, advanced one pass small out, 4360546 silesia.tar, level 16, advanced one pass small out, 4360385
silesia.tar, level 19, advanced one pass small out, 4265911 silesia.tar, level 19, advanced one pass small out, 4260939
silesia.tar, no source size, advanced one pass small out, 4854086 silesia.tar, no source size, advanced one pass small out, 4854086
silesia.tar, long distance mode, advanced one pass small out, 4840452 silesia.tar, long distance mode, advanced one pass small out, 4840452
silesia.tar, multithreaded, advanced one pass small out, 4854160 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, small chain log, advanced one pass small out, 4917041
silesia.tar, explicit params, advanced one pass small out, 4807274 silesia.tar, explicit params, advanced one pass small out, 4807274
silesia.tar, uncompressed literals, advanced one pass small out, 5122473 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, huffman literals, advanced one pass small out, 5341705
silesia.tar, multithreaded with advanced params, advanced one pass small out, 5122567 silesia.tar, multithreaded with advanced params, advanced one pass small out, 5122567
github, level -5, advanced one pass small out, 204407 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 copy, advanced one pass small out, 39948
github, level 13 with dict load, advanced one pass small out, 42624 github, level 13 with dict load, advanced one pass small out, 42624
github, level 16, advanced one pass small out, 133209 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, advanced one pass small out, 37902
github, level 16 with dict dms, advanced one pass small out, 37577 github, level 16 with dict dms, advanced one pass small out, 37902
github, level 16 with dict dds, advanced one pass small out, 37577 github, level 16 with dict dds, advanced one pass small out, 37902
github, level 16 with dict copy, advanced one pass small out, 37568 github, level 16 with dict copy, advanced one pass small out, 37892
github, level 16 with dict load, advanced one pass small out, 42338 github, level 16 with dict load, advanced one pass small out, 42402
github, level 19, advanced one pass small out, 132879 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, advanced one pass small out, 37916
github, level 19 with dict dms, advanced one pass small out, 37576 github, level 19 with dict dms, advanced one pass small out, 37916
github, level 19 with dict dds, advanced one pass small out, 37576 github, level 19 with dict dds, advanced one pass small out, 37916
github, level 19 with dict copy, advanced one pass small out, 37567 github, level 19 with dict copy, advanced one pass small out, 37906
github, level 19 with dict load, advanced one pass small out, 39613 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, advanced one pass small out, 136332
github, no source size with dict, advanced one pass small out, 41148 github, no source size with dict, advanced one pass small out, 41148
github, long distance mode, advanced one pass small out, 136332 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 copy, advanced one pass small out, 37130
github.tar, level 13 with dict load, advanced one pass small out, 36010 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, advanced one pass small out, 40466
github.tar, level 16 with dict, 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, 33206 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, 33206 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, 33374 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 16 with dict load, advanced one pass small out, 39081
github.tar, level 19, advanced one pass small out, 32276 github.tar, level 19, advanced one pass small out, 32262
github.tar, level 19 with dict, advanced one pass small out, 32712 github.tar, level 19 with dict, advanced one pass small out, 32701
github.tar, level 19 with dict dms, advanced one pass small out, 32555 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, 32555 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, 32712 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, 32479 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, advanced one pass small out, 38831
github.tar, no source size with dict, advanced one pass small out, 37995 github.tar, no source size with dict, advanced one pass small out, 37995
github.tar, long distance mode, advanced one pass small out, 40252 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, small chain log, advanced one pass small out, 41669
github.tar, explicit params, advanced one pass small out, 41385 github.tar, explicit params, advanced one pass small out, 41385
github.tar, uncompressed literals, advanced one pass small out, 41525 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, huffman literals, advanced one pass small out, 38853
github.tar, multithreaded with advanced params, advanced one pass small out, 41525 github.tar, multithreaded with advanced params, advanced one pass small out, 41525
silesia, level -5, advanced streaming, 6854744 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 1, advanced streaming, 4505658
silesia, level 12 row 2, advanced streaming, 4503429 silesia, level 12 row 2, advanced streaming, 4503429
silesia, level 13, advanced streaming, 4493990 silesia, level 13, advanced streaming, 4493990
silesia, level 16, advanced streaming, 4360041 silesia, level 16, advanced streaming, 4359652
silesia, level 19, advanced streaming, 4296055 silesia, level 19, advanced streaming, 4266582
silesia, no source size, advanced streaming, 4842039 silesia, no source size, advanced streaming, 4842039
silesia, long distance mode, advanced streaming, 4833710 silesia, long distance mode, advanced streaming, 4833710
silesia, multithreaded, advanced streaming, 4842075 silesia, multithreaded, advanced streaming, 4842075
@@ -895,7 +895,7 @@ silesia, small hash log, advanced
silesia, small chain log, advanced streaming, 4912197 silesia, small chain log, advanced streaming, 4912197
silesia, explicit params, advanced streaming, 4795857 silesia, explicit params, advanced streaming, 4795857
silesia, uncompressed literals, advanced streaming, 5120566 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, huffman literals, advanced streaming, 5321370
silesia, multithreaded with advanced params, advanced streaming, 5120566 silesia, multithreaded with advanced params, advanced streaming, 5120566
silesia.tar, level -5, advanced streaming, 6856523 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 1, advanced streaming, 4514514
silesia.tar, level 12 row 2, advanced streaming, 4514003 silesia.tar, level 12 row 2, advanced streaming, 4514003
silesia.tar, level 13, advanced streaming, 4502956 silesia.tar, level 13, advanced streaming, 4502956
silesia.tar, level 16, advanced streaming, 4360546 silesia.tar, level 16, advanced streaming, 4360385
silesia.tar, level 19, advanced streaming, 4265911 silesia.tar, level 19, advanced streaming, 4260939
silesia.tar, no source size, advanced streaming, 4859267 silesia.tar, no source size, advanced streaming, 4859267
silesia.tar, long distance mode, advanced streaming, 4840452 silesia.tar, long distance mode, advanced streaming, 4840452
silesia.tar, multithreaded, advanced streaming, 4854160 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, small chain log, advanced streaming, 4917021
silesia.tar, explicit params, advanced streaming, 4807288 silesia.tar, explicit params, advanced streaming, 4807288
silesia.tar, uncompressed literals, advanced streaming, 5127423 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, huffman literals, advanced streaming, 5341712
silesia.tar, multithreaded with advanced params, advanced streaming, 5122567 silesia.tar, multithreaded with advanced params, advanced streaming, 5122567
github, level -5, advanced streaming, 204407 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 copy, advanced streaming, 39948
github, level 13 with dict load, advanced streaming, 42624 github, level 13 with dict load, advanced streaming, 42624
github, level 16, advanced streaming, 133209 github, level 16, advanced streaming, 133209
github, level 16 with dict, advanced streaming, 37577 github, level 16 with dict, advanced streaming, 37902
github, level 16 with dict dms, advanced streaming, 37577 github, level 16 with dict dms, advanced streaming, 37902
github, level 16 with dict dds, advanced streaming, 37577 github, level 16 with dict dds, advanced streaming, 37902
github, level 16 with dict copy, advanced streaming, 37568 github, level 16 with dict copy, advanced streaming, 37892
github, level 16 with dict load, advanced streaming, 42338 github, level 16 with dict load, advanced streaming, 42402
github, level 19, advanced streaming, 132879 github, level 19, advanced streaming, 132879
github, level 19 with dict, advanced streaming, 37576 github, level 19 with dict, advanced streaming, 37916
github, level 19 with dict dms, advanced streaming, 37576 github, level 19 with dict dms, advanced streaming, 37916
github, level 19 with dict dds, advanced streaming, 37576 github, level 19 with dict dds, advanced streaming, 37916
github, level 19 with dict copy, advanced streaming, 37567 github, level 19 with dict copy, advanced streaming, 37906
github, level 19 with dict load, advanced streaming, 39613 github, level 19 with dict load, advanced streaming, 39770
github, no source size, advanced streaming, 136332 github, no source size, advanced streaming, 136332
github, no source size with dict, advanced streaming, 41148 github, no source size with dict, advanced streaming, 41148
github, long distance mode, advanced streaming, 136332 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 copy, advanced streaming, 37130
github.tar, level 13 with dict load, advanced streaming, 36010 github.tar, level 13 with dict load, advanced streaming, 36010
github.tar, level 16, advanced streaming, 40466 github.tar, level 16, advanced streaming, 40466
github.tar, level 16 with dict, advanced streaming, 33374 github.tar, level 16 with dict, advanced streaming, 33375
github.tar, level 16 with dict dms, advanced streaming, 33206 github.tar, level 16 with dict dms, advanced streaming, 33207
github.tar, level 16 with dict dds, advanced streaming, 33206 github.tar, level 16 with dict dds, advanced streaming, 33207
github.tar, level 16 with dict copy, advanced streaming, 33374 github.tar, level 16 with dict copy, advanced streaming, 33375
github.tar, level 16 with dict load, advanced streaming, 39081 github.tar, level 16 with dict load, advanced streaming, 39081
github.tar, level 19, advanced streaming, 32276 github.tar, level 19, advanced streaming, 32262
github.tar, level 19 with dict, advanced streaming, 32712 github.tar, level 19 with dict, advanced streaming, 32701
github.tar, level 19 with dict dms, advanced streaming, 32555 github.tar, level 19 with dict dms, advanced streaming, 32565
github.tar, level 19 with dict dds, advanced streaming, 32555 github.tar, level 19 with dict dds, advanced streaming, 32565
github.tar, level 19 with dict copy, advanced streaming, 32712 github.tar, level 19 with dict copy, advanced streaming, 32701
github.tar, level 19 with dict load, advanced streaming, 32479 github.tar, level 19 with dict load, advanced streaming, 32428
github.tar, no source size, advanced streaming, 38828 github.tar, no source size, advanced streaming, 38828
github.tar, no source size with dict, advanced streaming, 38000 github.tar, no source size with dict, advanced streaming, 38000
github.tar, long distance mode, advanced streaming, 40252 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, small chain log, advanced streaming, 41669
github.tar, explicit params, advanced streaming, 41385 github.tar, explicit params, advanced streaming, 41385
github.tar, uncompressed literals, advanced streaming, 41525 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, huffman literals, advanced streaming, 38853
github.tar, multithreaded with advanced params, advanced streaming, 41525 github.tar, multithreaded with advanced params, advanced streaming, 41525
silesia, level -5, old streaming, 6854744 silesia, level -5, old streaming, 6854744
@@ -1194,11 +1194,11 @@ silesia, level 6, old stre
silesia, level 7, old streaming, 4570271 silesia, level 7, old streaming, 4570271
silesia, level 9, old streaming, 4545850 silesia, level 9, old streaming, 4545850
silesia, level 13, old streaming, 4493990 silesia, level 13, old streaming, 4493990
silesia, level 16, old streaming, 4360041 silesia, level 16, old streaming, 4359652
silesia, level 19, old streaming, 4296055 silesia, level 19, old streaming, 4266582
silesia, no source size, old streaming, 4842039 silesia, no source size, old streaming, 4842039
silesia, uncompressed literals, old streaming, 4842075 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, huffman literals, old streaming, 6172207
silesia.tar, level -5, old streaming, 6856523 silesia.tar, level -5, old streaming, 6856523
silesia.tar, level -3, old streaming, 6505954 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 7, old streaming, 4579823
silesia.tar, level 9, old streaming, 4555445 silesia.tar, level 9, old streaming, 4555445
silesia.tar, level 13, old streaming, 4502956 silesia.tar, level 13, old streaming, 4502956
silesia.tar, level 16, old streaming, 4360546 silesia.tar, level 16, old streaming, 4360385
silesia.tar, level 19, old streaming, 4265911 silesia.tar, level 19, old streaming, 4260939
silesia.tar, no source size, old streaming, 4859267 silesia.tar, no source size, old streaming, 4859267
silesia.tar, uncompressed literals, old streaming, 4859271 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 silesia.tar, huffman literals, old streaming, 6179056
github, level -5, old streaming, 204407 github, level -5, old streaming, 204407
github, level -5 with dict, old streaming, 45832 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, old streaming, 132878
github, level 13 with dict, old streaming, 39900 github, level 13 with dict, old streaming, 39900
github, level 16, old streaming, 133209 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, 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, old streaming, 140599
github, no source size with dict, old streaming, 40654 github, no source size with dict, old streaming, 40654
github, uncompressed literals, old streaming, 136332 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, old streaming, 35501
github.tar, level 13 with dict, old streaming, 37130 github.tar, level 13 with dict, old streaming, 37130
github.tar, level 16, old streaming, 40466 github.tar, level 16, old streaming, 40466
github.tar, level 16 with dict, old streaming, 33374 github.tar, level 16 with dict, old streaming, 33375
github.tar, level 19, old streaming, 32276 github.tar, level 19, old streaming, 32262
github.tar, level 19 with dict, old streaming, 32712 github.tar, level 19 with dict, old streaming, 32701
github.tar, no source size, old streaming, 38828 github.tar, no source size, old streaming, 38828
github.tar, no source size with dict, old streaming, 38000 github.tar, no source size with dict, old streaming, 38000
github.tar, uncompressed literals, old streaming, 38831 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 github.tar, huffman literals, old streaming, 42560
silesia, level -5, old streaming advanced, 6854744 silesia, level -5, old streaming advanced, 6854744
silesia, level -3, old streaming advanced, 6503319 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 7, old streaming advanced, 4570271
silesia, level 9, old streaming advanced, 4545850 silesia, level 9, old streaming advanced, 4545850
silesia, level 13, old streaming advanced, 4493990 silesia, level 13, old streaming advanced, 4493990
silesia, level 16, old streaming advanced, 4360041 silesia, level 16, old streaming advanced, 4359652
silesia, level 19, old streaming advanced, 4296055 silesia, level 19, old streaming advanced, 4266582
silesia, no source size, old streaming advanced, 4842039 silesia, no source size, old streaming advanced, 4842039
silesia, long distance mode, old streaming advanced, 4842075 silesia, long distance mode, old streaming advanced, 4842075
silesia, multithreaded, 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, small chain log, old streaming advanced, 4912197
silesia, explicit params, old streaming advanced, 4795857 silesia, explicit params, old streaming advanced, 4795857
silesia, uncompressed literals, old streaming advanced, 4842075 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, huffman literals, old streaming advanced, 6172207
silesia, multithreaded with advanced params, old streaming advanced, 4842075 silesia, multithreaded with advanced params, old streaming advanced, 4842075
silesia.tar, level -5, old streaming advanced, 6856523 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 7, old streaming advanced, 4579823
silesia.tar, level 9, old streaming advanced, 4555445 silesia.tar, level 9, old streaming advanced, 4555445
silesia.tar, level 13, old streaming advanced, 4502956 silesia.tar, level 13, old streaming advanced, 4502956
silesia.tar, level 16, old streaming advanced, 4360546 silesia.tar, level 16, old streaming advanced, 4360385
silesia.tar, level 19, old streaming advanced, 4265911 silesia.tar, level 19, old streaming advanced, 4260939
silesia.tar, no source size, old streaming advanced, 4859267 silesia.tar, no source size, old streaming advanced, 4859267
silesia.tar, long distance mode, old streaming advanced, 4859271 silesia.tar, long distance mode, old streaming advanced, 4859271
silesia.tar, multithreaded, 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, small chain log, old streaming advanced, 4917021
silesia.tar, explicit params, old streaming advanced, 4807288 silesia.tar, explicit params, old streaming advanced, 4807288
silesia.tar, uncompressed literals, old streaming advanced, 4859271 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, huffman literals, old streaming advanced, 6179056
silesia.tar, multithreaded with advanced params, old streaming advanced, 4859271 silesia.tar, multithreaded with advanced params, old streaming advanced, 4859271
github, level -5, old streaming advanced, 213265 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, old streaming advanced, 138676
github, level 13 with dict, old streaming advanced, 39725 github, level 13 with dict, old streaming advanced, 39725
github, level 16, old streaming advanced, 138575 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, 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, old streaming advanced, 140599
github, no source size with dict, old streaming advanced, 40608 github, no source size with dict, old streaming advanced, 40608
github, long distance mode, old streaming advanced, 141104 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 13 with dict, old streaming advanced, 35807
github.tar, level 16, old streaming advanced, 40466 github.tar, level 16, old streaming advanced, 40466
github.tar, level 16 with dict, old streaming advanced, 38578 github.tar, level 16 with dict, old streaming advanced, 38578
github.tar, level 19, old streaming advanced, 32276 github.tar, level 19, old streaming advanced, 32262
github.tar, level 19 with dict, old streaming advanced, 32704 github.tar, level 19 with dict, old streaming advanced, 32678
github.tar, no source size, old streaming advanced, 38828 github.tar, no source size, old streaming advanced, 38828
github.tar, no source size with dict, old streaming advanced, 38015 github.tar, no source size with dict, old streaming advanced, 38015
github.tar, long distance mode, old streaming advanced, 38831 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, small chain log, old streaming advanced, 41669
github.tar, explicit params, old streaming advanced, 41385 github.tar, explicit params, old streaming advanced, 41385
github.tar, uncompressed literals, old streaming advanced, 38831 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, huffman literals, old streaming advanced, 42560
github.tar, multithreaded with advanced params, old streaming advanced, 38831 github.tar, multithreaded with advanced params, old streaming advanced, 38831
github, level -5 with dict, old streaming cdict, 45832 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 7 with dict, old streaming cdict, 38765
github, level 9 with dict, old streaming cdict, 39439 github, level 9 with dict, old streaming cdict, 39439
github, level 13 with dict, old streaming cdict, 39900 github, level 13 with dict, old streaming cdict, 39900
github, level 16 with dict, old streaming cdict, 37577 github, level 16 with dict, old streaming cdict, 37902
github, level 19 with dict, old streaming cdict, 37576 github, level 19 with dict, old streaming cdict, 37916
github, no source size with dict, old streaming cdict, 40654 github, no source size with dict, old streaming cdict, 40654
github.tar, level -5 with dict, old streaming cdict, 51286 github.tar, level -5 with dict, old streaming cdict, 51286
github.tar, level -3 with dict, old streaming cdict, 45147 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 9 with dict, old streaming cdict, 36322
github.tar, level 13 with dict, old streaming cdict, 36010 github.tar, level 13 with dict, old streaming cdict, 36010
github.tar, level 16 with dict, old streaming cdict, 39081 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.tar, no source size with dict, old streaming cdict, 38000
github, level -5 with dict, old streaming advanced cdict, 46708 github, level -5 with dict, old streaming advanced cdict, 46708
github, level -3 with dict, old streaming advanced cdict, 45476 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 7 with dict, old streaming advanced cdict, 38875
github, level 9 with dict, old streaming advanced cdict, 38941 github, level 9 with dict, old streaming advanced cdict, 38941
github, level 13 with dict, old streaming advanced cdict, 39725 github, level 13 with dict, old streaming advanced cdict, 39725
github, level 16 with dict, old streaming advanced cdict, 40789 github, level 16 with dict, old streaming advanced cdict, 40804
github, level 19 with dict, old streaming advanced cdict, 37576 github, level 19 with dict, old streaming advanced cdict, 37916
github, no source size with dict, old streaming advanced cdict, 40608 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 -5 with dict, old streaming advanced cdict, 50791
github.tar, level -3 with dict, old streaming advanced cdict, 44926 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 9 with dict, old streaming advanced cdict, 36241
github.tar, level 13 with dict, old streaming advanced cdict, 35807 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 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 github.tar, no source size with dict, old streaming advanced cdict, 38015
1 Data Config Method Total compressed size
11 silesia.tar level 7 compress simple 4579828
12 silesia.tar level 9 compress simple 4555448
13 silesia.tar level 13 compress simple 4502956
14 silesia.tar level 16 compress simple 4360546 4360385
15 silesia.tar level 19 compress simple 4265911 4260939
16 silesia.tar uncompressed literals compress simple 4854086
17 silesia.tar uncompressed literals optimal compress simple 4265911 4260939
18 silesia.tar huffman literals compress simple 6179047
19 github.tar level -5 compress simple 52115
20 github.tar level -3 compress simple 45678
29 github.tar level 9 compress simple 36723
30 github.tar level 13 compress simple 35501
31 github.tar level 16 compress simple 40466
32 github.tar level 19 compress simple 32276 32262
33 github.tar uncompressed literals compress simple 38831
34 github.tar uncompressed literals optimal compress simple 32276 32262
35 github.tar huffman literals compress simple 42560
36 silesia level -5 compress cctx 6857372
37 silesia level -3 compress cctx 6503412
45 silesia level 7 compress cctx 4570271
46 silesia level 9 compress cctx 4545850
47 silesia level 13 compress cctx 4493990
48 silesia level 16 compress cctx 4360041 4359652
49 silesia level 19 compress cctx 4296055 4266582
50 silesia long distance mode compress cctx 4842075
51 silesia multithreaded compress cctx 4842075
52 silesia multithreaded long distance mode compress cctx 4842075
55 silesia small chain log compress cctx 4912197
56 silesia explicit params compress cctx 4794318
57 silesia uncompressed literals compress cctx 4842075
58 silesia uncompressed literals optimal compress cctx 4296055 4266582
59 silesia huffman literals compress cctx 6172202
60 silesia multithreaded with advanced params compress cctx 4842075
61 github level -5 compress cctx 204407
83 github level 13 compress cctx 132878
84 github level 13 with dict compress cctx 39948
85 github level 16 compress cctx 133209
86 github level 16 with dict compress cctx 37568 37892
87 github level 19 compress cctx 132879
88 github level 19 with dict compress cctx 37567 37906
89 github long distance mode compress cctx 141069
90 github multithreaded compress cctx 141069
91 github multithreaded long distance mode compress cctx 141069
109 silesia level 7 zstdcli 4570319
110 silesia level 9 zstdcli 4545898
111 silesia level 13 zstdcli 4494038
112 silesia level 16 zstdcli 4360089 4359700
113 silesia level 19 zstdcli 4296103 4266630
114 silesia long distance mode zstdcli 4833785
115 silesia multithreaded zstdcli 4842123
116 silesia multithreaded long distance mode zstdcli 4833785
119 silesia small chain log zstdcli 4912245
120 silesia explicit params zstdcli 4795840
121 silesia uncompressed literals zstdcli 5120614
122 silesia uncompressed literals optimal zstdcli 4319566 4316928
123 silesia huffman literals zstdcli 5321417
124 silesia multithreaded with advanced params zstdcli 5120614
125 silesia.tar level -5 zstdcli 6862049
134 silesia.tar level 7 zstdcli 4581791
135 silesia.tar level 9 zstdcli 4555452
136 silesia.tar level 13 zstdcli 4502960
137 silesia.tar level 16 zstdcli 4360550 4360389
138 silesia.tar level 19 zstdcli 4265915 4260943
139 silesia.tar no source size zstdcli 4854160
140 silesia.tar long distance mode zstdcli 4845745
141 silesia.tar multithreaded zstdcli 4854164
145 silesia.tar small chain log zstdcli 4917022
146 silesia.tar explicit params zstdcli 4821112
147 silesia.tar uncompressed literals zstdcli 5122571
148 silesia.tar uncompressed literals optimal zstdcli 4310145 4308455
149 silesia.tar huffman literals zstdcli 5342074
150 silesia.tar multithreaded with advanced params zstdcli 5122571
151 github level -5 zstdcli 206407
173 github level 13 zstdcli 134878
174 github level 13 with dict zstdcli 41900
175 github level 16 zstdcli 135209
176 github level 16 with dict zstdcli 39577 39902
177 github level 19 zstdcli 134879
178 github level 19 with dict zstdcli 39576 39916
179 github long distance mode zstdcli 138332
180 github multithreaded zstdcli 138332
181 github multithreaded long distance mode zstdcli 138332
212 github.tar level 13 zstdcli 35505
213 github.tar level 13 with dict zstdcli 37134
214 github.tar level 16 zstdcli 40470
215 github.tar level 16 with dict zstdcli 33378 33379
216 github.tar level 19 zstdcli 32280 32266
217 github.tar level 19 with dict zstdcli 32716 32705
218 github.tar no source size zstdcli 38832
219 github.tar no source size with dict zstdcli 38004
220 github.tar long distance mode zstdcli 40236
225 github.tar small chain log zstdcli 41673
226 github.tar explicit params zstdcli 41385
227 github.tar uncompressed literals zstdcli 41529
228 github.tar uncompressed literals optimal zstdcli 35401 35360
229 github.tar huffman literals zstdcli 38857
230 github.tar multithreaded with advanced params zstdcli 41529
231 silesia level -5 advanced one pass 6857372
248 silesia level 12 row 1 advanced one pass 4505658
249 silesia level 12 row 2 advanced one pass 4503429
250 silesia level 13 advanced one pass 4493990
251 silesia level 16 advanced one pass 4360041 4359652
252 silesia level 19 advanced one pass 4296055 4266582
253 silesia no source size advanced one pass 4842075
254 silesia long distance mode advanced one pass 4833710
255 silesia multithreaded advanced one pass 4842075
259 silesia small chain log advanced one pass 4912197
260 silesia explicit params advanced one pass 4795840
261 silesia uncompressed literals advanced one pass 5120566
262 silesia uncompressed literals optimal advanced one pass 4319518 4316880
263 silesia huffman literals advanced one pass 5321369
264 silesia multithreaded with advanced params advanced one pass 5120566
265 silesia.tar level -5 advanced one pass 6861055
282 silesia.tar level 12 row 1 advanced one pass 4514517
283 silesia.tar level 12 row 2 advanced one pass 4514007
284 silesia.tar level 13 advanced one pass 4502956
285 silesia.tar level 16 advanced one pass 4360546 4360385
286 silesia.tar level 19 advanced one pass 4265911 4260939
287 silesia.tar no source size advanced one pass 4854086
288 silesia.tar long distance mode advanced one pass 4840452
289 silesia.tar multithreaded advanced one pass 4854160
293 silesia.tar small chain log advanced one pass 4917041
294 silesia.tar explicit params advanced one pass 4807274
295 silesia.tar uncompressed literals advanced one pass 5122473
296 silesia.tar uncompressed literals optimal advanced one pass 4310141 4308451
297 silesia.tar huffman literals advanced one pass 5341705
298 silesia.tar multithreaded with advanced params advanced one pass 5122567
299 github level -5 advanced one pass 204407
397 github level 13 with dict copy advanced one pass 39948
398 github level 13 with dict load advanced one pass 42624
399 github level 16 advanced one pass 133209
400 github level 16 with dict advanced one pass 37577 37902
401 github level 16 with dict dms advanced one pass 37577 37902
402 github level 16 with dict dds advanced one pass 37577 37902
403 github level 16 with dict copy advanced one pass 37568 37892
404 github level 16 with dict load advanced one pass 42338 42402
405 github level 19 advanced one pass 132879
406 github level 19 with dict advanced one pass 37576 37916
407 github level 19 with dict dms advanced one pass 37576 37916
408 github level 19 with dict dds advanced one pass 37576 37916
409 github level 19 with dict copy advanced one pass 37567 37906
410 github level 19 with dict load advanced one pass 39613 39770
411 github no source size advanced one pass 136332
412 github no source size with dict advanced one pass 41148
413 github long distance mode advanced one pass 136332
522 github.tar level 13 with dict copy advanced one pass 37130
523 github.tar level 13 with dict load advanced one pass 36010
524 github.tar level 16 advanced one pass 40466
525 github.tar level 16 with dict advanced one pass 33374 33375
526 github.tar level 16 with dict dms advanced one pass 33206 33207
527 github.tar level 16 with dict dds advanced one pass 33206 33207
528 github.tar level 16 with dict copy advanced one pass 33374 33375
529 github.tar level 16 with dict load advanced one pass 39081
530 github.tar level 19 advanced one pass 32276 32262
531 github.tar level 19 with dict advanced one pass 32712 32701
532 github.tar level 19 with dict dms advanced one pass 32555 32565
533 github.tar level 19 with dict dds advanced one pass 32555 32565
534 github.tar level 19 with dict copy advanced one pass 32712 32701
535 github.tar level 19 with dict load advanced one pass 32479 32428
536 github.tar no source size advanced one pass 38831
537 github.tar no source size with dict advanced one pass 37995
538 github.tar long distance mode advanced one pass 40252
543 github.tar small chain log advanced one pass 41669
544 github.tar explicit params advanced one pass 41385
545 github.tar uncompressed literals advanced one pass 41525
546 github.tar uncompressed literals optimal advanced one pass 35397 35356
547 github.tar huffman literals advanced one pass 38853
548 github.tar multithreaded with advanced params advanced one pass 41525
549 silesia level -5 advanced one pass small out 6857372
566 silesia level 12 row 1 advanced one pass small out 4505658
567 silesia level 12 row 2 advanced one pass small out 4503429
568 silesia level 13 advanced one pass small out 4493990
569 silesia level 16 advanced one pass small out 4360041 4359652
570 silesia level 19 advanced one pass small out 4296055 4266582
571 silesia no source size advanced one pass small out 4842075
572 silesia long distance mode advanced one pass small out 4833710
573 silesia multithreaded advanced one pass small out 4842075
577 silesia small chain log advanced one pass small out 4912197
578 silesia explicit params advanced one pass small out 4795840
579 silesia uncompressed literals advanced one pass small out 5120566
580 silesia uncompressed literals optimal advanced one pass small out 4319518 4316880
581 silesia huffman literals advanced one pass small out 5321369
582 silesia multithreaded with advanced params advanced one pass small out 5120566
583 silesia.tar level -5 advanced one pass small out 6861055
600 silesia.tar level 12 row 1 advanced one pass small out 4514517
601 silesia.tar level 12 row 2 advanced one pass small out 4514007
602 silesia.tar level 13 advanced one pass small out 4502956
603 silesia.tar level 16 advanced one pass small out 4360546 4360385
604 silesia.tar level 19 advanced one pass small out 4265911 4260939
605 silesia.tar no source size advanced one pass small out 4854086
606 silesia.tar long distance mode advanced one pass small out 4840452
607 silesia.tar multithreaded advanced one pass small out 4854160
611 silesia.tar small chain log advanced one pass small out 4917041
612 silesia.tar explicit params advanced one pass small out 4807274
613 silesia.tar uncompressed literals advanced one pass small out 5122473
614 silesia.tar uncompressed literals optimal advanced one pass small out 4310141 4308451
615 silesia.tar huffman literals advanced one pass small out 5341705
616 silesia.tar multithreaded with advanced params advanced one pass small out 5122567
617 github level -5 advanced one pass small out 204407
715 github level 13 with dict copy advanced one pass small out 39948
716 github level 13 with dict load advanced one pass small out 42624
717 github level 16 advanced one pass small out 133209
718 github level 16 with dict advanced one pass small out 37577 37902
719 github level 16 with dict dms advanced one pass small out 37577 37902
720 github level 16 with dict dds advanced one pass small out 37577 37902
721 github level 16 with dict copy advanced one pass small out 37568 37892
722 github level 16 with dict load advanced one pass small out 42338 42402
723 github level 19 advanced one pass small out 132879
724 github level 19 with dict advanced one pass small out 37576 37916
725 github level 19 with dict dms advanced one pass small out 37576 37916
726 github level 19 with dict dds advanced one pass small out 37576 37916
727 github level 19 with dict copy advanced one pass small out 37567 37906
728 github level 19 with dict load advanced one pass small out 39613 39770
729 github no source size advanced one pass small out 136332
730 github no source size with dict advanced one pass small out 41148
731 github long distance mode advanced one pass small out 136332
840 github.tar level 13 with dict copy advanced one pass small out 37130
841 github.tar level 13 with dict load advanced one pass small out 36010
842 github.tar level 16 advanced one pass small out 40466
843 github.tar level 16 with dict advanced one pass small out 33374 33375
844 github.tar level 16 with dict dms advanced one pass small out 33206 33207
845 github.tar level 16 with dict dds advanced one pass small out 33206 33207
846 github.tar level 16 with dict copy advanced one pass small out 33374 33375
847 github.tar level 16 with dict load advanced one pass small out 39081
848 github.tar level 19 advanced one pass small out 32276 32262
849 github.tar level 19 with dict advanced one pass small out 32712 32701
850 github.tar level 19 with dict dms advanced one pass small out 32555 32565
851 github.tar level 19 with dict dds advanced one pass small out 32555 32565
852 github.tar level 19 with dict copy advanced one pass small out 32712 32701
853 github.tar level 19 with dict load advanced one pass small out 32479 32428
854 github.tar no source size advanced one pass small out 38831
855 github.tar no source size with dict advanced one pass small out 37995
856 github.tar long distance mode advanced one pass small out 40252
861 github.tar small chain log advanced one pass small out 41669
862 github.tar explicit params advanced one pass small out 41385
863 github.tar uncompressed literals advanced one pass small out 41525
864 github.tar uncompressed literals optimal advanced one pass small out 35397 35356
865 github.tar huffman literals advanced one pass small out 38853
866 github.tar multithreaded with advanced params advanced one pass small out 41525
867 silesia level -5 advanced streaming 6854744
884 silesia level 12 row 1 advanced streaming 4505658
885 silesia level 12 row 2 advanced streaming 4503429
886 silesia level 13 advanced streaming 4493990
887 silesia level 16 advanced streaming 4360041 4359652
888 silesia level 19 advanced streaming 4296055 4266582
889 silesia no source size advanced streaming 4842039
890 silesia long distance mode advanced streaming 4833710
891 silesia multithreaded advanced streaming 4842075
895 silesia small chain log advanced streaming 4912197
896 silesia explicit params advanced streaming 4795857
897 silesia uncompressed literals advanced streaming 5120566
898 silesia uncompressed literals optimal advanced streaming 4319518 4316880
899 silesia huffman literals advanced streaming 5321370
900 silesia multithreaded with advanced params advanced streaming 5120566
901 silesia.tar level -5 advanced streaming 6856523
918 silesia.tar level 12 row 1 advanced streaming 4514514
919 silesia.tar level 12 row 2 advanced streaming 4514003
920 silesia.tar level 13 advanced streaming 4502956
921 silesia.tar level 16 advanced streaming 4360546 4360385
922 silesia.tar level 19 advanced streaming 4265911 4260939
923 silesia.tar no source size advanced streaming 4859267
924 silesia.tar long distance mode advanced streaming 4840452
925 silesia.tar multithreaded advanced streaming 4854160
929 silesia.tar small chain log advanced streaming 4917021
930 silesia.tar explicit params advanced streaming 4807288
931 silesia.tar uncompressed literals advanced streaming 5127423
932 silesia.tar uncompressed literals optimal advanced streaming 4310141 4308451
933 silesia.tar huffman literals advanced streaming 5341712
934 silesia.tar multithreaded with advanced params advanced streaming 5122567
935 github level -5 advanced streaming 204407
1033 github level 13 with dict copy advanced streaming 39948
1034 github level 13 with dict load advanced streaming 42624
1035 github level 16 advanced streaming 133209
1036 github level 16 with dict advanced streaming 37577 37902
1037 github level 16 with dict dms advanced streaming 37577 37902
1038 github level 16 with dict dds advanced streaming 37577 37902
1039 github level 16 with dict copy advanced streaming 37568 37892
1040 github level 16 with dict load advanced streaming 42338 42402
1041 github level 19 advanced streaming 132879
1042 github level 19 with dict advanced streaming 37576 37916
1043 github level 19 with dict dms advanced streaming 37576 37916
1044 github level 19 with dict dds advanced streaming 37576 37916
1045 github level 19 with dict copy advanced streaming 37567 37906
1046 github level 19 with dict load advanced streaming 39613 39770
1047 github no source size advanced streaming 136332
1048 github no source size with dict advanced streaming 41148
1049 github long distance mode advanced streaming 136332
1158 github.tar level 13 with dict copy advanced streaming 37130
1159 github.tar level 13 with dict load advanced streaming 36010
1160 github.tar level 16 advanced streaming 40466
1161 github.tar level 16 with dict advanced streaming 33374 33375
1162 github.tar level 16 with dict dms advanced streaming 33206 33207
1163 github.tar level 16 with dict dds advanced streaming 33206 33207
1164 github.tar level 16 with dict copy advanced streaming 33374 33375
1165 github.tar level 16 with dict load advanced streaming 39081
1166 github.tar level 19 advanced streaming 32276 32262
1167 github.tar level 19 with dict advanced streaming 32712 32701
1168 github.tar level 19 with dict dms advanced streaming 32555 32565
1169 github.tar level 19 with dict dds advanced streaming 32555 32565
1170 github.tar level 19 with dict copy advanced streaming 32712 32701
1171 github.tar level 19 with dict load advanced streaming 32479 32428
1172 github.tar no source size advanced streaming 38828
1173 github.tar no source size with dict advanced streaming 38000
1174 github.tar long distance mode advanced streaming 40252
1179 github.tar small chain log advanced streaming 41669
1180 github.tar explicit params advanced streaming 41385
1181 github.tar uncompressed literals advanced streaming 41525
1182 github.tar uncompressed literals optimal advanced streaming 35397 35356
1183 github.tar huffman literals advanced streaming 38853
1184 github.tar multithreaded with advanced params advanced streaming 41525
1185 silesia level -5 old streaming 6854744
1194 silesia level 7 old streaming 4570271
1195 silesia level 9 old streaming 4545850
1196 silesia level 13 old streaming 4493990
1197 silesia level 16 old streaming 4360041 4359652
1198 silesia level 19 old streaming 4296055 4266582
1199 silesia no source size old streaming 4842039
1200 silesia uncompressed literals old streaming 4842075
1201 silesia uncompressed literals optimal old streaming 4296055 4266582
1202 silesia huffman literals old streaming 6172207
1203 silesia.tar level -5 old streaming 6856523
1204 silesia.tar level -3 old streaming 6505954
1212 silesia.tar level 7 old streaming 4579823
1213 silesia.tar level 9 old streaming 4555445
1214 silesia.tar level 13 old streaming 4502956
1215 silesia.tar level 16 old streaming 4360546 4360385
1216 silesia.tar level 19 old streaming 4265911 4260939
1217 silesia.tar no source size old streaming 4859267
1218 silesia.tar uncompressed literals old streaming 4859271
1219 silesia.tar uncompressed literals optimal old streaming 4265911 4260939
1220 silesia.tar huffman literals old streaming 6179056
1221 github level -5 old streaming 204407
1222 github level -5 with dict old streaming 45832
1243 github level 13 old streaming 132878
1244 github level 13 with dict old streaming 39900
1245 github level 16 old streaming 133209
1246 github level 16 with dict old streaming 37577 37902
1247 github level 19 old streaming 132879
1248 github level 19 with dict old streaming 37576 37916
1249 github no source size old streaming 140599
1250 github no source size with dict old streaming 40654
1251 github uncompressed literals old streaming 136332
1276 github.tar level 13 old streaming 35501
1277 github.tar level 13 with dict old streaming 37130
1278 github.tar level 16 old streaming 40466
1279 github.tar level 16 with dict old streaming 33374 33375
1280 github.tar level 19 old streaming 32276 32262
1281 github.tar level 19 with dict old streaming 32712 32701
1282 github.tar no source size old streaming 38828
1283 github.tar no source size with dict old streaming 38000
1284 github.tar uncompressed literals old streaming 38831
1285 github.tar uncompressed literals optimal old streaming 32276 32262
1286 github.tar huffman literals old streaming 42560
1287 silesia level -5 old streaming advanced 6854744
1288 silesia level -3 old streaming advanced 6503319
1296 silesia level 7 old streaming advanced 4570271
1297 silesia level 9 old streaming advanced 4545850
1298 silesia level 13 old streaming advanced 4493990
1299 silesia level 16 old streaming advanced 4360041 4359652
1300 silesia level 19 old streaming advanced 4296055 4266582
1301 silesia no source size old streaming advanced 4842039
1302 silesia long distance mode old streaming advanced 4842075
1303 silesia multithreaded old streaming advanced 4842075
1307 silesia small chain log old streaming advanced 4912197
1308 silesia explicit params old streaming advanced 4795857
1309 silesia uncompressed literals old streaming advanced 4842075
1310 silesia uncompressed literals optimal old streaming advanced 4296055 4266582
1311 silesia huffman literals old streaming advanced 6172207
1312 silesia multithreaded with advanced params old streaming advanced 4842075
1313 silesia.tar level -5 old streaming advanced 6856523
1322 silesia.tar level 7 old streaming advanced 4579823
1323 silesia.tar level 9 old streaming advanced 4555445
1324 silesia.tar level 13 old streaming advanced 4502956
1325 silesia.tar level 16 old streaming advanced 4360546 4360385
1326 silesia.tar level 19 old streaming advanced 4265911 4260939
1327 silesia.tar no source size old streaming advanced 4859267
1328 silesia.tar long distance mode old streaming advanced 4859271
1329 silesia.tar multithreaded old streaming advanced 4859271
1333 silesia.tar small chain log old streaming advanced 4917021
1334 silesia.tar explicit params old streaming advanced 4807288
1335 silesia.tar uncompressed literals old streaming advanced 4859271
1336 silesia.tar uncompressed literals optimal old streaming advanced 4265911 4260939
1337 silesia.tar huffman literals old streaming advanced 6179056
1338 silesia.tar multithreaded with advanced params old streaming advanced 4859271
1339 github level -5 old streaming advanced 213265
1361 github level 13 old streaming advanced 138676
1362 github level 13 with dict old streaming advanced 39725
1363 github level 16 old streaming advanced 138575
1364 github level 16 with dict old streaming advanced 40789 40804
1365 github level 19 old streaming advanced 132879
1366 github level 19 with dict old streaming advanced 37576 37916
1367 github no source size old streaming advanced 140599
1368 github no source size with dict old streaming advanced 40608
1369 github long distance mode old streaming advanced 141104
1403 github.tar level 13 with dict old streaming advanced 35807
1404 github.tar level 16 old streaming advanced 40466
1405 github.tar level 16 with dict old streaming advanced 38578
1406 github.tar level 19 old streaming advanced 32276 32262
1407 github.tar level 19 with dict old streaming advanced 32704 32678
1408 github.tar no source size old streaming advanced 38828
1409 github.tar no source size with dict old streaming advanced 38015
1410 github.tar long distance mode old streaming advanced 38831
1415 github.tar small chain log old streaming advanced 41669
1416 github.tar explicit params old streaming advanced 41385
1417 github.tar uncompressed literals old streaming advanced 38831
1418 github.tar uncompressed literals optimal old streaming advanced 32276 32262
1419 github.tar huffman literals old streaming advanced 42560
1420 github.tar multithreaded with advanced params old streaming advanced 38831
1421 github level -5 with dict old streaming cdict 45832
1430 github level 7 with dict old streaming cdict 38765
1431 github level 9 with dict old streaming cdict 39439
1432 github level 13 with dict old streaming cdict 39900
1433 github level 16 with dict old streaming cdict 37577 37902
1434 github level 19 with dict old streaming cdict 37576 37916
1435 github no source size with dict old streaming cdict 40654
1436 github.tar level -5 with dict old streaming cdict 51286
1437 github.tar level -3 with dict old streaming cdict 45147
1446 github.tar level 9 with dict old streaming cdict 36322
1447 github.tar level 13 with dict old streaming cdict 36010
1448 github.tar level 16 with dict old streaming cdict 39081
1449 github.tar level 19 with dict old streaming cdict 32479 32428
1450 github.tar no source size with dict old streaming cdict 38000
1451 github level -5 with dict old streaming advanced cdict 46708
1452 github level -3 with dict old streaming advanced cdict 45476
1460 github level 7 with dict old streaming advanced cdict 38875
1461 github level 9 with dict old streaming advanced cdict 38941
1462 github level 13 with dict old streaming advanced cdict 39725
1463 github level 16 with dict old streaming advanced cdict 40789 40804
1464 github level 19 with dict old streaming advanced cdict 37576 37916
1465 github no source size with dict old streaming advanced cdict 40608
1466 github.tar level -5 with dict old streaming advanced cdict 50791
1467 github.tar level -3 with dict old streaming advanced cdict 44926
1476 github.tar level 9 with dict old streaming advanced cdict 36241
1477 github.tar level 13 with dict old streaming advanced cdict 35807
1478 github.tar level 16 with dict old streaming advanced cdict 38578
1479 github.tar level 19 with dict old streaming advanced cdict 32704 32678
1480 github.tar no source size with dict old streaming advanced cdict 38015
+53 -1
View File
@@ -1920,7 +1920,7 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests)
DISPLAYLEVEL(3, "test%3i : Block-Level External Sequence Producer API: ", testNb++); DISPLAYLEVEL(3, "test%3i : Block-Level External Sequence Producer API: ", testNb++);
{ {
size_t const dstBufSize = ZSTD_compressBound(CNBufferSize); 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; size_t const checkBufSize = CNBufferSize;
BYTE* const checkBuf = (BYTE*)malloc(checkBufSize); BYTE* const checkBuf = (BYTE*)malloc(checkBufSize);
int enableFallback; int enableFallback;
@@ -2356,6 +2356,58 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests)
} }
DISPLAYLEVEL(3, "OK \n"); 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: _end:
FUZ_freeDictionary(dictionary); FUZ_freeDictionary(dictionary);
ZSTD_freeCStream(zc); ZSTD_freeCStream(zc);
+17 -48
View File
@@ -77,9 +77,7 @@ int main _Z_OF((int argc, char *argv[]));
void *myalloc _Z_OF((void *, unsigned, unsigned)); void *myalloc _Z_OF((void *, unsigned, unsigned));
void myfree _Z_OF((void *, void *)); void myfree _Z_OF((void *, void *));
void *myalloc(q, n, m) void *myalloc(void *q, unsigned n, unsigned m)
void *q;
unsigned n, m;
{ {
void *buf = calloc(n, m); void *buf = calloc(n, m);
q = Z_NULL; q = Z_NULL;
@@ -110,10 +108,8 @@ void test_gzio _Z_OF((const char *fname,
/* =========================================================================== /* ===========================================================================
* Test compress() and uncompress() * Test compress() and uncompress()
*/ */
void test_compress(compr, comprLen, uncompr, uncomprLen) void test_compress(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen) {
uLong comprLen, uncomprLen;
{
int err; int err;
uLong len = (uLong)strlen(hello)+1; uLong len = (uLong)strlen(hello)+1;
@@ -136,11 +132,7 @@ void test_compress(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test read/write of .gz files * Test read/write of .gz files
*/ */
void test_gzio(fname, uncompr, uncomprLen) void test_gzio(const char *fname, Byte *uncompr, uLong uncomprLen) {
const char *fname; /* compressed file name */
Byte *uncompr;
uLong uncomprLen;
{
#ifdef NO_GZCOMPRESS #ifdef NO_GZCOMPRESS
fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
#else #else
@@ -222,10 +214,7 @@ void test_gzio(fname, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test deflate() with small buffers * Test deflate() with small buffers
*/ */
void test_deflate(compr, comprLen) void test_deflate(Byte *compr, uLong comprLen) {
Byte *compr;
uLong comprLen;
{
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
uLong len = (uLong)strlen(hello)+1; uLong len = (uLong)strlen(hello)+1;
@@ -260,10 +249,8 @@ void test_deflate(compr, comprLen)
/* =========================================================================== /* ===========================================================================
* Test inflate() with small buffers * Test inflate() with small buffers
*/ */
void test_inflate(compr, comprLen, uncompr, uncomprLen) void test_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen) {
uLong comprLen, uncomprLen;
{
int err; int err;
z_stream d_stream; /* decompression stream */ 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 * Test deflate() with large buffers and dynamic change of compression level
*/ */
void test_large_deflate(compr, comprLen, uncompr, uncomprLen) void test_large_deflate(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen) {
uLong comprLen, uncomprLen;
{
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
@@ -356,10 +341,8 @@ void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test inflate() with large buffers * Test inflate() with large buffers
*/ */
void test_large_inflate(compr, comprLen, uncompr, uncomprLen) void test_large_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen) {
uLong comprLen, uncomprLen;
{
int err; int err;
z_stream d_stream; /* decompression stream */ z_stream d_stream; /* decompression stream */
@@ -397,10 +380,7 @@ void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test deflate() with full flush * Test deflate() with full flush
*/ */
void test_flush(compr, comprLen) void test_flush(Byte *compr, uLong *comprLen) {
Byte *compr;
uLong *comprLen;
{
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
uInt len = (uInt)strlen(hello)+1; uInt len = (uInt)strlen(hello)+1;
@@ -435,10 +415,7 @@ void test_flush(compr, comprLen)
/* =========================================================================== /* ===========================================================================
* Test inflateSync() * Test inflateSync()
*/ */
void test_sync(compr, comprLen, uncompr, uncomprLen) void test_sync(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen) {
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err; int err;
z_stream d_stream; /* decompression stream */ z_stream d_stream; /* decompression stream */
@@ -479,10 +456,7 @@ void test_sync(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test deflate() with preset dictionary * Test deflate() with preset dictionary
*/ */
void test_dict_deflate(compr, comprLen) void test_dict_deflate(Byte *compr, uLong comprLen) {
Byte *compr;
uLong comprLen;
{
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
@@ -516,10 +490,8 @@ void test_dict_deflate(compr, comprLen)
/* =========================================================================== /* ===========================================================================
* Test inflate() with a preset dictionary * Test inflate() with a preset dictionary
*/ */
void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) void test_dict_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen) {
uLong comprLen, uncomprLen;
{
int err; int err;
z_stream d_stream; /* decompression stream */ z_stream d_stream; /* decompression stream */
@@ -567,10 +539,7 @@ void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
* Usage: example [output.gz [input.gz]] * Usage: example [output.gz [input.gz]]
*/ */
int main(argc, argv) int main(int argc, char *argv[]) {
int argc;
char *argv[];
{
Byte *compr, *uncompr; Byte *compr, *uncompr;
uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
uLong uncomprLen = comprLen; uLong uncomprLen = comprLen;
+15 -34
View File
@@ -102,9 +102,7 @@ void test_gzio _Z_OF((const char *fname,
/* =========================================================================== /* ===========================================================================
* Test compress() and uncompress() * Test compress() and uncompress()
*/ */
void test_compress(compr, comprLen, uncompr, uncomprLen) void test_compress(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{ {
int err; int err;
uLong len = (uLong)strlen(hello)+1; uLong len = (uLong)strlen(hello)+1;
@@ -128,10 +126,8 @@ void test_compress(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test read/write of .gz files * Test read/write of .gz files
*/ */
void test_gzio(fname, uncompr, uncomprLen) void test_gzio(const char *fname /* compressed file name */, Byte *uncompr,
const char *fname; /* compressed file name */ uLong uncomprLen)
Byte *uncompr;
uLong uncomprLen;
{ {
#ifdef NO_GZCOMPRESS #ifdef NO_GZCOMPRESS
fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
@@ -214,9 +210,7 @@ void test_gzio(fname, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test deflate() with small buffers * Test deflate() with small buffers
*/ */
void test_deflate(compr, comprLen) void test_deflate(Byte *compr, uLong comprLen)
Byte *compr;
uLong comprLen;
{ {
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
@@ -252,9 +246,7 @@ void test_deflate(compr, comprLen)
/* =========================================================================== /* ===========================================================================
* Test inflate() with small buffers * Test inflate() with small buffers
*/ */
void test_inflate(compr, comprLen, uncompr, uncomprLen) void test_inflate(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{ {
int err; int err;
z_stream d_stream; /* decompression stream */ 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 * Test deflate() with large buffers and dynamic change of compression level
*/ */
void test_large_deflate(compr, comprLen, uncompr, uncomprLen) void test_large_deflate(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen)
uLong comprLen, uncomprLen;
{ {
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
@@ -348,9 +339,8 @@ void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test inflate() with large buffers * Test inflate() with large buffers
*/ */
void test_large_inflate(compr, comprLen, uncompr, uncomprLen) void test_large_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen)
uLong comprLen, uncomprLen;
{ {
int err; int err;
z_stream d_stream; /* decompression stream */ z_stream d_stream; /* decompression stream */
@@ -389,9 +379,7 @@ void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test deflate() with full flush * Test deflate() with full flush
*/ */
void test_flush(compr, comprLen) void test_flush(Byte *compr, uLong comprLen)
Byte *compr;
uLong *comprLen;
{ {
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
@@ -427,9 +415,7 @@ void test_flush(compr, comprLen)
/* =========================================================================== /* ===========================================================================
* Test inflateSync() * Test inflateSync()
*/ */
void test_sync(compr, comprLen, uncompr, uncomprLen) void test_sync(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{ {
int err; int err;
z_stream d_stream; /* decompression stream */ z_stream d_stream; /* decompression stream */
@@ -471,9 +457,7 @@ void test_sync(compr, comprLen, uncompr, uncomprLen)
/* =========================================================================== /* ===========================================================================
* Test deflate() with preset dictionary * Test deflate() with preset dictionary
*/ */
void test_dict_deflate(compr, comprLen) void test_dict_deflate(Byte *compr, uLong comprLen)
Byte *compr;
uLong comprLen;
{ {
z_stream c_stream; /* compression stream */ z_stream c_stream; /* compression stream */
int err; int err;
@@ -508,9 +492,8 @@ void test_dict_deflate(compr, comprLen)
/* =========================================================================== /* ===========================================================================
* Test inflate() with a preset dictionary * Test inflate() with a preset dictionary
*/ */
void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) void test_dict_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
Byte *compr, *uncompr; uLong uncomprLen)
uLong comprLen, uncomprLen;
{ {
int err; int err;
z_stream d_stream; /* decompression stream */ z_stream d_stream; /* decompression stream */
@@ -559,9 +542,7 @@ void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
* Usage: example [output.gz [input.gz]] * Usage: example [output.gz [input.gz]]
*/ */
int main(argc, argv) int main(int argc, char *argv[])
int argc;
char *argv[];
{ {
Byte *compr, *uncompr; Byte *compr, *uncompr;
uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+14 -49
View File
@@ -82,8 +82,7 @@
The strwinerror function does not change the current setting The strwinerror function does not change the current setting
of GetLastError. */ of GetLastError. */
static char *strwinerror (error) static char *strwinerror(DWORD error)
DWORD error;
{ {
static char buf[1024]; static char buf[1024];
@@ -121,8 +120,7 @@ static char *strwinerror (error)
return buf; return buf;
} }
static void pwinerror (s) static void pwinerror (const char *s)
const char *s;
{ {
if (s && *s) if (s && *s)
fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
@@ -198,11 +196,7 @@ const char *mode;
return gz_open(NULL, fd, mode); return gz_open(NULL, fd, mode);
} }
gzFile gz_open(path, fd, mode) gzFile gz_open(const char *path, int fd, const char *mode) {
const char *path;
int fd;
const char *mode;
{
gzFile gz; gzFile gz;
int ret; int ret;
@@ -238,11 +232,7 @@ gzFile gz_open(path, fd, mode)
int gzwrite _Z_OF((gzFile, const void *, unsigned)); int gzwrite _Z_OF((gzFile, const void *, unsigned));
int gzwrite(gz, buf, len) int gzwrite(gzFile gz, const void *buf, unsigned len) {
gzFile gz;
const void *buf;
unsigned len;
{
z_stream *strm; z_stream *strm;
unsigned char out[BUFLEN]; unsigned char out[BUFLEN];
@@ -262,11 +252,7 @@ int gzwrite(gz, buf, len)
int gzread _Z_OF((gzFile, void *, unsigned)); int gzread _Z_OF((gzFile, void *, unsigned));
int gzread(gz, buf, len) int gzread(gzFile gz, void *buf, unsigned len) {
gzFile gz;
void *buf;
unsigned len;
{
int ret; int ret;
unsigned got; unsigned got;
unsigned char in[1]; unsigned char in[1];
@@ -299,9 +285,7 @@ int gzread(gz, buf, len)
int gzclose _Z_OF((gzFile)); int gzclose _Z_OF((gzFile));
int gzclose(gz) int gzclose(gzFile gz) {
gzFile gz;
{
z_stream *strm; z_stream *strm;
unsigned char out[BUFLEN]; unsigned char out[BUFLEN];
@@ -328,9 +312,7 @@ int gzclose(gz)
const char *gzerror _Z_OF((gzFile, int *)); const char *gzerror _Z_OF((gzFile, int *));
const char *gzerror(gz, err) const char *gzerror(gzFile gz, int *err)
gzFile gz;
int *err;
{ {
*err = gz->err; *err = gz->err;
return gz->msg; return gz->msg;
@@ -353,8 +335,7 @@ int main _Z_OF((int argc, char *argv[]));
/* =========================================================================== /* ===========================================================================
* Display error message and exit * Display error message and exit
*/ */
void error(msg) void error(const char *msg)
const char *msg;
{ {
fprintf(stderr, "%s: %s\n", prog, msg); fprintf(stderr, "%s: %s\n", prog, msg);
exit(1); exit(1);
@@ -364,9 +345,7 @@ void error(msg)
* Compress input to output then close both files. * Compress input to output then close both files.
*/ */
void gz_compress(in, out) void gz_compress(FILE *in, gzFile out)
FILE *in;
gzFile out;
{ {
local char buf[BUFLEN]; local char buf[BUFLEN];
int len; int len;
@@ -397,10 +376,7 @@ void gz_compress(in, out)
/* Try compressing the input file at once using mmap. Return Z_OK if /* Try compressing the input file at once using mmap. Return Z_OK if
* if success, Z_ERRNO otherwise. * if success, Z_ERRNO otherwise.
*/ */
int gz_compress_mmap(in, out) int gz_compress_mmap(FILE *in, gzFile out) {
FILE *in;
gzFile out;
{
int len; int len;
int err; int err;
int ifd = fileno(in); int ifd = fileno(in);
@@ -432,10 +408,7 @@ int gz_compress_mmap(in, out)
/* =========================================================================== /* ===========================================================================
* Uncompress input to output then close both files. * Uncompress input to output then close both files.
*/ */
void gz_uncompress(in, out) void gz_uncompress(gzFile in, FILE *out) {
gzFile in;
FILE *out;
{
local char buf[BUFLEN]; local char buf[BUFLEN];
int len; int len;
int err; int err;
@@ -459,10 +432,7 @@ void gz_uncompress(in, out)
* Compress the given file: create a corresponding .gz file and remove the * Compress the given file: create a corresponding .gz file and remove the
* original. * original.
*/ */
void file_compress(file, mode) void file_compress(char *file, char *mode) {
char *file;
char *mode;
{
local char outfile[MAX_NAME_LEN]; local char outfile[MAX_NAME_LEN];
FILE *in; FILE *in;
gzFile out; gzFile out;
@@ -494,9 +464,7 @@ void file_compress(file, mode)
/* =========================================================================== /* ===========================================================================
* Uncompress the given file and remove the original. * Uncompress the given file and remove the original.
*/ */
void file_uncompress(file) void file_uncompress(char *file) {
char *file;
{
local char buf[MAX_NAME_LEN]; local char buf[MAX_NAME_LEN];
char *infile, *outfile; char *infile, *outfile;
FILE *out; FILE *out;
@@ -546,10 +514,7 @@ void file_uncompress(file)
* -1 to -9 : compression level * -1 to -9 : compression level
*/ */
int main(argc, argv) int main(int argc, char *argv[]) {
int argc;
char *argv[];
{
int copyout = 0; int copyout = 0;
int uncompr = 0; int uncompr = 0;
gzFile file; gzFile file;
+1 -3
View File
@@ -11,9 +11,7 @@
/* gzclose() is in a separate file so that it is linked in only if it is used. /* 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 That way the other gzclose functions can be used instead to avoid linking in
unneeded compression or decompression routines. */ unneeded compression or decompression routines. */
int ZEXPORT gzclose(file) int ZEXPORT gzclose(gzFile file) {
gzFile file;
{
#ifndef NO_GZCOMPRESS #ifndef NO_GZCOMPRESS
gz_statep state; gz_statep state;
+20 -73
View File
@@ -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 The gz_strwinerror function does not change the current setting of
GetLastError. */ GetLastError. */
char ZLIB_INTERNAL *gz_strwinerror (error) char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
DWORD error;
{
static char buf[1024]; static char buf[1024];
wchar_t *msgbuf; wchar_t *msgbuf;
@@ -75,9 +73,7 @@ char ZLIB_INTERNAL *gz_strwinerror (error)
#endif /* UNDER_CE */ #endif /* UNDER_CE */
/* Reset gzip file state */ /* Reset gzip file state */
local void gz_reset(state) local void gz_reset(gz_statep state) {
gz_statep state;
{
state.state->x.have = 0; /* no output data available */ state.state->x.have = 0; /* no output data available */
if (state.state->mode == GZ_READ) { /* for reading ... */ if (state.state->mode == GZ_READ) { /* for reading ... */
state.state->eof = 0; /* not at end of file */ 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. */ /* Open a gzip file either by name or file descriptor. */
local gzFile gz_open(path, fd, mode) local gzFile gz_open(const void *path, int fd, const char *mode) {
const void *path;
int fd;
const char *mode;
{
gz_statep state; gz_statep state;
z_size_t len; z_size_t len;
int oflag; int oflag;
@@ -270,26 +262,17 @@ local gzFile gz_open(path, fd, mode)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
gzFile ZEXPORT gzopen(path, mode) gzFile ZEXPORT gzopen(const char *path, const char *mode) {
const char *path;
const char *mode;
{
return gz_open(path, -1, mode); return gz_open(path, -1, mode);
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
gzFile ZEXPORT gzopen64(path, mode) gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
const char *path;
const char *mode;
{
return gz_open(path, -1, mode); return gz_open(path, -1, mode);
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
gzFile ZEXPORT gzdopen(fd, mode) gzFile ZEXPORT gzdopen(int fd, const char *mode) {
int fd;
const char *mode;
{
char *path; /* identifier for error messages */ char *path; /* identifier for error messages */
gzFile gz; gzFile gz;
@@ -307,19 +290,13 @@ gzFile ZEXPORT gzdopen(fd, mode)
/* -- see zlib.h -- */ /* -- see zlib.h -- */
#ifdef WIDECHAR #ifdef WIDECHAR
gzFile ZEXPORT gzopen_w(path, mode) gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
const wchar_t *path;
const char *mode;
{
return gz_open(path, -2, mode); return gz_open(path, -2, mode);
} }
#endif #endif
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzbuffer(file, size) int ZEXPORT gzbuffer(gzFile file, unsigned size) {
gzFile file;
unsigned size;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@@ -343,9 +320,7 @@ int ZEXPORT gzbuffer(file, size)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzrewind(file) int ZEXPORT gzrewind(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@@ -366,11 +341,7 @@ int ZEXPORT gzrewind(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off64_t ZEXPORT gzseek64(file, offset, whence) z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
gzFile file;
z_off64_t offset;
int whence;
{
unsigned n; unsigned n;
z_off64_t ret; z_off64_t ret;
gz_statep state; gz_statep state;
@@ -443,11 +414,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off_t ZEXPORT gzseek(file, offset, whence) z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
gzFile file;
z_off_t offset;
int whence;
{
z_off64_t ret; z_off64_t ret;
ret = gzseek64(file, (z_off64_t)offset, whence); ret = gzseek64(file, (z_off64_t)offset, whence);
@@ -455,9 +422,7 @@ z_off_t ZEXPORT gzseek(file, offset, whence)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off64_t ZEXPORT gztell64(file) z_off64_t ZEXPORT gztell64(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@@ -472,9 +437,7 @@ z_off64_t ZEXPORT gztell64(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off_t ZEXPORT gztell(file) z_off_t ZEXPORT gztell(gzFile file) {
gzFile file;
{
z_off64_t ret; z_off64_t ret;
ret = gztell64(file); ret = gztell64(file);
@@ -482,9 +445,7 @@ z_off_t ZEXPORT gztell(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off64_t ZEXPORT gzoffset64(file) z_off64_t ZEXPORT gzoffset64(gzFile file) {
gzFile file;
{
z_off64_t offset; z_off64_t offset;
gz_statep state; gz_statep state;
@@ -505,9 +466,7 @@ z_off64_t ZEXPORT gzoffset64(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off_t ZEXPORT gzoffset(file) z_off_t ZEXPORT gzoffset(gzFile file) {
gzFile file;
{
z_off64_t ret; z_off64_t ret;
ret = gzoffset64(file); ret = gzoffset64(file);
@@ -515,9 +474,7 @@ z_off_t ZEXPORT gzoffset(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzeof(file) int ZEXPORT gzeof(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@@ -532,10 +489,7 @@ int ZEXPORT gzeof(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
const char * ZEXPORT gzerror(file, errnum) const char * ZEXPORT gzerror(gzFile file, int *errnum) {
gzFile file;
int *errnum;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@@ -553,9 +507,7 @@ const char * ZEXPORT gzerror(file, errnum)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
void ZEXPORT gzclearerr(file) void ZEXPORT gzclearerr(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* 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 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 allocation failure constructing the error message, then convert the error to
out of memory. */ out of memory. */
void ZLIB_INTERNAL gz_error(state, err, msg) void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
gz_statep state;
int err;
const char *msg;
{
/* free previously allocated message and clear */ /* free previously allocated message and clear */
if (state.state->msg != NULL) { if (state.state->msg != NULL) {
if (state.state->err != Z_MEM_ERROR) 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 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, used, since C standard permits 1's complement and sign-bit representations,
otherwise we could just use ((unsigned)-1) >> 1 */ otherwise we could just use ((unsigned)-1) >> 1 */
unsigned ZLIB_INTERNAL gz_intmax() unsigned ZLIB_INTERNAL gz_intmax() {
{
unsigned p, q; unsigned p, q;
p = 1; p = 1;
+17 -58
View File
@@ -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. 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 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. */ read the number of bytes requested, depending on the type of descriptor. */
local int gz_load(state, buf, len, have) local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
gz_statep state; unsigned *have) {
unsigned char *buf;
unsigned len;
unsigned *have;
{
ssize_t ret; ssize_t ret;
unsigned get, max = ((unsigned)-1 >> 2) + 1; 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 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 the input buffer, and then the remainder of the buffer is loaded with the
available data from the input file. */ available data from the input file. */
local int gz_avail(state) local int gz_avail(gz_statep state)
gz_statep state;
{ {
unsigned got; unsigned got;
z_streamp strm = &(state.state->strm); 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 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. a user buffer. If decompressing, the inflate state will be initialized.
gz_look() will return 0 on success or -1 on failure. */ gz_look() will return 0 on success or -1 on failure. */
local int gz_look(state) local int gz_look(gz_statep state) {
gz_statep state;
{
z_streamp strm = &(state.state->strm); z_streamp strm = &(state.state->strm);
/* allocate read buffers and inflate memory */ /* 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 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 the next gzip stream or raw data, once state.state->x.have is depleted. Returns 0
on success, -1 on failure. */ on success, -1 on failure. */
local int gz_decomp(state) local int gz_decomp(gz_statep state) {
gz_statep state;
{
int ret = Z_OK; int ret = Z_OK;
unsigned had; unsigned had;
z_streamp strm = &(state.state->strm); 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, 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 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. */ end of the input file has been reached and all data has been processed. */
local int gz_fetch(state) local int gz_fetch(gz_statep state) {
gz_statep state;
{
z_streamp strm = &(state.state->strm); z_streamp strm = &(state.state->strm);
do { do {
@@ -268,10 +257,7 @@ local int gz_fetch(state)
} }
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
local int gz_skip(state, len) local int gz_skip(gz_statep state, z_off64_t len) {
gz_statep state;
z_off64_t len;
{
unsigned n; unsigned n;
/* skip over len bytes or reach end-of-file, whichever comes first */ /* 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 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 end of file was reached, or there was an error. state.state->err must be
consulted in that case to determine which. */ consulted in that case to determine which. */
local z_size_t gz_read(state, buf, len) local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
gz_statep state;
voidp buf;
z_size_t len;
{
z_size_t got; z_size_t got;
unsigned n; unsigned n;
@@ -384,11 +366,7 @@ local z_size_t gz_read(state, buf, len)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzread(file, buf, len) int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
gzFile file;
voidp buf;
unsigned len;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@@ -420,12 +398,8 @@ int ZEXPORT gzread(file, buf, len)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_size_t ZEXPORT gzfread(buf, size, nitems, file) z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
voidp buf; gzFile file) {
z_size_t size;
z_size_t nitems;
gzFile file;
{
z_size_t len; z_size_t len;
gz_statep state; gz_statep state;
@@ -468,9 +442,7 @@ ZEXTERN int ZEXPORT gzgetc _Z_OF((gzFile file));
ZEXTERN int ZEXPORT gzgetc_ _Z_OF((gzFile file)); ZEXTERN int ZEXPORT gzgetc_ _Z_OF((gzFile file));
#endif #endif
int ZEXPORT gzgetc(file) int ZEXPORT gzgetc(gzFile file) {
gzFile file;
{
int ret; int ret;
unsigned char buf[1]; unsigned char buf[1];
gz_statep state; gz_statep state;
@@ -497,17 +469,12 @@ int ZEXPORT gzgetc(file)
return ret < 1 ? -1 : buf[0]; return ret < 1 ? -1 : buf[0];
} }
int ZEXPORT gzgetc_(file) int ZEXPORT gzgetc_(gzFile file) {
gzFile file;
{
return gzgetc(file); return gzgetc(file);
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzungetc(c, file) int ZEXPORT gzungetc(int c, gzFile file) {
int c;
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@@ -564,11 +531,7 @@ int ZEXPORT gzungetc(c, file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
char * ZEXPORT gzgets(file, buf, len) char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
gzFile file;
char *buf;
int len;
{
unsigned left, n; unsigned left, n;
char *str; char *str;
unsigned char *eol; unsigned char *eol;
@@ -628,9 +591,7 @@ char * ZEXPORT gzgets(file, buf, len)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzdirect(file) int ZEXPORT gzdirect(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@@ -648,9 +609,7 @@ int ZEXPORT gzdirect(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzclose_r(file) int ZEXPORT gzclose_r(gzFile file) {
gzFile file;
{
int ret, err; int ret, err;
gz_statep state; gz_statep state;
+18 -58
View File
@@ -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 /* 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 state.state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
success. */ success. */
local int gz_init(state) local int gz_init(gz_statep state) {
gz_statep state;
{
int ret; int ret;
z_streamp strm = &(state.state->strm); 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 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 reset to start a new gzip stream. If gz->direct is true, then simply write
to the output file without compressing, and ignore flush. */ to the output file without compressing, and ignore flush. */
local int gz_comp(state, flush) local int gz_comp(gz_statep state, int flush) {
gz_statep state;
int flush;
{
int ret, writ; int ret, writ;
unsigned have, put, max = ((unsigned)-1 >> 2) + 1; unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
z_streamp strm = &(state.state->strm); 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 /* Compress len zeros to output. Return -1 on a write error or memory
allocation failure by gz_comp(), or 0 on success. */ allocation failure by gz_comp(), or 0 on success. */
local int gz_zero(state, len) local int gz_zero(gz_statep state, z_off64_t len) {
gz_statep state;
z_off64_t len;
{
int first; int first;
unsigned n; unsigned n;
z_streamp strm = &(state.state->strm); 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 /* 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. */ the returned value is less than len, then there was an error. */
local z_size_t gz_write(state, buf, len) local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
gz_statep state;
voidpc buf;
z_size_t len;
{
z_size_t put = len; z_size_t put = len;
/* if len is zero, avoid unnecessary operations */ /* if len is zero, avoid unnecessary operations */
@@ -248,11 +236,7 @@ local z_size_t gz_write(state, buf, len)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzwrite(file, buf, len) int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
gzFile file;
voidpc buf;
unsigned len;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@@ -276,12 +260,8 @@ int ZEXPORT gzwrite(file, buf, len)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
voidpc buf; gzFile file) {
z_size_t size;
z_size_t nitems;
gzFile file;
{
z_size_t len; z_size_t len;
gz_statep state; gz_statep state;
@@ -307,10 +287,7 @@ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzputc(file, c) int ZEXPORT gzputc(gzFile file, int c) {
gzFile file;
int c;
{
unsigned have; unsigned have;
unsigned char buf[1]; unsigned char buf[1];
gz_statep state; gz_statep state;
@@ -355,10 +332,7 @@ int ZEXPORT gzputc(file, c)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzputs(file, str) int ZEXPORT gzputs(gzFile file, const char *str) {
gzFile file;
const char *str;
{
int ret; int ret;
z_size_t len; z_size_t len;
gz_statep state; gz_statep state;
@@ -382,8 +356,7 @@ int ZEXPORT gzputs(file, str)
#include <stdarg.h> #include <stdarg.h>
/* -- see zlib.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; int len;
unsigned left; unsigned left;
char *next; char *next;
@@ -454,8 +427,7 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
return len; return len;
} }
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
{
va_list va; va_list va;
int ret; int ret;
@@ -468,13 +440,10 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
#else /* !STDC && !Z_HAVE_STDARG_H */ #else /* !STDC && !Z_HAVE_STDARG_H */
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) int a4, int a5, int a6, int a7, int a8, int a9, int a10,
gzFile file; int a11, int a12, int a13, int a14, int a15, int a16,
const char *format; int a17, int a18, int a19, int a20) {
int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
{
unsigned len, left; unsigned len, left;
char *next; char *next;
gz_statep state; gz_statep state;
@@ -556,10 +525,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
#endif #endif
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzflush(file, flush) int ZEXPORT gzflush(gzFile file, int flush) {
gzFile file;
int flush;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@@ -588,11 +554,7 @@ int ZEXPORT gzflush(file, flush)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzsetparams(file, level, strategy) int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
gzFile file;
int level;
int strategy;
{
gz_statep state; gz_statep state;
z_streamp strm; z_streamp strm;
@@ -630,9 +592,7 @@ int ZEXPORT gzsetparams(file, level, strategy)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzclose_w(file) int ZEXPORT gzclose_w(gzFile file) {
gzFile file;
{
int ret = Z_OK; int ret = Z_OK;
gz_statep state; gz_statep state;