From 88731a76e522238bc390e583a26548c15bf567e7 Mon Sep 17 00:00:00 2001 From: giuseppe Date: Fri, 2 Sep 2022 09:41:48 +0200 Subject: [PATCH 01/10] imported lz4 v1.9.4 --- native/lz4/LICENSE | 2 +- native/lz4/Makefile | 112 +- native/lz4/README.md | 83 +- native/lz4/dll/example/Makefile | 2 +- native/lz4/dll/example/README.md | 20 +- native/lz4/dll/example/fullbench-dll.sln | 50 +- native/lz4/dll/example/fullbench-dll.vcxproj | 362 +++--- native/lz4/liblz4-dll.rc.in | 2 +- native/lz4/liblz4.pc.in | 6 +- native/lz4/lz4.c | 1094 ++++++++++++------ native/lz4/lz4.h | 288 +++-- native/lz4/lz4file.c | 311 +++++ native/lz4/lz4file.h | 93 ++ native/lz4/lz4frame.c | 784 ++++++++----- native/lz4/lz4frame.h | 211 ++-- native/lz4/lz4frame_static.h | 2 +- native/lz4/lz4hc.c | 527 +++++---- native/lz4/lz4hc.h | 73 +- 18 files changed, 2624 insertions(+), 1398 deletions(-) mode change 100755 => 100644 native/lz4/dll/example/Makefile mode change 100755 => 100644 native/lz4/dll/example/README.md mode change 100755 => 100644 native/lz4/dll/example/fullbench-dll.sln mode change 100755 => 100644 native/lz4/dll/example/fullbench-dll.vcxproj create mode 100644 native/lz4/lz4file.c create mode 100644 native/lz4/lz4file.h diff --git a/native/lz4/LICENSE b/native/lz4/LICENSE index 74c2cdd..4884916 100644 --- a/native/lz4/LICENSE +++ b/native/lz4/LICENSE @@ -1,5 +1,5 @@ LZ4 Library -Copyright (c) 2011-2016, Yann Collet +Copyright (c) 2011-2020, Yann Collet All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/native/lz4/Makefile b/native/lz4/Makefile index 8f21d3d..06503cb 100644 --- a/native/lz4/Makefile +++ b/native/lz4/Makefile @@ -1,6 +1,6 @@ # ################################################################ # LZ4 library - Makefile -# Copyright (C) Yann Collet 2011-2016 +# Copyright (C) Yann Collet 2011-2020 # All rights reserved. # # This Makefile is validated for Linux, macOS, *BSD, Hurd, Solaris, MSYS2 targets @@ -28,14 +28,15 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # You can contact the author at : -# - LZ4 source repository : https://github.com/Cyan4973/lz4 +# - LZ4 source repository : https://github.com/lz4/lz4 # - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c # ################################################################ +SED = sed # Version numbers -LIBVER_MAJOR_SCRIPT:=`sed -n '/define LZ4_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./lz4.h` -LIBVER_MINOR_SCRIPT:=`sed -n '/define LZ4_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./lz4.h` -LIBVER_PATCH_SCRIPT:=`sed -n '/define LZ4_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./lz4.h` +LIBVER_MAJOR_SCRIPT:=`$(SED) -n '/define LZ4_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./lz4.h` +LIBVER_MINOR_SCRIPT:=`$(SED) -n '/define LZ4_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./lz4.h` +LIBVER_PATCH_SCRIPT:=`$(SED) -n '/define LZ4_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./lz4.h` LIBVER_SCRIPT:= $(LIBVER_MAJOR_SCRIPT).$(LIBVER_MINOR_SCRIPT).$(LIBVER_PATCH_SCRIPT) LIBVER_MAJOR := $(shell echo $(LIBVER_MAJOR_SCRIPT)) LIBVER_MINOR := $(shell echo $(LIBVER_MINOR_SCRIPT)) @@ -46,12 +47,13 @@ BUILD_SHARED:=yes BUILD_STATIC:=yes CPPFLAGS+= -DXXH_NAMESPACE=LZ4_ +CPPFLAGS+= $(MOREFLAGS) CFLAGS ?= -O3 DEBUGFLAGS:= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes \ -Wundef -Wpointer-arith -Wstrict-aliasing=1 -CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) -FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) +CFLAGS += $(DEBUGFLAGS) +FLAGS = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) SRCFILES := $(sort $(wildcard *.c)) @@ -74,27 +76,33 @@ endif .PHONY: default default: lib-release +# silent mode by default; verbose can be triggered by V=1 or VERBOSE=1 +$(V)$(VERBOSE).SILENT: + lib-release: DEBUGFLAGS := lib-release: lib +.PHONY: lib lib: liblz4.a liblz4 +.PHONY: all all: lib +.PHONY: all32 all32: CFLAGS+=-m32 all32: all liblz4.a: $(SRCFILES) ifeq ($(BUILD_STATIC),yes) # can be disabled on command line @echo compiling static library - $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -c $^ - $(Q)$(AR) rcs $@ *.o + $(COMPILE.c) $^ + $(AR) rcs $@ *.o endif ifeq ($(WINBASED),yes) liblz4-dll.rc: liblz4-dll.rc.in @echo creating library resource - $(Q)sed -e 's|@LIBLZ4@|$(LIBLZ4)|' \ + $(SED) -e 's|@LIBLZ4@|$(LIBLZ4)|' \ -e 's|@LIBVER_MAJOR@|$(LIBVER_MAJOR)|g' \ -e 's|@LIBVER_MINOR@|$(LIBVER_MINOR)|g' \ -e 's|@LIBVER_PATCH@|$(LIBVER_PATCH)|g' \ @@ -104,31 +112,30 @@ liblz4-dll.o: liblz4-dll.rc $(WINDRES) -i liblz4-dll.rc -o liblz4-dll.o $(LIBLZ4): $(SRCFILES) liblz4-dll.o -else + @echo compiling dynamic library $(LIBVER) + $(CC) $(FLAGS) -DLZ4_DLL_EXPORT=1 -shared $^ -o dll/$@.dll -Wl,--out-implib,dll/$(LIBLZ4_EXP) + +else # not windows + $(LIBLZ4): $(SRCFILES) -endif -ifeq ($(BUILD_SHARED),yes) # can be disabled on command line @echo compiling dynamic library $(LIBVER) - ifeq ($(WINBASED),yes) - $(Q)$(CC) $(FLAGS) -DLZ4_DLL_EXPORT=1 -shared $^ -o dll/$@.dll -Wl,--out-implib,dll/$(LIBLZ4_EXP) - else - $(Q)$(CC) $(FLAGS) -shared $^ -fPIC -fvisibility=hidden $(SONAME_FLAGS) -o $@ + $(CC) $(FLAGS) -shared $^ -fPIC -fvisibility=hidden $(SONAME_FLAGS) -o $@ @echo creating versioned links - $(Q)$(LN_SF) $@ liblz4.$(SHARED_EXT_MAJOR) - $(Q)$(LN_SF) $@ liblz4.$(SHARED_EXT) - endif + $(LN_SF) $@ liblz4.$(SHARED_EXT_MAJOR) + $(LN_SF) $@ liblz4.$(SHARED_EXT) + endif -ifeq (,$(filter MINGW%,$(TARGET_OS))) +.PHONY: liblz4 liblz4: $(LIBLZ4) -endif +.PHONY: clean clean: ifeq ($(WINBASED),yes) - $(Q)$(RM) *.rc + $(RM) *.rc endif - $(Q)$(RM) core *.o liblz4.pc dll/$(LIBLZ4).dll dll/$(LIBLZ4_EXP) - $(Q)$(RM) *.a *.$(SHARED_EXT) *.$(SHARED_EXT_MAJOR) *.$(SHARED_EXT_VER) + $(RM) core *.o liblz4.pc dll/$(LIBLZ4).dll dll/$(LIBLZ4_EXP) + $(RM) *.a *.$(SHARED_EXT) *.$(SHARED_EXT_MAJOR) *.$(SHARED_EXT_VER) @echo Cleaning library completed #----------------------------------------------------------------------------- @@ -164,54 +171,55 @@ pkgconfigdir ?= $(PKGCONFIGDIR) liblz4.pc: liblz4.pc.in Makefile @echo creating pkgconfig - $(Q)sed -e 's|@PREFIX@|$(prefix)|' \ + $(SED) -e 's|@PREFIX@|$(prefix)|' \ -e 's|@LIBDIR@|$(libdir)|' \ -e 's|@INCLUDEDIR@|$(includedir)|' \ -e 's|@VERSION@|$(LIBVER)|' \ + -e 's|=${prefix}/|=$${prefix}/|' \ $< >$@ install: lib liblz4.pc - $(Q)$(INSTALL_DIR) $(DESTDIR)$(pkgconfigdir)/ $(DESTDIR)$(includedir)/ $(DESTDIR)$(libdir)/ $(DESTDIR)$(bindir)/ - $(Q)$(INSTALL_DATA) liblz4.pc $(DESTDIR)$(pkgconfigdir)/ - @echo Installing libraries + $(INSTALL_DIR) $(DESTDIR)$(pkgconfigdir)/ $(DESTDIR)$(includedir)/ $(DESTDIR)$(libdir)/ $(DESTDIR)$(bindir)/ + $(INSTALL_DATA) liblz4.pc $(DESTDIR)$(pkgconfigdir)/ + @echo Installing libraries in $(DESTDIR)$(libdir) ifeq ($(BUILD_STATIC),yes) - $(Q)$(INSTALL_DATA) liblz4.a $(DESTDIR)$(libdir)/liblz4.a - $(Q)$(INSTALL_DATA) lz4frame_static.h $(DESTDIR)$(includedir)/lz4frame_static.h + $(INSTALL_DATA) liblz4.a $(DESTDIR)$(libdir)/liblz4.a + $(INSTALL_DATA) lz4frame_static.h $(DESTDIR)$(includedir)/lz4frame_static.h endif ifeq ($(BUILD_SHARED),yes) -# Traditionnally, one installs the DLLs in the bin directory as programs +# Traditionally, one installs the DLLs in the bin directory as programs # search them first in their directory. This allows to not pollute system # directories (like c:/windows/system32), nor modify the PATH variable. ifeq ($(WINBASED),yes) - $(Q)$(INSTALL_PROGRAM) dll/$(LIBLZ4).dll $(DESTDIR)$(bindir) - $(Q)$(INSTALL_PROGRAM) dll/$(LIBLZ4_EXP) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) dll/$(LIBLZ4).dll $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) dll/$(LIBLZ4_EXP) $(DESTDIR)$(libdir) else - $(Q)$(INSTALL_PROGRAM) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir) - $(Q)$(LN_SF) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) - $(Q)$(LN_SF) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) + $(INSTALL_PROGRAM) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir) + $(LN_SF) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) + $(LN_SF) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) endif endif - @echo Installing headers in $(includedir) - $(Q)$(INSTALL_DATA) lz4.h $(DESTDIR)$(includedir)/lz4.h - $(Q)$(INSTALL_DATA) lz4hc.h $(DESTDIR)$(includedir)/lz4hc.h - $(Q)$(INSTALL_DATA) lz4frame.h $(DESTDIR)$(includedir)/lz4frame.h + @echo Installing headers in $(DESTDIR)$(includedir) + $(INSTALL_DATA) lz4.h $(DESTDIR)$(includedir)/lz4.h + $(INSTALL_DATA) lz4hc.h $(DESTDIR)$(includedir)/lz4hc.h + $(INSTALL_DATA) lz4frame.h $(DESTDIR)$(includedir)/lz4frame.h @echo lz4 libraries installed uninstall: - $(Q)$(RM) $(DESTDIR)$(pkgconfigdir)/liblz4.pc + $(RM) $(DESTDIR)$(pkgconfigdir)/liblz4.pc ifeq (WINBASED,1) - $(Q)$(RM) $(DESTDIR)$(bindir)/$(LIBLZ4).dll - $(Q)$(RM) $(DESTDIR)$(libdir)/$(LIBLZ4_EXP) + $(RM) $(DESTDIR)$(bindir)/$(LIBLZ4).dll + $(RM) $(DESTDIR)$(libdir)/$(LIBLZ4_EXP) else - $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) - $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) - $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_VER) + $(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) + $(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) + $(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_VER) endif - $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.a - $(Q)$(RM) $(DESTDIR)$(includedir)/lz4.h - $(Q)$(RM) $(DESTDIR)$(includedir)/lz4hc.h - $(Q)$(RM) $(DESTDIR)$(includedir)/lz4frame.h - $(Q)$(RM) $(DESTDIR)$(includedir)/lz4frame_static.h + $(RM) $(DESTDIR)$(libdir)/liblz4.a + $(RM) $(DESTDIR)$(includedir)/lz4.h + $(RM) $(DESTDIR)$(includedir)/lz4hc.h + $(RM) $(DESTDIR)$(includedir)/lz4frame.h + $(RM) $(DESTDIR)$(includedir)/lz4frame_static.h @echo lz4 libraries successfully uninstalled endif diff --git a/native/lz4/README.md b/native/lz4/README.md index cba2c34..08d1cef 100644 --- a/native/lz4/README.md +++ b/native/lz4/README.md @@ -2,16 +2,20 @@ LZ4 - Library Files ================================ The `/lib` directory contains many files, but depending on project's objectives, -not all of them are necessary. +not all of them are required. +Limited systems may want to reduce the nb of source files to include +as a way to reduce binary size and dependencies. -#### Minimal LZ4 build +Capabilities are added at the "level" granularity, detailed below. + +#### Level 1 : Minimal LZ4 build The minimum required is **`lz4.c`** and **`lz4.h`**, which provides the fast compression and decompression algorithms. They generate and decode data using the [LZ4 block format]. -#### High Compression variant +#### Level 2 : High Compression variant For more compression ratio at the cost of compression speed, the High Compression variant called **lz4hc** is available. @@ -20,7 +24,7 @@ This variant also compresses data using the [LZ4 block format], and depends on regular `lib/lz4.*` source files. -#### Frame support, for interoperability +#### Level 3 : Frame support, for interoperability In order to produce compressed data compatible with `lz4` command line utility, it's necessary to use the [official interoperable frame format]. @@ -28,28 +32,44 @@ This format is generated and decoded automatically by the **lz4frame** library. Its public API is described in `lib/lz4frame.h`. In order to work properly, lz4frame needs all other modules present in `/lib`, including, lz4 and lz4hc, and also **xxhash**. -So it's necessary to include all `*.c` and `*.h` files present in `/lib`. +So it's necessary to also include `xxhash.c` and `xxhash.h`. + + +#### Level 4 : File compression operations + +As a helper around file operations, +the library has been recently extended with `lz4file.c` and `lz4file.h` +(still considered experimental at the time of this writing). +These helpers allow opening, reading, writing, and closing files +using transparent LZ4 compression / decompression. +As a consequence, using `lz4file` adds a dependency on ``. + +`lz4file` relies on `lz4frame` in order to produce compressed data +conformant to the [LZ4 Frame format] specification. +Consequently, to enable this capability, +it's necessary to include all `*.c` and `*.h` files from `lib/` directory. #### Advanced / Experimental API Definitions which are not guaranteed to remain stable in future versions, are protected behind macros, such as `LZ4_STATIC_LINKING_ONLY`. -As the name implies, these definitions can only be invoked +As the name suggests, these definitions should only be invoked in the context of static linking ***only***. Otherwise, dependent application may fail on API or ABI break in the future. -The associated symbols are also not present in dynamic library by default. +The associated symbols are also not exposed by the dynamic library by default. Should they be nonetheless needed, it's possible to force their publication -by using build macro `LZ4_PUBLISH_STATIC_FUNCTIONS`. +by using build macros `LZ4_PUBLISH_STATIC_FUNCTIONS` +and `LZ4F_PUBLISH_STATIC_FUNCTIONS`. #### Build macros -The following build macro can be selected at compilation time : +The following build macro can be selected to adjust source code behavior at compilation time : -- `LZ4_FAST_DEC_LOOP` : this triggers the optimized decompression loop. - This loops works great on x86/x64 cpus, and is automatically enabled on this platform. - It's possible to enable or disable it manually, by passing `LZ4_FAST_DEC_LOOP=1` or `0` to the preprocessor. +- `LZ4_FAST_DEC_LOOP` : this triggers a speed optimized decompression loop, more powerful on modern cpus. + This loop works great on `x86`, `x64` and `aarch64` cpus, and is automatically enabled for them. + It's also possible to enable or disable it manually, by passing `LZ4_FAST_DEC_LOOP=1` or `0` to the preprocessor. For example, with `gcc` : `-DLZ4_FAST_DEC_LOOP=1`, and with `make` : `CPPFLAGS+=-DLZ4_FAST_DEC_LOOP=1 make lz4`. @@ -57,7 +77,7 @@ The following build macro can be selected at compilation time : Set to 65535 by default, which is the maximum value supported by lz4 format. Reducing maximum distance will reduce opportunities for LZ4 to find matches, hence will produce a worse compression ratio. - However, a smaller max distance can allow compatibility with specific decoders using limited memory budget. + Setting a smaller max distance could allow compatibility with specific decoders with limited memory budget. This build macro only influences the compressed output of the compressor. - `LZ4_DISABLE_DEPRECATE_WARNINGS` : invoking a deprecated function will make the compiler generate a warning. @@ -65,8 +85,36 @@ The following build macro can be selected at compilation time : Should this be a problem, it's generally possible to make the compiler ignore these warnings, for example with `-Wno-deprecated-declarations` on `gcc`, or `_CRT_SECURE_NO_WARNINGS` for Visual Studio. - Another method is to define `LZ4_DISABLE_DEPRECATE_WARNINGS` - before including the LZ4 header files. + This build macro offers another project-specific method + by defining `LZ4_DISABLE_DEPRECATE_WARNINGS` before including the LZ4 header files. + +- `LZ4_FORCE_SW_BITCOUNT` : by default, the compression algorithm tries to determine lengths + by using bitcount instructions, generally implemented as fast single instructions in many cpus. + In case the target cpus doesn't support it, or compiler intrinsic doesn't work, or feature bad performance, + it's possible to use an optimized software path instead. + This is achieved by setting this build macros. + In most cases, it's not expected to be necessary, + but it can be legitimately considered for less common platforms. + +- `LZ4_ALIGN_TEST` : alignment test ensures that the memory area + passed as argument to become a compression state is suitably aligned. + This test can be disabled if it proves flaky, by setting this value to 0. + +- `LZ4_USER_MEMORY_FUNCTIONS` : replace calls to ``'s `malloc()`, `calloc()` and `free()` + by user-defined functions, which must be named `LZ4_malloc()`, `LZ4_calloc()` and `LZ4_free()`. + User functions must be available at link time. + +- `LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION` : + Remove support of dynamic memory allocation. + For more details, see description of this macro in `lib/lz4.c`. + +- `LZ4_FREESTANDING` : by setting this build macro to 1, + LZ4/HC removes dependencies on the C standard library, + including allocation functions and `memmove()`, `memcpy()`, and `memset()`. + This build macro is designed to help use LZ4/HC in restricted environments + (embedded, bootloader, etc). + For more details, see description of this macro in `lib/lz4.h`. + #### Amalgamation @@ -84,7 +132,7 @@ All `*.h` files present in `/lib` remain necessary to compile `lz4_all.c`. DLL can be created using MinGW+MSYS with the `make liblz4` command. This command creates `dll\liblz4.dll` and the import library `dll\liblz4.lib`. -To override the `dlltool` command when cross-compiling on Linux, just set the `DLLTOOL` variable. Example of cross compilation on Linux with mingw-w64 64 bits: +To override the `dlltool` command when cross-compiling on Linux, just set the `DLLTOOL` variable. Example of cross compilation on Linux with mingw-w64 64 bits: ``` make BUILD_STATIC=no CC=x86_64-w64-mingw32-gcc DLLTOOL=x86_64-w64-mingw32-dlltool OS=Windows_NT ``` @@ -102,7 +150,7 @@ The compiled executable will require LZ4 DLL which is available at `dll\liblz4.d #### Miscellaneous -Other files present in the directory are not source code. There are : +Other files present in the directory are not source code. They are : - `LICENSE` : contains the BSD license text - `Makefile` : `make` script to compile and install lz4 library (static and dynamic) @@ -110,6 +158,7 @@ Other files present in the directory are not source code. There are : - `README.md` : this file [official interoperable frame format]: ../doc/lz4_Frame_format.md +[LZ4 Frame format]: ../doc/lz4_Frame_format.md [LZ4 block format]: ../doc/lz4_Block_format.md diff --git a/native/lz4/dll/example/Makefile b/native/lz4/dll/example/Makefile old mode 100755 new mode 100644 index e987956..eb8cc1e --- a/native/lz4/dll/example/Makefile +++ b/native/lz4/dll/example/Makefile @@ -1,6 +1,6 @@ # ########################################################################## # LZ4 programs - Makefile -# Copyright (C) Yann Collet 2016 +# Copyright (C) Yann Collet 2016-2020 # # GPL v2 License # diff --git a/native/lz4/dll/example/README.md b/native/lz4/dll/example/README.md old mode 100755 new mode 100644 index 223e473..b93914b --- a/native/lz4/dll/example/README.md +++ b/native/lz4/dll/example/README.md @@ -4,8 +4,8 @@ LZ4 Windows binary package #### The package contents - `lz4.exe` : Command Line Utility, supporting gzip-like arguments -- `dll\liblz4.dll` : The DLL of LZ4 library -- `dll\liblz4.lib` : The import library of LZ4 library for Visual C++ +- `dll\msys-lz4-1.dll` : The DLL of LZ4 library, compiled by msys +- `dll\liblz4.dll.a` : The import library of LZ4 library for Visual C++ - `example\` : The example of usage of LZ4 library - `include\` : Header files required with LZ4 library - `static\liblz4_static.lib` : The static LZ4 library @@ -35,15 +35,15 @@ Use `cd example` and `make` to build `fullbench-dll` and `fullbench-lib`. #### Using LZ4 DLL with gcc/MinGW -The header files from `include\` and the dynamic library `dll\liblz4.dll` +The header files from `include\` and the dynamic library `dll\msys-lz4-1.dll` are required to compile a project using gcc/MinGW. The dynamic library has to be added to linking options. It means that if a project that uses LZ4 consists of a single `test-dll.c` -file it should be linked with `dll\liblz4.dll`. For example: +file it should be linked with `dll\msys-lz4-1.dll`. For example: ``` - gcc $(CFLAGS) -Iinclude\ test-dll.c -o test-dll dll\liblz4.dll + gcc $(CFLAGS) -Iinclude\ test-dll.c -o test-dll dll\msys-lz4-1.dll ``` -The compiled executable will require LZ4 DLL which is available at `dll\liblz4.dll`. +The compiled executable will require LZ4 DLL which is available at `dll\msys-lz4-1.dll`. #### The example of usage of static and dynamic LZ4 libraries with Visual C++ @@ -51,19 +51,19 @@ The compiled executable will require LZ4 DLL which is available at `dll\liblz4.d Open `example\fullbench-dll.sln` to compile `fullbench-dll` that uses a dynamic LZ4 library from the `dll` directory. The solution works with Visual C++ 2010 or newer. When one will open the solution with Visual C++ newer than 2010 -then the solution will upgraded to the current version. +then the solution will be upgraded to the current version. #### Using LZ4 DLL with Visual C++ -The header files from `include\` and the import library `dll\liblz4.lib` +The header files from `include\` and the import library `dll\liblz4.dll.a` are required to compile a project using Visual C++. 1. The header files should be added to `Additional Include Directories` that can be found in project properties `C/C++` then `General`. 2. The import library has to be added to `Additional Dependencies` that can be found in project properties `Linker` then `Input`. - If one will provide only the name `liblz4.lib` without a full path to the library + If one will provide only the name `liblz4.dll.a` without a full path to the library the directory has to be added to `Linker\General\Additional Library Directories`. -The compiled executable will require LZ4 DLL which is available at `dll\liblz4.dll`. +The compiled executable will require LZ4 DLL which is available at `dll\msys-lz4-1.dll`. diff --git a/native/lz4/dll/example/fullbench-dll.sln b/native/lz4/dll/example/fullbench-dll.sln old mode 100755 new mode 100644 index 72e302e..ef8d4c0 --- a/native/lz4/dll/example/fullbench-dll.sln +++ b/native/lz4/dll/example/fullbench-dll.sln @@ -1,25 +1,25 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2012 for Windows Desktop -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench-dll", "fullbench-dll.vcxproj", "{13992FD2-077E-4954-B065-A428198201A9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.ActiveCfg = Debug|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.Build.0 = Debug|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.ActiveCfg = Debug|x64 - {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.Build.0 = Debug|x64 - {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.ActiveCfg = Release|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.Build.0 = Release|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.ActiveCfg = Release|x64 - {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench-dll", "fullbench-dll.vcxproj", "{13992FD2-077E-4954-B065-A428198201A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.ActiveCfg = Debug|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.Build.0 = Debug|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.ActiveCfg = Debug|x64 + {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.Build.0 = Debug|x64 + {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.ActiveCfg = Release|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.Build.0 = Release|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.ActiveCfg = Release|x64 + {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/lz4/dll/example/fullbench-dll.vcxproj b/native/lz4/dll/example/fullbench-dll.vcxproj old mode 100755 new mode 100644 index cdb5534..4f69f4c --- a/native/lz4/dll/example/fullbench-dll.vcxproj +++ b/native/lz4/dll/example/fullbench-dll.vcxproj @@ -1,182 +1,182 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {13992FD2-077E-4954-B065-A428198201A9} - Win32Proj - fullbench-dll - $(SolutionDir)bin\$(Platform)_$(Configuration)\ - $(SolutionDir)bin\obj\$(RootNamespace)_$(Platform)_$(Configuration)\ - - - - Application - true - Unicode - - - Application - true - Unicode - - - Application - false - true - Unicode - - - Application - false - true - Unicode - - - - - - - - - - - - - - - - - - - true - $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - - - true - $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - true - - - false - $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - - - false - $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - true - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) - true - false - ..\include - - - Console - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - liblz4.lib;%(AdditionalDependencies) - false - - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) - true - true - /analyze:stacksize295252 %(AdditionalOptions) - ..\include - - - Console - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - liblz4.lib;%(AdditionalDependencies) - - - - - Level4 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) - false - false - ..\include - - - Console - true - true - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - liblz4.lib;%(AdditionalDependencies) - false - - - - - Level4 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) - false - true - /analyze:stacksize295252 %(AdditionalOptions) - ..\include - - - Console - true - true - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - liblz4.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {13992FD2-077E-4954-B065-A428198201A9} + Win32Proj + fullbench-dll + $(SolutionDir)bin\$(Platform)_$(Configuration)\ + $(SolutionDir)bin\obj\$(RootNamespace)_$(Platform)_$(Configuration)\ + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); + + + true + $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); + true + + + false + $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); + + + false + $(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); + true + + + + + + Level4 + Disabled + WIN32;_DEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) + true + false + ..\include + + + Console + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + liblz4.lib;%(AdditionalDependencies) + false + + + + + + + Level4 + Disabled + WIN32;_DEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) + true + true + /analyze:stacksize295252 %(AdditionalOptions) + ..\include + + + Console + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + liblz4.lib;%(AdditionalDependencies) + + + + + Level4 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) + false + false + ..\include + + + Console + true + true + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + liblz4.lib;%(AdditionalDependencies) + false + + + + + Level4 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;LZ4_DLL_IMPORT=1;%(PreprocessorDefinitions) + false + true + /analyze:stacksize295252 %(AdditionalOptions) + ..\include + + + Console + true + true + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + liblz4.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/lz4/liblz4-dll.rc.in b/native/lz4/liblz4-dll.rc.in index bf9adf5..e2d84b6 100644 --- a/native/lz4/liblz4-dll.rc.in +++ b/native/lz4/liblz4-dll.rc.in @@ -22,7 +22,7 @@ BEGIN VALUE "FileDescription", "Extremely fast compression" VALUE "FileVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" VALUE "InternalName", "@LIBLZ4@" - VALUE "LegalCopyright", "Copyright (C) 2013-2016, Yann Collet" + VALUE "LegalCopyright", "Copyright (C) 2013-2020, Yann Collet" VALUE "OriginalFilename", "@LIBLZ4@.dll" VALUE "ProductName", "LZ4" VALUE "ProductVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" diff --git a/native/lz4/liblz4.pc.in b/native/lz4/liblz4.pc.in index cb31cd7..ed52214 100644 --- a/native/lz4/liblz4.pc.in +++ b/native/lz4/liblz4.pc.in @@ -1,5 +1,5 @@ # LZ4 - Fast LZ compression algorithm -# Copyright (C) 2011-2014, Yann Collet. +# Copyright (C) 2011-2020, Yann Collet. # BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) prefix=@PREFIX@ @@ -10,5 +10,5 @@ Name: lz4 Description: extremely fast lossless compression algorithm library URL: http://www.lz4.org/ Version: @VERSION@ -Libs: -L@LIBDIR@ -llz4 -Cflags: -I@INCLUDEDIR@ +Libs: -L${libdir} -llz4 +Cflags: -I${includedir} diff --git a/native/lz4/lz4.c b/native/lz4/lz4.c index 9808d70..654bfdf 100644 --- a/native/lz4/lz4.c +++ b/native/lz4/lz4.c @@ -1,6 +1,6 @@ /* LZ4 - Fast LZ compression algorithm - Copyright (C) 2011-present, Yann Collet. + Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -45,10 +45,16 @@ #endif /* - * ACCELERATION_DEFAULT : + * LZ4_ACCELERATION_DEFAULT : * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 */ -#define ACCELERATION_DEFAULT 1 +#define LZ4_ACCELERATION_DEFAULT 1 +/* + * LZ4_ACCELERATION_MAX : + * Any "acceleration" value higher than this threshold + * get treated as LZ4_ACCELERATION_MAX instead (fix #876) + */ +#define LZ4_ACCELERATION_MAX 65537 /*-************************************ @@ -82,6 +88,7 @@ * Define this parameter if your target system or compiler does not support hardware bit count */ #if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for WinCE doesn't support Hardware bit count */ +# undef LZ4_FORCE_SW_BITCOUNT /* avoid double def */ # define LZ4_FORCE_SW_BITCOUNT #endif @@ -114,10 +121,10 @@ /*-************************************ * Compiler Options **************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# include -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) /* Visual Studio 2005+ */ +# include /* only present in VS2005+ */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 6237) /* disable: C6237: conditional expression is always 0 */ #endif /* _MSC_VER */ #ifndef LZ4_FORCE_INLINE @@ -136,7 +143,7 @@ # endif /* _MSC_VER */ #endif /* LZ4_FORCE_INLINE */ -/* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE +/* LZ4_FORCE_O2 and LZ4_FORCE_INLINE * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8, * together with a simple 8-byte copy loop as a fall-back path. * However, this optimization hurts the decompression speed by >30%, @@ -151,11 +158,11 @@ * of LZ4_wildCopy8 does not affect the compression speed. */ #if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__) -# define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize("O2"))) -# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE __attribute__((optimize("O2"))) LZ4_FORCE_INLINE +# define LZ4_FORCE_O2 __attribute__((optimize("O2"))) +# undef LZ4_FORCE_INLINE +# define LZ4_FORCE_INLINE static __inline __attribute__((optimize("O2"),always_inline)) #else -# define LZ4_FORCE_O2_GCC_PPC64LE -# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static +# define LZ4_FORCE_O2 #endif #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) @@ -171,16 +178,60 @@ #define unlikely(expr) expect((expr) != 0, 0) #endif +/* Should the alignment test prove unreliable, for some reason, + * it can be disabled by setting LZ4_ALIGN_TEST to 0 */ +#ifndef LZ4_ALIGN_TEST /* can be externally provided */ +# define LZ4_ALIGN_TEST 1 +#endif + /*-************************************ * Memory routines **************************************/ -#include /* malloc, calloc, free */ -#define ALLOC(s) malloc(s) -#define ALLOC_AND_ZERO(s) calloc(1,s) -#define FREEMEM(p) free(p) -#include /* memset, memcpy */ -#define MEM_INIT(p,v,s) memset((p),(v),(s)) + +/*! LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION : + * Disable relatively high-level LZ4/HC functions that use dynamic memory + * allocation functions (malloc(), calloc(), free()). + * + * Note that this is a compile-time switch. And since it disables + * public/stable LZ4 v1 API functions, we don't recommend using this + * symbol to generate a library for distribution. + * + * The following public functions are removed when this symbol is defined. + * - lz4 : LZ4_createStream, LZ4_freeStream, + * LZ4_createStreamDecode, LZ4_freeStreamDecode, LZ4_create (deprecated) + * - lz4hc : LZ4_createStreamHC, LZ4_freeStreamHC, + * LZ4_createHC (deprecated), LZ4_freeHC (deprecated) + * - lz4frame, lz4file : All LZ4F_* functions + */ +#if defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) +# define ALLOC(s) lz4_error_memory_allocation_is_disabled +# define ALLOC_AND_ZERO(s) lz4_error_memory_allocation_is_disabled +# define FREEMEM(p) lz4_error_memory_allocation_is_disabled +#elif defined(LZ4_USER_MEMORY_FUNCTIONS) +/* memory management functions can be customized by user project. + * Below functions must exist somewhere in the Project + * and be available at link time */ +void* LZ4_malloc(size_t s); +void* LZ4_calloc(size_t n, size_t s); +void LZ4_free(void* p); +# define ALLOC(s) LZ4_malloc(s) +# define ALLOC_AND_ZERO(s) LZ4_calloc(1,s) +# define FREEMEM(p) LZ4_free(p) +#else +# include /* malloc, calloc, free */ +# define ALLOC(s) malloc(s) +# define ALLOC_AND_ZERO(s) calloc(1,s) +# define FREEMEM(p) free(p) +#endif + +#if ! LZ4_FREESTANDING +# include /* memset, memcpy */ +#endif +#if !defined(LZ4_memset) +# define LZ4_memset(p,v,s) memset((p),(v),(s)) +#endif +#define MEM_INIT(p,v,s) LZ4_memset((p),(v),(s)) /*-************************************ @@ -225,21 +276,27 @@ static const int LZ4_minLength = (MFLIMIT+1); #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) # include -static int g_debuglog_enable = 1; -# define DEBUGLOG(l, ...) { \ - if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ - fprintf(stderr, __FILE__ ": "); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, " \n"); \ - } } + static int g_debuglog_enable = 1; +# define DEBUGLOG(l, ...) { \ + if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ + fprintf(stderr, __FILE__ ": "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } } #else -# define DEBUGLOG(l, ...) {} /* disabled */ +# define DEBUGLOG(l, ...) {} /* disabled */ #endif +static int LZ4_isAligned(const void* ptr, size_t alignment) +{ + return ((size_t)ptr & (alignment -1)) == 0; +} + /*-************************************ * Types **************************************/ +#include #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # include typedef uint8_t BYTE; @@ -249,6 +306,9 @@ static int g_debuglog_enable = 1; typedef uint64_t U64; typedef uintptr_t uptrval; #else +# if UINT_MAX != 4294967295UL +# error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4" +# endif typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; @@ -273,6 +333,31 @@ typedef enum { /*-************************************ * Reading and writing into memory **************************************/ + +/** + * LZ4 relies on memcpy with a constant size being inlined. In freestanding + * environments, the compiler can't assume the implementation of memcpy() is + * standard compliant, so it can't apply its specialized memcpy() inlining + * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze + * memcpy() as if it were standard compliant, so it can inline it in freestanding + * environments. This is needed when decompressing the Linux Kernel, for example. + */ +#if !defined(LZ4_memcpy) +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size) +# else +# define LZ4_memcpy(dst, src, size) memcpy(dst, src, size) +# endif +#endif + +#if !defined(LZ4_memmove) +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4_memmove __builtin_memmove +# else +# define LZ4_memmove memmove +# endif +#endif + static unsigned LZ4_isLittleEndian(void) { const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ @@ -294,40 +379,40 @@ static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */ -typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign; +typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) LZ4_unalign; -static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } -static U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } -static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; } +static U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign*)ptr)->u16; } +static U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign*)ptr)->u32; } +static reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalign*)ptr)->uArch; } -static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } -static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } +static void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign*)memPtr)->u16 = value; } +static void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign*)memPtr)->u32 = value; } #else /* safe and portable access using memcpy() */ static U16 LZ4_read16(const void* memPtr) { - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static U32 LZ4_read32(const void* memPtr) { - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static reg_t LZ4_read_ARCH(const void* memPtr) { - reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; + reg_t val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static void LZ4_write16(void* memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + LZ4_memcpy(memPtr, &value, sizeof(value)); } static void LZ4_write32(void* memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + LZ4_memcpy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ @@ -355,14 +440,14 @@ static void LZ4_writeLE16(void* memPtr, U16 value) } /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ -LZ4_FORCE_O2_INLINE_GCC_PPC64LE +LZ4_FORCE_INLINE void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; BYTE* const e = (BYTE*)dstEnd; - do { memcpy(d,s,8); d+=8; s+=8; } while (d= 16. */ -LZ4_FORCE_O2_INLINE_GCC_PPC64LE void +LZ4_FORCE_INLINE void LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; BYTE* const e = (BYTE*)dstEnd; - do { memcpy(d,s,16); memcpy(d+16,s+16,16); d+=32; s+=32; } while (d= dstPtr + MINMATCH * - there is at least 8 bytes available to write after dstEnd */ -LZ4_FORCE_O2_INLINE_GCC_PPC64LE void +LZ4_FORCE_INLINE void LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset) { BYTE v[8]; assert(dstEnd >= dstPtr + MINMATCH); - LZ4_write32(dstPtr, 0); /* silence an msan warning when offset==0 */ switch(offset) { case 1: - memset(v, *srcPtr, 8); + MEM_INIT(v, *srcPtr, 8); break; case 2: - memcpy(v, srcPtr, 2); - memcpy(&v[2], srcPtr, 2); - memcpy(&v[4], &v[0], 4); + LZ4_memcpy(v, srcPtr, 2); + LZ4_memcpy(&v[2], srcPtr, 2); +#if defined(_MSC_VER) && (_MSC_VER <= 1933) /* MSVC 2022 ver 17.3 or earlier */ +# pragma warning(push) +# pragma warning(disable : 6385) /* warning C6385: Reading invalid data from 'v'. */ +#endif + LZ4_memcpy(&v[4], v, 4); +#if defined(_MSC_VER) && (_MSC_VER <= 1933) /* MSVC 2022 ver 17.3 or earlier */ +# pragma warning(pop) +#endif break; case 4: - memcpy(v, srcPtr, 4); - memcpy(&v[4], srcPtr, 4); + LZ4_memcpy(v, srcPtr, 4); + LZ4_memcpy(&v[4], srcPtr, 4); break; default: LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset); return; } - memcpy(dstPtr, v, 8); + LZ4_memcpy(dstPtr, v, 8); dstPtr += 8; while (dstPtr < dstEnd) { - memcpy(dstPtr, v, 8); + LZ4_memcpy(dstPtr, v, 8); dstPtr += 8; } } @@ -462,75 +557,103 @@ LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const si **************************************/ static unsigned LZ4_NbCommonBytes (reg_t val) { + assert(val != 0); if (LZ4_isLittleEndian()) { - if (sizeof(val)==8) { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + if (sizeof(val) == 8) { +# if defined(_MSC_VER) && (_MSC_VER >= 1800) && (defined(_M_AMD64) && !defined(_M_ARM64EC)) && !defined(LZ4_FORCE_SW_BITCOUNT) +/*-************************************************************************************************* +* ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications on ARM64 Windows 11. +* The ARM64EC ABI does not support AVX/AVX2/AVX512 instructions, nor their relevant intrinsics +* including _tzcnt_u64. Therefore, we need to neuter the _tzcnt_u64 code path for ARM64EC. +****************************************************************************************************/ +# if defined(__clang__) && (__clang_major__ < 10) + /* Avoid undefined clang-cl intrinsics issue. + * See https://github.com/lz4/lz4/pull/1017 for details. */ + return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3; +# else + /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */ + return (unsigned)_tzcnt_u64(val) >> 3; +# endif +# elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; - _BitScanForward64( &r, (U64)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + _BitScanForward64(&r, (U64)val); + return (unsigned)r >> 3; +# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_ctzll((U64)val) >> 3; # else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, - 0, 3, 1, 3, 1, 4, 2, 7, - 0, 2, 3, 6, 1, 5, 3, 5, - 1, 3, 4, 4, 2, 5, 6, 7, - 7, 0, 1, 2, 3, 3, 4, 6, - 2, 6, 5, 5, 3, 4, 5, 6, - 7, 1, 2, 4, 6, 4, 4, 5, - 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; + const U64 m = 0x0101010101010101ULL; + val ^= val - 1; + return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56); # endif } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) +# if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + _BitScanForward(&r, (U32)val); + return (unsigned)r >> 3; +# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_ctz((U32)val) >> 3; # else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, - 3, 2, 2, 1, 3, 2, 0, 1, - 3, 3, 1, 2, 2, 2, 2, 0, - 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; + const U32 m = 0x01010101; + return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24; # endif } } else /* Big Endian CPU */ { - if (sizeof(val)==8) { /* 64-bits */ -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + if (sizeof(val)==8) { +# if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_clzll((U64)val) >> 3; # else +#if 1 + /* this method is probably faster, + * but adds a 128 bytes lookup table */ + static const unsigned char ctz7_tab[128] = { + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + }; + U64 const mask = 0x0101010101010101ULL; + U64 const t = (((val >> 8) - mask) | val) & mask; + return ctz7_tab[(t * 0x0080402010080402ULL) >> 57]; +#else + /* this method doesn't consume memory space like the previous one, + * but it contains several branches, + * that may end up slowing execution */ static const U32 by32 = sizeof(val)*4; /* 32 on 64 bits (goal), 16 on 32 bits. - Just to avoid some static analyzer complaining about shift by 32 on 32-bits target. - Note that this code path is never triggered in 32-bits mode. */ + Just to avoid some static analyzer complaining about shift by 32 on 32-bits target. + Note that this code path is never triggered in 32-bits mode. */ unsigned r; if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; } if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } r += (!val); return r; +#endif # endif } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) +# if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_clz((U32)val) >> 3; # else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; + val >>= 8; + val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) | + (val + 0x00FF0000)) >> 24; + return (unsigned)val ^ 3; # endif } } } + #define STEPSIZE sizeof(reg_t) LZ4_FORCE_INLINE unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) @@ -585,10 +708,10 @@ typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere * else in memory, starting at ctx->dictionary with length * ctx->dictSize. - * - usingDictCtx : Like usingExtDict, but everything concerning the preceding - * content is in a separate context, pointed to by - * ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table - * entries in the current context that refer to positions + * - usingDictCtx : Everything concerning the preceding content is + * in a separate context, pointed to by ctx->dictCtx. + * ctx->dictionary, ctx->dictSize, and table entries + * in the current context that refer to positions * preceding the beginning of the current compression are * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx * ->dictSize describe the location and size of the preceding @@ -605,12 +728,12 @@ typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } -int LZ4_sizeofState() { return LZ4_STREAMSIZE; } +int LZ4_sizeofState(void) { return sizeof(LZ4_stream_t); } -/*-************************************ -* Internal Definitions used in Tests -**************************************/ +/*-**************************************** +* Internal Definitions, used only in Tests +*******************************************/ #if defined (__cplusplus) extern "C" { #endif @@ -620,7 +743,9 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize); - +int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, + int compressedSize, int targetOutputSize, int dstCapacity, + const void* dictStart, size_t dictSize); #if defined (__cplusplus) } #endif @@ -628,7 +753,7 @@ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, /*-****************************** * Compression functions ********************************/ -static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { if (tableType == byU16) return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); @@ -636,7 +761,7 @@ static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } -static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; if (LZ4_isLittleEndian()) { @@ -654,7 +779,7 @@ LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tab return LZ4_hash4(LZ4_read32(p), tableType); } -static void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) +LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { @@ -666,7 +791,7 @@ static void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) } } -static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) +LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { @@ -678,7 +803,7 @@ static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t cons } } -static void LZ4_putPositionOnHash(const BYTE* p, U32 h, +LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { @@ -703,7 +828,7 @@ LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_ * Assumption 1 : only valid if tableType == byU32 or byU16. * Assumption 2 : h is presumed valid (within limits of hash table) */ -static U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) +LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) { LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); if (tableType == byU32) { @@ -739,22 +864,13 @@ LZ4_FORCE_INLINE void LZ4_prepareTable(LZ4_stream_t_internal* const cctx, const int inputSize, const tableType_t tableType) { - /* If compression failed during the previous step, then the context - * is marked as dirty, therefore, it has to be fully reset. - */ - if (cctx->dirty) { - DEBUGLOG(5, "LZ4_prepareTable: Full reset for %p", cctx); - MEM_INIT(cctx, 0, sizeof(LZ4_stream_t_internal)); - return; - } - /* If the table hasn't been used, it's guaranteed to be zeroed out, and is * therefore safe to use no matter what mode we're in. Otherwise, we figure * out if it's safe to leave as is or whether it needs to be reset. */ - if (cctx->tableType != clearedTable) { + if ((tableType_t)cctx->tableType != clearedTable) { assert(inputSize >= 0); - if (cctx->tableType != tableType + if ((tableType_t)cctx->tableType != tableType || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU) || ((tableType == byU32) && cctx->currentOffset > 1 GB) || tableType == byPtr @@ -763,15 +879,16 @@ LZ4_prepareTable(LZ4_stream_t_internal* const cctx, DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx); MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE); cctx->currentOffset = 0; - cctx->tableType = clearedTable; + cctx->tableType = (U32)clearedTable; } else { DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)"); } } - /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, is faster - * than compressing without a gap. However, compressing with - * currentOffset == 0 is faster still, so we preserve that case. + /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, + * is faster than compressing without a gap. + * However, compressing with currentOffset == 0 is faster still, + * so we preserve that case. */ if (cctx->currentOffset != 0 && tableType == byU32) { DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset"); @@ -785,13 +902,17 @@ LZ4_prepareTable(LZ4_stream_t_internal* const cctx, } /** LZ4_compress_generic() : - inlined, to ensure branches are decided at compilation time */ -LZ4_FORCE_INLINE int LZ4_compress_generic( + * inlined, to ensure branches are decided at compilation time. + * Presumed already validated at this stage: + * - source != NULL + * - inputSize > 0 + */ +LZ4_FORCE_INLINE int LZ4_compress_generic_validated( LZ4_stream_t_internal* const cctx, const char* const source, char* const dest, const int inputSize, - int *inputConsumed, /* only written when outputDirective == fillOutput */ + int* inputConsumed, /* only written when outputDirective == fillOutput */ const int maxOutputSize, const limitedOutput_directive outputDirective, const tableType_t tableType, @@ -815,7 +936,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ - const BYTE* const dictEnd = dictionary + dictSize; + const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1; @@ -823,7 +944,8 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( /* the dictCtx currentOffset is indexed on the start of the dictionary, * while a dictionary in the current context precedes the currentOffset */ - const BYTE* dictBase = (dictDirective == usingDictCtx) ? + const BYTE* dictBase = (dictionary == NULL) ? NULL : + (dictDirective == usingDictCtx) ? dictionary + dictSize - dictCtx->currentOffset : dictionary + dictSize - startIndex; @@ -833,11 +955,11 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( U32 offset = 0; U32 forwardH; - DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, tableType); + DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType); + assert(ip != NULL); /* If init conditions are not met, we don't have to mark stream * as having dirty context, since no action was taken yet */ if (outputDirective == fillOutput && maxOutputSize < 1) { return 0; } /* Impossible to store anything */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; } /* Unsupported inputSize, too large (or negative) */ if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) { return 0; } /* Size too large (not within 64K limit) */ if (tableType==byPtr) assert(dictDirective==noDict); /* only supported use case with byPtr */ assert(acceleration >= 1); @@ -854,7 +976,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( cctx->dictSize += (U32)inputSize; } cctx->currentOffset += (U32)inputSize; - cctx->tableType = (U16)tableType; + cctx->tableType = (U32)tableType; if (inputSize= MINMATCH); + assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; } else { @@ -986,7 +1109,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( _next_match: /* at this stage, the following variables must be correctly set : * - ip : at start of LZ operation - * - match : at start of previous pattern occurence; can be within current prefix, or within extDict + * - match : at start of previous pattern occurrence; can be within current prefix, or within extDict * - offset : if maybe_ext_memSegment==1 (constant) * - lowLimit : must be == dictionary to mean "match is within extDict"; must be == source otherwise * - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written @@ -1111,6 +1234,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( } } else if (dictDirective==usingExtDict) { if (matchIndex < startIndex) { + assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; /* required for match length counter */ } else { @@ -1147,13 +1271,14 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( if (outputDirective == fillOutput) { /* adapt lastRun to fill 'dst' */ assert(olimit >= op); - lastRun = (size_t)(olimit-op) - 1; - lastRun -= (lastRun+240)/255; + lastRun = (size_t)(olimit-op) - 1/*token*/; + lastRun -= (lastRun + 256 - RUN_MASK) / 256; /*additional length tokens*/ } else { assert(outputDirective == limitedOutput); return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ } } + DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun); if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; *op++ = RUN_MASK << ML_BITS; @@ -1162,7 +1287,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( } else { *op++ = (BYTE)(lastRun< 0); + DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, result); return result; } +/** LZ4_compress_generic() : + * inlined, to ensure branches are decided at compilation time; + * takes care of src == (NULL, 0) + * and forward the rest to LZ4_compress_generic_validated */ +LZ4_FORCE_INLINE int LZ4_compress_generic( + LZ4_stream_t_internal* const cctx, + const char* const src, + char* const dst, + const int srcSize, + int *inputConsumed, /* only written when outputDirective == fillOutput */ + const int dstCapacity, + const limitedOutput_directive outputDirective, + const tableType_t tableType, + const dict_directive dictDirective, + const dictIssue_directive dictIssue, + const int acceleration) +{ + DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i", + srcSize, dstCapacity); + + if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; } /* Unsupported srcSize, too large (or negative) */ + if (srcSize == 0) { /* src == NULL supported if srcSize == 0 */ + if (outputDirective != notLimited && dstCapacity <= 0) return 0; /* no output, can't write anything */ + DEBUGLOG(5, "Generating an empty block"); + assert(outputDirective == notLimited || dstCapacity >= 1); + assert(dst != NULL); + dst[0] = 0; + if (outputDirective == fillOutput) { + assert (inputConsumed != NULL); + *inputConsumed = 0; + } + return 1; + } + assert(src != NULL); + + return LZ4_compress_generic_validated(cctx, src, dst, srcSize, + inputConsumed, /* only written into if outputDirective == fillOutput */ + dstCapacity, outputDirective, + tableType, dictDirective, dictIssue, acceleration); +} + int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse; assert(ctx != NULL); - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; if (maxOutputSize >= LZ4_compressBound(inputSize)) { if (inputSize < LZ4_64Klimit) { return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration); @@ -1211,7 +1378,8 @@ int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration) { LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; if (dstCapacity >= LZ4_compressBound(srcSize)) { if (srcSize < LZ4_64Klimit) { @@ -1249,7 +1417,7 @@ int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutp { int result; #if (LZ4_HEAPMODE) - LZ4_stream_t* ctxPtr = ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + LZ4_stream_t* ctxPtr = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ if (ctxPtr == NULL) return 0; #else LZ4_stream_t ctx; @@ -1270,22 +1438,6 @@ int LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputS } -/* hidden debug function */ -/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ -int LZ4_compress_fast_force(const char* src, char* dst, int srcSize, int dstCapacity, int acceleration) -{ - LZ4_stream_t ctx; - LZ4_initStream(&ctx, sizeof(ctx)); - - if (srcSize < LZ4_64Klimit) { - return LZ4_compress_generic(&ctx.internal_donotuse, src, dst, srcSize, NULL, dstCapacity, limitedOutput, byU16, noDict, noDictIssue, acceleration); - } else { - tableType_t const addrMode = (sizeof(void*) > 4) ? byU32 : byPtr; - return LZ4_compress_generic(&ctx.internal_donotuse, src, dst, srcSize, NULL, dstCapacity, limitedOutput, addrMode, noDict, noDictIssue, acceleration); - } -} - - /* Note!: This function leaves the stream in an unclean/broken state! * It is not safe to subsequently use the same state with a _fastReset() or * _continue() call without resetting it. */ @@ -1330,37 +1482,35 @@ int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targe * Streaming functions ********************************/ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_stream_t* LZ4_createStream(void) { LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); - LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal)); DEBUGLOG(4, "LZ4_createStream %p", lz4s); if (lz4s == NULL) return NULL; LZ4_initStream(lz4s, sizeof(*lz4s)); return lz4s; } +#endif -#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 : - it reports an aligment of 8-bytes, - while actually aligning LZ4_stream_t on 4 bytes. */ static size_t LZ4_stream_t_alignment(void) { - struct { char c; LZ4_stream_t t; } t_a; - return sizeof(t_a) - sizeof(t_a.t); -} +#if LZ4_ALIGN_TEST + typedef struct { char c; LZ4_stream_t t; } t_a; + return sizeof(t_a) - sizeof(LZ4_stream_t); +#else + return 1; /* effectively disabled */ #endif +} LZ4_stream_t* LZ4_initStream (void* buffer, size_t size) { DEBUGLOG(5, "LZ4_initStream"); if (buffer == NULL) { return NULL; } if (size < sizeof(LZ4_stream_t)) { return NULL; } -#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 : - it reports an aligment of 8-bytes, - while actually aligning LZ4_stream_t on 4 bytes. */ - if (((size_t)buffer) & (LZ4_stream_t_alignment() - 1)) { return NULL; } /* alignment check */ -#endif - MEM_INIT(buffer, 0, sizeof(LZ4_stream_t)); + if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL; + MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal)); return (LZ4_stream_t*)buffer; } @@ -1369,13 +1519,14 @@ LZ4_stream_t* LZ4_initStream (void* buffer, size_t size) void LZ4_resetStream (LZ4_stream_t* LZ4_stream) { DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream); - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal)); } void LZ4_resetStream_fast(LZ4_stream_t* ctx) { LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32); } +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { if (!LZ4_stream) return 0; /* support free on NULL */ @@ -1383,6 +1534,7 @@ int LZ4_freeStream (LZ4_stream_t* LZ4_stream) FREEMEM(LZ4_stream); return (0); } +#endif #define HASH_UNIT sizeof(reg_t) @@ -1418,7 +1570,7 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) base = dictEnd - dict->currentOffset; dict->dictionary = p; dict->dictSize = (U32)(dictEnd - p); - dict->tableType = tableType; + dict->tableType = (U32)tableType; while (p <= dictEnd-HASH_UNIT) { LZ4_putPosition(p, dict->hashTable, tableType, base); @@ -1428,20 +1580,15 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) return (int)dict->dictSize; } -void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) { - const LZ4_stream_t_internal* dictCtx = dictionaryStream == NULL ? NULL : +void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) +{ + const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL : &(dictionaryStream->internal_donotuse); DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)", workingStream, dictionaryStream, dictCtx != NULL ? dictCtx->dictSize : 0); - /* Calling LZ4_resetStream_fast() here makes sure that changes will not be - * erased by subsequent calls to LZ4_resetStream_fast() in case stream was - * marked as having dirty context, e.g. requiring full reset. - */ - LZ4_resetStream_fast(workingStream); - if (dictCtx != NULL) { /* If the current offset is zero, we will never look in the * external dictionary context, since there is no value a table @@ -1488,36 +1635,40 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, int acceleration) { const tableType_t tableType = byU32; - LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; - const BYTE* dictEnd = streamPtr->dictionary + streamPtr->dictSize; + LZ4_stream_t_internal* const streamPtr = &LZ4_stream->internal_donotuse; + const char* dictEnd = streamPtr->dictSize ? (const char*)streamPtr->dictionary + streamPtr->dictSize : NULL; - DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i)", inputSize); + DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)", inputSize, streamPtr->dictSize); - if (streamPtr->dirty) { return 0; } /* Uninitialized structure detected */ - LZ4_renormDictT(streamPtr, inputSize); /* avoid index overflow */ - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + LZ4_renormDictT(streamPtr, inputSize); /* fix index overflow */ + if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; /* invalidate tiny dictionaries */ - if ( (streamPtr->dictSize-1 < 4-1) /* intentional underflow */ - && (dictEnd != (const BYTE*)source) ) { + if ( (streamPtr->dictSize < 4) /* tiny dictionary : not enough for a hash */ + && (dictEnd != source) /* prefix mode */ + && (inputSize > 0) /* tolerance : don't lose history, in case next invocation would use prefix mode */ + && (streamPtr->dictCtx == NULL) /* usingDictCtx */ + ) { DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary); + /* remove dictionary existence from history, to employ faster prefix mode */ streamPtr->dictSize = 0; streamPtr->dictionary = (const BYTE*)source; - dictEnd = (const BYTE*)source; + dictEnd = source; } /* Check overlapping input/dictionary space */ - { const BYTE* sourceEnd = (const BYTE*) source + inputSize; - if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { + { const char* const sourceEnd = source + inputSize; + if ((sourceEnd > (const char*)streamPtr->dictionary) && (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; - streamPtr->dictionary = dictEnd - streamPtr->dictSize; + streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize; } } /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE*)source) { + if (dictEnd == source) { if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration); else @@ -1538,12 +1689,12 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, * cost to copy the dictionary's tables into the active context, * so that the compression loop is only looking into one table. */ - memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t)); + LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr)); result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); } else { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration); } - } else { + } else { /* small data <= 4 KB */ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration); } else { @@ -1581,19 +1732,25 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* /*! LZ4_saveDict() : * If previously compressed data block is not guaranteed to remain available at its memory location, * save it into a safer place (char* safeBuffer). - * Note : you don't need to call LZ4_loadDict() afterwards, - * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue(). - * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. + * Note : no need to call LZ4_loadDict() afterwards, dictionary is immediately usable, + * one can therefore call LZ4_compress_fast_continue() right after. + * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. */ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; - const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + + DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, safeBuffer); if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */ if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; } - memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + if (safeBuffer == NULL) assert(dictSize == 0); + if (dictSize > 0) { + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + assert(dict->dictionary); + LZ4_memmove(safeBuffer, previousDictEnd - dictSize, (size_t)dictSize); + } dict->dictionary = (const BYTE*)safeBuffer; dict->dictSize = (U32)dictSize; @@ -1607,41 +1764,167 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) * Decompression functions ********************************/ -typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive; #undef MIN #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) + +/* variant for decompress_unsafe() + * does not know end of input + * presumes input is well formed + * note : will consume at least one byte */ +size_t read_long_length_no_check(const BYTE** pp) +{ + size_t b, l = 0; + do { b = **pp; (*pp)++; l += b; } while (b==255); + DEBUGLOG(6, "read_long_length_no_check: +length=%zu using %zu input bytes", l, l/255 + 1) + return l; +} + +/* core decoder variant for LZ4_decompress_fast*() + * for legacy support only : these entry points are deprecated. + * - Presumes input is correctly formed (no defense vs malformed inputs) + * - Does not know input size (presume input buffer is "large enough") + * - Decompress a full block (only) + * @return : nb of bytes read from input. + * Note : this variant is not optimized for speed, just for maintenance. + * the goal is to remove support of decompress_fast*() variants by v2.0 +**/ +LZ4_FORCE_INLINE int +LZ4_decompress_unsafe_generic( + const BYTE* const istart, + BYTE* const ostart, + int decompressedSize, + + size_t prefixSize, + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note: =0 if dictStart==NULL */ + ) +{ + const BYTE* ip = istart; + BYTE* op = (BYTE*)ostart; + BYTE* const oend = ostart + decompressedSize; + const BYTE* const prefixStart = ostart - prefixSize; + + DEBUGLOG(5, "LZ4_decompress_unsafe_generic"); + if (dictStart == NULL) assert(dictSize == 0); + + while (1) { + /* start new sequence */ + unsigned token = *ip++; + + /* literals */ + { size_t ll = token >> ML_BITS; + if (ll==15) { + /* long literal length */ + ll += read_long_length_no_check(&ip); + } + if ((size_t)(oend-op) < ll) return -1; /* output buffer overflow */ + LZ4_memmove(op, ip, ll); /* support in-place decompression */ + op += ll; + ip += ll; + if ((size_t)(oend-op) < MFLIMIT) { + if (op==oend) break; /* end of block */ + DEBUGLOG(5, "invalid: literals end at distance %zi from end of block", oend-op); + /* incorrect end of block : + * last match must start at least MFLIMIT==12 bytes before end of output block */ + return -1; + } } + + /* match */ + { size_t ml = token & 15; + size_t const offset = LZ4_readLE16(ip); + ip+=2; + + if (ml==15) { + /* long literal length */ + ml += read_long_length_no_check(&ip); + } + ml += MINMATCH; + + if ((size_t)(oend-op) < ml) return -1; /* output buffer overflow */ + + { const BYTE* match = op - offset; + + /* out of range */ + if (offset > (size_t)(op - prefixStart) + dictSize) { + DEBUGLOG(6, "offset out of range"); + return -1; + } + + /* check special case : extDict */ + if (offset > (size_t)(op - prefixStart)) { + /* extDict scenario */ + const BYTE* const dictEnd = dictStart + dictSize; + const BYTE* extMatch = dictEnd - (offset - (size_t)(op-prefixStart)); + size_t const extml = (size_t)(dictEnd - extMatch); + if (extml > ml) { + /* match entirely within extDict */ + LZ4_memmove(op, extMatch, ml); + op += ml; + ml = 0; + } else { + /* match split between extDict & prefix */ + LZ4_memmove(op, extMatch, extml); + op += extml; + ml -= extml; + } + match = prefixStart; + } + + /* match copy - slow variant, supporting overlap copy */ + { size_t u; + for (u=0; u= lencheck. - * loop_check - check ip >= lencheck in body of loop. Returns loop_error if so. - * initial_check - check ip >= lencheck before start of loop. Returns initial_error if so. - * error (output) - error code. Should be set to 0 before call. - */ -typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_error; -LZ4_FORCE_INLINE unsigned -read_variable_length(const BYTE**ip, const BYTE* lencheck, int loop_check, int initial_check, variable_length_error* error) -{ - unsigned length = 0; - unsigned s; - if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */ - *error = initial_error; - return length; - } - do { - s = **ip; - (*ip)++; - length += s; - if (loop_check && unlikely((*ip) >= lencheck)) { /* overflow detection */ - *error = loop_error; - return length; + * @ip : input pointer + * @ilimit : position after which if length is not decoded, the input is necessarily corrupted. + * @initial_check - check ip >= ipmax before start of loop. Returns initial_error if so. + * @error (output) - error code. Must be set to 0 before call. +**/ +typedef size_t Rvl_t; +static const Rvl_t rvl_error = (Rvl_t)(-1); +LZ4_FORCE_INLINE Rvl_t +read_variable_length(const BYTE** ip, const BYTE* ilimit, + int initial_check) +{ + Rvl_t s, length = 0; + assert(ip != NULL); + assert(*ip != NULL); + assert(ilimit != NULL); + if (initial_check && unlikely((*ip) >= ilimit)) { /* read limit reached */ + return rvl_error; } - } while (s==255); + do { + s = **ip; + (*ip)++; + length += s; + if (unlikely((*ip) > ilimit)) { /* read limit reached */ + return rvl_error; + } + /* accumulator overflow detection (32-bit mode only) */ + if ((sizeof(length)<8) && unlikely(length > ((Rvl_t)(-1)/2)) ) { + return rvl_error; + } + } while (s==255); - return length; + return length; } /*! LZ4_decompress_generic() : @@ -1657,7 +1940,6 @@ LZ4_decompress_generic( int srcSize, int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */ - endCondition_directive endOnInput, /* endOnOutputSize, endOnInputSize */ earlyEnd_directive partialDecoding, /* full, partial */ dict_directive dict, /* noDict, withPrefix64k, usingExtDict */ const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */ @@ -1665,7 +1947,7 @@ LZ4_decompress_generic( const size_t dictSize /* note : = 0 if noDict */ ) { - if (src == NULL) { return -1; } + if ((src == NULL) || (outputSize < 0)) { return -1; } { const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; @@ -1676,13 +1958,12 @@ LZ4_decompress_generic( const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize; - const int safeDecode = (endOnInput==endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + const int checkOffset = (dictSize < (int)(64 KB)); /* Set up the "end" pointers for the shortcut. */ - const BYTE* const shortiend = iend - (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/; - const BYTE* const shortoend = oend - (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/; + const BYTE* const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/; + const BYTE* const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/; const BYTE* match; size_t offset; @@ -1694,83 +1975,70 @@ LZ4_decompress_generic( /* Special cases */ assert(lowPrefix <= op); - if ((endOnInput) && (unlikely(outputSize==0))) { + if (unlikely(outputSize==0)) { /* Empty output buffer */ if (partialDecoding) return 0; return ((srcSize==1) && (*ip==0)) ? 0 : -1; } - if ((!endOnInput) && (unlikely(outputSize==0))) { return (*ip==0 ? 1 : -1); } - if ((endOnInput) && unlikely(srcSize==0)) { return -1; } + if (unlikely(srcSize==0)) { return -1; } - /* Currently the fast loop shows a regression on qualcomm arm chips. */ + /* LZ4_FAST_DEC_LOOP: + * designed for modern OoO performance cpus, + * where copying reliably 32-bytes is preferable to an unpredictable branch. + * note : fast loop may show a regression for some client arm chips. */ #if LZ4_FAST_DEC_LOOP if ((oend - op) < FASTLOOP_SAFE_DISTANCE) { DEBUGLOG(6, "skip fast decode loop"); goto safe_decode; } - /* Fast loop : decode sequences as long as output < iend-FASTLOOP_SAFE_DISTANCE */ + /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */ while (1) { /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */ assert(oend - op >= FASTLOOP_SAFE_DISTANCE); - if (endOnInput) { assert(ip < iend); } + assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ - assert(!endOnInput || ip <= iend); /* ip < iend before the increment */ - /* decode literal length */ if (length == RUN_MASK) { - variable_length_error error = ok; - length += read_variable_length(&ip, iend-RUN_MASK, endOnInput, endOnInput, &error); - if (error == initial_error) { goto _output_error; } - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ - if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ + size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); + if (addl == rvl_error) { goto _output_error; } + length += addl; + if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ + if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ /* copy literals */ cpy = op+length; LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); - if (endOnInput) { /* LZ4_decompress_safe() */ - if ((cpy>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; } - LZ4_wildCopy32(op, ip, cpy); - } else { /* LZ4_decompress_fast() */ - if (cpy>oend-8) { goto safe_literal_copy; } - LZ4_wildCopy8(op, ip, cpy); /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : - * it doesn't know input length, and only relies on end-of-block properties */ - } + if ((cpy>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; } + LZ4_wildCopy32(op, ip, cpy); ip += length; op = cpy; } else { cpy = op+length; - if (endOnInput) { /* LZ4_decompress_safe() */ - DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length); - /* We don't need to check oend, since we check it once for each loop below */ - if (ip > iend-(16 + 1/*max lit + offset + nextToken*/)) { goto safe_literal_copy; } - /* Literals can only be 14, but hope compilers optimize if we copy by a register size */ - memcpy(op, ip, 16); - } else { /* LZ4_decompress_fast() */ - /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : - * it doesn't know input length, and relies on end-of-block properties */ - memcpy(op, ip, 8); - if (length > 8) { memcpy(op+8, ip+8, 8); } - } + DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length); + /* We don't need to check oend, since we check it once for each loop below */ + if (ip > iend-(16 + 1/*max lit + offset + nextToken*/)) { goto safe_literal_copy; } + /* Literals can only be <= 14, but hope compilers optimize better when copy by a register size */ + LZ4_memcpy(op, ip, 16); ip += length; op = cpy; } /* get offset */ offset = LZ4_readLE16(ip); ip+=2; match = op - offset; - assert(match <= op); + assert(match <= op); /* overflow check */ /* get matchlength */ length = token & ML_MASK; if (length == ML_MASK) { - variable_length_error error = ok; - if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */ - length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error); - if (error != ok) { goto _output_error; } - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */ + size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); + if (addl == rvl_error) { goto _output_error; } + length += addl; length += MINMATCH; + if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */ + if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */ if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { goto safe_match_copy; } @@ -1780,46 +2048,48 @@ LZ4_decompress_generic( goto safe_match_copy; } - /* Fastpath check: Avoids a branch in LZ4_wildCopy32 if true */ + /* Fastpath check: skip LZ4_wildCopy32 when true */ if ((dict == withPrefix64k) || (match >= lowPrefix)) { if (offset >= 8) { assert(match >= lowPrefix); assert(match <= op); assert(op + 18 <= oend); - memcpy(op, match, 8); - memcpy(op+8, match+8, 8); - memcpy(op+16, match+16, 2); + LZ4_memcpy(op, match, 8); + LZ4_memcpy(op+8, match+8, 8); + LZ4_memcpy(op+16, match+16, 2); op += length; continue; } } } - if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */ + if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */ /* match starting within external dictionary */ if ((dict==usingExtDict) && (match < lowPrefix)) { + assert(dictEnd != NULL); if (unlikely(op+length > oend-LASTLITERALS)) { if (partialDecoding) { - length = MIN(length, (size_t)(oend-op)); /* reach end of buffer */ + DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd"); + length = MIN(length, (size_t)(oend-op)); } else { goto _output_error; /* end-of-block condition violated */ } } if (length <= (size_t)(lowPrefix-match)) { /* match fits entirely within external dictionary : just copy */ - memmove(op, dictEnd - (lowPrefix-match), length); + LZ4_memmove(op, dictEnd - (lowPrefix-match), length); op += length; } else { /* match stretches into both external dictionary and current block */ size_t const copySize = (size_t)(lowPrefix - match); size_t const restSize = length - copySize; - memcpy(op, dictEnd - copySize, copySize); + LZ4_memcpy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ BYTE* const endOfMatch = op + restSize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) { *op++ = *copyFrom++; } } else { - memcpy(op, lowPrefix, restSize); + LZ4_memcpy(op, lowPrefix, restSize); op += restSize; } } continue; @@ -1842,11 +2112,10 @@ LZ4_decompress_generic( /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */ while (1) { + assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ - assert(!endOnInput || ip <= iend); /* ip < iend before the increment */ - /* A two-stage shortcut for the most common case: * 1) If the literal length is 0..14, and there is enough space, * enter the shortcut and copy 16 bytes on behalf of the literals @@ -1856,11 +2125,11 @@ LZ4_decompress_generic( * those 18 bytes earlier, upon entering the shortcut (in other words, * there is a combined check for both stages). */ - if ( (endOnInput ? length != RUN_MASK : length <= 8) + if ( (length != RUN_MASK) /* strictly "less than" on input, to re-enter the loop with at least one byte */ - && likely((endOnInput ? ip < shortiend : 1) & (op <= shortoend)) ) { + && likely((ip < shortiend) & (op <= shortoend)) ) { /* Copy the literals */ - memcpy(op, ip, endOnInput ? 16 : 8); + LZ4_memcpy(op, ip, 16); op += length; ip += length; /* The second stage: prepare for match copying, decode full info. @@ -1875,9 +2144,9 @@ LZ4_decompress_generic( && (offset >= 8) && (dict==withPrefix64k || match >= lowPrefix) ) { /* Copy the match. */ - memcpy(op + 0, match + 0, 8); - memcpy(op + 8, match + 8, 8); - memcpy(op +16, match +16, 2); + LZ4_memcpy(op + 0, match + 0, 8); + LZ4_memcpy(op + 8, match + 8, 8); + LZ4_memcpy(op +16, match +16, 2); op += length + MINMATCH; /* Both stages worked, load the next token. */ continue; @@ -1890,11 +2159,11 @@ LZ4_decompress_generic( /* decode literal length */ if (length == RUN_MASK) { - variable_length_error error = ok; - length += read_variable_length(&ip, iend-RUN_MASK, endOnInput, endOnInput, &error); - if (error == initial_error) { goto _output_error; } - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ - if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ + size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); + if (addl == rvl_error) { goto _output_error; } + length += addl; + if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ + if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ } /* copy literals */ @@ -1903,55 +2172,59 @@ LZ4_decompress_generic( safe_literal_copy: #endif LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); - if ( ((endOnInput) && ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) - { + if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) { /* We've either hit the input parsing restriction or the output parsing restriction. - * If we've hit the input parsing condition then this must be the last sequence. - * If we've hit the output parsing condition then we are either using partialDecoding - * or we've hit the output parsing condition. + * In the normal scenario, decoding a full block, it must be the last sequence, + * otherwise it's an error (invalid input or dimensions). + * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow. */ if (partialDecoding) { /* Since we are partial decoding we may be in this block because of the output parsing * restriction, which is not valid since the output buffer is allowed to be undersized. */ - assert(endOnInput); - /* If we're in this block because of the input parsing condition, then we must be on the - * last sequence (or invalid), so we must check that we exactly consume the input. + DEBUGLOG(7, "partialDecoding: copying literals, close to input or output end") + DEBUGLOG(7, "partialDecoding: literal length = %u", (unsigned)length); + DEBUGLOG(7, "partialDecoding: remaining space in dstBuffer : %i", (int)(oend - op)); + DEBUGLOG(7, "partialDecoding: remaining space in srcBuffer : %i", (int)(iend - ip)); + /* Finishing in the middle of a literals segment, + * due to lack of input. */ - if ((ip+length>iend-(2+1+LASTLITERALS)) && (ip+length != iend)) { goto _output_error; } - assert(ip+length <= iend); - /* We are finishing in the middle of a literals segment. - * Break after the copy. + if (ip+length > iend) { + length = (size_t)(iend-ip); + cpy = op + length; + } + /* Finishing in the middle of a literals segment, + * due to lack of output space. */ if (cpy > oend) { cpy = oend; assert(op<=oend); length = (size_t)(oend-op); } - assert(ip+length <= iend); } else { - /* We must be on the last sequence because of the parsing limitations so check - * that we exactly regenerate the original size (must be exact when !endOnInput). - */ - if ((!endOnInput) && (cpy != oend)) { goto _output_error; } /* We must be on the last sequence (or invalid) because of the parsing limitations * so check that we exactly consume the input and don't overrun the output buffer. */ - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) { goto _output_error; } + if ((ip+length != iend) || (cpy > oend)) { + DEBUGLOG(6, "should have been last run of literals") + DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend); + DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend); + goto _output_error; + } } - memmove(op, ip, length); /* supports overlapping memory regions, which only matters for in-place decompression scenarios */ + LZ4_memmove(op, ip, length); /* supports overlapping memory regions, for in-place decompression scenarios */ ip += length; op += length; - /* Necessarily EOF when !partialDecoding. When partialDecoding - * it is EOF if we've either filled the output buffer or hit - * the input parsing restriction. + /* Necessarily EOF when !partialDecoding. + * When partialDecoding, it is EOF if we've either + * filled the output buffer or + * can't proceed with reading an offset for following match. */ - if (!partialDecoding || (cpy == oend) || (ip == iend)) { + if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) { break; } } else { - LZ4_wildCopy8(op, ip, cpy); /* may overwrite up to WILDCOPYLENGTH beyond cpy */ + LZ4_wildCopy8(op, ip, cpy); /* can overwrite up to 8 bytes beyond cpy */ ip += length; op = cpy; } @@ -1964,10 +2237,10 @@ LZ4_decompress_generic( _copy_match: if (length == ML_MASK) { - variable_length_error error = ok; - length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error); - if (error != ok) goto _output_error; - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ + size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); + if (addl == rvl_error) { goto _output_error; } + length += addl; + if (unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ } length += MINMATCH; @@ -1977,6 +2250,7 @@ LZ4_decompress_generic( if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */ /* match starting within external dictionary */ if ((dict==usingExtDict) && (match < lowPrefix)) { + assert(dictEnd != NULL); if (unlikely(op+length > oend-LASTLITERALS)) { if (partialDecoding) length = MIN(length, (size_t)(oend-op)); else goto _output_error; /* doesn't respect parsing restriction */ @@ -1984,20 +2258,20 @@ LZ4_decompress_generic( if (length <= (size_t)(lowPrefix-match)) { /* match fits entirely within external dictionary : just copy */ - memmove(op, dictEnd - (lowPrefix-match), length); + LZ4_memmove(op, dictEnd - (lowPrefix-match), length); op += length; } else { /* match stretches into both external dictionary and current block */ size_t const copySize = (size_t)(lowPrefix - match); size_t const restSize = length - copySize; - memcpy(op, dictEnd - copySize, copySize); + LZ4_memcpy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ BYTE* const endOfMatch = op + restSize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) *op++ = *copyFrom++; } else { - memcpy(op, lowPrefix, restSize); + LZ4_memcpy(op, lowPrefix, restSize); op += restSize; } } continue; @@ -2016,7 +2290,7 @@ LZ4_decompress_generic( if (matchEnd > op) { /* overlap copy */ while (op < copyEnd) { *op++ = *match++; } } else { - memcpy(op, match, mlen); + LZ4_memcpy(op, match, mlen); } op = copyEnd; if (op == oend) { break; } @@ -2030,10 +2304,10 @@ LZ4_decompress_generic( op[2] = match[2]; op[3] = match[3]; match += inc32table[offset]; - memcpy(op+4, match, 4); + LZ4_memcpy(op+4, match, 4); match -= dec64table[offset]; } else { - memcpy(op, match, 8); + LZ4_memcpy(op, match, 8); match += 8; } op += 8; @@ -2048,18 +2322,15 @@ LZ4_decompress_generic( } while (op < cpy) { *op++ = *match++; } } else { - memcpy(op, match, 8); + LZ4_memcpy(op, match, 8); if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); } } op = cpy; /* wildcopy correction */ } /* end of decoding */ - if (endOnInput) { - return (int) (((char*)op)-dst); /* Nb of output bytes decoded */ - } else { - return (int) (((const char*)ip)-src); /* Nb of input bytes read */ - } + DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst)); + return (int) (((char*)op)-dst); /* Nb of output bytes decoded */ /* Overflow error detected */ _output_error: @@ -2070,75 +2341,106 @@ LZ4_decompress_generic( /*===== Instantiate the API decoding functions. =====*/ -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, - endOnInputSize, decode_full_block, noDict, + decode_full_block, noDict, (BYTE*)dest, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 int LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity) { dstCapacity = MIN(targetOutputSize, dstCapacity); return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity, - endOnInputSize, partial_decode, + partial_decode, noDict, (BYTE*)dst, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 int LZ4_decompress_fast(const char* source, char* dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, decode_full_block, withPrefix64k, - (BYTE*)dest - 64 KB, NULL, 0); + DEBUGLOG(5, "LZ4_decompress_fast"); + return LZ4_decompress_unsafe_generic( + (const BYTE*)source, (BYTE*)dest, originalSize, + 0, NULL, 0); } /*===== Instantiate a few more decoding cases, used more than once. =====*/ -LZ4_FORCE_O2_GCC_PPC64LE /* Exported, an obsolete API function. */ +LZ4_FORCE_O2 /* Exported, an obsolete API function. */ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, decode_full_block, withPrefix64k, + decode_full_block, withPrefix64k, + (BYTE*)dest - 64 KB, NULL, 0); +} + +LZ4_FORCE_O2 +static int LZ4_decompress_safe_partial_withPrefix64k(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + partial_decode, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 0); } /* Another obsolete API function, paired with the previous one. */ int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) { - /* LZ4_decompress_fast doesn't validate match offsets, - * and thus serves well with any prefixed dictionary. */ - return LZ4_decompress_fast(source, dest, originalSize); + return LZ4_decompress_unsafe_generic( + (const BYTE*)source, (BYTE*)dest, originalSize, + 64 KB, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize, size_t prefixSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, decode_full_block, noDict, + decode_full_block, noDict, + (BYTE*)dest-prefixSize, NULL, 0); +} + +LZ4_FORCE_O2 +static int LZ4_decompress_safe_partial_withSmallPrefix(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, + size_t prefixSize) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + partial_decode, noDict, (BYTE*)dest-prefixSize, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, decode_full_block, usingExtDict, + decode_full_block, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 +int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, + int compressedSize, int targetOutputSize, int dstCapacity, + const void* dictStart, size_t dictSize) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + partial_decode, usingExtDict, + (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + +LZ4_FORCE_O2 static int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize, const void* dictStart, size_t dictSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, decode_full_block, usingExtDict, - (BYTE*)dest, (const BYTE*)dictStart, dictSize); + return LZ4_decompress_unsafe_generic( + (const BYTE*)source, (BYTE*)dest, originalSize, + 0, (const BYTE*)dictStart, dictSize); } /* The "double dictionary" mode, for use with e.g. ring buffers: the first part @@ -2150,26 +2452,17 @@ int LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compresse size_t prefixSize, const void* dictStart, size_t dictSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, decode_full_block, usingExtDict, - (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize); -} - -LZ4_FORCE_INLINE -int LZ4_decompress_fast_doubleDict(const char* source, char* dest, int originalSize, - size_t prefixSize, const void* dictStart, size_t dictSize) -{ - return LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, decode_full_block, usingExtDict, + decode_full_block, usingExtDict, (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize); } /*===== streaming decompression functions =====*/ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_streamDecode_t* LZ4_createStreamDecode(void) { - LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); - LZ4_STATIC_ASSERT(LZ4_STREAMDECODESIZE >= sizeof(LZ4_streamDecode_t_internal)); /* A compilation error here means LZ4_STREAMDECODESIZE is not large enough */ - return lz4s; + LZ4_STATIC_ASSERT(sizeof(LZ4_streamDecode_t) >= sizeof(LZ4_streamDecode_t_internal)); + return (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); } int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) @@ -2178,6 +2471,7 @@ int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) FREEMEM(LZ4_stream); return 0; } +#endif /*! LZ4_setStreamDecode() : * Use this function to instruct where to find the dictionary. @@ -2188,8 +2482,13 @@ int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) { LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; - lz4sd->prefixSize = (size_t) dictSize; - lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->prefixSize = (size_t)dictSize; + if (dictSize) { + assert(dictionary != NULL); + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + } else { + lz4sd->prefixEnd = (const BYTE*) dictionary; + } lz4sd->externalDict = NULL; lz4sd->extDictSize = 0; return 1; @@ -2221,7 +2520,7 @@ int LZ4_decoderRingBufferSize(int maxBlockSize) If it's not possible, save the relevant part of decoded data into a safe buffer, and indicate where it stands using LZ4_setStreamDecode() */ -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; @@ -2261,29 +2560,35 @@ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch return result; } -LZ4_FORCE_O2_GCC_PPC64LE -int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +LZ4_FORCE_O2 int +LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, + const char* source, char* dest, int originalSize) { - LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + LZ4_streamDecode_t_internal* const lz4sd = + (assert(LZ4_streamDecode!=NULL), &LZ4_streamDecode->internal_donotuse); int result; + + DEBUGLOG(5, "LZ4_decompress_fast_continue (toDecodeSize=%i)", originalSize); assert(originalSize >= 0); if (lz4sd->prefixSize == 0) { + DEBUGLOG(5, "first invocation : no prefix nor extDict"); assert(lz4sd->extDictSize == 0); result = LZ4_decompress_fast(source, dest, originalSize); if (result <= 0) return result; lz4sd->prefixSize = (size_t)originalSize; lz4sd->prefixEnd = (BYTE*)dest + originalSize; } else if (lz4sd->prefixEnd == (BYTE*)dest) { - if (lz4sd->prefixSize >= 64 KB - 1 || lz4sd->extDictSize == 0) - result = LZ4_decompress_fast(source, dest, originalSize); - else - result = LZ4_decompress_fast_doubleDict(source, dest, originalSize, - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + DEBUGLOG(5, "continue using existing prefix"); + result = LZ4_decompress_unsafe_generic( + (const BYTE*)source, (BYTE*)dest, originalSize, + lz4sd->prefixSize, + lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += (size_t)originalSize; lz4sd->prefixEnd += originalSize; } else { + DEBUGLOG(5, "prefix becomes extDict"); lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_fast_extDict(source, dest, originalSize, @@ -2319,10 +2624,27 @@ int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressed return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize); } +int LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_safe_partial(source, dest, compressedSize, targetOutputSize, dstCapacity); + if (dictStart+dictSize == dest) { + if (dictSize >= 64 KB - 1) { + return LZ4_decompress_safe_partial_withPrefix64k(source, dest, compressedSize, targetOutputSize, dstCapacity); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_withSmallPrefix(source, dest, compressedSize, targetOutputSize, dstCapacity, (size_t)dictSize); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_forceExtDict(source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, (size_t)dictSize); +} + int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) { if (dictSize==0 || dictStart+dictSize == dest) - return LZ4_decompress_fast(source, dest, originalSize); + return LZ4_decompress_unsafe_generic( + (const BYTE*)source, (BYTE*)dest, originalSize, + (size_t)dictSize, NULL, 0); assert(dictSize >= 0); return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize); } @@ -2374,7 +2696,7 @@ int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, /* Obsolete Streaming functions */ -int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } +int LZ4_sizeofStreamState(void) { return sizeof(LZ4_stream_t); } int LZ4_resetStreamState(void* state, char* inputBuffer) { @@ -2383,11 +2705,13 @@ int LZ4_resetStreamState(void* state, char* inputBuffer) return 0; } +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) void* LZ4_create (char* inputBuffer) { (void)inputBuffer; return LZ4_createStream(); } +#endif char* LZ4_slideInputBuffer (void* state) { diff --git a/native/lz4/lz4.h b/native/lz4/lz4.h index 32108e2..491c608 100644 --- a/native/lz4/lz4.h +++ b/native/lz4/lz4.h @@ -1,7 +1,7 @@ /* * LZ4 - Fast LZ compression algorithm * Header File - * Copyright (C) 2011-present, Yann Collet. + * Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -97,36 +97,77 @@ extern "C" { # define LZ4LIB_API LZ4LIB_VISIBILITY #endif +/*! LZ4_FREESTANDING : + * When this macro is set to 1, it enables "freestanding mode" that is + * suitable for typical freestanding environment which doesn't support + * standard C library. + * + * - LZ4_FREESTANDING is a compile-time switch. + * - It requires the following macros to be defined: + * LZ4_memcpy, LZ4_memmove, LZ4_memset. + * - It only enables LZ4/HC functions which don't use heap. + * All LZ4F_* functions are not supported. + * - See tests/freestanding.c to check its basic setup. + */ +#if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1) +# define LZ4_HEAPMODE 0 +# define LZ4HC_HEAPMODE 0 +# define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1 +# if !defined(LZ4_memcpy) +# error "LZ4_FREESTANDING requires macro 'LZ4_memcpy'." +# endif +# if !defined(LZ4_memset) +# error "LZ4_FREESTANDING requires macro 'LZ4_memset'." +# endif +# if !defined(LZ4_memmove) +# error "LZ4_FREESTANDING requires macro 'LZ4_memmove'." +# endif +#elif ! defined(LZ4_FREESTANDING) +# define LZ4_FREESTANDING 0 +#endif + + /*------ Version ------*/ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 2 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_RELEASE 4 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) #define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE #define LZ4_QUOTE(str) #str #define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) -#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) +#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) /* requires v1.7.3+ */ -LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version */ -LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; useful to check dll version */ +LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version; requires v1.3.0+ */ +LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; useful to check dll version; requires v1.7.5+ */ /*-************************************ * Tuning parameter **************************************/ +#define LZ4_MEMORY_USAGE_MIN 10 +#define LZ4_MEMORY_USAGE_DEFAULT 14 +#define LZ4_MEMORY_USAGE_MAX 20 + /*! * LZ4_MEMORY_USAGE : - * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) - * Increasing memory usage improves compression ratio. - * Reduced memory usage may improve speed, thanks to better cache locality. + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; ) + * Increasing memory usage improves compression ratio, at the cost of speed. + * Reduced memory usage may improve speed at the cost of ratio, thanks to better cache locality. * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ #ifndef LZ4_MEMORY_USAGE -# define LZ4_MEMORY_USAGE 14 +# define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT #endif +#if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN) +# error "LZ4_MEMORY_USAGE is too small !" +#endif + +#if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX) +# error "LZ4_MEMORY_USAGE is too large !" +#endif /*-************************************ * Simple Functions @@ -186,7 +227,8 @@ LZ4LIB_API int LZ4_compressBound(int inputSize); The larger the acceleration value, the faster the algorithm, but also the lesser the compression. It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. An acceleration value of "1" is the same as regular LZ4_compress_default() - Values <= 0 will be replaced by ACCELERATION_DEFAULT (currently == 1, see lz4.c). + Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c). + Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c). */ LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); @@ -212,7 +254,18 @@ LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* d * New value is necessarily <= input value. * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize) * or 0 if compression fails. -*/ + * + * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+): + * the produced compressed content could, in specific circumstances, + * require to be decompressed into a destination buffer larger + * by at least 1 byte than the content to decompress. + * If an application uses `LZ4_compress_destSize()`, + * it's highly recommended to update liblz4 to v1.9.2 or better. + * If this can't be done or ensured, + * the receiving decompression function should provide + * a dstCapacity which is > decompressedSize, by at least 1 byte. + * See https://github.com/lz4/lz4/issues/859 for details + */ LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize); @@ -220,25 +273,35 @@ LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePt * Decompress an LZ4 compressed block, of size 'srcSize' at position 'src', * into destination buffer 'dst' of size 'dstCapacity'. * Up to 'targetOutputSize' bytes will be decoded. - * The function stops decoding on reaching this objective, - * which can boost performance when only the beginning of a block is required. + * The function stops decoding on reaching this objective. + * This can be useful to boost performance + * whenever only the beginning of a block is required. * - * @return : the number of bytes decoded in `dst` (necessarily <= dstCapacity) + * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize) * If source stream is detected malformed, function returns a negative result. * - * Note : @return can be < targetOutputSize, if compressed block contains less data. + * Note 1 : @return can be < targetOutputSize, if compressed block contains less data. * - * Note 2 : this function features 2 parameters, targetOutputSize and dstCapacity, - * and expects targetOutputSize <= dstCapacity. - * It effectively stops decoding on reaching targetOutputSize, + * Note 2 : targetOutputSize must be <= dstCapacity + * + * Note 3 : this function effectively stops decoding on reaching targetOutputSize, * so dstCapacity is kind of redundant. - * This is because in a previous version of this function, - * decoding operation would not "break" a sequence in the middle. - * As a consequence, there was no guarantee that decoding would stop at exactly targetOutputSize, + * This is because in older versions of this function, + * decoding operation would still write complete sequences. + * Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize, * it could write more bytes, though only up to dstCapacity. * Some "margin" used to be required for this operation to work properly. - * This is no longer necessary. - * The function nonetheless keeps its signature, in an effort to not break API. + * Thankfully, this is no longer necessary. + * The function nonetheless keeps the same signature, in an effort to preserve API compatibility. + * + * Note 4 : If srcSize is the exact size of the block, + * then targetOutputSize can be any value, + * including larger than the block's decompressed size. + * The function will, at most, generate block's decompressed size. + * + * Note 5 : If srcSize is _larger_ than block's compressed size, + * then targetOutputSize **MUST** be <= block's decompressed size. + * Otherwise, *silent corruption will occur*. */ LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity); @@ -248,8 +311,25 @@ LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcS ***********************************************/ typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ +/** + Note about RC_INVOKED + + - RC_INVOKED is predefined symbol of rc.exe (the resource compiler which is part of MSVC/Visual Studio). + https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros + + - Since rc.exe is a legacy compiler, it truncates long symbol (> 30 chars) + and reports warning "RC4011: identifier truncated". + + - To eliminate the warning, we surround long preprocessor symbol with + "#if !defined(RC_INVOKED) ... #endif" block that means + "skip this block when rc.exe is trying to read it". +*/ +#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr); +#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ +#endif /*! LZ4_resetStream_fast() : v1.9.0+ * Use this to prepare an LZ4_stream_t for a new chain of dependent blocks @@ -333,8 +413,12 @@ typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */ * creation / destruction of streaming decompression tracking context. * A tracking context can be re-used multiple times. */ +#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); +#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ +#endif /*! LZ4_setStreamDecode() : * An LZ4_streamDecode_t context can be allocated once and re-used multiple times. @@ -384,7 +468,10 @@ LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize); * save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression, * then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block. */ -LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity); +LZ4LIB_API int +LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, + const char* src, char* dst, + int srcSize, int dstCapacity); /*! LZ4_decompress_*_usingDict() : @@ -395,7 +482,16 @@ LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecod * Performance tip : Decompression speed can be substantially increased * when dst == dictStart + dictSize. */ -LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize); +LZ4LIB_API int +LZ4_decompress_safe_usingDict(const char* src, char* dst, + int srcSize, int dstCapacity, + const char* dictStart, int dictSize); + +LZ4LIB_API int +LZ4_decompress_safe_partial_usingDict(const char* src, char* dst, + int compressedSize, + int targetOutputSize, int maxOutputSize, + const char* dictStart, int dictSize); #endif /* LZ4_H_2983827168210 */ @@ -474,13 +570,15 @@ LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const c * stream (and source buffer) must remain in-place / accessible / unchanged * through the completion of the first compression call on the stream. */ -LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream); +LZ4LIB_STATIC_API void +LZ4_attach_dictionary(LZ4_stream_t* workingStream, + const LZ4_stream_t* dictionaryStream); /*! In-place compression and decompression * * It's possible to have input and output sharing the same buffer, - * for highly contrained memory environments. + * for highly constrained memory environments. * In both cases, it requires input to lay at the end of the buffer, * and decompression to start at beginning of the buffer. * Buffer size must feature some margin, hence be larger than final size. @@ -547,74 +645,52 @@ LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const #define LZ4_H_98237428734687 /*-************************************************************ - * PRIVATE DEFINITIONS + * Private Definitions ************************************************************** * Do not use these definitions directly. * They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. - * Accessing members will expose code to API and/or ABI break in future versions of the library. + * Accessing members will expose user code to API and/or ABI break in future versions of the library. **************************************************************/ #define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -#include - -typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; -struct LZ4_stream_t_internal { - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint16_t dirty; - uint16_t tableType; - const uint8_t* dictionary; - const LZ4_stream_t_internal* dictCtx; - uint32_t dictSize; -}; - -typedef struct { - const uint8_t* externalDict; - size_t extDictSize; - const uint8_t* prefixEnd; - size_t prefixSize; -} LZ4_streamDecode_t_internal; - +# include + typedef int8_t LZ4_i8; + typedef uint8_t LZ4_byte; + typedef uint16_t LZ4_u16; + typedef uint32_t LZ4_u32; #else + typedef signed char LZ4_i8; + typedef unsigned char LZ4_byte; + typedef unsigned short LZ4_u16; + typedef unsigned int LZ4_u32; +#endif + +/*! LZ4_stream_t : + * Never ever use below internal definitions directly ! + * These definitions are not API/ABI safe, and may change in future versions. + * If you need static allocation, declare or allocate an LZ4_stream_t object. +**/ typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; struct LZ4_stream_t_internal { - unsigned int hashTable[LZ4_HASH_SIZE_U32]; - unsigned int currentOffset; - unsigned short dirty; - unsigned short tableType; - const unsigned char* dictionary; + LZ4_u32 hashTable[LZ4_HASH_SIZE_U32]; + const LZ4_byte* dictionary; const LZ4_stream_t_internal* dictCtx; - unsigned int dictSize; + LZ4_u32 currentOffset; + LZ4_u32 tableType; + LZ4_u32 dictSize; + /* Implicit padding to ensure structure is aligned */ }; -typedef struct { - const unsigned char* externalDict; - const unsigned char* prefixEnd; - size_t extDictSize; - size_t prefixSize; -} LZ4_streamDecode_t_internal; - -#endif - -/*! LZ4_stream_t : - * information structure to track an LZ4 stream. - * LZ4_stream_t can also be created using LZ4_createStream(), which is recommended. - * The structure definition can be convenient for static allocation - * (on stack, or as part of larger structure). - * Init this structure with LZ4_initStream() before first use. - * note : only use this definition in association with static linking ! - * this definition is not API/ABI safe, and may change in a future version. - */ -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4 + ((sizeof(void*)==16) ? 4 : 0) /*AS-400*/ ) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) +#define LZ4_STREAM_MINSIZE ((1UL << LZ4_MEMORY_USAGE) + 32) /* static size, for inter-version compatibility */ union LZ4_stream_u { - unsigned long long table[LZ4_STREAMSIZE_U64]; + char minStateSize[LZ4_STREAM_MINSIZE]; LZ4_stream_t_internal internal_donotuse; -} ; /* previously typedef'd to LZ4_stream_t */ +}; /* previously typedef'd to LZ4_stream_t */ + /*! LZ4_initStream() : v1.9.0+ * An LZ4_stream_t structure must be initialized at least once. @@ -629,21 +705,25 @@ union LZ4_stream_u { * In which case, the function will @return NULL. * Note2: An LZ4_stream_t structure guarantees correct alignment and size. * Note3: Before v1.9.0, use LZ4_resetStream() instead - */ +**/ LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size); /*! LZ4_streamDecode_t : - * information structure to track an LZ4 stream during decompression. - * init this structure using LZ4_setStreamDecode() before first use. - * note : only use in association with static linking ! - * this definition is not API/ABI safe, - * and may change in a future version ! - */ -#define LZ4_STREAMDECODESIZE_U64 (4 + ((sizeof(void*)==16) ? 2 : 0) /*AS-400*/ ) -#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) + * Never ever use below internal definitions directly ! + * These definitions are not API/ABI safe, and may change in future versions. + * If you need static allocation, declare or allocate an LZ4_streamDecode_t object. +**/ +typedef struct { + const LZ4_byte* externalDict; + const LZ4_byte* prefixEnd; + size_t extDictSize; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#define LZ4_STREAMDECODE_MINSIZE 32 union LZ4_streamDecode_u { - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + char minStateSize[LZ4_STREAMDECODE_MINSIZE]; LZ4_streamDecode_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_streamDecode_t */ @@ -667,22 +747,21 @@ union LZ4_streamDecode_u { #ifdef LZ4_DISABLE_DEPRECATE_WARNINGS # define LZ4_DEPRECATED(message) /* disable deprecation warnings */ #else -# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ # define LZ4_DEPRECATED(message) [[deprecated(message)]] -# elif (LZ4_GCC_VERSION >= 405) || defined(__clang__) -# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) -# elif (LZ4_GCC_VERSION >= 301) -# define LZ4_DEPRECATED(message) __attribute__((deprecated)) # elif defined(_MSC_VER) # define LZ4_DEPRECATED(message) __declspec(deprecated(message)) +# elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45)) +# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31) +# define LZ4_DEPRECATED(message) __attribute__((deprecated)) # else -# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") -# define LZ4_DEPRECATED(message) +# pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler") +# define LZ4_DEPRECATED(message) /* disabled */ # endif #endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ -/* Obsolete compression functions */ +/*! Obsolete compression functions (since v1.7.3) */ LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* src, char* dest, int srcSize); LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize); LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); @@ -690,11 +769,12 @@ LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_co LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); -/* Obsolete decompression functions */ +/*! Obsolete decompression functions (since v1.8.0) */ LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize); LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); -/* Obsolete streaming functions; degraded functionality; do not use! +/* Obsolete streaming functions (since v1.7.0) + * degraded functionality; do not use! * * In order to perform streaming compression, these functions depended on data * that is no longer tracked in the state. They have been preserved as well as @@ -708,23 +788,22 @@ LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStre LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer); LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state); -/* Obsolete streaming decoding functions */ +/*! Obsolete streaming decoding functions (since v1.7.0) */ LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); -/*! LZ4_decompress_fast() : **unsafe!** +/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) : * These functions used to be faster than LZ4_decompress_safe(), - * but it has changed, and they are now slower than LZ4_decompress_safe(). + * but this is no longer the case. They are now slower. * This is because LZ4_decompress_fast() doesn't know the input size, - * and therefore must progress more cautiously in the input buffer to not read beyond the end of block. + * and therefore must progress more cautiously into the input buffer to not read beyond the end of block. * On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability. * As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated. * * The last remaining LZ4_decompress_fast() specificity is that * it can decompress a block without knowing its compressed size. - * Such functionality could be achieved in a more secure manner, - * by also providing the maximum size of input buffer, - * but it would require new prototypes, and adaptation of the implementation to this new use case. + * Such functionality can be achieved in a more secure manner + * by employing LZ4_decompress_safe_partial(). * * Parameters: * originalSize : is the uncompressed size to regenerate. @@ -739,7 +818,6 @@ LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4 * But they may happen if input data is invalid (error or intentional tampering). * As a consequence, use these functions in trusted environments with trusted data **only**. */ - LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize); LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead") diff --git a/native/lz4/lz4file.c b/native/lz4/lz4file.c new file mode 100644 index 0000000..eaf9b17 --- /dev/null +++ b/native/lz4/lz4file.c @@ -0,0 +1,311 @@ +/* + * LZ4 file library + * Copyright (C) 2022, Xiaomi Inc. + * + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://www.lz4.org + * - LZ4 source repository : https://github.com/lz4/lz4 + */ +#include +#include +#include "lz4.h" +#include "lz4file.h" + +struct LZ4_readFile_s { + LZ4F_dctx* dctxPtr; + FILE* fp; + LZ4_byte* srcBuf; + size_t srcBufNext; + size_t srcBufSize; + size_t srcBufMaxSize; +}; + +struct LZ4_writeFile_s { + LZ4F_cctx* cctxPtr; + FILE* fp; + LZ4_byte* dstBuf; + size_t maxWriteSize; + size_t dstBufMaxSize; + LZ4F_errorCode_t errCode; +}; + +LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp) +{ + char buf[LZ4F_HEADER_SIZE_MAX]; + size_t consumedSize; + LZ4F_errorCode_t ret; + LZ4F_frameInfo_t info; + + if (fp == NULL || lz4fRead == NULL) { + return -LZ4F_ERROR_GENERIC; + } + + *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t)); + if (*lz4fRead == NULL) { + return -LZ4F_ERROR_allocation_failed; + } + + ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_getVersion()); + if (LZ4F_isError(ret)) { + free(*lz4fRead); + return ret; + } + + (*lz4fRead)->fp = fp; + consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp); + if (consumedSize != sizeof(buf)) { + free(*lz4fRead); + return -LZ4F_ERROR_GENERIC; + } + + ret = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize); + if (LZ4F_isError(ret)) { + LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); + free(*lz4fRead); + return ret; + } + + switch (info.blockSizeID) { + case LZ4F_default : + case LZ4F_max64KB : + (*lz4fRead)->srcBufMaxSize = 64 * 1024; + break; + case LZ4F_max256KB: + (*lz4fRead)->srcBufMaxSize = 256 * 1024; + break; + case LZ4F_max1MB: + (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024; + break; + case LZ4F_max4MB: + (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024; + break; + default: + LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); + free(*lz4fRead); + return -LZ4F_ERROR_maxBlockSize_invalid; + } + + (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize); + if ((*lz4fRead)->srcBuf == NULL) { + LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); + free(lz4fRead); + return -LZ4F_ERROR_allocation_failed; + } + + (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize; + memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize); + + return ret; +} + +size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size) +{ + LZ4_byte* p = (LZ4_byte*)buf; + size_t next = 0; + + if (lz4fRead == NULL || buf == NULL) + return -LZ4F_ERROR_GENERIC; + + while (next < size) { + size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext; + size_t dstsize = size - next; + size_t ret; + + if (srcsize == 0) { + ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp); + if (ret > 0) { + lz4fRead->srcBufSize = ret; + srcsize = lz4fRead->srcBufSize; + lz4fRead->srcBufNext = 0; + } + else if (ret == 0) { + break; + } + else { + return -LZ4F_ERROR_GENERIC; + } + } + + ret = LZ4F_decompress(lz4fRead->dctxPtr, + p, &dstsize, + lz4fRead->srcBuf + lz4fRead->srcBufNext, + &srcsize, + NULL); + if (LZ4F_isError(ret)) { + return ret; + } + + lz4fRead->srcBufNext += srcsize; + next += dstsize; + p += dstsize; + } + + return next; +} + +LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead) +{ + if (lz4fRead == NULL) + return -LZ4F_ERROR_GENERIC; + LZ4F_freeDecompressionContext(lz4fRead->dctxPtr); + free(lz4fRead->srcBuf); + free(lz4fRead); + return LZ4F_OK_NoError; +} + +LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr) +{ + LZ4_byte buf[LZ4F_HEADER_SIZE_MAX]; + size_t ret; + + if (fp == NULL || lz4fWrite == NULL) + return -LZ4F_ERROR_GENERIC; + + *lz4fWrite = (LZ4_writeFile_t*)malloc(sizeof(LZ4_writeFile_t)); + if (*lz4fWrite == NULL) { + return -LZ4F_ERROR_allocation_failed; + } + if (prefsPtr != NULL) { + switch (prefsPtr->frameInfo.blockSizeID) { + case LZ4F_default : + case LZ4F_max64KB : + (*lz4fWrite)->maxWriteSize = 64 * 1024; + break; + case LZ4F_max256KB: + (*lz4fWrite)->maxWriteSize = 256 * 1024; + break; + case LZ4F_max1MB: + (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024; + break; + case LZ4F_max4MB: + (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024; + break; + default: + free(lz4fWrite); + return -LZ4F_ERROR_maxBlockSize_invalid; + } + } else { + (*lz4fWrite)->maxWriteSize = 64 * 1024; + } + + (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr); + (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize); + if ((*lz4fWrite)->dstBuf == NULL) { + free(*lz4fWrite); + return -LZ4F_ERROR_allocation_failed; + } + + ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_getVersion()); + if (LZ4F_isError(ret)) { + free((*lz4fWrite)->dstBuf); + free(*lz4fWrite); + return ret; + } + + ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr); + if (LZ4F_isError(ret)) { + LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr); + free((*lz4fWrite)->dstBuf); + free(*lz4fWrite); + return ret; + } + + if (ret != fwrite(buf, 1, ret, fp)) { + LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr); + free((*lz4fWrite)->dstBuf); + free(*lz4fWrite); + return -LZ4F_ERROR_GENERIC; + } + + (*lz4fWrite)->fp = fp; + (*lz4fWrite)->errCode = LZ4F_OK_NoError; + return LZ4F_OK_NoError; +} + +size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size) +{ + LZ4_byte* p = (LZ4_byte*)buf; + size_t remain = size; + size_t chunk; + size_t ret; + + if (lz4fWrite == NULL || buf == NULL) + return -LZ4F_ERROR_GENERIC; + while (remain) { + if (remain > lz4fWrite->maxWriteSize) + chunk = lz4fWrite->maxWriteSize; + else + chunk = remain; + + ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr, + lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize, + p, chunk, + NULL); + if (LZ4F_isError(ret)) { + lz4fWrite->errCode = ret; + return ret; + } + + if(ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) { + lz4fWrite->errCode = -LZ4F_ERROR_GENERIC; + return -LZ4F_ERROR_GENERIC; + } + + p += chunk; + remain -= chunk; + } + + return size; +} + +LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite) +{ + LZ4F_errorCode_t ret = LZ4F_OK_NoError; + + if (lz4fWrite == NULL) + return -LZ4F_ERROR_GENERIC; + + if (lz4fWrite->errCode == LZ4F_OK_NoError) { + ret = LZ4F_compressEnd(lz4fWrite->cctxPtr, + lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize, + NULL); + if (LZ4F_isError(ret)) { + goto out; + } + + if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) { + ret = -LZ4F_ERROR_GENERIC; + } + } + +out: + LZ4F_freeCompressionContext(lz4fWrite->cctxPtr); + free(lz4fWrite->dstBuf); + free(lz4fWrite); + return ret; +} diff --git a/native/lz4/lz4file.h b/native/lz4/lz4file.h new file mode 100644 index 0000000..5527130 --- /dev/null +++ b/native/lz4/lz4file.h @@ -0,0 +1,93 @@ +/* + LZ4 file library + Header File + Copyright (C) 2022, Xiaomi Inc. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef LZ4FILE_H +#define LZ4FILE_H + +#include +#include "lz4frame_static.h" + +typedef struct LZ4_readFile_s LZ4_readFile_t; +typedef struct LZ4_writeFile_s LZ4_writeFile_t; + +/*! LZ4F_readOpen() : + * Set read lz4file handle. + * `lz4f` will set a lz4file handle. + * `fp` must be the return value of the lz4 file opened by fopen. + */ +LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp); + +/*! LZ4F_read() : + * Read lz4file content to buffer. + * `lz4f` must use LZ4_readOpen to set first. + * `buf` read data buffer. + * `size` read data buffer size. + */ +LZ4FLIB_STATIC_API size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size); + +/*! LZ4F_readClose() : + * Close lz4file handle. + * `lz4f` must use LZ4_readOpen to set first. + */ +LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead); + +/*! LZ4F_writeOpen() : + * Set write lz4file handle. + * `lz4f` will set a lz4file handle. + * `fp` must be the return value of the lz4 file opened by fopen. + */ +LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr); + +/*! LZ4F_write() : + * Write buffer to lz4file. + * `lz4f` must use LZ4F_writeOpen to set first. + * `buf` write data buffer. + * `size` write data buffer size. + */ +LZ4FLIB_STATIC_API size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size); + +/*! LZ4F_writeClose() : + * Close lz4file handle. + * `lz4f` must use LZ4F_writeOpen to set first. + */ +LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite); + +#endif /* LZ4FILE_H */ + +#if defined (__cplusplus) +} +#endif diff --git a/native/lz4/lz4frame.c b/native/lz4/lz4frame.c index c9f630d..174f9ae 100644 --- a/native/lz4/lz4frame.c +++ b/native/lz4/lz4frame.c @@ -45,7 +45,7 @@ * Compiler Options **************************************/ #ifdef _MSC_VER /* Visual Studio */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #endif @@ -62,6 +62,19 @@ #endif +/*-************************************ +* Library declarations +**************************************/ +#define LZ4F_STATIC_LINKING_ONLY +#include "lz4frame.h" +#define LZ4_STATIC_LINKING_ONLY +#include "lz4.h" +#define LZ4_HC_STATIC_LINKING_ONLY +#include "lz4hc.h" +#define XXH_STATIC_LINKING_ONLY +#include "xxhash.h" + + /*-************************************ * Memory routines **************************************/ @@ -70,31 +83,56 @@ * malloc(), calloc() and free() * towards another library or solution of their choice * by modifying below section. - */ -#include /* malloc, calloc, free */ +**/ + +#include /* memset, memcpy, memmove */ +#ifndef LZ4_SRC_INCLUDED /* avoid redefinition when sources are coalesced */ +# define MEM_INIT(p,v,s) memset((p),(v),(s)) +#endif + #ifndef LZ4_SRC_INCLUDED /* avoid redefinition when sources are coalesced */ +# include /* malloc, calloc, free */ # define ALLOC(s) malloc(s) # define ALLOC_AND_ZERO(s) calloc(1,(s)) # define FREEMEM(p) free(p) #endif -#include /* memset, memcpy, memmove */ -#ifndef LZ4_SRC_INCLUDED /* avoid redefinition when sources are coalesced */ -# define MEM_INIT(p,v,s) memset((p),(v),(s)) -#endif +static void* LZ4F_calloc(size_t s, LZ4F_CustomMem cmem) +{ + /* custom calloc defined : use it */ + if (cmem.customCalloc != NULL) { + return cmem.customCalloc(cmem.opaqueState, s); + } + /* nothing defined : use default 's calloc() */ + if (cmem.customAlloc == NULL) { + return ALLOC_AND_ZERO(s); + } + /* only custom alloc defined : use it, and combine it with memset() */ + { void* const p = cmem.customAlloc(cmem.opaqueState, s); + if (p != NULL) MEM_INIT(p, 0, s); + return p; +} } +static void* LZ4F_malloc(size_t s, LZ4F_CustomMem cmem) +{ + /* custom malloc defined : use it */ + if (cmem.customAlloc != NULL) { + return cmem.customAlloc(cmem.opaqueState, s); + } + /* nothing defined : use default 's malloc() */ + return ALLOC(s); +} -/*-************************************ -* Library declarations -**************************************/ -#define LZ4F_STATIC_LINKING_ONLY -#include "lz4frame.h" -#define LZ4_STATIC_LINKING_ONLY -#include "lz4.h" -#define LZ4_HC_STATIC_LINKING_ONLY -#include "lz4hc.h" -#define XXH_STATIC_LINKING_ONLY -#include "xxhash.h" +static void LZ4F_free(void* p, LZ4F_CustomMem cmem) +{ + /* custom malloc defined : use it */ + if (cmem.customFree != NULL) { + cmem.customFree(cmem.opaqueState, p); + return; + } + /* nothing defined : use default 's free() */ + FREEMEM(p); +} /*-************************************ @@ -143,7 +181,7 @@ static int g_debuglog_enable = 1; #endif -/* unoptimized version; solves endianess & alignment issues */ +/* unoptimized version; solves endianness & alignment issues */ static U32 LZ4F_readLE32 (const void* src) { const BYTE* const srcPtr = (const BYTE*)src; @@ -206,8 +244,6 @@ static void LZ4F_writeLE64 (void* dst, U64 value64) #define _4BITS 0x0F #define _8BITS 0xFF -#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U -#define LZ4F_MAGICNUMBER 0x184D2204U #define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U #define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB @@ -220,22 +256,27 @@ static const size_t BFSize = LZ4F_BLOCK_CHECKSUM_SIZE; /* block footer : checks /*-************************************ * Structures and local types **************************************/ + +typedef enum { LZ4B_COMPRESSED, LZ4B_UNCOMPRESSED} LZ4F_blockCompression_t; + typedef struct LZ4F_cctx_s { + LZ4F_CustomMem cmem; LZ4F_preferences_t prefs; U32 version; U32 cStage; const LZ4F_CDict* cdict; size_t maxBlockSize; size_t maxBufferSize; - BYTE* tmpBuff; - BYTE* tmpIn; - size_t tmpInSize; + BYTE* tmpBuff; /* internal buffer, for streaming */ + BYTE* tmpIn; /* starting position of data compress within internal buffer (>= tmpBuff) */ + size_t tmpInSize; /* amount of data to compress after tmpIn */ U64 totalInSize; XXH32_state_t xxh; void* lz4CtxPtr; U16 lz4CtxAlloc; /* sized for: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */ U16 lz4CtxState; /* in use as: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */ + LZ4F_blockCompression_t blockCompression; } LZ4F_cctx_t; @@ -264,27 +305,33 @@ LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult) return (LZ4F_errorCodes)(-(ptrdiff_t)functionResult); } -static LZ4F_errorCode_t err0r(LZ4F_errorCodes code) +static LZ4F_errorCode_t LZ4F_returnErrorCode(LZ4F_errorCodes code) { /* A compilation error here means sizeof(ptrdiff_t) is not large enough */ LZ4F_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t)); return (LZ4F_errorCode_t)-(ptrdiff_t)code; } +#define RETURN_ERROR(e) return LZ4F_returnErrorCode(LZ4F_ERROR_ ## e) + +#define RETURN_ERROR_IF(c,e) if (c) RETURN_ERROR(e) + +#define FORWARD_IF_ERROR(r) if (LZ4F_isError(r)) return (r) + unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; } int LZ4F_compressionLevel_max(void) { return LZ4HC_CLEVEL_MAX; } -size_t LZ4F_getBlockSize(unsigned blockSizeID) +size_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID) { static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB }; if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT; if (blockSizeID < LZ4F_max64KB || blockSizeID > LZ4F_max4MB) - return err0r(LZ4F_ERROR_maxBlockSize_invalid); - blockSizeID -= LZ4F_max64KB; - return blockSizes[blockSizeID]; -} + RETURN_ERROR(maxBlockSize_invalid); + { int const blockSizeIdx = (int)blockSizeID - (int)LZ4F_max64KB; + return blockSizes[blockSizeIdx]; +} } /*-************************************ * Private functions @@ -397,21 +444,20 @@ size_t LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx, MEM_INIT(&options, 0, sizeof(options)); options.stableSrc = 1; - if (dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs)) /* condition to guarantee success */ - return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); + RETURN_ERROR_IF(dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs), dstMaxSize_tooSmall); { size_t const headerSize = LZ4F_compressBegin_usingCDict(cctx, dstBuffer, dstCapacity, cdict, &prefs); /* write header */ - if (LZ4F_isError(headerSize)) return headerSize; + FORWARD_IF_ERROR(headerSize); dstPtr += headerSize; /* header size */ } assert(dstEnd >= dstPtr); { size_t const cSize = LZ4F_compressUpdate(cctx, dstPtr, (size_t)(dstEnd-dstPtr), srcBuffer, srcSize, &options); - if (LZ4F_isError(cSize)) return cSize; + FORWARD_IF_ERROR(cSize); dstPtr += cSize; } assert(dstEnd >= dstPtr); { size_t const tailSize = LZ4F_compressEnd(cctx, dstPtr, (size_t)(dstEnd-dstPtr), &options); /* flush last block, and generate suffix */ - if (LZ4F_isError(tailSize)) return tailSize; + FORWARD_IF_ERROR(tailSize); dstPtr += tailSize; } assert(dstEnd >= dstStart); @@ -432,27 +478,26 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, { size_t result; #if (LZ4F_HEAPMODE) - LZ4F_cctx_t *cctxPtr; + LZ4F_cctx_t* cctxPtr; result = LZ4F_createCompressionContext(&cctxPtr, LZ4F_VERSION); - if (LZ4F_isError(result)) return result; + FORWARD_IF_ERROR(result); #else LZ4F_cctx_t cctx; LZ4_stream_t lz4ctx; - LZ4F_cctx_t *cctxPtr = &cctx; + LZ4F_cctx_t* const cctxPtr = &cctx; - DEBUGLOG(4, "LZ4F_compressFrame"); MEM_INIT(&cctx, 0, sizeof(cctx)); cctx.version = LZ4F_VERSION; cctx.maxBufferSize = 5 MB; /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */ - if (preferencesPtr == NULL || - preferencesPtr->compressionLevel < LZ4HC_CLEVEL_MIN) - { + if ( preferencesPtr == NULL + || preferencesPtr->compressionLevel < LZ4HC_CLEVEL_MIN ) { LZ4_initStream(&lz4ctx, sizeof(lz4ctx)); cctxPtr->lz4CtxPtr = &lz4ctx; cctxPtr->lz4CtxAlloc = 1; cctxPtr->lz4CtxState = 1; } #endif + DEBUGLOG(4, "LZ4F_compressFrame"); result = LZ4F_compressFrame_usingCDict(cctxPtr, dstBuffer, dstCapacity, srcBuffer, srcSize, @@ -461,10 +506,9 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, #if (LZ4F_HEAPMODE) LZ4F_freeCompressionContext(cctxPtr); #else - if (preferencesPtr != NULL && - preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN) - { - FREEMEM(cctxPtr->lz4CtxPtr); + if ( preferencesPtr != NULL + && preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN ) { + LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem); } #endif return result; @@ -476,30 +520,31 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, *****************************************************/ struct LZ4F_CDict_s { + LZ4F_CustomMem cmem; void* dictContent; LZ4_stream_t* fastCtx; LZ4_streamHC_t* HCCtx; }; /* typedef'd to LZ4F_CDict within lz4frame_static.h */ -/*! LZ4F_createCDict() : - * When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once. - * LZ4F_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay. - * LZ4F_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. - * `dictBuffer` can be released after LZ4F_CDict creation, since its content is copied within CDict - * @return : digested dictionary for compression, or NULL if failed */ -LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize) +LZ4F_CDict* +LZ4F_createCDict_advanced(LZ4F_CustomMem cmem, const void* dictBuffer, size_t dictSize) { const char* dictStart = (const char*)dictBuffer; - LZ4F_CDict* cdict = (LZ4F_CDict*) ALLOC(sizeof(*cdict)); - DEBUGLOG(4, "LZ4F_createCDict"); + LZ4F_CDict* const cdict = (LZ4F_CDict*)LZ4F_malloc(sizeof(*cdict), cmem); + DEBUGLOG(4, "LZ4F_createCDict_advanced"); if (!cdict) return NULL; + cdict->cmem = cmem; if (dictSize > 64 KB) { dictStart += dictSize - 64 KB; dictSize = 64 KB; } - cdict->dictContent = ALLOC(dictSize); - cdict->fastCtx = LZ4_createStream(); - cdict->HCCtx = LZ4_createStreamHC(); + cdict->dictContent = LZ4F_malloc(dictSize, cmem); + cdict->fastCtx = (LZ4_stream_t*)LZ4F_malloc(sizeof(LZ4_stream_t), cmem); + if (cdict->fastCtx) + LZ4_initStream(cdict->fastCtx, sizeof(LZ4_stream_t)); + cdict->HCCtx = (LZ4_streamHC_t*)LZ4F_malloc(sizeof(LZ4_streamHC_t), cmem); + if (cdict->HCCtx) + LZ4_initStream(cdict->HCCtx, sizeof(LZ4_streamHC_t)); if (!cdict->dictContent || !cdict->fastCtx || !cdict->HCCtx) { LZ4F_freeCDict(cdict); return NULL; @@ -511,13 +556,25 @@ LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize) return cdict; } +/*! LZ4F_createCDict() : + * When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once. + * LZ4F_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay. + * LZ4F_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. + * @dictBuffer can be released after LZ4F_CDict creation, since its content is copied within CDict + * @return : digested dictionary for compression, or NULL if failed */ +LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize) +{ + DEBUGLOG(4, "LZ4F_createCDict"); + return LZ4F_createCDict_advanced(LZ4F_defaultCMem, dictBuffer, dictSize); +} + void LZ4F_freeCDict(LZ4F_CDict* cdict) { if (cdict==NULL) return; /* support free on NULL */ - FREEMEM(cdict->dictContent); - LZ4_freeStream(cdict->fastCtx); - LZ4_freeStreamHC(cdict->HCCtx); - FREEMEM(cdict); + LZ4F_free(cdict->dictContent, cdict->cmem); + LZ4F_free(cdict->fastCtx, cdict->cmem); + LZ4F_free(cdict->HCCtx, cdict->cmem); + LZ4F_free(cdict, cdict->cmem); } @@ -525,6 +582,20 @@ void LZ4F_freeCDict(LZ4F_CDict* cdict) * Advanced compression functions ***********************************/ +LZ4F_cctx* +LZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version) +{ + LZ4F_cctx* const cctxPtr = + (LZ4F_cctx*)LZ4F_calloc(sizeof(LZ4F_cctx), customMem); + if (cctxPtr==NULL) return NULL; + + cctxPtr->cmem = customMem; + cctxPtr->version = version; + cctxPtr->cStage = 0; /* Uninitialized. Next stage : init cctx */ + + return cctxPtr; +} + /*! LZ4F_createCompressionContext() : * The first thing to do is to create a compressionContext object, which will be used in all compression operations. * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure. @@ -532,31 +603,27 @@ void LZ4F_freeCDict(LZ4F_CDict* cdict) * The function will provide a pointer to an allocated LZ4F_compressionContext_t object. * If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation. * Object can release its memory using LZ4F_freeCompressionContext(); - */ -LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version) +**/ +LZ4F_errorCode_t +LZ4F_createCompressionContext(LZ4F_cctx** LZ4F_compressionContextPtr, unsigned version) { - LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOC_AND_ZERO(sizeof(LZ4F_cctx_t)); - if (cctxPtr==NULL) return err0r(LZ4F_ERROR_allocation_failed); - - cctxPtr->version = version; - cctxPtr->cStage = 0; /* Next stage : init stream */ - - *LZ4F_compressionContextPtr = (LZ4F_compressionContext_t)cctxPtr; + assert(LZ4F_compressionContextPtr != NULL); /* considered a violation of narrow contract */ + /* in case it nonetheless happen in production */ + RETURN_ERROR_IF(LZ4F_compressionContextPtr == NULL, parameter_null); + *LZ4F_compressionContextPtr = LZ4F_createCompressionContext_advanced(LZ4F_defaultCMem, version); + RETURN_ERROR_IF(*LZ4F_compressionContextPtr==NULL, allocation_failed); return LZ4F_OK_NoError; } -LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext) +LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctxPtr) { - LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)LZ4F_compressionContext; - if (cctxPtr != NULL) { /* support free on NULL */ - FREEMEM(cctxPtr->lz4CtxPtr); /* works because LZ4_streamHC_t and LZ4_stream_t are simple POD types */ - FREEMEM(cctxPtr->tmpBuff); - FREEMEM(LZ4F_compressionContext); + LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem); /* note: LZ4_streamHC_t and LZ4_stream_t are simple POD types */ + LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem); + LZ4F_free(cctxPtr, cctxPtr->cmem); } - return LZ4F_OK_NoError; } @@ -590,11 +657,21 @@ static void LZ4F_initStream(void* ctx, } } +static int ctxTypeID_to_size(int ctxTypeID) { + switch(ctxTypeID) { + case 1: + return LZ4_sizeofState(); + case 2: + return LZ4_sizeofStateHC(); + default: + return 0; + } +} /*! LZ4F_compressBegin_usingCDict() : - * init streaming compression and writes frame header into dstBuffer. - * dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes. - * @return : number of bytes written into dstBuffer for the header + * init streaming compression AND writes frame header into @dstBuffer. + * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes. + * @return : number of bytes written into @dstBuffer for the header * or an error code (can be tested using LZ4F_isError()) */ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr, @@ -602,41 +679,46 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr, const LZ4F_CDict* cdict, const LZ4F_preferences_t* preferencesPtr) { - LZ4F_preferences_t prefNull; + LZ4F_preferences_t const prefNull = LZ4F_INIT_PREFERENCES; BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; - BYTE* headerStart; - if (dstCapacity < maxFHSize) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); - MEM_INIT(&prefNull, 0, sizeof(prefNull)); + RETURN_ERROR_IF(dstCapacity < maxFHSize, dstMaxSize_tooSmall); if (preferencesPtr == NULL) preferencesPtr = &prefNull; cctxPtr->prefs = *preferencesPtr; - /* Ctx Management */ + /* cctx Management */ { U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2; - if (cctxPtr->lz4CtxAlloc < ctxTypeID) { - FREEMEM(cctxPtr->lz4CtxPtr); + int requiredSize = ctxTypeID_to_size(ctxTypeID); + int allocatedSize = ctxTypeID_to_size(cctxPtr->lz4CtxAlloc); + if (allocatedSize < requiredSize) { + /* not enough space allocated */ + LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem); if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) { - cctxPtr->lz4CtxPtr = LZ4_createStream(); + /* must take ownership of memory allocation, + * in order to respect custom allocator contract */ + cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_stream_t), cctxPtr->cmem); + if (cctxPtr->lz4CtxPtr) + LZ4_initStream(cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t)); } else { - cctxPtr->lz4CtxPtr = LZ4_createStreamHC(); + cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_streamHC_t), cctxPtr->cmem); + if (cctxPtr->lz4CtxPtr) + LZ4_initStreamHC(cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t)); } - if (cctxPtr->lz4CtxPtr == NULL) - return err0r(LZ4F_ERROR_allocation_failed); + RETURN_ERROR_IF(cctxPtr->lz4CtxPtr == NULL, allocation_failed); cctxPtr->lz4CtxAlloc = ctxTypeID; cctxPtr->lz4CtxState = ctxTypeID; } else if (cctxPtr->lz4CtxState != ctxTypeID) { - /* otherwise, a sufficient buffer is allocated, but we need to - * reset it to the correct context type */ + /* otherwise, a sufficient buffer is already allocated, + * but we need to reset it to the correct context type */ if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) { - LZ4_initStream((LZ4_stream_t *) cctxPtr->lz4CtxPtr, sizeof (LZ4_stream_t)); + LZ4_initStream((LZ4_stream_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t)); } else { - LZ4_initStreamHC((LZ4_streamHC_t *) cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t)); - LZ4_setCompressionLevel((LZ4_streamHC_t *) cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel); + LZ4_initStreamHC((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t)); + LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel); } cctxPtr->lz4CtxState = ctxTypeID; - } - } + } } /* Buffer Management */ if (cctxPtr->prefs.frameInfo.blockSizeID == 0) @@ -649,9 +731,9 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr, if (cctxPtr->maxBufferSize < requiredBuffSize) { cctxPtr->maxBufferSize = 0; - FREEMEM(cctxPtr->tmpBuff); - cctxPtr->tmpBuff = (BYTE*)ALLOC_AND_ZERO(requiredBuffSize); - if (cctxPtr->tmpBuff == NULL) return err0r(LZ4F_ERROR_allocation_failed); + LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem); + cctxPtr->tmpBuff = (BYTE*)LZ4F_calloc(requiredBuffSize, cctxPtr->cmem); + RETURN_ERROR_IF(cctxPtr->tmpBuff == NULL, allocation_failed); cctxPtr->maxBufferSize = requiredBuffSize; } } cctxPtr->tmpIn = cctxPtr->tmpBuff; @@ -671,31 +753,32 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr, /* Magic Number */ LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER); dstPtr += 4; - headerStart = dstPtr; - - /* FLG Byte */ - *dstPtr++ = (BYTE)(((1 & _2BITS) << 6) /* Version('01') */ - + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5) - + ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4) - + ((unsigned)(cctxPtr->prefs.frameInfo.contentSize > 0) << 3) - + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2) - + (cctxPtr->prefs.frameInfo.dictID > 0) ); - /* BD Byte */ - *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4); - /* Optional Frame content size field */ - if (cctxPtr->prefs.frameInfo.contentSize) { - LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize); - dstPtr += 8; - cctxPtr->totalInSize = 0; - } - /* Optional dictionary ID field */ - if (cctxPtr->prefs.frameInfo.dictID) { - LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID); - dstPtr += 4; + { BYTE* const headerStart = dstPtr; + + /* FLG Byte */ + *dstPtr++ = (BYTE)(((1 & _2BITS) << 6) /* Version('01') */ + + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5) + + ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4) + + ((unsigned)(cctxPtr->prefs.frameInfo.contentSize > 0) << 3) + + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2) + + (cctxPtr->prefs.frameInfo.dictID > 0) ); + /* BD Byte */ + *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4); + /* Optional Frame content size field */ + if (cctxPtr->prefs.frameInfo.contentSize) { + LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize); + dstPtr += 8; + cctxPtr->totalInSize = 0; + } + /* Optional dictionary ID field */ + if (cctxPtr->prefs.frameInfo.dictID) { + LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID); + dstPtr += 4; + } + /* Header CRC Byte */ + *dstPtr = LZ4F_headerChecksum(headerStart, (size_t)(dstPtr - headerStart)); + dstPtr++; } - /* Header CRC Byte */ - *dstPtr = LZ4F_headerChecksum(headerStart, (size_t)(dstPtr - headerStart)); - dstPtr++; cctxPtr->cStage = 1; /* header written, now request input data block */ return (size_t)(dstPtr - dstStart); @@ -703,9 +786,9 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr, /*! LZ4F_compressBegin() : - * init streaming compression and writes frame header into dstBuffer. - * dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes. - * preferencesPtr can be NULL, in which case default parameters are selected. + * init streaming compression AND writes frame header into @dstBuffer. + * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes. + * @preferencesPtr can be NULL, in which case default parameters are selected. * @return : number of bytes written into dstBuffer for the header * or an error code (can be tested using LZ4F_isError()) */ @@ -725,6 +808,9 @@ size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, */ size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr) { + if (preferencesPtr && preferencesPtr->autoFlush) { + return LZ4F_compressBound_internal(srcSize, preferencesPtr, 0); + } return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1); } @@ -743,10 +829,13 @@ static size_t LZ4F_makeBlock(void* dst, LZ4F_blockChecksum_t crcFlag) { BYTE* const cSizePtr = (BYTE*)dst; - U32 cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize), - (int)(srcSize), (int)(srcSize-1), - level, cdict); - if (cSize == 0) { /* compression failed */ + U32 cSize; + assert(compress != NULL); + cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize), + (int)(srcSize), (int)(srcSize-1), + level, cdict); + + if (cSize == 0 || cSize >= srcSize) { cSize = (U32)srcSize; LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG); memcpy(cSizePtr+BHSize, src, srcSize); @@ -764,6 +853,7 @@ static size_t LZ4F_makeBlock(void* dst, static int LZ4F_compressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) { int const acceleration = (level < 0) ? -level + 1 : 1; + DEBUGLOG(5, "LZ4F_compressBlock (srcSize=%i)", srcSize); LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent); if (cdict) { return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration); @@ -776,6 +866,7 @@ static int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, in { int const acceleration = (level < 0) ? -level + 1 : 1; (void)cdict; /* init once at beginning of frame */ + DEBUGLOG(5, "LZ4F_compressBlock_continue (srcSize=%i)", srcSize); return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration); } @@ -794,8 +885,15 @@ static int LZ4F_compressBlockHC_continue(void* ctx, const char* src, char* dst, return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity); } -static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level) +static int LZ4F_doNotCompressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) +{ + (void)ctx; (void)src; (void)dst; (void)srcSize; (void)dstCapacity; (void)level; (void)cdict; + return 0; +} + +static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level, LZ4F_blockCompression_t compressMode) { + if (compressMode == LZ4B_UNCOMPRESSED) return LZ4F_doNotCompressBlock; if (level < LZ4HC_CLEVEL_MIN) { if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlock; return LZ4F_compressBlock_continue; @@ -804,6 +902,7 @@ static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int lev return LZ4F_compressBlockHC_continue; } +/* Save history (up to 64KB) into @tmpBuff */ static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr) { if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) @@ -813,38 +912,57 @@ static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr) typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus; -/*! LZ4F_compressUpdate() : +static const LZ4F_compressOptions_t k_cOptionsNull = { 0, { 0, 0, 0 } }; + + + /*! LZ4F_compressUpdateImpl() : * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. - * dstBuffer MUST be >= LZ4F_compressBound(srcSize, preferencesPtr). - * LZ4F_compressOptions_t structure is optional : you can provide NULL as argument. + * When successful, the function always entirely consumes @srcBuffer. + * src data is either buffered or compressed into @dstBuffer. + * If the block compression does not match the compression of the previous block, the old data is flushed + * and operations continue with the new compression mode. + * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr) when block compression is turned on. + * @compressOptionsPtr is optional : provide NULL to mean "default". * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. * or an error code if it fails (which can be tested using LZ4F_isError()) + * After an error, the state is left in a UB state, and must be re-initialized. */ -size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, - void* dstBuffer, size_t dstCapacity, +static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr, + void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, - const LZ4F_compressOptions_t* compressOptionsPtr) -{ - LZ4F_compressOptions_t cOptionsNull; + const LZ4F_compressOptions_t* compressOptionsPtr, + LZ4F_blockCompression_t blockCompression) + { size_t const blockSize = cctxPtr->maxBlockSize; const BYTE* srcPtr = (const BYTE*)srcBuffer; const BYTE* const srcEnd = srcPtr + srcSize; BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; LZ4F_lastBlockStatus lastBlockCompressed = notDone; - compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel); - + compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, blockCompression); + size_t bytesWritten; DEBUGLOG(4, "LZ4F_compressUpdate (srcSize=%zu)", srcSize); - if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC); + RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized); /* state must be initialized and waiting for next block */ if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize)) - return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); - MEM_INIT(&cOptionsNull, 0, sizeof(cOptionsNull)); - if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull; + RETURN_ERROR(dstMaxSize_tooSmall); + + if (blockCompression == LZ4B_UNCOMPRESSED && dstCapacity < srcSize) + RETURN_ERROR(dstMaxSize_tooSmall); + + /* flush currently written block, to continue with new block compression */ + if (cctxPtr->blockCompression != blockCompression) { + bytesWritten = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr); + dstPtr += bytesWritten; + cctxPtr->blockCompression = blockCompression; + } + + if (compressOptionsPtr == NULL) compressOptionsPtr = &k_cOptionsNull; /* complete tmp buffer */ if (cctxPtr->tmpInSize > 0) { /* some data already within tmp buffer */ size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize; + assert(blockSize > cctxPtr->tmpInSize); if (sizeToCopy > srcSize) { /* add src to tmpIn buffer */ memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize); @@ -862,11 +980,9 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); - if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize; cctxPtr->tmpInSize = 0; - } - } + } } while ((size_t)(srcEnd - srcPtr) >= blockSize) { /* compress full blocks */ @@ -880,33 +996,38 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, } if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) { - /* compress remaining input < blockSize */ + /* autoFlush : remaining input (< blockSize) is compressed */ lastBlockCompressed = fromSrcBuffer; dstPtr += LZ4F_makeBlock(dstPtr, srcPtr, (size_t)(srcEnd - srcPtr), compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); - srcPtr = srcEnd; + srcPtr = srcEnd; } - /* preserve dictionary if necessary */ + /* preserve dictionary within @tmpBuff whenever necessary */ if ((cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) && (lastBlockCompressed==fromSrcBuffer)) { + /* linked blocks are only supported in compressed mode, see LZ4F_uncompressedUpdate */ + assert(blockCompression == LZ4B_COMPRESSED); if (compressOptionsPtr->stableSrc) { - cctxPtr->tmpIn = cctxPtr->tmpBuff; + cctxPtr->tmpIn = cctxPtr->tmpBuff; /* src is stable : dictionary remains in src across invocations */ } else { int const realDictSize = LZ4F_localSaveDict(cctxPtr); - if (realDictSize==0) return err0r(LZ4F_ERROR_GENERIC); + assert(0 <= realDictSize && realDictSize <= 64 KB); cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; } } /* keep tmpIn within limits */ - if ((cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) /* necessarily LZ4F_blockLinked && lastBlockCompressed==fromTmpBuffer */ - && !(cctxPtr->prefs.autoFlush)) + if (!(cctxPtr->prefs.autoFlush) /* no autoflush : there may be some data left within internal buffer */ + && (cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) ) /* not enough room to store next block */ { + /* only preserve 64KB within internal buffer. Ensures there is enough room for next block. + * note: this situation necessarily implies lastBlockCompressed==fromTmpBuffer */ int const realDictSize = LZ4F_localSaveDict(cctxPtr); cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; + assert((cctxPtr->tmpIn + blockSize) <= (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)); } /* some input data left, necessarily < blockSize */ @@ -924,6 +1045,53 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, return (size_t)(dstPtr - dstStart); } +/*! LZ4F_compressUpdate() : + * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. + * When successful, the function always entirely consumes @srcBuffer. + * src data is either buffered or compressed into @dstBuffer. + * If previously an uncompressed block was written, buffered data is flushed + * before appending compressed data is continued. + * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr). + * @compressOptionsPtr is optional : provide NULL to mean "default". + * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. + * or an error code if it fails (which can be tested using LZ4F_isError()) + * After an error, the state is left in a UB state, and must be re-initialized. + */ +size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, + void* dstBuffer, size_t dstCapacity, + const void* srcBuffer, size_t srcSize, + const LZ4F_compressOptions_t* compressOptionsPtr) +{ + return LZ4F_compressUpdateImpl(cctxPtr, + dstBuffer, dstCapacity, + srcBuffer, srcSize, + compressOptionsPtr, LZ4B_COMPRESSED); +} + +/*! LZ4F_compressUpdate() : + * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. + * When successful, the function always entirely consumes @srcBuffer. + * src data is either buffered or compressed into @dstBuffer. + * If previously an uncompressed block was written, buffered data is flushed + * before appending compressed data is continued. + * This is only supported when LZ4F_blockIndependent is used + * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr). + * @compressOptionsPtr is optional : provide NULL to mean "default". + * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. + * or an error code if it fails (which can be tested using LZ4F_isError()) + * After an error, the state is left in a UB state, and must be re-initialized. + */ +size_t LZ4F_uncompressedUpdate(LZ4F_cctx* cctxPtr, + void* dstBuffer, size_t dstCapacity, + const void* srcBuffer, size_t srcSize, + const LZ4F_compressOptions_t* compressOptionsPtr) { + RETURN_ERROR_IF(cctxPtr->prefs.frameInfo.blockMode != LZ4F_blockIndependent, blockMode_invalid); + return LZ4F_compressUpdateImpl(cctxPtr, + dstBuffer, dstCapacity, + srcBuffer, srcSize, + compressOptionsPtr, LZ4B_UNCOMPRESSED); +} + /*! LZ4F_flush() : * When compressed data must be sent immediately, without waiting for a block to be filled, @@ -942,13 +1110,12 @@ size_t LZ4F_flush(LZ4F_cctx* cctxPtr, compressFunc_t compress; if (cctxPtr->tmpInSize == 0) return 0; /* nothing to flush */ - if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC); - if (dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize)) - return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); - (void)compressOptionsPtr; /* not yet useful */ + RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized); + RETURN_ERROR_IF(dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize), dstMaxSize_tooSmall); + (void)compressOptionsPtr; /* not useful (yet) */ /* select compression function */ - compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel); + compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, cctxPtr->blockCompression); /* compress tmp buffer */ dstPtr += LZ4F_makeBlock(dstPtr, @@ -989,19 +1156,21 @@ size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, BYTE* dstPtr = dstStart; size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr); - if (LZ4F_isError(flushSize)) return flushSize; + DEBUGLOG(5,"LZ4F_compressEnd: dstCapacity=%u", (unsigned)dstCapacity); + FORWARD_IF_ERROR(flushSize); dstPtr += flushSize; assert(flushSize <= dstCapacity); dstCapacity -= flushSize; - if (dstCapacity < 4) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); + RETURN_ERROR_IF(dstCapacity < 4, dstMaxSize_tooSmall); LZ4F_writeLE32(dstPtr, 0); dstPtr += 4; /* endMark */ if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) { U32 const xxh = XXH32_digest(&(cctxPtr->xxh)); - if (dstCapacity < 8) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); + RETURN_ERROR_IF(dstCapacity < 8, dstMaxSize_tooSmall); + DEBUGLOG(5,"Writing 32-bit content checksum"); LZ4F_writeLE32(dstPtr, xxh); dstPtr+=4; /* content Checksum */ } @@ -1011,7 +1180,7 @@ size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, if (cctxPtr->prefs.frameInfo.contentSize) { if (cctxPtr->prefs.frameInfo.contentSize != cctxPtr->totalInSize) - return err0r(LZ4F_ERROR_frameSize_wrong); + RETURN_ERROR(frameSize_wrong); } return (size_t)(dstPtr - dstStart); @@ -1035,6 +1204,7 @@ typedef enum { } dStage_t; struct LZ4F_dctx_s { + LZ4F_CustomMem cmem; LZ4F_frameInfo_t frameInfo; U32 version; dStage_t dStage; @@ -1052,26 +1222,37 @@ struct LZ4F_dctx_s { size_t tmpOutStart; XXH32_state_t xxh; XXH32_state_t blockChecksum; + int skipChecksum; BYTE header[LZ4F_HEADER_SIZE_MAX]; }; /* typedef'd to LZ4F_dctx in lz4frame.h */ +LZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version) +{ + LZ4F_dctx* const dctx = (LZ4F_dctx*)LZ4F_calloc(sizeof(LZ4F_dctx), customMem); + if (dctx == NULL) return NULL; + + dctx->cmem = customMem; + dctx->version = version; + return dctx; +} + /*! LZ4F_createDecompressionContext() : * Create a decompressionContext object, which will track all decompression operations. * Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object. * Object can later be released using LZ4F_freeDecompressionContext(). * @return : if != 0, there was an error during context creation. */ -LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber) +LZ4F_errorCode_t +LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber) { - LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOC_AND_ZERO(sizeof(LZ4F_dctx)); - if (dctx == NULL) { /* failed allocation */ - *LZ4F_decompressionContextPtr = NULL; - return err0r(LZ4F_ERROR_allocation_failed); - } + assert(LZ4F_decompressionContextPtr != NULL); /* violation of narrow contract */ + RETURN_ERROR_IF(LZ4F_decompressionContextPtr == NULL, parameter_null); /* in case it nonetheless happen in production */ - dctx->version = versionNumber; - *LZ4F_decompressionContextPtr = dctx; + *LZ4F_decompressionContextPtr = LZ4F_createDecompressionContext_advanced(LZ4F_defaultCMem, versionNumber); + if (*LZ4F_decompressionContextPtr == NULL) { /* failed allocation */ + RETURN_ERROR(allocation_failed); + } return LZ4F_OK_NoError; } @@ -1080,9 +1261,9 @@ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx) LZ4F_errorCode_t result = LZ4F_OK_NoError; if (dctx != NULL) { /* can accept NULL input, like free() */ result = (LZ4F_errorCode_t)dctx->dStage; - FREEMEM(dctx->tmpIn); - FREEMEM(dctx->tmpOutBuffer); - FREEMEM(dctx); + LZ4F_free(dctx->tmpIn, dctx->cmem); + LZ4F_free(dctx->tmpOutBuffer, dctx->cmem); + LZ4F_free(dctx, dctx->cmem); } return result; } @@ -1095,6 +1276,7 @@ void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx) dctx->dStage = dstage_getFrameHeader; dctx->dict = NULL; dctx->dictSize = 0; + dctx->skipChecksum = 0; } @@ -1112,8 +1294,9 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize size_t frameHeaderSize; const BYTE* srcPtr = (const BYTE*)src; + DEBUGLOG(5, "LZ4F_decodeHeader"); /* need to decode header to get frameInfo */ - if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* minimal frame header size */ + RETURN_ERROR_IF(srcSize < minFHSize, frameHeader_incomplete); /* minimal frame header size */ MEM_INIT(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo)); /* special case : skippable frames */ @@ -1127,13 +1310,14 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize } else { dctx->dStage = dstage_getSFrameSize; return 4; - } - } + } } /* control magic number */ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) - return err0r(LZ4F_ERROR_frameType_unknown); + if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) { + DEBUGLOG(4, "frame header error : unknown magic number"); + RETURN_ERROR(frameType_unknown); + } #endif dctx->frameInfo.frameType = LZ4F_frame; @@ -1146,8 +1330,8 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize contentChecksumFlag = (FLG>>2) & _1BIT; dictIDFlag = FLG & _1BIT; /* validate */ - if (((FLG>>1)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */ - if (version != 1) return err0r(LZ4F_ERROR_headerVersion_wrong); /* Version Number, only supported value */ + if (((FLG>>1)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bit */ + if (version != 1) RETURN_ERROR(headerVersion_wrong); /* Version Number, only supported value */ } /* Frame Header Size */ @@ -1166,17 +1350,16 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize { U32 const BD = srcPtr[5]; blockSizeID = (BD>>4) & _3BITS; /* validate */ - if (((BD>>7)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */ - if (blockSizeID < 4) return err0r(LZ4F_ERROR_maxBlockSize_invalid); /* 4-7 only supported values for the time being */ - if (((BD>>0)&_4BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */ + if (((BD>>7)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bit */ + if (blockSizeID < 4) RETURN_ERROR(maxBlockSize_invalid); /* 4-7 only supported values for the time being */ + if (((BD>>0)&_4BITS) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bits */ } /* check header */ assert(frameHeaderSize > 5); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION { BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5); - if (HC != srcPtr[frameHeaderSize-1]) - return err0r(LZ4F_ERROR_headerChecksum_invalid); + RETURN_ERROR_IF(HC != srcPtr[frameHeaderSize-1], headerChecksum_invalid); } #endif @@ -1185,10 +1368,9 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize dctx->frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)blockChecksumFlag; dctx->frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)contentChecksumFlag; dctx->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID; - dctx->maxBlockSize = LZ4F_getBlockSize(blockSizeID); + dctx->maxBlockSize = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID); if (contentSizeFlag) - dctx->frameRemainingSize = - dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6); + dctx->frameRemainingSize = dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6); if (dictIDFlag) dctx->frameInfo.dictID = LZ4F_readLE32(srcPtr + frameHeaderSize - 5); @@ -1204,11 +1386,11 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize */ size_t LZ4F_headerSize(const void* src, size_t srcSize) { - if (src == NULL) return err0r(LZ4F_ERROR_srcPtr_wrong); + RETURN_ERROR_IF(src == NULL, srcPtr_wrong); /* minimal srcSize to determine header size */ if (srcSize < LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH) - return err0r(LZ4F_ERROR_frameHeader_incomplete); + RETURN_ERROR(frameHeader_incomplete); /* special case : skippable frames */ if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) @@ -1217,7 +1399,7 @@ size_t LZ4F_headerSize(const void* src, size_t srcSize) /* control magic number */ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER) - return err0r(LZ4F_ERROR_frameType_unknown); + RETURN_ERROR(frameType_unknown); #endif /* Frame Header Size */ @@ -1259,13 +1441,13 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, if (dctx->dStage == dstage_storeFrameHeader) { /* frame decoding already started, in the middle of header => automatic fail */ *srcSizePtr = 0; - return err0r(LZ4F_ERROR_frameDecoding_alreadyStarted); + RETURN_ERROR(frameDecoding_alreadyStarted); } else { size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr); if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; } if (*srcSizePtr < hSize) { *srcSizePtr=0; - return err0r(LZ4F_ERROR_frameHeader_incomplete); + RETURN_ERROR(frameHeader_incomplete); } { size_t decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize); @@ -1282,15 +1464,18 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, /* LZ4F_updateDict() : - * only used for LZ4F_blockLinked mode */ + * only used for LZ4F_blockLinked mode + * Condition : @dstPtr != NULL + */ static void LZ4F_updateDict(LZ4F_dctx* dctx, const BYTE* dstPtr, size_t dstSize, const BYTE* dstBufferStart, unsigned withinTmp) { - if (dctx->dictSize==0) - dctx->dict = (const BYTE*)dstPtr; /* priority to dictionary continuity */ + assert(dstPtr != NULL); + if (dctx->dictSize==0) dctx->dict = (const BYTE*)dstPtr; /* will lead to prefix mode */ + assert(dctx->dict != NULL); - if (dctx->dict + dctx->dictSize == dstPtr) { /* dictionary continuity, directly within dstBuffer */ + if (dctx->dict + dctx->dictSize == dstPtr) { /* prefix mode, everything within dstBuffer */ dctx->dictSize += dstSize; return; } @@ -1304,9 +1489,10 @@ static void LZ4F_updateDict(LZ4F_dctx* dctx, assert(dstSize < 64 KB); /* if dstSize >= 64 KB, dictionary would be set into dstBuffer directly */ - /* dstBuffer does not contain whole useful history (64 KB), so it must be saved within tmpOut */ + /* dstBuffer does not contain whole useful history (64 KB), so it must be saved within tmpOutBuffer */ + assert(dctx->tmpOutBuffer != NULL); - if ((withinTmp) && (dctx->dict == dctx->tmpOutBuffer)) { /* continue history within tmpOutBuffer */ + if (withinTmp && (dctx->dict == dctx->tmpOutBuffer)) { /* continue history within tmpOutBuffer */ /* withinTmp expectation : content of [dstPtr,dstSize] is same as [dict+dictSize,dstSize], so we just extend it */ assert(dctx->dict + dctx->dictSize == dctx->tmpOut + dctx->tmpOutStart); dctx->dictSize += dstSize; @@ -1349,7 +1535,6 @@ static void LZ4F_updateDict(LZ4F_dctx* dctx, } - /*! LZ4F_decompress() : * Call this function repetitively to regenerate compressed data in srcBuffer. * The function will attempt to decode up to *srcSizePtr bytes from srcBuffer @@ -1378,17 +1563,22 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, const BYTE* const srcEnd = srcStart + *srcSizePtr; const BYTE* srcPtr = srcStart; BYTE* const dstStart = (BYTE*)dstBuffer; - BYTE* const dstEnd = dstStart + *dstSizePtr; + BYTE* const dstEnd = dstStart ? dstStart + *dstSizePtr : NULL; BYTE* dstPtr = dstStart; const BYTE* selectedIn = NULL; unsigned doAnotherStage = 1; size_t nextSrcSizeHint = 1; + DEBUGLOG(5, "LZ4F_decompress : %p,%u => %p,%u", + srcBuffer, (unsigned)*srcSizePtr, dstBuffer, (unsigned)*dstSizePtr); + if (dstBuffer == NULL) assert(*dstSizePtr == 0); MEM_INIT(&optionsNull, 0, sizeof(optionsNull)); if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull; *srcSizePtr = 0; *dstSizePtr = 0; + assert(dctx != NULL); + dctx->skipChecksum |= (decompressOptionsPtr->skipChecksums != 0); /* once set, disable for the remainder of the frame */ /* behaves as a state machine */ @@ -1398,9 +1588,10 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, { case dstage_getFrameHeader: + DEBUGLOG(6, "dstage_getFrameHeader"); if ((size_t)(srcEnd-srcPtr) >= maxFHSize) { /* enough to decode - shortcut */ size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, (size_t)(srcEnd-srcPtr)); /* will update dStage appropriately */ - if (LZ4F_isError(hSize)) return hSize; + FORWARD_IF_ERROR(hSize); srcPtr += hSize; break; } @@ -1411,6 +1602,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, /* fall-through */ case dstage_storeFrameHeader: + DEBUGLOG(6, "dstage_storeFrameHeader"); { size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr)); memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); dctx->tmpInSize += sizeToCopy; @@ -1421,26 +1613,23 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, doAnotherStage = 0; /* not enough src data, ask for some more */ break; } - { size_t const hSize = LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget); /* will update dStage appropriately */ - if (LZ4F_isError(hSize)) return hSize; - } + FORWARD_IF_ERROR( LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget) ); /* will update dStage appropriately */ break; case dstage_init: + DEBUGLOG(6, "dstage_init"); if (dctx->frameInfo.contentChecksumFlag) (void)XXH32_reset(&(dctx->xxh), 0); /* internal buffers allocation */ { size_t const bufferNeeded = dctx->maxBlockSize + ((dctx->frameInfo.blockMode==LZ4F_blockLinked) ? 128 KB : 0); if (bufferNeeded > dctx->maxBufferSize) { /* tmp buffers too small */ dctx->maxBufferSize = 0; /* ensure allocation will be re-attempted on next entry*/ - FREEMEM(dctx->tmpIn); - dctx->tmpIn = (BYTE*)ALLOC(dctx->maxBlockSize + BFSize /* block checksum */); - if (dctx->tmpIn == NULL) - return err0r(LZ4F_ERROR_allocation_failed); - FREEMEM(dctx->tmpOutBuffer); - dctx->tmpOutBuffer= (BYTE*)ALLOC(bufferNeeded); - if (dctx->tmpOutBuffer== NULL) - return err0r(LZ4F_ERROR_allocation_failed); + LZ4F_free(dctx->tmpIn, dctx->cmem); + dctx->tmpIn = (BYTE*)LZ4F_malloc(dctx->maxBlockSize + BFSize /* block checksum */, dctx->cmem); + RETURN_ERROR_IF(dctx->tmpIn == NULL, allocation_failed); + LZ4F_free(dctx->tmpOutBuffer, dctx->cmem); + dctx->tmpOutBuffer= (BYTE*)LZ4F_malloc(bufferNeeded, dctx->cmem); + RETURN_ERROR_IF(dctx->tmpOutBuffer== NULL, allocation_failed); dctx->maxBufferSize = bufferNeeded; } } dctx->tmpInSize = 0; @@ -1480,17 +1669,21 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, } /* if (dctx->dStage == dstage_storeBlockHeader) */ /* decode block header */ - { size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU; + { U32 const blockHeader = LZ4F_readLE32(selectedIn); + size_t const nextCBlockSize = blockHeader & 0x7FFFFFFFU; size_t const crcSize = dctx->frameInfo.blockChecksumFlag * BFSize; - if (nextCBlockSize==0) { /* frameEnd signal, no more block */ + if (blockHeader==0) { /* frameEnd signal, no more block */ + DEBUGLOG(5, "end of frame"); dctx->dStage = dstage_getSuffix; break; } - if (nextCBlockSize > dctx->maxBlockSize) - return err0r(LZ4F_ERROR_maxBlockSize_invalid); - if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) { + if (nextCBlockSize > dctx->maxBlockSize) { + RETURN_ERROR(maxBlockSize_invalid); + } + if (blockHeader & LZ4F_BLOCKUNCOMPRESSED_FLAG) { /* next block is uncompressed */ dctx->tmpInTarget = nextCBlockSize; + DEBUGLOG(5, "next block is uncompressed (size %u)", (U32)nextCBlockSize); if (dctx->frameInfo.blockChecksumFlag) { (void)XXH32_reset(&dctx->blockChecksum, 0); } @@ -1508,20 +1701,28 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, } case dstage_copyDirect: /* uncompressed block */ - { size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr)); - size_t const sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize); - memcpy(dstPtr, srcPtr, sizeToCopy); - if (dctx->frameInfo.blockChecksumFlag) { - (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy); - } - if (dctx->frameInfo.contentChecksumFlag) - (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy); - if (dctx->frameInfo.contentSize) - dctx->frameRemainingSize -= sizeToCopy; + DEBUGLOG(6, "dstage_copyDirect"); + { size_t sizeToCopy; + if (dstPtr == NULL) { + sizeToCopy = 0; + } else { + size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr)); + sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize); + memcpy(dstPtr, srcPtr, sizeToCopy); + if (!dctx->skipChecksum) { + if (dctx->frameInfo.blockChecksumFlag) { + (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy); + } + if (dctx->frameInfo.contentChecksumFlag) + (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy); + } + if (dctx->frameInfo.contentSize) + dctx->frameRemainingSize -= sizeToCopy; - /* history management (linked blocks only)*/ - if (dctx->frameInfo.blockMode == LZ4F_blockLinked) - LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0); + /* history management (linked blocks only)*/ + if (dctx->frameInfo.blockMode == LZ4F_blockLinked) { + LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0); + } } srcPtr += sizeToCopy; dstPtr += sizeToCopy; @@ -1534,15 +1735,16 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, break; } dctx->tmpInTarget -= sizeToCopy; /* need to copy more */ - nextSrcSizeHint = dctx->tmpInTarget + - +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0) - + BHSize /* next header size */; - doAnotherStage = 0; - break; } + nextSrcSizeHint = dctx->tmpInTarget + + +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0) + + BHSize /* next header size */; + doAnotherStage = 0; + break; /* check block checksum for recently transferred uncompressed block */ case dstage_getBlockChecksum: + DEBUGLOG(6, "dstage_getBlockChecksum"); { const void* crcSrc; if ((srcEnd-srcPtr >= 4) && (dctx->tmpInSize==0)) { crcSrc = srcPtr; @@ -1559,11 +1761,16 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, } crcSrc = dctx->header; } - { U32 const readCRC = LZ4F_readLE32(crcSrc); + if (!dctx->skipChecksum) { + U32 const readCRC = LZ4F_readLE32(crcSrc); U32 const calcCRC = XXH32_digest(&dctx->blockChecksum); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (readCRC != calcCRC) - return err0r(LZ4F_ERROR_blockChecksum_invalid); + DEBUGLOG(6, "compare block checksum"); + if (readCRC != calcCRC) { + DEBUGLOG(4, "incorrect block checksum: %08X != %08X", + readCRC, calcCRC); + RETURN_ERROR(blockChecksum_invalid); + } #else (void)readCRC; (void)calcCRC; @@ -1573,6 +1780,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, break; case dstage_getCBlock: + DEBUGLOG(6, "dstage_getCBlock"); if ((size_t)(srcEnd-srcPtr) < dctx->tmpInTarget) { dctx->tmpInSize = 0; dctx->dStage = dstage_storeCBlock; @@ -1582,7 +1790,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, selectedIn = srcPtr; srcPtr += dctx->tmpInTarget; - if (0) /* jump over next block */ + if (0) /* always jump over next block */ case dstage_storeCBlock: { size_t const wantedData = dctx->tmpInTarget - dctx->tmpInSize; size_t const inputLeft = (size_t)(srcEnd-srcPtr); @@ -1601,64 +1809,75 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, } /* At this stage, input is large enough to decode a block */ + + /* First, decode and control block checksum if it exists */ if (dctx->frameInfo.blockChecksumFlag) { + assert(dctx->tmpInTarget >= 4); dctx->tmpInTarget -= 4; assert(selectedIn != NULL); /* selectedIn is defined at this stage (either srcPtr, or dctx->tmpIn) */ { U32 const readBlockCrc = LZ4F_readLE32(selectedIn + dctx->tmpInTarget); U32 const calcBlockCrc = XXH32(selectedIn, dctx->tmpInTarget, 0); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (readBlockCrc != calcBlockCrc) - return err0r(LZ4F_ERROR_blockChecksum_invalid); + RETURN_ERROR_IF(readBlockCrc != calcBlockCrc, blockChecksum_invalid); #else (void)readBlockCrc; (void)calcBlockCrc; #endif } } - if ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize) { + /* decode directly into destination buffer if there is enough room */ + if ( ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize) + /* unless the dictionary is stored in tmpOut: + * in which case it's faster to decode within tmpOut + * to benefit from prefix speedup */ + && !(dctx->dict!= NULL && (const BYTE*)dctx->dict + dctx->dictSize == dctx->tmpOut) ) + { const char* dict = (const char*)dctx->dict; size_t dictSize = dctx->dictSize; int decodedSize; + assert(dstPtr != NULL); if (dict && dictSize > 1 GB) { - /* the dictSize param is an int, avoid truncation / sign issues */ + /* overflow control : dctx->dictSize is an int, avoid truncation / sign issues */ dict += dictSize - 64 KB; dictSize = 64 KB; } - /* enough capacity in `dst` to decompress directly there */ decodedSize = LZ4_decompress_safe_usingDict( (const char*)selectedIn, (char*)dstPtr, (int)dctx->tmpInTarget, (int)dctx->maxBlockSize, dict, (int)dictSize); - if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC); /* decompression failed */ - if (dctx->frameInfo.contentChecksumFlag) + RETURN_ERROR_IF(decodedSize < 0, decompressionFailed); + if ((dctx->frameInfo.contentChecksumFlag) && (!dctx->skipChecksum)) XXH32_update(&(dctx->xxh), dstPtr, (size_t)decodedSize); if (dctx->frameInfo.contentSize) dctx->frameRemainingSize -= (size_t)decodedSize; /* dictionary management */ - if (dctx->frameInfo.blockMode==LZ4F_blockLinked) + if (dctx->frameInfo.blockMode==LZ4F_blockLinked) { LZ4F_updateDict(dctx, dstPtr, (size_t)decodedSize, dstStart, 0); + } dstPtr += decodedSize; - dctx->dStage = dstage_getBlockHeader; + dctx->dStage = dstage_getBlockHeader; /* end of block, let's get another one */ break; } /* not enough place into dst : decode into tmpOut */ - /* ensure enough place for tmpOut */ + + /* manage dictionary */ if (dctx->frameInfo.blockMode == LZ4F_blockLinked) { if (dctx->dict == dctx->tmpOutBuffer) { + /* truncate dictionary to 64 KB if too big */ if (dctx->dictSize > 128 KB) { memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - 64 KB, 64 KB); dctx->dictSize = 64 KB; } dctx->tmpOut = dctx->tmpOutBuffer + dctx->dictSize; - } else { /* dict not within tmp */ + } else { /* dict not within tmpOut */ size_t const reservedDictSpace = MIN(dctx->dictSize, 64 KB); dctx->tmpOut = dctx->tmpOutBuffer + reservedDictSpace; } } - /* Decode block */ + /* Decode block into tmpOut */ { const char* dict = (const char*)dctx->dict; size_t dictSize = dctx->dictSize; int decodedSize; @@ -1671,9 +1890,8 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, (const char*)selectedIn, (char*)dctx->tmpOut, (int)dctx->tmpInTarget, (int)dctx->maxBlockSize, dict, (int)dictSize); - if (decodedSize < 0) /* decompression failed */ - return err0r(LZ4F_ERROR_decompressionFailed); - if (dctx->frameInfo.contentChecksumFlag) + RETURN_ERROR_IF(decodedSize < 0, decompressionFailed); + if (dctx->frameInfo.contentChecksumFlag && !dctx->skipChecksum) XXH32_update(&(dctx->xxh), dctx->tmpOut, (size_t)decodedSize); if (dctx->frameInfo.contentSize) dctx->frameRemainingSize -= (size_t)decodedSize; @@ -1684,7 +1902,9 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, /* fall-through */ case dstage_flushOut: /* flush decoded data from tmpOut to dstBuffer */ - { size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr)); + DEBUGLOG(6, "dstage_flushOut"); + if (dstPtr != NULL) { + size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr)); memcpy(dstPtr, dctx->tmpOut + dctx->tmpOutStart, sizeToCopy); /* dictionary management */ @@ -1693,20 +1913,18 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, dctx->tmpOutStart += sizeToCopy; dstPtr += sizeToCopy; - - if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */ - dctx->dStage = dstage_getBlockHeader; /* get next block */ - break; - } - /* could not flush everything : stop there, just request a block header */ - doAnotherStage = 0; - nextSrcSizeHint = BHSize; + } + if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */ + dctx->dStage = dstage_getBlockHeader; /* get next block */ break; } + /* could not flush everything : stop there, just request a block header */ + doAnotherStage = 0; + nextSrcSizeHint = BHSize; + break; case dstage_getSuffix: - if (dctx->frameRemainingSize) - return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */ + RETURN_ERROR_IF(dctx->frameRemainingSize, frameSize_wrong); /* incorrect frame size decoded */ if (!dctx->frameInfo.contentChecksumFlag) { /* no checksum, frame is completed */ nextSrcSizeHint = 0; LZ4F_resetDecompressionContext(dctx); @@ -1738,20 +1956,20 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, } /* if (dctx->dStage == dstage_storeSuffix) */ /* case dstage_checkSuffix: */ /* no direct entry, avoid initialization risks */ - { U32 const readCRC = LZ4F_readLE32(selectedIn); + if (!dctx->skipChecksum) { + U32 const readCRC = LZ4F_readLE32(selectedIn); U32 const resultCRC = XXH32_digest(&(dctx->xxh)); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (readCRC != resultCRC) - return err0r(LZ4F_ERROR_contentChecksum_invalid); + RETURN_ERROR_IF(readCRC != resultCRC, contentChecksum_invalid); #else (void)readCRC; (void)resultCRC; #endif - nextSrcSizeHint = 0; - LZ4F_resetDecompressionContext(dctx); - doAnotherStage = 0; - break; } + nextSrcSizeHint = 0; + LZ4F_resetDecompressionContext(dctx); + doAnotherStage = 0; + break; case dstage_getSFrameSize: if ((srcEnd - srcPtr) >= 4) { @@ -1802,10 +2020,11 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, } /* switch (dctx->dStage) */ } /* while (doAnotherStage) */ - /* preserve history within tmp whenever necessary */ + /* preserve history within tmpOut whenever necessary */ LZ4F_STATIC_ASSERT((unsigned)dstage_init == 2); if ( (dctx->frameInfo.blockMode==LZ4F_blockLinked) /* next block will use up to 64KB from previous ones */ && (dctx->dict != dctx->tmpOutBuffer) /* dictionary is not already within tmp */ + && (dctx->dict != NULL) /* dictionary exists */ && (!decompressOptionsPtr->stableDst) /* cannot rely on dst data to remain there for next call */ && ((unsigned)(dctx->dStage)-2 < (unsigned)(dstage_getSuffix)-2) ) /* valid stages : [init ... getSuffix[ */ { @@ -1815,9 +2034,9 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, const BYTE* oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart; if (dctx->tmpOutSize > 64 KB) copySize = 0; if (copySize > preserveSize) copySize = preserveSize; + assert(dctx->tmpOutBuffer != NULL); - if (copySize > 0) - memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize); + memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize); dctx->dict = dctx->tmpOutBuffer; dctx->dictSize = preserveSize + dctx->tmpOutStart; @@ -1825,8 +2044,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize; size_t const newDictSize = MIN(dctx->dictSize, 64 KB); - if (newDictSize > 0) - memcpy(dctx->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize); + memcpy(dctx->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize); dctx->dict = dctx->tmpOutBuffer; dctx->dictSize = newDictSize; diff --git a/native/lz4/lz4frame.h b/native/lz4/lz4frame.h index 391e484..1bdf6c4 100644 --- a/native/lz4/lz4frame.h +++ b/native/lz4/lz4frame.h @@ -1,7 +1,7 @@ /* - LZ4 auto-framing library + LZ4F - LZ4-Frame library Header File - Copyright (C) 2011-2017, Yann Collet. + Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without @@ -39,7 +39,7 @@ * LZ4F also offers streaming capabilities. * * lz4.h is not required when using lz4frame.h, - * except to extract common constant such as LZ4_VERSION_NUMBER. + * except to extract common constants such as LZ4_VERSION_NUMBER. * */ #ifndef LZ4F_H_09782039843 @@ -54,29 +54,34 @@ extern "C" { /** - Introduction - - lz4frame.h implements LZ4 frame specification (doc/lz4_Frame_format.md). - lz4frame.h provides frame compression functions that take care - of encoding standard metadata alongside LZ4-compressed blocks. -*/ + * Introduction + * + * lz4frame.h implements LZ4 frame specification: see doc/lz4_Frame_format.md . + * LZ4 Frames are compatible with `lz4` CLI, + * and designed to be interoperable with any system. +**/ /*-*************************************************************** * Compiler specifics *****************************************************************/ /* LZ4_DLL_EXPORT : * Enable exporting of functions when building a Windows DLL - * LZ4FLIB_API : + * LZ4FLIB_VISIBILITY : * Control library symbols visibility. */ +#ifndef LZ4FLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4FLIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define LZ4FLIB_VISIBILITY +# endif +#endif #if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) -# define LZ4FLIB_API __declspec(dllexport) +# define LZ4FLIB_API __declspec(dllexport) LZ4FLIB_VISIBILITY #elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) -# define LZ4FLIB_API __declspec(dllimport) -#elif defined(__GNUC__) && (__GNUC__ >= 4) -# define LZ4FLIB_API __attribute__ ((__visibility__ ("default"))) +# define LZ4FLIB_API __declspec(dllimport) LZ4FLIB_VISIBILITY #else -# define LZ4FLIB_API +# define LZ4FLIB_API LZ4FLIB_VISIBILITY #endif #ifdef LZ4F_DISABLE_DEPRECATE_WARNINGS @@ -103,7 +108,7 @@ LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /**< return /*-************************************ * Frame compression types - **************************************/ + ************************************* */ /* #define LZ4F_ENABLE_OBSOLETE_ENUMS // uncomment to enable obsolete enums */ #ifdef LZ4F_ENABLE_OBSOLETE_ENUMS # define LZ4F_OBSOLETE_ENUM(x) , LZ4F_DEPRECATE(x) = LZ4F_##x @@ -113,7 +118,8 @@ LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /**< return /* The larger the block size, the (slightly) better the compression ratio, * though there are diminishing returns. - * Larger blocks also increase memory usage on both compression and decompression sides. */ + * Larger blocks also increase memory usage on both compression and decompression sides. + */ typedef enum { LZ4F_default=0, LZ4F_max64KB=4, @@ -204,7 +210,7 @@ LZ4FLIB_API int LZ4F_compressionLevel_max(void); /* v1.8.0+ */ * Returns the maximum possible compressed size with LZ4F_compressFrame() given srcSize and preferences. * `preferencesPtr` is optional. It can be replaced by NULL, in which case, the function will assume default preferences. * Note : this result is only usable with LZ4F_compressFrame(). - * It may also be used with LZ4F_compressUpdate() _if no flush() operation_ is performed. + * It may also be relevant to LZ4F_compressUpdate() _only if_ no flush() operation is ever performed. */ LZ4FLIB_API size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr); @@ -224,7 +230,7 @@ LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, * Advanced compression functions *************************************/ typedef struct LZ4F_cctx_s LZ4F_cctx; /* incomplete type */ -typedef LZ4F_cctx* LZ4F_compressionContext_t; /* for compatibility with previous API version */ +typedef LZ4F_cctx* LZ4F_compressionContext_t; /* for compatibility with older APIs, prefer using LZ4F_cctx */ typedef struct { unsigned stableSrc; /* 1 == src content will remain present on future calls to LZ4F_compress(); skip copying src content within tmp buffer */ @@ -237,20 +243,27 @@ typedef struct { LZ4FLIB_API unsigned LZ4F_getVersion(void); /*! LZ4F_createCompressionContext() : - * The first thing to do is to create a compressionContext object, which will be used in all compression operations. - * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version. - * The version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL. - * The function will provide a pointer to a fully allocated LZ4F_cctx object. - * If @return != zero, there was an error during context creation. - * Object can release its memory using LZ4F_freeCompressionContext(); - */ + * The first thing to do is to create a compressionContext object, + * which will keep track of operation state during streaming compression. + * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version, + * and a pointer to LZ4F_cctx*, to write the resulting pointer into. + * @version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL. + * The function provides a pointer to a fully allocated LZ4F_cctx object. + * @cctxPtr MUST be != NULL. + * If @return != zero, context creation failed. + * A created compression context can be employed multiple times for consecutive streaming operations. + * Once all streaming compression jobs are completed, + * the state object can be released using LZ4F_freeCompressionContext(). + * Note1 : LZ4F_freeCompressionContext() is always successful. Its return value can be ignored. + * Note2 : LZ4F_freeCompressionContext() works fine with NULL input pointers (do nothing). +**/ LZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version); LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx); /*---- Compression ----*/ -#define LZ4F_HEADER_SIZE_MIN 7 /* LZ4 Frame header size can vary, depending on selected paramaters */ +#define LZ4F_HEADER_SIZE_MIN 7 /* LZ4 Frame header size can vary, depending on selected parameters */ #define LZ4F_HEADER_SIZE_MAX 19 /* Size in bytes of a block header in little-endian format. Highest bit indicates if block data is uncompressed */ @@ -284,7 +297,7 @@ LZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_cctx* cctx, * @return is always the same for a srcSize and prefsPtr. * prefsPtr is optional : when NULL is provided, preferences will be set to cover worst case scenario. * tech details : - * @return includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes. + * @return if automatic flushing is not enabled, includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes. * It also includes frame footer (ending + checksum), since it might be generated by LZ4F_compressEnd(). * @return doesn't include frame header, as it was already generated by LZ4F_compressBegin(). */ @@ -295,8 +308,9 @@ LZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* * Important rule: dstCapacity MUST be large enough to ensure operation success even in worst case situations. * This value is provided by LZ4F_compressBound(). * If this condition is not respected, LZ4F_compress() will fail (result is an errorCode). - * LZ4F_compressUpdate() doesn't guarantee error recovery. - * When an error occurs, compression context must be freed or resized. + * After an error, the state is left in a UB state, and must be re-initialized or freed. + * If previously an uncompressed block was written, buffered data is flushed + * before appending compressed data is continued. * `cOptPtr` is optional : NULL can be provided, in which case all options are set to default. * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered). * or an error code if it fails (which can be tested using LZ4F_isError()) @@ -341,8 +355,12 @@ typedef struct LZ4F_dctx_s LZ4F_dctx; /* incomplete type */ typedef LZ4F_dctx* LZ4F_decompressionContext_t; /* compatibility with previous API versions */ typedef struct { - unsigned stableDst; /* pledges that last 64KB decompressed data will remain available unmodified. This optimization skips storage operations in tmp buffers. */ - unsigned reserved[3]; /* must be set to zero for forward compatibility */ + unsigned stableDst; /* pledges that last 64KB decompressed data will remain available unmodified between invocations. + * This optimization skips storage operations in tmp buffers. */ + unsigned skipChecksums; /* disable checksum calculation and verification, even when one is present in frame, to save CPU time. + * Setting this option to 1 once disables all checksums for the rest of the frame. */ + unsigned reserved1; /* must be set to zero for forward compatibility */ + unsigned reserved0; /* idem */ } LZ4F_decompressOptions_t; @@ -350,9 +368,10 @@ typedef struct { /*! LZ4F_createDecompressionContext() : * Create an LZ4F_dctx object, to track all decompression operations. - * The version provided MUST be LZ4F_VERSION. - * The function provides a pointer to an allocated and initialized LZ4F_dctx object. - * The result is an errorCode, which can be tested using LZ4F_isError(). + * @version provided MUST be LZ4F_VERSION. + * @dctxPtr MUST be valid. + * The function fills @dctxPtr with the value of a pointer to an allocated and initialized LZ4F_dctx object. + * The @return is an errorCode, which can be tested using LZ4F_isError(). * dctx memory can be released using LZ4F_freeDecompressionContext(); * Result of LZ4F_freeDecompressionContext() indicates current state of decompressionContext when being released. * That is, it should be == 0 if decompression has been completed fully and correctly. @@ -365,6 +384,8 @@ LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx); * Streaming decompression functions *************************************/ +#define LZ4F_MAGICNUMBER 0x184D2204U +#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U #define LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH 5 /*! LZ4F_headerSize() : v1.9.0+ @@ -376,11 +397,11 @@ LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx); * note : Frame header size is variable, but is guaranteed to be * >= LZ4F_HEADER_SIZE_MIN bytes, and <= LZ4F_HEADER_SIZE_MAX bytes. */ -size_t LZ4F_headerSize(const void* src, size_t srcSize); +LZ4FLIB_API size_t LZ4F_headerSize(const void* src, size_t srcSize); /*! LZ4F_getFrameInfo() : * This function extracts frame parameters (max blockSize, dictID, etc.). - * Its usage is optional: user can call LZ4F_decompress() directly. + * Its usage is optional: user can also invoke LZ4F_decompress() directly. * * Extracted information will fill an existing LZ4F_frameInfo_t structure. * This can be useful for allocation and dictionary identification purposes. @@ -421,13 +442,16 @@ size_t LZ4F_headerSize(const void* src, size_t srcSize); * note 1 : in case of error, dctx is not modified. Decoding operation can resume from beginning safely. * note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure. */ -LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, - LZ4F_frameInfo_t* frameInfoPtr, - const void* srcBuffer, size_t* srcSizePtr); +LZ4FLIB_API size_t +LZ4F_getFrameInfo(LZ4F_dctx* dctx, + LZ4F_frameInfo_t* frameInfoPtr, + const void* srcBuffer, size_t* srcSizePtr); /*! LZ4F_decompress() : - * Call this function repetitively to regenerate compressed data from `srcBuffer`. - * The function will read up to *srcSizePtr bytes from srcBuffer, + * Call this function repetitively to regenerate data compressed in `srcBuffer`. + * + * The function requires a valid dctx state. + * It will read up to *srcSizePtr bytes from srcBuffer, * and decompress data into dstBuffer, of capacity *dstSizePtr. * * The nb of bytes consumed from srcBuffer will be written into *srcSizePtr (necessarily <= original value). @@ -454,10 +478,11 @@ LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, * * After a frame is fully decoded, dctx can be used again to decompress another frame. */ -LZ4FLIB_API size_t LZ4F_decompress(LZ4F_dctx* dctx, - void* dstBuffer, size_t* dstSizePtr, - const void* srcBuffer, size_t* srcSizePtr, - const LZ4F_decompressOptions_t* dOptPtr); +LZ4FLIB_API size_t +LZ4F_decompress(LZ4F_dctx* dctx, + void* dstBuffer, size_t* dstSizePtr, + const void* srcBuffer, size_t* srcSizePtr, + const LZ4F_decompressOptions_t* dOptPtr); /*! LZ4F_resetDecompressionContext() : added in v1.8.0 @@ -493,9 +518,9 @@ extern "C" { * Use at your own risk. */ #ifdef LZ4F_PUBLISH_STATIC_FUNCTIONS -#define LZ4FLIB_STATIC_API LZ4FLIB_API +# define LZ4FLIB_STATIC_API LZ4FLIB_API #else -#define LZ4FLIB_STATIC_API +# define LZ4FLIB_STATIC_API #endif @@ -521,6 +546,8 @@ extern "C" { ITEM(ERROR_headerChecksum_invalid) \ ITEM(ERROR_contentChecksum_invalid) \ ITEM(ERROR_frameDecoding_alreadyStarted) \ + ITEM(ERROR_compressionState_uninitialized) \ + ITEM(ERROR_parameter_null) \ ITEM(ERROR_maxCode) #define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, @@ -531,7 +558,31 @@ typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) LZ4FLIB_STATIC_API LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult); -LZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(unsigned); + +/*! LZ4F_getBlockSize() : + * Return, in scalar format (size_t), + * the maximum block size associated with blockSizeID. +**/ +LZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID); + +/*! LZ4F_uncompressedUpdate() : + * LZ4F_uncompressedUpdate() can be called repetitively to add as much data uncompressed data as necessary. + * Important rule: dstCapacity MUST be large enough to store the entire source buffer as + * no compression is done for this operation + * If this condition is not respected, LZ4F_uncompressedUpdate() will fail (result is an errorCode). + * After an error, the state is left in a UB state, and must be re-initialized or freed. + * If previously a compressed block was written, buffered data is flushed + * before appending uncompressed data is continued. + * This is only supported when LZ4F_blockIndependent is used + * `cOptPtr` is optional : NULL can be provided, in which case all options are set to default. + * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered). + * or an error code if it fails (which can be tested using LZ4F_isError()) + */ +LZ4FLIB_STATIC_API size_t +LZ4F_uncompressedUpdate(LZ4F_cctx* cctx, + void* dstBuffer, size_t dstCapacity, + const void* srcBuffer, size_t srcSize, + const LZ4F_compressOptions_t* cOptPtr); /********************************** * Bulk processing dictionary API @@ -575,12 +626,12 @@ LZ4FLIB_STATIC_API void LZ4F_freeCDict(LZ4F_CDict* CDict); * but it's not recommended, as it's the only way to provide dictID in the frame header. * @return : number of bytes written into dstBuffer. * or an error code if it fails (can be tested using LZ4F_isError()) */ -LZ4FLIB_STATIC_API size_t LZ4F_compressFrame_usingCDict( - LZ4F_cctx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const LZ4F_CDict* cdict, - const LZ4F_preferences_t* preferencesPtr); +LZ4FLIB_STATIC_API size_t +LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const LZ4F_CDict* cdict, + const LZ4F_preferences_t* preferencesPtr); /*! LZ4F_compressBegin_usingCDict() : @@ -590,23 +641,49 @@ LZ4FLIB_STATIC_API size_t LZ4F_compressFrame_usingCDict( * however, it's the only way to provide dictID in the frame header. * @return : number of bytes written into dstBuffer for the header, * or an error code (which can be tested using LZ4F_isError()) */ -LZ4FLIB_STATIC_API size_t LZ4F_compressBegin_usingCDict( - LZ4F_cctx* cctx, - void* dstBuffer, size_t dstCapacity, - const LZ4F_CDict* cdict, - const LZ4F_preferences_t* prefsPtr); +LZ4FLIB_STATIC_API size_t +LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctx, + void* dstBuffer, size_t dstCapacity, + const LZ4F_CDict* cdict, + const LZ4F_preferences_t* prefsPtr); /*! LZ4F_decompress_usingDict() : * Same as LZ4F_decompress(), using a predefined dictionary. * Dictionary is used "in place", without any preprocessing. - * It must remain accessible throughout the entire frame decoding. */ -LZ4FLIB_STATIC_API size_t LZ4F_decompress_usingDict( - LZ4F_dctx* dctxPtr, - void* dstBuffer, size_t* dstSizePtr, - const void* srcBuffer, size_t* srcSizePtr, - const void* dict, size_t dictSize, - const LZ4F_decompressOptions_t* decompressOptionsPtr); +** It must remain accessible throughout the entire frame decoding. */ +LZ4FLIB_STATIC_API size_t +LZ4F_decompress_usingDict(LZ4F_dctx* dctxPtr, + void* dstBuffer, size_t* dstSizePtr, + const void* srcBuffer, size_t* srcSizePtr, + const void* dict, size_t dictSize, + const LZ4F_decompressOptions_t* decompressOptionsPtr); + + +/*! Custom memory allocation : + * These prototypes make it possible to pass custom allocation/free functions. + * LZ4F_customMem is provided at state creation time, using LZ4F_create*_advanced() listed below. + * All allocation/free operations will be completed using these custom variants instead of regular ones. + */ +typedef void* (*LZ4F_AllocFunction) (void* opaqueState, size_t size); +typedef void* (*LZ4F_CallocFunction) (void* opaqueState, size_t size); +typedef void (*LZ4F_FreeFunction) (void* opaqueState, void* address); +typedef struct { + LZ4F_AllocFunction customAlloc; + LZ4F_CallocFunction customCalloc; /* optional; when not defined, uses customAlloc + memset */ + LZ4F_FreeFunction customFree; + void* opaqueState; +} LZ4F_CustomMem; +static +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif +LZ4F_CustomMem const LZ4F_defaultCMem = { NULL, NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ + +LZ4FLIB_STATIC_API LZ4F_cctx* LZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version); +LZ4FLIB_STATIC_API LZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version); +LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict_advanced(LZ4F_CustomMem customMem, const void* dictBuffer, size_t dictSize); + #if defined (__cplusplus) } diff --git a/native/lz4/lz4frame_static.h b/native/lz4/lz4frame_static.h index 925a2c5..2b44a63 100644 --- a/native/lz4/lz4frame_static.h +++ b/native/lz4/lz4frame_static.h @@ -1,7 +1,7 @@ /* LZ4 auto-framing library Header File for static linking only - Copyright (C) 2011-2016, Yann Collet. + Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) diff --git a/native/lz4/lz4hc.c b/native/lz4/lz4hc.c index 5922ed7..b21ad6b 100644 --- a/native/lz4/lz4hc.c +++ b/native/lz4/lz4hc.c @@ -1,6 +1,6 @@ /* LZ4 HC - High Compression Mode of LZ4 - Copyright (C) 2011-2017, Yann Collet. + Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -42,7 +42,7 @@ * Select how default compression function will allocate workplace memory, * in stack (0:fastest), or in heap (1:requires malloc()). * Since workplace is rather large, heap mode is recommended. - */ +**/ #ifndef LZ4HC_HEAPMODE # define LZ4HC_HEAPMODE 1 #endif @@ -53,7 +53,7 @@ #include "lz4hc.h" -/*=== Common LZ4 definitions ===*/ +/*=== Common definitions ===*/ #if defined(__GNUC__) # pragma GCC diagnostic ignored "-Wunused-function" #endif @@ -61,15 +61,16 @@ # pragma clang diagnostic ignored "-Wunused-function" #endif -/*=== Enums ===*/ -typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive; - - #define LZ4_COMMONDEFS_ONLY #ifndef LZ4_SRC_INCLUDED #include "lz4.c" /* LZ4_count, constants, mem */ #endif + +/*=== Enums ===*/ +typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive; + + /*=== Constants ===*/ #define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH) #define LZ4_OPT_NUM (1<<12) @@ -92,24 +93,26 @@ static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr) **************************************/ static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4) { - MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable)); + MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable)); MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); } static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start) { - uptrval startingOffset = (uptrval)(hc4->end - hc4->base); - if (startingOffset > 1 GB) { + size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart); + size_t newStartingOffset = bufferSize + hc4->dictLimit; + assert(newStartingOffset >= bufferSize); /* check overflow */ + if (newStartingOffset > 1 GB) { LZ4HC_clearTables(hc4); - startingOffset = 0; + newStartingOffset = 0; } - startingOffset += 64 KB; - hc4->nextToUpdate = (U32) startingOffset; - hc4->base = start - startingOffset; + newStartingOffset += 64 KB; + hc4->nextToUpdate = (U32)newStartingOffset; + hc4->prefixStart = start; hc4->end = start; - hc4->dictBase = start - startingOffset; - hc4->dictLimit = (U32) startingOffset; - hc4->lowLimit = (U32) startingOffset; + hc4->dictStart = start; + hc4->dictLimit = (U32)newStartingOffset; + hc4->lowLimit = (U32)newStartingOffset; } @@ -118,12 +121,15 @@ LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) { U16* const chainTable = hc4->chainTable; U32* const hashTable = hc4->hashTable; - const BYTE* const base = hc4->base; - U32 const target = (U32)(ip - base); + const BYTE* const prefixPtr = hc4->prefixStart; + U32 const prefixIdx = hc4->dictLimit; + U32 const target = (U32)(ip - prefixPtr) + prefixIdx; U32 idx = hc4->nextToUpdate; + assert(ip >= prefixPtr); + assert(target >= prefixIdx); while (idx < target) { - U32 const h = LZ4HC_hashPtr(base+idx); + U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx); size_t delta = idx - hashTable[h]; if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX; DELTANEXTU16(chainTable, idx) = (U16)delta; @@ -161,8 +167,7 @@ int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match, static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern) { size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3; - if (bitsToRotate == 0) - return pattern; + if (bitsToRotate == 0) return pattern; return LZ4HC_rotl32(pattern, (int)bitsToRotate); } @@ -172,7 +177,8 @@ static unsigned LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32) { const BYTE* const iStart = ip; - reg_t const pattern = (sizeof(pattern)==8) ? (reg_t)pattern32 + (((reg_t)pattern32) << 32) : pattern32; + reg_t const pattern = (sizeof(pattern)==8) ? + (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32; while (likely(ip < iEnd-(sizeof(pattern)-1))) { reg_t const diff = LZ4_read_ARCH(ip) ^ pattern; @@ -192,15 +198,14 @@ LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32) BYTE const byte = (BYTE)(pattern >> bitOffset); if (*ip != byte) break; ip ++; bitOffset -= 8; - } - } + } } return (unsigned)(ip - iStart); } /* LZ4HC_reverseCountPattern() : * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) - * read using natural platform endianess */ + * read using natural platform endianness */ static unsigned LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern) { @@ -210,7 +215,7 @@ LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern) if (LZ4_read32(ip-4) != pattern) break; ip -= 4; } - { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */ + { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */ while (likely(ip>iLow)) { if (ip[-1] != *bytePtr) break; ip--; bytePtr--; @@ -233,28 +238,28 @@ typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e; LZ4_FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( - LZ4HC_CCtx_internal* hc4, - const BYTE* const ip, - const BYTE* const iLowLimit, - const BYTE* const iHighLimit, - int longest, - const BYTE** matchpos, - const BYTE** startpos, - const int maxNbAttempts, - const int patternAnalysis, - const int chainSwap, - const dictCtx_directive dict, - const HCfavor_e favorDecSpeed) + LZ4HC_CCtx_internal* const hc4, + const BYTE* const ip, + const BYTE* const iLowLimit, const BYTE* const iHighLimit, + int longest, + const BYTE** matchpos, + const BYTE** startpos, + const int maxNbAttempts, + const int patternAnalysis, const int chainSwap, + const dictCtx_directive dict, + const HCfavor_e favorDecSpeed) { U16* const chainTable = hc4->chainTable; U32* const HashTable = hc4->hashTable; const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx; - const BYTE* const base = hc4->base; - const U32 dictLimit = hc4->dictLimit; - const BYTE* const lowPrefixPtr = base + dictLimit; - const U32 ipIndex = (U32)(ip - base); - const U32 lowestMatchIndex = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX; - const BYTE* const dictBase = hc4->dictBase; + const BYTE* const prefixPtr = hc4->prefixStart; + const U32 prefixIdx = hc4->dictLimit; + const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx; + const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex); + const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX; + const BYTE* const dictStart = hc4->dictStart; + const U32 dictIdx = hc4->lowLimit; + const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx; int const lookBackLength = (int)(ip-iLowLimit); int nbAttempts = maxNbAttempts; U32 matchChainPos = 0; @@ -270,20 +275,19 @@ LZ4HC_InsertAndGetWiderMatch ( DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)", matchIndex, lowestMatchIndex); - while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) { + while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) { int matchLength=0; nbAttempts--; assert(matchIndex < ipIndex); if (favorDecSpeed && (ipIndex - matchIndex < 8)) { /* do nothing */ - } else if (matchIndex >= dictLimit) { /* within current Prefix */ - const BYTE* const matchPtr = base + matchIndex; - assert(matchPtr >= lowPrefixPtr); + } else if (matchIndex >= prefixIdx) { /* within current Prefix */ + const BYTE* const matchPtr = prefixPtr + matchIndex - prefixIdx; assert(matchPtr < ip); assert(longest >= 1); if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) { if (LZ4_read32(matchPtr) == pattern) { - int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, lowPrefixPtr) : 0; + int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0; matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); matchLength -= back; if (matchLength > longest) { @@ -292,24 +296,25 @@ LZ4HC_InsertAndGetWiderMatch ( *startpos = ip + back; } } } } else { /* lowestMatchIndex <= matchIndex < dictLimit */ - const BYTE* const matchPtr = dictBase + matchIndex; - if (LZ4_read32(matchPtr) == pattern) { - const BYTE* const dictStart = dictBase + hc4->lowLimit; + const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx); + assert(matchIndex >= dictIdx); + if ( likely(matchIndex <= prefixIdx - 4) + && (LZ4_read32(matchPtr) == pattern) ) { int back = 0; - const BYTE* vLimit = ip + (dictLimit - matchIndex); + const BYTE* vLimit = ip + (prefixIdx - matchIndex); if (vLimit > iHighLimit) vLimit = iHighLimit; matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; if ((ip+matchLength == vLimit) && (vLimit < iHighLimit)) - matchLength += LZ4_count(ip+matchLength, lowPrefixPtr, iHighLimit); + matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit); back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0; matchLength -= back; if (matchLength > longest) { longest = matchLength; - *matchpos = base + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */ + *matchpos = prefixPtr - prefixIdx + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */ *startpos = ip + back; } } } - if (chainSwap && matchLength==longest) { /* better match => select a better chain */ + if (chainSwap && matchLength==longest) { /* better match => select a better chain */ assert(lookBackLength==0); /* search forward only */ if (matchIndex + (U32)longest <= ipIndex) { int const kTrigger = 4; @@ -325,8 +330,7 @@ LZ4HC_InsertAndGetWiderMatch ( distanceToNextMatch = candidateDist; matchChainPos = (U32)pos; accel = 1 << kTrigger; - } - } + } } if (distanceToNextMatch > 1) { if (distanceToNextMatch > matchIndex) break; /* avoid overflow */ matchIndex -= distanceToNextMatch; @@ -346,23 +350,24 @@ LZ4HC_InsertAndGetWiderMatch ( repeat = rep_not; } } if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex) - && LZ4HC_protectDictEnd(dictLimit, matchCandidateIdx) ) { - const int extDict = matchCandidateIdx < dictLimit; - const BYTE* const matchPtr = (extDict ? dictBase : base) + matchCandidateIdx; + && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) { + const int extDict = matchCandidateIdx < prefixIdx; + const BYTE* const matchPtr = (extDict ? dictStart - dictIdx : prefixPtr - prefixIdx) + matchCandidateIdx; if (LZ4_read32(matchPtr) == pattern) { /* good candidate */ - const BYTE* const dictStart = dictBase + hc4->lowLimit; - const BYTE* const iLimit = extDict ? dictBase + dictLimit : iHighLimit; + const BYTE* const iLimit = extDict ? dictEnd : iHighLimit; size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern); if (extDict && matchPtr + forwardPatternLength == iLimit) { U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern); - forwardPatternLength += LZ4HC_countPattern(lowPrefixPtr, iHighLimit, rotatedPattern); + forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern); } - { const BYTE* const lowestMatchPtr = extDict ? dictStart : lowPrefixPtr; + { const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr; size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern); size_t currentSegmentLength; - if (!extDict && matchPtr - backLength == lowPrefixPtr && hc4->lowLimit < dictLimit) { + if (!extDict + && matchPtr - backLength == prefixPtr + && dictIdx < prefixIdx) { U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern); - backLength += LZ4HC_reverseCountPattern(dictBase + dictLimit, dictStart, rotatedPattern); + backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern); } /* Limit backLength not go further than lowestMatchIndex */ backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex); @@ -372,28 +377,28 @@ LZ4HC_InsertAndGetWiderMatch ( if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */ && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */ U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */ - if (LZ4HC_protectDictEnd(dictLimit, newMatchIndex)) + if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) matchIndex = newMatchIndex; else { /* Can only happen if started in the prefix */ - assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict); - matchIndex = dictLimit; + assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict); + matchIndex = prefixIdx; } } else { U32 const newMatchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */ - if (!LZ4HC_protectDictEnd(dictLimit, newMatchIndex)) { - assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict); - matchIndex = dictLimit; + if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) { + assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict); + matchIndex = prefixIdx; } else { matchIndex = newMatchIndex; if (lookBackLength==0) { /* no back possible */ size_t const maxML = MIN(currentSegmentLength, srcPatternLength); if ((size_t)longest < maxML) { - assert(base + matchIndex < ip); - if (ip - (base+matchIndex) > LZ4_DISTANCE_MAX) break; + assert(prefixPtr - prefixIdx + matchIndex != ip); + if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break; assert(maxML < 2 GB); longest = (int)maxML; - *matchpos = base + matchIndex; /* virtual pos, relative to ip, to retrieve offset */ + *matchpos = prefixPtr - prefixIdx + matchIndex; /* virtual pos, relative to ip, to retrieve offset */ *startpos = ip; } { U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex); @@ -410,14 +415,14 @@ LZ4HC_InsertAndGetWiderMatch ( } /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */ if ( dict == usingDictCtxHc - && nbAttempts + && nbAttempts > 0 && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) { - size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base); + size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit; U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)]; assert(dictEndOffset <= 1 GB); matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset; while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) { - const BYTE* const matchPtr = dictCtx->base + dictMatchIndex; + const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex; if (LZ4_read32(matchPtr) == pattern) { int mlt; @@ -425,11 +430,11 @@ LZ4HC_InsertAndGetWiderMatch ( const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex); if (vLimit > iHighLimit) vLimit = iHighLimit; mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; - back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->base + dictCtx->dictLimit) : 0; + back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0; mlt -= back; if (mlt > longest) { longest = mlt; - *matchpos = base + matchIndex + back; + *matchpos = prefixPtr - prefixIdx + matchIndex + back; *startpos = ip + back; } } @@ -441,13 +446,13 @@ LZ4HC_InsertAndGetWiderMatch ( return longest; } -LZ4_FORCE_INLINE -int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */ - const BYTE* const ip, const BYTE* const iLimit, - const BYTE** matchpos, - const int maxNbAttempts, - const int patternAnalysis, - const dictCtx_directive dict) +LZ4_FORCE_INLINE int +LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */ + const BYTE* const ip, const BYTE* const iLimit, + const BYTE** matchpos, + const int maxNbAttempts, + const int patternAnalysis, + const dictCtx_directive dict) { const BYTE* uselessPtr = ip; /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), @@ -460,74 +465,90 @@ int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index tabl * @return : 0 if ok, * 1 if buffer issue detected */ LZ4_FORCE_INLINE int LZ4HC_encodeSequence ( - const BYTE** ip, - BYTE** op, - const BYTE** anchor, + const BYTE** _ip, + BYTE** _op, + const BYTE** _anchor, int matchLength, const BYTE* const match, limitedOutput_directive limit, BYTE* oend) { +#define ip (*_ip) +#define op (*_op) +#define anchor (*_anchor) + size_t length; - BYTE* const token = (*op)++; + BYTE* const token = op++; #if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6) static const BYTE* start = NULL; static U32 totalCost = 0; - U32 const pos = (start==NULL) ? 0 : (U32)(*anchor - start); - U32 const ll = (U32)(*ip - *anchor); + U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start); + U32 const ll = (U32)(ip - anchor); U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0; U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0; U32 const cost = 1 + llAdd + ll + 2 + mlAdd; - if (start==NULL) start = *anchor; /* only works for single segment */ + if (start==NULL) start = anchor; /* only works for single segment */ /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */ - DEBUGLOG(6, "pos:%7u -- literals:%3u, match:%4i, offset:%5u, cost:%3u + %u", + DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u", pos, - (U32)(*ip - *anchor), matchLength, (U32)(*ip-match), + (U32)(ip - anchor), matchLength, (U32)(ip-match), cost, totalCost); totalCost += cost; #endif /* Encode Literal length */ - length = (size_t)(*ip - *anchor); - if ((limit) && ((*op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */ + length = (size_t)(ip - anchor); + LZ4_STATIC_ASSERT(notLimited == 0); + /* Check output limit */ + if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) { + DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)", + (int)length, (int)(oend - op)); + return 1; + } if (length >= RUN_MASK) { size_t len = length - RUN_MASK; *token = (RUN_MASK << ML_BITS); - for(; len >= 255 ; len -= 255) *(*op)++ = 255; - *(*op)++ = (BYTE)len; + for(; len >= 255 ; len -= 255) *op++ = 255; + *op++ = (BYTE)len; } else { *token = (BYTE)(length << ML_BITS); } /* Copy Literals */ - LZ4_wildCopy8(*op, *anchor, (*op) + length); - *op += length; + LZ4_wildCopy8(op, anchor, op + length); + op += length; /* Encode Offset */ - assert( (*ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */ - LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2; + assert( (ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */ + LZ4_writeLE16(op, (U16)(ip - match)); op += 2; /* Encode MatchLength */ assert(matchLength >= MINMATCH); length = (size_t)matchLength - MINMATCH; - if ((limit) && (*op + (length / 255) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */ + if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) { + DEBUGLOG(6, "Not enough room to write match length"); + return 1; /* Check output limit */ + } if (length >= ML_MASK) { *token += ML_MASK; length -= ML_MASK; - for(; length >= 510 ; length -= 510) { *(*op)++ = 255; *(*op)++ = 255; } - if (length >= 255) { length -= 255; *(*op)++ = 255; } - *(*op)++ = (BYTE)length; + for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; } + if (length >= 255) { length -= 255; *op++ = 255; } + *op++ = (BYTE)length; } else { *token += (BYTE)(length); } /* Prepare next loop */ - *ip += matchLength; - *anchor = *ip; + ip += matchLength; + anchor = ip; return 0; } +#undef ip +#undef op +#undef anchor LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( LZ4HC_CCtx_internal* const ctx, @@ -535,7 +556,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( char* const dest, int* srcSizePtr, int const maxOutputSize, - unsigned maxNbAttempts, + int maxNbAttempts, const limitedOutput_directive limit, const dictCtx_directive dict ) @@ -565,7 +586,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( /* init */ *srcSizePtr = 0; if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ - if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ + if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ /* Main Loop */ while (ip <= mflimit) { @@ -637,7 +658,11 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow; ip = start2; optr = op; - if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) goto _dest_overflow; + if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) { + ml = ml2; + ref = ref2; + goto _dest_overflow; + } continue; } @@ -709,17 +734,18 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( _last_literals: /* Encode Last Literals */ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */ - size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255; - size_t const totalSize = 1 + litLength + lastRunSize; + size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255; + size_t const totalSize = 1 + llAdd + lastRunSize; if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit && (op + totalSize > oend)) { - if (limit == limitedOutput) return 0; /* Check output limit */ + if (limit == limitedOutput) return 0; /* adapt lastRunSize to fill 'dest' */ - lastRunSize = (size_t)(oend - op) - 1; - litLength = (lastRunSize + 255 - RUN_MASK) / 255; - lastRunSize -= litLength; + lastRunSize = (size_t)(oend - op) - 1 /*token*/; + llAdd = (lastRunSize + 256 - RUN_MASK) / 256; + lastRunSize -= llAdd; } - ip = anchor + lastRunSize; + DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize); + ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */ if (lastRunSize >= RUN_MASK) { size_t accumulator = lastRunSize - RUN_MASK; @@ -729,7 +755,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( } else { *op++ = (BYTE)(lastRunSize << ML_BITS); } - memcpy(op, anchor, lastRunSize); + LZ4_memcpy(op, anchor, lastRunSize); op += lastRunSize; } @@ -739,9 +765,25 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( _dest_overflow: if (limit == fillOutput) { + /* Assumption : ip, anchor, ml and ref must be set correctly */ + size_t const ll = (size_t)(ip - anchor); + size_t const ll_addbytes = (ll + 240) / 255; + size_t const ll_totalCost = 1 + ll_addbytes + ll; + BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */ + DEBUGLOG(6, "Last sequence overflowing"); op = optr; /* restore correct out pointer */ + if (op + ll_totalCost <= maxLitPos) { + /* ll validated; now adjust match length */ + size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost)); + size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255); + assert(maxMlSize < INT_MAX); assert(ml >= 0); + if ((size_t)ml > maxMlSize) ml = (int)maxMlSize; + if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) { + LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend); + } } goto _last_literals; } + /* compression failed */ return 0; } @@ -752,7 +794,7 @@ static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx, int const nbSearches, size_t sufficient_len, const limitedOutput_directive limit, int const fullUpdate, const dictCtx_directive dict, - HCfavor_e favorDecSpeed); + const HCfavor_e favorDecSpeed); LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal ( @@ -769,7 +811,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal ( typedef enum { lz4hc, lz4opt } lz4hc_strat_e; typedef struct { lz4hc_strat_e strat; - U32 nbSearches; + int nbSearches; U32 targetLength; } cParams_t; static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = { @@ -788,7 +830,8 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal ( { lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */ }; - DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d)", ctx, src, *srcSizePtr); + DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)", + ctx, src, *srcSizePtr, limit); if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */ @@ -808,7 +851,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal ( assert(cParam.strat == lz4opt); result = LZ4HC_compress_optimal(ctx, src, dst, srcSizePtr, dstCapacity, - (int)cParam.nbSearches, cParam.targetLength, limit, + cParam.nbSearches, cParam.targetLength, limit, cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */ dict, favor); } @@ -845,13 +888,13 @@ LZ4HC_compress_generic_dictCtx ( limitedOutput_directive limit ) { - const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit; + const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit); assert(ctx->dictCtx != NULL); if (position >= 64 KB) { ctx->dictCtx = NULL; return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); } else if (position == 0 && *srcSizePtr > 4 KB) { - memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal)); + LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal)); LZ4HC_setExternalDict(ctx, (const BYTE *)src); ctx->compressionLevel = (short)cLevel; return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); @@ -881,27 +924,22 @@ LZ4HC_compress_generic ( int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); } -#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 : - * it reports an aligment of 8-bytes, - * while actually aligning LZ4_streamHC_t on 4 bytes. */ static size_t LZ4_streamHC_t_alignment(void) { - struct { char c; LZ4_streamHC_t t; } t_a; - return sizeof(t_a) - sizeof(t_a.t); -} +#if LZ4_ALIGN_TEST + typedef struct { char c; LZ4_streamHC_t t; } t_a; + return sizeof(t_a) - sizeof(LZ4_streamHC_t); +#else + return 1; /* effectively disabled */ #endif +} /* state is presumed correctly initialized, * in which case its size and alignment have already been validate */ int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) { LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; -#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 : - * it reports an aligment of 8-bytes, - * while actually aligning LZ4_streamHC_t on 4 bytes. */ - assert(((size_t)state & (LZ4_streamHC_t_alignment() - 1)) == 0); /* check alignment */ -#endif - if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */ + if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0; LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel); LZ4HC_init_internal (ctx, (const BYTE*)src); if (dstCapacity < LZ4_compressBound(srcSize)) @@ -919,13 +957,15 @@ int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int src int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) { + int cSize; #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t)); + if (statePtr==NULL) return 0; #else LZ4_streamHC_t state; LZ4_streamHC_t* const statePtr = &state; #endif - int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel); + cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel); #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 FREEMEM(statePtr); #endif @@ -948,12 +988,14 @@ int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* s * Streaming Functions **************************************/ /* allocation */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_streamHC_t* LZ4_createStreamHC(void) { - LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t)); - if (LZ4_streamHCPtr==NULL) return NULL; - LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); /* full initialization, malloc'ed buffer can be full of garbage */ - return LZ4_streamHCPtr; + LZ4_streamHC_t* const state = + (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t)); + if (state == NULL) return NULL; + LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT); + return state; } int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) @@ -963,27 +1005,20 @@ int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) FREEMEM(LZ4_streamHCPtr); return 0; } +#endif LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size) { LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer; + DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size); + /* check conditions */ if (buffer == NULL) return NULL; if (size < sizeof(LZ4_streamHC_t)) return NULL; -#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 : - * it reports an aligment of 8-bytes, - * while actually aligning LZ4_streamHC_t on 4 bytes. */ - if (((size_t)buffer) & (LZ4_streamHC_t_alignment() - 1)) return NULL; /* alignment check */ -#endif - /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */ - LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE); - DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", LZ4_streamHCPtr, (unsigned)size); - /* end-base will trigger a clearTable on starting compression */ - LZ4_streamHCPtr->internal_donotuse.end = (const BYTE *)(ptrdiff_t)-1; - LZ4_streamHCPtr->internal_donotuse.base = NULL; - LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL; - LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = 0; - LZ4_streamHCPtr->internal_donotuse.dirty = 0; + if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL; + /* init */ + { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse); + MEM_INIT(hcstate, 0, sizeof(*hcstate)); } LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT); return LZ4_streamHCPtr; } @@ -1001,9 +1036,13 @@ void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLev if (LZ4_streamHCPtr->internal_donotuse.dirty) { LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); } else { - /* preserve end - base : can trigger clearTable's threshold */ - LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.base; - LZ4_streamHCPtr->internal_donotuse.base = NULL; + /* preserve end - prefixStart : can trigger clearTable's threshold */ + if (LZ4_streamHCPtr->internal_donotuse.end != NULL) { + LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.prefixStart; + } else { + assert(LZ4_streamHCPtr->internal_donotuse.prefixStart == NULL); + } + LZ4_streamHCPtr->internal_donotuse.prefixStart = NULL; LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL; } LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel); @@ -1028,7 +1067,7 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize) { LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; - DEBUGLOG(4, "LZ4_loadDictHC(%p, %p, %d)", LZ4_streamHCPtr, dictionary, dictSize); + DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize); assert(LZ4_streamHCPtr != NULL); if (dictSize > 64 KB) { dictionary += (size_t)dictSize - 64 KB; @@ -1054,14 +1093,14 @@ void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) { DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock); - if (ctxPtr->end >= ctxPtr->base + ctxPtr->dictLimit + 4) + if (ctxPtr->end >= ctxPtr->prefixStart + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ /* Only one memory segment for extDict, so any previous extDict is lost at this stage */ ctxPtr->lowLimit = ctxPtr->dictLimit; - ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base); - ctxPtr->dictBase = ctxPtr->base; - ctxPtr->base = newBlock - ctxPtr->dictLimit; + ctxPtr->dictStart = ctxPtr->prefixStart; + ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart); + ctxPtr->prefixStart = newBlock; ctxPtr->end = newBlock; ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */ @@ -1069,21 +1108,22 @@ static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBl ctxPtr->dictCtx = NULL; } -static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, - const char* src, char* dst, - int* srcSizePtr, int dstCapacity, - limitedOutput_directive limit) +static int +LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, + const char* src, char* dst, + int* srcSizePtr, int dstCapacity, + limitedOutput_directive limit) { LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; - DEBUGLOG(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)", - LZ4_streamHCPtr, src, *srcSizePtr); + DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)", + LZ4_streamHCPtr, src, *srcSizePtr, limit); assert(ctxPtr != NULL); /* auto-init if forgotten */ - if (ctxPtr->base == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src); + if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src); /* Check overflow */ - if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) { - size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit; + if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) { + size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart); if (dictSize > 64 KB) dictSize = 64 KB; LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize); } @@ -1094,14 +1134,16 @@ static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, /* Check overlapping input/dictionary space */ { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr; - const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; - const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; + const BYTE* const dictBegin = ctxPtr->dictStart; + const BYTE* const dictEnd = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit); if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) { if (sourceEnd > dictEnd) sourceEnd = dictEnd; - ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase); - if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit; - } - } + ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart); + ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart); + if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) { + ctxPtr->lowLimit = ctxPtr->dictLimit; + ctxPtr->dictStart = ctxPtr->prefixStart; + } } } return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit); } @@ -1121,23 +1163,31 @@ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const ch -/* dictionary saving */ - +/* LZ4_saveDictHC : + * save history content + * into a user-provided buffer + * which is then used to continue compression + */ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize) { LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; - int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); - DEBUGLOG(4, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize); + int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart); + DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize); + assert(prefixSize >= 0); if (dictSize > 64 KB) dictSize = 64 KB; if (dictSize < 4) dictSize = 0; if (dictSize > prefixSize) dictSize = prefixSize; - memmove(safeBuffer, streamPtr->end - dictSize, dictSize); - { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base); + if (safeBuffer == NULL) assert(dictSize == 0); + if (dictSize > 0) + LZ4_memmove(safeBuffer, streamPtr->end - dictSize, dictSize); + { U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit; streamPtr->end = (const BYTE*)safeBuffer + dictSize; - streamPtr->base = streamPtr->end - endIndex; + streamPtr->prefixStart = streamPtr->end - dictSize; streamPtr->dictLimit = endIndex - (U32)dictSize; streamPtr->lowLimit = endIndex - (U32)dictSize; - if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit; + streamPtr->dictStart = streamPtr->prefixStart; + if (streamPtr->nextToUpdate < streamPtr->dictLimit) + streamPtr->nextToUpdate = streamPtr->dictLimit; } return dictSize; } @@ -1163,7 +1213,7 @@ int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, /* Deprecated streaming functions */ -int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; } +int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); } /* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t) * @return : 0 on success, !=0 if error */ @@ -1175,6 +1225,7 @@ int LZ4_resetStreamStateHC(void* state, char* inputBuffer) return 0; } +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) void* LZ4_createHC (const char* inputBuffer) { LZ4_streamHC_t* const hc4 = LZ4_createStreamHC(); @@ -1189,6 +1240,7 @@ int LZ4_freeHC (void* LZ4HC_Data) FREEMEM(LZ4HC_Data); return 0; } +#endif int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel) { @@ -1202,11 +1254,11 @@ int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, c char* LZ4_slideInputBufferHC(void* LZ4HC_Data) { - LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data; - const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit; + LZ4_streamHC_t* const ctx = (LZ4_streamHC_t*)LZ4HC_Data; + const BYTE* bufferStart = ctx->internal_donotuse.prefixStart - ctx->internal_donotuse.dictLimit + ctx->internal_donotuse.lowLimit; LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel); /* avoid const char * -> char * conversion warning :( */ - return (char *)(uptrval)bufferStart; + return (char*)(uptrval)bufferStart; } @@ -1287,8 +1339,13 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, const dictCtx_directive dict, const HCfavor_e favorDecSpeed) { + int retval = 0; #define TRAILING_LITERALS 3 +#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 + LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS)); +#else LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */ +#endif const BYTE* ip = (const BYTE*) source; const BYTE* anchor = ip; @@ -1298,15 +1355,19 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, BYTE* op = (BYTE*) dst; BYTE* opSaved = (BYTE*) dst; BYTE* oend = op + dstCapacity; + int ovml = MINMATCH; /* overflow - last sequence */ + const BYTE* ovref = NULL; /* init */ +#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 + if (opt == NULL) goto _return_label; +#endif DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity); *srcSizePtr = 0; if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1; /* Main Loop */ - assert(ip - anchor < LZ4_MAX_INPUT_SIZE); while (ip <= mflimit) { int const llen = (int)(ip - anchor); int best_mlen, best_off; @@ -1320,8 +1381,11 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, int const firstML = firstMatch.len; const BYTE* const matchPos = ip - firstMatch.off; opSaved = op; - if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) /* updates ip, op and anchor */ + if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) { /* updates ip, op and anchor */ + ovml = firstML; + ovref = matchPos; goto _dest_overflow; + } continue; } @@ -1463,7 +1527,7 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, best_off = opt[last_match_pos].off; cur = last_match_pos - best_mlen; - encode: /* cur, last_match_pos, best_mlen, best_off must be set */ +encode: /* cur, last_match_pos, best_mlen, best_off must be set */ assert(cur < LZ4_OPT_NUM); assert(last_match_pos >= 1); /* == 1 when only one candidate */ DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos); @@ -1493,25 +1557,31 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, assert(ml >= MINMATCH); assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX)); opSaved = op; - if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) /* updates ip, op and anchor */ + if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) { /* updates ip, op and anchor */ + ovml = ml; + ovref = ip - offset; goto _dest_overflow; - } } + } } } } /* while (ip <= mflimit) */ - _last_literals: +_last_literals: /* Encode Last Literals */ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */ - size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255; - size_t const totalSize = 1 + litLength + lastRunSize; + size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255; + size_t const totalSize = 1 + llAdd + lastRunSize; if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit && (op + totalSize > oend)) { - if (limit == limitedOutput) return 0; /* Check output limit */ + if (limit == limitedOutput) { /* Check output limit */ + retval = 0; + goto _return_label; + } /* adapt lastRunSize to fill 'dst' */ - lastRunSize = (size_t)(oend - op) - 1; - litLength = (lastRunSize + 255 - RUN_MASK) / 255; - lastRunSize -= litLength; + lastRunSize = (size_t)(oend - op) - 1 /*token*/; + llAdd = (lastRunSize + 256 - RUN_MASK) / 256; + lastRunSize -= llAdd; } - ip = anchor + lastRunSize; + DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize); + ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */ if (lastRunSize >= RUN_MASK) { size_t accumulator = lastRunSize - RUN_MASK; @@ -1521,18 +1591,41 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, } else { *op++ = (BYTE)(lastRunSize << ML_BITS); } - memcpy(op, anchor, lastRunSize); + LZ4_memcpy(op, anchor, lastRunSize); op += lastRunSize; } /* End */ *srcSizePtr = (int) (((const char*)ip) - source); - return (int) ((char*)op-dst); + retval = (int) ((char*)op-dst); + goto _return_label; - _dest_overflow: - if (limit == fillOutput) { - op = opSaved; /* restore correct out pointer */ - goto _last_literals; - } - return 0; - } +_dest_overflow: +if (limit == fillOutput) { + /* Assumption : ip, anchor, ovml and ovref must be set correctly */ + size_t const ll = (size_t)(ip - anchor); + size_t const ll_addbytes = (ll + 240) / 255; + size_t const ll_totalCost = 1 + ll_addbytes + ll; + BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */ + DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved)); + op = opSaved; /* restore correct out pointer */ + if (op + ll_totalCost <= maxLitPos) { + /* ll validated; now adjust match length */ + size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost)); + size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255); + assert(maxMlSize < INT_MAX); assert(ovml >= 0); + if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize; + if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) { + DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml); + DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor); + LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend); + DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor); + } } + goto _last_literals; +} +_return_label: +#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 + FREEMEM(opt); +#endif + return retval; +} diff --git a/native/lz4/lz4hc.h b/native/lz4/lz4hc.h index 44e35bb..e937acf 100644 --- a/native/lz4/lz4hc.h +++ b/native/lz4/lz4hc.h @@ -1,7 +1,7 @@ /* LZ4 HC - High Compression Mode of LZ4 Header File - Copyright (C) 2011-2017, Yann Collet. + Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without @@ -198,63 +198,36 @@ LZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, in #define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1) -#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -#include - -typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal; -struct LZ4HC_CCtx_internal -{ - uint32_t hashTable[LZ4HC_HASHTABLESIZE]; - uint16_t chainTable[LZ4HC_MAXD]; - const uint8_t* end; /* next block here to continue on current prefix */ - const uint8_t* base; /* All index relative to this position */ - const uint8_t* dictBase; /* alternate base for extDict */ - uint32_t dictLimit; /* below that point, need extDict */ - uint32_t lowLimit; /* below that point, no more dict */ - uint32_t nextToUpdate; /* index from which to continue dictionary update */ - short compressionLevel; - int8_t favorDecSpeed; /* favor decompression speed if this flag set, - otherwise, favor compression ratio */ - int8_t dirty; /* stream has to be fully reset if this flag is set */ - const LZ4HC_CCtx_internal* dictCtx; -}; - -#else - +/* Never ever use these definitions directly ! + * Declare or allocate an LZ4_streamHC_t instead. +**/ typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal; struct LZ4HC_CCtx_internal { - unsigned int hashTable[LZ4HC_HASHTABLESIZE]; - unsigned short chainTable[LZ4HC_MAXD]; - const unsigned char* end; /* next block here to continue on current prefix */ - const unsigned char* base; /* All index relative to this position */ - const unsigned char* dictBase; /* alternate base for extDict */ - unsigned int dictLimit; /* below that point, need extDict */ - unsigned int lowLimit; /* below that point, no more dict */ - unsigned int nextToUpdate; /* index from which to continue dictionary update */ - short compressionLevel; - char favorDecSpeed; /* favor decompression speed if this flag set, - otherwise, favor compression ratio */ - char dirty; /* stream has to be fully reset if this flag is set */ + LZ4_u32 hashTable[LZ4HC_HASHTABLESIZE]; + LZ4_u16 chainTable[LZ4HC_MAXD]; + const LZ4_byte* end; /* next block here to continue on current prefix */ + const LZ4_byte* prefixStart; /* Indexes relative to this position */ + const LZ4_byte* dictStart; /* alternate reference for extDict */ + LZ4_u32 dictLimit; /* below that point, need extDict */ + LZ4_u32 lowLimit; /* below that point, no more dict */ + LZ4_u32 nextToUpdate; /* index from which to continue dictionary update */ + short compressionLevel; + LZ4_i8 favorDecSpeed; /* favor decompression speed if this flag set, + otherwise, favor compression ratio */ + LZ4_i8 dirty; /* stream has to be fully reset if this flag is set */ const LZ4HC_CCtx_internal* dictCtx; }; -#endif - - -/* Do not use these definitions directly ! - * Declare or allocate an LZ4_streamHC_t instead. - */ -#define LZ4_STREAMHCSIZE (4*LZ4HC_HASHTABLESIZE + 2*LZ4HC_MAXD + 56 + ((sizeof(void*)==16) ? 56 : 0) /* AS400*/ ) /* 262200 or 262256*/ -#define LZ4_STREAMHCSIZE_SIZET (LZ4_STREAMHCSIZE / sizeof(size_t)) +#define LZ4_STREAMHC_MINSIZE 262200 /* static size, for inter-version compatibility */ union LZ4_streamHC_u { - size_t table[LZ4_STREAMHCSIZE_SIZET]; + char minStateSize[LZ4_STREAMHC_MINSIZE]; LZ4HC_CCtx_internal internal_donotuse; }; /* previously typedef'd to LZ4_streamHC_t */ /* LZ4_streamHC_t : * This structure allows static allocation of LZ4 HC streaming state. - * This can be used to allocate statically, on state, or as part of a larger structure. + * This can be used to allocate statically on stack, or as part of a larger structure. * * Such state **must** be initialized using LZ4_initStreamHC() before first use. * @@ -269,7 +242,7 @@ union LZ4_streamHC_u { * Required before first use of a statically allocated LZ4_streamHC_t. * Before v1.9.0 : use LZ4_resetStreamHC() instead */ -LZ4LIB_API LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size); +LZ4LIB_API LZ4_streamHC_t* LZ4_initStreamHC(void* buffer, size_t size); /*-************************************ @@ -297,9 +270,11 @@ LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_comp * LZ4_slideInputBufferHC() will truncate the history of the stream, rather * than preserve a window-sized chunk of history. */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API void* LZ4_createHC (const char* inputBuffer); -LZ4_DEPRECATED("use LZ4_saveDictHC() instead") LZ4LIB_API char* LZ4_slideInputBufferHC (void* LZ4HC_Data); LZ4_DEPRECATED("use LZ4_freeStreamHC() instead") LZ4LIB_API int LZ4_freeHC (void* LZ4HC_Data); +#endif +LZ4_DEPRECATED("use LZ4_saveDictHC() instead") LZ4LIB_API char* LZ4_slideInputBufferHC (void* LZ4HC_Data); LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel); LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API int LZ4_sizeofStreamStateHC(void); @@ -330,7 +305,7 @@ LZ4LIB_API void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionL * They should not be linked from DLL, * as there is no guarantee of API stability yet. * Prototypes will be promoted to "stable" status - * after successfull usage in real-life scenarios. + * after successful usage in real-life scenarios. ***************************************************/ #ifdef LZ4_HC_STATIC_LINKING_ONLY /* protection macro */ #ifndef LZ4_HC_SLO_098092834 From 398f7263e7310bedf9e45c0e9b449e28796191f2 Mon Sep 17 00:00:00 2001 From: giuseppe Date: Fri, 2 Sep 2022 09:44:07 +0200 Subject: [PATCH 02/10] imported zstd v1.5.2 --- native/zstd/BUCK | 12 +- native/zstd/Makefile | 414 +- native/zstd/README.md | 94 +- native/zstd/common/bits.h | 175 + native/zstd/common/bitstream.h | 169 +- native/zstd/common/compiler.h | 218 +- native/zstd/common/cpu.h | 4 +- native/zstd/common/debug.c | 42 +- native/zstd/common/debug.h | 71 +- native/zstd/common/entropy_common.c | 263 +- native/zstd/common/error_private.c | 7 +- native/zstd/common/error_private.h | 91 +- native/zstd/common/fse.h | 95 +- native/zstd/common/fse_decompress.c | 210 +- native/zstd/common/huf.h | 114 +- native/zstd/common/mem.h | 219 +- native/zstd/common/pool.c | 75 +- native/zstd/common/pool.h | 16 +- native/zstd/common/portability_macros.h | 148 + native/zstd/common/threading.c | 20 +- native/zstd/common/threading.h | 7 +- native/zstd/common/xxhash.c | 888 +-- native/zstd/common/xxhash.h | 5763 ++++++++++++++++- native/zstd/common/zstd_common.c | 20 +- native/zstd/common/zstd_deps.h | 111 + native/zstd/common/zstd_internal.h | 322 +- native/zstd/common/zstd_trace.h | 163 + native/zstd/compress/clevels.h | 134 + native/zstd/compress/fse_compress.c | 197 +- native/zstd/compress/hist.c | 104 +- native/zstd/compress/hist.h | 46 +- native/zstd/compress/huf_compress.c | 1206 +++- native/zstd/compress/zstd_compress.c | 4525 ++++++++++--- native/zstd/compress/zstd_compress_internal.h | 714 +- native/zstd/compress/zstd_compress_literals.c | 79 +- native/zstd/compress/zstd_compress_literals.h | 6 +- .../zstd/compress/zstd_compress_sequences.c | 97 +- .../zstd/compress/zstd_compress_sequences.h | 13 +- .../zstd/compress/zstd_compress_superblock.c | 579 ++ .../zstd/compress/zstd_compress_superblock.h | 32 + native/zstd/compress/zstd_cwksp.h | 331 +- native/zstd/compress/zstd_double_fast.c | 548 +- native/zstd/compress/zstd_double_fast.h | 7 +- native/zstd/compress/zstd_fast.c | 982 ++- native/zstd/compress/zstd_fast.h | 7 +- native/zstd/compress/zstd_lazy.c | 1489 ++++- native/zstd/compress/zstd_lazy.h | 60 +- native/zstd/compress/zstd_ldm.c | 551 +- native/zstd/compress/zstd_ldm.h | 18 +- native/zstd/compress/zstd_ldm_geartab.h | 106 + native/zstd/compress/zstd_opt.c | 703 +- native/zstd/compress/zstd_opt.h | 2 +- native/zstd/compress/zstdmt_compress.c | 674 +- native/zstd/compress/zstdmt_compress.h | 149 +- native/zstd/decompress/huf_decompress.c | 1477 +++-- native/zstd/decompress/huf_decompress_amd64.S | 574 ++ native/zstd/decompress/zstd_ddict.c | 38 +- native/zstd/decompress/zstd_ddict.h | 6 +- native/zstd/decompress/zstd_decompress.c | 962 ++- .../zstd/decompress/zstd_decompress_block.c | 1431 +++- .../zstd/decompress/zstd_decompress_block.h | 23 +- .../decompress/zstd_decompress_internal.h | 84 +- native/zstd/deprecated/zbuff.h | 6 +- native/zstd/deprecated/zbuff_common.c | 4 +- native/zstd/deprecated/zbuff_compress.c | 28 +- native/zstd/deprecated/zbuff_decompress.c | 2 +- native/zstd/dictBuilder/cover.c | 100 +- native/zstd/dictBuilder/cover.h | 29 +- native/zstd/dictBuilder/divsufsort.c | 2 +- native/zstd/dictBuilder/divsufsort.h | 0 native/zstd/dictBuilder/fastcover.c | 91 +- native/zstd/dictBuilder/zdict.c | 222 +- native/zstd/dll/example/Makefile | 3 +- native/zstd/dll/example/README.md | 40 +- native/zstd/dll/example/build_package.bat | 40 +- native/zstd/dll/example/fullbench-dll.sln | 50 +- native/zstd/dll/example/fullbench-dll.vcxproj | 360 +- native/zstd/legacy/zstd_legacy.h | 8 +- native/zstd/legacy/zstd_v01.c | 44 +- native/zstd/legacy/zstd_v01.h | 2 +- native/zstd/legacy/zstd_v02.c | 36 +- native/zstd/legacy/zstd_v02.h | 2 +- native/zstd/legacy/zstd_v03.c | 36 +- native/zstd/legacy/zstd_v03.h | 2 +- native/zstd/legacy/zstd_v04.c | 42 +- native/zstd/legacy/zstd_v04.h | 2 +- native/zstd/legacy/zstd_v05.c | 64 +- native/zstd/legacy/zstd_v05.h | 4 +- native/zstd/legacy/zstd_v06.c | 64 +- native/zstd/legacy/zstd_v06.h | 2 +- native/zstd/legacy/zstd_v07.c | 70 +- native/zstd/legacy/zstd_v07.h | 2 +- native/zstd/libzstd.mk | 207 + native/zstd/libzstd.pc.in | 7 +- native/zstd/module.modulemap | 25 + native/zstd/zdict.h | 452 ++ native/zstd/zstd.h | 1069 ++- native/zstd/zstd_errors.h | 96 + 98 files changed, 23497 insertions(+), 7401 deletions(-) create mode 100644 native/zstd/common/bits.h mode change 100755 => 100644 native/zstd/common/bitstream.h mode change 100755 => 100644 native/zstd/common/compiler.h mode change 100755 => 100644 native/zstd/common/cpu.h mode change 100755 => 100644 native/zstd/common/debug.c mode change 100755 => 100644 native/zstd/common/debug.h mode change 100755 => 100644 native/zstd/common/entropy_common.c mode change 100755 => 100644 native/zstd/common/error_private.c mode change 100755 => 100644 native/zstd/common/error_private.h mode change 100755 => 100644 native/zstd/common/fse.h mode change 100755 => 100644 native/zstd/common/fse_decompress.c mode change 100755 => 100644 native/zstd/common/huf.h mode change 100755 => 100644 native/zstd/common/mem.h mode change 100755 => 100644 native/zstd/common/pool.c mode change 100755 => 100644 native/zstd/common/pool.h create mode 100644 native/zstd/common/portability_macros.h mode change 100755 => 100644 native/zstd/common/threading.c mode change 100755 => 100644 native/zstd/common/threading.h mode change 100755 => 100644 native/zstd/common/xxhash.c mode change 100755 => 100644 native/zstd/common/xxhash.h mode change 100755 => 100644 native/zstd/common/zstd_common.c create mode 100644 native/zstd/common/zstd_deps.h mode change 100755 => 100644 native/zstd/common/zstd_internal.h create mode 100644 native/zstd/common/zstd_trace.h create mode 100644 native/zstd/compress/clevels.h mode change 100755 => 100644 native/zstd/compress/fse_compress.c mode change 100755 => 100644 native/zstd/compress/hist.c mode change 100755 => 100644 native/zstd/compress/hist.h mode change 100755 => 100644 native/zstd/compress/huf_compress.c mode change 100755 => 100644 native/zstd/compress/zstd_compress.c mode change 100755 => 100644 native/zstd/compress/zstd_compress_internal.h mode change 100755 => 100644 native/zstd/compress/zstd_compress_literals.c mode change 100755 => 100644 native/zstd/compress/zstd_compress_literals.h mode change 100755 => 100644 native/zstd/compress/zstd_compress_sequences.c mode change 100755 => 100644 native/zstd/compress/zstd_compress_sequences.h create mode 100644 native/zstd/compress/zstd_compress_superblock.c create mode 100644 native/zstd/compress/zstd_compress_superblock.h mode change 100755 => 100644 native/zstd/compress/zstd_cwksp.h mode change 100755 => 100644 native/zstd/compress/zstd_double_fast.c mode change 100755 => 100644 native/zstd/compress/zstd_double_fast.h mode change 100755 => 100644 native/zstd/compress/zstd_fast.c mode change 100755 => 100644 native/zstd/compress/zstd_fast.h mode change 100755 => 100644 native/zstd/compress/zstd_lazy.c mode change 100755 => 100644 native/zstd/compress/zstd_lazy.h mode change 100755 => 100644 native/zstd/compress/zstd_ldm.c mode change 100755 => 100644 native/zstd/compress/zstd_ldm.h create mode 100644 native/zstd/compress/zstd_ldm_geartab.h mode change 100755 => 100644 native/zstd/compress/zstd_opt.c mode change 100755 => 100644 native/zstd/compress/zstd_opt.h mode change 100755 => 100644 native/zstd/compress/zstdmt_compress.c mode change 100755 => 100644 native/zstd/compress/zstdmt_compress.h mode change 100755 => 100644 native/zstd/decompress/huf_decompress.c create mode 100644 native/zstd/decompress/huf_decompress_amd64.S mode change 100755 => 100644 native/zstd/decompress/zstd_ddict.c mode change 100755 => 100644 native/zstd/decompress/zstd_ddict.h mode change 100755 => 100644 native/zstd/decompress/zstd_decompress.c mode change 100755 => 100644 native/zstd/decompress/zstd_decompress_block.c mode change 100755 => 100644 native/zstd/decompress/zstd_decompress_block.h mode change 100755 => 100644 native/zstd/decompress/zstd_decompress_internal.h mode change 100755 => 100644 native/zstd/deprecated/zbuff.h mode change 100755 => 100644 native/zstd/deprecated/zbuff_common.c mode change 100755 => 100644 native/zstd/deprecated/zbuff_compress.c mode change 100755 => 100644 native/zstd/deprecated/zbuff_decompress.c mode change 100755 => 100644 native/zstd/dictBuilder/cover.c mode change 100755 => 100644 native/zstd/dictBuilder/cover.h mode change 100755 => 100644 native/zstd/dictBuilder/divsufsort.c mode change 100755 => 100644 native/zstd/dictBuilder/divsufsort.h mode change 100755 => 100644 native/zstd/dictBuilder/fastcover.c mode change 100755 => 100644 native/zstd/dictBuilder/zdict.c mode change 100755 => 100644 native/zstd/dll/example/Makefile mode change 100755 => 100644 native/zstd/dll/example/README.md mode change 100755 => 100644 native/zstd/dll/example/build_package.bat mode change 100755 => 100644 native/zstd/dll/example/fullbench-dll.sln mode change 100755 => 100644 native/zstd/dll/example/fullbench-dll.vcxproj mode change 100755 => 100644 native/zstd/legacy/zstd_legacy.h mode change 100755 => 100644 native/zstd/legacy/zstd_v01.c mode change 100755 => 100644 native/zstd/legacy/zstd_v01.h mode change 100755 => 100644 native/zstd/legacy/zstd_v02.c mode change 100755 => 100644 native/zstd/legacy/zstd_v02.h mode change 100755 => 100644 native/zstd/legacy/zstd_v03.c mode change 100755 => 100644 native/zstd/legacy/zstd_v03.h mode change 100755 => 100644 native/zstd/legacy/zstd_v04.c mode change 100755 => 100644 native/zstd/legacy/zstd_v04.h mode change 100755 => 100644 native/zstd/legacy/zstd_v05.c mode change 100755 => 100644 native/zstd/legacy/zstd_v05.h mode change 100755 => 100644 native/zstd/legacy/zstd_v06.c mode change 100755 => 100644 native/zstd/legacy/zstd_v06.h mode change 100755 => 100644 native/zstd/legacy/zstd_v07.c mode change 100755 => 100644 native/zstd/legacy/zstd_v07.h create mode 100644 native/zstd/libzstd.mk create mode 100644 native/zstd/module.modulemap create mode 100644 native/zstd/zdict.h create mode 100644 native/zstd/zstd_errors.h diff --git a/native/zstd/BUCK b/native/zstd/BUCK index 637c20d..60c6bbb 100644 --- a/native/zstd/BUCK +++ b/native/zstd/BUCK @@ -65,9 +65,7 @@ cxx_library( name='zdict', header_namespace='', visibility=['PUBLIC'], - exported_headers=subdir_glob([ - ('dictBuilder', 'zdict.h'), - ]), + exported_headers=['zdict.h'], headers=subdir_glob([ ('dictBuilder', 'divsufsort.h'), ('dictBuilder', 'cover.h'), @@ -131,10 +129,10 @@ cxx_library( name='errors', header_namespace='', visibility=['PUBLIC'], - exported_headers=subdir_glob([ - ('common', 'error_private.h'), - ('common', 'zstd_errors.h'), - ]), + exported_headers=[ + 'zstd_errors.h', + 'common/error_private.h', + ] srcs=['common/error_private.c'], ) diff --git a/native/zstd/Makefile b/native/zstd/Makefile index 273ceb9..ef20218 100644 --- a/native/zstd/Makefile +++ b/native/zstd/Makefile @@ -1,216 +1,259 @@ # ################################################################ -# Copyright (c) 2015-present, Yann Collet, Facebook, Inc. +# Copyright (c) Yann Collet, Facebook, Inc. # 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. # ################################################################ -# Version numbers -LIBVER_MAJOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./zstd.h` -LIBVER_MINOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./zstd.h` -LIBVER_PATCH_SCRIPT:=`sed -n '/define ZSTD_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./zstd.h` -LIBVER_SCRIPT:= $(LIBVER_MAJOR_SCRIPT).$(LIBVER_MINOR_SCRIPT).$(LIBVER_PATCH_SCRIPT) -LIBVER_MAJOR := $(shell echo $(LIBVER_MAJOR_SCRIPT)) -LIBVER_MINOR := $(shell echo $(LIBVER_MINOR_SCRIPT)) -LIBVER_PATCH := $(shell echo $(LIBVER_PATCH_SCRIPT)) -LIBVER := $(shell echo $(LIBVER_SCRIPT)) -VERSION?= $(LIBVER) -CCVER := $(shell $(CC) --version) - -CPPFLAGS+= -I. -I./common -DXXH_NAMESPACE=ZSTD_ -ifeq ($(OS),Windows_NT) # MinGW assumed -CPPFLAGS += -D__USE_MINGW_ANSI_STDIO # compatibility with %zu formatting -endif -CFLAGS ?= -O3 -DEBUGFLAGS= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ - -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ - -Wstrict-prototypes -Wundef -Wpointer-arith \ - -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ - -Wredundant-decls -Wmissing-prototypes -Wc++-compat -CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) -FLAGS = $(CPPFLAGS) $(CFLAGS) - -HAVE_COLORNEVER = $(shell echo a | grep --color=never a > /dev/null 2> /dev/null && echo 1 || echo 0) -GREP_OPTIONS ?= -ifeq ($HAVE_COLORNEVER, 1) -GREP_OPTIONS += --color=never -endif -GREP = grep $(GREP_OPTIONS) - -ZSTDCOMMON_FILES := $(sort $(wildcard common/*.c)) -ZSTDCOMP_FILES := $(sort $(wildcard compress/*.c)) -ZSTDDECOMP_FILES := $(sort $(wildcard decompress/*.c)) -ZDICT_FILES := $(sort $(wildcard dictBuilder/*.c)) -ZDEPR_FILES := $(sort $(wildcard deprecated/*.c)) -ZSTD_FILES := $(ZSTDCOMMON_FILES) - -ifeq ($(findstring GCC,$(CCVER)),GCC) -decompress/zstd_decompress_block.o : CFLAGS+=-fno-tree-vectorize -endif - -ZSTD_LEGACY_SUPPORT ?= 5 +# Modules ZSTD_LIB_COMPRESSION ?= 1 ZSTD_LIB_DECOMPRESSION ?= 1 ZSTD_LIB_DICTBUILDER ?= 1 -ZSTD_LIB_DEPRECATED ?= 1 -HUF_FORCE_DECOMPRESS_X1 ?= 0 -HUF_FORCE_DECOMPRESS_X2 ?= 0 -ZSTD_FORCE_DECOMPRESS_SHORT ?= 0 -ZSTD_FORCE_DECOMPRESS_LONG ?= 0 -ZSTD_NO_INLINE ?= 0 -ZSTD_STRIP_ERROR_STRINGS ?= 0 -ZSTD_LEGACY_MULTITHREADED_API ?= 0 +ZSTD_LIB_DEPRECATED ?= 0 +# Input variables for libzstd.mk ifeq ($(ZSTD_LIB_COMPRESSION), 0) - ZSTD_LIB_DICTBUILDER = 0 - ZSTD_LIB_DEPRECATED = 0 + ZSTD_LIB_DICTBUILDER = 0 + ZSTD_LIB_DEPRECATED = 0 endif ifeq ($(ZSTD_LIB_DECOMPRESSION), 0) - ZSTD_LEGACY_SUPPORT = 0 - ZSTD_LIB_DEPRECATED = 0 + ZSTD_LEGACY_SUPPORT = 0 + ZSTD_LIB_DEPRECATED = 0 endif +include libzstd.mk + +ZSTD_FILES := $(ZSTD_COMMON_FILES) $(ZSTD_LEGACY_FILES) + ifneq ($(ZSTD_LIB_COMPRESSION), 0) - ZSTD_FILES += $(ZSTDCOMP_FILES) + ZSTD_FILES += $(ZSTD_COMPRESS_FILES) endif ifneq ($(ZSTD_LIB_DECOMPRESSION), 0) - ZSTD_FILES += $(ZSTDDECOMP_FILES) + ZSTD_FILES += $(ZSTD_DECOMPRESS_FILES) endif ifneq ($(ZSTD_LIB_DEPRECATED), 0) - ZSTD_FILES += $(ZDEPR_FILES) + ZSTD_FILES += $(ZSTD_DEPRECATED_FILES) endif ifneq ($(ZSTD_LIB_DICTBUILDER), 0) - ZSTD_FILES += $(ZDICT_FILES) -endif - -ifneq ($(HUF_FORCE_DECOMPRESS_X1), 0) - CFLAGS += -DHUF_FORCE_DECOMPRESS_X1 + ZSTD_FILES += $(ZSTD_DICTBUILDER_FILES) endif -ifneq ($(HUF_FORCE_DECOMPRESS_X2), 0) - CFLAGS += -DHUF_FORCE_DECOMPRESS_X2 -endif +ZSTD_LOCAL_SRC := $(notdir $(ZSTD_FILES)) +ZSTD_LOCAL_OBJ0 := $(ZSTD_LOCAL_SRC:.c=.o) +ZSTD_LOCAL_OBJ := $(ZSTD_LOCAL_OBJ0:.S=.o) -ifneq ($(ZSTD_FORCE_DECOMPRESS_SHORT), 0) - CFLAGS += -DZSTD_FORCE_DECOMPRESS_SHORT -endif - -ifneq ($(ZSTD_FORCE_DECOMPRESS_LONG), 0) - CFLAGS += -DZSTD_FORCE_DECOMPRESS_LONG -endif +VERSION := $(ZSTD_VERSION) -ifneq ($(ZSTD_NO_INLINE), 0) - CFLAGS += -DZSTD_NO_INLINE -endif +# Note: by default, the static library is built single-threaded and dynamic library is built +# multi-threaded. It is possible to force multi or single threaded builds by appending +# -mt or -nomt to the build target (like lib-mt for multi-threaded, lib-nomt for single-threaded). +.PHONY: default +default: lib-release -ifneq ($(ZSTD_STRIP_ERROR_STRINGS), 0) - CFLAGS += -DZSTD_STRIP_ERROR_STRINGS -endif +CPPFLAGS_DYNLIB += -DZSTD_MULTITHREAD # dynamic library build defaults to multi-threaded +LDFLAGS_DYNLIB += -pthread +CPPFLAGS_STATLIB += # static library build defaults to single-threaded -ifneq ($(ZSTD_LEGACY_MULTITHREADED_API), 0) - CFLAGS += -DZSTD_LEGACY_MULTITHREADED_API -endif -ifneq ($(ZSTD_LEGACY_SUPPORT), 0) -ifeq ($(shell test $(ZSTD_LEGACY_SUPPORT) -lt 8; echo $$?), 0) - ZSTD_FILES += $(shell ls legacy/*.c | $(GREP) 'v0[$(ZSTD_LEGACY_SUPPORT)-7]') -endif - CPPFLAGS += -I./legacy +ifeq ($(findstring GCC,$(CCVER)),GCC) +decompress/zstd_decompress_block.o : CFLAGS+=-fno-tree-vectorize endif -CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) -ZSTD_OBJ := $(patsubst %.c,%.o,$(ZSTD_FILES)) # macOS linker doesn't support -soname, and use different extension # see : https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html -ifeq ($(shell uname), Darwin) - SHARED_EXT = dylib - SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT) - SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT) - SONAME_FLAGS = -install_name $(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) -compatibility_version $(LIBVER_MAJOR) -current_version $(LIBVER) +ifeq ($(UNAME), Darwin) + SHARED_EXT = dylib + SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT) + SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT) + SONAME_FLAGS = -install_name $(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) -compatibility_version $(LIBVER_MAJOR) -current_version $(LIBVER) else - SONAME_FLAGS = -Wl,-soname=libzstd.$(SHARED_EXT).$(LIBVER_MAJOR) - SHARED_EXT = so - SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR) - SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER) + ifeq ($(UNAME), AIX) + SONAME_FLAGS = + else + SONAME_FLAGS = -Wl,-soname=libzstd.$(SHARED_EXT).$(LIBVER_MAJOR) + endif + SHARED_EXT = so + SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR) + SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER) endif -.PHONY: default all clean install uninstall +.PHONY: all +all: lib + -default: lib-release +.PHONY: libzstd.a # must be run every time +libzstd.a: CPPFLAGS += $(CPPFLAGS_STATLIB) -all: lib +SET_CACHE_DIRECTORY = \ + +$(MAKE) --no-print-directory $@ \ + BUILD_DIR=obj/$(HASH_DIR) \ + CPPFLAGS="$(CPPFLAGS)" \ + CFLAGS="$(CFLAGS)" \ + LDFLAGS="$(LDFLAGS)" + +ifndef BUILD_DIR +# determine BUILD_DIR from compilation flags -libzstd.a: ARFLAGS = rcs -libzstd.a: $(ZSTD_OBJ) - @echo compiling static library - @$(AR) $(ARFLAGS) $@ $^ +libzstd.a: + $(SET_CACHE_DIRECTORY) -libzstd.a-mt: CPPFLAGS += -DZSTD_MULTITHREAD -libzstd.a-mt: libzstd.a +else +# BUILD_DIR is defined + +ZSTD_STATLIB_DIR := $(BUILD_DIR)/static +ZSTD_STATLIB := $(ZSTD_STATLIB_DIR)/libzstd.a +ZSTD_STATLIB_OBJ := $(addprefix $(ZSTD_STATLIB_DIR)/,$(ZSTD_LOCAL_OBJ)) +$(ZSTD_STATLIB): ARFLAGS = rcs +$(ZSTD_STATLIB): | $(ZSTD_STATLIB_DIR) +$(ZSTD_STATLIB): $(ZSTD_STATLIB_OBJ) + # Check for multithread flag at target execution time + $(if $(filter -DZSTD_MULTITHREAD,$(CPPFLAGS)),\ + @echo compiling multi-threaded static library $(LIBVER),\ + @echo compiling single-threaded static library $(LIBVER)) + $(AR) $(ARFLAGS) $@ $^ + +libzstd.a: $(ZSTD_STATLIB) + cp -f $< $@ + +endif -ifneq (,$(filter Windows%,$(OS))) +ifneq (,$(filter Windows%,$(TARGET_SYSTEM))) -LIBZSTD = dll\libzstd.dll +LIBZSTD = dll/libzstd.dll $(LIBZSTD): $(ZSTD_FILES) @echo compiling dynamic library $(LIBVER) - $(CC) $(FLAGS) -DZSTD_DLL_EXPORT=1 -Wl,--out-implib,dll\libzstd.lib -shared $^ -o $@ + $(CC) $(FLAGS) -DZSTD_DLL_EXPORT=1 -Wl,--out-implib,dll/libzstd.dll.a -shared $^ -o $@ -else +else # not Windows LIBZSTD = libzstd.$(SHARED_EXT_VER) -$(LIBZSTD): LDFLAGS += -shared -fPIC -fvisibility=hidden -$(LIBZSTD): $(ZSTD_FILES) - @echo compiling dynamic library $(LIBVER) - @$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@ +.PHONY: $(LIBZSTD) # must be run every time +$(LIBZSTD): CPPFLAGS += $(CPPFLAGS_DYNLIB) +$(LIBZSTD): CFLAGS += -fPIC -fvisibility=hidden +$(LIBZSTD): LDFLAGS += -shared $(LDFLAGS_DYNLIB) + +ifndef BUILD_DIR +# determine BUILD_DIR from compilation flags + +$(LIBZSTD): + $(SET_CACHE_DIRECTORY) + +else +# BUILD_DIR is defined + +ZSTD_DYNLIB_DIR := $(BUILD_DIR)/dynamic +ZSTD_DYNLIB := $(ZSTD_DYNLIB_DIR)/$(LIBZSTD) +ZSTD_DYNLIB_OBJ := $(addprefix $(ZSTD_DYNLIB_DIR)/,$(ZSTD_LOCAL_OBJ)) + +$(ZSTD_DYNLIB): | $(ZSTD_DYNLIB_DIR) +$(ZSTD_DYNLIB): $(ZSTD_DYNLIB_OBJ) +# Check for multithread flag at target execution time + $(if $(filter -DZSTD_MULTITHREAD,$(CPPFLAGS)),\ + @echo compiling multi-threaded dynamic library $(LIBVER),\ + @echo compiling single-threaded dynamic library $(LIBVER)) + $(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@ @echo creating versioned links - @ln -sf $@ libzstd.$(SHARED_EXT_MAJOR) - @ln -sf $@ libzstd.$(SHARED_EXT) + ln -sf $@ libzstd.$(SHARED_EXT_MAJOR) + ln -sf $@ libzstd.$(SHARED_EXT) -endif +$(LIBZSTD): $(ZSTD_DYNLIB) + cp -f $< $@ +endif # ifndef BUILD_DIR +endif # if windows +.PHONY: libzstd libzstd : $(LIBZSTD) -libzstd-mt : CPPFLAGS += -DZSTD_MULTITHREAD -libzstd-mt : libzstd +.PHONY: lib +lib : libzstd.a libzstd + + +# note : do not define lib-mt or lib-release as .PHONY +# make does not consider implicit pattern rule for .PHONY target + +%-mt : CPPFLAGS_DYNLIB := -DZSTD_MULTITHREAD +%-mt : CPPFLAGS_STATLIB := -DZSTD_MULTITHREAD +%-mt : LDFLAGS_DYNLIB := -pthread +%-mt : % + @echo multi-threaded build completed + +%-nomt : CPPFLAGS_DYNLIB := +%-nomt : LDFLAGS_DYNLIB := +%-nomt : CPPFLAGS_STATLIB := +%-nomt : % + @echo single-threaded build completed + +%-release : DEBUGFLAGS := +%-release : % + @echo release build completed + -lib: libzstd.a libzstd +# Generate .h dependencies automatically -lib-mt: CPPFLAGS += -DZSTD_MULTITHREAD -lib-mt: lib +DEPFLAGS = -MT $@ -MMD -MP -MF + +$(ZSTD_DYNLIB_DIR)/%.o : %.c $(ZSTD_DYNLIB_DIR)/%.d | $(ZSTD_DYNLIB_DIR) + @echo CC $@ + $(COMPILE.c) $(DEPFLAGS) $(ZSTD_DYNLIB_DIR)/$*.d $(OUTPUT_OPTION) $< + +$(ZSTD_STATLIB_DIR)/%.o : %.c $(ZSTD_STATLIB_DIR)/%.d | $(ZSTD_STATLIB_DIR) + @echo CC $@ + $(COMPILE.c) $(DEPFLAGS) $(ZSTD_STATLIB_DIR)/$*.d $(OUTPUT_OPTION) $< + +$(ZSTD_DYNLIB_DIR)/%.o : %.S | $(ZSTD_DYNLIB_DIR) + @echo AS $@ + $(COMPILE.S) $(OUTPUT_OPTION) $< + +$(ZSTD_STATLIB_DIR)/%.o : %.S | $(ZSTD_STATLIB_DIR) + @echo AS $@ + $(COMPILE.S) $(OUTPUT_OPTION) $< + +MKDIR ?= mkdir +$(BUILD_DIR) $(ZSTD_DYNLIB_DIR) $(ZSTD_STATLIB_DIR): + $(MKDIR) -p $@ + +DEPFILES := $(ZSTD_DYNLIB_OBJ:.o=.d) $(ZSTD_STATLIB_OBJ:.o=.d) +$(DEPFILES): + +include $(wildcard $(DEPFILES)) -lib-release lib-release-mt: DEBUGFLAGS := -lib-release: lib -lib-release-mt: lib-mt # Special case : building library in single-thread mode _and_ without zstdmt_compress.c ZSTDMT_FILES = compress/zstdmt_compress.c ZSTD_NOMT_FILES = $(filter-out $(ZSTDMT_FILES),$(ZSTD_FILES)) -libzstd-nomt: LDFLAGS += -shared -fPIC -fvisibility=hidden +libzstd-nomt: CFLAGS += -fPIC -fvisibility=hidden +libzstd-nomt: LDFLAGS += -shared libzstd-nomt: $(ZSTD_NOMT_FILES) @echo compiling single-thread dynamic library $(LIBVER) @echo files : $(ZSTD_NOMT_FILES) - @$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@ + $(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@ +.PHONY: clean clean: - @$(RM) -r *.dSYM # macOS-specific - @$(RM) core *.o *.a *.gcda *.$(SHARED_EXT) *.$(SHARED_EXT).* libzstd.pc - @$(RM) dll/libzstd.dll dll/libzstd.lib libzstd-nomt* - @$(RM) common/*.o compress/*.o decompress/*.o dictBuilder/*.o legacy/*.o deprecated/*.o + $(RM) -r *.dSYM # macOS-specific + $(RM) core *.o *.a *.gcda *.$(SHARED_EXT) *.$(SHARED_EXT).* libzstd.pc + $(RM) dll/libzstd.dll dll/libzstd.lib libzstd-nomt* + $(RM) -r obj/* @echo Cleaning library completed #----------------------------------------------------------------------------- -# make install is validated only for Linux, macOS, BSD, Hurd and Solaris targets +# make install is validated only for below listed environments #----------------------------------------------------------------------------- -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku)) +ifneq (,$(filter $(UNAME),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku AIX)) + +lib: libzstd.pc + +HAS_EXPLICIT_EXEC_PREFIX := $(if $(or $(EXEC_PREFIX),$(exec_prefix)),1,) DESTDIR ?= # directory variables : GNU conventions prefer lowercase @@ -219,71 +262,96 @@ DESTDIR ?= prefix ?= /usr/local PREFIX ?= $(prefix) exec_prefix ?= $(PREFIX) -libdir ?= $(exec_prefix)/lib +EXEC_PREFIX ?= $(exec_prefix) +libdir ?= $(EXEC_PREFIX)/lib LIBDIR ?= $(libdir) includedir ?= $(PREFIX)/include INCLUDEDIR ?= $(includedir) -ifneq (,$(filter $(shell uname),FreeBSD NetBSD DragonFly)) -PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig +PCINCDIR := $(patsubst $(PREFIX)%,%,$(INCLUDEDIR)) +PCLIBDIR := $(patsubst $(EXEC_PREFIX)%,%,$(LIBDIR)) + +# If we successfully stripped off a prefix, we'll add a reference to the +# relevant pc variable. +PCINCPREFIX := $(if $(findstring $(INCLUDEDIR),$(PCINCDIR)),,$${prefix}) +PCLIBPREFIX := $(if $(findstring $(LIBDIR),$(PCLIBDIR)),,$${exec_prefix}) + +# If no explicit EXEC_PREFIX was set by the caller, write it out as a reference +# to PREFIX, rather than as a resolved value. +PCEXEC_PREFIX := $(if $(HAS_EXPLICIT_EXEC_PREFIX),$(EXEC_PREFIX),$${prefix}) + +ifneq (,$(filter $(UNAME),FreeBSD NetBSD DragonFly)) + PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig else -PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig + PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig endif -ifneq (,$(filter $(shell uname),SunOS)) -INSTALL ?= ginstall +ifneq (,$(filter $(UNAME),SunOS)) + INSTALL ?= ginstall else -INSTALL ?= install + INSTALL ?= install endif INSTALL_PROGRAM ?= $(INSTALL) INSTALL_DATA ?= $(INSTALL) -m 644 -libzstd.pc: libzstd.pc: libzstd.pc.in @echo creating pkgconfig - @sed -e 's|@PREFIX@|$(PREFIX)|' \ - -e 's|@VERSION@|$(VERSION)|' \ - $< >$@ - + @sed $(SED_ERE_OPT) \ + -e 's|@PREFIX@|$(PREFIX)|' \ + -e 's|@EXEC_PREFIX@|$(PCEXEC_PREFIX)|' \ + -e 's|@INCLUDEDIR@|$(PCINCPREFIX)$(PCINCDIR)|' \ + -e 's|@LIBDIR@|$(PCLIBPREFIX)$(PCLIBDIR)|' \ + -e 's|@VERSION@|$(VERSION)|' \ + -e 's|@LIBS_PRIVATE@|$(LDFLAGS_DYNLIB)|' \ + $< >$@ + +.PHONY: install install: install-pc install-static install-shared install-includes @echo zstd static and shared library installed +.PHONY: install-pc install-pc: libzstd.pc - @$(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)/ - @$(INSTALL_DATA) libzstd.pc $(DESTDIR)$(PKGCONFIGDIR)/ - -install-static: libzstd.a + [ -e $(DESTDIR)$(PKGCONFIGDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)/ + $(INSTALL_DATA) libzstd.pc $(DESTDIR)$(PKGCONFIGDIR)/ + +.PHONY: install-static +install-static: + # only generate libzstd.a if it's not already present + [ -e libzstd.a ] || $(MAKE) libzstd.a-release + [ -e $(DESTDIR)$(LIBDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/ @echo Installing static library - @$(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/ - @$(INSTALL_DATA) libzstd.a $(DESTDIR)$(LIBDIR) + $(INSTALL_DATA) libzstd.a $(DESTDIR)$(LIBDIR) -install-shared: libzstd +.PHONY: install-shared +install-shared: + # only generate libzstd.so if it's not already present + [ -e $(LIBZSTD) ] || $(MAKE) libzstd-release + [ -e $(DESTDIR)$(LIBDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/ @echo Installing shared library - @$(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/ - @$(INSTALL_PROGRAM) $(LIBZSTD) $(DESTDIR)$(LIBDIR) - @ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) - @ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) + $(INSTALL_PROGRAM) $(LIBZSTD) $(DESTDIR)$(LIBDIR) + ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) + ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) +.PHONY: install-includes install-includes: + [ -e $(DESTDIR)$(INCLUDEDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)/ @echo Installing includes - @$(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)/ - @$(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR) - @$(INSTALL_DATA) common/zstd_errors.h $(DESTDIR)$(INCLUDEDIR) - @$(INSTALL_DATA) deprecated/zbuff.h $(DESTDIR)$(INCLUDEDIR) # prototypes generate deprecation warnings - @$(INSTALL_DATA) dictBuilder/zdict.h $(DESTDIR)$(INCLUDEDIR) + $(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR) + $(INSTALL_DATA) zstd_errors.h $(DESTDIR)$(INCLUDEDIR) + $(INSTALL_DATA) zdict.h $(DESTDIR)$(INCLUDEDIR) +.PHONY: uninstall uninstall: - @$(RM) $(DESTDIR)$(LIBDIR)/libzstd.a - @$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) - @$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) - @$(RM) $(DESTDIR)$(LIBDIR)/$(LIBZSTD) - @$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libzstd.pc - @$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h - @$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_errors.h - @$(RM) $(DESTDIR)$(INCLUDEDIR)/zbuff.h # Deprecated streaming functions - @$(RM) $(DESTDIR)$(INCLUDEDIR)/zdict.h + $(RM) $(DESTDIR)$(LIBDIR)/libzstd.a + $(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) + $(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) + $(RM) $(DESTDIR)$(LIBDIR)/$(LIBZSTD) + $(RM) $(DESTDIR)$(PKGCONFIGDIR)/libzstd.pc + $(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h + $(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_errors.h + $(RM) $(DESTDIR)$(INCLUDEDIR)/zdict.h @echo zstd libraries successfully uninstalled endif diff --git a/native/zstd/README.md b/native/zstd/README.md index 0062c0d..015cde5 100644 --- a/native/zstd/README.md +++ b/native/zstd/README.md @@ -19,12 +19,16 @@ The scope can be reduced on demand (see paragraph _modular build_). #### Multithreading support -Multithreading is disabled by default when building with `make`. +When building with `make`, by default the dynamic library is multithreaded and static library is single-threaded (for compatibility reasons). + Enabling multithreading requires 2 conditions : - set build macro `ZSTD_MULTITHREAD` (`-DZSTD_MULTITHREAD` for `gcc`) - for POSIX systems : compile with pthread (`-pthread` compilation flag for `gcc`) -Both conditions are automatically applied when invoking `make lib-mt` target. +For convenience, we provide a build target to generate multi and single threaded libraries: +- Force enable multithreading on both dynamic and static libraries by appending `-mt` to the target, e.g. `make lib-mt`. +- Force disable multithreading on both dynamic and static libraries by appending `-nomt` to the target, e.g. `make lib-nomt`. +- By default, as mentioned before, dynamic library is multithreaded, and static library is single-threaded, e.g. `make lib`. When linking a POSIX program with a multithreaded version of `libzstd`, note that it's necessary to invoke the `-pthread` flag during link stage. @@ -42,8 +46,8 @@ Zstandard's stable API is exposed within [lib/zstd.h](zstd.h). Optional advanced features are exposed via : -- `lib/common/zstd_errors.h` : translates `size_t` function results - into a `ZSTD_ErrorCode`, for accurate error handling. +- `lib/zstd_errors.h` : translates `size_t` function results + into a `ZSTD_ErrorCode`, for accurate error handling. - `ZSTD_STATIC_LINKING_ONLY` : if this macro is defined _before_ including `zstd.h`, it unlocks access to the experimental API, @@ -85,28 +89,48 @@ The file structure is designed to make this selection manually achievable for an - While invoking `make libzstd`, it's possible to define build macros `ZSTD_LIB_COMPRESSION, ZSTD_LIB_DECOMPRESSION`, `ZSTD_LIB_DICTBUILDER`, - and `ZSTD_LIB_DEPRECATED` as `0` to forgo compilation of the corresponding features. - This will also disable compilation of all dependencies - (eg. `ZSTD_LIB_COMPRESSION=0` will also disable dictBuilder). - -- There are some additional build macros that can be used to minify the decoder. - - Zstandard often has more than one implementation of a piece of functionality, - where each implementation optimizes for different scenarios. For example, the - Huffman decoder has complementary implementations that decode the stream one - symbol at a time or two symbols at a time. Zstd normally includes both (and - dispatches between them at runtime), but by defining `HUF_FORCE_DECOMPRESS_X1` - or `HUF_FORCE_DECOMPRESS_X2`, you can force the use of one or the other, avoiding + and `ZSTD_LIB_DEPRECATED` as `0` to forgo compilation of the + corresponding features. This will also disable compilation of all + dependencies (e.g. `ZSTD_LIB_COMPRESSION=0` will also disable + dictBuilder). + +- There are a number of options that can help minimize the binary size of + `libzstd`. + + The first step is to select the components needed (using the above-described + `ZSTD_LIB_COMPRESSION` etc.). + + The next step is to set `ZSTD_LIB_MINIFY` to `1` when invoking `make`. This + disables various optional components and changes the compilation flags to + prioritize space-saving. + + Detailed options: Zstandard's code and build environment is set up by default + to optimize above all else for performance. In pursuit of this goal, Zstandard + makes significant trade-offs in code size. For example, Zstandard often has + more than one implementation of a particular component, with each + implementation optimized for different scenarios. For example, the Huffman + decoder has complementary implementations that decode the stream one symbol at + a time or two symbols at a time. Zstd normally includes both (and dispatches + between them at runtime), but by defining `HUF_FORCE_DECOMPRESS_X1` or + `HUF_FORCE_DECOMPRESS_X2`, you can force the use of one or the other, avoiding compilation of the other. Similarly, `ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT` and `ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG` force the compilation and use of only one or the other of two decompression implementations. The smallest binary is achieved by using `HUF_FORCE_DECOMPRESS_X1` and - `ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT`. + `ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT` (implied by `ZSTD_LIB_MINIFY`). For squeezing the last ounce of size out, you can also define `ZSTD_NO_INLINE`, which disables inlining, and `ZSTD_STRIP_ERROR_STRINGS`, which removes the error messages that are otherwise returned by - `ZSTD_getErrorName`. + `ZSTD_getErrorName` (implied by `ZSTD_LIB_MINIFY`). + + Finally, when integrating into your application, make sure you're doing link- + time optimization and unused symbol garbage collection (via some combination of, + e.g., `-flto`, `-ffat-lto-objects`, `-fuse-linker-plugin`, + `-ffunction-sections`, `-fdata-sections`, `-fmerge-all-constants`, + `-Wl,--gc-sections`, `-Wl,-z,norelro`, and an archiver that understands + the compiler's intermediate representation, e.g., `AR=gcc-ar`). Consult your + compiler's documentation. - While invoking `make libzstd`, the build macro `ZSTD_LEGACY_MULTITHREADED_API=1` will expose the deprecated `ZSTDMT` API exposed by `zstdmt_compress.h` in @@ -123,6 +147,20 @@ The file structure is designed to make this selection manually achievable for an Setting this macro will either force to generate the BMI2 dispatcher (1) or prevent it (0). It overrides automatic detection. +- The build macro `ZSTD_NO_UNUSED_FUNCTIONS` can be defined to hide the definitions of functions + that zstd does not use. Not all unused functions are hidden, but they can be if needed. + Currently, this macro will hide function definitions in FSE and HUF that use an excessive + amount of stack space. + +- The build macro `ZSTD_NO_INTRINSICS` can be defined to disable all explicit intrinsics. + Compiler builtins are still used. + +- The build macro `ZSTD_DECODER_INTERNAL_BUFFER` can be set to control + the amount of extra memory used during decompression to store literals. + This defaults to 64kB. Reducing this value reduces the memory footprint of + `ZSTD_DCtx` decompression contexts, + but might also result in a small decompression speed cost. + #### Windows : using MinGW+MSYS to create DLL @@ -140,6 +178,26 @@ file it should be linked with `dll\libzstd.dll`. For example: The compiled executable will require ZSTD DLL which is available at `dll\libzstd.dll`. +#### Advanced Build options + +The build system requires a hash function in order to +separate object files created with different compilation flags. +By default, it tries to use `md5sum` or equivalent. +The hash function can be manually switched by setting the `HASH` variable. +For example : `make HASH=xxhsum` +The hash function needs to generate at least 64-bit using hexadecimal format. +When no hash function is found, +the Makefile just generates all object files into the same default directory, +irrespective of compilation flags. +This functionality only matters if `libzstd` is compiled multiple times +with different build flags. + +The build directory, where object files are stored +can also be manually controlled using variable `BUILD_DIR`, +for example `make BUILD_DIR=objectDir/v1`. +In which case, the hash function doesn't matter. + + #### Deprecated API Obsolete API on their way out are stored in directory `lib/deprecated`. diff --git a/native/zstd/common/bits.h b/native/zstd/common/bits.h new file mode 100644 index 0000000..c0e9177 --- /dev/null +++ b/native/zstd/common/bits.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) Facebook, Inc. + * 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. + */ + +#ifndef ZSTD_BITS_H +#define ZSTD_BITS_H + +#include "mem.h" + +MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) +{ + assert(val != 0); + { + static const int DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3, + 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, + 26, 12, 18, 6, 11, 5, 10, 9}; + return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; + } +} + +MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val) +{ + assert(val != 0); +# if defined(_MSC_VER) +# if STATIC_BMI2 == 1 + return _tzcnt_u32(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)__builtin_ctz(val); +# else + return ZSTD_countTrailingZeros32_fallback(val); +# endif +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) { + assert(val != 0); + { + static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31}; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27]; + } +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val) +{ + assert(val != 0); +# if defined(_MSC_VER) +# if STATIC_BMI2 == 1 + return _lzcnt_u32(val); +# else + if (val != 0) { + unsigned long r; + _BitScanReverse(&r, val); + return (unsigned)(31 - r); + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)__builtin_clz(val); +# else + return ZSTD_countLeadingZeros32_fallback(val); +# endif +} + +MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val) +{ + assert(val != 0); +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 == 1 + return _tzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward64(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__) + return (unsigned)__builtin_ctzll(val); +# else + { + U32 mostSignificantWord = (U32)(val >> 32); + U32 leastSignificantWord = (U32)val; + if (leastSignificantWord == 0) { + return 32 + ZSTD_countTrailingZeros32(mostSignificantWord); + } else { + return ZSTD_countTrailingZeros32(leastSignificantWord); + } + } +# endif +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val) +{ + assert(val != 0); +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 == 1 + return _lzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanReverse64(&r, val); + return (unsigned)(63 - r); + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)(__builtin_clzll(val)); +# else + { + U32 mostSignificantWord = (U32)(val >> 32); + U32 leastSignificantWord = (U32)val; + if (mostSignificantWord == 0) { + return 32 + ZSTD_countLeadingZeros32(leastSignificantWord); + } else { + return ZSTD_countLeadingZeros32(mostSignificantWord); + } + } +# endif +} + +MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val) +{ + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { + return ZSTD_countTrailingZeros64((U64)val) >> 3; + } else { + return ZSTD_countTrailingZeros32((U32)val) >> 3; + } + } else { /* Big Endian CPU */ + if (MEM_64bits()) { + return ZSTD_countLeadingZeros64((U64)val) >> 3; + } else { + return ZSTD_countLeadingZeros32((U32)val) >> 3; + } + } +} + +MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ +{ + assert(val != 0); + return 31 - ZSTD_countLeadingZeros32(val); +} + +#endif /* ZSTD_BITS_H */ diff --git a/native/zstd/common/bitstream.h b/native/zstd/common/bitstream.h old mode 100755 new mode 100644 index 1c294b8..8417786 --- a/native/zstd/common/bitstream.h +++ b/native/zstd/common/bitstream.h @@ -1,35 +1,15 @@ /* ****************************************************************** - bitstream - Part of FSE library - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * bitstream + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * 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. ****************************************************************** */ #ifndef BITSTREAM_H_MODULE #define BITSTREAM_H_MODULE @@ -37,7 +17,6 @@ #if defined (__cplusplus) extern "C" { #endif - /* * This API consists of small unitary functions, which must be inlined for best performance. * Since link-time-optimization is not available for all compilers, @@ -48,17 +27,21 @@ extern "C" { * Dependencies ******************************************/ #include "mem.h" /* unaligned access routines */ +#include "compiler.h" /* UNLIKELY() */ #include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ #include "error_private.h" /* error codes and messages */ +#include "bits.h" /* ZSTD_highbit32 */ /*========================================= * Target specific =========================================*/ -#if defined(__BMI__) && defined(__GNUC__) -# include /* support for bextr (experimental) */ -#elif defined(__ICCARM__) -# include +#ifndef ZSTD_NO_INTRINSICS +# if (defined(__BMI__) || defined(__BMI2__)) && defined(__GNUC__) +# include /* support for bextr (experimental)/bzhi */ +# elif defined(__ICCARM__) +# include +# endif #endif #define STREAM_ACCUMULATOR_MIN_32 25 @@ -150,39 +133,6 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); /* faster, but works only if nbBits >= 1 */ - - -/*-************************************************************** -* Internal functions -****************************************************************/ -MEM_STATIC unsigned BIT_highbit32 (U32 val) -{ - assert(val != 0); - { -# if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; -# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ - return __builtin_clz (val) ^ 31; -# elif defined(__ICCARM__) /* IAR Intrinsic */ - return 31 - __CLZ(val); -# else /* Software version */ - static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31 }; - U32 v = val; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; -# endif - } -} - /*===== Local Constants =====*/ static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, @@ -212,16 +162,26 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, return 0; } +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ +#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS) + return _bzhi_u64(bitContainer, nbBits); +#else + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; +#endif +} + /*! BIT_addBits() : * can add up to 31 bits into `bitC`. * Note : does not check for register overflow ! */ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { - MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32); + DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32); assert(nbBits < BIT_MASK_SIZE); assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); - bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; + bitC->bitContainer |= BIT_getLowerBits(value, nbBits) << bitC->bitPos; bitC->bitPos += nbBits; } @@ -291,7 +251,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) { - if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } bitD->start = (const char*)srcBuffer; bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); @@ -300,7 +260,7 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); bitD->bitContainer = MEM_readLEST(bitD->ptr); { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } } else { bitD->ptr = bitD->start; @@ -308,27 +268,27 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si switch(srcSize) { case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); - /* fall-through */ + ZSTD_FALLTHROUGH; case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); - /* fall-through */ + ZSTD_FALLTHROUGH; case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); - /* fall-through */ + ZSTD_FALLTHROUGH; case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; - /* fall-through */ + ZSTD_FALLTHROUGH; case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; - /* fall-through */ + ZSTD_FALLTHROUGH; case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; - /* fall-through */ + ZSTD_FALLTHROUGH; default: break; } { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; + bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ } bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; @@ -337,23 +297,26 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si return srcSize; } -MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { return bitContainer >> start; } -MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) { U32 const regMask = sizeof(bitContainer)*8 - 1; /* if start > regMask, bitstream is corrupted, and result is undefined */ assert(nbBits < BIT_MASK_SIZE); + /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better + * than accessing memory. When bmi2 instruction is not present, we consider + * such cpus old (pre-Haswell, 2013) and their performance is not of that + * importance. + */ +#if defined(__x86_64__) || defined(_M_X86) + return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1); +#else return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; -} - -MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) -{ - assert(nbBits < BIT_MASK_SIZE); - return bitContainer & BIT_mask[nbBits]; +#endif } /*! BIT_lookBits() : @@ -362,7 +325,7 @@ MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) * On 32-bits, maxNbBits==24. * On 64-bits, maxNbBits==56. * @return : value extracted */ -MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) { /* arbitrate between double-shift and shift+mask */ #if 1 @@ -385,7 +348,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); } -MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; } @@ -394,7 +357,7 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) * Read (consume) next n bits from local register and update. * Pay attention to not read more than nbBits contained into local register. * @return : extracted value. */ -MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBits(bitD, nbBits); BIT_skipBits(bitD, nbBits); @@ -402,7 +365,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) } /*! BIT_readBitsFast() : - * unsafe version; only works only if nbBits >= 1 */ + * unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBitsFast(bitD, nbBits); @@ -411,6 +374,23 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) return value; } +/*! BIT_reloadDStreamFast() : + * Similar to BIT_reloadDStream(), but with two differences: + * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold! + * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this + * point you must use BIT_reloadDStream() to reload. + */ +MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD) +{ + if (UNLIKELY(bitD->ptr < bitD->limitPtr)) + return BIT_DStream_overflow; + assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); + bitD->ptr -= bitD->bitsConsumed >> 3; + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; +} + /*! BIT_reloadDStream() : * Refill `bitD` from buffer previously set in BIT_initDStream() . * This function is safe, it guarantees it will not read beyond src buffer. @@ -422,10 +402,7 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) return BIT_DStream_overflow; if (bitD->ptr >= bitD->limitPtr) { - bitD->ptr -= bitD->bitsConsumed >> 3; - bitD->bitsConsumed &= 7; - bitD->bitContainer = MEM_readLEST(bitD->ptr); - return BIT_DStream_unfinished; + return BIT_reloadDStreamFast(bitD); } if (bitD->ptr == bitD->start) { if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; diff --git a/native/zstd/common/compiler.h b/native/zstd/common/compiler.h old mode 100755 new mode 100644 index 1877a0c..6c7100e --- a/native/zstd/common/compiler.h +++ b/native/zstd/common/compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,13 +11,15 @@ #ifndef ZSTD_COMPILER_H #define ZSTD_COMPILER_H +#include "portability_macros.h" + /*-******************************************************* * Compiler specifics *********************************************************/ /* force inlining */ #if !defined(ZSTD_NO_INLINE) -#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ # define INLINE_KEYWORD inline #else # define INLINE_KEYWORD @@ -38,6 +40,17 @@ #endif +/** + On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC). + This explicitly marks such functions as __cdecl so that the code will still compile + if a CC other than __cdecl has been made the default. +*/ +#if defined(_MSC_VER) +# define WIN_CDECL __cdecl +#else +# define WIN_CDECL +#endif + /** * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant * parameters. They must be inlined for the compiler to eliminate the constant @@ -79,30 +92,19 @@ # endif #endif + /* target attribute */ -#ifndef __has_attribute - #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif #if defined(__GNUC__) || defined(__ICCARM__) # define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) #else # define TARGET_ATTRIBUTE(target) #endif -/* Enable runtime BMI2 dispatch based on the CPU. - * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. +/* Target attribute for BMI2 dynamic dispatch. + * Enable lzcnt, bmi, and bmi2. + * We test for bmi1 & bmi2. lzcnt is included in bmi1. */ -#ifndef DYNAMIC_BMI2 - #if ((defined(__clang__) && __has_attribute(__target__)) \ - || (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ - && (defined(__x86_64__) || defined(_M_X86)) \ - && !defined(__BMI2__) - # define DYNAMIC_BMI2 1 - #else - # define DYNAMIC_BMI2 0 - #endif -#endif +#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") /* prefetch * can be disabled, by declaring NO_PREFETCH build macro */ @@ -117,6 +119,9 @@ # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) +# elif defined(__aarch64__) +# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) +# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) # else # define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ # define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ @@ -135,8 +140,9 @@ } /* vectorization - * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */ -#if !defined(__clang__) && defined(__GNUC__) + * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, + * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */ +#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__) # if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) # define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) # else @@ -146,6 +152,19 @@ # define DONT_VECTORIZE #endif +/* Tell the compiler that a branch is likely or unlikely. + * Only use these macros if it causes the compiler to generate better code. + * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc + * and clang, please do. + */ +#if defined(__GNUC__) +#define LIKELY(x) (__builtin_expect((x), 1)) +#define UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define LIKELY(x) (x) +#define UNLIKELY(x) (x) +#endif + /* disable warnings */ #ifdef _MSC_VER /* Visual Studio */ # include /* For Visual 2005 */ @@ -156,4 +175,163 @@ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ #endif +/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ +#ifndef STATIC_BMI2 +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) +# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 +# define STATIC_BMI2 1 +# endif +# elif defined(__BMI2__) && defined(__x86_64__) && defined(__GNUC__) +# define STATIC_BMI2 1 +# endif +#endif + +#ifndef STATIC_BMI2 + #define STATIC_BMI2 0 +#endif + +/* compile time determination of SIMD support */ +#if !defined(ZSTD_NO_INTRINSICS) +# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) +# define ZSTD_ARCH_X86_SSE2 +# endif +# if defined(__ARM_NEON) || defined(_M_ARM64) +# define ZSTD_ARCH_ARM_NEON +# endif +# +# if defined(ZSTD_ARCH_X86_SSE2) +# include +# elif defined(ZSTD_ARCH_ARM_NEON) +# include +# endif +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define ZSTD_HAS_C_ATTRIBUTE(x) 0 +#endif + +/* Only use C++ attributes in C++. Some compilers report support for C++ + * attributes when compiling with C. + */ +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute. + * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough + * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough + * - Else: __attribute__((__fallthrough__)) + */ +#ifndef ZSTD_FALLTHROUGH +# if ZSTD_HAS_C_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif ZSTD_HAS_CPP_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif __has_attribute(__fallthrough__) +/* Leading semicolon is to satisfy gcc-11 with -pedantic. Without the semicolon + * gcc complains about: a label can only be part of a statement and a declaration is not a statement. + */ +# define ZSTD_FALLTHROUGH ; __attribute__((__fallthrough__)) +# else +# define ZSTD_FALLTHROUGH +# endif +#endif + +/*-************************************************************** +* Alignment check +*****************************************************************/ + +/* this test was initially positioned in mem.h, + * but this file is removed (or replaced) for linux kernel + * so it's now hosted in compiler.h, + * which remains valid for both user & kernel spaces. + */ + +#ifndef ZSTD_ALIGNOF +# if defined(__GNUC__) || defined(_MSC_VER) +/* covers gcc, clang & MSVC */ +/* note : this section must come first, before C11, + * due to a limitation in the kernel source generator */ +# define ZSTD_ALIGNOF(T) __alignof(T) + +# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +/* C11 support */ +# include +# define ZSTD_ALIGNOF(T) alignof(T) + +# else +/* No known support for alignof() - imperfect backup */ +# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T)) + +# endif +#endif /* ZSTD_ALIGNOF */ + +/*-************************************************************** +* Sanitizer +*****************************************************************/ + +#if ZSTD_MEMORY_SANITIZER +/* Not all platforms that support msan provide sanitizers/msan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ +#define ZSTD_DEPS_NEED_STDINT +#include "zstd_deps.h" /* intptr_t */ + +/* Make memory region fully initialized (without changing its contents). */ +void __msan_unpoison(const volatile void *a, size_t size); + +/* Make memory region fully uninitialized (without changing its contents). + This is a legacy interface that does not update origin information. Use + __msan_allocated_memory() instead. */ +void __msan_poison(const volatile void *a, size_t size); + +/* Returns the offset of the first (at least partially) poisoned byte in the + memory range, or -1 if the whole range is good. */ +intptr_t __msan_test_shadow(const volatile void *x, size_t size); +#endif + +#if ZSTD_ADDRESS_SANITIZER +/* Not all platforms that support asan provide sanitizers/asan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ + +/** + * Marks a memory region ([addr, addr+size)) as unaddressable. + * + * This memory must be previously allocated by your program. Instrumented + * code is forbidden from accessing addresses in this region until it is + * unpoisoned. This function is not guaranteed to poison the entire region - + * it could poison only a subregion of [addr, addr+size) due to ASan + * alignment restrictions. + * + * \note This function is not thread-safe because no two threads can poison or + * unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_poison_memory_region(void const volatile *addr, size_t size); + +/** + * Marks a memory region ([addr, addr+size)) as addressable. + * + * This memory must be previously allocated by your program. Accessing + * addresses in this region is allowed until this region is poisoned again. + * This function could unpoison a super-region of [addr, addr+size) due + * to ASan alignment restrictions. + * + * \note This function is not thread-safe because no two threads can + * poison or unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#endif + #endif /* ZSTD_COMPILER_H */ diff --git a/native/zstd/common/cpu.h b/native/zstd/common/cpu.h old mode 100755 new mode 100644 index 5f0923f..8acd33b --- a/native/zstd/common/cpu.h +++ b/native/zstd/common/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-present, Facebook, Inc. + * Copyright (c) Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,8 +16,6 @@ * https://github.com/facebook/folly/blob/master/folly/CpuId.h */ -#include - #include "mem.h" #ifdef _MSC_VER diff --git a/native/zstd/common/debug.c b/native/zstd/common/debug.c old mode 100755 new mode 100644 index 3ebdd1c..bb863c9 --- a/native/zstd/common/debug.c +++ b/native/zstd/common/debug.c @@ -1,35 +1,15 @@ /* ****************************************************************** - debug - Part of FSE library - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * debug + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * 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. ****************************************************************** */ diff --git a/native/zstd/common/debug.h b/native/zstd/common/debug.h old mode 100755 new mode 100644 index b4fc89d..3b2a320 --- a/native/zstd/common/debug.h +++ b/native/zstd/common/debug.h @@ -1,35 +1,15 @@ /* ****************************************************************** - debug - Part of FSE library - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * debug + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * 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. ****************************************************************** */ @@ -71,15 +51,6 @@ extern "C" { #endif -/* DEBUGFILE can be defined externally, - * typically through compiler command line. - * note : currently useless. - * Value must be stderr or stdout */ -#ifndef DEBUGFILE -# define DEBUGFILE stderr -#endif - - /* recommended values for DEBUGLEVEL : * 0 : release mode, no debug, all run-time checks disabled * 1 : enables assert() only, no display @@ -96,7 +67,8 @@ extern "C" { */ #if (DEBUGLEVEL>=1) -# include +# define ZSTD_DEPS_NEED_ASSERT +# include "zstd_deps.h" #else # ifndef assert /* assert may be already defined, due to prior #include */ # define assert(condition) ((void)0) /* disable assert (default) */ @@ -104,7 +76,8 @@ extern "C" { #endif #if (DEBUGLEVEL>=2) -# include +# define ZSTD_DEPS_NEED_IO +# include "zstd_deps.h" extern int g_debuglevel; /* the variable is only declared, it actually lives in debug.c, and is shared by the whole process. @@ -112,14 +85,14 @@ extern int g_debuglevel; /* the variable is only declared, It's useful when enabling very verbose levels on selective conditions (such as position in src) */ -# define RAWLOG(l, ...) { \ - if (l<=g_debuglevel) { \ - fprintf(stderr, __VA_ARGS__); \ +# define RAWLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__VA_ARGS__); \ } } -# define DEBUGLOG(l, ...) { \ - if (l<=g_debuglevel) { \ - fprintf(stderr, __FILE__ ": " __VA_ARGS__); \ - fprintf(stderr, " \n"); \ +# define DEBUGLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \ + ZSTD_DEBUG_PRINT(" \n"); \ } } #else # define RAWLOG(l, ...) {} /* disabled */ diff --git a/native/zstd/common/entropy_common.c b/native/zstd/common/entropy_common.c old mode 100755 new mode 100644 index b12944e..98bd423 --- a/native/zstd/common/entropy_common.c +++ b/native/zstd/common/entropy_common.c @@ -1,36 +1,16 @@ -/* - Common functions of New Generation Entropy library - Copyright (C) 2016, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -*************************************************************************** */ +/* ****************************************************************** + * Common functions of New Generation Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * 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. +****************************************************************** */ /* ************************************* * Dependencies @@ -41,6 +21,7 @@ #include "fse.h" #define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */ #include "huf.h" +#include "bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */ /*=== Version ===*/ @@ -58,8 +39,9 @@ const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } /*-************************************************************** * FSE NCount encoding-decoding ****************************************************************/ -size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) +FORCE_INLINE_TEMPLATE +size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) { const BYTE* const istart = (const BYTE*) headerBuffer; const BYTE* const iend = istart + hbSize; @@ -70,23 +52,23 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t U32 bitStream; int bitCount; unsigned charnum = 0; + unsigned const maxSV1 = *maxSVPtr + 1; int previous0 = 0; - if (hbSize < 4) { - /* This function only works when hbSize >= 4 */ - char buffer[4]; - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, headerBuffer, hbSize); + if (hbSize < 8) { + /* This function only works when hbSize >= 8 */ + char buffer[8] = {0}; + ZSTD_memcpy(buffer, headerBuffer, hbSize); { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, buffer, sizeof(buffer)); if (FSE_isError(countSize)) return countSize; if (countSize > hbSize) return ERROR(corruption_detected); return countSize; } } - assert(hbSize >= 4); + assert(hbSize >= 8); /* init */ - memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ + ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ bitStream = MEM_readLE32(ip); nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); @@ -97,36 +79,58 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t threshold = 1<1) & (charnum<=*maxSVPtr)) { + for (;;) { if (previous0) { - unsigned n0 = charnum; - while ((bitStream & 0xFFFF) == 0xFFFF) { - n0 += 24; - if (ip < iend-5) { - ip += 2; - bitStream = MEM_readLE32(ip) >> bitCount; + /* Count the number of repeats. Each time the + * 2-bit repeat code is 0b11 there is another + * repeat. + * Avoid UB by setting the high bit to 1. + */ + int repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; + while (repeats >= 12) { + charnum += 3 * 12; + if (LIKELY(ip <= iend-7)) { + ip += 3; } else { - bitStream >>= 16; - bitCount += 16; - } } - while ((bitStream & 3) == 3) { - n0 += 3; - bitStream >>= 2; - bitCount += 2; + bitCount -= (int)(8 * (iend - 7 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; } - n0 += bitStream & 3; + charnum += 3 * repeats; + bitStream >>= 2 * repeats; + bitCount += 2 * repeats; + + /* Add the final repeat which isn't 0b11. */ + assert((bitStream & 3) < 3); + charnum += bitStream & 3; bitCount += 2; - if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); - while (charnum < n0) normalizedCounter[charnum++] = 0; - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + + /* This is an error, but break and return an error + * at the end, because returning out of a loop makes + * it harder for the compiler to optimize. + */ + if (charnum >= maxSV1) break; + + /* We don't need to set the normalized count to 0 + * because we already memset the whole buffer to 0. + */ + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { assert((bitCount >> 3) <= 3); /* For first condition to work */ ip += bitCount>>3; bitCount &= 7; - bitStream = MEM_readLE32(ip) >> bitCount; } else { - bitStream >>= 2; - } } - { int const max = (2*threshold-1) - remaining; + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } + { + int const max = (2*threshold-1) - remaining; int count; if ((bitStream & (threshold-1)) < (U32)max) { @@ -139,24 +143,43 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t } count--; /* extra accuracy */ - remaining -= count < 0 ? -count : count; /* -1 means +1 */ + /* When it matters (small blocks), this is a + * predictable branch, because we don't use -1. + */ + if (count >= 0) { + remaining -= count; + } else { + assert(count == -1); + remaining += count; + } normalizedCounter[charnum++] = (short)count; previous0 = !count; - while (remaining < threshold) { - nbBits--; - threshold >>= 1; + + assert(threshold > 1); + if (remaining < threshold) { + /* This branch can be folded into the + * threshold update condition because we + * know that threshold > 1. + */ + if (remaining <= 1) break; + nbBits = ZSTD_highbit32(remaining) + 1; + threshold = 1 << (nbBits - 1); } + if (charnum >= maxSV1) break; - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { ip += bitCount>>3; bitCount &= 7; } else { bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; ip = iend - 4; } - bitStream = MEM_readLE32(ip) >> (bitCount & 31); - } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */ + bitStream = MEM_readLE32(ip) >> bitCount; + } } if (remaining != 1) return ERROR(corruption_detected); + /* Only possible when there are too many zeros. */ + if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall); if (bitCount > 32) return ERROR(corruption_detected); *maxSVPtr = charnum-1; @@ -164,6 +187,43 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t return ip-istart; } +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_readNCount_body_default( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} +#endif + +size_t FSE_readNCount_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); + } +#endif + (void)bmi2; + return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +size_t FSE_readNCount( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0); +} + /*! HUF_readStats() : Read compact Huffman tree, saved by HUF_writeCTable(). @@ -175,6 +235,17 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, const void* src, size_t srcSize) +{ + U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0); +} + +FORCE_INLINE_TEMPLATE size_t +HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) { U32 weightTotal; const BYTE* ip = (const BYTE*) src; @@ -183,7 +254,7 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ + /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ oSize = iSize - 127; @@ -197,31 +268,31 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, huffWeight[n+1] = ip[n/2] & 15; } } } else { /* header compressed with FSE (normal case) */ - FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */ if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */ + /* max (hwSize-1) values decoded, as last one is implied */ + oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2); if (FSE_isError(oSize)) return oSize; } /* collect weight stats */ - memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); + ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); weightTotal = 0; { U32 n; for (n=0; n= HUF_TABLELOG_MAX) return ERROR(corruption_detected); + if (huffWeight[n] > HUF_TABLELOG_MAX) return ERROR(corruption_detected); rankStats[huffWeight[n]]++; weightTotal += (1 << huffWeight[n]) >> 1; } } if (weightTotal == 0) return ERROR(corruption_detected); /* get last non-null symbol weight (implied, total must be 2^n) */ - { U32 const tableLog = BIT_highbit32(weightTotal) + 1; + { U32 const tableLog = ZSTD_highbit32(weightTotal) + 1; if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); *tableLogPtr = tableLog; /* determine last weight */ { U32 const total = 1 << tableLog; U32 const rest = total - weightTotal; - U32 const verif = 1 << BIT_highbit32(rest); - U32 const lastWeight = BIT_highbit32(rest) + 1; + U32 const verif = 1 << ZSTD_highbit32(rest); + U32 const lastWeight = ZSTD_highbit32(rest) + 1; if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ huffWeight[oSize] = (BYTE)lastWeight; rankStats[lastWeight]++; @@ -234,3 +305,37 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, *nbSymbolsPtr = (U32)(oSize+1); return iSize+1; } + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); +} +#endif + +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); + } +#endif + (void)bmi2; + return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); +} diff --git a/native/zstd/common/error_private.c b/native/zstd/common/error_private.c old mode 100755 new mode 100644 index 7c1bb67..1b67500 --- a/native/zstd/common/error_private.c +++ b/native/zstd/common/error_private.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -27,7 +27,7 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(version_unsupported): return "Version not supported"; case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; - case PREFIX(corruption_detected): return "Corrupted block detected"; + case PREFIX(corruption_detected): return "Data corruption detected"; case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; case PREFIX(parameter_unsupported): return "Unsupported parameter"; case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; @@ -38,6 +38,7 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; + case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected"; case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; case PREFIX(dictionary_wrong): return "Dictionary mismatch"; case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; @@ -47,6 +48,8 @@ const char* ERR_getErrorString(ERR_enum code) /* following error codes are not stable and may be removed or changed in a future version */ case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; + case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; + case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; case PREFIX(maxCode): default: return notErrorCode; } diff --git a/native/zstd/common/error_private.h b/native/zstd/common/error_private.h old mode 100755 new mode 100644 index 0d2fa7e..007d810 --- a/native/zstd/common/error_private.h +++ b/native/zstd/common/error_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -21,8 +21,10 @@ extern "C" { /* **************************************** * Dependencies ******************************************/ -#include /* size_t */ -#include "zstd_errors.h" /* enum list */ +#include "../zstd_errors.h" /* enum list */ +#include "compiler.h" +#include "debug.h" +#include "zstd_deps.h" /* size_t */ /* **************************************** @@ -49,7 +51,7 @@ typedef ZSTD_ErrorCode ERR_enum; /*-**************************************** * Error codes handling ******************************************/ -#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ +#undef ERROR /* already defined on Visual Studio */ #define ERROR(name) ZSTD_ERROR(name) #define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) @@ -57,6 +59,10 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } +/* check and forward error code */ +#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e +#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } + /*-**************************************** * Error Strings @@ -69,6 +75,83 @@ ERR_STATIC const char* ERR_getErrorName(size_t code) return ERR_getErrorString(ERR_getErrorCode(code)); } +/** + * Ignore: this is an internal helper. + * + * This is a helper function to help force C99-correctness during compilation. + * Under strict compilation modes, variadic macro arguments can't be empty. + * However, variadic function arguments can be. Using a function therefore lets + * us statically check that at least one (string) argument was passed, + * independent of the compilation flags. + */ +static INLINE_KEYWORD UNUSED_ATTR +void _force_has_format_string(const char *format, ...) { + (void)format; +} + +/** + * Ignore: this is an internal helper. + * + * We want to force this function invocation to be syntactically correct, but + * we don't want to force runtime evaluation of its arguments. + */ +#define _FORCE_HAS_FORMAT_STRING(...) \ + if (0) { \ + _force_has_format_string(__VA_ARGS__); \ + } + +#define ERR_QUOTE(str) #str + +/** + * Return the specified error if the condition evaluates to true. + * + * In debug modes, prints additional information. + * In order to do that (particularly, printing the conditional that failed), + * this can't just wrap RETURN_ERROR(). + */ +#define RETURN_ERROR_IF(cond, err, ...) \ + if (cond) { \ + RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } + +/** + * Unconditionally return the specified error. + * + * In debug modes, prints additional information. + */ +#define RETURN_ERROR(err, ...) \ + do { \ + RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } while(0); + +/** + * If the provided expression evaluates to an error code, returns that error code. + * + * In debug modes, prints additional information. + */ +#define FORWARD_IF_ERROR(err, ...) \ + do { \ + size_t const err_code = (err); \ + if (ERR_isError(err_code)) { \ + RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ + __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return err_code; \ + } \ + } while(0); + #if defined (__cplusplus) } #endif diff --git a/native/zstd/common/fse.h b/native/zstd/common/fse.h old mode 100755 new mode 100644 index a7553e3..466a072 --- a/native/zstd/common/fse.h +++ b/native/zstd/common/fse.h @@ -1,35 +1,15 @@ /* ****************************************************************** - FSE : Finite State Entropy codec - Public Prototypes declaration - Copyright (C) 2013-2016, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * FSE : Finite State Entropy codec + * Public Prototypes declaration + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * 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. ****************************************************************** */ #if defined (__cplusplus) @@ -43,7 +23,7 @@ extern "C" { /*-***************************************** * Dependencies ******************************************/ -#include /* size_t, ptrdiff_t */ +#include "zstd_deps.h" /* size_t, ptrdiff_t */ /*-***************************************** @@ -157,10 +137,16 @@ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize /*! FSE_normalizeCount(): normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). + useLowProbCount is a boolean parameter which trades off compressed size for + faster header decoding. When it is set to 1, the compressed data will be slightly + smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be + faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0 + is a good default, since header deserialization makes a big speed difference. + Otherwise, useLowProbCount=1 is a good default, since the speed difference is small. @return : tableLog, or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, - const unsigned* count, size_t srcSize, unsigned maxSymbolValue); + const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount); /*! FSE_NCountWriteBound(): Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. @@ -248,6 +234,13 @@ FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize); +/*! FSE_readNCount_bmi2(): + * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise. + */ +FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize, int bmi2); + /*! Constructor and Destructor of FSE_DTable. Note that its size depends on 'tableLog' */ typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ @@ -308,12 +301,12 @@ If there is an error, the function will return an error code, which can be teste *******************************************/ /* FSE buffer bounds */ #define FSE_NCOUNTBOUND 512 -#define FSE_BLOCKBOUND(size) (size + (size>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) +#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) #define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ /* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ -#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2)) -#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1< 12) ? (1 << (maxTableLog - 2)) : 1024) ) +#define FSE_COMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) ) size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits); @@ -342,18 +335,31 @@ size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); /* FSE_buildCTable_wksp() : * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). - * `wkspSize` must be >= `(1<= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`. + * See FSE_buildCTable_wksp() for breakdown of workspace usage. */ +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */) +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)) size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); +#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8) +#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned)) +FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); +/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */ + size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits); /**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */ size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue); /**< build a fake FSE_DTable, designed to always generate the same symbolValue */ -size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog); -/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */ +#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + 1 + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1) +#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned)) +size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize); +/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */ + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2); +/**< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */ typedef enum { FSE_repeat_none, /**< Cannot use the previous table */ @@ -549,7 +555,7 @@ MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePt /* FSE_getMaxNbBits() : * Approximate maximum cost of a symbol, in bits. - * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) + * Fractional get rounded up (i.e. a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) * note 1 : assume symbolValue is valid (<= maxSymbolValue) * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) @@ -664,6 +670,9 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) #ifndef FSE_DEFAULT_MEMORY_USAGE # define FSE_DEFAULT_MEMORY_USAGE 13 #endif +#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE) +# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE" +#endif /*!FSE_MAX_SYMBOL_VALUE : * Maximum symbol value authorized. @@ -697,7 +706,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) # error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" #endif -#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3) +#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3) #endif /* FSE_STATIC_LINKING_ONLY */ diff --git a/native/zstd/common/fse_decompress.c b/native/zstd/common/fse_decompress.c old mode 100755 new mode 100644 index 4f07378..7034fd9 --- a/native/zstd/common/fse_decompress.c +++ b/native/zstd/common/fse_decompress.c @@ -1,48 +1,30 @@ /* ****************************************************************** - FSE : Finite State Entropy decoder - Copyright (C) 2013-2015, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c + * FSE : Finite State Entropy decoder + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * 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. ****************************************************************** */ /* ************************************************************** * Includes ****************************************************************/ -#include /* malloc, free, qsort */ -#include /* memcpy, memset */ +#include "debug.h" /* assert */ #include "bitstream.h" #include "compiler.h" #define FSE_STATIC_LINKING_ONLY #include "fse.h" #include "error_private.h" +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" +#include "bits.h" /* ZSTD_highbit32 */ /* ************************************************************** @@ -51,11 +33,6 @@ #define FSE_isError ERR_isError #define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ -/* check and forward error code */ -#ifndef CHECK_F -#define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; } -#endif - /* ************************************************************** * Templates @@ -84,25 +61,27 @@ FSE_DTable* FSE_createDTable (unsigned tableLog) { if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; - return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); + return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); } void FSE_freeDTable (FSE_DTable* dt) { - free(dt); + ZSTD_free(dt); } -size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) +static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) { void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); - U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1]; + U16* symbolNext = (U16*)workSpace; + BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; U32 highThreshold = tableSize-1; /* Sanity Checks */ + if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); @@ -120,11 +99,57 @@ size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0; symbolNext[s] = normalizedCounter[s]; } } } - memcpy(dt, &DTableH, sizeof(DTableH)); + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - { U32 const tableMask = tableSize-1; + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */ - if (tableLog > maxLog) return ERROR(tableLog_tooLarge); - ip += NCountLength; - cSrcSize -= NCountLength; + { + size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); + if (FSE_isError(NCountLength)) return NCountLength; + if (tableLog > maxLog) return ERROR(tableLog_tooLarge); + assert(NCountLength <= cSrcSize); + ip += NCountLength; + cSrcSize -= NCountLength; + } + + if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); + assert(sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog) <= wkspSize); + workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + + CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); - CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) ); + { + const void* ptr = wksp->dtable; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; - return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */ + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1); + return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0); + } +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); +} +#endif + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); + } +#endif + (void)bmi2; + return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); } typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) { + U32 wksp[FSE_BUILD_DTABLE_WKSP_SIZE_U32(FSE_TABLELOG_ABSOLUTE_MAX, FSE_MAX_SYMBOL_VALUE)]; + return FSE_buildDTable_wksp(dt, normalizedCounter, maxSymbolValue, tableLog, wksp, sizeof(wksp)); +} + size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) { - DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ - return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG); + /* Static analyzer seems unable to understand this table will be properly initialized later */ + U32 wksp[FSE_DECOMPRESS_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)]; + return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, FSE_MAX_TABLELOG, wksp, sizeof(wksp)); } - +#endif #endif /* FSE_COMMONDEFS_ONLY */ diff --git a/native/zstd/common/huf.h b/native/zstd/common/huf.h old mode 100755 new mode 100644 index 6b572c4..8551848 --- a/native/zstd/common/huf.h +++ b/native/zstd/common/huf.h @@ -1,35 +1,15 @@ /* ****************************************************************** - huff0 huffman codec, - part of Finite State Entropy library - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * huff0 huffman codec, + * part of Finite State Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * 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. ****************************************************************** */ #if defined (__cplusplus) @@ -40,7 +20,7 @@ extern "C" { #define HUF_H_298734234 /* *** Dependencies *** */ -#include /* size_t */ +#include "zstd_deps.h" /* size_t */ /* *** library symbols visibility *** */ @@ -109,9 +89,9 @@ HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, /** HUF_compress4X_wksp() : * Same as HUF_compress2(), but uses externally allocated `workSpace`. - * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */ -#define HUF_WORKSPACE_SIZE (6 << 10) -#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32)) + * `workspace` must be at least as large as HUF_WORKSPACE_SIZE */ +#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */) +#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64)) HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, @@ -131,14 +111,16 @@ HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, /* *** Dependencies *** */ #include "mem.h" /* U32 */ +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" /* *** Constants *** */ -#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */ +#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */ #define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ #define HUF_SYMBOLVALUE_MAX 255 -#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ #if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) # error "HUF_TABLELOG_MAX is too large !" #endif @@ -153,12 +135,12 @@ HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, #define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ /* static allocation of HUF's Compression Table */ -#define HUF_CTABLE_SIZE_U32(maxSymbolValue) ((maxSymbolValue)+1) /* Use tables of U32, for proper alignment */ -#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32)) +/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */ +typedef size_t HUF_CElt; /* consider it an incomplete type */ +#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */ +#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t)) #define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ - U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \ - void* name##hv = &(name##hb); \ - HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */ + HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */ /* static allocation of HUF's DTable */ typedef U32 HUF_DTable; @@ -204,10 +186,13 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, * or to save and regenerate 'CTable' using external methods. */ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); -typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */ size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */ size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); +size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize); size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2); +size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); typedef enum { HUF_repeat_none, /**< Cannot use the previous table */ @@ -218,12 +203,13 @@ typedef enum { * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. * If it uses hufTable it does not modify hufTable or repeat. * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. */ + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ size_t HUF_compress4X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible); /** HUF_buildCTable_wksp() : * Same as HUF_buildCTable(), but using externally allocated scratch buffer. @@ -244,15 +230,27 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, const void* src, size_t srcSize); +/*! HUF_readStats_wksp() : + * Same as HUF_readStats() but takes an external workspace which must be + * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1) +#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workspace, size_t wkspSize, + int bmi2); + /** HUF_readCTable() : * Loading a CTable saved with HUF_writeCTable() */ -size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); -/** HUF_getNbBits() : +/** HUF_getNbBitsFromCTable() : * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX - * Note 1 : is not inlined, as HUF_CElt definition is private - * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */ -U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue); + * Note 1 : is not inlined, as HUF_CElt definition is private */ +U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue); /* * HUF_decompress() does the following: @@ -278,7 +276,7 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); * a required workspace size greater than that specified in the following * macro. */ -#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10) +#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9)) #define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) #ifndef HUF_FORCE_DECOMPRESS_X2 @@ -304,18 +302,20 @@ size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* c /* ====================== */ size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); -size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ +size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U64 U64 */ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2); /** HUF_compress1X_repeat() : * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. * If it uses hufTable it does not modify hufTable or repeat. * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. */ + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ size_t HUF_compress1X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible); size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ #ifndef HUF_FORCE_DECOMPRESS_X1 @@ -350,6 +350,12 @@ size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstS #endif size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif #endif /* HUF_STATIC_LINKING_ONLY */ diff --git a/native/zstd/common/mem.h b/native/zstd/common/mem.h old mode 100755 new mode 100644 index 530d30c..4b10f7c --- a/native/zstd/common/mem.h +++ b/native/zstd/common/mem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -18,8 +18,10 @@ extern "C" { /*-**************************************** * Dependencies ******************************************/ -#include /* size_t, ptrdiff_t */ -#include /* memcpy */ +#include /* size_t, ptrdiff_t */ +#include "compiler.h" /* __has_builtin */ +#include "debug.h" /* DEBUG_STATIC_ASSERT */ +#include "zstd_deps.h" /* ZSTD_memcpy */ /*-**************************************** @@ -39,94 +41,18 @@ extern "C" { # define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ #endif -#ifndef __has_builtin -# define __has_builtin(x) 0 /* compat. with non-clang compilers */ -#endif - -/* code only tested on 32 and 64 bits systems */ -#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; } -MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } - -/* detects whether we are being compiled under msan */ -#if defined (__has_feature) -# if __has_feature(memory_sanitizer) -# define MEMORY_SANITIZER 1 -# endif -#endif - -#if defined (MEMORY_SANITIZER) -/* Not all platforms that support msan provide sanitizers/msan_interface.h. - * We therefore declare the functions we need ourselves, rather than trying to - * include the header file... */ - -#include /* intptr_t */ - -/* Make memory region fully initialized (without changing its contents). */ -void __msan_unpoison(const volatile void *a, size_t size); - -/* Make memory region fully uninitialized (without changing its contents). - This is a legacy interface that does not update origin information. Use - __msan_allocated_memory() instead. */ -void __msan_poison(const volatile void *a, size_t size); - -/* Returns the offset of the first (at least partially) poisoned byte in the - memory range, or -1 if the whole range is good. */ -intptr_t __msan_test_shadow(const volatile void *x, size_t size); -#endif - -/* detects whether we are being compiled under asan */ -#if defined (__has_feature) -# if __has_feature(address_sanitizer) -# define ADDRESS_SANITIZER 1 -# endif -#elif defined(__SANITIZE_ADDRESS__) -# define ADDRESS_SANITIZER 1 -#endif - -#if defined (ADDRESS_SANITIZER) -/* Not all platforms that support asan provide sanitizers/asan_interface.h. - * We therefore declare the functions we need ourselves, rather than trying to - * include the header file... */ - -/** - * Marks a memory region ([addr, addr+size)) as unaddressable. - * - * This memory must be previously allocated by your program. Instrumented - * code is forbidden from accessing addresses in this region until it is - * unpoisoned. This function is not guaranteed to poison the entire region - - * it could poison only a subregion of [addr, addr+size) due to ASan - * alignment restrictions. - * - * \note This function is not thread-safe because no two threads can poison or - * unpoison memory in the same memory region simultaneously. - * - * \param addr Start of memory region. - * \param size Size of memory region. */ -void __asan_poison_memory_region(void const volatile *addr, size_t size); - -/** - * Marks a memory region ([addr, addr+size)) as addressable. - * - * This memory must be previously allocated by your program. Accessing - * addresses in this region is allowed until this region is poisoned again. - * This function could unpoison a super-region of [addr, addr+size) due - * to ASan alignment restrictions. - * - * \note This function is not thread-safe because no two threads can - * poison or unpoison memory in the same memory region simultaneously. - * - * \param addr Start of memory region. - * \param size Size of memory region. */ -void __asan_unpoison_memory_region(void const volatile *addr, size_t size); -#endif - - /*-************************************************************** * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; + typedef uint8_t U8; + typedef int8_t S8; typedef uint16_t U16; typedef int16_t S16; typedef uint32_t U32; @@ -139,6 +65,8 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); # error "this implementation requires char to be exactly 8-bit type" #endif typedef unsigned char BYTE; + typedef unsigned char U8; + typedef signed char S8; #if USHRT_MAX != 65535 # error "this implementation requires short to be exactly 16-bit type" #endif @@ -157,7 +85,53 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); /*-************************************************************** -* Memory I/O +* Memory I/O API +*****************************************************************/ +/*=== Static platform detection ===*/ +MEM_STATIC unsigned MEM_32bits(void); +MEM_STATIC unsigned MEM_64bits(void); +MEM_STATIC unsigned MEM_isLittleEndian(void); + +/*=== Native unaligned read/write ===*/ +MEM_STATIC U16 MEM_read16(const void* memPtr); +MEM_STATIC U32 MEM_read32(const void* memPtr); +MEM_STATIC U64 MEM_read64(const void* memPtr); +MEM_STATIC size_t MEM_readST(const void* memPtr); + +MEM_STATIC void MEM_write16(void* memPtr, U16 value); +MEM_STATIC void MEM_write32(void* memPtr, U32 value); +MEM_STATIC void MEM_write64(void* memPtr, U64 value); + +/*=== Little endian unaligned read/write ===*/ +MEM_STATIC U16 MEM_readLE16(const void* memPtr); +MEM_STATIC U32 MEM_readLE24(const void* memPtr); +MEM_STATIC U32 MEM_readLE32(const void* memPtr); +MEM_STATIC U64 MEM_readLE64(const void* memPtr); +MEM_STATIC size_t MEM_readLEST(const void* memPtr); + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val); +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val); +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val); + +/*=== Big endian unaligned read/write ===*/ +MEM_STATIC U32 MEM_readBE32(const void* memPtr); +MEM_STATIC U64 MEM_readBE64(const void* memPtr); +MEM_STATIC size_t MEM_readBEST(const void* memPtr); + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val); + +/*=== Byteswap ===*/ +MEM_STATIC U32 MEM_swap32(U32 in); +MEM_STATIC U64 MEM_swap64(U64 in); +MEM_STATIC size_t MEM_swapST(size_t in); + + +/*-************************************************************** +* Memory I/O Implementation *****************************************************************/ /* MEM_FORCE_MEMORY_ACCESS : * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. @@ -173,9 +147,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -185,8 +157,22 @@ MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } MEM_STATIC unsigned MEM_isLittleEndian(void) { +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + return 1; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + return 0; +#elif defined(__clang__) && __LITTLE_ENDIAN__ + return 1; +#elif defined(__clang__) && __BIG_ENDIAN__ + return 0; +#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86) + return 1; +#elif defined(__DMC__) && defined(_M_IX86) + return 1; +#else const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; +#endif } #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) @@ -236,41 +222,49 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = MEM_STATIC U16 MEM_read16(const void* memPtr) { - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U32 MEM_read32(const void* memPtr) { - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U64 MEM_read64(const void* memPtr) { - U64 val; memcpy(&val, memPtr, sizeof(val)); return val; + U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC size_t MEM_readST(const void* memPtr) { - size_t val; memcpy(&val, memPtr, sizeof(val)); return val; + size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC void MEM_write16(void* memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + ZSTD_memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write32(void* memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + ZSTD_memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write64(void* memPtr, U64 value) { - memcpy(memPtr, &value, sizeof(value)); + ZSTD_memcpy(memPtr, &value, sizeof(value)); } #endif /* MEM_FORCE_MEMORY_ACCESS */ +MEM_STATIC U32 MEM_swap32_fallback(U32 in) +{ + return ((in << 24) & 0xff000000 ) | + ((in << 8) & 0x00ff0000 ) | + ((in >> 8) & 0x0000ff00 ) | + ((in >> 24) & 0x000000ff ); +} + MEM_STATIC U32 MEM_swap32(U32 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -279,22 +273,13 @@ MEM_STATIC U32 MEM_swap32(U32 in) || (defined(__clang__) && __has_builtin(__builtin_bswap32)) return __builtin_bswap32(in); #else - return ((in << 24) & 0xff000000 ) | - ((in << 8) & 0x00ff0000 ) | - ((in >> 8) & 0x0000ff00 ) | - ((in >> 24) & 0x000000ff ); + return MEM_swap32_fallback(in); #endif } -MEM_STATIC U64 MEM_swap64(U64 in) +MEM_STATIC U64 MEM_swap64_fallback(U64 in) { -#if defined(_MSC_VER) /* Visual Studio */ - return _byteswap_uint64(in); -#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ - || (defined(__clang__) && __has_builtin(__builtin_bswap64)) - return __builtin_bswap64(in); -#else - return ((in << 56) & 0xff00000000000000ULL) | + return ((in << 56) & 0xff00000000000000ULL) | ((in << 40) & 0x00ff000000000000ULL) | ((in << 24) & 0x0000ff0000000000ULL) | ((in << 8) & 0x000000ff00000000ULL) | @@ -302,6 +287,17 @@ MEM_STATIC U64 MEM_swap64(U64 in) ((in >> 24) & 0x0000000000ff0000ULL) | ((in >> 40) & 0x000000000000ff00ULL) | ((in >> 56) & 0x00000000000000ffULL); +} + +MEM_STATIC U64 MEM_swap64(U64 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_uint64(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap64)) + return __builtin_bswap64(in); +#else + return MEM_swap64_fallback(in); #endif } @@ -338,7 +334,7 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) MEM_STATIC U32 MEM_readLE24(const void* memPtr) { - return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); + return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16); } MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) @@ -445,6 +441,9 @@ MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) MEM_writeBE64(memPtr, (U64)val); } +/* code only tested on 32 and 64 bits systems */ +MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } + #if defined (__cplusplus) } diff --git a/native/zstd/common/pool.c b/native/zstd/common/pool.c old mode 100755 new mode 100644 index f575935..5c1d07d --- a/native/zstd/common/pool.c +++ b/native/zstd/common/pool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -10,9 +10,9 @@ /* ====== Dependencies ======= */ -#include /* size_t */ +#include "zstd_deps.h" /* size_t */ #include "debug.h" /* assert */ -#include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */ +#include "zstd_internal.h" /* ZSTD_customMalloc, ZSTD_customFree */ #include "pool.h" /* ====== Compiler specifics ====== */ @@ -86,7 +86,7 @@ static void* POOL_thread(void* opaque) { { POOL_job const job = ctx->queue[ctx->queueHead]; ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; ctx->numThreadsBusy++; - ctx->queueEmpty = ctx->queueHead == ctx->queueTail; + ctx->queueEmpty = (ctx->queueHead == ctx->queueTail); /* Unlock the mutex, signal a pusher, and run the job */ ZSTD_pthread_cond_signal(&ctx->queuePushCond); ZSTD_pthread_mutex_unlock(&ctx->queueMutex); @@ -96,33 +96,37 @@ static void* POOL_thread(void* opaque) { /* If the intended queue size was 0, signal after finishing job */ ZSTD_pthread_mutex_lock(&ctx->queueMutex); ctx->numThreadsBusy--; - if (ctx->queueSize == 1) { - ZSTD_pthread_cond_signal(&ctx->queuePushCond); - } + ZSTD_pthread_cond_signal(&ctx->queuePushCond); ZSTD_pthread_mutex_unlock(&ctx->queueMutex); } } /* for (;;) */ assert(0); /* Unreachable */ } +/* ZSTD_createThreadPool() : public access point */ +POOL_ctx* ZSTD_createThreadPool(size_t numThreads) { + return POOL_create (numThreads, 0); +} + POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); } POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, - ZSTD_customMem customMem) { + ZSTD_customMem customMem) +{ POOL_ctx* ctx; /* Check parameters */ if (!numThreads) { return NULL; } /* Allocate the context and zero initialize */ - ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem); + ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem); if (!ctx) { return NULL; } /* Initialize the job queue. * It needs one extra space since one space is wasted to differentiate * empty and full queues. */ ctx->queueSize = queueSize + 1; - ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem); + ctx->queue = (POOL_job*)ZSTD_customMalloc(ctx->queueSize * sizeof(POOL_job), customMem); ctx->queueHead = 0; ctx->queueTail = 0; ctx->numThreadsBusy = 0; @@ -136,7 +140,7 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, } ctx->shutdown = 0; /* Allocate space for the thread handles */ - ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem); + ctx->threads = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); ctx->threadCapacity = 0; ctx->customMem = customMem; /* Check for errors */ @@ -179,14 +183,27 @@ void POOL_free(POOL_ctx *ctx) { ZSTD_pthread_mutex_destroy(&ctx->queueMutex); ZSTD_pthread_cond_destroy(&ctx->queuePushCond); ZSTD_pthread_cond_destroy(&ctx->queuePopCond); - ZSTD_free(ctx->queue, ctx->customMem); - ZSTD_free(ctx->threads, ctx->customMem); - ZSTD_free(ctx, ctx->customMem); + ZSTD_customFree(ctx->queue, ctx->customMem); + ZSTD_customFree(ctx->threads, ctx->customMem); + ZSTD_customFree(ctx, ctx->customMem); } +/*! POOL_joinJobs() : + * Waits for all queued jobs to finish executing. + */ +void POOL_joinJobs(POOL_ctx* ctx) { + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + while(!ctx->queueEmpty || ctx->numThreadsBusy > 0) { + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + } + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); +} +void ZSTD_freeThreadPool (ZSTD_threadPool* pool) { + POOL_free (pool); +} -size_t POOL_sizeof(POOL_ctx *ctx) { +size_t POOL_sizeof(const POOL_ctx* ctx) { if (ctx==NULL) return 0; /* supports sizeof NULL */ return sizeof(*ctx) + ctx->queueSize * sizeof(POOL_job) @@ -203,11 +220,11 @@ static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) return 0; } /* numThreads > threadCapacity */ - { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); + { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); if (!threadPool) return 1; /* replace existing thread pool */ - memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); - ZSTD_free(ctx->threads, ctx->customMem); + ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); + ZSTD_customFree(ctx->threads, ctx->customMem); ctx->threads = threadPool; /* Initialize additional threads */ { size_t threadId; @@ -251,7 +268,8 @@ static int isQueueFull(POOL_ctx const* ctx) { } -static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) +static void +POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) { POOL_job const job = {function, opaque}; assert(ctx != NULL); @@ -301,21 +319,28 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) struct POOL_ctx_s { int dummy; }; -static POOL_ctx g_ctx; +static POOL_ctx g_poolCtx; POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); } -POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) { +POOL_ctx* +POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) +{ (void)numThreads; (void)queueSize; (void)customMem; - return &g_ctx; + return &g_poolCtx; } void POOL_free(POOL_ctx* ctx) { - assert(!ctx || ctx == &g_ctx); + assert(!ctx || ctx == &g_poolCtx); + (void)ctx; +} + +void POOL_joinJobs(POOL_ctx* ctx){ + assert(!ctx || ctx == &g_poolCtx); (void)ctx; } @@ -335,9 +360,9 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { return 1; } -size_t POOL_sizeof(POOL_ctx* ctx) { +size_t POOL_sizeof(const POOL_ctx* ctx) { if (ctx==NULL) return 0; /* supports sizeof NULL */ - assert(ctx == &g_ctx); + assert(ctx == &g_poolCtx); return sizeof(*ctx); } diff --git a/native/zstd/common/pool.h b/native/zstd/common/pool.h old mode 100755 new mode 100644 index 458d37f..b86a345 --- a/native/zstd/common/pool.h +++ b/native/zstd/common/pool.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,9 +16,9 @@ extern "C" { #endif -#include /* size_t */ +#include "zstd_deps.h" #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ -#include "zstd.h" +#include "../zstd.h" typedef struct POOL_ctx_s POOL_ctx; @@ -38,6 +38,12 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, */ void POOL_free(POOL_ctx* ctx); + +/*! POOL_joinJobs() : + * Waits for all queued jobs to finish executing. + */ +void POOL_joinJobs(POOL_ctx* ctx); + /*! POOL_resize() : * Expands or shrinks pool's number of threads. * This is more efficient than releasing + creating a new context, @@ -53,7 +59,7 @@ int POOL_resize(POOL_ctx* ctx, size_t numThreads); * @return threadpool memory usage * note : compatible with NULL (returns 0 in this case) */ -size_t POOL_sizeof(POOL_ctx* ctx); +size_t POOL_sizeof(const POOL_ctx* ctx); /*! POOL_function : * The function type that can be added to a thread pool. @@ -70,7 +76,7 @@ void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); /*! POOL_tryAdd() : - * Add the job `function(opaque)` to thread pool _if_ a worker is available. + * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. * Returns immediately even if not (does not block). * @return : 1 if successful, 0 if not. */ diff --git a/native/zstd/common/portability_macros.h b/native/zstd/common/portability_macros.h new file mode 100644 index 0000000..1650fa3 --- /dev/null +++ b/native/zstd/common/portability_macros.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) Facebook, Inc. + * 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. + */ + +#ifndef ZSTD_PORTABILITY_MACROS_H +#define ZSTD_PORTABILITY_MACROS_H + +/** + * This header file contains macro definitions to support portability. + * This header is shared between C and ASM code, so it MUST only + * contain macro definitions. It MUST not contain any C code. + * + * This header ONLY defines macros to detect platforms/feature support. + * + */ + + +/* compat. with non-clang compilers */ +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +/* detects whether we are being compiled under msan */ +#ifndef ZSTD_MEMORY_SANITIZER +# if __has_feature(memory_sanitizer) +# define ZSTD_MEMORY_SANITIZER 1 +# else +# define ZSTD_MEMORY_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under asan */ +#ifndef ZSTD_ADDRESS_SANITIZER +# if __has_feature(address_sanitizer) +# define ZSTD_ADDRESS_SANITIZER 1 +# elif defined(__SANITIZE_ADDRESS__) +# define ZSTD_ADDRESS_SANITIZER 1 +# else +# define ZSTD_ADDRESS_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under dfsan */ +#ifndef ZSTD_DATAFLOW_SANITIZER +# if __has_feature(dataflow_sanitizer) +# define ZSTD_DATAFLOW_SANITIZER 1 +# else +# define ZSTD_DATAFLOW_SANITIZER 0 +# endif +#endif + +/* Mark the internal assembly functions as hidden */ +#ifdef __ELF__ +# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func +#else +# define ZSTD_HIDE_ASM_FUNCTION(func) +#endif + +/* Enable runtime BMI2 dispatch based on the CPU. + * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. + */ +#ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (defined(__x86_64__) || defined(_M_X64)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 + #else + # define DYNAMIC_BMI2 0 + #endif +#endif + +/** + * Only enable assembly for GNUC compatible compilers, + * because other platforms may not support GAS assembly syntax. + * + * Only enable assembly for Linux / MacOS, other platforms may + * work, but they haven't been tested. This could likely be + * extended to BSD systems. + * + * Disable assembly when MSAN is enabled, because MSAN requires + * 100% of code to be instrumented to work. + */ +#if defined(__GNUC__) +# if defined(__linux__) || defined(__linux) || defined(__APPLE__) +# if ZSTD_MEMORY_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# elif ZSTD_DATAFLOW_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# else +# define ZSTD_ASM_SUPPORTED 1 +# endif +# else +# define ZSTD_ASM_SUPPORTED 0 +# endif +#else +# define ZSTD_ASM_SUPPORTED 0 +#endif + +/** + * Determines whether we should enable assembly for x86-64 + * with BMI2. + * + * Enable if all of the following conditions hold: + * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM + * - Assembly is supported + * - We are compiling for x86-64 and either: + * - DYNAMIC_BMI2 is enabled + * - BMI2 is supported at compile time + */ +#if !defined(ZSTD_DISABLE_ASM) && \ + ZSTD_ASM_SUPPORTED && \ + defined(__x86_64__) && \ + (DYNAMIC_BMI2 || defined(__BMI2__)) +# define ZSTD_ENABLE_ASM_X86_64_BMI2 1 +#else +# define ZSTD_ENABLE_ASM_X86_64_BMI2 0 +#endif + +/* + * For x86 ELF targets, add .note.gnu.property section for Intel CET in + * assembly sources when CET is enabled. + */ +#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \ + && defined(__has_include) +# if __has_include() +# include +# endif +#endif + +#endif /* ZSTD_PORTABILITY_MACROS_H */ diff --git a/native/zstd/common/threading.c b/native/zstd/common/threading.c old mode 100755 new mode 100644 index 482664b..4f69f76 --- a/native/zstd/common/threading.c +++ b/native/zstd/common/threading.c @@ -2,12 +2,13 @@ * Copyright (c) 2016 Tino Reichardt * All rights reserved. * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * * 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 can contact the author at: - * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * You may select, at your option, one of the above-listed licenses. */ /** @@ -62,6 +63,8 @@ int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr) if (!thread.handle) return 0; result = WaitForSingleObject(thread.handle, INFINITE); + CloseHandle(thread.handle); + switch (result) { case WAIT_OBJECT_0: if (value_ptr) *value_ptr = thread.arg; @@ -77,11 +80,12 @@ int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr) #if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) -#include +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) { - *mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); + *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); if (!*mutex) return 1; return pthread_mutex_init(*mutex, attr); @@ -93,14 +97,14 @@ int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) return 0; { int const ret = pthread_mutex_destroy(*mutex); - free(*mutex); + ZSTD_free(*mutex); return ret; } } int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) { - *cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t)); + *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); if (!*cond) return 1; return pthread_cond_init(*cond, attr); @@ -112,7 +116,7 @@ int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) return 0; { int const ret = pthread_cond_destroy(*cond); - free(*cond); + ZSTD_free(*cond); return ret; } } diff --git a/native/zstd/common/threading.h b/native/zstd/common/threading.h old mode 100755 new mode 100644 index 3193ca7..fd0060d --- a/native/zstd/common/threading.h +++ b/native/zstd/common/threading.h @@ -2,12 +2,13 @@ * Copyright (c) 2016 Tino Reichardt * All rights reserved. * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * * 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 can contact the author at: - * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * You may select, at your option, one of the above-listed licenses. */ #ifndef THREADING_H_938743 diff --git a/native/zstd/common/xxhash.c b/native/zstd/common/xxhash.c old mode 100755 new mode 100644 index 99d2459..d49497c --- a/native/zstd/common/xxhash.c +++ b/native/zstd/common/xxhash.c @@ -1,882 +1,24 @@ /* -* xxHash - Fast Hash algorithm -* Copyright (C) 2012-2016, Yann Collet -* -* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above -* copyright notice, this list of conditions and the following disclaimer -* in the documentation and/or other materials provided with the -* distribution. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* You can contact the author at : -* - xxHash homepage: http://www.xxhash.com -* - xxHash source repository : https://github.com/Cyan4973/xxHash + * xxHash - Fast Hash algorithm + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - xxHash homepage: http://www.xxhash.com + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * 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. */ -/* ************************************* -* Tuning parameters -***************************************/ -/*!XXH_FORCE_MEMORY_ACCESS : - * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. - * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. - * The below switch allow to select different access method for improved performance. - * Method 0 (default) : use `memcpy()`. Safe and portable. - * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). - * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. - * Method 2 : direct access. This method doesn't depend on compiler but violate C standard. - * It can generate buggy code on targets which do not support unaligned memory accesses. - * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) - * See http://stackoverflow.com/a/32095106/646947 for details. - * Prefer these methods in priority order (0 > 1 > 2) - */ -#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define XXH_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) || \ - defined(__ICCARM__) -# define XXH_FORCE_MEMORY_ACCESS 1 -# endif -#endif - -/*!XXH_ACCEPT_NULL_INPUT_POINTER : - * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer. - * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input. - * By default, this option is disabled. To enable it, uncomment below define : - */ -/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */ - -/*!XXH_FORCE_NATIVE_FORMAT : - * By default, xxHash library provides endian-independent Hash values, based on little-endian convention. - * Results are therefore identical for little-endian and big-endian CPU. - * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. - * Should endian-independence be of no importance for your application, you may set the #define below to 1, - * to improve speed for Big-endian CPU. - * This option has no impact on Little_Endian CPU. - */ -#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */ -# define XXH_FORCE_NATIVE_FORMAT 0 -#endif -/*!XXH_FORCE_ALIGN_CHECK : - * This is a minor performance trick, only useful with lots of very small keys. - * It means : check for aligned/unaligned input. - * The check costs one initial branch per hash; set to 0 when the input data - * is guaranteed to be aligned. +/* + * xxhash.c instantiates functions defined in xxhash.h */ -#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ -# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) -# define XXH_FORCE_ALIGN_CHECK 0 -# else -# define XXH_FORCE_ALIGN_CHECK 1 -# endif -#endif - -/* ************************************* -* Includes & Memory related functions -***************************************/ -/* Modify the local functions below should you wish to use some other memory routines */ -/* for malloc(), free() */ -#include -#include /* size_t */ -static void* XXH_malloc(size_t s) { return malloc(s); } -static void XXH_free (void* p) { free(p); } -/* for memcpy() */ -#include -static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } +#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ +#define XXH_IMPLEMENTATION /* access definitions */ -#ifndef XXH_STATIC_LINKING_ONLY -# define XXH_STATIC_LINKING_ONLY -#endif #include "xxhash.h" - - -/* ************************************* -* Compiler Specific Options -***************************************/ -#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# define INLINE_KEYWORD inline -#else -# define INLINE_KEYWORD -#endif - -#if defined(__GNUC__) || defined(__ICCARM__) -# define FORCE_INLINE_ATTR __attribute__((always_inline)) -#elif defined(_MSC_VER) -# define FORCE_INLINE_ATTR __forceinline -#else -# define FORCE_INLINE_ATTR -#endif - -#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR - - -#ifdef _MSC_VER -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#endif - - -/* ************************************* -* Basic Types -***************************************/ -#ifndef MEM_MODULE -# define MEM_MODULE -# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include - typedef uint8_t BYTE; - typedef uint16_t U16; - typedef uint32_t U32; - typedef int32_t S32; - typedef uint64_t U64; -# else - typedef unsigned char BYTE; - typedef unsigned short U16; - typedef unsigned int U32; - typedef signed int S32; - typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */ -# endif -#endif - - -#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) - -/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ -static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; } -static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; } - -#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) - -/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ -/* currently only defined for gcc and icc */ -typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign; - -static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } -static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } - -#else - -/* portable and safe solution. Generally efficient. - * see : http://stackoverflow.com/a/32095106/646947 - */ - -static U32 XXH_read32(const void* memPtr) -{ - U32 val; - memcpy(&val, memPtr, sizeof(val)); - return val; -} - -static U64 XXH_read64(const void* memPtr) -{ - U64 val; - memcpy(&val, memPtr, sizeof(val)); - return val; -} - -#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ - - -/* **************************************** -* Compiler-specific Functions and Macros -******************************************/ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) - -/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ -#if defined(_MSC_VER) -# define XXH_rotl32(x,r) _rotl(x,r) -# define XXH_rotl64(x,r) _rotl64(x,r) -#else -#if defined(__ICCARM__) -# include -# define XXH_rotl32(x,r) __ROR(x,(32 - r)) -#else -# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) -#endif -# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) -#endif - -#if defined(_MSC_VER) /* Visual Studio */ -# define XXH_swap32 _byteswap_ulong -# define XXH_swap64 _byteswap_uint64 -#elif GCC_VERSION >= 403 -# define XXH_swap32 __builtin_bswap32 -# define XXH_swap64 __builtin_bswap64 -#else -static U32 XXH_swap32 (U32 x) -{ - return ((x << 24) & 0xff000000 ) | - ((x << 8) & 0x00ff0000 ) | - ((x >> 8) & 0x0000ff00 ) | - ((x >> 24) & 0x000000ff ); -} -static U64 XXH_swap64 (U64 x) -{ - return ((x << 56) & 0xff00000000000000ULL) | - ((x << 40) & 0x00ff000000000000ULL) | - ((x << 24) & 0x0000ff0000000000ULL) | - ((x << 8) & 0x000000ff00000000ULL) | - ((x >> 8) & 0x00000000ff000000ULL) | - ((x >> 24) & 0x0000000000ff0000ULL) | - ((x >> 40) & 0x000000000000ff00ULL) | - ((x >> 56) & 0x00000000000000ffULL); -} -#endif - - -/* ************************************* -* Architecture Macros -***************************************/ -typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; - -/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */ -#ifndef XXH_CPU_LITTLE_ENDIAN - static const int g_one = 1; -# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one)) -#endif - - -/* *************************** -* Memory reads -*****************************/ -typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; - -FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) -{ - if (align==XXH_unaligned) - return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); - else - return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); -} - -FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) -{ - return XXH_readLE32_align(ptr, endian, XXH_unaligned); -} - -static U32 XXH_readBE32(const void* ptr) -{ - return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); -} - -FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) -{ - if (align==XXH_unaligned) - return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); - else - return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); -} - -FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) -{ - return XXH_readLE64_align(ptr, endian, XXH_unaligned); -} - -static U64 XXH_readBE64(const void* ptr) -{ - return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); -} - - -/* ************************************* -* Macros -***************************************/ -#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ - - -/* ************************************* -* Constants -***************************************/ -static const U32 PRIME32_1 = 2654435761U; -static const U32 PRIME32_2 = 2246822519U; -static const U32 PRIME32_3 = 3266489917U; -static const U32 PRIME32_4 = 668265263U; -static const U32 PRIME32_5 = 374761393U; - -static const U64 PRIME64_1 = 11400714785074694791ULL; -static const U64 PRIME64_2 = 14029467366897019727ULL; -static const U64 PRIME64_3 = 1609587929392839161ULL; -static const U64 PRIME64_4 = 9650029242287828579ULL; -static const U64 PRIME64_5 = 2870177450012600261ULL; - -XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } - - -/* ************************** -* Utils -****************************/ -XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState) -{ - memcpy(dstState, srcState, sizeof(*dstState)); -} - -XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState) -{ - memcpy(dstState, srcState, sizeof(*dstState)); -} - - -/* *************************** -* Simple Hash Functions -*****************************/ - -static U32 XXH32_round(U32 seed, U32 input) -{ - seed += input * PRIME32_2; - seed = XXH_rotl32(seed, 13); - seed *= PRIME32_1; - return seed; -} - -FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) -{ - const BYTE* p = (const BYTE*)input; - const BYTE* bEnd = p + len; - U32 h32; -#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align) - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (p==NULL) { - len=0; - bEnd=p=(const BYTE*)(size_t)16; - } -#endif - - if (len>=16) { - const BYTE* const limit = bEnd - 16; - U32 v1 = seed + PRIME32_1 + PRIME32_2; - U32 v2 = seed + PRIME32_2; - U32 v3 = seed + 0; - U32 v4 = seed - PRIME32_1; - - do { - v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4; - v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4; - v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4; - v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4; - } while (p<=limit); - - h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); - } else { - h32 = seed + PRIME32_5; - } - - h32 += (U32) len; - - while (p+4<=bEnd) { - h32 += XXH_get32bits(p) * PRIME32_3; - h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; - p+=4; - } - - while (p> 15; - h32 *= PRIME32_2; - h32 ^= h32 >> 13; - h32 *= PRIME32_3; - h32 ^= h32 >> 16; - - return h32; -} - - -XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed) -{ -#if 0 - /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ - XXH32_CREATESTATE_STATIC(state); - XXH32_reset(state, seed); - XXH32_update(state, input, len); - return XXH32_digest(state); -#else - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if (XXH_FORCE_ALIGN_CHECK) { - if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); - else - return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); - } } - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); - else - return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); -#endif -} - - -static U64 XXH64_round(U64 acc, U64 input) -{ - acc += input * PRIME64_2; - acc = XXH_rotl64(acc, 31); - acc *= PRIME64_1; - return acc; -} - -static U64 XXH64_mergeRound(U64 acc, U64 val) -{ - val = XXH64_round(0, val); - acc ^= val; - acc = acc * PRIME64_1 + PRIME64_4; - return acc; -} - -FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) -{ - const BYTE* p = (const BYTE*)input; - const BYTE* const bEnd = p + len; - U64 h64; -#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align) - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (p==NULL) { - len=0; - bEnd=p=(const BYTE*)(size_t)32; - } -#endif - - if (len>=32) { - const BYTE* const limit = bEnd - 32; - U64 v1 = seed + PRIME64_1 + PRIME64_2; - U64 v2 = seed + PRIME64_2; - U64 v3 = seed + 0; - U64 v4 = seed - PRIME64_1; - - do { - v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8; - v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8; - v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8; - v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8; - } while (p<=limit); - - h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); - h64 = XXH64_mergeRound(h64, v1); - h64 = XXH64_mergeRound(h64, v2); - h64 = XXH64_mergeRound(h64, v3); - h64 = XXH64_mergeRound(h64, v4); - - } else { - h64 = seed + PRIME64_5; - } - - h64 += (U64) len; - - while (p+8<=bEnd) { - U64 const k1 = XXH64_round(0, XXH_get64bits(p)); - h64 ^= k1; - h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; - p+=8; - } - - if (p+4<=bEnd) { - h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; - h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; - p+=4; - } - - while (p> 33; - h64 *= PRIME64_2; - h64 ^= h64 >> 29; - h64 *= PRIME64_3; - h64 ^= h64 >> 32; - - return h64; -} - - -XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed) -{ -#if 0 - /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ - XXH64_CREATESTATE_STATIC(state); - XXH64_reset(state, seed); - XXH64_update(state, input, len); - return XXH64_digest(state); -#else - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if (XXH_FORCE_ALIGN_CHECK) { - if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); - else - return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); - } } - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); - else - return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); -#endif -} - - -/* ************************************************** -* Advanced Hash Functions -****************************************************/ - -XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) -{ - return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); -} -XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) -{ - XXH_free(statePtr); - return XXH_OK; -} - -XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) -{ - return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); -} -XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) -{ - XXH_free(statePtr); - return XXH_OK; -} - - -/*** Hash feed ***/ - -XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed) -{ - XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ - memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */ - state.v1 = seed + PRIME32_1 + PRIME32_2; - state.v2 = seed + PRIME32_2; - state.v3 = seed + 0; - state.v4 = seed - PRIME32_1; - memcpy(statePtr, &state, sizeof(state)); - return XXH_OK; -} - - -XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed) -{ - XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ - memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */ - state.v1 = seed + PRIME64_1 + PRIME64_2; - state.v2 = seed + PRIME64_2; - state.v3 = seed + 0; - state.v4 = seed - PRIME64_1; - memcpy(statePtr, &state, sizeof(state)); - return XXH_OK; -} - - -FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) -{ - const BYTE* p = (const BYTE*)input; - const BYTE* const bEnd = p + len; - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (input==NULL) return XXH_ERROR; -#endif - - state->total_len_32 += (unsigned)len; - state->large_len |= (len>=16) | (state->total_len_32>=16); - - if (state->memsize + len < 16) { /* fill in tmp buffer */ - XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len); - state->memsize += (unsigned)len; - return XXH_OK; - } - - if (state->memsize) { /* some data left from previous update */ - XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize); - { const U32* p32 = state->mem32; - state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++; - state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++; - state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++; - state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++; - } - p += 16-state->memsize; - state->memsize = 0; - } - - if (p <= bEnd-16) { - const BYTE* const limit = bEnd - 16; - U32 v1 = state->v1; - U32 v2 = state->v2; - U32 v3 = state->v3; - U32 v4 = state->v4; - - do { - v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4; - v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4; - v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4; - v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4; - } while (p<=limit); - - state->v1 = v1; - state->v2 = v2; - state->v3 = v3; - state->v4 = v4; - } - - if (p < bEnd) { - XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); - state->memsize = (unsigned)(bEnd-p); - } - - return XXH_OK; -} - -XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_update_endian(state_in, input, len, XXH_littleEndian); - else - return XXH32_update_endian(state_in, input, len, XXH_bigEndian); -} - - - -FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) -{ - const BYTE * p = (const BYTE*)state->mem32; - const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize; - U32 h32; - - if (state->large_len) { - h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18); - } else { - h32 = state->v3 /* == seed */ + PRIME32_5; - } - - h32 += state->total_len_32; - - while (p+4<=bEnd) { - h32 += XXH_readLE32(p, endian) * PRIME32_3; - h32 = XXH_rotl32(h32, 17) * PRIME32_4; - p+=4; - } - - while (p> 15; - h32 *= PRIME32_2; - h32 ^= h32 >> 13; - h32 *= PRIME32_3; - h32 ^= h32 >> 16; - - return h32; -} - - -XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_digest_endian(state_in, XXH_littleEndian); - else - return XXH32_digest_endian(state_in, XXH_bigEndian); -} - - - -/* **** XXH64 **** */ - -FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) -{ - const BYTE* p = (const BYTE*)input; - const BYTE* const bEnd = p + len; - -#ifdef XXH_ACCEPT_NULL_INPUT_POINTER - if (input==NULL) return XXH_ERROR; -#endif - - state->total_len += len; - - if (state->memsize + len < 32) { /* fill in tmp buffer */ - XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len); - state->memsize += (U32)len; - return XXH_OK; - } - - if (state->memsize) { /* tmp buffer is full */ - XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize); - state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian)); - state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian)); - state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian)); - state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian)); - p += 32-state->memsize; - state->memsize = 0; - } - - if (p+32 <= bEnd) { - const BYTE* const limit = bEnd - 32; - U64 v1 = state->v1; - U64 v2 = state->v2; - U64 v3 = state->v3; - U64 v4 = state->v4; - - do { - v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8; - v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8; - v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8; - v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8; - } while (p<=limit); - - state->v1 = v1; - state->v2 = v2; - state->v3 = v3; - state->v4 = v4; - } - - if (p < bEnd) { - XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); - state->memsize = (unsigned)(bEnd-p); - } - - return XXH_OK; -} - -XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_update_endian(state_in, input, len, XXH_littleEndian); - else - return XXH64_update_endian(state_in, input, len, XXH_bigEndian); -} - - - -FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) -{ - const BYTE * p = (const BYTE*)state->mem64; - const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize; - U64 h64; - - if (state->total_len >= 32) { - U64 const v1 = state->v1; - U64 const v2 = state->v2; - U64 const v3 = state->v3; - U64 const v4 = state->v4; - - h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); - h64 = XXH64_mergeRound(h64, v1); - h64 = XXH64_mergeRound(h64, v2); - h64 = XXH64_mergeRound(h64, v3); - h64 = XXH64_mergeRound(h64, v4); - } else { - h64 = state->v3 + PRIME64_5; - } - - h64 += (U64) state->total_len; - - while (p+8<=bEnd) { - U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian)); - h64 ^= k1; - h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; - p+=8; - } - - if (p+4<=bEnd) { - h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1; - h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; - p+=4; - } - - while (p> 33; - h64 *= PRIME64_2; - h64 ^= h64 >> 29; - h64 *= PRIME64_3; - h64 ^= h64 >> 32; - - return h64; -} - - -XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_digest_endian(state_in, XXH_littleEndian); - else - return XXH64_digest_endian(state_in, XXH_bigEndian); -} - - -/* ************************** -* Canonical representation -****************************/ - -/*! Default XXH result types are basic unsigned 32 and 64 bits. -* The canonical representation follows human-readable write convention, aka big-endian (large digits first). -* These functions allow transformation of hash result into and from its canonical format. -* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs. -*/ - -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)); - if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); - memcpy(dst, &hash, sizeof(*dst)); -} - -XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) -{ - XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); - if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); - memcpy(dst, &hash, sizeof(*dst)); -} - -XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) -{ - return XXH_readBE32(src); -} - -XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) -{ - return XXH_readBE64(src); -} diff --git a/native/zstd/common/xxhash.h b/native/zstd/common/xxhash.h old mode 100755 new mode 100644 index 9bad1f5..f87102a --- a/native/zstd/common/xxhash.h +++ b/native/zstd/common/xxhash.h @@ -1,40 +1,36 @@ /* - xxHash - Extremely Fast Hash algorithm - Header File - Copyright (C) 2012-2016, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - xxHash source repository : https://github.com/Cyan4973/xxHash + * xxHash - Fast Hash algorithm + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - xxHash homepage: http://www.xxhash.com + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * 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. */ -/* Notice extracted from xxHash homepage : -xxHash is an extremely fast Hash algorithm, running at RAM speed limits. +#ifndef XXH_NO_XXH3 +# define XXH_NO_XXH3 +#endif + +#ifndef XXH_NAMESPACE +# define XXH_NAMESPACE ZSTD_ +#endif + +/*! + * @mainpage xxHash + * + * @file xxhash.h + * xxHash prototypes and implementation + */ +/* TODO: update */ +/* Notice extracted from xxHash homepage: + +xxHash is an extremely fast hash algorithm, running at RAM speed limits. It also successfully passes all tests from the SMHasher suite. Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) @@ -42,7 +38,7 @@ Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo Name Speed Q.Score Author xxHash 5.4 GB/s 10 CrapWow 3.2 GB/s 2 Andrew -MumurHash 3a 2.7 GB/s 10 Austin Appleby +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 @@ -57,8 +53,13 @@ Q.Score is a measure of quality of the hash function. It depends on successfully passing SMHasher test set. 10 is a perfect score. -A 64-bits version, named XXH64, is available since r35. -It offers much better speed, but for 64-bits applications only. +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 @@ -68,33 +69,34 @@ XXH32 6.8 GB/s 6.0 GB/s extern "C" { #endif -#ifndef XXHASH_H_5627135585666179 -#define XXHASH_H_5627135585666179 1 - - -/* **************************** -* Definitions -******************************/ -#include /* size_t */ -typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; - - /* **************************** -* API modifier -******************************/ -/** XXH_PRIVATE_API -* This is useful if you want to include xxhash functions in `static` mode -* in order to inline them, and remove their symbol from the public list. -* Methodology : -* #define XXH_PRIVATE_API -* #include "xxhash.h" -* `xxhash.c` is automatically included. -* It's not useful to compile and link it as a separate module anymore. -*/ -#ifdef XXH_PRIVATE_API -# ifndef XXH_STATIC_LINKING_ONLY -# define XXH_STATIC_LINKING_ONLY -# endif + * INLINE mode + ******************************/ +/*! + * XXH_INLINE_ALL (and XXH_PRIVATE_API) + * Use these build macros to inline xxhash into the target unit. + * Inlining improves performance on small inputs, especially when the length is + * expressed as a compile-time constant: + * + * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html + * + * It also keeps xxHash symbols private to the unit, so they are not exported. + * + * Usage: + * #define XXH_INLINE_ALL + * #include "xxhash.h" + * + * Do not compile and link xxhash.o as a separate object, as it is not useful. + */ +#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ + && !defined(XXH_INLINE_ALL_31684351384) + /* this section should be traversed only once */ +# define XXH_INLINE_ALL_31684351384 + /* give access to the advanced API, required to compile implementations */ +# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ +# define XXH_STATIC_LINKING_ONLY + /* make all functions private */ +# undef XXH_PUBLIC_API # if defined(__GNUC__) # define XXH_PUBLIC_API static __inline __attribute__((unused)) # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) @@ -102,45 +104,205 @@ typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; # elif defined(_MSC_VER) # define XXH_PUBLIC_API static __inline # else -# define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */ + /* note: this version may generate warnings for unused static functions */ +# define XXH_PUBLIC_API static # endif -#else -# define XXH_PUBLIC_API /* do nothing */ -#endif /* XXH_PRIVATE_API */ -/*!XXH_NAMESPACE, aka Namespace Emulation : + /* + * This part deals with the special case where a unit wants to inline xxHash, + * but "xxhash.h" has previously been included without XXH_INLINE_ALL, + * such as part of some previously included *.h header file. + * Without further action, the new include would just be ignored, + * and functions would effectively _not_ be inlined (silent failure). + * The following macros solve this situation by prefixing all inlined names, + * avoiding naming collision with previous inclusions. + */ + /* Before that, we unconditionally #undef all symbols, + * in case they were already defined with XXH_NAMESPACE. + * They will then be redefined for XXH_INLINE_ALL + */ +# undef XXH_versionNumber + /* XXH32 */ +# undef XXH32 +# undef XXH32_createState +# undef XXH32_freeState +# undef XXH32_reset +# undef XXH32_update +# undef XXH32_digest +# undef XXH32_copyState +# undef XXH32_canonicalFromHash +# undef XXH32_hashFromCanonical + /* XXH64 */ +# undef XXH64 +# undef XXH64_createState +# undef XXH64_freeState +# undef XXH64_reset +# undef XXH64_update +# undef XXH64_digest +# undef XXH64_copyState +# undef XXH64_canonicalFromHash +# undef XXH64_hashFromCanonical + /* XXH3_64bits */ +# undef XXH3_64bits +# undef XXH3_64bits_withSecret +# undef XXH3_64bits_withSeed +# undef XXH3_64bits_withSecretandSeed +# undef XXH3_createState +# undef XXH3_freeState +# undef XXH3_copyState +# undef XXH3_64bits_reset +# undef XXH3_64bits_reset_withSeed +# undef XXH3_64bits_reset_withSecret +# undef XXH3_64bits_update +# undef XXH3_64bits_digest +# undef XXH3_generateSecret + /* XXH3_128bits */ +# undef XXH128 +# undef XXH3_128bits +# undef XXH3_128bits_withSeed +# undef XXH3_128bits_withSecret +# undef XXH3_128bits_reset +# undef XXH3_128bits_reset_withSeed +# undef XXH3_128bits_reset_withSecret +# undef XXH3_128bits_reset_withSecretandSeed +# undef XXH3_128bits_update +# undef XXH3_128bits_digest +# undef XXH128_isEqual +# undef XXH128_cmp +# undef XXH128_canonicalFromHash +# undef XXH128_hashFromCanonical + /* Finally, free the namespace itself */ +# undef XXH_NAMESPACE -If you want to include _and expose_ xxHash functions from within your own library, -but also want to avoid symbol collisions with another library which also includes xxHash, + /* employ the namespace for XXH_INLINE_ALL */ +# define XXH_NAMESPACE XXH_INLINE_ + /* + * Some identifiers (enums, type names) are not symbols, + * but they must nonetheless be renamed to avoid redeclaration. + * Alternative solution: do not redeclare them. + * However, this requires some #ifdefs, and has a more dispersed impact. + * Meanwhile, renaming can be achieved in a single place. + */ +# define XXH_IPREF(Id) XXH_NAMESPACE ## Id +# define XXH_OK XXH_IPREF(XXH_OK) +# define XXH_ERROR XXH_IPREF(XXH_ERROR) +# define XXH_errorcode XXH_IPREF(XXH_errorcode) +# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) +# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) +# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) +# define XXH32_state_s XXH_IPREF(XXH32_state_s) +# define XXH32_state_t XXH_IPREF(XXH32_state_t) +# define XXH64_state_s XXH_IPREF(XXH64_state_s) +# define XXH64_state_t XXH_IPREF(XXH64_state_t) +# define XXH3_state_s XXH_IPREF(XXH3_state_s) +# define XXH3_state_t XXH_IPREF(XXH3_state_t) +# define XXH128_hash_t XXH_IPREF(XXH128_hash_t) + /* Ensure the header is parsed again, even if it was previously included */ +# undef XXHASH_H_5627135585666179 +# undef XXHASH_H_STATIC_13879238742 +#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ -you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library -with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values). -Note that no change is required within the calling program as long as it includes `xxhash.h` : -regular symbol name will be automatically translated by this header. -*/ + +/* **************************************************************** + * Stable API + *****************************************************************/ +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + + +/*! + * @defgroup public Public API + * Contains details on the public xxHash functions. + * @{ + */ +/* specific declaration modes for Windows */ +#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 + +#ifdef XXH_DOXYGEN +/*! + * @brief Emulate a namespace by transparently prefixing all symbols. + * + * If you want to include _and expose_ xxHash functions from within your own + * library, but also want to avoid symbol collisions with other libraries which + * may also include xxHash, you can use XXH_NAMESPACE to automatically prefix + * any public symbol from xxhash library with the value of XXH_NAMESPACE + * (therefore, avoid empty or numeric values). + * + * Note that no change is required within the calling program as long as it + * includes `xxhash.h`: Regular symbol names will be automatically translated + * by this header. + */ +# define XXH_NAMESPACE /* YOUR NAME HERE */ +# undef XXH_NAMESPACE +#endif + #ifdef XXH_NAMESPACE # define XXH_CAT(A,B) A##B # define XXH_NAME2(A,B) XXH_CAT(A,B) -# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) -# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) # define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +/* XXH32 */ +# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) # define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) -# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) # define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) -# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) # define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) -# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) # define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) -# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) # define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) -# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) # define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) -# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) # define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) -# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) # define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) +/* XXH64 */ +# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) +# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) # define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) +/* XXH3_64bits */ +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) +# define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) +# define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) +/* XXH3_128bits */ +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) +# define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) #endif @@ -148,156 +310,5375 @@ regular symbol name will be automatically translated by this header. * Version ***************************************/ #define XXH_VERSION_MAJOR 0 -#define XXH_VERSION_MINOR 6 -#define XXH_VERSION_RELEASE 2 +#define XXH_VERSION_MINOR 8 +#define XXH_VERSION_RELEASE 1 #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) + +/*! + * @brief Obtains the xxHash version. + * + * This is mostly useful when xxHash is compiled as a shared library, + * since the returned value comes from the library, as opposed to header file. + * + * @return `XXH_VERSION_NUMBER` of the invoked library. + */ XXH_PUBLIC_API unsigned XXH_versionNumber (void); /* **************************** -* Simple Hash Functions +* Common basic types ******************************/ -typedef unsigned int XXH32_hash_t; -typedef unsigned long long XXH64_hash_t; - -XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed); -XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed); - -/*! -XXH32() : - Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input". - The memory between input & input+length must be valid (allocated and read-accessible). - "seed" can be used to alter the result predictably. - Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s -XXH64() : - Calculate the 64-bits hash of sequence of length "len" stored at memory address "input". - "seed" can be used to alter the result predictably. - This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark). -*/ +#include /* size_t */ +typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; -/* **************************** -* Streaming Hash Functions -******************************/ -typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ -typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ +/*-********************************************************************** +* 32-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* Don't show include */ +/*! + * @brief An unsigned 32-bit integer. + * + * Not necessarily defined to `uint32_t` but functionally equivalent. + */ +typedef uint32_t XXH32_hash_t; -/*! State allocation, compatible with dynamic libraries */ +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint32_t XXH32_hash_t; -XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); -XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +#else +# include +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# else +# if ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform: need a 32-bit type" +# endif +# endif +#endif -XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); -XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); +/*! + * @} + * + * @defgroup xxh32_family XXH32 family + * @ingroup public + * Contains functions used in the classic 32-bit xxHash algorithm. + * + * @note + * XXH32 is useful for older platforms, with no or poor 64-bit performance. + * Note that @ref xxh3_family provides competitive speed + * for both 32-bit and 64-bit systems, and offers true 64/128 bit hash results. + * + * @see @ref xxh64_family, @ref xxh3_family : Other xxHash families + * @see @ref xxh32_impl for implementation details + * @{ + */ + +/*! + * @brief Calculates the 32-bit hash of @p input using xxHash32. + * + * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 32-bit seed to alter the hash's output predictably. + * + * @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 32-bit hash value. + * + * @see + * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); +/*! + * Streaming functions generate the xxHash value from an incremental input. + * This method is slower than single-call functions, due to state management. + * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. + * + * An XXH state must first be allocated using `XXH*_createState()`. + * + * Start a new hash by initializing the state with a seed using `XXH*_reset()`. + * + * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. + * + * The function returns an error code, with 0 meaning OK, and any other value + * meaning there is an error. + * + * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. + * This function returns the nn-bits hash as an int or long long. + * + * It's still possible to continue inserting input into the hash state after a + * digest, and generate new hash values later on by invoking `XXH*_digest()`. + * + * When done, release the state using `XXH*_freeState()`. + * + * Example code for incrementally hashing a file: + * @code{.c} + * #include + * #include + * #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 + */ + +/*! + * @typedef struct XXH32_state_s XXH32_state_t + * @brief The opaque state struct for the XXH32 streaming API. + * + * @see XXH32_state_s for details. + */ +typedef struct XXH32_state_s XXH32_state_t; + +/*! + * @brief Allocates an @ref XXH32_state_t. + * + * Must be freed with XXH32_freeState(). + * @return An allocated XXH32_state_t on success, `NULL` on failure. + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); +/*! + * @brief Frees an @ref XXH32_state_t. + * + * Must be allocated with XXH32_createState(). + * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). + * @return XXH_OK. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +/*! + * @brief Copies one @ref XXH32_state_t to another. + * + * @param dst_state The state to copy to. + * @param src_state The state to copy from. + * @pre + * @p dst_state and @p src_state must not be `NULL` and must not overlap. + */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); -/* hash streaming */ +/*! + * @brief Resets an @ref XXH32_state_t to begin a new hash. + * + * This function resets and seeds a state. Call it before @ref XXH32_update(). + * + * @param statePtr The state struct to reset. + * @param seed The 32-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. + */ +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, unsigned int seed); +/*! + * @brief Consumes a block of @p input to an @ref XXH32_state_t. + * + * Call this to incrementally consume blocks of data. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @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, @ref XXH_ERROR on failure. + */ XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); + +/*! + * @brief Returns the calculated hash value from an @ref XXH32_state_t. + * + * @note + * Calling XXH32_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated xxHash32 value from that state. + */ XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); -XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed); -XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); -XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); +/******* Canonical representation *******/ /* -These functions generate the xxHash of an input provided in multiple segments. -Note that, for small input, they are slower than single-call functions, due to state management. -For small input, prefer `XXH32()` and `XXH64()` . + * 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. + */ +typedef struct { + unsigned char digest[4]; /*!< Hash bytes, big endian */ +} 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 hash The @ref XXH32_hash_t to be converted. + * + * @pre + * @p dst must not be `NULL`. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); -XXH state must first be allocated, using XXH*_createState() . +/*! + * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. + * + * @param src The @ref XXH32_canonical_t to convert. + * + * @pre + * @p src must not be `NULL`. + * + * @return The converted hash. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); -Start a new hash by initializing state with a seed, using XXH*_reset(). -Then, feed the hash state by calling XXH*_update() as many times as necessary. -Obviously, input must be allocated and read accessible. -The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. +#ifdef __has_attribute +# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +# define XXH_HAS_ATTRIBUTE(x) 0 +#endif -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. +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define XXH_HAS_C_ATTRIBUTE(x) 0 +#endif -It's still possible to continue inserting input into the hash state after a digest, -and generate some new hashes later on, by calling again XXH*_digest(). +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define XXH_HAS_CPP_ATTRIBUTE(x) 0 +#endif -When done, free XXH state space if it was allocated dynamically. +/* +Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute +introduced in CPP17 and C23. +CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough +C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough */ +#if XXH_HAS_C_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_CPP_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_ATTRIBUTE(__fallthrough__) +# define XXH_FALLTHROUGH __attribute__ ((fallthrough)) +#else +# define XXH_FALLTHROUGH +#endif +/*! + * @} + * @ingroup public + * @{ + */ -/* ************************** -* Utils -****************************/ -#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* ! C99 */ -# define restrict /* disable restrict */ +#ifndef XXH_NO_LONG_LONG +/*-********************************************************************** +* 64-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* don't include */ +/*! + * @brief An unsigned 64-bit integer. + * + * Not necessarily defined to `uint64_t` but functionally equivalent. + */ +typedef uint64_t XXH64_hash_t; +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint64_t XXH64_hash_t; +#else +# include +# if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL + /* LP64 ABI says uint64_t is unsigned long */ + typedef unsigned long XXH64_hash_t; +# else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +# endif #endif -XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state); -XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state); +/*! + * @} + * + * @defgroup xxh64_family XXH64 family + * @ingroup public + * @{ + * Contains functions used in the classic 64-bit xxHash algorithm. + * + * @note + * XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. + * It provides better speed for systems with vector processing capabilities. + */ -/* ************************** -* Canonical representation -****************************/ -/* Default result type for XXH functions are primitive unsigned 32 and 64 bits. -* The canonical representation uses human-readable write convention, aka big-endian (large digits first). -* These functions allow transformation of hash result into and from its canonical format. -* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs. -*/ -typedef struct { unsigned char digest[4]; } XXH32_canonical_t; -typedef struct { unsigned char digest[8]; } XXH64_canonical_t; +/*! + * @brief Calculates the 64-bit hash of @p input using xxHash64. + * + * This function usually runs faster on 64-bit systems, but slower on 32-bit + * systems (see benchmark). + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 64-bit seed to alter the hash's output predictably. + * + * @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 hash. + * + * @see + * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH64_hash_t XXH64(const void* input, size_t length, XXH64_hash_t seed); -XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); -XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); +/******* Streaming *******/ +/*! + * @brief The opaque state struct for the XXH64 streaming API. + * + * @see XXH64_state_s for details. + */ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); +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 XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); + +/******* Canonical representation *******/ +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); +#ifndef XXH_NO_XXH3 +/*! + * @} + * ************************************************************************ + * @defgroup xxh3_family XXH3 family + * @ingroup public + * @{ + * + * XXH3 is a more recent hash algorithm featuring: + * - Improved speed for both small and large inputs + * - True 64-bit and 128-bit outputs + * - SIMD acceleration + * - Improved 32-bit viability + * + * Speed analysis methodology is explained here: + * + * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * + * Compared to XXH64, expect XXH3 to run approximately + * ~2x faster on large inputs and >3x faster on small ones, + * exact differences vary depending on platform. + * + * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, + * but does not require it. + * Any 32-bit and 64-bit targets that can run XXH32 smoothly + * can run XXH3 at competitive speeds, even without vector support. + * Further details are explained in the implementation. + * + * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8, + * ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro. + * + * XXH3 implementation is portable: + * it has a generic C90 formulation that can be compiled on any platform, + * all implementations generage exactly the same hash value on all platforms. + * Starting from v0.8.0, it's also labelled "stable", meaning that + * any future version will also generate the same hash value. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * + * When only 64 bits are needed, prefer invoking the _64bits variant, as it + * reduces the amount of mixing, resulting in faster speed on small inputs. + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + */ + +/*-********************************************************************** +* XXH3 64-bit variant +************************************************************************/ + +/* XXH3_64bits(): + * default 64-bit variant, using default secret and default seed of 0. + * It's the fastest variant. */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); + +/* + * XXH3_64bits_withSeed(): + * This variant generates a custom secret on the fly + * based on default secret altered using the `seed` value. + * While this operation is decently fast, note that it's not completely free. + * Note: seed==0 produces the same results as XXH3_64bits(). + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); + +/*! + * The bare minimum size for a custom secret. + * + * @see + * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), + * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). + */ +#define XXH3_SECRET_SIZE_MIN 136 + +/* + * XXH3_64bits_withSecret(): + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). + * However, the quality of the secret impacts the dispersion of the hash algorithm. + * Therefore, the secret _must_ look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever in doubt about the "randomness" of the blob of bytes, + * consider employing "XXH3_generateSecret()" instead (see below). + * 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. + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + */ + +/*! + * @brief The state struct for the XXH3 streaming API. + * + * @see XXH3_state_s for details. + */ +typedef struct XXH3_state_s XXH3_state_t; +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); +XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state); + +/* + * XXH3_64bits_reset(): + * Initialize with default parameters. + * digest will be equivalent to `XXH3_64bits()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr); +/* + * XXH3_64bits_reset_withSeed(): + * Generate a custom secret from `seed`, and store it into `statePtr`. + * digest will be equivalent to `XXH3_64bits_withSeed()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +/* + * XXH3_64bits_reset_withSecret(): + * `secret` is referenced, it _must outlive_ the hash streaming session. + * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_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); + +/* note : canonical representation of XXH3 is the same as XXH64 + * since they both produce XXH64_hash_t values */ + + +/*-********************************************************************** +* XXH3 128-bit variant +************************************************************************/ + +/*! + * @brief The return value from 128-bit hashes. + * + * Stored in little endian order, although the fields themselves are in native + * endianness. + */ +typedef struct { + XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ + XXH64_hash_t high64; /*!< `value >> 64` */ +} XXH128_hash_t; + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + * + * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). + * Use already declared XXH3_createState() and XXH3_freeState(). + * + * All reset and streaming functions have same meaning as their 64-bit counterpart. + */ + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +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); + +/* Following helper functions make it possible to compare XXH128_hast_t values. + * Since XXH128_hash_t is a structure, this capability is not offered by the language. + * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ + +/*! + * XXH128_isEqual(): + * Return: 1 if `h1` and `h2` are equal, 0 if they are not. + */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); + +/*! + * XXH128_cmp(): + * + * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. + * + * return: >0 if *h128_1 > *h128_2 + * =0 if *h128_1 == *h128_2 + * <0 if *h128_1 < *h128_2 + */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); + + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); + + +#endif /* !XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ + +/*! + * @} + */ #endif /* XXHASH_H_5627135585666179 */ -/* ================================================================================================ - This section contains definitions which are not guaranteed to remain stable. - They may change in future versions, becoming incompatible with a different version of the library. - They shall only be used with static linking. - Never use these definitions in association with dynamic linking ! -=================================================================================================== */ -#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXH_STATIC_H_3543687687345) -#define XXH_STATIC_H_3543687687345 - -/* These definitions are only meant to allow allocation of XXH state - statically, on stack, or in a struct for example. - Do not use members directly. */ - - struct XXH32_state_s { - unsigned total_len_32; - unsigned large_len; - unsigned v1; - unsigned v2; - unsigned v3; - unsigned v4; - unsigned mem32[4]; /* buffer defined as U32 for alignment */ - unsigned memsize; - unsigned reserved; /* never read nor write, will be removed in a future version */ - }; /* typedef'd to XXH32_state_t */ - - struct XXH64_state_s { - unsigned long long total_len; - unsigned long long v1; - unsigned long long v2; - unsigned long long v3; - unsigned long long v4; - unsigned long long mem64[4]; /* buffer defined as U64 for alignment */ - unsigned memsize; - unsigned reserved[2]; /* never read nor write, will be removed in a future version */ - }; /* typedef'd to XXH64_state_t */ - - -# ifdef XXH_PRIVATE_API -# include "xxhash.c" /* include xxhash functions as `static`, for inlining */ +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) +#define XXHASH_H_STATIC_13879238742 +/* **************************************************************************** + * This section contains declarations which are not guaranteed to remain stable. + * They may change in future versions, becoming incompatible with a different + * version of the library. + * These declarations should only be used with static linking. + * Never use them in association with dynamic linking! + ***************************************************************************** */ + +/* + * These definitions are only present to allow static allocation + * of XXH states, on stack or in a struct, for example. + * Never **ever** access their members directly. + */ + +/*! + * @internal + * @brief Structure for XXH32 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH32_state_t. + * Do not access the members of this struct directly. + * @see XXH64_state_s, XXH3_state_s + */ +struct XXH32_state_s { + XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ + XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ + XXH32_hash_t v[4]; /*!< Accumulator lanes */ + XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */ + XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ +}; /* typedef'd to XXH32_state_t */ + + +#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ + +/*! + * @internal + * @brief Structure for XXH64 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH64_state_t. + * Do not access the members of this struct directly. + * @see XXH32_state_s, XXH3_state_s + */ +struct XXH64_state_s { + XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ + XXH64_hash_t v[4]; /*!< Accumulator lanes */ + XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */ + XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ + XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ +}; /* typedef'd to XXH64_state_t */ + + +#ifndef XXH_NO_XXH3 + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ +# include +# define XXH_ALIGN(n) alignas(n) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ +/* In C++ alignas() is a keyword */ +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +/* Old GCC versions only accept the attribute after the type in structures. */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ + && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ + && defined(__GNUC__) +# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) +#else +# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type +#endif + +/*! + * @brief The size of the internal XXH3 buffer. + * + * This is the optimal update size for incremental hashing. + * + * @see XXH3_64b_update(), XXH3_128b_update(). + */ +#define XXH3_INTERNALBUFFER_SIZE 256 + +/*! + * @brief Default size of the secret buffer (and @ref XXH3_kSecret). + * + * This is the size used in @ref XXH3_kSecret and the seeded functions. + * + * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. + */ +#define XXH3_SECRET_DEFAULT_SIZE 192 + +/*! + * @internal + * @brief Structure for XXH3 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. + * Otherwise it is an opaque type. + * Never use this definition in combination with dynamic library. + * This allows fields to safely be changed in the future. + * + * @note ** This structure has a strict alignment requirement of 64 bytes!! ** + * Do not allocate this with `malloc()` or `new`, + * it will not be sufficiently aligned. + * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. + * + * Typedef'd to @ref XXH3_state_t. + * Do never access the members of this struct directly. + * + * @see XXH3_INITSTATE() for stack initialization. + * @see XXH3_createState(), XXH3_freeState(). + * @see XXH32_state_s, XXH64_state_s + */ +struct XXH3_state_s { + XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); + /*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref XXH64_state_s */ + XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); + /*!< Used to store a custom secret generated from a seed. */ + XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); + /*!< The internal buffer. @see XXH32_state_s::mem32 */ + XXH32_hash_t bufferedSize; + /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ + XXH32_hash_t useSeed; + /*!< Reserved field. Needed for padding on 64-bit. */ + size_t nbStripesSoFar; + /*!< Number or stripes processed. */ + XXH64_hash_t totalLen; + /*!< Total length hashed. 64-bit even on 32-bit targets. */ + size_t nbStripesPerBlock; + /*!< Number of stripes per block. */ + size_t secretLimit; + /*!< Size of @ref customSecret or @ref extSecret */ + XXH64_hash_t seed; + /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ + XXH64_hash_t reserved64; + /*!< Reserved field. */ + const unsigned char* extSecret; + /*!< Reference to an external secret for the _withSecret variants, NULL + * for other variants. */ + /* note: there may be some padding at the end due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +#undef XXH_ALIGN_MEMBER + +/*! + * @brief Initializes a stack-allocated `XXH3_state_s`. + * + * When the @ref XXH3_state_t structure is merely emplaced on stack, + * it should be initialized with XXH3_INITSTATE() or a memset() + * in case its first reset uses XXH3_NNbits_reset_withSeed(). + * This init can be omitted if the first reset uses default or _withSecret mode. + * This operation isn't necessary when the state is created with XXH3_createState(). + * Note that this doesn't prepare the state for a streaming operation, + * it's still necessary to use XXH3_NNbits_reset*() afterwards. + */ +#define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; } + + +/* XXH128() : + * simple alias to pre-selected XXH3_128bits variant + */ +XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); + + +/* === Experimental API === */ +/* Symbols defined below must be considered tied to a specific library version. */ + +/* + * XXH3_generateSecret(): + * + * Derive a high-entropy secret from any user-defined content, named customSeed. + * The generated secret can be used in combination with `*_withSecret()` functions. + * The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed, + * as it becomes much more difficult for an external actor to guess how to impact the calculation logic. + * + * The function accepts as input a custom seed of any length and any content, + * and derives from it a high-entropy secret of length @secretSize + * into an already allocated buffer @secretBuffer. + * @secretSize must be >= XXH3_SECRET_SIZE_MIN + * + * The generated secret can then be used with any `*_withSecret()` variant. + * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`, + * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()` + * are part of this list. They all accept a `secret` parameter + * which must be large enough for implementation reasons (>= XXH3_SECRET_SIZE_MIN) + * _and_ feature very high entropy (consist of random-looking bytes). + * These conditions can be a high bar to meet, so + * XXH3_generateSecret() can be employed to ensure proper quality. + * + * customSeed can be anything. It can have any size, even small ones, + * and its content can be anything, even "poor entropy" sources such as a bunch of zeroes. + * The resulting `secret` will nonetheless provide all required qualities. + * + * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize); + + +/* + * XXH3_generateSecret_fromSeed(): + * + * Generate the same secret as the _withSeed() variants. + * + * The resulting secret has a length of XXH3_SECRET_DEFAULT_SIZE (necessarily). + * @secretBuffer must be already allocated, of size at least XXH3_SECRET_DEFAULT_SIZE bytes. + * + * The generated secret can be used in combination with + *`*_withSecret()` and `_withSecretandSeed()` variants. + * This generator is notably useful in combination with `_withSecretandSeed()`, + * as a way to emulate a faster `_withSeed()` variant. + */ +XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed); + +/* + * *_withSecretandSeed() : + * These variants generate hash values using either + * @seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) + * or @secret for "large" keys (>= XXH3_MIDSIZE_MAX). + * + * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. + * `_withSeed()` has to generate the secret on the fly for "large" keys. + * It's fast, but can be perceptible for "not so large" keys (< 1 KB). + * `_withSecret()` has to generate the masks on the fly for "small" keys, + * which requires more instructions than _withSeed() variants. + * Therefore, _withSecretandSeed variant combines the best of both worlds. + * + * When @secret has been generated by XXH3_generateSecret_fromSeed(), + * this variant produces *exactly* the same results as `_withSeed()` variant, + * hence offering only a pure speed benefit on "large" input, + * by skipping the need to regenerate the secret for every large input. + * + * Another usage scenario is to hash the secret to a 64-bit hash value, + * for example with XXH3_64bits(), which then becomes the seed, + * and then employ both the seed and the secret in _withSecretandSeed(). + * On top of speed, an added benefit is that each bit in the secret + * has a 50% chance to swap each bit in the output, + * via its impact to the seed. + * This is not guaranteed when using the secret directly in "small data" scenarios, + * because only portions of the secret are employed for small data. + */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed); + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + + +#endif /* XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ +#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) +# define XXH_IMPLEMENTATION +#endif + +#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ + + +/* ======================================================================== */ +/* ======================================================================== */ +/* ======================================================================== */ + + +/*-********************************************************************** + * xxHash implementation + *-********************************************************************** + * xxHash's implementation used to be hosted inside xxhash.c. + * + * However, inlining requires implementation to be visible to the compiler, + * hence be included alongside the header. + * Previously, implementation was hosted inside xxhash.c, + * which was then #included when inlining was activated. + * This construction created issues with a few build and install systems, + * as it required xxhash.c to be stored in /include directory. + * + * xxHash implementation is now directly integrated within xxhash.h. + * As a consequence, xxhash.c is no longer needed in /include. + * + * xxhash.c is still available and is still useful. + * In a "normal" setup, when xxhash is not inlined, + * xxhash.h only exposes the prototypes and public symbols, + * while xxhash.c can be built into an object file xxhash.o + * which can then be linked into the final binary. + ************************************************************************/ + +#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ + || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) +# define XXH_IMPLEM_13a8737387 + +/* ************************************* +* Tuning parameters +***************************************/ + +/*! + * @defgroup tuning Tuning parameters + * @{ + * + * Various macros to control xxHash's behavior. + */ +#ifdef XXH_DOXYGEN +/*! + * @brief Define this to disable 64-bit code. + * + * Useful if only using the @ref xxh32_family and you have a strict C90 compiler. + */ +# define XXH_NO_LONG_LONG +# undef XXH_NO_LONG_LONG /* don't actually */ +/*! + * @brief Controls how unaligned memory is accessed. + * + * By default, access to unaligned memory is controlled by `memcpy()`, which is + * safe and portable. + * + * Unfortunately, on some target/compiler combinations, the generated assembly + * is sub-optimal. + * + * The below switch allow selection of a different access method + * in the search for improved performance. + * + * @par Possible options: + * + * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` + * @par + * Use `memcpy()`. Safe and portable. Note that most modern compilers will + * eliminate the function call and treat it as an unaligned access. + * + * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))` + * @par + * Depends on compiler extensions and is therefore not portable. + * This method is safe _if_ your compiler supports it, + * and *generally* as fast or faster than `memcpy`. + * + * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast + * @par + * Casts directly and dereferences. This method doesn't depend on the + * compiler, but it violates the C standard as it directly dereferences an + * unaligned pointer. It can generate buggy code on targets which do not + * support unaligned memory accesses, but in some circumstances, it's the + * only known way to get the most performance. + * + * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift + * @par + * Also portable. This can generate the best code on old compilers which don't + * inline small `memcpy()` calls, and it might also be faster on big-endian + * systems which lack a native byteswap instruction. However, some compilers + * will emit literal byteshifts even if the target supports unaligned access. + * . + * + * @warning + * Methods 1 and 2 rely on implementation-defined behavior. Use these with + * care, as what works on one compiler/platform/optimization level may cause + * another to read garbage data or even crash. + * + * See http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. + * + * Prefer these methods in priority order (0 > 3 > 1 > 2) + */ +# define XXH_FORCE_MEMORY_ACCESS 0 + +/*! + * @def XXH_FORCE_ALIGN_CHECK + * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() + * and XXH64() only). + * + * This is an important performance trick for architectures without decent + * unaligned memory access performance. + * + * It checks for input alignment, and when conditions are met, uses a "fast + * path" employing direct 32-bit/64-bit reads, resulting in _dramatically + * faster_ read speed. + * + * The check costs one initial branch per hash, which is generally negligible, + * but not zero. + * + * Moreover, it's not useful to generate an additional code path if memory + * access uses the same instruction for both aligned and unaligned + * addresses (e.g. x86 and aarch64). + * + * In these cases, the alignment check can be removed by setting this macro to 0. + * Then the code will always use unaligned memory access. + * Align check is automatically disabled on x86, x64 & arm64, + * which are platforms known to offer good unaligned memory accesses performance. + * + * This option does not affect XXH3 (only XXH32 and XXH64). + */ +# define XXH_FORCE_ALIGN_CHECK 0 + +/*! + * @def XXH_NO_INLINE_HINTS + * @brief When non-zero, sets all functions to `static`. + * + * By default, xxHash tries to force the compiler to inline almost all internal + * functions. + * + * This can usually improve performance due to reduced jumping and improved + * constant folding, but significantly increases the size of the binary which + * might not be favorable. + * + * Additionally, sometimes the forced inlining can be detrimental to performance, + * depending on the architecture. + * + * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the + * compiler full control on whether to inline or not. + * + * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using + * -fno-inline with GCC or Clang, this will automatically be defined. + */ +# define XXH_NO_INLINE_HINTS 0 + +/*! + * @def XXH32_ENDJMP + * @brief Whether to use a jump for `XXH32_finalize`. + * + * For performance, `XXH32_finalize` uses multiple branches in the finalizer. + * This is generally preferable for performance, + * but depending on exact architecture, a jmp may be preferable. + * + * This setting is only possibly making a difference for very small inputs. + */ +# define XXH32_ENDJMP 0 + +/*! + * @internal + * @brief Redefines old internal names. + * + * For compatibility with code that uses xxHash's internals before the names + * were changed to improve namespacing. There is no other reason to use this. + */ +# define XXH_OLD_NAMES +# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ +#endif /* XXH_DOXYGEN */ +/*! + * @} + */ + +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ + /* prefer __packed__ structures (method 1) for gcc on armv7+ and mips */ +# if !defined(__clang__) && \ +( \ + (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ + ( \ + defined(__GNUC__) && ( \ + (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \ + ( \ + defined(__mips__) && \ + (__mips <= 5 || __mips_isa_rev < 6) && \ + (!defined(__mips16) || defined(__mips_mips16e2)) \ + ) \ + ) \ + ) \ +) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ +# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ + || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + +#ifndef XXH_NO_INLINE_HINTS +# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ + || defined(__NO_INLINE__) /* -O0, -fno-inline */ +# define XXH_NO_INLINE_HINTS 1 +# else +# define XXH_NO_INLINE_HINTS 0 +# endif +#endif + +#ifndef XXH32_ENDJMP +/* generally preferable for performance */ +# define XXH32_ENDJMP 0 +#endif + +/*! + * @defgroup impl Implementation + * @{ + */ + + +/* ************************************* +* Includes & Memory related functions +***************************************/ +/* Modify the local functions below should you wish to use some other memory routines */ +/* for ZSTD_malloc(), ZSTD_free() */ +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */ +static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); } +static void XXH_free (void* p) { ZSTD_free(p); } +static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); } + + +/* ************************************* +* Compiler Specific Options +***************************************/ +#ifdef _MSC_VER /* Visual Studio warning fix */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +#if XXH_NO_INLINE_HINTS /* disable inlining hints */ +# if defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __attribute__((unused)) +# else +# define XXH_FORCE_INLINE static # endif +# define XXH_NO_INLINE static +/* enable inlining hints */ +#elif defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) +# define XXH_NO_INLINE static __attribute__((noinline)) +#elif defined(_MSC_VER) /* Visual Studio */ +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) +#elif defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static +#else +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static +#endif + + -#endif /* XXH_STATIC_LINKING_ONLY && XXH_STATIC_H_3543687687345 */ +/* ************************************* +* Debug +***************************************/ +/*! + * @ingroup tuning + * @def XXH_DEBUGLEVEL + * @brief Sets the debugging level. + * + * XXH_DEBUGLEVEL is expected to be defined externally, typically via the + * compiler's command line options. The value must be a number. + */ +#ifndef XXH_DEBUGLEVEL +# ifdef DEBUGLEVEL /* backwards compat */ +# define XXH_DEBUGLEVEL DEBUGLEVEL +# else +# define XXH_DEBUGLEVEL 0 +# endif +#endif + +#if (XXH_DEBUGLEVEL>=1) +# include /* note: can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# define XXH_ASSERT(c) ((void)0) +#endif + +/* note: use after variable declarations */ +#ifndef XXH_STATIC_ASSERT +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ +# include +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# else +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) +# endif +# define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) +#endif + +/*! + * @internal + * @def XXH_COMPILER_GUARD(var) + * @brief Used to prevent unwanted optimizations for @p var. + * + * It uses an empty GCC inline assembly statement with a register constraint + * which forces @p var into a general purpose register (e.g. eax, ebx, ecx + * on x86) and marks it as modified. + * + * This is used in a few places to avoid unwanted autovectorization (e.g. + * XXH32_round()). All vectorization we want is explicit via intrinsics, + * and _usually_ isn't wanted elsewhere. + * + * We also use it to prevent unwanted constant folding for AArch64 in + * XXH3_initCustomSecret_scalar(). + */ +#if defined(__GNUC__) || defined(__clang__) +# define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r" (var)) +#else +# define XXH_COMPILER_GUARD(var) ((void)0) +#endif + +/* ************************************* +* Basic Types +***************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; +#endif +typedef XXH32_hash_t xxh_u32; + +#ifdef XXH_OLD_NAMES +# define BYTE xxh_u8 +# define U8 xxh_u8 +# define U32 xxh_u32 +#endif + +/* *** Memory access *** */ + +/*! + * @internal + * @fn xxh_u32 XXH_read32(const void* ptr) + * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit native endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32(const void* ptr) + * @brief Reads an unaligned 32-bit little endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readBE32(const void* ptr) + * @brief Reads an unaligned 32-bit big endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit big endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) + * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is + * always @ref XXH_alignment::XXH_unaligned. + * + * @param ptr The pointer to read from. + * @param align Whether @p ptr is aligned. + * @pre + * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte + * aligned. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE32 and XXH_readBE32. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* + * Force direct memory access. Only works on CPU which support unaligned memory + * access in hardware. + */ +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; +#endif +static xxh_u32 XXH_read32(const void* ptr) +{ + typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; + return ((const xxh_unalign*)ptr)->u32; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u32 XXH_read32(const void* memPtr) +{ + xxh_u32 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* *** Endianness *** */ + +/*! + * @ingroup tuning + * @def XXH_CPU_LITTLE_ENDIAN + * @brief Whether the target is little endian. + * + * Defined to 1 if the target is little endian, or 0 if it is big endian. + * It can be defined externally, for example on the compiler command line. + * + * If it is not defined, + * a runtime check (which is usually constant folded) is used instead. + * + * @note + * This is not necessarily defined to an integer constant. + * + * @see XXH_isLittleEndian() for the runtime check. + */ +#ifndef XXH_CPU_LITTLE_ENDIAN +/* + * Try to detect endianness automatically, to avoid the nonstandard behavior + * in `XXH_isLittleEndian()` + */ +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +/*! + * @internal + * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. + * + * Most compilers will constant fold this. + */ +static int XXH_isLittleEndian(void) +{ + /* + * Portable and well-defined behavior. + * Don't use static: it is detrimental to performance. + */ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#ifdef __has_builtin +# define XXH_HAS_BUILTIN(x) __has_builtin(x) +#else +# define XXH_HAS_BUILTIN(x) 0 +#endif + +/*! + * @internal + * @def XXH_rotl32(x,r) + * @brief 32-bit rotate left. + * + * @param x The 32-bit integer to be rotated. + * @param r The number of bits to rotate. + * @pre + * @p r > 0 && @p r < 32 + * @note + * @p x and @p r may be evaluated multiple times. + * @return The rotated result. + */ +#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ + && XXH_HAS_BUILTIN(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 +/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ +#elif defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#endif + +/*! + * @internal + * @fn xxh_u32 XXH_swap32(xxh_u32 x) + * @brief A 32-bit byteswap. + * + * @param x The 32-bit integer to byteswap. + * @return @p x, byteswapped. + */ +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +#else +static xxh_u32 XXH_swap32 (xxh_u32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +#endif + + +/* *************************** +* Memory reads +*****************************/ + +/*! + * @internal + * @brief Enum to indicate whether a pointer is aligned. + */ +typedef enum { + XXH_aligned, /*!< Aligned */ + XXH_unaligned /*!< Possibly unaligned */ +} XXH_alignment; + +/* + * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. + * + * This is ideal for older compilers which don't inline memcpy. + */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u32)bytePtr[1] << 8) + | ((xxh_u32)bytePtr[2] << 16) + | ((xxh_u32)bytePtr[3] << 24); +} + +XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[3] + | ((xxh_u32)bytePtr[2] << 8) + | ((xxh_u32)bytePtr[1] << 16) + | ((xxh_u32)bytePtr[0] << 24); +} + +#else +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); +} + +static xxh_u32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } +} + + +/* ************************************* +* Misc +***************************************/ +/*! @ingroup public */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ******************************************************************* +* 32-bit hash functions +*********************************************************************/ +/*! + * @} + * @defgroup xxh32_impl XXH32 implementation + * @ingroup impl + * @{ + */ + /* #define instead of static const, to be used as initializers */ +#define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ +#define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ +#define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ +#define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ +#define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ + +#ifdef XXH_OLD_NAMES +# define PRIME32_1 XXH_PRIME32_1 +# define PRIME32_2 XXH_PRIME32_2 +# define PRIME32_3 XXH_PRIME32_3 +# define PRIME32_4 XXH_PRIME32_4 +# define PRIME32_5 XXH_PRIME32_5 +#endif + +/*! + * @internal + * @brief Normal stripe processing routine. + * + * This shuffles the bits so that any bit from @p input impacts several bits in + * @p acc. + * + * @param acc The accumulator lane. + * @param input The stripe of input to mix. + * @return The mixed accumulator lane. + */ +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) +{ + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; +#if (defined(__SSE4_1__) || defined(__aarch64__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * UGLY HACK: + * A compiler fence is the only thing that prevents GCC and Clang from + * autovectorizing the XXH32 loop (pragmas and attributes don't work for some + * reason) without globally disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on + * newer chips!) making it slightly slower to multiply four integers at + * once compared to four integers independently. Even when pmulld was + * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE + * just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because + * the SIMD actually serializes this operation: While v1 is rotating, v2 + * can load data, while v3 can multiply. SSE forces them to operate + * together. + * + * This is also enabled on AArch64, as Clang autovectorizes it incorrectly + * and it is pointless writing a NEON implementation that is basically the + * same speed as scalar for XXH32. + */ + XXH_COMPILER_GUARD(acc); +#endif + return acc; +} + +/*! + * @internal + * @brief Mixes all bits to finalize the hash. + * + * The final mix ensures that all input bits have a chance to impact any bit in + * the output digest, resulting in an unbiased distribution. + * + * @param h32 The hash to avalanche. + * @return The avalanched hash. + */ +static xxh_u32 XXH32_avalanche(xxh_u32 h32) +{ + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + return(h32); +} + +#define XXH_get32bits(p) XXH_readLE32_align(p, align) + +/*! + * @internal + * @brief Processes the last 0-15 bytes of @p ptr. + * + * There may be up to 15 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 h32 The hash to finalize. + * @param ptr The pointer to the remaining input. + * @param len The remaining length, modulo 16. + * @param align Whether @p ptr is aligned. + * @return The finalized hash. + */ +static xxh_u32 +XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1 do { \ + h32 += (*ptr++) * XXH_PRIME32_5; \ + h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \ +} while (0) + +#define XXH_PROCESS4 do { \ + h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \ + ptr += 4; \ + h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \ +} while (0) + + if (ptr==NULL) XXH_ASSERT(len == 0); + + /* Compact rerolled version; generally faster */ + if (!XXH32_ENDJMP) { + len &= 15; + while (len >= 4) { + XXH_PROCESS4; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1; + --len; + } + return XXH32_avalanche(h32); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 8: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 4: XXH_PROCESS4; + return XXH32_avalanche(h32); + + case 13: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 9: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 5: XXH_PROCESS4; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 14: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 10: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 6: XXH_PROCESS4; + XXH_PROCESS1; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 15: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 11: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 7: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 3: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 2: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 1: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 0: return XXH32_avalanche(h32); + } + XXH_ASSERT(0); + return h32; /* reaching this point is deemed impossible */ + } +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1 XXH_PROCESS1 +# define PROCESS4 XXH_PROCESS4 +#else +# undef XXH_PROCESS1 +# undef XXH_PROCESS4 +#endif + +/*! + * @internal + * @brief The implementation for @ref XXH32(). + * + * @param input , len , seed Directly passed from @ref XXH32(). + * @param align Whether @p input is aligned. + * @return The calculated hash. + */ +XXH_FORCE_INLINE xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) +{ + xxh_u32 h32; + + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=16) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 15; + xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + xxh_u32 v2 = seed + XXH_PRIME32_2; + xxh_u32 v3 = seed + 0; + xxh_u32 v4 = seed - XXH_PRIME32_1; + + do { + v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; + v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; + v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; + v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; + } while (input < limit); + + h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); + } else { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (xxh_u32)len; + + return XXH32_finalize(h32, input, len&15, align); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_state_t state; + XXH32_reset(&state, seed); + XXH32_update(&state, (const xxh_u8*)input, len); + return XXH32_digest(&state); +#else + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); +#endif +} + + + +/******* Hash streaming *******/ +/*! + * @ingroup xxh32_family + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) +{ + return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) +{ + XXH_memcpy(dstState, srcState, sizeof(*dstState)); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) +{ + XXH_ASSERT(statePtr != NULL); + memset(statePtr, 0, sizeof(*statePtr)); + statePtr->v[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + statePtr->v[1] = seed + XXH_PRIME32_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME32_1; + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); + + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); + state->memsize += (XXH32_hash_t)len; + return XXH_OK; + } + + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const xxh_u32* p32 = state->mem32; + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p32)); p32++; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p32)); p32++; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p32)); p32++; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p32)); + } + p += 16-state->memsize; + state->memsize = 0; + } + + if (p <= bEnd-16) { + const xxh_u8* const limit = bEnd - 16; + + do { + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p)); p+=4; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p)); p+=4; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p)); p+=4; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p)); p+=4; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) +{ + xxh_u32 h32; + + if (state->large_len) { + h32 = XXH_rotl32(state->v[0], 1) + + XXH_rotl32(state->v[1], 7) + + XXH_rotl32(state->v[2], 12) + + XXH_rotl32(state->v[3], 18); + } else { + h32 = state->v[2] /* == seed */ + XXH_PRIME32_5; + } + + h32 += state->total_len_32; + + return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! + * @ingroup xxh32_family + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * + * The canonical representation uses big endian convention, the same convention + * as human-readable numbers (large digits first). + * + * This way, hash values can be written into a file or buffer, remaining + * comparable across different systems. + * + * The following functions allow transformation of hash values to and from their + * canonical format. + */ +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)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} + + +#ifndef XXH_NO_LONG_LONG + +/* ******************************************************************* +* 64-bit hash functions +*********************************************************************/ +/*! + * @} + * @ingroup impl + * @{ + */ +/******* Memory access *******/ + +typedef XXH64_hash_t xxh_u64; + +#ifdef XXH_OLD_NAMES +# define U64 xxh_u64 +#endif + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE64 and XXH_readBE64. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + return *(const xxh_u64*) memPtr; +} + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer, but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; +#endif +static xxh_u64 XXH_read64(const void* ptr) +{ + typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; + return ((const xxh_unalign64*)ptr)->u64; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + xxh_u64 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap64 _byteswap_uint64 +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap64 __builtin_bswap64 +#else +static xxh_u64 XXH_swap64(xxh_u64 x) +{ + return ((x << 56) & 0xff00000000000000ULL) | + ((x << 40) & 0x00ff000000000000ULL) | + ((x << 24) & 0x0000ff0000000000ULL) | + ((x << 8) & 0x000000ff00000000ULL) | + ((x >> 8) & 0x00000000ff000000ULL) | + ((x >> 24) & 0x0000000000ff0000ULL) | + ((x >> 40) & 0x000000000000ff00ULL) | + ((x >> 56) & 0x00000000000000ffULL); +} +#endif + + +/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u64)bytePtr[1] << 8) + | ((xxh_u64)bytePtr[2] << 16) + | ((xxh_u64)bytePtr[3] << 24) + | ((xxh_u64)bytePtr[4] << 32) + | ((xxh_u64)bytePtr[5] << 40) + | ((xxh_u64)bytePtr[6] << 48) + | ((xxh_u64)bytePtr[7] << 56); +} + +XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[7] + | ((xxh_u64)bytePtr[6] << 8) + | ((xxh_u64)bytePtr[5] << 16) + | ((xxh_u64)bytePtr[4] << 24) + | ((xxh_u64)bytePtr[3] << 32) + | ((xxh_u64)bytePtr[2] << 40) + | ((xxh_u64)bytePtr[1] << 48) + | ((xxh_u64)bytePtr[0] << 56); +} + +#else +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); +} + +static xxh_u64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); +} + + +/******* xxh64 *******/ +/*! + * @} + * @defgroup xxh64_impl XXH64 implementation + * @ingroup impl + * @{ + */ +/* #define rather that static const, to be used as initializers */ +#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ +#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ +#define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ +#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ +#define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ + +#ifdef XXH_OLD_NAMES +# define PRIME64_1 XXH_PRIME64_1 +# define PRIME64_2 XXH_PRIME64_2 +# define PRIME64_3 XXH_PRIME64_3 +# define PRIME64_4 XXH_PRIME64_4 +# define PRIME64_5 XXH_PRIME64_5 +#endif + +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) +{ + acc += input * XXH_PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= XXH_PRIME64_1; + return acc; +} + +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; + return acc; +} + +static xxh_u64 XXH64_avalanche(xxh_u64 h64) +{ + h64 ^= h64 >> 33; + h64 *= XXH_PRIME64_2; + h64 ^= h64 >> 29; + h64 *= XXH_PRIME64_3; + h64 ^= h64 >> 32; + return h64; +} + + +#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) +{ + if (ptr==NULL) XXH_ASSERT(len == 0); + len &= 31; + while (len >= 8) { + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); + ptr += 8; + h64 ^= k1; + h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; + len -= 8; + } + if (len >= 4) { + h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; + ptr += 4; + h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; + len -= 4; + } + while (len > 0) { + h64 ^= (*ptr++) * XXH_PRIME64_5; + h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; + --len; + } + return XXH64_avalanche(h64); +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1_64 XXH_PROCESS1_64 +# define PROCESS4_64 XXH_PROCESS4_64 +# define PROCESS8_64 XXH_PROCESS8_64 +#else +# undef XXH_PROCESS1_64 +# undef XXH_PROCESS4_64 +# undef XXH_PROCESS8_64 +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) +{ + xxh_u64 h64; + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=32) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 31; + xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + xxh_u64 v2 = seed + XXH_PRIME64_2; + xxh_u64 v3 = seed + 0; + xxh_u64 v4 = seed - XXH_PRIME64_1; + + do { + v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; + v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; + v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; + v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; + } while (inputv[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + statePtr->v[1] = seed + XXH_PRIME64_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME64_1; + return XXH_OK; +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH64_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); + state->memsize += (xxh_u32)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(state->mem64+0)); + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(state->mem64+1)); + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(state->mem64+2)); + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(state->mem64+3)); + p += 32 - state->memsize; + state->memsize = 0; + } + + if (p+32 <= bEnd) { + const xxh_u8* const limit = bEnd - 32; + + do { + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(p)); p+=8; + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(p)); p+=8; + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(p)); p+=8; + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(p)); p+=8; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state) +{ + xxh_u64 h64; + + if (state->total_len >= 32) { + h64 = XXH_rotl64(state->v[0], 1) + XXH_rotl64(state->v[1], 7) + XXH_rotl64(state->v[2], 12) + XXH_rotl64(state->v[3], 18); + h64 = XXH64_mergeRound(h64, state->v[0]); + h64 = XXH64_mergeRound(h64, state->v[1]); + h64 = XXH64_mergeRound(h64, state->v[2]); + h64 = XXH64_mergeRound(h64, state->v[3]); + } else { + h64 = state->v[2] /*seed*/ + XXH_PRIME64_5; + } + + h64 += (xxh_u64) state->total_len; + + return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) +{ + /* XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} + +#ifndef XXH_NO_XXH3 + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ +/*! + * @} + * @defgroup xxh3_impl XXH3 implementation + * @ingroup impl + * @{ + */ + +/* === Compiler specifics === */ + +#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ +# define XXH_RESTRICT /* disable */ +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#else +/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */ +# define XXH_RESTRICT /* disable */ +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) \ + || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ + || defined(__clang__) +# define XXH_likely(x) __builtin_expect(x, 1) +# define XXH_unlikely(x) __builtin_expect(x, 0) +#else +# define XXH_likely(x) (x) +# define XXH_unlikely(x) (x) +#endif + +#if defined(__GNUC__) || defined(__clang__) +# if defined(__ARM_NEON__) || defined(__ARM_NEON) \ + || defined(__aarch64__) || defined(_M_ARM) \ + || defined(_M_ARM64) || defined(_M_ARM64EC) +# define inline __inline__ /* circumvent a clang bug */ +# include +# undef inline +# elif defined(__AVX2__) +# include +# elif defined(__SSE2__) +# include +# endif +#endif + +#if defined(_MSC_VER) +# include +#endif + +/* + * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while + * remaining a true 64-bit/128-bit hash function. + * + * This is done by prioritizing a subset of 64-bit operations that can be + * emulated without too many steps on the average 32-bit machine. + * + * For example, these two lines seem similar, and run equally fast on 64-bit: + * + * xxh_u64 x; + * x ^= (x >> 47); // good + * x ^= (x >> 13); // bad + * + * However, to a 32-bit machine, there is a major difference. + * + * x ^= (x >> 47) looks like this: + * + * x.lo ^= (x.hi >> (47 - 32)); + * + * while x ^= (x >> 13) looks like this: + * + * // note: funnel shifts are not usually cheap. + * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); + * x.hi ^= (x.hi >> 13); + * + * The first one is significantly faster than the second, simply because the + * shift is larger than 32. This means: + * - All the bits we need are in the upper 32 bits, so we can ignore the lower + * 32 bits in the shift. + * - The shift result will always fit in the lower 32 bits, and therefore, + * we can ignore the upper 32 bits in the xor. + * + * Thanks to this optimization, XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * - For the 128-bit variant, a decent byteswap helps short inputs. + * + * The first two are already required by XXH32, and almost all 32-bit and 64-bit + * platforms which can run XXH32 can run XXH3 efficiently. + * + * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one + * notable exception. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand allowing free + * shifts is helpful, too. + * + * Therefore, we do a quick sanity check. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we will + * emit a warning, as it is not a "sane" platform to compile for. + * + * Usually, if this happens, it is because of an accident and you probably need + * to specify -march, as you likely meant to compile for a newer architecture. + * + * Credit: large sections of the vectorial and asm source code paths + * have been contributed by @easyaspi314 + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ + +#ifdef XXH_DOXYGEN +/*! + * @ingroup tuning + * @brief Overrides the vectorization implementation chosen for XXH3. + * + * Can be defined to 0 to disable SIMD or any of the values mentioned in + * @ref XXH_VECTOR_TYPE. + * + * If this is not defined, it uses predefined macros to determine the best + * implementation. + */ +# define XXH_VECTOR XXH_SCALAR +/*! + * @ingroup tuning + * @brief Possible values for @ref XXH_VECTOR. + * + * Note that these are actually implemented as macros. + * + * If this is not defined, it is detected automatically. + * @ref XXH_X86DISPATCH overrides this. + */ +enum XXH_VECTOR_TYPE /* fake enum */ { + XXH_SCALAR = 0, /*!< Portable scalar version */ + XXH_SSE2 = 1, /*!< + * SSE2 for Pentium 4, Opteron, all x86_64. + * + * @note SSE2 is also guaranteed on Windows 10, macOS, and + * Android x86. + */ + XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */ + XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ + XXH_NEON = 4, /*!< NEON for most ARMv7-A and all AArch64 */ + XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */ +}; +/*! + * @ingroup tuning + * @brief Selects the minimum alignment for XXH3's accumulators. + * + * When using SIMD, this should match the alignment required for said vector + * type, so, for example, 32 for AVX2. + * + * Default: Auto detected. + */ +# define XXH_ACC_ALIGN 8 +#endif + +/* Actual definition */ +#ifndef XXH_DOXYGEN +# define XXH_SCALAR 0 +# define XXH_SSE2 1 +# define XXH_AVX2 2 +# define XXH_AVX512 3 +# define XXH_NEON 4 +# define XXH_VSX 5 +#endif + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if ( \ + defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ + || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ + ) && ( \ + defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ + ) +# define XXH_VECTOR XXH_NEON +# elif defined(__AVX512F__) +# define XXH_VECTOR XXH_AVX512 +# elif defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ + || (defined(__s390x__) && defined(__VEC__)) \ + && defined(__GNUC__) /* TODO: IBM XL */ +# define XXH_VECTOR XXH_VSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* + * Controls the alignment of the accumulator, + * for compatibility with aligned vector loads, which are usually faster. + */ +#ifndef XXH_ACC_ALIGN +# if defined(XXH_X86DISPATCH) +# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ +# elif XXH_VECTOR == XXH_SCALAR /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == XXH_SSE2 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == XXH_NEON /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_VSX /* vsx */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ +# define XXH_ACC_ALIGN 64 +# endif +#endif + +#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ + || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#else +# define XXH_SEC_ALIGN 8 +#endif + +/* + * UGLY HACK: + * GCC usually generates the best code with -O3 for xxHash. + * + * However, when targeting AVX2, it is overzealous in its unrolling resulting + * in code roughly 3/4 the speed of Clang. + * + * There are other issues, such as GCC splitting _mm256_loadu_si256 into + * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which + * only applies to Sandy and Ivy Bridge... which don't even support AVX2. + * + * That is why when compiling the AVX2 version, it is recommended to use either + * -O2 -mavx2 -march=haswell + * or + * -O2 -mavx2 -mno-avx256-split-unaligned-load + * for decent performance, or to use Clang instead. + * + * Fortunately, we can control the first one with a pragma that forces GCC into + * -O2, but the other one we can't control without "failed to inline always + * inline function due to target mismatch" warnings. + */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC push_options +# pragma GCC optimize("-O2") +#endif + + +#if XXH_VECTOR == XXH_NEON +/* + * NEON's setup for vmlal_u32 is a little more complicated than it is on + * SSE2, AVX2, and VSX. + * + * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast. + * + * To do the same operation, the 128-bit 'Q' register needs to be split into + * two 64-bit 'D' registers, performing this operation:: + * + * [ a | b ] + * | '---------. .--------' | + * | x | + * | .---------' '--------. | + * [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32 ] + * + * Due to significant changes in aarch64, the fastest method for aarch64 is + * completely different than the fastest method for ARMv7-A. + * + * ARMv7-A treats D registers as unions overlaying Q registers, so modifying + * D11 will modify the high half of Q5. This is similar to how modifying AH + * will only affect bits 8-15 of AX on x86. + * + * VZIP takes two registers, and puts even lanes in one register and odd lanes + * in the other. + * + * On ARMv7-A, this strangely modifies both parameters in place instead of + * taking the usual 3-operand form. + * + * Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the + * lower and upper halves of the Q register to end up with the high and low + * halves where we want - all in one instruction. + * + * vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] } + * + * Unfortunately we need inline assembly for this: Instructions modifying two + * registers at once is not possible in GCC or Clang's IR, and they have to + * create a copy. + * + * aarch64 requires a different approach. + * + * In order to make it easier to write a decent compiler for aarch64, many + * quirks were removed, such as conditional execution. + * + * NEON was also affected by this. + * + * aarch64 cannot access the high bits of a Q-form register, and writes to a + * D-form register zero the high bits, similar to how writes to W-form scalar + * registers (or DWORD registers on x86_64) work. + * + * The formerly free vget_high intrinsics now require a vext (with a few + * exceptions) + * + * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent + * of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one + * operand. + * + * The equivalent of the VZIP.32 on the lower and upper halves would be this + * mess: + * + * ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] } + * zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] } + * zip2 v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] } + * + * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN): + * + * shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32); + * xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF); + * + * This is available on ARMv7-A, but is less efficient than a single VZIP.32. + */ + +/*! + * Function-like macro: + * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi) + * { + * outLo = (uint32x2_t)(in & 0xFFFFFFFF); + * outHi = (uint32x2_t)(in >> 32); + * in = UNDEFINED; + * } + */ +# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \ + && (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__arm__) || defined(__thumb__) || defined(_M_ARM)) +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ + /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ + /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ + __asm__("vzip.32 %e0, %f0" : "+w" (in)); \ + (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ + (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ + } while (0) +# else +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + (outLo) = vmovn_u64 (in); \ + (outHi) = vshrn_n_u64 ((in), 32); \ + } while (0) +# endif + +/*! + * @ingroup tuning + * @brief Controls the NEON to scalar ratio for XXH3 + * + * On AArch64 when not optimizing for size, XXH3 will run 6 lanes using NEON and + * 2 lanes on scalar by default. + * + * This can be set to 2, 4, 6, or 8. ARMv7 will default to all 8 NEON lanes, as the + * 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 it can't + * have more than 2 NEON (F0/F1) micro-ops. If you are only using NEON instructions, + * you are only using 2/3 of the CPU bandwidth. + * + * This is even more noticeable on the more advanced cores like the A76 which + * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. + * + * Therefore, @ref XXH3_NEON_LANES lanes will be processed using NEON, and the + * remaining lanes will use scalar instructions. This improves the bandwidth + * and also gives the integer pipelines something to do besides twiddling loop + * counters and pointers. + * + * This change benefits CPUs with large micro-op buffers without negatively affecting + * other CPUs: + * + * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | + * |:----------------------|:--------------------|----------:|-----------:|------:| + * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | + * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | + * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | + * + * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. + * + * @see XXH3_accumulate_512_neon() + */ +# ifndef XXH3_NEON_LANES +# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ + && !defined(__OPTIMIZE_SIZE__) +# define XXH3_NEON_LANES 6 +# else +# define XXH3_NEON_LANES XXH_ACC_NB +# endif +# endif +#endif /* XXH_VECTOR == XXH_NEON */ + +/* + * VSX and Z Vector helpers. + * + * This is very messy, and any pull requests to clean this up are welcome. + * + * There are a lot of problems with supporting VSX and s390x, due to + * inconsistent intrinsics, spotty coverage, and multiple endiannesses. + */ +#if XXH_VECTOR == XXH_VSX +# if defined(__s390x__) +# include +# 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 +# endif + +typedef __vector unsigned long long xxh_u64x2; +typedef __vector unsigned char xxh_u8x16; +typedef __vector unsigned xxh_u32x4; + +# ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +# endif /* !defined(XXH_VSX_BE) */ + +# if XXH_VSX_BE +# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) +# define XXH_vec_revb vec_revb +# else +/*! + * A polyfill for POWER9's vec_revb(). + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) +{ + xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif +# endif /* XXH_VSX_BE */ + +/*! + * Performs an unaligned vector load and byte swaps it on big endian. + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) +{ + xxh_u64x2 ret; + XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); +# if XXH_VSX_BE + ret = XXH_vec_revb(ret); +# endif + return ret; +} + +/* + * vec_mulo and vec_mule are very problematic intrinsics on PowerPC + * + * These intrinsics weren't added until GCC 8, despite existing for a while, + * and they are endian dependent. Also, their meaning swap depending on version. + * */ +# if defined(__s390x__) + /* s390x is always big endian, no issue on this platform */ +# define XXH_vec_mulo vec_mulo +# define XXH_vec_mule vec_mule +# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) +/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +# else +/* gcc needs inline assembly */ +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +# endif /* XXH_vec_mulo, XXH_vec_mule */ +#endif /* XXH_VECTOR == XXH_VSX */ + + +/* prefetch + * can be disabled, by declaring XXH_NO_PREFETCH build macro */ +#if defined(XXH_NO_PREFETCH) +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# else +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* XXH_NO_PREFETCH */ + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +/*! Pseudorandom secret taken directly from FARSH. */ +XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + + +#ifdef XXH_OLD_NAMES +# define kSecret XXH3_kSecret +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Calculates a 32-bit to 64-bit long multiply. + * + * Implemented as a macro. + * + * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't + * need to (but it shouldn't need to anyways, it is about 7 instructions to do + * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we + * use that instead of the normal method. + * + * If you are compiling for platforms like Thumb-1 and don't have a better option, + * you may also want to write your own long multiply routine here. + * + * @param x, y Numbers to be multiplied + * @return 64-bit product of the low 32 bits of @p x and @p y. + */ +XXH_FORCE_INLINE xxh_u64 +XXH_mult32to64(xxh_u64 x, xxh_u64 y) +{ + return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); +} +#elif defined(_MSC_VER) && defined(_M_IX86) +# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) +#else +/* + * Downcast + upcast is usually better than masking on older compilers like + * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. + * + * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands + * and perform a full 64x64 multiply -- entirely redundant on 32-bit. + */ +# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) +#endif + +/*! + * @brief Calculates a 64->128-bit long multiply. + * + * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar + * version. + * + * @param lhs , rhs The 64-bit integers to be multiplied + * @return The 128-bit result represented in an @ref XXH128_hash_t. + */ +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this type + * despite not having the arithmetic for it. This results in a laggy + * compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t r128; + r128.low64 = (xxh_u64)(product); + r128.high64 = (xxh_u64)(product >> 64); + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t r128; + r128.low64 = product_low; + r128.high64 = product_high; + return r128; + + /* + * MSVC for ARM64's __umulh method. + * + * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. + */ +#elif defined(_M_ARM64) || defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(__umulh) +#endif + XXH128_hash_t r128; + r128.low64 = lhs * rhs; + r128.high64 = __umulh(lhs, rhs); + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown below + * with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 + * --------- + * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. + * This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARM's Digital Signal Processing extension + * in 32-bit ARMv6 and later, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, and + * allows this to be calculated in only 4 instructions at speeds + * comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be a couple + * of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128; + r128.low64 = lower; + r128.high64 = upper; + return r128; +#endif +} + +/*! + * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. + * + * The reason for the separate function is to prevent passing too many structs + * around by value. This will hopefully inline the multiply, but we don't force it. + * + * @param lhs , rhs The 64-bit integers to multiply + * @return The low 64 bits of the product XOR'd by the high 64 bits. + * @see XXH_mult64to128() + */ +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + +/*! Seems to produce slightly better code on GCC for some reason. */ +XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) +{ + XXH_ASSERT(0 <= shift && shift < 64); + return v64 ^ (v64 >> shift); +} + +/* + * This is a fast avalanche stage, + * suitable when input bits are already partially mixed + */ +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 = XXH_xorshift64(h64, 37); + h64 *= 0x165667919E3779F9ULL; + h64 = XXH_xorshift64(h64, 32); + return h64; +} + +/* + * This is a stronger avalanche, + * inspired by Pelle Evensen's rrmxmx + * preferable when input has not been previously mixed + */ +static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) +{ + /* this mix is inspired by Pelle Evensen's rrmxmx */ + h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); + h64 *= 0x9FB21C651E98DF25ULL; + h64 ^= (h64 >> 35) + len ; + h64 *= 0x9FB21C651E98DF25ULL; + return XXH_xorshift64(h64, 28); +} + + +/* ========================================== + * Short keys + * ========================================== + * One of the shortcomings of XXH32 and XXH64 was that their performance was + * sub-optimal on short lengths. It used an iterative algorithm which strongly + * favored lengths that were a multiple of 4 or 8. + * + * Instead of iterating over individual inputs, we use a set of single shot + * functions which piece together a range of lengths and operate in constant time. + * + * Additionally, the number of multiplies has been significantly reduced. This + * reduces latency, especially when emulating 64-bit multiplies on 32-bit. + * + * Depending on the platform, this may or may not be faster than XXH32, but it + * is almost guaranteed to be faster than XXH64. + */ + +/* + * At very short lengths, there isn't enough input to fully hide secrets, or use + * the entire secret. + * + * There is also only a limited amount of mixing we can do before significantly + * impacting performance. + * + * Therefore, we use different sections of the secret and always mix two secret + * samples with an XOR. This should have no effect on performance on the + * seedless or withSeed variants because everything _should_ be constant folded + * by modern compilers. + * + * The XOR mixing hides individual parts of the secret and increases entropy. + * + * This adds an extra layer of strength for custom secrets. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combined = { input[0], 0x01, input[0], input[0] } + * len = 2: combined = { input[1], 0x02, input[0], input[1] } + * len = 3: combined = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; + return XXH64_avalanche(keyed); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input1 = XXH_readLE32(input); + xxh_u32 const input2 = XXH_readLE32(input + len - 4); + xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; + xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); + xxh_u64 const keyed = input64 ^ bitflip; + return XXH3_rrmxmx(keyed, len); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; + xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; + xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; + xxh_u64 const acc = len + + XXH_swap64(input_lo) + input_hi + + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); + if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); + } +} + +/* + * DISCLAIMER: There are known *seed-dependent* multicollisions here due to + * multiplication by zero, affecting hashes of lengths 17 to 240. + * + * However, they are very unlikely. + * + * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all + * unseeded non-cryptographic hashes, it does not attempt to defend itself + * against specially crafted inputs, only random inputs. + * + * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes + * cancelling out the secret is taken an arbitrary number of times (addressed + * in XXH3_accumulate_512), this collision is very unlikely with random inputs + * and/or proper seeding: + * + * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a + * function that is only called up to 16 times per hash with up to 240 bytes of + * input. + * + * This is not too bad for a non-cryptographic hash function, especially with + * only 64 bit outputs. + * + * The 128-bit variant (which trades some speed for strength) is NOT affected + * by this, although it is always a good idea to use a proper seed if you care + * about strength. + */ +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ +#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ + /* + * UGLY HACK: + * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in + * slower code. + * + * By forcing seed64 into a register, we disrupt the cost model and + * cause it to scalarize. See `XXH32_round()` + * + * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, + * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on + * GCC 9.2, despite both emitting scalar code. + * + * GCC generates much better scalar code than Clang for the rest of XXH3, + * which is why finding a more optimal codepath is an interest. + */ + XXH_COMPILER_GUARD(seed64); +#endif + { xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) + ); + } +} + +/* For mid range keys, XXH3 uses a Mum-hash variant. */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * XXH_PRIME64_1; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); + + return XXH3_avalanche(acc); + } +} + +#define XXH3_MIDSIZE_MAX 240 + +XXH_NO_INLINE XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * XXH_PRIME64_1; + int const nbRounds = (int)len / 16; + int i; + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + acc = XXH3_avalanche(acc); + XXH_ASSERT(nbRounds >= 8); +#if defined(__clang__) /* Clang */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. + * In everywhere else, it uses scalar code. + * + * For 64->128-bit multiplies, even if the NEON was 100% optimal, it + * would still be slower than UMAAL (see XXH_mult64to128). + * + * Unfortunately, Clang doesn't handle the long multiplies properly and + * converts them to the nonexistent "vmulq_u64" intrinsic, which is then + * scalarized into an ugly mess of VMOV.32 instructions. + * + * This mess is difficult to avoid without turning autovectorization + * off completely, but they are usually relatively minor and/or not + * worth it to fix. + * + * This loop is the easiest to fix, as unlike XXH32, this pragma + * _actually works_ because it is a loop vectorization instead of an + * SLP vectorization. + */ + #pragma clang loop vectorize(disable) +#endif + for (i=8 ; i < nbRounds; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + /* last bytes */ + acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + return XXH3_avalanche(acc); + } +} + + +/* ======= Long Keys ======= */ + +#define XXH_STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) + +#ifdef XXH_OLD_NAMES +# define STRIPE_LEN XXH_STRIPE_LEN +# define ACC_NB XXH_ACC_NB +#endif + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + XXH_memcpy(dst, &v64, sizeof(v64)); +} + +/* Several intrinsic functions below are supposed to accept __int64 as argument, + * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . + * However, several environments do not define __int64 type, + * requiring a workaround. + */ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) + typedef int64_t xxh_i64; +#else + /* the following type must have a width of 64-bit */ + typedef long long xxh_i64; +#endif + + +/* + * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. + * + * It is a hardened version of UMAC, based off of FARSH's implementation. + * + * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD + * implementations, and it is ridiculously fast. + * + * We harden it by mixing the original input to the accumulators as well as the product. + * + * This means that in the (relatively likely) case of a multiply by zero, the + * original input is preserved. + * + * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve + * cross-pollination, as otherwise the upper and lower halves would be + * essentially independent. + * + * This doesn't matter on 64-bit hashes since they all get merged together in + * the end, so we skip the extra step. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +#if (XXH_VECTOR == XXH_AVX512) \ + || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) + +#ifndef XXH_TARGET_AVX512 +# define XXH_TARGET_AVX512 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + __m512i* const xacc = (__m512i *) acc; + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + + { + /* data_vec = input[0]; */ + __m512i const data_vec = _mm512_loadu_si512 (input); + /* key_vec = secret[0]; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + /* data_key = data_vec ^ key_vec; */ + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); + /* xacc[0] += swap(data_vec); */ + __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); + __m512i const sum = _mm512_add_epi64(*xacc, data_swap); + /* xacc[0] += product; */ + *xacc = _mm512_add_epi64(product, sum); + } +} + +/* + * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. + * + * Multiplication isn't perfect, as explained by Google in HighwayHash: + * + * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + * // varying degrees. In descending order of goodness, bytes + * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + * // As expected, the upper and lower bytes are much worse. + * + * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 + * + * Since our algorithm uses a pseudorandom secret to add some variance into the + * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. + * + * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid + * extraction. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + { __m512i* const xacc = (__m512i*) acc; + const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); + + /* xacc[0] ^= (xacc[0] >> 47) */ + __m512i const acc_vec = *xacc; + __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); + __m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted); + /* xacc[0] ^= secret; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + + /* 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 prod_lo = _mm512_mul_epu32 (data_key, prime32); + __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); + *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); + XXH_ASSERT(((size_t)customSecret & 63) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); + __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, (xxh_i64)(0U - seed64)); + + const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); + __m512i* const dest = ( __m512i*) customSecret; + int i; + XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 63) == 0); + for (i=0; i < nbRounds; ++i) { + /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', + * this will warn "discards 'const' qualifier". */ + union { + const __m512i* cp; + void* p; + } remote_const_void; + remote_const_void.cp = src + i; + dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_AVX2) \ + || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) + +#ifndef XXH_TARGET_AVX2 +# define XXH_TARGET_AVX2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xinput = (const __m256i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm256_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); + (void)(&XXH_writeLE64); + XXH_PREFETCH(customSecret); + { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); + + const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); + __m256i* dest = ( __m256i*) customSecret; + +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dest); +# endif + XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 31) == 0); + + /* GCC -O2 need unroll loop manually */ + dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); + dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); + dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); + dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); + dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); + dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed); + } +} + +#endif + +/* x86dispatch always generates SSE2 */ +#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_SSE2 +# define XXH_TARGET_SSE2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* SSE2 is just a half-scale version of the AVX2 version. */ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xinput = (const __m128i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); + +# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 + /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ + XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; + __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); +# else + __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); +# endif + int i; + + const void* const src16 = XXH3_kSecret; + __m128i* dst16 = (__m128i*) customSecret; +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dst16); +# endif + XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dst16 & 15) == 0); + + for (i=0; i < nbRounds; ++i) { + dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_NEON) + +/* forward declarations for the scalar routines */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, size_t lane); + +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, size_t lane); + +/*! + * @internal + * @brief The bulk processing loop for NEON. + * + * The NEON code path is actually partially scalar when running on AArch64. This + * is to optimize the pipelining and can have up to 15% speedup depending on the + * CPU, and it also mitigates some GCC codegen issues. + * + * @see XXH3_NEON_LANES for configuring this and details about this optimization. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); + { + uint64x2_t* const xacc = (uint64x2_t *) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* const xinput = (const uint8_t *) input; + uint8_t const* const xsecret = (const uint8_t *) secret; + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* data_vec = xinput[i]; */ + uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key; + uint32x2_t data_key_lo, data_key_hi; + /* xacc[i] += swap(data_vec); */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped = vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + /* data_key = data_vec ^ key_vec; */ + data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); + /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (data_key >> 32); + * data_key = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ + xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); + + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { uint64x2_t* xacc = (uint64x2_t*) acc; + uint8_t const* xsecret = (uint8_t const*) secret; + uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1); + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + uint64x2_t acc_vec = xacc[i]; + uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); + uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); + + /* xacc[i] ^= xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8 (xsecret + (i * 16)); + uint64x2_t data_key = veorq_u64 (data_vec, vreinterpretq_u64_u8(key_vec)); + + /* xacc[i] *= XXH_PRIME32_1 */ + uint32x2_t data_key_lo, data_key_hi; + /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (xacc[i] >> 32); + * xacc[i] = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + { /* + * prod_hi = (data_key >> 32) * XXH_PRIME32_1; + * + * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will + * incorrectly "optimize" this: + * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b)); + * shifted = vshll_n_u32(tmp, 32); + * to this: + * tmp = "vmulq_u64"(a, b); // no such thing! + * shifted = vshlq_n_u64(tmp, 32); + * + * However, unlike SSE, Clang lacks a 64-bit multiply routine + * for NEON, and it scalarizes two 64-bit multiplies instead. + * + * vmull_u32 has the same timing as vmul_u32, and it avoids + * this bug completely. + * See https://bugs.llvm.org/show_bug.cgi?id=39967 + */ + uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime); + /* xacc[i] = prod_hi << 32; */ + xacc[i] = vshlq_n_u64(prod_hi, 32); + /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */ + xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime); + } + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } + } +} + +#endif + +#if (XXH_VECTOR == XXH_VSX) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* presumed aligned */ + unsigned int* const xacc = (unsigned int*) acc; + xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ + xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ + xxh_u64x2 const v32 = { 32, 32 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* data_vec = xinput[i]; */ + xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i); + /* key_vec = xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + /* shuffled = (data_key << 32) | (data_key >> 32); */ + xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); + /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ + xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); + /* acc_vec = xacc[i]; */ + xxh_u64x2 acc_vec = (xxh_u64x2)vec_xl(0, xacc + 4 * i); + acc_vec += product; + + /* swap high and low halves */ +#ifdef __s390x__ + acc_vec += vec_permi(data_vec, data_vec, 2); +#else + acc_vec += vec_xxpermdi(data_vec, data_vec, 2); +#endif + /* xacc[i] = acc_vec; */ + vec_xst((xxh_u32x4)acc_vec, 0, xacc + 4 * i); + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_u64x2* const xacc = (xxh_u64x2*) acc; + const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; + /* constants */ + xxh_u64x2 const v32 = { 32, 32 }; + xxh_u64x2 const v47 = { 47, 47 }; + xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + xxh_u64x2 const acc_vec = xacc[i]; + xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + + /* xacc[i] ^= xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + + /* xacc[i] *= XXH_PRIME32_1 */ + /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ + xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); + /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ + xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } } +} + +#endif + +/* scalar variants - universal */ + +/*! + * @internal + * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* xacc = (xxh_u64*) acc; + xxh_u8 const* xinput = (xxh_u8 const*) input; + xxh_u8 const* xsecret = (xxh_u8 const*) secret; + XXH_ASSERT(lane < XXH_ACC_NB); + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + { + xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); + xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ + xacc[lane] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); + } +} + +/*! + * @internal + * @brief Processes a 64 byte block of data using the scalar path. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } +} + +/*! + * @internal + * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + XXH_ASSERT(lane < XXH_ACC_NB); + { + xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); + xxh_u64 acc64 = xacc[lane]; + acc64 = XXH_xorshift64(acc64, 47); + acc64 ^= key64; + acc64 *= XXH_PRIME32_1; + xacc[lane] = acc64; + } +} + +/*! + * @internal + * @brief Scrambles the accumulators after a large chunk has been read + */ +XXH_FORCE_INLINE void +XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } +} + +XXH_FORCE_INLINE void +XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + /* + * We need a separate pointer for the hack below, + * which requires a non-const pointer. + * Any decent compiler will optimize this out otherwise. + */ + const xxh_u8* kSecretPtr = XXH3_kSecret; + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + +#if defined(__clang__) && defined(__aarch64__) + /* + * UGLY HACK: + * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are + * placed sequentially, in order, at the top of the unrolled loop. + * + * While MOVK is great for generating constants (2 cycles for a 64-bit + * constant compared to 4 cycles for LDR), it fights for bandwidth with + * the arithmetic instructions. + * + * I L S + * MOVK + * MOVK + * MOVK + * MOVK + * ADD + * SUB STR + * STR + * By forcing loads from memory (as the asm line causes Clang to assume + * that XXH3_kSecretPtr has been changed), the pipelines are used more + * efficiently: + * I L S + * LDR + * ADD LDR + * SUB STR + * STR + * + * See XXH3_NEON_LANES for details on the pipsline. + * + * XXH3_64bits_withSeed, len == 256, Snapdragon 835 + * without hack: 2654.4 MB/s + * with hack: 3202.9 MB/s + */ + XXH_COMPILER_GUARD(kSecretPtr); +#endif + /* + * Note: in debug mode, this overrides the asm optimization + * and Clang will emit MOVK chains again. + */ + XXH_ASSERT(kSecretPtr == XXH3_kSecret); + + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + for (i=0; i < nbRounds; i++) { + /* + * The asm hack causes Clang to assume that kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; + xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; + XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); + XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); + } } +} + + +typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*); +typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); +typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); + + +#if (XXH_VECTOR == XXH_AVX512) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 + +#elif (XXH_VECTOR == XXH_AVX2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 + +#elif (XXH_VECTOR == XXH_SSE2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 + +#elif (XXH_VECTOR == XXH_NEON) + +#define XXH3_accumulate_512 XXH3_accumulate_512_neon +#define XXH3_scrambleAcc XXH3_scrambleAcc_neon +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_VSX) + +#define XXH3_accumulate_512 XXH3_accumulate_512_vsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#else /* scalar */ + +#define XXH3_accumulate_512 XXH3_accumulate_512_scalar +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#endif + + + +#ifndef XXH_PREFETCH_DIST +# ifdef __clang__ +# define XXH_PREFETCH_DIST 320 +# else +# if (XXH_VECTOR == XXH_AVX512) +# define XXH_PREFETCH_DIST 512 +# else +# define XXH_PREFETCH_DIST 384 +# endif +# endif /* __clang__ */ +#endif /* XXH_PREFETCH_DIST */ + +/* + * XXH3_accumulate() + * Loops over XXH3_accumulate_512(). + * Assumption: nbStripes will not overflow the secret size + */ +XXH_FORCE_INLINE void +XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes, + XXH3_f_accumulate_512 f_acc512) +{ + size_t n; + for (n = 0; n < nbStripes; n++ ) { + const xxh_u8* const in = input + n*XXH_STRIPE_LEN; + XXH_PREFETCH(in + XXH_PREFETCH_DIST); + f_acc512(acc, + in, + secret + n*XXH_SECRET_CONSUME_RATE); + } +} + +XXH_FORCE_INLINE void +XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; + size_t const nb_blocks = (len - 1) / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > XXH_STRIPE_LEN); + { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512); + + /* last stripe */ + { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ + f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + size_t i = 0; + + for (i = 0; i < 4; i++) { + result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); +#if defined(__clang__) /* Clang */ \ + && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Prevent autovectorization on Clang ARMv7-a. Exact same problem as + * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. + * XXH3_64bits, len == 256, Snapdragon 835: + * without hack: 2063.7 MB/s + * with hack: 2560.7 MB/s + */ + XXH_COMPILER_GUARD(result64); +#endif + } + + return XXH3_avalanche(result64); +} + +#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ + XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, + const void* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + /* do not align on 8, so that the secret is different from the accumulator */ +#define XXH_SECRET_MERGEACCS_START 11 + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); +} + +/* + * It's important for performance to transmit secret's size (when it's static) + * so that the compiler can properly optimize the vectorized loop. + * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's preferable for performance that XXH3_hashLong is not inlined, + * as it results in a smaller function for small data, easier to the instruction cache. + * Note that inside this no_inline function, we do inline the internal loop, + * and provide a statically defined secret size to allow optimization of vector loop. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * XXH3_hashLong_64b_withSeed(): + * Generate a custom key based on alteration of default XXH3_kSecret with the seed, + * and then use this key for long mode hashing. + * + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + * + * It's important for performance that XXH3_hashLong is not inlined. Not sure + * why (uop cache maybe?), but the difference is large and easily measurable. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, + XXH64_hash_t seed, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed == 0) + return XXH3_hashLong_64b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed); + return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed(const void* input, size_t len, + XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_64b_withSeed_internal(input, len, seed, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + + +typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong64_f f_hashLong) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secretLen` condition is not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + * Also, note that function signature doesn't offer room to return an error. + */ + if (len <= 16) + return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); +} + + +/* === Public entry point === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) +{ + return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_64b_withSecret(input, len, seed, (const xxh_u8*)secret, secretSize); +} + + +/* === XXH3 streaming === */ + +/* + * Malloc's a pointer that is always aligned to align. + * + * This must be freed with `XXH_alignedFree()`. + * + * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte + * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 + * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. + * + * This underalignment previously caused a rather obvious crash which went + * completely unnoticed due to XXH3_createState() not actually being tested. + * Credit to RedSpah for noticing this bug. + * + * The alignment is done manually: Functions like posix_memalign or _mm_malloc + * are avoided: To maintain portability, we would have to write a fallback + * like this anyways, and besides, testing for the existence of library + * functions without relying on external build tools is impossible. + * + * The method is simple: Overallocate, manually align, and store the offset + * to the original behind the returned pointer. + * + * Align must be a power of 2 and 8 <= align <= 128. + */ +static void* XXH_alignedMalloc(size_t s, size_t align) +{ + XXH_ASSERT(align <= 128 && align >= 8); /* range check */ + XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ + XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ + { /* Overallocate to make room for manual realignment and an offset byte */ + xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); + if (base != NULL) { + /* + * Get the offset needed to align this pointer. + * + * Even if the returned pointer is aligned, there will always be + * at least one byte to store the offset to the original pointer. + */ + size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ + /* Add the offset for the now-aligned pointer */ + xxh_u8* ptr = base + offset; + + XXH_ASSERT((size_t)ptr % align == 0); + + /* Store the offset immediately before the returned pointer. */ + ptr[-1] = (xxh_u8)offset; + return ptr; + } + return NULL; + } +} +/* + * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass + * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. + */ +static void XXH_alignedFree(void* p) +{ + if (p != NULL) { + xxh_u8* ptr = (xxh_u8*)p; + /* Get the offset byte we added in XXH_malloc. */ + xxh_u8 offset = ptr[-1]; + /* Free the original malloc'd pointer */ + xxh_u8* base = ptr - offset; + XXH_free(base); + } +} +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); + if (state==NULL) return NULL; + XXH3_INITSTATE(state); + return state; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_alignedFree(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) +{ + XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + size_t const initStart = offsetof(XXH3_state_t, bufferedSize); + size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; + XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); + XXH_ASSERT(statePtr != NULL); + /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ + memset((char*)statePtr + initStart, 0, initLength); + statePtr->acc[0] = XXH_PRIME32_3; + statePtr->acc[1] = XXH_PRIME64_1; + statePtr->acc[2] = XXH_PRIME64_2; + statePtr->acc[3] = XXH_PRIME64_3; + statePtr->acc[4] = XXH_PRIME64_4; + statePtr->acc[5] = XXH_PRIME32_2; + statePtr->acc[6] = XXH_PRIME64_5; + statePtr->acc[7] = XXH_PRIME32_1; + statePtr->seed = seed; + statePtr->useSeed = (seed != 0); + statePtr->extSecret = (const unsigned char*)secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_64bits_reset(statePtr); + if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) + XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed64) +{ + if (statePtr == NULL) return XXH_ERROR; + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + XXH3_reset_internal(statePtr, seed64, secret, secretSize); + statePtr->useSeed = 1; /* always, even if seed64==0 */ + return XXH_OK; +} + +/* Note : when XXH3_consumeStripes() is invoked, + * there must be a guarantee that at least one more byte must be consumed from input + * so that the function can blindly consume all stripes using the "normal" secret segment */ +XXH_FORCE_INLINE void +XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, + size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, + const xxh_u8* XXH_RESTRICT input, size_t nbStripes, + const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ + XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); + if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { + /* need a scrambling operation */ + size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; + size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); + f_scramble(acc, secret + secretLimit); + XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); + *nbStripesSoFarPtr = nbStripesAfterBlock; + } else { + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); + *nbStripesSoFarPtr += nbStripes; + } +} + +#ifndef XXH3_STREAM_USE_STACK +# ifndef __clang__ /* clang doesn't need additional stack space */ +# define XXH3_STREAM_USE_STACK 1 +# endif +#endif +/* + * Both XXH3_64bits_update and XXH3_128bits_update use this routine. + */ +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* XXH_RESTRICT const state, + const xxh_u8* XXH_RESTRICT input, size_t len, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + XXH_ASSERT(state != NULL); + { const xxh_u8* const bEnd = input + len; + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* For some reason, gcc and MSVC seem to suffer greatly + * when operating accumulators directly into state. + * Operating into stack space seems to enable proper optimization. + * clang, on the other hand, doesn't seem to need this trick */ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; memcpy(acc, state->acc, sizeof(acc)); +#else + xxh_u64* XXH_RESTRICT const acc = state->acc; +#endif + state->totalLen += len; + XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); + + /* small input : just fill in tmp buffer */ + if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + + /* total input is now > XXH3_INTERNALBUFFER_SIZE */ + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ + + /* + * Internal buffer is partially filled (always, except at beginning) + * Complete it, then consume it. + */ + if (state->bufferedSize) { + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + state->bufferedSize = 0; + } + XXH_ASSERT(input < bEnd); + + /* large input to consume : ingest per full block */ + if ((size_t)(bEnd - input) > state->nbStripesPerBlock * XXH_STRIPE_LEN) { + size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; + XXH_ASSERT(state->nbStripesPerBlock >= state->nbStripesSoFar); + /* join to current block's end */ + { size_t const nbStripesToEnd = state->nbStripesPerBlock - state->nbStripesSoFar; + XXH_ASSERT(nbStripesToEnd <= nbStripes); + XXH3_accumulate(acc, input, secret + state->nbStripesSoFar * XXH_SECRET_CONSUME_RATE, nbStripesToEnd, f_acc512); + f_scramble(acc, secret + state->secretLimit); + state->nbStripesSoFar = 0; + input += nbStripesToEnd * XXH_STRIPE_LEN; + nbStripes -= nbStripesToEnd; + } + /* consume per entire blocks */ + while(nbStripes >= state->nbStripesPerBlock) { + XXH3_accumulate(acc, input, secret, state->nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + state->secretLimit); + input += state->nbStripesPerBlock * XXH_STRIPE_LEN; + nbStripes -= state->nbStripesPerBlock; + } + /* consume last partial block */ + XXH3_accumulate(acc, input, secret, nbStripes, f_acc512); + input += nbStripes * XXH_STRIPE_LEN; + XXH_ASSERT(input < bEnd); /* at least some bytes left */ + state->nbStripesSoFar = nbStripes; + /* buffer predecessor of last partial stripe */ + XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + XXH_ASSERT(bEnd - input <= XXH_STRIPE_LEN); + } else { + /* content to consume <= block size */ + /* Consume input by a multiple of internal buffer size */ + if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { + const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; + do { + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + input += XXH3_INTERNALBUFFER_SIZE; + } while (inputbuffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + } + } + + /* Some remaining input (always) : buffer it */ + XXH_ASSERT(input < bEnd); + XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); + XXH_ASSERT(state->bufferedSize == 0); + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* save stack accumulators into state */ + memcpy(state->acc, acc, sizeof(acc)); +#endif + } + + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, + const XXH3_state_t* state, + const unsigned char* secret) +{ + /* + * Digest on a local copy. This way, the state remains unaltered, and it can + * continue ingesting more input afterwards. + */ + XXH_memcpy(acc, state->acc, sizeof(state->acc)); + if (state->bufferedSize >= XXH_STRIPE_LEN) { + size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; + size_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, nbStripes, + secret, state->secretLimit, + XXH3_accumulate_512, XXH3_scrambleAcc); + /* last stripe */ + XXH3_accumulate_512(acc, + state->buffer + state->bufferedSize - XXH_STRIPE_LEN, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } else { /* bufferedSize < XXH_STRIPE_LEN */ + xxh_u8 lastStripe[XXH_STRIPE_LEN]; + size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; + XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ + XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + XXH3_accumulate_512(acc, + lastStripe, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + return XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + } + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if (state->useSeed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + + + +/* ========================================== + * XXH3 128 bits (a.k.a XXH128) + * ========================================== + * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, + * even without counting the significantly larger output size. + * + * For example, extra steps are taken to avoid the seed-dependent collisions + * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). + * + * This strength naturally comes at the cost of some speed, especially on short + * lengths. Note that longer hashes are about as fast as the 64-bit version + * due to it using only a slight modification of the 64-bit loop. + * + * XXH128 is also more oriented towards 64-bit machines. It is still extremely + * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). + */ + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + /* A doubled version of 1to3_64b with different constants. */ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } + * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } + * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); + xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; + XXH128_hash_t h128; + h128.low64 = XXH64_avalanche(keyed_lo); + h128.high64 = XXH64_avalanche(keyed_hi); + return h128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; + xxh_u64 const keyed = input_64 ^ bitflip; + + /* Shift len to the left to ensure it is even, this avoids even multiplies. */ + XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); + + m128.high64 += (m128.low64 << 1); + m128.low64 ^= (m128.high64 >> 3); + + m128.low64 = XXH_xorshift64(m128.low64, 35); + m128.low64 *= 0x9FB21C651E98DF25ULL; + m128.low64 = XXH_xorshift64(m128.low64, 28); + m128.high64 = XXH3_avalanche(m128.high64); + return m128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; + xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 input_hi = XXH_readLE64(input + len - 8); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); + /* + * Put len in the middle of m128 to ensure that the length gets mixed to + * both the low and high bits in the 128x64 multiply below. + */ + m128.low64 += (xxh_u64)(len - 1) << 54; + input_hi ^= bitfliph; + /* + * Add the high 32 bits of input_hi to the high 32 bits of m128, then + * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to + * the high 64 bits of m128. + * + * The best approach to this operation is different on 32-bit and 64-bit. + */ + if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ + /* + * 32-bit optimized version, which is more readable. + * + * On 32-bit, it removes an ADC and delays a dependency between the two + * halves of m128.high64, but it generates an extra mask on 64-bit. + */ + m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); + } else { + /* + * 64-bit optimized (albeit more confusing) version. + * + * Uses some properties of addition and multiplication to remove the mask: + * + * Let: + * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) + * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) + * c = XXH_PRIME32_2 + * + * a + (b * c) + * Inverse Property: x + y - x == y + * a + (b * (1 + c - 1)) + * Distributive Property: x * (y + z) == (x * y) + (x * z) + * a + (b * 1) + (b * (c - 1)) + * Identity Property: x * 1 == x + * a + b + (b * (c - 1)) + * + * Substitute a, b, and c: + * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + * + * Since input_hi.hi + input_hi.lo == input_hi, we get this: + * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + */ + m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); + } + /* m128 ^= XXH_swap64(m128 >> 64); */ + m128.low64 ^= XXH_swap64(m128.high64); + + { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ + XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); + h128.high64 += m128.high64 * XXH_PRIME64_2; + + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* + * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t h128; + xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); + xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); + h128.low64 = XXH64_avalanche(seed ^ bitflipl); + h128.high64 = XXH64_avalanche( seed ^ bitfliph); + return h128; + } } +} + +/* + * A bit slower than XXH3_mix16B, but handles multiply by zero better. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, + const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_NO_INLINE XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + int const nbRounds = (int)len / 32; + int i; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + for (i=0; i<4; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + (32 * i), + seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + XXH_ASSERT(nbRounds >= 4); + for (i=4 ; i < nbRounds; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), + seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, + input + len - 16, + input + len - 32, + secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, + 0ULL - seed); + + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)len * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + secretSize + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)len * XXH_PRIME64_2)); + return h128; + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance to pass @secretLen (when it's static) + * to the compiler, so that it can properly optimize the vectorized loop. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed64 == 0) + return XXH3_hashLong_128b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed64); + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + +typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const void* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_128bits_internal(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong128_f f_hl128) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secret` conditions are not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + */ + if (len <= 16) + return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hl128(input, len, seed64, secret, secretLen); +} + + +/* === Public XXH128 API === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) +{ + return XXH3_128bits_internal(input, len, 0, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_128bits_internal(input, len, 0, + (const xxh_u8*)secret, secretSize, + XXH3_hashLong_128b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_internal(input, len, seed, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_withSeed); +} + +/*! @ingroup xxh3_family */ +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) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ + +/* + * All initialization and update functions are identical to 64-bit streaming variant. + * The only difference is the finalization routine. + */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH3_state_t* statePtr) +{ + return XXH3_64bits_reset(statePtr); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSeed(statePtr, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + state->secretLimit + XXH_STRIPE_LEN + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); + return h128; + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + +/* 128-bit utility functions */ + +#include /* memcmp, memcpy */ + +/* return : 1 is equal, 0 if different */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); + XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + + + +/* ========================================== + * Secret generators + * ========================================== + */ +#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) +{ + XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); + XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize) +{ +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(secretBuffer != NULL); + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); +#else + /* production mode, assert() are disabled */ + if (secretBuffer == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; +#endif + + if (customSeedSize == 0) { + customSeed = XXH3_kSecret; + customSeedSize = XXH_SECRET_DEFAULT_SIZE; + } +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(customSeed != NULL); +#else + if (customSeed == NULL) return XXH_ERROR; +#endif + + /* Fill secretBuffer with a copy of customSeed - repeat as needed */ + { size_t pos = 0; + while (pos < secretSize) { + size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); + memcpy((char*)secretBuffer + pos, customSeed, toCopy); + pos += toCopy; + } } + + { size_t const nbSeg16 = secretSize / 16; + size_t n; + XXH128_canonical_t scrambler; + XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); + for (n=0; n /* malloc, calloc, free */ -#include /* memset */ +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */ #include "error_private.h" #include "zstd_internal.h" @@ -53,31 +53,31 @@ const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString /*=************************************************************** * Custom allocator ****************************************************************/ -void* ZSTD_malloc(size_t size, ZSTD_customMem customMem) +void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem) { if (customMem.customAlloc) return customMem.customAlloc(customMem.opaque, size); - return malloc(size); + return ZSTD_malloc(size); } -void* ZSTD_calloc(size_t size, ZSTD_customMem customMem) +void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem) { if (customMem.customAlloc) { /* calloc implemented as malloc+memset; * not as efficient as calloc, but next best guess for custom malloc */ void* const ptr = customMem.customAlloc(customMem.opaque, size); - memset(ptr, 0, size); + ZSTD_memset(ptr, 0, size); return ptr; } - return calloc(1, size); + return ZSTD_calloc(1, size); } -void ZSTD_free(void* ptr, ZSTD_customMem customMem) +void ZSTD_customFree(void* ptr, ZSTD_customMem customMem) { if (ptr!=NULL) { if (customMem.customFree) customMem.customFree(customMem.opaque, ptr); else - free(ptr); + ZSTD_free(ptr); } } diff --git a/native/zstd/common/zstd_deps.h b/native/zstd/common/zstd_deps.h new file mode 100644 index 0000000..1421134 --- /dev/null +++ b/native/zstd/common/zstd_deps.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) Facebook, Inc. + * 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. + */ + +/* This file provides common libc dependencies that zstd requires. + * The purpose is to allow replacing this file with a custom implementation + * to compile zstd without libc support. + */ + +/* Need: + * NULL + * INT_MAX + * UINT_MAX + * ZSTD_memcpy() + * ZSTD_memset() + * ZSTD_memmove() + */ +#ifndef ZSTD_DEPS_COMMON +#define ZSTD_DEPS_COMMON + +#include +#include +#include + +#if defined(__GNUC__) && __GNUC__ >= 4 +# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) +#else +# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) memset((p),(v),(l)) +#endif + +#endif /* ZSTD_DEPS_COMMON */ + +/* Need: + * ZSTD_malloc() + * ZSTD_free() + * ZSTD_calloc() + */ +#ifdef ZSTD_DEPS_NEED_MALLOC +#ifndef ZSTD_DEPS_MALLOC +#define ZSTD_DEPS_MALLOC + +#include + +#define ZSTD_malloc(s) malloc(s) +#define ZSTD_calloc(n,s) calloc((n), (s)) +#define ZSTD_free(p) free((p)) + +#endif /* ZSTD_DEPS_MALLOC */ +#endif /* ZSTD_DEPS_NEED_MALLOC */ + +/* + * Provides 64-bit math support. + * Need: + * U64 ZSTD_div64(U64 dividend, U32 divisor) + */ +#ifdef ZSTD_DEPS_NEED_MATH64 +#ifndef ZSTD_DEPS_MATH64 +#define ZSTD_DEPS_MATH64 + +#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) + +#endif /* ZSTD_DEPS_MATH64 */ +#endif /* ZSTD_DEPS_NEED_MATH64 */ + +/* Need: + * assert() + */ +#ifdef ZSTD_DEPS_NEED_ASSERT +#ifndef ZSTD_DEPS_ASSERT +#define ZSTD_DEPS_ASSERT + +#include + +#endif /* ZSTD_DEPS_ASSERT */ +#endif /* ZSTD_DEPS_NEED_ASSERT */ + +/* Need: + * ZSTD_DEBUG_PRINT() + */ +#ifdef ZSTD_DEPS_NEED_IO +#ifndef ZSTD_DEPS_IO +#define ZSTD_DEPS_IO + +#include +#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) + +#endif /* ZSTD_DEPS_IO */ +#endif /* ZSTD_DEPS_NEED_IO */ + +/* Only requested when is known to be present. + * Need: + * intptr_t + */ +#ifdef ZSTD_DEPS_NEED_STDINT +#ifndef ZSTD_DEPS_STDINT +#define ZSTD_DEPS_STDINT + +#include + +#endif /* ZSTD_DEPS_STDINT */ +#endif /* ZSTD_DEPS_NEED_STDINT */ diff --git a/native/zstd/common/zstd_internal.h b/native/zstd/common/zstd_internal.h old mode 100755 new mode 100644 index dcdcbdb..e892267 --- a/native/zstd/common/zstd_internal.h +++ b/native/zstd/common/zstd_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,11 +20,12 @@ * Dependencies ***************************************/ #include "compiler.h" +#include "cpu.h" #include "mem.h" #include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ #include "error_private.h" #define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" +#include "../zstd.h" #define FSE_STATIC_LINKING_ONLY #include "fse.h" #define HUF_STATIC_LINKING_ONLY @@ -33,6 +34,11 @@ # define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ #endif #include "xxhash.h" /* XXH_reset, update, digest */ +#ifndef ZSTD_NO_TRACE +# include "zstd_trace.h" +#else +# define ZSTD_TRACE 0 +#endif #if defined (__cplusplus) extern "C" { @@ -52,50 +58,7 @@ extern "C" { #undef MAX #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) - -/** - * Return the specified error if the condition evaluates to true. - * - * In debug modes, prints additional information. - * In order to do that (particularly, printing the conditional that failed), - * this can't just wrap RETURN_ERROR(). - */ -#define RETURN_ERROR_IF(cond, err, ...) \ - if (cond) { \ - RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", __FILE__, __LINE__, ZSTD_QUOTE(cond), ZSTD_QUOTE(ERROR(err))); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } - -/** - * Unconditionally return the specified error. - * - * In debug modes, prints additional information. - */ -#define RETURN_ERROR(err, ...) \ - do { \ - RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", __FILE__, __LINE__, ZSTD_QUOTE(ERROR(err))); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } while(0); - -/** - * If the provided expression evaluates to an error code, returns that error code. - * - * In debug modes, prints additional information. - */ -#define FORWARD_IF_ERROR(err, ...) \ - do { \ - size_t const err_code = (err); \ - if (ERR_isError(err_code)) { \ - RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", __FILE__, __LINE__, ZSTD_QUOTE(err), ERR_getErrorName(err_code)); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return err_code; \ - } \ - } while(0); +#define BOUNDED(min,val,max) (MAX(min,MIN(val,max))) /*-************************************* @@ -104,8 +67,7 @@ extern "C" { #define ZSTD_OPT_NUM (1<<12) #define ZSTD_REP_NUM 3 /* number of repcodes */ -#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1) -static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; +static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; #define KB *(1 <<10) #define MB *(1 <<20) @@ -119,19 +81,20 @@ static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; #define BIT0 1 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 -static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; -static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; +static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; +static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; #define ZSTD_FRAMEIDSIZE 4 /* magic number size */ #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ -static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; +static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; +#define ZSTD_FRAMECHECKSUMSIZE 4 + #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ -#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */) /* for a non-null block */ -#define HufLog 12 typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; #define LONGNBSEQ 0x7F00 @@ -139,6 +102,7 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy #define MINMATCH 3 #define Litbits 8 +#define LitHufLog 11 #define MaxLit ((1<= 8 || (ovtype == ZSTD_no_overlap && diff <= -WILDCOPY_VECLEN)); - if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) { /* Handle short offset copies. */ do { @@ -230,15 +229,16 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e } while (op < oend); } else { assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); - /* Separate out the first two COPY16() calls because the copy length is + /* Separate out the first COPY16() call because the copy length is * almost certain to be short, so the branches have different - * probabilities. - * On gcc-9 unrolling once is +1.6%, twice is +2%, thrice is +1.8%. - * On clang-8 unrolling once is +1.4%, twice is +3.3%, thrice is +3%. + * probabilities. Since it is almost certain to be short, only do + * one COPY16() in the first call. Then, do two calls per loop since + * at that point it is more likely to have a high trip count. */ - COPY16(op, ip); - COPY16(op, ip); - if (op >= oend) return; + ZSTD_copy16(op, ip); + if (16 >= length) return; + op += 16; + ip += 16; do { COPY16(op, ip); COPY16(op, ip); @@ -247,30 +247,92 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e } } +MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + size_t const length = MIN(dstCapacity, srcSize); + if (length > 0) { + ZSTD_memcpy(dst, src, length); + } + return length; +} + +/* define "workspace is too large" as this number of times larger than needed */ +#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 + +/* when workspace is continuously too large + * during at least this number of times, + * context's memory usage is considered wasteful, + * because it's sized to handle a worst case scenario which rarely happens. + * In which case, resize it down to free some memory */ +#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 + +/* Controls whether the input/output buffer is buffered or stable. */ +typedef enum { + ZSTD_bm_buffered = 0, /* Buffer the input/output */ + ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */ +} ZSTD_bufferMode_e; + /*-******************************************* * Private declarations *********************************************/ typedef struct seqDef_s { - U32 offset; + U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */ U16 litLength; - U16 matchLength; + U16 mlBase; /* mlBase == matchLength - MINMATCH */ } seqDef; +/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */ +typedef enum { + ZSTD_llt_none = 0, /* no longLengthType */ + ZSTD_llt_literalLength = 1, /* represents a long literal */ + ZSTD_llt_matchLength = 2 /* represents a long match */ +} ZSTD_longLengthType_e; + typedef struct { seqDef* sequencesStart; - seqDef* sequences; - BYTE* litStart; - BYTE* lit; - BYTE* llCode; - BYTE* mlCode; - BYTE* ofCode; + seqDef* sequences; /* ptr to end of sequences */ + BYTE* litStart; + BYTE* lit; /* ptr to end of literals */ + BYTE* llCode; + BYTE* mlCode; + BYTE* ofCode; size_t maxNbSeq; size_t maxNbLit; - U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */ - U32 longLengthPos; + + /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength + * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment + * the existing value of the litLength or matchLength by 0x10000. + */ + ZSTD_longLengthType_e longLengthType; + U32 longLengthPos; /* Index of the sequence to apply long length modification to */ } seqStore_t; +typedef struct { + U32 litLength; + U32 matchLength; +} ZSTD_sequenceLength; + +/** + * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences + * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength. + */ +MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq) +{ + ZSTD_sequenceLength seqLen; + seqLen.litLength = seq->litLength; + seqLen.matchLength = seq->mlBase + MINMATCH; + if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) { + if (seqStore->longLengthType == ZSTD_llt_literalLength) { + seqLen.litLength += 0x10000; + } + if (seqStore->longLengthType == ZSTD_llt_matchLength) { + seqLen.matchLength += 0x10000; + } + } + return seqLen; +} + /** * Contains the compressed frame size and an upper-bound for the decompressed frame size. * Note: before using `compressedSize`, check for errors using ZSTD_isError(). @@ -286,35 +348,9 @@ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBu void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ /* custom memory allocation functions */ -void* ZSTD_malloc(size_t size, ZSTD_customMem customMem); -void* ZSTD_calloc(size_t size, ZSTD_customMem customMem); -void ZSTD_free(void* ptr, ZSTD_customMem customMem); - - -MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ -{ - assert(val != 0); - { -# if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse(&r, val); - return (unsigned)r; -# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ - return __builtin_clz (val) ^ 31; -# elif defined(__ICCARM__) /* IAR Intrinsic */ - return 31 - __CLZ(val); -# else /* Software version */ - static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; - U32 v = val; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - return DeBruijnClz[(v * 0x07C4ACDDU) >> 27]; -# endif - } -} +void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem); +void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem); +void ZSTD_customFree(void* ptr, ZSTD_customMem customMem); /* ZSTD_invalidateRepCodes() : @@ -342,6 +378,14 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize); +/** + * @returns true iff the CPU supports dynamic BMI2 dispatch. + */ +MEM_STATIC int ZSTD_cpuSupportsBmi2(void) +{ + ZSTD_cpuid_t cpuid = ZSTD_cpuid(); + return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid); +} #if defined (__cplusplus) } diff --git a/native/zstd/common/zstd_trace.h b/native/zstd/common/zstd_trace.h new file mode 100644 index 0000000..6215f1e --- /dev/null +++ b/native/zstd/common/zstd_trace.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) Facebook, Inc. + * 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. + */ + +#ifndef ZSTD_TRACE_H +#define ZSTD_TRACE_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#include + +/* weak symbol support + * For now, enable conservatively: + * - Only GNUC + * - Only ELF + * - Only x86-64, i386 and aarch64 + * Also, explicitly disable on platforms known not to work so they aren't + * forgotten in the future. + */ +#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ + defined(__GNUC__) && defined(__ELF__) && \ + (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) || defined(__aarch64__)) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ + !defined(__CYGWIN__) && !defined(_AIX) +# define ZSTD_HAVE_WEAK_SYMBOLS 1 +#else +# define ZSTD_HAVE_WEAK_SYMBOLS 0 +#endif +#if ZSTD_HAVE_WEAK_SYMBOLS +# define ZSTD_WEAK_ATTR __attribute__((__weak__)) +#else +# define ZSTD_WEAK_ATTR +#endif + +/* Only enable tracing when weak symbols are available. */ +#ifndef ZSTD_TRACE +# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS +#endif + +#if ZSTD_TRACE + +struct ZSTD_CCtx_s; +struct ZSTD_DCtx_s; +struct ZSTD_CCtx_params_s; + +typedef struct { + /** + * ZSTD_VERSION_NUMBER + * + * This is guaranteed to be the first member of ZSTD_trace. + * Otherwise, this struct is not stable between versions. If + * the version number does not match your expectation, you + * should not interpret the rest of the struct. + */ + unsigned version; + /** + * Non-zero if streaming (de)compression is used. + */ + unsigned streaming; + /** + * The dictionary ID. + */ + unsigned dictionaryID; + /** + * Is the dictionary cold? + * Only set on decompression. + */ + unsigned dictionaryIsCold; + /** + * The dictionary size or zero if no dictionary. + */ + size_t dictionarySize; + /** + * The uncompressed size of the data. + */ + size_t uncompressedSize; + /** + * The compressed size of the data. + */ + size_t compressedSize; + /** + * The fully resolved CCtx parameters (NULL on decompression). + */ + struct ZSTD_CCtx_params_s const* params; + /** + * The ZSTD_CCtx pointer (NULL on decompression). + */ + struct ZSTD_CCtx_s const* cctx; + /** + * The ZSTD_DCtx pointer (NULL on compression). + */ + struct ZSTD_DCtx_s const* dctx; +} ZSTD_Trace; + +/** + * A tracing context. It must be 0 when tracing is disabled. + * Otherwise, any non-zero value returned by a tracing begin() + * function is presented to any subsequent calls to end(). + * + * Any non-zero value is treated as tracing is enabled and not + * interpreted by the library. + * + * Two possible uses are: + * * A timestamp for when the begin() function was called. + * * A unique key identifying the (de)compression, like the + * address of the [dc]ctx pointer if you need to track + * more information than just a timestamp. + */ +typedef unsigned long long ZSTD_TraceCtx; + +/** + * Trace the beginning of a compression call. + * @param cctx The dctx pointer for the compression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( + struct ZSTD_CCtx_s const* cctx); + +/** + * Trace the end of a compression call. + * @param ctx The return value of ZSTD_trace_compress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +/** + * Trace the beginning of a decompression call. + * @param dctx The dctx pointer for the decompression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( + struct ZSTD_DCtx_s const* dctx); + +/** + * Trace the end of a decompression call. + * @param ctx The return value of ZSTD_trace_decompress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +#endif /* ZSTD_TRACE */ + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_TRACE_H */ diff --git a/native/zstd/compress/clevels.h b/native/zstd/compress/clevels.h new file mode 100644 index 0000000..7ed2e00 --- /dev/null +++ b/native/zstd/compress/clevels.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * 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. + */ + +#ifndef ZSTD_CLEVELS_H +#define ZSTD_CLEVELS_H + +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ +#include "../zstd.h" + +/*-===== Pre-defined compression levels =====-*/ + +#define ZSTD_MAX_CLEVEL 22 + +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif + +static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { +{ /* "default" - for any srcSize > 256 KB */ + /* W, C, H, S, L, TL, strat */ + { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ + { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ + { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ + { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ + { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ + { 21, 18, 19, 3, 5, 2, ZSTD_greedy }, /* level 5 */ + { 21, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6 */ + { 21, 19, 20, 4, 5, 8, ZSTD_lazy }, /* level 7 */ + { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 8 */ + { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ + { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 10 */ + { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 11 */ + { 22, 22, 23, 6, 5, 32, ZSTD_lazy2 }, /* level 12 */ + { 22, 22, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ + { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ + { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ + { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ + { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ + { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ + { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ + { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ + { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ + { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ +}, +{ /* for srcSize <= 256 KB */ + /* W, C, H, S, L, T, strat */ + { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ + { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ + { 18, 16, 17, 3, 5, 2, ZSTD_greedy }, /* level 4.*/ + { 18, 17, 18, 5, 5, 2, ZSTD_greedy }, /* level 5.*/ + { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ + { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ + { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ + { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ + { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 128 KB */ + /* W, C, H, S, L, T, strat */ + { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ + { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ + { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ + { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ + { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 17, 16, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 17, 16, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 17, 16, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 17, 16, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ + { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ + { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ + { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ + { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ + { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 16 KB */ + /* W, C, H, S, L, T, strat */ + { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ + { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ + { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ + { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ + { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ + { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ + { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ + { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ + { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ + { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ + { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ + { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ + { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ + { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ + { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ + { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +}; + + + +#endif /* ZSTD_CLEVELS_H */ diff --git a/native/zstd/compress/fse_compress.c b/native/zstd/compress/fse_compress.c old mode 100755 new mode 100644 index 68b47e1..21be8c5 --- a/native/zstd/compress/fse_compress.c +++ b/native/zstd/compress/fse_compress.c @@ -1,50 +1,32 @@ /* ****************************************************************** - FSE : Finite State Entropy encoder - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c + * FSE : Finite State Entropy encoder + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * 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. ****************************************************************** */ /* ************************************************************** * Includes ****************************************************************/ -#include /* malloc, free, qsort */ -#include /* memcpy, memset */ -#include "compiler.h" -#include "mem.h" /* U32, U16, etc. */ -#include "debug.h" /* assert, DEBUGLOG */ +#include "../common/compiler.h" +#include "../common/mem.h" /* U32, U16, etc. */ +#include "../common/debug.h" /* assert, DEBUGLOG */ #include "hist.h" /* HIST_count_wksp */ -#include "bitstream.h" +#include "../common/bitstream.h" #define FSE_STATIC_LINKING_ONLY -#include "fse.h" -#include "error_private.h" +#include "../common/fse.h" +#include "../common/error_private.h" +#define ZSTD_DEPS_NEED_MALLOC +#define ZSTD_DEPS_NEED_MATH64 +#include "../common/zstd_deps.h" /* ZSTD_malloc, ZSTD_free, ZSTD_memcpy, ZSTD_memset */ +#include "../common/bits.h" /* ZSTD_highbit32 */ /* ************************************************************** @@ -94,13 +76,16 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ; FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); U32 const step = FSE_TABLESTEP(tableSize); - U32 cumul[FSE_MAX_SYMBOL_VALUE+2]; + U32 const maxSV1 = maxSymbolValue+1; + + U16* cumul = (U16*)workSpace; /* size = maxSV1 */ + FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)(cumul + (maxSV1+1)); /* size = tableSize */ - FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace; U32 highThreshold = tableSize-1; + assert(((size_t)workSpace & 1) == 0); /* Must be 2 bytes-aligned */ + if (FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) > wkspSize) return ERROR(tableLog_tooLarge); /* CTable header */ - if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge); tableU16[-2] = (U16) tableLog; tableU16[-1] = (U16) maxSymbolValue; assert(tableLog < 16); /* required for threshold strategy to work */ @@ -109,26 +94,67 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ #ifdef __clang_analyzer__ - memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ + ZSTD_memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ #endif /* symbol start positions */ { U32 u; cumul[0] = 0; - for (u=1; u <= maxSymbolValue+1; u++) { + for (u=1; u <= maxSV1; u++) { if (normalizedCounter[u-1]==-1) { /* Low proba symbol */ cumul[u] = cumul[u-1] + 1; tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1); } else { - cumul[u] = cumul[u-1] + normalizedCounter[u-1]; + assert(normalizedCounter[u-1] >= 0); + cumul[u] = cumul[u-1] + (U16)normalizedCounter[u-1]; + assert(cumul[u] >= cumul[u-1]); /* no overflow */ } } - cumul[maxSymbolValue+1] = tableSize+1; + cumul[maxSV1] = (U16)(tableSize+1); } /* Spread symbols */ - { U32 position = 0; + if (highThreshold == tableSize - 1) { + /* Case for no low prob count symbols. Lay down 8 bytes at a time + * to reduce branch misses since we are operating on a small block + */ + BYTE* const spread = tableSymbol + tableSize; /* size = tableSize + 8 (may write beyond tableSize) */ + { U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s=0); + pos += (size_t)n; + } + } + /* Spread symbols across the table. Lack of lowprob symbols means that + * we don't need variable sized inner loop, so we can unroll the loop and + * reduce branch misses. + */ + { size_t position = 0; + size_t s; + size_t const unroll = 2; /* Experimentally determined optimal unroll */ + assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ + for (s = 0; s < (size_t)tableSize; s += unroll) { + size_t u; + for (u = 0; u < unroll; ++u) { + size_t const uPosition = (position + (u * step)) & tableMask; + tableSymbol[uPosition] = spread[s + u]; + } + position = (position + (unroll * step)) & tableMask; + } + assert(position == 0); /* Must have initialized all positions */ + } + } else { + U32 position = 0; U32 symbol; - for (symbol=0; symbol<=maxSymbolValue; symbol++) { + for (symbol=0; symbol highThreshold) position = (position + step) & tableMask; /* Low proba area */ } } - assert(position==0); /* Must have initialized all positions */ } @@ -161,16 +186,17 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, case -1: case 1: symbolTT[s].deltaNbBits = (tableLog << 16) - (1< 1); + { U32 const maxBitsOut = tableLog - ZSTD_highbit32 ((U32)normalizedCounter[s]-1); + U32 const minStatePlus = (U32)normalizedCounter[s] << maxBitsOut; symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus; - symbolTT[s].deltaFindState = total - normalizedCounter[s]; - total += normalizedCounter[s]; + symbolTT[s].deltaFindState = (int)(total - (unsigned)normalizedCounter[s]); + total += (unsigned)normalizedCounter[s]; } } } } #if 0 /* debug : symbol costs */ @@ -181,31 +207,26 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, symbol, normalizedCounter[symbol], FSE_getMaxNbBits(symbolTT, symbol), (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256); - } - } + } } #endif return 0; } -size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) -{ - FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */ - return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol)); -} - - #ifndef FSE_COMMONDEFS_ONLY - /*-************************************************************** * FSE NCount encoding ****************************************************************/ size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog) { - size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3; + size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog + + 4 /* bitCount initialized at 4 */ + + 2 /* first two symbols may use one additional bit each */) / 8) + + 1 /* round up to whole nb bytes */ + + 2 /* additional two bytes for bitstream flush */; return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */ } @@ -327,16 +348,16 @@ FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog) size_t size; if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32); - return (FSE_CTable*)malloc(size); + return (FSE_CTable*)ZSTD_malloc(size); } -void FSE_freeCTable (FSE_CTable* ct) { free(ct); } +void FSE_freeCTable (FSE_CTable* ct) { ZSTD_free(ct); } /* provides the minimum logSize to safely represent a distribution */ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) { - U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1; - U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2; + U32 minBitsSrc = ZSTD_highbit32((U32)(srcSize)) + 1; + U32 minBitsSymbols = ZSTD_highbit32(maxSymbolValue) + 2; U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols; assert(srcSize > 1); /* Not supported, RLE should be used instead */ return minBits; @@ -344,7 +365,7 @@ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus) { - U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus; + U32 maxBitsSrc = ZSTD_highbit32((U32)(srcSize - 1)) - minus; U32 tableLog = maxTableLog; U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue); assert(srcSize > 1); /* Not supported, RLE should be used instead */ @@ -361,11 +382,10 @@ unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2); } - /* Secondary normalization method. To be used when primary method fails. */ -static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue) +static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue, short lowProbCount) { short const NOT_YET_ASSIGNED = -2; U32 s; @@ -382,7 +402,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, continue; } if (count[s] <= lowThreshold) { - norm[s] = -1; + norm[s] = lowProbCount; distributed++; total -= count[s]; continue; @@ -434,7 +454,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, { U64 const vStepLog = 62 - tableLog; U64 const mid = (1ULL << (vStepLog-1)) - 1; - U64 const rStep = ((((U64)1<> scale); @@ -490,7 +510,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, } } if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) { /* corner case, need another normalization method */ - size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue); + size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue, lowProbCount); if (FSE_isError(errorCode)) return errorCode; } else normalizedCounter[largest] += (short)stillToDistribute; @@ -645,9 +665,7 @@ size_t FSE_compress_usingCTable (void* dst, size_t dstSize, size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); } -#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e -#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } - +#ifndef ZSTD_NO_UNUSED_FUNCTIONS /* FSE_compress_wksp() : * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`). * `wkspSize` size must be `(1<= 2048) ); /* Write table description header */ { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) ); @@ -701,13 +719,16 @@ size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t src typedef struct { FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)]; - BYTE scratchBuffer[1 << FSE_MAX_TABLELOG]; + union { + U32 hist_wksp[HIST_WKSP_SIZE_U32]; + BYTE scratchBuffer[1 << FSE_MAX_TABLELOG]; + } workspace; } fseWkspMax_t; size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog) { fseWkspMax_t scratchBuffer; - DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */ + DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_COMPRESS_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer)); } @@ -716,6 +737,6 @@ size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcS { return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG); } - +#endif #endif /* FSE_COMMONDEFS_ONLY */ diff --git a/native/zstd/compress/hist.c b/native/zstd/compress/hist.c old mode 100755 new mode 100644 index 45b7bab..073c57e --- a/native/zstd/compress/hist.c +++ b/native/zstd/compress/hist.c @@ -1,42 +1,22 @@ /* ****************************************************************** - hist : Histogram functions - part of Finite State Entropy project - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c + * hist : Histogram functions + * part of Finite State Entropy project + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * 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. ****************************************************************** */ /* --- dependencies --- */ -#include "mem.h" /* U32, BYTE, etc. */ -#include "debug.h" /* assert, DEBUGLOG */ -#include "error_private.h" /* ERROR */ +#include "../common/mem.h" /* U32, BYTE, etc. */ +#include "../common/debug.h" /* assert, DEBUGLOG */ +#include "../common/error_private.h" /* ERROR */ #include "hist.h" @@ -54,7 +34,7 @@ unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned largestCount=0; - memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); + ZSTD_memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; } while (ip= HIST_WKSP_SIZE_U32. + * `workSpace` must be a U32 table of size >= HIST_WKSP_SIZE_U32. * @return : largest histogram frequency, - * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */ + * or an error code (notably when histogram's alphabet is larger than *maxSymbolValuePtr) */ static size_t HIST_count_parallel_wksp( unsigned* count, unsigned* maxSymbolValuePtr, const void* source, size_t sourceSize, @@ -91,22 +71,21 @@ static size_t HIST_count_parallel_wksp( { const BYTE* ip = (const BYTE*)source; const BYTE* const iend = ip+sourceSize; - unsigned maxSymbolValue = *maxSymbolValuePtr; + size_t const countSize = (*maxSymbolValuePtr + 1) * sizeof(*count); unsigned max=0; U32* const Counting1 = workSpace; U32* const Counting2 = Counting1 + 256; U32* const Counting3 = Counting2 + 256; U32* const Counting4 = Counting3 + 256; - memset(workSpace, 0, 4*256*sizeof(unsigned)); - /* safety checks */ + assert(*maxSymbolValuePtr <= 255); if (!sourceSize) { - memset(count, 0, maxSymbolValue + 1); + ZSTD_memset(count, 0, countSize); *maxSymbolValuePtr = 0; return 0; } - if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ + ZSTD_memset(workSpace, 0, 4*256*sizeof(unsigned)); /* by stripes of 16 bytes */ { U32 cached = MEM_read32(ip); ip += 4; @@ -138,21 +117,18 @@ static size_t HIST_count_parallel_wksp( /* finish last symbols */ while (ipmaxSymbolValue; s--) { - Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; - if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); - } } - { U32 s; - if (maxSymbolValue > 255) maxSymbolValue = 255; - for (s=0; s<=maxSymbolValue; s++) { - count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; - if (count[s] > max) max = count[s]; + for (s=0; s<256; s++) { + Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; + if (Counting1[s] > max) max = Counting1[s]; } } - while (!count[maxSymbolValue]) maxSymbolValue--; - *maxSymbolValuePtr = maxSymbolValue; + { unsigned maxSymbolValue = 255; + while (!Counting1[maxSymbolValue]) maxSymbolValue--; + if (check && maxSymbolValue > *maxSymbolValuePtr) return ERROR(maxSymbolValue_tooSmall); + *maxSymbolValuePtr = maxSymbolValue; + ZSTD_memmove(count, Counting1, countSize); /* in case count & Counting1 are overlapping */ + } return (size_t)max; } @@ -172,14 +148,6 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace); } -/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ -size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, - const void* source, size_t sourceSize) -{ - unsigned tmpCounters[HIST_WKSP_SIZE_U32]; - return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); -} - /* HIST_count_wksp() : * Same as HIST_count(), but using an externally provided scratch buffer. * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */ @@ -195,9 +163,19 @@ size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize); } +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ +size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize) +{ + unsigned tmpCounters[HIST_WKSP_SIZE_U32]; + return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); +} + size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize) { unsigned tmpCounters[HIST_WKSP_SIZE_U32]; return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters)); } +#endif diff --git a/native/zstd/compress/hist.h b/native/zstd/compress/hist.h old mode 100755 new mode 100644 index 8b38935..228ed48 --- a/native/zstd/compress/hist.h +++ b/native/zstd/compress/hist.h @@ -1,40 +1,20 @@ /* ****************************************************************** - hist : Histogram functions - part of Finite State Entropy project - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c + * hist : Histogram functions + * part of Finite State Entropy project + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * 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. ****************************************************************** */ /* --- dependencies --- */ -#include /* size_t */ +#include "../common/zstd_deps.h" /* size_t */ /* --- simple histogram functions --- */ diff --git a/native/zstd/compress/huf_compress.c b/native/zstd/compress/huf_compress.c old mode 100755 new mode 100644 index f074f1e..5d90c16 --- a/native/zstd/compress/huf_compress.c +++ b/native/zstd/compress/huf_compress.c @@ -1,35 +1,15 @@ /* ****************************************************************** - Huffman encoder, part of New Generation Entropy library - Copyright (C) 2013-2016, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c + * Huffman encoder, part of New Generation Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * 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. ****************************************************************** */ /* ************************************************************** @@ -43,16 +23,16 @@ /* ************************************************************** * Includes ****************************************************************/ -#include /* memcpy, memset */ -#include /* printf (debug) */ -#include "compiler.h" -#include "bitstream.h" +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include "../common/compiler.h" +#include "../common/bitstream.h" #include "hist.h" #define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */ -#include "fse.h" /* header compression */ +#include "../common/fse.h" /* header compression */ #define HUF_STATIC_LINKING_ONLY -#include "huf.h" -#include "error_private.h" +#include "../common/huf.h" +#include "../common/error_private.h" +#include "../common/bits.h" /* ZSTD_highbit32 */ /* ************************************************************** @@ -60,29 +40,114 @@ ****************************************************************/ #define HUF_isError ERR_isError #define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ -#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e -#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } /* ************************************************************** -* Utils +* Required declarations ****************************************************************/ -unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) +typedef struct nodeElt_s { + U32 count; + U16 parent; + BYTE byte; + BYTE nbBits; +} nodeElt; + + +/* ************************************************************** +* Debug Traces +****************************************************************/ + +#if DEBUGLEVEL >= 2 + +static size_t showU32(const U32* arr, size_t size) +{ + size_t u; + for (u=0; u= add) { + assert(add < align); + assert(((size_t)aligned & mask) == 0); + *workspaceSizePtr -= add; + return aligned; + } else { + *workspaceSizePtr = 0; + return NULL; + } +} + + /* HUF_compressWeights() : * Same as FSE_compress(), but dedicated to huff0's weights compression. * The use case needs much less stack memory. * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX. */ #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6 -static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize) + +typedef struct { + FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; + U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)]; + unsigned count[HUF_TABLELOG_MAX+1]; + S16 norm[HUF_TABLELOG_MAX+1]; +} HUF_CompressWeightsWksp; + +static size_t +HUF_compressWeights(void* dst, size_t dstSize, + const void* weightTable, size_t wtSize, + void* workspace, size_t workspaceSize) { BYTE* const ostart = (BYTE*) dst; BYTE* op = ostart; @@ -90,69 +155,101 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight unsigned maxSymbolValue = HUF_TABLELOG_MAX; U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER; + HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; - BYTE scratchBuffer[1<count, &maxSymbolValue, weightTable, wtSize); /* never fails */ if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */ } tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue); - CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) ); + CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) ); /* Write table description header */ - { CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) ); + { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) ); op += hSize; } /* Compress */ - CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) ); - { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) ); + CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) ); + { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) ); if (cSize == 0) return 0; /* not enough space for compressed data */ op += cSize; } - return op-ostart; + return (size_t)(op-ostart); +} + +static size_t HUF_getNbBits(HUF_CElt elt) +{ + return elt & 0xFF; +} + +static size_t HUF_getNbBitsFast(HUF_CElt elt) +{ + return elt; } +static size_t HUF_getValue(HUF_CElt elt) +{ + return elt & ~(size_t)0xFF; +} -struct HUF_CElt_s { - U16 val; - BYTE nbBits; -}; /* typedef'd to HUF_CElt within "huf.h" */ +static size_t HUF_getValueFast(HUF_CElt elt) +{ + return elt; +} -/*! HUF_writeCTable() : - `CTable` : Huffman tree to save, using huf representation. - @return : size of saved CTable */ -size_t HUF_writeCTable (void* dst, size_t maxDstSize, - const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog) +static void HUF_setNbBits(HUF_CElt* elt, size_t nbBits) +{ + assert(nbBits <= HUF_TABLELOG_ABSOLUTEMAX); + *elt = nbBits; +} + +static void HUF_setValue(HUF_CElt* elt, size_t value) { + size_t const nbBits = HUF_getNbBits(*elt); + if (nbBits > 0) { + assert((value >> nbBits) == 0); + *elt |= value << (sizeof(HUF_CElt) * 8 - nbBits); + } +} + +typedef struct { + HUF_CompressWeightsWksp wksp; BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */ BYTE huffWeight[HUF_SYMBOLVALUE_MAX]; +} HUF_WriteCTableWksp; + +size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, + const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, + void* workspace, size_t workspaceSize) +{ + HUF_CElt const* const ct = CTable + 1; BYTE* op = (BYTE*)dst; U32 n; + HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - /* check conditions */ + /* check conditions */ + if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC); if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge); /* convert to weight */ - bitsToWeight[0] = 0; + wksp->bitsToWeight[0] = 0; for (n=1; nbitsToWeight[n] = (BYTE)(huffLog + 1 - n); for (n=0; nhuffWeight[n] = wksp->bitsToWeight[HUF_getNbBits(ct[n])]; /* attempt weights compression by FSE */ - { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) ); + if (maxDstSize < 1) return ERROR(dstSize_tooSmall); + { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) ); if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */ op[0] = (BYTE)hSize; return hSize+1; @@ -162,45 +259,59 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize, if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */ if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1)); - huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ + wksp->huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ for (n=0; nhuffWeight[n] << 4) + wksp->huffWeight[n+1]); return ((maxSymbolValue+1)/2) + 1; } +/*! HUF_writeCTable() : + `CTable` : Huffman tree to save, using huf representation. + @return : size of saved CTable */ +size_t HUF_writeCTable (void* dst, size_t maxDstSize, + const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog) +{ + HUF_WriteCTableWksp wksp; + return HUF_writeCTable_wksp(dst, maxDstSize, CTable, maxSymbolValue, huffLog, &wksp, sizeof(wksp)); +} + -size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize) +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights) { BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */ U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */ U32 tableLog = 0; U32 nbSymbols = 0; + HUF_CElt* const ct = CTable + 1; /* get symbol weights */ CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize)); + *hasZeroWeights = (rankVal[0] > 0); /* check result */ if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall); + CTable[0] = tableLog; + /* Prepare base value per rank */ { U32 n, nextRankStart = 0; for (n=1; n<=tableLog; n++) { - U32 current = nextRankStart; + U32 curr = nextRankStart; nextRankStart += (rankVal[n] << (n-1)); - rankVal[n] = current; + rankVal[n] = curr; } } /* fill nbBits */ { U32 n; for (n=0; nn=tableLog+1 */ U16 valPerRank[HUF_TABLELOG_MAX+2] = {0}; - { U32 n; for (n=0; n>= 1; } } /* assign value within rank, symbol order */ - { U32 n; for (n=0; n @targetNbBits + * to employ @targetNbBits instead. Then it adjusts the tree + * so that it remains a valid canonical Huffman tree. + * + * @pre The sum of the ranks of each symbol == 2^largestBits, + * where largestBits == huffNode[lastNonNull].nbBits. + * @post The sum of the ranks of each symbol == 2^largestBits, + * where largestBits is the return value (expected <= targetNbBits). + * + * @param huffNode The Huffman tree modified in place to enforce targetNbBits. + * It's presumed sorted, from most frequent to rarest symbol. + * @param lastNonNull The symbol with the lowest count in the Huffman tree. + * @param targetNbBits The allowed number of bits, which the Huffman tree + * may not respect. After this function the Huffman tree will + * respect targetNbBits. + * @return The maximum number of bits of the Huffman tree after adjustment. + */ +static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits) { const U32 largestBits = huffNode[lastNonNull].nbBits; - if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */ + /* early exit : no elt > targetNbBits, so the tree is already valid. */ + if (largestBits <= targetNbBits) return largestBits; + + DEBUGLOG(5, "HUF_setMaxHeight (targetNbBits = %u)", targetNbBits); /* there are several too large elements (at least >= 2) */ { int totalCost = 0; - const U32 baseCost = 1 << (largestBits - maxNbBits); - U32 n = lastNonNull; - - while (huffNode[n].nbBits > maxNbBits) { + const U32 baseCost = 1 << (largestBits - targetNbBits); + int n = (int)lastNonNull; + + /* Adjust any ranks > targetNbBits to targetNbBits. + * Compute totalCost, which is how far the sum of the ranks is + * we are over 2^largestBits after adjust the offending ranks. + */ + while (huffNode[n].nbBits > targetNbBits) { totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); - huffNode[n].nbBits = (BYTE)maxNbBits; - n --; - } /* n stops at huffNode[n].nbBits <= maxNbBits */ - while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */ + huffNode[n].nbBits = (BYTE)targetNbBits; + n--; + } + /* n stops at huffNode[n].nbBits <= targetNbBits */ + assert(huffNode[n].nbBits <= targetNbBits); + /* n end at index of smallest symbol using < targetNbBits */ + while (huffNode[n].nbBits == targetNbBits) --n; - /* renorm totalCost */ - totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */ + /* renorm totalCost from 2^largestBits to 2^targetNbBits + * note : totalCost is necessarily a multiple of baseCost */ + assert((totalCost & (baseCost - 1)) == 0); + totalCost >>= (largestBits - targetNbBits); + assert(totalCost > 0); /* repay normalized cost */ { U32 const noSymbol = 0xF0F0F0F0; U32 rankLast[HUF_TABLELOG_MAX+2]; - int pos; - /* Get pos of last (smallest) symbol per rank */ - memset(rankLast, 0xF0, sizeof(rankLast)); - { U32 currentNbBits = maxNbBits; + /* Get pos of last (smallest = lowest cum. count) symbol per rank */ + ZSTD_memset(rankLast, 0xF0, sizeof(rankLast)); + { U32 currentNbBits = targetNbBits; + int pos; for (pos=n ; pos >= 0; pos--) { if (huffNode[pos].nbBits >= currentNbBits) continue; - currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ - rankLast[maxNbBits-currentNbBits] = pos; + currentNbBits = huffNode[pos].nbBits; /* < targetNbBits */ + rankLast[targetNbBits-currentNbBits] = (U32)pos; } } while (totalCost > 0) { - U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1; + /* Try to reduce the next power of 2 above totalCost because we + * gain back half the rank. + */ + U32 nBitsToDecrease = ZSTD_highbit32((U32)totalCost) + 1; for ( ; nBitsToDecrease > 1; nBitsToDecrease--) { - U32 highPos = rankLast[nBitsToDecrease]; - U32 lowPos = rankLast[nBitsToDecrease-1]; + U32 const highPos = rankLast[nBitsToDecrease]; + U32 const lowPos = rankLast[nBitsToDecrease-1]; if (highPos == noSymbol) continue; + /* Decrease highPos if no symbols of lowPos or if it is + * not cheaper to remove 2 lowPos than highPos. + */ if (lowPos == noSymbol) break; { U32 const highTotal = huffNode[highPos].count; U32 const lowTotal = 2 * huffNode[lowPos].count; if (highTotal <= lowTotal) break; } } /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ + assert(rankLast[nBitsToDecrease] != noSymbol || nBitsToDecrease == 1); /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) - nBitsToDecrease ++; + nBitsToDecrease++; + assert(rankLast[nBitsToDecrease] != noSymbol); + /* Increase the number of bits to gain back half the rank cost. */ totalCost -= 1 << (nBitsToDecrease-1); + huffNode[rankLast[nBitsToDecrease]].nbBits++; + + /* Fix up the new rank. + * If the new rank was empty, this symbol is now its smallest. + * Otherwise, this symbol will be the largest in the new rank so no adjustment. + */ if (rankLast[nBitsToDecrease-1] == noSymbol) - rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */ - huffNode[rankLast[nBitsToDecrease]].nbBits ++; + rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; + /* Fix up the old rank. + * If the symbol was at position 0, meaning it was the highest weight symbol in the tree, + * it must be the only symbol in its rank, so the old rank now has no symbols. + * Otherwise, since the Huffman nodes are sorted by count, the previous position is now + * the smallest node in the rank. If the previous position belongs to a different rank, + * then the rank is now empty. + */ if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */ rankLast[nBitsToDecrease] = noSymbol; else { rankLast[nBitsToDecrease]--; - if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) + if (huffNode[rankLast[nBitsToDecrease]].nbBits != targetNbBits-nBitsToDecrease) rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ - } } /* while (totalCost > 0) */ - + } + } /* while (totalCost > 0) */ + + /* If we've removed too much weight, then we have to add it back. + * To avoid overshooting again, we only adjust the smallest rank. + * We take the largest nodes from the lowest rank 0 and move them + * to rank 1. There's guaranteed to be enough rank 0 symbols because + * TODO. + */ while (totalCost < 0) { /* Sometimes, cost correction overshoot */ - if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ - while (huffNode[n].nbBits == maxNbBits) n--; + /* special case : no rank 1 symbol (using targetNbBits-1); + * let's create one from largest rank 0 (using targetNbBits). + */ + if (rankLast[1] == noSymbol) { + while (huffNode[n].nbBits == targetNbBits) n--; huffNode[n+1].nbBits--; - rankLast[1] = n+1; + assert(n >= 0); + rankLast[1] = (U32)(n+1); totalCost++; continue; } huffNode[ rankLast[1] + 1 ].nbBits--; rankLast[1]++; totalCost ++; - } } } /* there are several too large elements (at least >= 2) */ + } + } /* repay normalized cost */ + } /* there are several too large elements (at least >= 2) */ - return maxNbBits; + return targetNbBits; } - typedef struct { - U32 base; - U32 current; + U16 base; + U16 curr; } rankPos; -static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue) -{ - rankPos rank[32]; +typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32]; + +/* Number of buckets available for HUF_sort() */ +#define RANK_POSITION_TABLE_SIZE 192 + +typedef struct { + huffNodeTable huffNodeTbl; + rankPos rankPosition[RANK_POSITION_TABLE_SIZE]; +} HUF_buildCTable_wksp_tables; + +/* RANK_POSITION_DISTINCT_COUNT_CUTOFF == Cutoff point in HUF_sort() buckets for which we use log2 bucketing. + * Strategy is to use as many buckets as possible for representing distinct + * counts while using the remainder to represent all "large" counts. + * + * To satisfy this requirement for 192 buckets, we can do the following: + * Let buckets 0-166 represent distinct counts of [0, 166] + * Let buckets 166 to 192 represent all remaining counts up to RANK_POSITION_MAX_COUNT_LOG using log2 bucketing. + */ +#define RANK_POSITION_MAX_COUNT_LOG 32 +#define RANK_POSITION_LOG_BUCKETS_BEGIN (RANK_POSITION_TABLE_SIZE - 1) - RANK_POSITION_MAX_COUNT_LOG - 1 /* == 158 */ +#define RANK_POSITION_DISTINCT_COUNT_CUTOFF RANK_POSITION_LOG_BUCKETS_BEGIN + ZSTD_highbit32(RANK_POSITION_LOG_BUCKETS_BEGIN) /* == 166 */ + +/* Return the appropriate bucket index for a given count. See definition of + * RANK_POSITION_DISTINCT_COUNT_CUTOFF for explanation of bucketing strategy. + */ +static U32 HUF_getIndex(U32 const count) { + return (count < RANK_POSITION_DISTINCT_COUNT_CUTOFF) + ? count + : ZSTD_highbit32(count) + RANK_POSITION_LOG_BUCKETS_BEGIN; +} + +/* Helper swap function for HUF_quickSortPartition() */ +static void HUF_swapNodes(nodeElt* a, nodeElt* b) { + nodeElt tmp = *a; + *a = *b; + *b = tmp; +} + +/* Returns 0 if the huffNode array is not sorted by descending count */ +MEM_STATIC int HUF_isSorted(nodeElt huffNode[], U32 const maxSymbolValue1) { + U32 i; + for (i = 1; i < maxSymbolValue1; ++i) { + if (huffNode[i].count > huffNode[i-1].count) { + return 0; + } + } + return 1; +} + +/* Insertion sort by descending order */ +HINT_INLINE void HUF_insertionSort(nodeElt huffNode[], int const low, int const high) { + int i; + int const size = high-low+1; + huffNode += low; + for (i = 1; i < size; ++i) { + nodeElt const key = huffNode[i]; + int j = i - 1; + while (j >= 0 && huffNode[j].count < key.count) { + huffNode[j + 1] = huffNode[j]; + j--; + } + huffNode[j + 1] = key; + } +} + +/* Pivot helper function for quicksort. */ +static int HUF_quickSortPartition(nodeElt arr[], int const low, int const high) { + /* Simply select rightmost element as pivot. "Better" selectors like + * median-of-three don't experimentally appear to have any benefit. + */ + U32 const pivot = arr[high].count; + int i = low - 1; + int j = low; + for ( ; j < high; j++) { + if (arr[j].count > pivot) { + i++; + HUF_swapNodes(&arr[i], &arr[j]); + } + } + HUF_swapNodes(&arr[i + 1], &arr[high]); + return i + 1; +} + +/* Classic quicksort by descending with partially iterative calls + * to reduce worst case callstack size. + */ +static void HUF_simpleQuickSort(nodeElt arr[], int low, int high) { + int const kInsertionSortThreshold = 8; + if (high - low < kInsertionSortThreshold) { + HUF_insertionSort(arr, low, high); + return; + } + while (low < high) { + int const idx = HUF_quickSortPartition(arr, low, high); + if (idx - low < high - idx) { + HUF_simpleQuickSort(arr, low, idx - 1); + low = idx + 1; + } else { + HUF_simpleQuickSort(arr, idx + 1, high); + high = idx - 1; + } + } +} + +/** + * HUF_sort(): + * Sorts the symbols [0, maxSymbolValue] by count[symbol] in decreasing order. + * This is a typical bucket sorting strategy that uses either quicksort or insertion sort to sort each bucket. + * + * @param[out] huffNode Sorted symbols by decreasing count. Only members `.count` and `.byte` are filled. + * Must have (maxSymbolValue + 1) entries. + * @param[in] count Histogram of the symbols. + * @param[in] maxSymbolValue Maximum symbol value. + * @param rankPosition This is a scratch workspace. Must have RANK_POSITION_TABLE_SIZE entries. + */ +static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSymbolValue, rankPos rankPosition[]) { U32 n; + U32 const maxSymbolValue1 = maxSymbolValue+1; + + /* Compute base and set curr to base. + * For symbol s let lowerRank = HUF_getIndex(count[n]) and rank = lowerRank + 1. + * See HUF_getIndex to see bucketing strategy. + * We attribute each symbol to lowerRank's base value, because we want to know where + * each rank begins in the output, so for rank R we want to count ranks R+1 and above. + */ + ZSTD_memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE); + for (n = 0; n < maxSymbolValue1; ++n) { + U32 lowerRank = HUF_getIndex(count[n]); + assert(lowerRank < RANK_POSITION_TABLE_SIZE - 1); + rankPosition[lowerRank].base++; + } - memset(rank, 0, sizeof(rank)); - for (n=0; n<=maxSymbolValue; n++) { - U32 r = BIT_highbit32(count[n] + 1); - rank[r].base ++; + assert(rankPosition[RANK_POSITION_TABLE_SIZE - 1].base == 0); + /* Set up the rankPosition table */ + for (n = RANK_POSITION_TABLE_SIZE - 1; n > 0; --n) { + rankPosition[n-1].base += rankPosition[n].base; + rankPosition[n-1].curr = rankPosition[n-1].base; } - for (n=30; n>0; n--) rank[n-1].base += rank[n].base; - for (n=0; n<32; n++) rank[n].current = rank[n].base; - for (n=0; n<=maxSymbolValue; n++) { + + /* Insert each symbol into their appropriate bucket, setting up rankPosition table. */ + for (n = 0; n < maxSymbolValue1; ++n) { U32 const c = count[n]; - U32 const r = BIT_highbit32(c+1) + 1; - U32 pos = rank[r].current++; - while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) { - huffNode[pos] = huffNode[pos-1]; - pos--; - } + U32 const r = HUF_getIndex(c) + 1; + U32 const pos = rankPosition[r].curr++; + assert(pos < maxSymbolValue1); huffNode[pos].count = c; huffNode[pos].byte = (BYTE)n; } + + /* Sort each bucket. */ + for (n = RANK_POSITION_DISTINCT_COUNT_CUTOFF; n < RANK_POSITION_TABLE_SIZE - 1; ++n) { + int const bucketSize = rankPosition[n].curr - rankPosition[n].base; + U32 const bucketStartIdx = rankPosition[n].base; + if (bucketSize > 1) { + assert(bucketStartIdx < maxSymbolValue1); + HUF_simpleQuickSort(huffNode + bucketStartIdx, 0, bucketSize-1); + } + } + + assert(HUF_isSorted(huffNode, maxSymbolValue1)); } /** HUF_buildCTable_wksp() : * Same as HUF_buildCTable(), but using externally allocated scratch buffer. - * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of HUF_CTABLE_WORKSPACE_SIZE_U32 unsigned. + * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as sizeof(HUF_buildCTable_wksp_tables). */ #define STARTNODE (HUF_SYMBOLVALUE_MAX+1) -typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32]; -size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize) + +/* HUF_buildTree(): + * Takes the huffNode array sorted by HUF_sort() and builds an unlimited-depth Huffman tree. + * + * @param huffNode The array sorted by HUF_sort(). Builds the Huffman tree in this array. + * @param maxSymbolValue The maximum symbol value. + * @return The smallest node in the Huffman tree (by count). + */ +static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue) { - nodeElt* const huffNode0 = (nodeElt*)workSpace; - nodeElt* const huffNode = huffNode0+1; - U32 n, nonNullRank; + nodeElt* const huffNode0 = huffNode - 1; + int nonNullRank; int lowS, lowN; - U16 nodeNb = STARTNODE; - U32 nodeRoot; - - /* safety checks */ - if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ - if (wkspSize < sizeof(huffNodeTable)) return ERROR(workSpace_tooSmall); - if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; - if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge); - memset(huffNode0, 0, sizeof(huffNodeTable)); - - /* sort, decreasing order */ - HUF_sort(huffNode, count, maxSymbolValue); - + int nodeNb = STARTNODE; + int n, nodeRoot; + DEBUGLOG(5, "HUF_buildTree (alphabet size = %u)", maxSymbolValue + 1); /* init for parents */ - nonNullRank = maxSymbolValue; + nonNullRank = (int)maxSymbolValue; while(huffNode[nonNullRank].count == 0) nonNullRank--; lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb; huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count; - huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb; + huffNode[lowS].parent = huffNode[lowS-1].parent = (U16)nodeNb; nodeNb++; lowS-=2; for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30); huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */ /* create parents */ while (nodeNb <= nodeRoot) { - U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; - U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; + int const n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; + int const n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count; - huffNode[n1].parent = huffNode[n2].parent = nodeNb; + huffNode[n1].parent = huffNode[n2].parent = (U16)nodeNb; nodeNb++; } @@ -392,126 +696,404 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbo for (n=0; n<=nonNullRank; n++) huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1; - /* enforce maxTableLog */ - maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits); + DEBUGLOG(6, "Initial distribution of bits completed (%zu sorted symbols)", showHNodeBits(huffNode, maxSymbolValue+1)); - /* fill result into tree (val, nbBits) */ - { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0}; - U16 valPerRank[HUF_TABLELOG_MAX+1] = {0}; - if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ - for (n=0; n<=nonNullRank; n++) - nbPerRank[huffNode[n].nbBits]++; - /* determine stating value per rank */ - { U16 min = 0; - for (n=maxNbBits; n>0; n--) { - valPerRank[n] = min; /* get starting value within each rank */ - min += nbPerRank[n]; - min >>= 1; - } } - for (n=0; n<=maxSymbolValue; n++) - tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */ - for (n=0; n<=maxSymbolValue; n++) - tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */ - } - - return maxNbBits; + return nonNullRank; } -/** HUF_buildCTable() : - * @return : maxNbBits - * Note : count is used before tree is written, so they can safely overlap +/** + * HUF_buildCTableFromTree(): + * Build the CTable given the Huffman tree in huffNode. + * + * @param[out] CTable The output Huffman CTable. + * @param huffNode The Huffman tree. + * @param nonNullRank The last and smallest node in the Huffman tree. + * @param maxSymbolValue The maximum symbol value. + * @param maxNbBits The exact maximum number of bits used in the Huffman tree. */ -size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits) +static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, int nonNullRank, U32 maxSymbolValue, U32 maxNbBits) +{ + HUF_CElt* const ct = CTable + 1; + /* fill result into ctable (val, nbBits) */ + int n; + U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0}; + U16 valPerRank[HUF_TABLELOG_MAX+1] = {0}; + int const alphabetSize = (int)(maxSymbolValue + 1); + for (n=0; n<=nonNullRank; n++) + nbPerRank[huffNode[n].nbBits]++; + /* determine starting value per rank */ + { U16 min = 0; + for (n=(int)maxNbBits; n>0; n--) { + valPerRank[n] = min; /* get starting value within each rank */ + min += nbPerRank[n]; + min >>= 1; + } } + for (n=0; nhuffNodeTbl; + nodeElt* const huffNode = huffNode0+1; + int nonNullRank; + + DEBUGLOG(5, "HUF_buildCTable_wksp (alphabet size = %u)", maxSymbolValue+1); + + /* safety checks */ + if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) + return ERROR(workSpace_tooSmall); + if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; + if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) + return ERROR(maxSymbolValue_tooLarge); + ZSTD_memset(huffNode0, 0, sizeof(huffNodeTable)); + + /* sort, decreasing order */ + HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition); + DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1)); + + /* build tree */ + nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); + + /* determine and enforce maxTableLog */ + maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); + if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ + + HUF_buildCTableFromTree(CTable, huffNode, nonNullRank, maxSymbolValue, maxNbBits); + + return maxNbBits; } -static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) +size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { + HUF_CElt const* ct = CTable + 1; size_t nbBits = 0; int s; for (s = 0; s <= (int)maxSymbolValue; ++s) { - nbBits += CTable[s].nbBits * count[s]; + nbBits += HUF_getNbBits(ct[s]) * count[s]; } return nbBits >> 3; } -static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { +int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { + HUF_CElt const* ct = CTable + 1; int bad = 0; int s; for (s = 0; s <= (int)maxSymbolValue; ++s) { - bad |= (count[s] != 0) & (CTable[s].nbBits == 0); + bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0); } return !bad; } size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); } +/** HUF_CStream_t: + * Huffman uses its own BIT_CStream_t implementation. + * There are three major differences from BIT_CStream_t: + * 1. HUF_addBits() takes a HUF_CElt (size_t) which is + * the pair (nbBits, value) in the format: + * format: + * - Bits [0, 4) = nbBits + * - Bits [4, 64 - nbBits) = 0 + * - Bits [64 - nbBits, 64) = value + * 2. The bitContainer is built from the upper bits and + * right shifted. E.g. to add a new value of N bits + * you right shift the bitContainer by N, then or in + * the new value into the N upper bits. + * 3. The bitstream has two bit containers. You can add + * bits to the second container and merge them into + * the first container. + */ + +#define HUF_BITS_IN_CONTAINER (sizeof(size_t) * 8) + +typedef struct { + size_t bitContainer[2]; + size_t bitPos[2]; + + BYTE* startPtr; + BYTE* ptr; + BYTE* endPtr; +} HUF_CStream_t; + +/**! HUF_initCStream(): + * Initializes the bitstream. + * @returns 0 or an error code. + */ +static size_t HUF_initCStream(HUF_CStream_t* bitC, + void* startPtr, size_t dstCapacity) +{ + ZSTD_memset(bitC, 0, sizeof(*bitC)); + bitC->startPtr = (BYTE*)startPtr; + bitC->ptr = bitC->startPtr; + bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer[0]); + if (dstCapacity <= sizeof(bitC->bitContainer[0])) return ERROR(dstSize_tooSmall); + return 0; +} + +/*! HUF_addBits(): + * Adds the symbol stored in HUF_CElt elt to the bitstream. + * + * @param elt The element we're adding. This is a (nbBits, value) pair. + * See the HUF_CStream_t docs for the format. + * @param idx Insert into the bitstream at this idx. + * @param kFast This is a template parameter. If the bitstream is guaranteed + * to have at least 4 unused bits after this call it may be 1, + * otherwise it must be 0. HUF_addBits() is faster when fast is set. + */ +FORCE_INLINE_TEMPLATE void HUF_addBits(HUF_CStream_t* bitC, HUF_CElt elt, int idx, int kFast) +{ + assert(idx <= 1); + assert(HUF_getNbBits(elt) <= HUF_TABLELOG_ABSOLUTEMAX); + /* This is efficient on x86-64 with BMI2 because shrx + * only reads the low 6 bits of the register. The compiler + * knows this and elides the mask. When fast is set, + * every operation can use the same value loaded from elt. + */ + bitC->bitContainer[idx] >>= HUF_getNbBits(elt); + bitC->bitContainer[idx] |= kFast ? HUF_getValueFast(elt) : HUF_getValue(elt); + /* We only read the low 8 bits of bitC->bitPos[idx] so it + * doesn't matter that the high bits have noise from the value. + */ + bitC->bitPos[idx] += HUF_getNbBitsFast(elt); + assert((bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); + /* The last 4-bits of elt are dirty if fast is set, + * so we must not be overwriting bits that have already been + * inserted into the bit container. + */ +#if DEBUGLEVEL >= 1 + { + size_t const nbBits = HUF_getNbBits(elt); + size_t const dirtyBits = nbBits == 0 ? 0 : ZSTD_highbit32((U32)nbBits) + 1; + (void)dirtyBits; + /* Middle bits are 0. */ + assert(((elt >> dirtyBits) << (dirtyBits + nbBits)) == 0); + /* We didn't overwrite any bits in the bit container. */ + assert(!kFast || (bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); + (void)dirtyBits; + } +#endif +} + +FORCE_INLINE_TEMPLATE void HUF_zeroIndex1(HUF_CStream_t* bitC) +{ + bitC->bitContainer[1] = 0; + bitC->bitPos[1] = 0; +} + +/*! HUF_mergeIndex1() : + * Merges the bit container @ index 1 into the bit container @ index 0 + * and zeros the bit container @ index 1. + */ +FORCE_INLINE_TEMPLATE void HUF_mergeIndex1(HUF_CStream_t* bitC) +{ + assert((bitC->bitPos[1] & 0xFF) < HUF_BITS_IN_CONTAINER); + bitC->bitContainer[0] >>= (bitC->bitPos[1] & 0xFF); + bitC->bitContainer[0] |= bitC->bitContainer[1]; + bitC->bitPos[0] += bitC->bitPos[1]; + assert((bitC->bitPos[0] & 0xFF) <= HUF_BITS_IN_CONTAINER); +} + +/*! HUF_flushBits() : +* Flushes the bits in the bit container @ index 0. +* +* @post bitPos will be < 8. +* @param kFast If kFast is set then we must know a-priori that +* the bit container will not overflow. +*/ +FORCE_INLINE_TEMPLATE void HUF_flushBits(HUF_CStream_t* bitC, int kFast) +{ + /* The upper bits of bitPos are noisy, so we must mask by 0xFF. */ + size_t const nbBits = bitC->bitPos[0] & 0xFF; + size_t const nbBytes = nbBits >> 3; + /* The top nbBits bits of bitContainer are the ones we need. */ + size_t const bitContainer = bitC->bitContainer[0] >> (HUF_BITS_IN_CONTAINER - nbBits); + /* Mask bitPos to account for the bytes we consumed. */ + bitC->bitPos[0] &= 7; + assert(nbBits > 0); + assert(nbBits <= sizeof(bitC->bitContainer[0]) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitContainer); + bitC->ptr += nbBytes; + assert(!kFast || bitC->ptr <= bitC->endPtr); + if (!kFast && bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; + /* bitContainer doesn't need to be modified because the leftover + * bits are already the top bitPos bits. And we don't care about + * noise in the lower values. + */ +} + +/*! HUF_endMark() + * @returns The Huffman stream end mark: A 1-bit value = 1. + */ +static HUF_CElt HUF_endMark(void) +{ + HUF_CElt endMark; + HUF_setNbBits(&endMark, 1); + HUF_setValue(&endMark, 1); + return endMark; +} + +/*! HUF_closeCStream() : + * @return Size of CStream, in bytes, + * or 0 if it could not fit into dstBuffer */ +static size_t HUF_closeCStream(HUF_CStream_t* bitC) +{ + HUF_addBits(bitC, HUF_endMark(), /* idx */ 0, /* kFast */ 0); + HUF_flushBits(bitC, /* kFast */ 0); + { + size_t const nbBits = bitC->bitPos[0] & 0xFF; + if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ + return (size_t)(bitC->ptr - bitC->startPtr) + (nbBits > 0); + } +} + FORCE_INLINE_TEMPLATE void -HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable) +HUF_encodeSymbol(HUF_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable, int idx, int fast) { - BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits); + HUF_addBits(bitCPtr, CTable[symbol], idx, fast); } -#define HUF_FLUSHBITS(s) BIT_flushBits(s) +FORCE_INLINE_TEMPLATE void +HUF_compress1X_usingCTable_internal_body_loop(HUF_CStream_t* bitC, + const BYTE* ip, size_t srcSize, + const HUF_CElt* ct, + int kUnroll, int kFastFlush, int kLastFast) +{ + /* Join to kUnroll */ + int n = (int)srcSize; + int rem = n % kUnroll; + if (rem > 0) { + for (; rem > 0; --rem) { + HUF_encodeSymbol(bitC, ip[--n], ct, 0, /* fast */ 0); + } + HUF_flushBits(bitC, kFastFlush); + } + assert(n % kUnroll == 0); + + /* Join to 2 * kUnroll */ + if (n % (2 * kUnroll)) { + int u; + for (u = 1; u < kUnroll; ++u) { + HUF_encodeSymbol(bitC, ip[n - u], ct, 0, 1); + } + HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, 0, kLastFast); + HUF_flushBits(bitC, kFastFlush); + n -= kUnroll; + } + assert(n % (2 * kUnroll) == 0); + + for (; n>0; n-= 2 * kUnroll) { + /* Encode kUnroll symbols into the bitstream @ index 0. */ + int u; + for (u = 1; u < kUnroll; ++u) { + HUF_encodeSymbol(bitC, ip[n - u], ct, /* idx */ 0, /* fast */ 1); + } + HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, /* idx */ 0, /* fast */ kLastFast); + HUF_flushBits(bitC, kFastFlush); + /* Encode kUnroll symbols into the bitstream @ index 1. + * This allows us to start filling the bit container + * without any data dependencies. + */ + HUF_zeroIndex1(bitC); + for (u = 1; u < kUnroll; ++u) { + HUF_encodeSymbol(bitC, ip[n - kUnroll - u], ct, /* idx */ 1, /* fast */ 1); + } + HUF_encodeSymbol(bitC, ip[n - kUnroll - kUnroll], ct, /* idx */ 1, /* fast */ kLastFast); + /* Merge bitstream @ index 1 into the bitstream @ index 0 */ + HUF_mergeIndex1(bitC); + HUF_flushBits(bitC, kFastFlush); + } + assert(n == 0); + +} -#define HUF_FLUSHBITS_1(stream) \ - if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream) +/** + * Returns a tight upper bound on the output space needed by Huffman + * with 8 bytes buffer to handle over-writes. If the output is at least + * this large we don't need to do bounds checks during Huffman encoding. + */ +static size_t HUF_tightCompressBound(size_t srcSize, size_t tableLog) +{ + return ((srcSize * tableLog) >> 3) + 8; +} -#define HUF_FLUSHBITS_2(stream) \ - if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream) FORCE_INLINE_TEMPLATE size_t HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { + U32 const tableLog = (U32)CTable[0]; + HUF_CElt const* ct = CTable + 1; const BYTE* ip = (const BYTE*) src; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; BYTE* op = ostart; - size_t n; - BIT_CStream_t bitC; + HUF_CStream_t bitC; /* init */ if (dstSize < 8) return 0; /* not enough space to compress */ - { size_t const initErr = BIT_initCStream(&bitC, op, oend-op); + { size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op)); if (HUF_isError(initErr)) return 0; } - n = srcSize & ~3; /* join to mod 4 */ - switch (srcSize & 3) - { - case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable); - HUF_FLUSHBITS_2(&bitC); - /* fall-through */ - case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable); - HUF_FLUSHBITS_1(&bitC); - /* fall-through */ - case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable); - HUF_FLUSHBITS(&bitC); - /* fall-through */ - case 0 : /* fall-through */ - default: break; - } - - for (; n>0; n-=4) { /* note : n&3==0 at this stage */ - HUF_encodeSymbol(&bitC, ip[n- 1], CTable); - HUF_FLUSHBITS_1(&bitC); - HUF_encodeSymbol(&bitC, ip[n- 2], CTable); - HUF_FLUSHBITS_2(&bitC); - HUF_encodeSymbol(&bitC, ip[n- 3], CTable); - HUF_FLUSHBITS_1(&bitC); - HUF_encodeSymbol(&bitC, ip[n- 4], CTable); - HUF_FLUSHBITS(&bitC); + if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11) + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ MEM_32bits() ? 2 : 4, /* kFast */ 0, /* kLastFast */ 0); + else { + if (MEM_32bits()) { + switch (tableLog) { + case 11: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 10: ZSTD_FALLTHROUGH; + case 9: ZSTD_FALLTHROUGH; + case 8: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + case 7: ZSTD_FALLTHROUGH; + default: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 3, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + } + } else { + switch (tableLog) { + case 11: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 10: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + case 9: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 6, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 8: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 7, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 7: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 8, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 6: ZSTD_FALLTHROUGH; + default: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 9, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + } + } } + assert(bitC.ptr <= bitC.endPtr); - return BIT_closeCStream(&bitC); + return HUF_closeCStream(&bitC); } #if DYNAMIC_BMI2 -static TARGET_ATTRIBUTE("bmi2") size_t +static BMI2_TARGET_ATTRIBUTE size_t HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) @@ -553,9 +1135,13 @@ HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); + return HUF_compress1X_usingCTable_bmi2(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); } +size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2) +{ + return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, bmi2); +} static size_t HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, @@ -573,41 +1159,48 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, if (srcSize < 12) return 0; /* no saving possible : too small input */ op += 6; /* jumpTable */ - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) ); - if (cSize==0) return 0; - assert(cSize <= 65535); + assert(op <= oend); + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); + if (cSize == 0 || cSize > 65535) return 0; MEM_writeLE16(ostart, (U16)cSize); op += cSize; } ip += segmentSize; - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) ); - if (cSize==0) return 0; - assert(cSize <= 65535); + assert(op <= oend); + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); + if (cSize == 0 || cSize > 65535) return 0; MEM_writeLE16(ostart+2, (U16)cSize); op += cSize; } ip += segmentSize; - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) ); - if (cSize==0) return 0; - assert(cSize <= 65535); + assert(op <= oend); + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); + if (cSize == 0 || cSize > 65535) return 0; MEM_writeLE16(ostart+4, (U16)cSize); op += cSize; } ip += segmentSize; - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, iend-ip, CTable, bmi2) ); - if (cSize==0) return 0; + assert(op <= oend); + assert(ip <= iend); + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, bmi2) ); + if (cSize == 0 || cSize > 65535) return 0; op += cSize; } - return op-ostart; + return (size_t)(op-ostart); } size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); + return HUF_compress4X_usingCTable_bmi2(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); +} + +size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2) +{ + return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, bmi2); } typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e; @@ -618,24 +1211,42 @@ static size_t HUF_compressCTable_internal( HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2) { size_t const cSize = (nbStreams==HUF_singleStream) ? - HUF_compress1X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2) : - HUF_compress4X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2); + HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2) : + HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2); if (HUF_isError(cSize)) { return cSize; } if (cSize==0) { return 0; } /* uncompressible */ op += cSize; /* check compressibility */ + assert(op >= ostart); if ((size_t)(op-ostart) >= srcSize-1) { return 0; } - return op-ostart; + return (size_t)(op-ostart); +} + + +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) +{ + unsigned tableLog = FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); + assert(tableLog <= HUF_TABLELOG_MAX); + + return tableLog; } typedef struct { unsigned count[HUF_SYMBOLVALUE_MAX + 1]; - HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1]; - huffNodeTable nodeTable; + HUF_CElt CTable[HUF_CTABLE_SIZE_ST(HUF_SYMBOLVALUE_MAX)]; + union { + HUF_buildCTable_wksp_tables buildCTable_wksp; + HUF_WriteCTableWksp writeCTable_wksp; + U32 hist_wksp[HIST_WKSP_SIZE_U32]; + } wksps; } HUF_compress_tables_t; +#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096 +#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */ + /* HUF_compress_internal() : - * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ + * `workSpace_align4` must be aligned on 4-bytes boundaries, + * and occupies the same space as a table of HUF_WORKSPACE_SIZE_U64 unsigned */ static size_t HUF_compress_internal (void* dst, size_t dstSize, const void* src, size_t srcSize, @@ -643,16 +1254,18 @@ HUF_compress_internal (void* dst, size_t dstSize, HUF_nbStreams_e nbStreams, void* workSpace, size_t wkspSize, HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat, - const int bmi2) + const int bmi2, unsigned suspectUncompressible) { - HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace; + HUF_compress_tables_t* const table = (HUF_compress_tables_t*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(size_t)); BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; BYTE* op = ostart; + DEBUGLOG(5, "HUF_compress_internal (srcSize=%zu)", srcSize); + HUF_STATIC_ASSERT(sizeof(*table) + HUF_WORKSPACE_MAX_ALIGNMENT <= HUF_WORKSPACE_SIZE); + /* checks & inits */ - if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ - if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall); + if (wkspSize < sizeof(*table)) return ERROR(workSpace_tooSmall); if (!srcSize) return 0; /* Uncompressed */ if (!dstSize) return 0; /* cannot fit anything within dst budget */ if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */ @@ -668,11 +1281,28 @@ HUF_compress_internal (void* dst, size_t dstSize, nbStreams, oldHufTable, bmi2); } + /* If uncompressible data is suspected, do a smaller sampling first */ + DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2); + if (suspectUncompressible && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) { + size_t largestTotal = 0; + DEBUGLOG(5, "input suspected incompressible : sampling to check"); + { unsigned maxSymbolValueBegin = maxSymbolValue; + CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); + largestTotal += largestBegin; + } + { unsigned maxSymbolValueEnd = maxSymbolValue; + CHECK_V_F(largestEnd, HIST_count_simple (table->count, &maxSymbolValueEnd, (const BYTE*)src + srcSize - SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); + largestTotal += largestEnd; + } + if (largestTotal <= ((2 * SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) >> 7)+4) return 0; /* heuristic : probably not compressible enough */ + } + /* Scan input and build symbol stats */ - { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) ); + { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, table->wksps.hist_wksp, sizeof(table->wksps.hist_wksp)) ); if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */ if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */ } + DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1)); /* Check validity of previous table */ if ( repeat @@ -691,16 +1321,21 @@ HUF_compress_internal (void* dst, size_t dstSize, huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); { size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count, maxSymbolValue, huffLog, - table->nodeTable, sizeof(table->nodeTable)); + &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp)); CHECK_F(maxBits); huffLog = (U32)maxBits; - /* Zero unused symbols in CTable, so we can check it for validity */ - memset(table->CTable + (maxSymbolValue + 1), 0, - sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt))); + DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1)); + } + /* Zero unused symbols in CTable, so we can check it for validity */ + { + size_t const ctableSize = HUF_CTABLE_SIZE_ST(maxSymbolValue); + size_t const unusedSize = sizeof(table->CTable) - ctableSize * sizeof(HUF_CElt); + ZSTD_memset(table->CTable + ctableSize, 0, unusedSize); } /* Write table description header */ - { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) ); + { CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog, + &table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) ); /* Check if using previous huffman table is beneficial */ if (repeat && *repeat != HUF_repeat_none) { size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue); @@ -716,7 +1351,7 @@ HUF_compress_internal (void* dst, size_t dstSize, op += hSize; if (repeat) { *repeat = HUF_repeat_none; } if (oldHufTable) - memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ + ZSTD_memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ } return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, @@ -732,27 +1367,21 @@ size_t HUF_compress1X_wksp (void* dst, size_t dstSize, return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_singleStream, workSpace, wkspSize, - NULL, NULL, 0, 0 /*bmi2*/); + NULL, NULL, 0, 0 /*bmi2*/, 0); } size_t HUF_compress1X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, + int bmi2, unsigned suspectUncompressible) { + DEBUGLOG(5, "HUF_compress1X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_singleStream, workSpace, wkspSize, hufTable, - repeat, preferRepeat, bmi2); -} - -size_t HUF_compress1X (void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned huffLog) -{ - unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; - return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); + repeat, preferRepeat, bmi2, suspectUncompressible); } /* HUF_compress4X_repeat(): @@ -763,32 +1392,54 @@ size_t HUF_compress4X_wksp (void* dst, size_t dstSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize) { + DEBUGLOG(5, "HUF_compress4X_wksp (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_fourStreams, workSpace, wkspSize, - NULL, NULL, 0, 0 /*bmi2*/); + NULL, NULL, 0, 0 /*bmi2*/, 0); } /* HUF_compress4X_repeat(): * compress input using 4 streams. + * consider skipping quickly * re-use an existing huffman compression table */ size_t HUF_compress4X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible) { + DEBUGLOG(5, "HUF_compress4X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_fourStreams, workSpace, wkspSize, - hufTable, repeat, preferRepeat, bmi2); + hufTable, repeat, preferRepeat, bmi2, suspectUncompressible); +} + +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +/** HUF_buildCTable() : + * @return : maxNbBits + * Note : count is used before tree is written, so they can safely overlap + */ +size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits) +{ + HUF_buildCTable_wksp_tables workspace; + return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, &workspace, sizeof(workspace)); +} + +size_t HUF_compress1X (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog) +{ + U64 workSpace[HUF_WORKSPACE_SIZE_U64]; + return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); } size_t HUF_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog) { - unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; + U64 workSpace[HUF_WORKSPACE_SIZE_U64]; return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); } @@ -796,3 +1447,4 @@ size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSi { return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT); } +#endif diff --git a/native/zstd/compress/zstd_compress.c b/native/zstd/compress/zstd_compress.c old mode 100755 new mode 100644 index 35346b9..59d441b --- a/native/zstd/compress/zstd_compress.c +++ b/native/zstd/compress/zstd_compress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,15 +11,13 @@ /*-************************************* * Dependencies ***************************************/ -#include /* INT_MAX */ -#include /* memset */ -#include "cpu.h" -#include "mem.h" +#include "../common/zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */ +#include "../common/mem.h" #include "hist.h" /* HIST_countFast_wksp */ #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ -#include "fse.h" +#include "../common/fse.h" #define HUF_STATIC_LINKING_ONLY -#include "huf.h" +#include "../common/huf.h" #include "zstd_compress_internal.h" #include "zstd_compress_sequences.h" #include "zstd_compress_literals.h" @@ -28,11 +26,45 @@ #include "zstd_lazy.h" #include "zstd_opt.h" #include "zstd_ldm.h" +#include "zstd_compress_superblock.h" +#include "../common/bits.h" /* ZSTD_highbit32 */ + +/* *************************************************************** +* Tuning parameters +*****************************************************************/ +/*! + * COMPRESS_HEAPMODE : + * Select how default decompression function ZSTD_compress() allocates its context, + * on stack (0, default), or into heap (1). + * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected. + */ +#ifndef ZSTD_COMPRESS_HEAPMODE +# define ZSTD_COMPRESS_HEAPMODE 0 +#endif +/*! + * ZSTD_HASHLOG3_MAX : + * Maximum size of the hash table dedicated to find 3-bytes matches, + * in log format, aka 17 => 1 << 17 == 128Ki positions. + * This structure is only used in zstd_opt. + * Since allocation is centralized for all strategies, it has to be known here. + * The actual (selected) size of the hash table is then stored in ZSTD_matchState_t.hashLog3, + * so that zstd_opt.c doesn't need to know about this constant. + */ +#ifndef ZSTD_HASHLOG3_MAX +# define ZSTD_HASHLOG3_MAX 17 +#endif /*-************************************* * Helper functions ***************************************/ +/* ZSTD_compressBound() + * Note that the result from this function is only compatible with the "normal" + * full-block strategy. + * When there are a lot of small blocks due to frequent flush in streaming mode + * the overhead of headers can make the compressed data to be larger than the + * return value of ZSTD_compressBound(). + */ size_t ZSTD_compressBound(size_t srcSize) { return ZSTD_COMPRESSBOUND(srcSize); } @@ -44,6 +76,7 @@ size_t ZSTD_compressBound(size_t srcSize) { struct ZSTD_CDict_s { const void* dictContent; size_t dictContentSize; + ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ ZSTD_cwksp workspace; ZSTD_matchState_t matchState; @@ -51,6 +84,10 @@ struct ZSTD_CDict_s { ZSTD_customMem customMem; U32 dictID; int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ + ZSTD_paramSwitch_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use + * row-based matchfinder. Unless the cdict is reloaded, we will use + * the same greedy/lazy matchfinder at compression time. + */ }; /* typedef'd to ZSTD_CDict within "zstd.h" */ ZSTD_CCtx* ZSTD_createCCtx(void) @@ -61,9 +98,9 @@ ZSTD_CCtx* ZSTD_createCCtx(void) static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) { assert(cctx != NULL); - memset(cctx, 0, sizeof(*cctx)); + ZSTD_memset(cctx, 0, sizeof(*cctx)); cctx->customMem = memManager; - cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); + cctx->bmi2 = ZSTD_cpuSupportsBmi2(); { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); assert(!ZSTD_isError(err)); (void)err; @@ -74,36 +111,34 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) { ZSTD_STATIC_ASSERT(zcss_init==0); ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem); if (!cctx) return NULL; ZSTD_initCCtx(cctx, customMem); return cctx; } } -ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) +ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) { ZSTD_cwksp ws; ZSTD_CCtx* cctx; if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ - ZSTD_cwksp_init(&ws, workspace, workspaceSize); + ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx)); - if (cctx == NULL) { - return NULL; - } - memset(cctx, 0, sizeof(ZSTD_CCtx)); + if (cctx == NULL) return NULL; + + ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx)); ZSTD_cwksp_move(&cctx->workspace, &ws); cctx->staticSize = workspaceSize; /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ - if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; + if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); - cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object( - &cctx->workspace, HUF_WORKSPACE_SIZE); + cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE); cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); return cctx; } @@ -113,10 +148,10 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) */ static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) { - ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem); + ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem); ZSTD_freeCDict(cctx->localDict.cdict); - memset(&cctx->localDict, 0, sizeof(cctx->localDict)); - memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); + ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict)); + ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); cctx->cdict = NULL; } @@ -143,12 +178,9 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) if (cctx==NULL) return 0; /* support free on NULL */ RETURN_ERROR_IF(cctx->staticSize, memory_allocation, "not compatible with static CCtx"); - { - int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); + { int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); ZSTD_freeCCtxContent(cctx); - if (!cctxInWorkspace) { - ZSTD_free(cctx, cctx->customMem); - } + if (!cctxInWorkspace) ZSTD_customFree(cctx, cctx->customMem); } return 0; } @@ -183,15 +215,90 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } +/* Returns true if the strategy supports using a row based matchfinder */ +static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) { + return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2); +} + +/* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder + * for this compression. + */ +static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_paramSwitch_e mode) { + assert(mode != ZSTD_ps_auto); + return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_ps_enable); +} + +/* Returns row matchfinder usage given an initial mode and cParams */ +static ZSTD_paramSwitch_e ZSTD_resolveRowMatchFinderMode(ZSTD_paramSwitch_e mode, + const ZSTD_compressionParameters* const cParams) { +#if defined(ZSTD_ARCH_X86_SSE2) || defined(ZSTD_ARCH_ARM_NEON) + int const kHasSIMD128 = 1; +#else + int const kHasSIMD128 = 0; +#endif + if (mode != ZSTD_ps_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */ + mode = ZSTD_ps_disable; + if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode; + if (kHasSIMD128) { + if (cParams->windowLog > 14) mode = ZSTD_ps_enable; + } else { + if (cParams->windowLog > 17) mode = ZSTD_ps_enable; + } + return mode; +} + +/* Returns block splitter usage (generally speaking, when using slower/stronger compression modes) */ +static ZSTD_paramSwitch_e ZSTD_resolveBlockSplitterMode(ZSTD_paramSwitch_e mode, + const ZSTD_compressionParameters* const cParams) { + if (mode != ZSTD_ps_auto) return mode; + return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17) ? ZSTD_ps_enable : ZSTD_ps_disable; +} + +/* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */ +static int ZSTD_allocateChainTable(const ZSTD_strategy strategy, + const ZSTD_paramSwitch_e useRowMatchFinder, + const U32 forDDSDict) { + assert(useRowMatchFinder != ZSTD_ps_auto); + /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate. + * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder. + */ + return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder)); +} + +/* Returns 1 if compression parameters are such that we should + * enable long distance matching (wlog >= 27, strategy >= btopt). + * Returns 0 otherwise. + */ +static ZSTD_paramSwitch_e ZSTD_resolveEnableLdm(ZSTD_paramSwitch_e mode, + const ZSTD_compressionParameters* const cParams) { + if (mode != ZSTD_ps_auto) return mode; + return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable; +} + +/* Returns 1 if compression parameters are such that CDict hashtable and chaintable indices are tagged. + * If so, the tags need to be removed in ZSTD_resetCCtx_byCopyingCDict. */ +static int ZSTD_CDictIndicesAreTagged(const ZSTD_compressionParameters* const cParams) { + return cParams->strategy == ZSTD_fast || cParams->strategy == ZSTD_dfast; +} + static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( ZSTD_compressionParameters cParams) { ZSTD_CCtx_params cctxParams; - memset(&cctxParams, 0, sizeof(cctxParams)); + /* should not matter, as all cParams are presumed properly defined */ + ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT); cctxParams.cParams = cParams; - cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ + + /* Adjust advanced params according to cParams */ + cctxParams.ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams.ldmParams.enableLdm, &cParams); + if (cctxParams.ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams); + assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog); + assert(cctxParams.ldmParams.hashRateLog < 32); + } + cctxParams.useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams.useBlockSplitter, &cParams); + cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); assert(!ZSTD_checkCParams(cParams)); - cctxParams.fParams.contentSizeFlag = 1; return cctxParams; } @@ -199,13 +306,12 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( ZSTD_customMem customMem) { ZSTD_CCtx_params* params; - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - params = (ZSTD_CCtx_params*)ZSTD_calloc( + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + params = (ZSTD_CCtx_params*)ZSTD_customCalloc( sizeof(ZSTD_CCtx_params), customMem); if (!params) { return NULL; } + ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); params->customMem = customMem; - params->compressionLevel = ZSTD_CLEVEL_DEFAULT; - params->fParams.contentSizeFlag = 1; return params; } @@ -217,7 +323,7 @@ ZSTD_CCtx_params* ZSTD_createCCtxParams(void) size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } - ZSTD_free(params, params->customMem); + ZSTD_customFree(params, params->customMem); return 0; } @@ -227,36 +333,58 @@ size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) } size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { - RETURN_ERROR_IF(!cctxParams, GENERIC); - memset(cctxParams, 0, sizeof(*cctxParams)); + RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); + ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); cctxParams->compressionLevel = compressionLevel; cctxParams->fParams.contentSizeFlag = 1; return 0; } +#define ZSTD_NO_CLEVEL 0 + +/** + * Initializes the cctxParams from params and compressionLevel. + * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. + */ +static void ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, ZSTD_parameters const* params, int compressionLevel) +{ + assert(!ZSTD_checkCParams(params->cParams)); + ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); + cctxParams->cParams = params->cParams; + cctxParams->fParams = params->fParams; + /* Should not matter, as all cParams are presumed properly defined. + * But, set it for tracing anyway. + */ + cctxParams->compressionLevel = compressionLevel; + cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams); + cctxParams->useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->useBlockSplitter, ¶ms->cParams); + cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, ¶ms->cParams); + DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d", + cctxParams->useRowMatchFinder, cctxParams->useBlockSplitter, cctxParams->ldmParams.enableLdm); +} + size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { - RETURN_ERROR_IF(!cctxParams, GENERIC); - FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); - memset(cctxParams, 0, sizeof(*cctxParams)); - assert(!ZSTD_checkCParams(params.cParams)); - cctxParams->cParams = params.cParams; - cctxParams->fParams = params.fParams; - cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ + RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); + FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); + ZSTD_CCtxParams_init_internal(cctxParams, ¶ms, ZSTD_NO_CLEVEL); return 0; } -/* ZSTD_assignParamsToCCtxParams() : - * params is presumed valid at this stage */ -static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( - const ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) -{ - ZSTD_CCtx_params ret = *cctxParams; - assert(!ZSTD_checkCParams(params.cParams)); - ret.cParams = params.cParams; - ret.fParams = params.fParams; - ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ - return ret; +/** + * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone. + * @param param Validated zstd parameters. + */ +static void ZSTD_CCtxParams_setZstdParams( + ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) +{ + assert(!ZSTD_checkCParams(params->cParams)); + cctxParams->cParams = params->cParams; + cctxParams->fParams = params->fParams; + /* Should not matter, as all cParams are presumed properly defined. + * But, set it for tracing anyway. + */ + cctxParams->compressionLevel = ZSTD_NO_CLEVEL; } ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) @@ -339,8 +467,18 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) return bounds; case ZSTD_c_overlapLog: +#ifdef ZSTD_MULTITHREAD bounds.lowerBound = ZSTD_OVERLAPLOG_MIN; bounds.upperBound = ZSTD_OVERLAPLOG_MAX; +#else + bounds.lowerBound = 0; + bounds.upperBound = 0; +#endif + return bounds; + + case ZSTD_c_enableDedicatedDictSearch: + bounds.lowerBound = 0; + bounds.upperBound = 1; return bounds; case ZSTD_c_enableLongDistanceMatching: @@ -386,15 +524,15 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) return bounds; case ZSTD_c_forceAttachDict: - ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy); + ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad); bounds.lowerBound = ZSTD_dictDefaultAttach; bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */ return bounds; case ZSTD_c_literalCompressionMode: - ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); - bounds.lowerBound = ZSTD_lcm_auto; - bounds.upperBound = ZSTD_lcm_uncompressed; + ZSTD_STATIC_ASSERT(ZSTD_ps_auto < ZSTD_ps_enable && ZSTD_ps_enable < ZSTD_ps_disable); + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; return bounds; case ZSTD_c_targetCBlockSize: @@ -407,10 +545,45 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) bounds.upperBound = ZSTD_SRCSIZEHINT_MAX; return bounds; + case ZSTD_c_stableInBuffer: + case ZSTD_c_stableOutBuffer: + bounds.lowerBound = (int)ZSTD_bm_buffered; + bounds.upperBound = (int)ZSTD_bm_stable; + return bounds; + + case ZSTD_c_blockDelimiters: + bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters; + bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters; + return bounds; + + case ZSTD_c_validateSequences: + bounds.lowerBound = 0; + bounds.upperBound = 1; + return bounds; + + case ZSTD_c_useBlockSplitter: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + + case ZSTD_c_useRowMatchFinder: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + + case ZSTD_c_deterministicRefPrefix: + bounds.lowerBound = 0; + bounds.upperBound = 1; + return bounds; + + case ZSTD_c_prefetchCDictTables: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + default: - { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 }; - return boundError; - } + bounds.error = ERROR(parameter_unsupported); + return bounds; } } @@ -428,7 +601,7 @@ static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) #define BOUNDCHECK(cParam, val) { \ RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ - parameter_outOfBound); \ + parameter_outOfBound, "Param out of bounds"); \ } @@ -455,6 +628,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: + case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: @@ -464,6 +638,14 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_literalCompressionMode: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: + case ZSTD_c_stableInBuffer: + case ZSTD_c_stableOutBuffer: + case ZSTD_c_blockDelimiters: + case ZSTD_c_validateSequences: + case ZSTD_c_useBlockSplitter: + case ZSTD_c_useRowMatchFinder: + case ZSTD_c_deterministicRefPrefix: + case ZSTD_c_prefetchCDictTables: default: return 0; } @@ -476,7 +658,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) if (ZSTD_isUpdateAuthorized(param)) { cctx->cParamsChanged = 1; } else { - RETURN_ERROR(stage_wrong); + RETURN_ERROR(stage_wrong, "can only set params in ctx init stage"); } } switch(param) @@ -505,15 +687,24 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: + case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: case ZSTD_c_ldmBucketSizeLog: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: + case ZSTD_c_stableInBuffer: + case ZSTD_c_stableOutBuffer: + case ZSTD_c_blockDelimiters: + case ZSTD_c_validateSequences: + case ZSTD_c_useBlockSplitter: + case ZSTD_c_useRowMatchFinder: + case ZSTD_c_deterministicRefPrefix: + case ZSTD_c_prefetchCDictTables: break; - default: RETURN_ERROR(parameter_unsupported); + default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value); } @@ -530,10 +721,11 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, return (size_t)CCtxParams->format; case ZSTD_c_compressionLevel : { - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); - if (value) { /* 0 : does not change current level */ + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); + if (value == 0) + CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ + else CCtxParams->compressionLevel = value; - } if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel; return 0; /* return type (size_t) cannot represent negative values */ } @@ -565,12 +757,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_minMatch : if (value!=0) /* 0 => use default */ BOUNDCHECK(ZSTD_c_minMatch, value); - CCtxParams->cParams.minMatch = value; + CCtxParams->cParams.minMatch = (U32)value; return CCtxParams->cParams.minMatch; case ZSTD_c_targetLength : BOUNDCHECK(ZSTD_c_targetLength, value); - CCtxParams->cParams.targetLength = value; + CCtxParams->cParams.targetLength = (U32)value; return CCtxParams->cParams.targetLength; case ZSTD_c_strategy : @@ -583,12 +775,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, /* Content size written in frame header _when known_ (default:1) */ DEBUGLOG(4, "set content size flag = %u", (value!=0)); CCtxParams->fParams.contentSizeFlag = value != 0; - return CCtxParams->fParams.contentSizeFlag; + return (size_t)CCtxParams->fParams.contentSizeFlag; case ZSTD_c_checksumFlag : /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ CCtxParams->fParams.checksumFlag = value != 0; - return CCtxParams->fParams.checksumFlag; + return (size_t)CCtxParams->fParams.checksumFlag; case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); @@ -597,7 +789,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_forceMaxWindow : CCtxParams->forceWindow = (value != 0); - return CCtxParams->forceWindow; + return (size_t)CCtxParams->forceWindow; case ZSTD_c_forceAttachDict : { const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; @@ -607,7 +799,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, } case ZSTD_c_literalCompressionMode : { - const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; + const ZSTD_paramSwitch_e lcm = (ZSTD_paramSwitch_e)value; BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); CCtxParams->literalCompressionMode = lcm; return CCtxParams->literalCompressionMode; @@ -618,7 +810,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); return 0; #else - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); CCtxParams->nbWorkers = value; return CCtxParams->nbWorkers; #endif @@ -631,7 +823,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, /* Adjust to the minimum non-default value. */ if (value != 0 && value < ZSTDMT_JOBSIZE_MIN) value = ZSTDMT_JOBSIZE_MIN; - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); assert(value >= 0); CCtxParams->jobSize = value; return CCtxParams->jobSize; @@ -642,7 +834,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); return 0; #else - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); CCtxParams->overlapLog = value; return CCtxParams->overlapLog; #endif @@ -652,62 +844,106 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); return 0; #else - FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); + FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); CCtxParams->rsyncable = value; return CCtxParams->rsyncable; #endif + case ZSTD_c_enableDedicatedDictSearch : + CCtxParams->enableDedicatedDictSearch = (value!=0); + return (size_t)CCtxParams->enableDedicatedDictSearch; + case ZSTD_c_enableLongDistanceMatching : - CCtxParams->ldmParams.enableLdm = (value!=0); + CCtxParams->ldmParams.enableLdm = (ZSTD_paramSwitch_e)value; return CCtxParams->ldmParams.enableLdm; case ZSTD_c_ldmHashLog : if (value!=0) /* 0 ==> auto */ BOUNDCHECK(ZSTD_c_ldmHashLog, value); - CCtxParams->ldmParams.hashLog = value; + CCtxParams->ldmParams.hashLog = (U32)value; return CCtxParams->ldmParams.hashLog; case ZSTD_c_ldmMinMatch : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmMinMatch, value); - CCtxParams->ldmParams.minMatchLength = value; + CCtxParams->ldmParams.minMatchLength = (U32)value; return CCtxParams->ldmParams.minMatchLength; case ZSTD_c_ldmBucketSizeLog : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); - CCtxParams->ldmParams.bucketSizeLog = value; + CCtxParams->ldmParams.bucketSizeLog = (U32)value; return CCtxParams->ldmParams.bucketSizeLog; case ZSTD_c_ldmHashRateLog : - RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, - parameter_outOfBound); - CCtxParams->ldmParams.hashRateLog = value; + if (value!=0) /* 0 ==> default */ + BOUNDCHECK(ZSTD_c_ldmHashRateLog, value); + CCtxParams->ldmParams.hashRateLog = (U32)value; return CCtxParams->ldmParams.hashRateLog; case ZSTD_c_targetCBlockSize : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_targetCBlockSize, value); - CCtxParams->targetCBlockSize = value; + CCtxParams->targetCBlockSize = (U32)value; return CCtxParams->targetCBlockSize; case ZSTD_c_srcSizeHint : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_srcSizeHint, value); CCtxParams->srcSizeHint = value; - return CCtxParams->srcSizeHint; + return (size_t)CCtxParams->srcSizeHint; + + case ZSTD_c_stableInBuffer: + BOUNDCHECK(ZSTD_c_stableInBuffer, value); + CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value; + return CCtxParams->inBufferMode; + + case ZSTD_c_stableOutBuffer: + BOUNDCHECK(ZSTD_c_stableOutBuffer, value); + CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value; + return CCtxParams->outBufferMode; + + case ZSTD_c_blockDelimiters: + BOUNDCHECK(ZSTD_c_blockDelimiters, value); + CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value; + return CCtxParams->blockDelimiters; + + case ZSTD_c_validateSequences: + BOUNDCHECK(ZSTD_c_validateSequences, value); + CCtxParams->validateSequences = value; + return CCtxParams->validateSequences; + + case ZSTD_c_useBlockSplitter: + BOUNDCHECK(ZSTD_c_useBlockSplitter, value); + CCtxParams->useBlockSplitter = (ZSTD_paramSwitch_e)value; + return CCtxParams->useBlockSplitter; + + case ZSTD_c_useRowMatchFinder: + BOUNDCHECK(ZSTD_c_useRowMatchFinder, value); + CCtxParams->useRowMatchFinder = (ZSTD_paramSwitch_e)value; + return CCtxParams->useRowMatchFinder; + + case ZSTD_c_deterministicRefPrefix: + BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value); + CCtxParams->deterministicRefPrefix = !!value; + return CCtxParams->deterministicRefPrefix; + + case ZSTD_c_prefetchCDictTables: + BOUNDCHECK(ZSTD_c_prefetchCDictTables, value); + CCtxParams->prefetchCDictTables = (ZSTD_paramSwitch_e)value; + return CCtxParams->prefetchCDictTables; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } } -size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value) +size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value) { return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); } size_t ZSTD_CCtxParams_getParameter( - ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value) + ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value) { switch(param) { @@ -784,6 +1020,9 @@ size_t ZSTD_CCtxParams_getParameter( *value = CCtxParams->rsyncable; break; #endif + case ZSTD_c_enableDedicatedDictSearch : + *value = CCtxParams->enableDedicatedDictSearch; + break; case ZSTD_c_enableLongDistanceMatching : *value = CCtxParams->ldmParams.enableLdm; break; @@ -805,6 +1044,30 @@ size_t ZSTD_CCtxParams_getParameter( case ZSTD_c_srcSizeHint : *value = (int)CCtxParams->srcSizeHint; break; + case ZSTD_c_stableInBuffer : + *value = (int)CCtxParams->inBufferMode; + break; + case ZSTD_c_stableOutBuffer : + *value = (int)CCtxParams->outBufferMode; + break; + case ZSTD_c_blockDelimiters : + *value = (int)CCtxParams->blockDelimiters; + break; + case ZSTD_c_validateSequences : + *value = (int)CCtxParams->validateSequences; + break; + case ZSTD_c_useBlockSplitter : + *value = (int)CCtxParams->useBlockSplitter; + break; + case ZSTD_c_useRowMatchFinder : + *value = (int)CCtxParams->useRowMatchFinder; + break; + case ZSTD_c_deterministicRefPrefix: + *value = (int)CCtxParams->deterministicRefPrefix; + break; + case ZSTD_c_prefetchCDictTables: + *value = (int)CCtxParams->prefetchCDictTables; + break; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } return 0; @@ -821,21 +1084,33 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams( ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) { DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); - RETURN_ERROR_IF(cctx->cdict, stage_wrong); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "The context is in the wrong stage!"); + RETURN_ERROR_IF(cctx->cdict, stage_wrong, + "Can't override parameters with cdict attached (some must " + "be inherited from the cdict)."); cctx->requestedParams = *params; return 0; } -ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) +size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't set pledgedSrcSize when not in init stage."); cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; return 0; } +static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams( + int const compressionLevel, + size_t const dictSize); +static int ZSTD_dedicatedDictSearch_isSupported( + const ZSTD_compressionParameters* cParams); +static void ZSTD_dedicatedDictSearch_revertCParams( + ZSTD_compressionParameters* cParams); + /** * Initializes the local dict using the requested parameters. * NOTE: This does not use the pledged src size, because it may be used for more @@ -844,8 +1119,6 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) { ZSTD_localDict* const dl = &cctx->localDict; - ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams( - &cctx->requestedParams, 0, dl->dictSize); if (dl->dict == NULL) { /* No local dictionary. */ assert(dl->dictBuffer == NULL); @@ -862,14 +1135,14 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) assert(cctx->cdict == NULL); assert(cctx->prefixDict.dict == NULL); - dl->cdict = ZSTD_createCDict_advanced( + dl->cdict = ZSTD_createCDict_advanced2( dl->dict, dl->dictSize, ZSTD_dlm_byRef, dl->dictContentType, - cParams, + &cctx->requestedParams, cctx->customMem); - RETURN_ERROR_IF(!dl->cdict, memory_allocation); + RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed"); cctx->cdict = dl->cdict; return 0; } @@ -878,9 +1151,8 @@ size_t ZSTD_CCtx_loadDictionary_advanced( ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); - RETURN_ERROR_IF(cctx->staticSize, memory_allocation, - "no malloc for static CCtx"); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't load a dictionary when ctx is not in init stage."); DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); ZSTD_clearAllDicts(cctx); /* in case one already exists */ if (dict == NULL || dictSize == 0) /* no dictionary mode */ @@ -888,9 +1160,12 @@ size_t ZSTD_CCtx_loadDictionary_advanced( if (dictLoadMethod == ZSTD_dlm_byRef) { cctx->localDict.dict = dict; } else { - void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem); - RETURN_ERROR_IF(!dictBuffer, memory_allocation); - memcpy(dictBuffer, dict, dictSize); + void* dictBuffer; + RETURN_ERROR_IF(cctx->staticSize, memory_allocation, + "no malloc for static CCtx"); + dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem); + RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!"); + ZSTD_memcpy(dictBuffer, dict, dictSize); cctx->localDict.dictBuffer = dictBuffer; cctx->localDict.dict = dictBuffer; } @@ -899,14 +1174,14 @@ size_t ZSTD_CCtx_loadDictionary_advanced( return 0; } -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( +size_t ZSTD_CCtx_loadDictionary_byReference( ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); } -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); @@ -915,13 +1190,22 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't ref a dict when ctx not in init stage."); /* Free the existing local cdict (if any) to save memory. */ ZSTD_clearAllDicts(cctx); cctx->cdict = cdict; return 0; } +size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool) +{ + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't ref a pool when ctx not in init stage."); + cctx->pool = pool; + return 0; +} + size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) { return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); @@ -930,11 +1214,14 @@ size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSiz size_t ZSTD_CCtx_refPrefix_advanced( ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't ref a prefix when ctx not in init stage."); ZSTD_clearAllDicts(cctx); - cctx->prefixDict.dict = prefix; - cctx->prefixDict.dictSize = prefixSize; - cctx->prefixDict.dictContentType = dictContentType; + if (prefix != NULL && prefixSize > 0) { + cctx->prefixDict.dict = prefix; + cctx->prefixDict.dictSize = prefixSize; + cctx->prefixDict.dictContentType = dictContentType; + } return 0; } @@ -949,7 +1236,8 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) } if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't reset parameters only when not in init stage."); ZSTD_clearAllDicts(cctx); return ZSTD_CCtxParams_reset(&cctx->requestedParams); } @@ -996,31 +1284,89 @@ ZSTD_clampCParams(ZSTD_compressionParameters cParams) /** ZSTD_cycleLog() : * condition for correct operation : hashLog > 1 */ -static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) +U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) { U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); return hashLog - btScale; } +/** ZSTD_dictAndWindowLog() : + * Returns an adjusted window log that is large enough to fit the source and the dictionary. + * The zstd format says that the entire dictionary is valid if one byte of the dictionary + * is within the window. So the hashLog and chainLog should be large enough to reference both + * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing + * the hashLog and windowLog. + * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN. + */ +static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) +{ + const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX; + /* No dictionary ==> No change */ + if (dictSize == 0) { + return windowLog; + } + assert(windowLog <= ZSTD_WINDOWLOG_MAX); + assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */ + { + U64 const windowSize = 1ULL << windowLog; + U64 const dictAndWindowSize = dictSize + windowSize; + /* If the window size is already large enough to fit both the source and the dictionary + * then just use the window size. Otherwise adjust so that it fits the dictionary and + * the window. + */ + if (windowSize >= dictSize + srcSize) { + return windowLog; /* Window size large enough already */ + } else if (dictAndWindowSize >= maxWindowSize) { + return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */ + } else { + return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1; + } + } +} + /** ZSTD_adjustCParams_internal() : * optimize `cPar` for a specified input (`srcSize` and `dictSize`). * mostly downsize to reduce memory consumption and initialization latency. * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. - * note : for the time being, `srcSize==0` means "unknown" too, for compatibility with older convention. + * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`. + * note : `srcSize==0` means 0! * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ static ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, - size_t dictSize) + size_t dictSize, + ZSTD_cParamMode_e mode) { - static const U64 minSrcSize = 513; /* (1<<9) + 1 */ - static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); + const U64 minSrcSize = 513; /* (1<<9) + 1 */ + const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); assert(ZSTD_checkCParams(cPar)==0); - if (dictSize && (srcSize+1<2) /* ZSTD_CONTENTSIZE_UNKNOWN and 0 mean "unknown" */ ) - srcSize = minSrcSize; /* presumed small when there is a dictionary */ - else if (srcSize == 0) - srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ + switch (mode) { + case ZSTD_cpm_unknown: + case ZSTD_cpm_noAttachDict: + /* If we don't know the source size, don't make any + * assumptions about it. We will already have selected + * smaller parameters if a dictionary is in use. + */ + break; + case ZSTD_cpm_createCDict: + /* Assume a small source size when creating a dictionary + * with an unknown source size. + */ + if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) + srcSize = minSrcSize; + break; + case ZSTD_cpm_attachDict: + /* Dictionary has its own dedicated parameters which have + * already been selected. We are selecting parameters + * for only the source. + */ + dictSize = 0; + break; + default: + assert(0); + break; + } /* resize windowLog if input is small enough, to use less memory */ if ( (srcSize < maxWindowResize) @@ -1031,15 +1377,24 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, ZSTD_highbit32(tSize-1) + 1; if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; } - if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; - { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); - if (cycleLog > cPar.windowLog) - cPar.chainLog -= (cycleLog - cPar.windowLog); + if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) { + U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize); + U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); + if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1; + if (cycleLog > dictAndWindowLog) + cPar.chainLog -= (cycleLog - dictAndWindowLog); } if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ + if (mode == ZSTD_cpm_createCDict && ZSTD_CDictIndicesAreTagged(&cPar)) { + U32 const maxShortCacheHashLog = 32 - ZSTD_SHORT_CACHE_TAG_BITS; + if (cPar.hashLog > maxShortCacheHashLog) { + cPar.hashLog = maxShortCacheHashLog; + } + } + return cPar; } @@ -1049,34 +1404,51 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar, size_t dictSize) { cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ - return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); + if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN; + return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown); +} + +static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); +static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); + +static void ZSTD_overrideCParams( + ZSTD_compressionParameters* cParams, + const ZSTD_compressionParameters* overrides) +{ + if (overrides->windowLog) cParams->windowLog = overrides->windowLog; + if (overrides->hashLog) cParams->hashLog = overrides->hashLog; + if (overrides->chainLog) cParams->chainLog = overrides->chainLog; + if (overrides->searchLog) cParams->searchLog = overrides->searchLog; + if (overrides->minMatch) cParams->minMatch = overrides->minMatch; + if (overrides->targetLength) cParams->targetLength = overrides->targetLength; + if (overrides->strategy) cParams->strategy = overrides->strategy; } ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { ZSTD_compressionParameters cParams; if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { srcSizeHint = CCtxParams->srcSizeHint; } - cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); - if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; - if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; - if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; - if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; - if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; - if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch; - if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; - if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; + cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode); + if (CCtxParams->ldmParams.enableLdm == ZSTD_ps_enable) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; + ZSTD_overrideCParams(&cParams, &CCtxParams->cParams); assert(!ZSTD_checkCParams(cParams)); - return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); + /* srcSizeHint == 0 means 0 */ + return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode); } static size_t ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, + const ZSTD_paramSwitch_e useRowMatchFinder, + const U32 enableDedicatedDictSearch, const U32 forCCtx) { - size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); + /* chain table size should be 0 for fast or row-hash strategies */ + size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx) + ? ((size_t)1 << cParams->chainLog) + : 0; size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; @@ -1086,58 +1458,117 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, + hSize * sizeof(U32) + h3Size * sizeof(U32); size_t const optPotentialSpace = - ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32)) - + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32)) - + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32)) - + ZSTD_cwksp_alloc_size((1<strategy, useRowMatchFinder) + ? ZSTD_cwksp_aligned_alloc_size(hSize*sizeof(U16)) + : 0; size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt)) ? optPotentialSpace : 0; + size_t const slackSpace = ZSTD_cwksp_slack_space_required(); + + /* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */ + ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4); + assert(useRowMatchFinder != ZSTD_ps_auto); + DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", (U32)chainSize, (U32)hSize, (U32)h3Size); - return tableSpace + optSpace; + return tableSpace + optSpace + slackSpace + lazyAdditionalSpace; +} + +static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( + const ZSTD_compressionParameters* cParams, + const ldmParams_t* ldmParams, + const int isStatic, + const ZSTD_paramSwitch_e useRowMatchFinder, + const size_t buffInSize, + const size_t buffOutSize, + const U64 pledgedSrcSize) +{ + size_t const windowSize = (size_t) BOUNDED(1ULL, 1ULL << cParams->windowLog, pledgedSrcSize); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); + U32 const divider = (cParams->minMatch==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef)) + + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); + size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE); + size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); + size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1); + + size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams); + size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize); + size_t const ldmSeqSpace = ldmParams->enableLdm == ZSTD_ps_enable ? + ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0; + + + size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + + ZSTD_cwksp_alloc_size(buffOutSize); + + size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; + + size_t const neededSpace = + cctxSpace + + entropySpace + + blockStateSpace + + ldmSpace + + ldmSeqSpace + + matchStateSize + + tokenSpace + + bufferSpace; + + DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); + return neededSpace; } size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) { - RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); - { ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, 0, 0); - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - U32 const divider = (cParams.minMatch==3) ? 3 : 4; - size_t const maxNbSeq = blockSize / divider; - size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) - + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) - + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); - size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); - size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); - size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); - - size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); - size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq)); + ZSTD_compressionParameters const cParams = + ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, + &cParams); - size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace + - matchStateSize + ldmSpace + ldmSeqSpace; - size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)); - - DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)cctxSpace); - DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); - return cctxSpace + neededSpace; - } + RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); + /* estimateCCtxSize is for one-shot compression. So no buffers should + * be needed. However, we still allocate two 0-sized buffers, which can + * take space under ASAN. */ + return ZSTD_estimateCCtxSize_usingCCtxParams_internal( + &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN); } size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); - return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); + ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); + if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { + /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ + size_t noRowCCtxSize; + size_t rowCCtxSize; + initialParams.useRowMatchFinder = ZSTD_ps_disable; + noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); + initialParams.useRowMatchFinder = ZSTD_ps_enable; + rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); + return MAX(noRowCCtxSize, rowCCtxSize); + } else { + return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); + } } static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); - return ZSTD_estimateCCtxSize_usingCParams(cParams); + int tier = 0; + size_t largestSize = 0; + static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN}; + for (; tier < 4; ++tier) { + /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */ + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); + largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize); + } + return largestSize; } size_t ZSTD_estimateCCtxSize(int compressionLevel) @@ -1145,6 +1576,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) int level; size_t memBudget = 0; for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { + /* Ensure monotonically increasing memory usage as compression level increases */ size_t const newMB = ZSTD_estimateCCtxSize_internal(level); if (newMB > memBudget) memBudget = newMB; } @@ -1155,27 +1587,42 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) { RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); { ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, 0, 0); - size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); + ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; - size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; - size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize) - + ZSTD_cwksp_alloc_size(outBuffSize); - - return CCtxSize + streamingSize; + size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) + ? ((size_t)1 << cParams.windowLog) + blockSize + : 0; + size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered) + ? ZSTD_compressBound(blockSize) + 1 + : 0; + ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams); + + return ZSTD_estimateCCtxSize_usingCCtxParams_internal( + &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, + ZSTD_CONTENTSIZE_UNKNOWN); } } size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); - return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); + ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); + if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { + /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ + size_t noRowCCtxSize; + size_t rowCCtxSize; + initialParams.useRowMatchFinder = ZSTD_ps_disable; + noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); + initialParams.useRowMatchFinder = ZSTD_ps_enable; + rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); + return MAX(noRowCCtxSize, rowCCtxSize); + } else { + return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); + } } static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); return ZSTD_estimateCStreamSize_usingCParams(cParams); } @@ -1243,7 +1690,7 @@ static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, assert(cParams1.strategy == cParams2.strategy); } -static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) +void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) { int i; for (i = 0; i < ZSTD_REP_NUM; ++i) @@ -1268,16 +1715,6 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) ms->dictMatchState = NULL; } -/** - * Indicates whether this compression proceeds directly from user-provided - * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or - * whether the context needs to buffer the input/output (ZSTDb_buffered). - */ -typedef enum { - ZSTDb_not_buffered, - ZSTDb_buffered -} ZSTD_buffered_policy_e; - /** * Controls, for this matchState reset, whether the tables need to be cleared / * prepared for the coming compression (ZSTDcrp_makeClean), or whether the @@ -1305,25 +1742,29 @@ typedef enum { ZSTD_resetTarget_CCtx } ZSTD_resetTarget_e; + static size_t ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_cwksp* ws, const ZSTD_compressionParameters* cParams, + const ZSTD_paramSwitch_e useRowMatchFinder, const ZSTD_compResetPolicy_e crp, const ZSTD_indexResetPolicy_e forceResetIndex, const ZSTD_resetTarget_e forWho) { - size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); + /* disable chain table allocation for fast or row-based strategies */ + size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, + ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict)) + ? ((size_t)1 << cParams->chainLog) + : 0; size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset); + assert(useRowMatchFinder != ZSTD_ps_auto); if (forceResetIndex == ZSTDirp_reset) { - memset(&ms->window, 0, sizeof(ms->window)); - ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */ - ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ - ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */ + ZSTD_window_init(&ms->window); ZSTD_cwksp_mark_tables_dirty(ws); } @@ -1360,11 +1801,23 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t)); } + if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) { + { /* Row match finder needs an additional table of hashes ("tags") */ + size_t const tagTableSize = hSize*sizeof(U16); + ms->tagTable = (U16*)ZSTD_cwksp_reserve_aligned(ws, tagTableSize); + if (ms->tagTable) ZSTD_memset(ms->tagTable, 0, tagTableSize); + } + { /* Switch to 32-entry rows if searchLog is 5 (or more) */ + U32 const rowLog = BOUNDED(4, cParams->searchLog, 6); + assert(cParams->hashLog >= rowLog); + ms->rowHashLog = cParams->hashLog - rowLog; + } + } + ms->cParams = *cParams; RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, "failed a workspace allocation in ZSTD_reset_matchState"); - return 0; } @@ -1381,75 +1834,87 @@ static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); } +/** ZSTD_dictTooBig(): + * When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in + * one go generically. So we ensure that in that case we reset the tables to zero, + * so that we can load as much of the dictionary as possible. + */ +static int ZSTD_dictTooBig(size_t const loadedDictSize) +{ + return loadedDictSize > ZSTD_CHUNKSIZE_MAX; +} + /*! ZSTD_resetCCtx_internal() : - note : `params` are assumed fully validated at this stage */ + * @param loadedDictSize The size of the dictionary to be loaded + * into the context, if any. If no dictionary is used, or the + * dictionary is being attached / copied, then pass 0. + * note : `params` are assumed fully validated at this stage. + */ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, - ZSTD_CCtx_params params, + ZSTD_CCtx_params const* params, U64 const pledgedSrcSize, + size_t const loadedDictSize, ZSTD_compResetPolicy_e const crp, ZSTD_buffered_policy_e const zbuff) { ZSTD_cwksp* const ws = &zc->workspace; - DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", - (U32)pledgedSrcSize, params.cParams.windowLog); - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d useBlockSplitter=%d", + (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder, (int)params->useBlockSplitter); + assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); zc->isFirstBlock = 1; - if (params.ldmParams.enableLdm) { + /* Set applied params early so we can modify them for LDM, + * and point params at the applied params. + */ + zc->appliedParams = *params; + params = &zc->appliedParams; + + assert(params->useRowMatchFinder != ZSTD_ps_auto); + assert(params->useBlockSplitter != ZSTD_ps_auto); + assert(params->ldmParams.enableLdm != ZSTD_ps_auto); + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* Adjust long distance matching parameters */ - ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); - assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); - assert(params.ldmParams.hashRateLog < 32); - zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); + ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, ¶ms->cParams); + assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog); + assert(params->ldmParams.hashRateLog < 32); } - { 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(ZSTD_BLOCKSIZE_MAX, windowSize); - U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; + U32 const divider = (params->cParams.minMatch==3) ? 3 : 4; size_t const maxNbSeq = blockSize / divider; - size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) - + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) - + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); - size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; - size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; - size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); - size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); - - ZSTD_indexResetPolicy_e needsIndexReset = ZSTDirp_continue; - - if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) { - needsIndexReset = ZSTDirp_reset; - } - - ZSTD_cwksp_bump_oversized_duration(ws, 0); - - /* Check if workspace is large enough, alloc a new one if needed */ - { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; - size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); - size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); - size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize); - size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); - size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)); - - size_t const neededSpace = - cctxSpace + - entropySpace + - blockStateSpace + - ldmSpace + - ldmSeqSpace + - matchStateSize + - tokenSpace + - bufferSpace; - + size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered) + ? ZSTD_compressBound(blockSize) + 1 + : 0; + size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered) + ? windowSize + blockSize + : 0; + size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize); + + int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window); + int const dictTooBig = ZSTD_dictTooBig(loadedDictSize); + ZSTD_indexResetPolicy_e needsIndexReset = + (indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue; + + size_t const neededSpace = + ZSTD_estimateCCtxSize_usingCCtxParams_internal( + ¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, + buffInSize, buffOutSize, pledgedSrcSize); + int resizeWorkspace; + + FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); + + if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); + + { /* Check if workspace is large enough, alloc a new one if needed */ int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace); - - DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", - neededSpace>>10, matchStateSize>>10, bufferSpace>>10); + resizeWorkspace = workspaceTooSmall || workspaceWasteful; + DEBUGLOG(4, "Need %zu B workspace", neededSpace); DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); - if (workspaceTooSmall || workspaceWasteful) { + if (resizeWorkspace) { DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB", ZSTD_cwksp_sizeof(ws) >> 10, neededSpace >> 10); @@ -1459,7 +1924,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, needsIndexReset = ZSTDirp_reset; ZSTD_cwksp_free(ws, zc->customMem); - FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem)); + FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), ""); DEBUGLOG(5, "reserving object space"); /* Statically sized space. @@ -1470,15 +1935,15 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock"); zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock"); - zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE); - RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); + zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE); + RETURN_ERROR_IF(zc->entropyWorkspace == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); } } ZSTD_cwksp_clear(ws); /* init params */ - zc->appliedParams = params; - zc->blockState.matchState.cParams = params.cParams; + zc->blockState.matchState.cParams = params->cParams; + zc->blockState.matchState.prefetchCDictTables = params->prefetchCDictTables == ZSTD_ps_enable; zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; zc->producedCSize = 0; @@ -1491,6 +1956,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, XXH64_reset(&zc->xxhState, 0); zc->stage = ZSTDcs_init; zc->dictID = 0; + zc->dictContentSize = 0; ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); @@ -1501,19 +1967,20 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, zc->seqStore.maxNbLit = blockSize; /* buffers */ + zc->bufferedPolicy = zbuff; zc->inBuffSize = buffInSize; zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); zc->outBuffSize = buffOutSize; zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); /* ldm bucketOffsets table */ - if (params.ldmParams.enableLdm) { + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* TODO: avoid memset? */ - size_t const ldmBucketSize = - ((size_t)1) << (params.ldmParams.hashLog - - params.ldmParams.bucketSizeLog); - zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize); - memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize); + size_t const numBuckets = + ((size_t)1) << (params->ldmParams.hashLog - + params->ldmParams.bucketSizeLog); + zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets); + ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets); } /* sequences storage */ @@ -1527,25 +1994,29 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, FORWARD_IF_ERROR(ZSTD_reset_matchState( &zc->blockState.matchState, ws, - ¶ms.cParams, + ¶ms->cParams, + params->useRowMatchFinder, crp, needsIndexReset, - ZSTD_resetTarget_CCtx)); + ZSTD_resetTarget_CCtx), ""); /* ldm hash table */ - if (params.ldmParams.enableLdm) { + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* TODO: avoid memset? */ - size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; + size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog; zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); - memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); + ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); zc->maxNbLdmSequences = maxNbLdmSeq; - memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window)); - ZSTD_window_clear(&zc->ldmState.window); + ZSTD_window_init(&zc->ldmState.window); + zc->ldmState.loadedDictEnd = 0; } DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); + assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace, resizeWorkspace)); + + zc->initialized = 1; return 0; } @@ -1583,12 +2054,14 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, U64 pledgedSrcSize) { size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; - return ( pledgedSrcSize <= cutoff - || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || params->attachDictPref == ZSTD_dictForceAttach ) - && params->attachDictPref != ZSTD_dictForceCopy - && !params->forceWindow; /* dictMatchState isn't correctly - * handled in _enforceMaxDist */ + int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch; + return dedicatedDictSearch + || ( ( pledgedSrcSize <= cutoff + || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN + || params->attachDictPref == ZSTD_dictForceAttach ) + && params->attachDictPref != ZSTD_dictForceCopy + && !params->forceWindow ); /* dictMatchState isn't correctly + * handled in _enforceMaxDist */ } static size_t @@ -1598,16 +2071,28 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams; + DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu", + (unsigned long long)pledgedSrcSize); + { + ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams; unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Resize working context table params for input only, since the dict * has its own tables. */ - params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); + /* pledgedSrcSize == 0 means 0! */ + + if (cdict->matchState.dedicatedDictSearch) { + ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams); + } + + params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize, + cdict->dictContentSize, ZSTD_cpm_attachDict); params.cParams.windowLog = windowLog; - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, - ZSTDcrp_makeClean, zbuff)); - assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); + params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */ + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, + /* loadedDictSize */ 0, + ZSTDcrp_makeClean, zbuff), ""); + assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy); } { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc @@ -1632,13 +2117,30 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, } } cctx->dictID = cdict->dictID; + cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } +static void ZSTD_copyCDictTableIntoCCtx(U32* dst, U32 const* src, size_t tableSize, + ZSTD_compressionParameters const* cParams) { + if (ZSTD_CDictIndicesAreTagged(cParams)){ + /* Remove tags from the CDict table if they are present. + * See docs on "short cache" in zstd_compress_internal.h for context. */ + size_t i; + for (i = 0; i < tableSize; i++) { + U32 const taggedIndex = src[i]; + U32 const index = taggedIndex >> ZSTD_SHORT_CACHE_TAG_BITS; + dst[i] = index; + } + } else { + ZSTD_memcpy(dst, src, tableSize * sizeof(U32)); + } +} + static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, @@ -1647,39 +2149,57 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, { const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; - DEBUGLOG(4, "copying dictionary into context"); + assert(!cdict->matchState.dedicatedDictSearch); + DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu", + (unsigned long long)pledgedSrcSize); { unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Copy only compression parameters related to tables. */ params.cParams = *cdict_cParams; params.cParams.windowLog = windowLog; - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, - ZSTDcrp_leaveDirty, zbuff)); + params.useRowMatchFinder = cdict->useRowMatchFinder; + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, + /* loadedDictSize */ 0, + ZSTDcrp_leaveDirty, zbuff), ""); assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); } ZSTD_cwksp_mark_tables_dirty(&cctx->workspace); + assert(params.useRowMatchFinder != ZSTD_ps_auto); /* copy tables */ - { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); + { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */) + ? ((size_t)1 << cdict_cParams->chainLog) + : 0; size_t const hSize = (size_t)1 << cdict_cParams->hashLog; - memcpy(cctx->blockState.matchState.hashTable, - cdict->matchState.hashTable, - hSize * sizeof(U32)); - memcpy(cctx->blockState.matchState.chainTable, - cdict->matchState.chainTable, - chainSize * sizeof(U32)); + ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.hashTable, + cdict->matchState.hashTable, + hSize, cdict_cParams); + + /* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */ + if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) { + ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.chainTable, + cdict->matchState.chainTable, + chainSize, cdict_cParams); + } + /* copy tag table */ + if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) { + size_t const tagTableSize = hSize*sizeof(U16); + ZSTD_memcpy(cctx->blockState.matchState.tagTable, + cdict->matchState.tagTable, + tagTableSize); + } } /* Zero the hashTable3, since the cdict never fills it */ { int const h3log = cctx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; assert(cdict->matchState.hashLog3 == 0); - memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); + ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); } ZSTD_cwksp_mark_tables_clean(&cctx->workspace); @@ -1693,9 +2213,10 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, } cctx->dictID = cdict->dictID; + cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } @@ -1735,15 +2256,22 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { + RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong, + "Can't copy a ctx that's not in init stage."); DEBUGLOG(5, "ZSTD_copyCCtx_internal"); - RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong); - - memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); + ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); { ZSTD_CCtx_params params = dstCCtx->requestedParams; /* Copy only compression parameters related to tables. */ params.cParams = srcCCtx->appliedParams.cParams; + assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_ps_auto); + assert(srcCCtx->appliedParams.useBlockSplitter != ZSTD_ps_auto); + assert(srcCCtx->appliedParams.ldmParams.enableLdm != ZSTD_ps_auto); + params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder; + params.useBlockSplitter = srcCCtx->appliedParams.useBlockSplitter; + params.ldmParams = srcCCtx->appliedParams.ldmParams; params.fParams = fParams; - ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, + ZSTD_resetCCtx_internal(dstCCtx, ¶ms, pledgedSrcSize, + /* loadedDictSize */ 0, ZSTDcrp_leaveDirty, zbuff); assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); @@ -1755,18 +2283,22 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace); /* copy tables */ - { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); + { size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy, + srcCCtx->appliedParams.useRowMatchFinder, + 0 /* forDDSDict */) + ? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog) + : 0; size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; int const h3log = srcCCtx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; - memcpy(dstCCtx->blockState.matchState.hashTable, + ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, hSize * sizeof(U32)); - memcpy(dstCCtx->blockState.matchState.chainTable, + ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable, srcCCtx->blockState.matchState.chainTable, chainSize * sizeof(U32)); - memcpy(dstCCtx->blockState.matchState.hashTable3, + ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3, srcCCtx->blockState.matchState.hashTable3, h3Size * sizeof(U32)); } @@ -1782,9 +2314,10 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; } dstCCtx->dictID = srcCCtx->dictID; + dstCCtx->dictContentSize = srcCCtx->dictContentSize; /* copy block state */ - memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); + ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); return 0; } @@ -1797,7 +2330,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) { ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); + ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy; ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); @@ -1821,10 +2354,12 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa int const nbRows = (int)size / ZSTD_ROWSIZE; int cellNb = 0; int rowNb; + /* Protect special index values < ZSTD_WINDOW_START_INDEX. */ + U32 const reducerThreshold = reducerValue + ZSTD_WINDOW_START_INDEX; assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ assert(size < (1U<<31)); /* can be casted to int */ -#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) +#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) /* To validate that the table re-use logic is sound, and that we don't * access table space that we haven't cleaned, we re-"poison" the table * space every time we mark it dirty. @@ -1840,12 +2375,17 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa for (rowNb=0 ; rowNb < nbRows ; rowNb++) { int column; for (column=0; columnhashTable, hSize, reducerValue); } - if (params->cParams.strategy != ZSTD_fast) { + if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) { U32 const chainSize = (U32)1 << params->cParams.chainLog; if (params->cParams.strategy == ZSTD_btlazy2) ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); @@ -1889,16 +2429,6 @@ static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* par /* See doc/zstd_compression_format.md for detailed format description */ -static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) -{ - U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); - RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, - dstSize_tooSmall); - MEM_writeLE24(dst, cBlockHeader24); - memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); - return ZSTD_blockHeaderSize + srcSize; -} - void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) { const seqDef* const sequences = seqStorePtr->sequencesStart; @@ -1910,36 +2440,182 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) assert(nbSeq <= seqStorePtr->maxNbSeq); for (u=0; ulongLengthID==1) + if (seqStorePtr->longLengthType==ZSTD_llt_literalLength) llCodeTable[seqStorePtr->longLengthPos] = MaxLL; - if (seqStorePtr->longLengthID==2) + if (seqStorePtr->longLengthType==ZSTD_llt_matchLength) mlCodeTable[seqStorePtr->longLengthPos] = MaxML; } -static int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams) +/* ZSTD_useTargetCBlockSize(): + * Returns if target compressed block size param is being used. + * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize. + * Returns 1 if true, 0 otherwise. */ +static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams) { - switch (cctxParams->literalCompressionMode) { - case ZSTD_lcm_huffman: - return 0; - case ZSTD_lcm_uncompressed: - return 1; - default: - assert(0 /* impossible: pre-validated */); - /* fall-through */ - case ZSTD_lcm_auto: - return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); - } + DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize); + return (cctxParams->targetCBlockSize != 0); +} + +/* ZSTD_blockSplitterEnabled(): + * Returns if block splitting param is being used + * If used, compression will do best effort to split a block in order to improve compression ratio. + * At the time this function is called, the parameter must be finalized. + * Returns 1 if true, 0 otherwise. */ +static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams) +{ + DEBUGLOG(5, "ZSTD_blockSplitterEnabled (useBlockSplitter=%d)", cctxParams->useBlockSplitter); + assert(cctxParams->useBlockSplitter != ZSTD_ps_auto); + return (cctxParams->useBlockSplitter == ZSTD_ps_enable); +} + +/* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types + * and size of the sequences statistics + */ +typedef struct { + U32 LLtype; + U32 Offtype; + U32 MLtype; + size_t size; + size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ +} ZSTD_symbolEncodingTypeStats_t; + +/* ZSTD_buildSequencesStatistics(): + * Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field. + * Modifies `nextEntropy` to have the appropriate values as a side effect. + * nbSeq must be greater than 0. + * + * entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32) + */ +static ZSTD_symbolEncodingTypeStats_t +ZSTD_buildSequencesStatistics(seqStore_t* seqStorePtr, size_t nbSeq, + const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy, + BYTE* dst, const BYTE* const dstEnd, + ZSTD_strategy strategy, unsigned* countWorkspace, + void* entropyWorkspace, size_t entropyWkspSize) { + BYTE* const ostart = dst; + const BYTE* const oend = dstEnd; + BYTE* op = ostart; + FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; + FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; + FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; + const BYTE* const ofCodeTable = seqStorePtr->ofCode; + const BYTE* const llCodeTable = seqStorePtr->llCode; + const BYTE* const mlCodeTable = seqStorePtr->mlCode; + ZSTD_symbolEncodingTypeStats_t stats; + + stats.lastCountSize = 0; + /* convert length/distances into codes */ + ZSTD_seqToCodes(seqStorePtr); + assert(op <= oend); + assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */ + /* build CTable for Literal Lengths */ + { unsigned max = MaxLL; + size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + DEBUGLOG(5, "Building LL table"); + nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; + stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, + countWorkspace, max, mostFrequent, nbSeq, + LLFSELog, prevEntropy->litlengthCTable, + LL_defaultNorm, LL_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(set_basic < set_compressed && set_rle < set_compressed); + assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype, + countWorkspace, max, llCodeTable, nbSeq, + LL_defaultNorm, LL_defaultNormLog, MaxLL, + prevEntropy->litlengthCTable, + sizeof(prevEntropy->litlengthCTable), + entropyWorkspace, entropyWkspSize); + if (ZSTD_isError(countSize)) { + DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed"); + stats.size = countSize; + return stats; + } + if (stats.LLtype == set_compressed) + stats.lastCountSize = countSize; + op += countSize; + assert(op <= oend); + } } + /* build CTable for Offsets */ + { unsigned max = MaxOff; + size_t const mostFrequent = HIST_countFast_wksp( + countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ + ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; + DEBUGLOG(5, "Building OF table"); + nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; + stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, + countWorkspace, max, mostFrequent, nbSeq, + OffFSELog, prevEntropy->offcodeCTable, + OF_defaultNorm, OF_defaultNormLog, + defaultPolicy, strategy); + assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype, + countWorkspace, max, ofCodeTable, nbSeq, + OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, + prevEntropy->offcodeCTable, + sizeof(prevEntropy->offcodeCTable), + entropyWorkspace, entropyWkspSize); + if (ZSTD_isError(countSize)) { + DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed"); + stats.size = countSize; + return stats; + } + if (stats.Offtype == set_compressed) + stats.lastCountSize = countSize; + op += countSize; + assert(op <= oend); + } } + /* build CTable for MatchLengths */ + { unsigned max = MaxML; + size_t const mostFrequent = HIST_countFast_wksp( + countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); + nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; + stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, + countWorkspace, max, mostFrequent, nbSeq, + MLFSELog, prevEntropy->matchlengthCTable, + ML_defaultNorm, ML_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype, + countWorkspace, max, mlCodeTable, nbSeq, + ML_defaultNorm, ML_defaultNormLog, MaxML, + prevEntropy->matchlengthCTable, + sizeof(prevEntropy->matchlengthCTable), + entropyWorkspace, entropyWkspSize); + if (ZSTD_isError(countSize)) { + DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed"); + stats.size = countSize; + return stats; + } + if (stats.MLtype == set_compressed) + stats.lastCountSize = countSize; + op += countSize; + assert(op <= oend); + } } + stats.size = (size_t)(op-ostart); + return stats; } -/* ZSTD_compressSequences_internal(): - * actually compresses both literals and sequences */ +/* ZSTD_entropyCompressSeqStore_internal(): + * compresses both literals and sequences + * Returns compressed size of block, or a zstd error. + */ +#define SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO 20 MEM_STATIC size_t -ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, +ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr, const ZSTD_entropyCTables_t* prevEntropy, ZSTD_entropyCTables_t* nextEntropy, const ZSTD_CCtx_params* cctxParams, @@ -1949,44 +2625,50 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, { const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; ZSTD_strategy const strategy = cctxParams->cParams.strategy; - unsigned count[MaxSeq+1]; + unsigned* count = (unsigned*)entropyWorkspace; FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; - U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ const seqDef* const sequences = seqStorePtr->sequencesStart; + const size_t nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; const BYTE* const ofCodeTable = seqStorePtr->ofCode; const BYTE* const llCodeTable = seqStorePtr->llCode; const BYTE* const mlCodeTable = seqStorePtr->mlCode; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstCapacity; BYTE* op = ostart; - size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - BYTE* seqHead; - BYTE* lastNCount = NULL; + size_t lastCountSize; + + entropyWorkspace = count + (MaxSeq + 1); + entropyWkspSize -= (MaxSeq + 1) * sizeof(*count); - DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq); + DEBUGLOG(5, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu, dstCapacity=%zu)", nbSeq, dstCapacity); ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= HUF_WORKSPACE_SIZE); /* Compress literals */ { const BYTE* const literals = seqStorePtr->litStart; + size_t const numSequences = seqStorePtr->sequences - seqStorePtr->sequencesStart; + size_t const numLiterals = seqStorePtr->lit - seqStorePtr->litStart; + /* Base suspicion of uncompressibility on ratio of literals to sequences */ + unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO); size_t const litSize = (size_t)(seqStorePtr->lit - literals); size_t const cSize = ZSTD_compressLiterals( &prevEntropy->huf, &nextEntropy->huf, cctxParams->cParams.strategy, - ZSTD_disableLiteralsCompression(cctxParams), + ZSTD_literalsCompressionIsDisabled(cctxParams), op, dstCapacity, literals, litSize, entropyWorkspace, entropyWkspSize, - bmi2); - FORWARD_IF_ERROR(cSize); + bmi2, suspectUncompressible); + FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed"); assert(cSize <= dstCapacity); op += cSize; } /* Sequences Header */ RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, - dstSize_tooSmall); + dstSize_tooSmall, "Can't fit seq hdr in output buf!"); if (nbSeq < 128) { *op++ = (BYTE)nbSeq; } else if (nbSeq < LONGNBSEQ) { @@ -2001,98 +2683,22 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, assert(op <= oend); if (nbSeq==0) { /* Copy the old tables over as if we repeated them */ - memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); + ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); return (size_t)(op - ostart); } - - /* seqHead : flags for FSE encoding type */ - seqHead = op++; - assert(op <= oend); - - /* convert length/distances into codes */ - ZSTD_seqToCodes(seqStorePtr); - /* build CTable for Literal Lengths */ - { unsigned max = MaxLL; - size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - DEBUGLOG(5, "Building LL table"); - nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; - LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, - count, max, mostFrequent, nbSeq, - LLFSELog, prevEntropy->fse.litlengthCTable, - LL_defaultNorm, LL_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(set_basic < set_compressed && set_rle < set_compressed); - assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, - count, max, llCodeTable, nbSeq, - LL_defaultNorm, LL_defaultNormLog, MaxLL, - prevEntropy->fse.litlengthCTable, - sizeof(prevEntropy->fse.litlengthCTable), - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(countSize); - if (LLtype == set_compressed) - lastNCount = op; - op += countSize; - assert(op <= oend); - } } - /* build CTable for Offsets */ - { unsigned max = MaxOff; - size_t const mostFrequent = HIST_countFast_wksp( - count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ - ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; - DEBUGLOG(5, "Building OF table"); - nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; - Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, - count, max, mostFrequent, nbSeq, - OffFSELog, prevEntropy->fse.offcodeCTable, - OF_defaultNorm, OF_defaultNormLog, - defaultPolicy, strategy); - assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, - count, max, ofCodeTable, nbSeq, - OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, - prevEntropy->fse.offcodeCTable, - sizeof(prevEntropy->fse.offcodeCTable), - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(countSize); - if (Offtype == set_compressed) - lastNCount = op; - op += countSize; - assert(op <= oend); - } } - /* build CTable for MatchLengths */ - { unsigned max = MaxML; - size_t const mostFrequent = HIST_countFast_wksp( - count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); - nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; - MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, - count, max, mostFrequent, nbSeq, - MLFSELog, prevEntropy->fse.matchlengthCTable, - ML_defaultNorm, ML_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, - count, max, mlCodeTable, nbSeq, - ML_defaultNorm, ML_defaultNormLog, MaxML, - prevEntropy->fse.matchlengthCTable, - sizeof(prevEntropy->fse.matchlengthCTable), - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(countSize); - if (MLtype == set_compressed) - lastNCount = op; - op += countSize; - assert(op <= oend); - } } - - *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); + { BYTE* const seqHead = op++; + /* build stats for sequences */ + const ZSTD_symbolEncodingTypeStats_t stats = + ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, + &prevEntropy->fse, &nextEntropy->fse, + op, oend, + strategy, count, + entropyWorkspace, entropyWkspSize); + FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); + *seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2)); + lastCountSize = stats.lastCountSize; + op += stats.size; + } { size_t const bitstreamSize = ZSTD_encodeSequences( op, (size_t)(oend - op), @@ -2101,7 +2707,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, CTable_LitLength, llCodeTable, sequences, nbSeq, longOffsets, bmi2); - FORWARD_IF_ERROR(bitstreamSize); + FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); op += bitstreamSize; assert(op <= oend); /* zstd versions <= 1.3.4 mistakenly report corruption when @@ -2112,9 +2718,9 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, * In this exceedingly rare case, we will simply emit an uncompressed * block, since it isn't worth optimizing. */ - if (lastNCount && (op - lastNCount) < 4) { - /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ - assert(op - lastNCount == 3); + if (lastCountSize && (lastCountSize + bitstreamSize) < 4) { + /* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ + assert(lastCountSize + bitstreamSize == 3); DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " "emitting an uncompressed block."); return 0; @@ -2126,7 +2732,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, } MEM_STATIC size_t -ZSTD_compressSequences(seqStore_t* seqStorePtr, +ZSTD_entropyCompressSeqStore(seqStore_t* seqStorePtr, const ZSTD_entropyCTables_t* prevEntropy, ZSTD_entropyCTables_t* nextEntropy, const ZSTD_CCtx_params* cctxParams, @@ -2135,7 +2741,7 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr, void* entropyWorkspace, size_t entropyWkspSize, int bmi2) { - size_t const cSize = ZSTD_compressSequences_internal( + size_t const cSize = ZSTD_entropyCompressSeqStore_internal( seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity, entropyWorkspace, entropyWkspSize, bmi2); @@ -2143,24 +2749,26 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr, /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. */ - if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) + if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) { + DEBUGLOG(4, "not enough dstCapacity (%zu) for ZSTD_entropyCompressSeqStore_internal()=> do not compress block", dstCapacity); return 0; /* block not compressed */ - FORWARD_IF_ERROR(cSize); + } + FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed"); /* Check compressibility */ { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); if (cSize >= maxCSize) return 0; /* block not compressed */ } - + DEBUGLOG(5, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize); return cSize; } /* ZSTD_selectBlockCompressor() : * Not static, but internal use only (used by long distance matcher) * assumption : strat is a valid strategy */ -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e useRowMatchFinder, ZSTD_dictMode_e dictMode) { - static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = { + static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = { { ZSTD_compressBlock_fast /* default for 0 */, ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, @@ -2190,13 +2798,44 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo ZSTD_compressBlock_btlazy2_dictMatchState, ZSTD_compressBlock_btopt_dictMatchState, ZSTD_compressBlock_btultra_dictMatchState, - ZSTD_compressBlock_btultra_dictMatchState } + ZSTD_compressBlock_btultra_dictMatchState }, + { NULL /* default for 0 */, + NULL, + NULL, + ZSTD_compressBlock_greedy_dedicatedDictSearch, + ZSTD_compressBlock_lazy_dedicatedDictSearch, + ZSTD_compressBlock_lazy2_dedicatedDictSearch, + NULL, + NULL, + NULL, + NULL } }; ZSTD_blockCompressor selectedCompressor; ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); - selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; + DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder); + if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) { + static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = { + { ZSTD_compressBlock_greedy_row, + ZSTD_compressBlock_lazy_row, + ZSTD_compressBlock_lazy2_row }, + { ZSTD_compressBlock_greedy_extDict_row, + ZSTD_compressBlock_lazy_extDict_row, + ZSTD_compressBlock_lazy2_extDict_row }, + { ZSTD_compressBlock_greedy_dictMatchState_row, + ZSTD_compressBlock_lazy_dictMatchState_row, + ZSTD_compressBlock_lazy2_dictMatchState_row }, + { ZSTD_compressBlock_greedy_dedicatedDictSearch_row, + ZSTD_compressBlock_lazy_dedicatedDictSearch_row, + ZSTD_compressBlock_lazy2_dedicatedDictSearch_row } + }; + DEBUGLOG(4, "Selecting a row-based matchfinder"); + assert(useRowMatchFinder != ZSTD_ps_auto); + selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy]; + } else { + selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; + } assert(selectedCompressor != NULL); return selectedCompressor; } @@ -2204,7 +2843,7 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, const BYTE* anchor, size_t lastLLSize) { - memcpy(seqStorePtr->lit, anchor, lastLLSize); + ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -2212,7 +2851,7 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr) { ssPtr->lit = ssPtr->litStart; ssPtr->sequences = ssPtr->sequencesStart; - ssPtr->longLengthID = 0; + ssPtr->longLengthType = ZSTD_llt_none; } typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; @@ -2224,8 +2863,14 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) assert(srcSize <= ZSTD_BLOCKSIZE_MAX); /* Assert that we have correctly flushed the ctx params into the ms's copy */ ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); - if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { - ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); + /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding + * additional 1. We need to revisit and change this logic to be more consistent */ + if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { + if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) { + ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize); + } else { + ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); + } return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ } ZSTD_resetSeqStore(&(zc->seqStore)); @@ -2241,10 +2886,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) /* limited update after a very long match */ { const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const U32 current = (U32)(istart-base); + const U32 curr = (U32)(istart-base); if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ - if (current > ms->nextToUpdate + 384) - ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); + if (curr > ms->nextToUpdate + 384) + ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384)); } /* select and store sequences */ @@ -2255,32 +2900,37 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; } if (zc->externSeqStore.pos < zc->externSeqStore.size) { - assert(!zc->appliedParams.ldmParams.enableLdm); + assert(zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_disable); /* Updates ldmSeqStore.pos */ lastLLSize = ZSTD_ldm_blockCompress(&zc->externSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, + zc->appliedParams.useRowMatchFinder, src, srcSize); assert(zc->externSeqStore.pos <= zc->externSeqStore.size); - } else if (zc->appliedParams.ldmParams.enableLdm) { - rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; + } else if (zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { + rawSeqStore_t ldmSeqStore = kNullRawSeqStore; ldmSeqStore.seq = zc->ldmSequences; ldmSeqStore.capacity = zc->maxNbLdmSequences; /* Updates ldmSeqStore.size */ FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, &zc->appliedParams.ldmParams, - src, srcSize)); + src, srcSize), ""); /* Updates ldmSeqStore.pos */ lastLLSize = ZSTD_ldm_blockCompress(&ldmSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, + zc->appliedParams.useRowMatchFinder, src, srcSize); assert(ldmSeqStore.pos == ldmSeqStore.size); } else { /* not long range mode */ - ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); + ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, + zc->appliedParams.useRowMatchFinder, + dictMode); + ms->ldmSeqStore = NULL; lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); } { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; @@ -2292,62 +2942,75 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc) { const seqStore_t* seqStore = ZSTD_getSeqStore(zc); - const seqDef* seqs = seqStore->sequencesStart; - size_t seqsSize = seqStore->sequences - seqs; + const seqDef* seqStoreSeqs = seqStore->sequencesStart; + size_t seqStoreSeqSize = seqStore->sequences - seqStoreSeqs; + size_t seqStoreLiteralsSize = (size_t)(seqStore->lit - seqStore->litStart); + size_t literalsRead = 0; + size_t lastLLSize; ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex]; - size_t i; size_t position; int repIdx; + size_t i; + repcodes_t updatedRepcodes; assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences); - for (i = 0, position = 0; i < seqsSize; ++i) { - outSeqs[i].offset = seqs[i].offset; - outSeqs[i].litLength = seqs[i].litLength; - outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH; + /* Ensure we have enough space for last literals "sequence" */ + assert(zc->seqCollector.maxSequences >= seqStoreSeqSize + 1); + ZSTD_memcpy(updatedRepcodes.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); + for (i = 0; i < seqStoreSeqSize; ++i) { + U32 rawOffset = seqStoreSeqs[i].offBase - ZSTD_REP_NUM; + outSeqs[i].litLength = seqStoreSeqs[i].litLength; + outSeqs[i].matchLength = seqStoreSeqs[i].mlBase + MINMATCH; + outSeqs[i].rep = 0; if (i == seqStore->longLengthPos) { - if (seqStore->longLengthID == 1) { + if (seqStore->longLengthType == ZSTD_llt_literalLength) { outSeqs[i].litLength += 0x10000; - } else if (seqStore->longLengthID == 2) { + } else if (seqStore->longLengthType == ZSTD_llt_matchLength) { outSeqs[i].matchLength += 0x10000; } } - if (outSeqs[i].offset <= ZSTD_REP_NUM) { - outSeqs[i].rep = outSeqs[i].offset; - repIdx = (unsigned int)i - outSeqs[i].offset; - - if (outSeqs[i].litLength == 0) { - if (outSeqs[i].offset < 3) { - --repIdx; + if (seqStoreSeqs[i].offBase <= ZSTD_REP_NUM) { + /* Derive the correct offset corresponding to a repcode */ + outSeqs[i].rep = seqStoreSeqs[i].offBase; + if (outSeqs[i].litLength != 0) { + rawOffset = updatedRepcodes.rep[outSeqs[i].rep - 1]; + } else { + if (outSeqs[i].rep == 3) { + rawOffset = updatedRepcodes.rep[0] - 1; } else { - repIdx = (unsigned int)i - 1; + rawOffset = updatedRepcodes.rep[outSeqs[i].rep]; } - ++outSeqs[i].rep; } - assert(repIdx >= -3); - outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1]; - if (outSeqs[i].rep == 4) { - --outSeqs[i].offset; - } - } else { - outSeqs[i].offset -= ZSTD_REP_NUM; } - - position += outSeqs[i].litLength; - outSeqs[i].matchPos = (unsigned int)position; - position += outSeqs[i].matchLength; + outSeqs[i].offset = rawOffset; + /* seqStoreSeqs[i].offset == offCode+1, and ZSTD_updateRep() expects offCode + so we provide seqStoreSeqs[i].offset - 1 */ + ZSTD_updateRep(updatedRepcodes.rep, + seqStoreSeqs[i].offBase, + seqStoreSeqs[i].litLength == 0); + literalsRead += outSeqs[i].litLength; } - zc->seqCollector.seqIndex += seqsSize; + /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0. + * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker + * for the block boundary, according to the API. + */ + assert(seqStoreLiteralsSize >= literalsRead); + lastLLSize = seqStoreLiteralsSize - literalsRead; + outSeqs[i].litLength = (U32)lastLLSize; + outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0; + seqStoreSeqSize++; + zc->seqCollector.seqIndex += seqStoreSeqSize; } -size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, - size_t outSeqsSize, const void* src, size_t srcSize) +size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize) { const size_t dstCapacity = ZSTD_compressBound(srcSize); - void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem); + void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem); SeqCollector seqCollector; - RETURN_ERROR_IF(dst == NULL, memory_allocation); + RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!"); seqCollector.collectSequences = 1; seqCollector.seqStart = outSeqs; @@ -2356,27 +3019,805 @@ size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, zc->seqCollector = seqCollector; ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); - ZSTD_free(dst, ZSTD_defaultCMem); + ZSTD_customFree(dst, ZSTD_defaultCMem); return zc->seqCollector.seqIndex; } -/* Returns true if the given block is a RLE block */ -static int ZSTD_isRLE(const BYTE *ip, size_t length) { +size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) { + size_t in = 0; + size_t out = 0; + for (; in < seqsSize; ++in) { + if (sequences[in].offset == 0 && sequences[in].matchLength == 0) { + if (in != seqsSize - 1) { + sequences[in+1].litLength += sequences[in].litLength; + } + } else { + sequences[out] = sequences[in]; + ++out; + } + } + return out; +} + +/* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */ +static int ZSTD_isRLE(const BYTE* src, size_t length) { + const BYTE* ip = src; + const BYTE value = ip[0]; + const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL); + const size_t unrollSize = sizeof(size_t) * 4; + const size_t unrollMask = unrollSize - 1; + const size_t prefixLength = length & unrollMask; size_t i; - if (length < 2) return 1; - for (i = 1; i < length; ++i) { - if (ip[0] != ip[i]) return 0; + size_t u; + if (length == 1) return 1; + /* Check if prefix is RLE first before using unrolled loop */ + if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) { + return 0; + } + for (i = prefixLength; i != length; i += unrollSize) { + for (u = 0; u < unrollSize; u += sizeof(size_t)) { + if (MEM_readST(ip + i + u) != valueST) { + return 0; + } + } } return 1; } -static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, U32 frame) +/* Returns true if the given block may be RLE. + * This is just a heuristic based on the compressibility. + * It may return both false positives and false negatives. + */ +static int ZSTD_maybeRLE(seqStore_t const* seqStore) +{ + size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); + size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart); + + return nbSeqs < 4 && nbLits < 10; +} + +static void ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs) +{ + ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock; + bs->prevCBlock = bs->nextCBlock; + bs->nextCBlock = tmp; +} + +/* Writes the block header */ +static void writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) { + U32 const cBlockHeader = cSize == 1 ? + lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : + lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); + MEM_writeLE24(op, cBlockHeader); + DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock); +} + +/** ZSTD_buildBlockEntropyStats_literals() : + * Builds entropy for the literals. + * Stores literals block type (raw, rle, compressed, repeat) and + * huffman description table to hufMetadata. + * Requires ENTROPY_WORKSPACE_SIZE workspace + * @return : size of huffman description table or error code */ +static size_t ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize, + const ZSTD_hufCTables_t* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_hufCTablesMetadata_t* hufMetadata, + const int literalsCompressionIsDisabled, + void* workspace, size_t wkspSize) +{ + BYTE* const wkspStart = (BYTE*)workspace; + BYTE* const wkspEnd = wkspStart + wkspSize; + BYTE* const countWkspStart = wkspStart; + unsigned* const countWksp = (unsigned*)workspace; + const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); + BYTE* const nodeWksp = countWkspStart + countWkspSize; + const size_t nodeWkspSize = (size_t)(wkspEnd - nodeWksp); + unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; + unsigned huffLog = LitHufLog; + HUF_repeat repeat = prevHuf->repeatMode; + DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize); + + /* Prepare nextEntropy assuming reusing the existing table */ + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + + if (literalsCompressionIsDisabled) { + DEBUGLOG(5, "set_basic - disabled"); + hufMetadata->hType = set_basic; + return 0; + } + + /* small ? don't even attempt compression (speed opt) */ +#ifndef COMPRESS_LITERALS_SIZE_MIN +#define COMPRESS_LITERALS_SIZE_MIN 63 +#endif + { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; + if (srcSize <= minLitSize) { + DEBUGLOG(5, "set_basic - too small"); + hufMetadata->hType = set_basic; + return 0; + } + } + + /* Scan input and build symbol stats */ + { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize); + FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); + if (largest == srcSize) { + DEBUGLOG(5, "set_rle"); + hufMetadata->hType = set_rle; + return 0; + } + if (largest <= (srcSize >> 7)+4) { + DEBUGLOG(5, "set_basic - no gain"); + hufMetadata->hType = set_basic; + return 0; + } + } + + /* Validate the previous Huffman table */ + if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { + repeat = HUF_repeat_none; + } + + /* Build Huffman Tree */ + ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); + huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); + assert(huffLog <= LitHufLog); + { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, + maxSymbolValue, huffLog, + nodeWksp, nodeWkspSize); + FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); + huffLog = (U32)maxBits; + { /* Build and write the CTable */ + size_t const newCSize = HUF_estimateCompressedSize( + (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); + size_t const hSize = HUF_writeCTable_wksp( + hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), + (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog, + nodeWksp, nodeWkspSize); + /* Check against repeating the previous CTable */ + if (repeat != HUF_repeat_none) { + size_t const oldCSize = HUF_estimateCompressedSize( + (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); + if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { + DEBUGLOG(5, "set_repeat - smaller"); + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + hufMetadata->hType = set_repeat; + return 0; + } + } + if (newCSize + hSize >= srcSize) { + DEBUGLOG(5, "set_basic - no gains"); + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + hufMetadata->hType = set_basic; + return 0; + } + DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); + hufMetadata->hType = set_compressed; + nextHuf->repeatMode = HUF_repeat_check; + return hSize; + } + } +} + + +/* ZSTD_buildDummySequencesStatistics(): + * Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic, + * and updates nextEntropy to the appropriate repeatMode. + */ +static ZSTD_symbolEncodingTypeStats_t +ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) { + ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0}; + nextEntropy->litlength_repeatMode = FSE_repeat_none; + nextEntropy->offcode_repeatMode = FSE_repeat_none; + nextEntropy->matchlength_repeatMode = FSE_repeat_none; + return stats; +} + +/** ZSTD_buildBlockEntropyStats_sequences() : + * Builds entropy for the sequences. + * Stores symbol compression modes and fse table to fseMetadata. + * Requires ENTROPY_WORKSPACE_SIZE wksp. + * @return : size of fse tables or error code */ +static size_t ZSTD_buildBlockEntropyStats_sequences(seqStore_t* seqStorePtr, + const ZSTD_fseCTables_t* prevEntropy, + ZSTD_fseCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_fseCTablesMetadata_t* fseMetadata, + void* workspace, size_t wkspSize) +{ + ZSTD_strategy const strategy = cctxParams->cParams.strategy; + size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; + BYTE* const ostart = fseMetadata->fseTablesBuffer; + BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); + BYTE* op = ostart; + unsigned* countWorkspace = (unsigned*)workspace; + unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1); + size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace); + ZSTD_symbolEncodingTypeStats_t stats; + + DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq); + stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, + prevEntropy, nextEntropy, op, oend, + strategy, countWorkspace, + entropyWorkspace, entropyWorkspaceSize) + : ZSTD_buildDummySequencesStatistics(nextEntropy); + FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); + fseMetadata->llType = (symbolEncodingType_e) stats.LLtype; + fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype; + fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype; + fseMetadata->lastCountSize = stats.lastCountSize; + return stats.size; +} + + +/** ZSTD_buildBlockEntropyStats() : + * Builds entropy for the block. + * Requires workspace size ENTROPY_WORKSPACE_SIZE + * + * @return : 0 on success or error code + */ +size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize) +{ + size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart; + entropyMetadata->hufMetadata.hufDesSize = + ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize, + &prevEntropy->huf, &nextEntropy->huf, + &entropyMetadata->hufMetadata, + ZSTD_literalsCompressionIsDisabled(cctxParams), + workspace, wkspSize); + FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed"); + entropyMetadata->fseMetadata.fseTablesSize = + ZSTD_buildBlockEntropyStats_sequences(seqStorePtr, + &prevEntropy->fse, &nextEntropy->fse, + cctxParams, + &entropyMetadata->fseMetadata, + workspace, wkspSize); + FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed"); + return 0; +} + +/* Returns the size estimate for the literals section (header + content) of a block */ +static size_t ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize, + const ZSTD_hufCTables_t* huf, + const ZSTD_hufCTablesMetadata_t* hufMetadata, + void* workspace, size_t wkspSize, + int writeEntropy) +{ + unsigned* const countWksp = (unsigned*)workspace; + unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; + size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB); + U32 singleStream = litSize < 256; + + if (hufMetadata->hType == set_basic) return litSize; + else if (hufMetadata->hType == set_rle) return 1; + else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { + size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); + if (ZSTD_isError(largest)) return litSize; + { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); + if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; + if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */ + return cLitSizeEstimate + literalSectionHeaderSize; + } } + assert(0); /* impossible */ + return 0; +} + +/* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */ +static size_t ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type, + const BYTE* codeTable, size_t nbSeq, unsigned maxCode, + const FSE_CTable* fseCTable, + const U8* additionalBits, + short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, + void* workspace, size_t wkspSize) +{ + unsigned* const countWksp = (unsigned*)workspace; + const BYTE* ctp = codeTable; + const BYTE* const ctStart = ctp; + const BYTE* const ctEnd = ctStart + nbSeq; + size_t cSymbolTypeSizeEstimateInBits = 0; + unsigned max = maxCode; + + HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ + if (type == set_basic) { + /* We selected this encoding type, so it must be valid. */ + assert(max <= defaultMax); + (void)defaultMax; + cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); + } else if (type == set_rle) { + cSymbolTypeSizeEstimateInBits = 0; + } else if (type == set_compressed || type == set_repeat) { + cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); + } + if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) { + return nbSeq * 10; + } + while (ctp < ctEnd) { + if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; + else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ + ctp++; + } + return cSymbolTypeSizeEstimateInBits >> 3; +} + +/* Returns the size estimate for the sequences section (header + content) of a block */ +static size_t ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable, + const BYTE* llCodeTable, + const BYTE* mlCodeTable, + size_t nbSeq, + const ZSTD_fseCTables_t* fseTables, + const ZSTD_fseCTablesMetadata_t* fseMetadata, + void* workspace, size_t wkspSize, + int writeEntropy) +{ + size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ); + size_t cSeqSizeEstimate = 0; + cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff, + fseTables->offcodeCTable, NULL, + OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, + workspace, wkspSize); + cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL, + fseTables->litlengthCTable, LL_bits, + LL_defaultNorm, LL_defaultNormLog, MaxLL, + workspace, wkspSize); + cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML, + fseTables->matchlengthCTable, ML_bits, + ML_defaultNorm, ML_defaultNormLog, MaxML, + workspace, wkspSize); + if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; + return cSeqSizeEstimate + sequencesSectionHeaderSize; +} + +/* Returns the size estimate for a given stream of literals, of, ll, ml */ +static size_t ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize, + const BYTE* ofCodeTable, + const BYTE* llCodeTable, + const BYTE* mlCodeTable, + size_t nbSeq, + const ZSTD_entropyCTables_t* entropy, + const ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize, + int writeLitEntropy, int writeSeqEntropy) { + size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize, + &entropy->huf, &entropyMetadata->hufMetadata, + workspace, wkspSize, writeLitEntropy); + size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, + nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, + workspace, wkspSize, writeSeqEntropy); + return seqSize + literalsSize + ZSTD_blockHeaderSize; +} + +/* Builds entropy statistics and uses them for blocksize estimation. + * + * Returns the estimated compressed size of the seqStore, or a zstd error. + */ +static size_t ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, ZSTD_CCtx* zc) { + ZSTD_entropyCTablesMetadata_t* entropyMetadata = &zc->blockSplitCtx.entropyMetadata; + DEBUGLOG(6, "ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize()"); + FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore, + &zc->blockState.prevCBlock->entropy, + &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + entropyMetadata, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); + return ZSTD_estimateBlockSize(seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart), + seqStore->ofCode, seqStore->llCode, seqStore->mlCode, + (size_t)(seqStore->sequences - seqStore->sequencesStart), + &zc->blockState.nextCBlock->entropy, entropyMetadata, zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE, + (int)(entropyMetadata->hufMetadata.hType == set_compressed), 1); +} + +/* Returns literals bytes represented in a seqStore */ +static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) { + size_t literalsBytes = 0; + size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart; + size_t i; + for (i = 0; i < nbSeqs; ++i) { + seqDef seq = seqStore->sequencesStart[i]; + literalsBytes += seq.litLength; + if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) { + literalsBytes += 0x10000; + } + } + return literalsBytes; +} + +/* Returns match bytes represented in a seqStore */ +static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) { + size_t matchBytes = 0; + size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart; + size_t i; + for (i = 0; i < nbSeqs; ++i) { + seqDef seq = seqStore->sequencesStart[i]; + matchBytes += seq.mlBase + MINMATCH; + if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) { + matchBytes += 0x10000; + } + } + return matchBytes; +} + +/* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx). + * Stores the result in resultSeqStore. + */ +static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore, + const seqStore_t* originalSeqStore, + size_t startIdx, size_t endIdx) +{ + *resultSeqStore = *originalSeqStore; + if (startIdx > 0) { + resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx; + resultSeqStore->litStart += ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); + } + + /* Move longLengthPos into the correct position if necessary */ + if (originalSeqStore->longLengthType != ZSTD_llt_none) { + if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) { + resultSeqStore->longLengthType = ZSTD_llt_none; + } else { + resultSeqStore->longLengthPos -= (U32)startIdx; + } + } + resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx; + resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx; + if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) { + /* This accounts for possible last literals if the derived chunk reaches the end of the block */ + assert(resultSeqStore->lit == originalSeqStore->lit); + } else { + size_t const literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); + resultSeqStore->lit = resultSeqStore->litStart + literalsBytes; + } + resultSeqStore->llCode += startIdx; + resultSeqStore->mlCode += startIdx; + resultSeqStore->ofCode += startIdx; +} + +/** + * Returns the raw offset represented by the combination of offBase, ll0, and repcode history. + * offBase must represent a repcode in the numeric representation of ZSTD_storeSeq(). + */ +static U32 +ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offBase, const U32 ll0) +{ + U32 const adjustedRepCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; /* [ 0 - 3 ] */ + assert(OFFBASE_IS_REPCODE(offBase)); + if (adjustedRepCode == ZSTD_REP_NUM) { + /* litlength == 0 and offCode == 2 implies selection of first repcode - 1 + * This is only valid if it results in a valid offset value, aka > 0. + * Note : it may happen that `rep[0]==1` in exceptional circumstances. + * In which case this function will return 0, which is an invalid offset. + * It's not an issue though, since this value will be + * compared and discarded within ZSTD_seqStore_resolveOffCodes(). + */ + return rep[0] - 1; + } + return rep[adjustedRepCode]; +} + +/** + * ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise + * due to emission of RLE/raw blocks that disturb the offset history, + * and replaces any repcodes within the seqStore that may be invalid. + * + * dRepcodes are updated as would be on the decompression side. + * cRepcodes are updated exactly in accordance with the seqStore. + * + * Note : this function assumes seq->offBase respects the following numbering scheme : + * 0 : invalid + * 1-3 : repcode 1-3 + * 4+ : real_offset+3 + */ +static void ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes, + seqStore_t* const seqStore, U32 const nbSeq) { + U32 idx = 0; + for (; idx < nbSeq; ++idx) { + seqDef* const seq = seqStore->sequencesStart + idx; + U32 const ll0 = (seq->litLength == 0); + U32 const offBase = seq->offBase; + assert(seq->offBase > 0); + if (OFFBASE_IS_REPCODE(offBase)) { + U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offBase, ll0); + U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offBase, ll0); + /* Adjust simulated decompression repcode history if we come across a mismatch. Replace + * the repcode with the offset it actually references, determined by the compression + * repcode history. + */ + if (dRawOffset != cRawOffset) { + seq->offBase = cRawOffset + ZSTD_REP_NUM; + } + } + /* Compression repcode history is always updated with values directly from the unmodified seqStore. + * Decompression repcode history may use modified seq->offset value taken from compression repcode history. + */ + ZSTD_updateRep(dRepcodes->rep, seq->offBase, ll0); + ZSTD_updateRep(cRepcodes->rep, offBase, ll0); + } +} + +/* ZSTD_compressSeqStore_singleBlock(): + * Compresses a seqStore into a block with a block header, into the buffer dst. + * + * Returns the total size of that block (including header) or a ZSTD error code. + */ +static size_t +ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, seqStore_t* const seqStore, + repcodes_t* const dRep, repcodes_t* const cRep, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + U32 lastBlock, U32 isPartition) +{ + const U32 rleMaxLength = 25; + BYTE* op = (BYTE*)dst; + const BYTE* ip = (const BYTE*)src; + size_t cSize; + size_t cSeqsSize; + + /* In case of an RLE or raw block, the simulated decompression repcode history must be reset */ + repcodes_t const dRepOriginal = *dRep; + DEBUGLOG(5, "ZSTD_compressSeqStore_singleBlock"); + if (isPartition) + ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart)); + + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "Block header doesn't fit"); + cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore, + &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, + srcSize, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + zc->bmi2); + FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!"); + + if (!zc->isFirstBlock && + cSeqsSize < rleMaxLength && + ZSTD_isRLE((BYTE const*)src, srcSize)) { + /* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + cSeqsSize = 1; + } + + if (zc->seqCollector.collectSequences) { + ZSTD_copyBlockSequences(zc); + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + return 0; + } + + if (cSeqsSize == 0) { + cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock); + FORWARD_IF_ERROR(cSize, "Nocompress block failed"); + DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize); + *dRep = dRepOriginal; /* reset simulated decompression repcode history */ + } else if (cSeqsSize == 1) { + cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock); + FORWARD_IF_ERROR(cSize, "RLE compress block failed"); + DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize); + *dRep = dRepOriginal; /* reset simulated decompression repcode history */ + } else { + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + writeBlockHeader(op, cSeqsSize, srcSize, lastBlock); + cSize = ZSTD_blockHeaderSize + cSeqsSize; + DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize); + } + + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + + return cSize; +} + +/* Struct to keep track of where we are in our recursive calls. */ +typedef struct { + U32* splitLocations; /* Array of split indices */ + size_t idx; /* The current index within splitLocations being worked on */ +} seqStoreSplits; + +#define MIN_SEQUENCES_BLOCK_SPLITTING 300 + +/* Helper function to perform the recursive search for block splits. + * Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half. + * If advantageous to split, then we recurse down the two sub-blocks. If not, or if an error occurred in estimation, then + * we do not recurse. + * + * Note: The recursion depth is capped by a heuristic minimum number of sequences, defined by MIN_SEQUENCES_BLOCK_SPLITTING. + * In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING). + * In practice, recursion depth usually doesn't go beyond 4. + * + * Furthermore, the number of splits is capped by ZSTD_MAX_NB_BLOCK_SPLITS. + * At ZSTD_MAX_NB_BLOCK_SPLITS == 196 with the current existing blockSize + * maximum of 128 KB, this value is actually impossible to reach. + */ +static void +ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx, + ZSTD_CCtx* zc, const seqStore_t* origSeqStore) +{ + seqStore_t* fullSeqStoreChunk = &zc->blockSplitCtx.fullSeqStoreChunk; + seqStore_t* firstHalfSeqStore = &zc->blockSplitCtx.firstHalfSeqStore; + seqStore_t* secondHalfSeqStore = &zc->blockSplitCtx.secondHalfSeqStore; + size_t estimatedOriginalSize; + size_t estimatedFirstHalfSize; + size_t estimatedSecondHalfSize; + size_t midIdx = (startIdx + endIdx)/2; + + if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= ZSTD_MAX_NB_BLOCK_SPLITS) { + DEBUGLOG(6, "ZSTD_deriveBlockSplitsHelper: Too few sequences"); + return; + } + DEBUGLOG(5, "ZSTD_deriveBlockSplitsHelper: startIdx=%zu endIdx=%zu", startIdx, endIdx); + ZSTD_deriveSeqStoreChunk(fullSeqStoreChunk, origSeqStore, startIdx, endIdx); + ZSTD_deriveSeqStoreChunk(firstHalfSeqStore, origSeqStore, startIdx, midIdx); + ZSTD_deriveSeqStoreChunk(secondHalfSeqStore, origSeqStore, midIdx, endIdx); + estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(fullSeqStoreChunk, zc); + estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(firstHalfSeqStore, zc); + estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(secondHalfSeqStore, zc); + DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu", + estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize); + if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) { + return; + } + if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) { + DEBUGLOG(5, "split decided at seqNb:%zu", midIdx); + ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore); + splits->splitLocations[splits->idx] = (U32)midIdx; + splits->idx++; + ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore); + } +} + +/* Base recursive function. Populates a table with intra-block partition indices that can improve compression ratio. + * + * Returns the number of splits made (which equals the size of the partition table - 1). + */ +static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) +{ + seqStoreSplits splits = {partitions, 0}; + if (nbSeq <= 4) { + DEBUGLOG(5, "ZSTD_deriveBlockSplits: Too few sequences to split"); + /* Refuse to try and split anything with less than 4 sequences */ + return 0; + } + ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore); + splits.splitLocations[splits.idx] = nbSeq; + DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1); + return splits.idx; +} + +/* ZSTD_compressBlock_splitBlock(): + * Attempts to split a given block into multiple blocks to improve compression ratio. + * + * Returns combined size of all blocks (which includes headers), or a ZSTD error code. + */ +static size_t +ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, + const void* src, size_t blockSize, U32 lastBlock, U32 nbSeq) +{ + size_t cSize = 0; + const BYTE* ip = (const BYTE*)src; + BYTE* op = (BYTE*)dst; + size_t i = 0; + size_t srcBytesTotal = 0; + U32* partitions = zc->blockSplitCtx.partitions; /* size == ZSTD_MAX_NB_BLOCK_SPLITS */ + seqStore_t* nextSeqStore = &zc->blockSplitCtx.nextSeqStore; + seqStore_t* currSeqStore = &zc->blockSplitCtx.currSeqStore; + size_t numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq); + + /* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history + * may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two + * separate repcode histories that simulate repcode history on compression and decompression side, + * and use the histories to determine whether we must replace a particular repcode with its raw offset. + * + * 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed + * or RLE. This allows us to retrieve the offset value that an invalid repcode references within + * a nocompress/RLE block. + * 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use + * the replacement offset value rather than the original repcode to update the repcode history. + * dRep also will be the final repcode history sent to the next block. + * + * See ZSTD_seqStore_resolveOffCodes() for more details. + */ + repcodes_t dRep; + repcodes_t cRep; + ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); + ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); + ZSTD_memset(nextSeqStore, 0, sizeof(seqStore_t)); + + DEBUGLOG(4, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", + (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, + (unsigned)zc->blockState.matchState.nextToUpdate); + + if (numSplits == 0) { + size_t cSizeSingleBlock = ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore, + &dRep, &cRep, + op, dstCapacity, + ip, blockSize, + lastBlock, 0 /* isPartition */); + FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!"); + DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits"); + assert(cSizeSingleBlock <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize); + return cSizeSingleBlock; + } + + ZSTD_deriveSeqStoreChunk(currSeqStore, &zc->seqStore, 0, partitions[0]); + for (i = 0; i <= numSplits; ++i) { + size_t cSizeChunk; + U32 const lastPartition = (i == numSplits); + U32 lastBlockEntireSrc = 0; + + size_t srcBytes = ZSTD_countSeqStoreLiteralsBytes(currSeqStore) + ZSTD_countSeqStoreMatchBytes(currSeqStore); + srcBytesTotal += srcBytes; + if (lastPartition) { + /* This is the final partition, need to account for possible last literals */ + srcBytes += blockSize - srcBytesTotal; + lastBlockEntireSrc = lastBlock; + } else { + ZSTD_deriveSeqStoreChunk(nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]); + } + + cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, currSeqStore, + &dRep, &cRep, + op, dstCapacity, + ip, srcBytes, + lastBlockEntireSrc, 1 /* isPartition */); + DEBUGLOG(5, "Estimated size: %zu actual size: %zu", ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(currSeqStore, zc), cSizeChunk); + FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!"); + + ip += srcBytes; + op += cSizeChunk; + dstCapacity -= cSizeChunk; + cSize += cSizeChunk; + *currSeqStore = *nextSeqStore; + assert(cSizeChunk <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize); + } + /* cRep and dRep may have diverged during the compression. If so, we use the dRep repcodes + * for the next block. + */ + ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t)); + return cSize; +} + +static size_t +ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, U32 lastBlock) { - /* This the upper bound for the length of an rle block. - * This isn't the actual upper bound. Finding the real threshold - * needs further investigation. + const BYTE* ip = (const BYTE*)src; + BYTE* op = (BYTE*)dst; + U32 nbSeq; + size_t cSize; + DEBUGLOG(4, "ZSTD_compressBlock_splitBlock"); + assert(zc->appliedParams.useBlockSplitter == ZSTD_ps_enable); + + { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); + FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); + if (bss == ZSTDbss_noCompress) { + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); + DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block"); + return cSize; + } + nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart); + } + + cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq); + FORWARD_IF_ERROR(cSize, "Splitting blocks failed!"); + return cSize; +} + +static size_t +ZSTD_compressBlock_internal(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, U32 frame) +{ + /* This is an estimated upper bound for the length of an rle block. + * This isn't the actual upper bound. + * Finding the real threshold needs further investigation. */ const U32 rleMaxLength = 25; size_t cSize; @@ -2387,22 +3828,23 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, (unsigned)zc->blockState.matchState.nextToUpdate); { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); - FORWARD_IF_ERROR(bss); + FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } } if (zc->seqCollector.collectSequences) { ZSTD_copyBlockSequences(zc); + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); return 0; } /* encode sequences and literals */ - cSize = ZSTD_compressSequences(&zc->seqStore, + cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore, &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, &zc->appliedParams, dst, dstCapacity, srcSize, - zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, zc->bmi2); if (frame && @@ -2420,10 +3862,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, out: if (!ZSTD_isError(cSize) && cSize > 1) { - /* confirm repcodes and entropy tables when emitting a compressed block */ - ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; - zc->blockState.prevCBlock = zc->blockState.nextCBlock; - zc->blockState.nextCBlock = tmp; + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); } /* We check that dictionaries have offset codes available for the first * block. After the first block, the offcode table might not have large @@ -2435,6 +3874,80 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, return cSize; } +static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const size_t bss, U32 lastBlock) +{ + DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()"); + if (bss == ZSTDbss_compress) { + if (/* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + !zc->isFirstBlock && + ZSTD_maybeRLE(&zc->seqStore) && + ZSTD_isRLE((BYTE const*)src, srcSize)) + { + return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock); + } + /* Attempt superblock compression. + * + * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the + * standard ZSTD_compressBound(). This is a problem, because even if we have + * space now, taking an extra byte now could cause us to run out of space later + * and violate ZSTD_compressBound(). + * + * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize. + * + * In order to respect ZSTD_compressBound() we must attempt to emit a raw + * uncompressed block in these cases: + * * cSize == 0: Return code for an uncompressed block. + * * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize). + * ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of + * output space. + * * cSize >= blockBound(srcSize): We have expanded the block too much so + * emit an uncompressed block. + */ + { + size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); + if (cSize != ERROR(dstSize_tooSmall)) { + size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); + FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed"); + if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) { + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + return cSize; + } + } + } + } + + DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()"); + /* Superblock compression failed, attempt to emit a single no compress block. + * The decoder will be able to stream this block since it is uncompressed. + */ + return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); +} + +static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + U32 lastBlock) +{ + size_t cSize = 0; + const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); + DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)", + (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize); + FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); + + cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed"); + + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + + return cSize; +} static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, ZSTD_cwksp* ws, @@ -2442,9 +3955,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, void const* ip, void const* iend) { - if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { - U32 const maxDist = (U32)1 << params->cParams.windowLog; - U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); + U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); + U32 const maxDist = (U32)1 << params->cParams.windowLog; + if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) { U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); @@ -2467,7 +3980,7 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, * Frame is supposed already started (header already produced) * @return : compressed size, or an error code */ -static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, +static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastFrameChunk) @@ -2478,9 +3991,10 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; + assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); - DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); + DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); if (cctx->appliedParams.fParams.checksumFlag && srcSize) XXH64_update(&cctx->xxhState, src, srcSize); @@ -2488,7 +4002,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, ZSTD_matchState_t* const ms = &cctx->blockState.matchState; U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, + /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding + * additional 1. We need to revisit and change this logic to be more consistent */ + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE + 1, dstSize_tooSmall, "not enough space to store compressed block"); if (remaining < blockSize) blockSize = remaining; @@ -2496,25 +4012,40 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, ZSTD_overflowCorrectIfNeeded( ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize); ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); + ZSTD_window_enforceMaxDist(&ms->window, ip, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; - { size_t cSize = ZSTD_compressBlock_internal(cctx, - op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, - ip, blockSize, 1 /* frame */); - FORWARD_IF_ERROR(cSize); - if (cSize == 0) { /* block is not compressible */ - cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cSize); + { size_t cSize; + if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) { + cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed"); + assert(cSize > 0); + assert(cSize <= blockSize + ZSTD_blockHeaderSize); + } else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) { + cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed"); + assert(cSize > 0 || cctx->seqCollector.collectSequences == 1); } else { - const U32 cBlockHeader = cSize == 1 ? - lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : - lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); - MEM_writeLE24(op, cBlockHeader); - cSize += ZSTD_blockHeaderSize; + cSize = ZSTD_compressBlock_internal(cctx, + op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, + ip, blockSize, 1 /* frame */); + FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed"); + + if (cSize == 0) { /* block is not compressible */ + cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); + } else { + U32 const cBlockHeader = cSize == 1 ? + lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : + lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); + MEM_writeLE24(op, cBlockHeader); + cSize += ZSTD_blockHeaderSize; + } } + ip += blockSize; assert(remaining >= blockSize); remaining -= blockSize; @@ -2546,10 +4077,10 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, size_t pos=0; assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); - RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall); + RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall, + "dst buf is too small to fit worst-case frame header size."); DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); - if (params->format == ZSTD_f_zstd1) { MEM_writeLE32(dst, ZSTD_MAGICNUMBER); pos = 4; @@ -2558,7 +4089,9 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, if (!singleSegment) op[pos++] = windowLogByte; switch(dictIDSizeCode) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : break; case 1 : op[pos] = (BYTE)(dictID); pos++; break; case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; @@ -2566,7 +4099,9 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, } switch(fcsCode) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; @@ -2575,6 +4110,26 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, return pos; } +/* ZSTD_writeSkippableFrame_advanced() : + * Writes out a skippable frame with the specified magic number variant (16 are supported), + * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data. + * + * Returns the total number of bytes written, or a ZSTD error code. + */ +size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, + const void* src, size_t srcSize, unsigned magicVariant) { + BYTE* op = (BYTE*)dst; + RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */, + dstSize_tooSmall, "Not enough room for skippable frame"); + RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame"); + RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported"); + + MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant)); + MEM_writeLE32(op+4, (U32)srcSize); + ZSTD_memcpy(op+8, src, srcSize); + return srcSize + ZSTD_SKIPPABLEHEADERSIZE; +} + /* ZSTD_writeLastEmptyBlock() : * output an empty Block with end-of-frame mark to complete a frame * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) @@ -2582,7 +4137,8 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, */ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) { - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall); + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, + "dst buf is too small to write frame trailer empty block."); { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ MEM_writeLE24(dst, cBlockHeader24); return ZSTD_blockHeaderSize; @@ -2591,13 +4147,16 @@ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) { - RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong); - RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, - parameter_unsupported); + RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong, + "wrong cctx stage"); + RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable, + parameter_unsupported, + "incompatible with ldm"); cctx->externSeqStore.seq = seq; cctx->externSeqStore.size = nbSeq; cctx->externSeqStore.capacity = nbSeq; cctx->externSeqStore.pos = 0; + cctx->externSeqStore.posInSequence = 0; return 0; } @@ -2618,7 +4177,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (frame && (cctx->stage==ZSTDcs_init)) { fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, cctx->pledgedSrcSizePlusOne-1, cctx->dictID); - FORWARD_IF_ERROR(fhSize); + FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); assert(fhSize <= dstCapacity); dstCapacity -= fhSize; dst = (char*)dst + fhSize; @@ -2627,11 +4186,12 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (!srcSize) return fhSize; /* do not generate an empty block if no input */ - if (!ZSTD_window_update(&ms->window, src, srcSize)) { + if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) { + ms->forceNonContiguous = 0; ms->nextToUpdate = ms->window.dictLimit; } - if (cctx->appliedParams.ldmParams.enableLdm) { - ZSTD_window_update(&cctx->ldmState.window, src, srcSize); + if (cctx->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0); } if (!frame) { @@ -2645,7 +4205,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, { size_t const cSize = frame ? ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */); - FORWARD_IF_ERROR(cSize); + FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed"); cctx->consumedSrcSize += srcSize; cctx->producedCSize += (cSize + fhSize); assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); @@ -2682,7 +4242,7 @@ size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const { DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); { size_t const blockSizeMax = ZSTD_getBlockSize(cctx); - RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong); } + RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); } return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); } @@ -2691,58 +4251,110 @@ size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const * @return : 0, or an error code */ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, + ldmState_t* ls, ZSTD_cwksp* ws, ZSTD_CCtx_params const* params, const void* src, size_t srcSize, - ZSTD_dictTableLoadMethod_e dtlm) + ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp) { const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; + int const loadLdmDict = params->ldmParams.enableLdm == ZSTD_ps_enable && ls != NULL; - ZSTD_window_update(&ms->window, src, srcSize); - ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); - - /* Assert that we the ms params match the params we're being given */ + /* Assert that the ms params match the params we're being given */ ZSTD_assertEqualCParams(params->cParams, ms->cParams); - if (srcSize <= HASH_READ_SIZE) return 0; + { /* Ensure large dictionaries can't cause index overflow */ - while (iend - ip > HASH_READ_SIZE) { - size_t const remaining = (size_t)(iend - ip); - size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); - const BYTE* const ichunk = ip + chunk; + /* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX. + * Dictionaries right at the edge will immediately trigger overflow + * correction, but I don't want to insert extra constraints here. + */ + U32 maxDictSize = ZSTD_CURRENT_MAX - ZSTD_WINDOW_START_INDEX; + + int const CDictTaggedIndices = ZSTD_CDictIndicesAreTagged(¶ms->cParams); + if (CDictTaggedIndices && tfp == ZSTD_tfp_forCDict) { + /* Some dictionary matchfinders in zstd use "short cache", + * which treats the lower ZSTD_SHORT_CACHE_TAG_BITS of each + * CDict hashtable entry as a tag rather than as part of an index. + * When short cache is used, we need to truncate the dictionary + * so that its indices don't overlap with the tag. */ + U32 const shortCacheMaxDictSize = (1u << (32 - ZSTD_SHORT_CACHE_TAG_BITS)) - ZSTD_WINDOW_START_INDEX; + maxDictSize = MIN(maxDictSize, shortCacheMaxDictSize); + assert(!loadLdmDict); + } - ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk); + /* If the dictionary is too large, only load the suffix of the dictionary. */ + if (srcSize > maxDictSize) { + ip = iend - maxDictSize; + src = ip; + srcSize = maxDictSize; + } } - switch(params->cParams.strategy) - { - case ZSTD_fast: - ZSTD_fillHashTable(ms, ichunk, dtlm); - break; - case ZSTD_dfast: - ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); - break; + if (srcSize > ZSTD_CHUNKSIZE_MAX) { + /* We must have cleared our windows when our source is this large. */ + assert(ZSTD_window_isEmpty(ms->window)); + if (loadLdmDict) assert(ZSTD_window_isEmpty(ls->window)); + } - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - if (chunk >= HASH_READ_SIZE) - ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); - break; + DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder); + ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0); + ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); + ms->forceNonContiguous = params->deterministicRefPrefix; - case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - if (chunk >= HASH_READ_SIZE) - ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); - break; + if (loadLdmDict) { + ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0); + ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); + } - default: - assert(0); /* not possible : not a valid strategy id */ + if (srcSize <= HASH_READ_SIZE) return 0; + + ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend); + + if (loadLdmDict) + ZSTD_ldm_fillHashTable(ls, ip, iend, ¶ms->ldmParams); + + switch(params->cParams.strategy) + { + case ZSTD_fast: + ZSTD_fillHashTable(ms, iend, dtlm, tfp); + break; + case ZSTD_dfast: + ZSTD_fillDoubleHashTable(ms, iend, dtlm, tfp); + break; + + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + assert(srcSize >= HASH_READ_SIZE); + if (ms->dedicatedDictSearch) { + assert(ms->chainTable != NULL); + ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE); + } else { + assert(params->useRowMatchFinder != ZSTD_ps_auto); + if (params->useRowMatchFinder == ZSTD_ps_enable) { + size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog) * sizeof(U16); + ZSTD_memset(ms->tagTable, 0, tagTableSize); + ZSTD_row_update(ms, iend-HASH_READ_SIZE); + DEBUGLOG(4, "Using row-based hash table for lazy dict"); + } else { + ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); + DEBUGLOG(4, "Using chain-based hash table for lazy dict"); + } } + break; - ip = ichunk; + case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + assert(srcSize >= HASH_READ_SIZE); + ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); + break; + + default: + assert(0); /* not possible : not a valid strategy id */ } ms->nextToUpdate = (U32)(iend - ms->window.base); @@ -2751,102 +4363,91 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, /* Dictionaries that assign zero probability to symbols that show up causes problems - when FSE encoding. Refuse dictionaries that assign zero probability to symbols - that we may encounter during compression. - NOTE: This behavior is not standard and could be improved in the future. */ -static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { + * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check + * and only dictionaries with 100% valid symbols can be assumed valid. + */ +static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) +{ U32 s; - RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted); + if (dictMaxSymbolValue < maxSymbolValue) { + return FSE_repeat_check; + } for (s = 0; s <= maxSymbolValue; ++s) { - RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted); + if (normalizedCounter[s] == 0) { + return FSE_repeat_check; + } } - return 0; + return FSE_repeat_valid; } - -/* Dictionary format : - * See : - * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format - */ -/*! ZSTD_loadZstdDictionary() : - * @return : dictID, or an error code - * assumptions : magic number supposed already checked - * dictSize supposed >= 8 - */ -static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, - ZSTD_matchState_t* ms, - ZSTD_cwksp* ws, - ZSTD_CCtx_params const* params, - const void* dict, size_t dictSize, - ZSTD_dictTableLoadMethod_e dtlm, - void* workspace) +size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, + const void* const dict, size_t dictSize) { - const BYTE* dictPtr = (const BYTE*)dict; - const BYTE* const dictEnd = dictPtr + dictSize; short offcodeNCount[MaxOff+1]; unsigned offcodeMaxValue = MaxOff; - size_t dictID; + const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */ + const BYTE* const dictEnd = dictPtr + dictSize; + dictPtr += 8; + bs->entropy.huf.repeatMode = HUF_repeat_check; - ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= 8); - assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); + { unsigned maxSymbolValue = 255; + unsigned hasZeroWeights = 1; + size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, + dictEnd-dictPtr, &hasZeroWeights); - dictPtr += 4; /* skip magic number */ - dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); - dictPtr += 4; + /* We only set the loaded table as valid if it contains all non-zero + * weights. Otherwise, we set it to check */ + if (!hasZeroWeights) + bs->entropy.huf.repeatMode = HUF_repeat_valid; - { unsigned maxSymbolValue = 255; - size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted); - RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted); + RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, ""); dictPtr += hufHeaderSize; } { unsigned offcodeLog; size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted); - RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted); - /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ + RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); /* fill all offset symbols to avoid garbage at end of table */ RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.offcodeCTable, offcodeNCount, MaxOff, offcodeLog, workspace, HUF_WORKSPACE_SIZE)), - dictionary_corrupted); + dictionary_corrupted, ""); + /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ dictPtr += offcodeHeaderSize; } { short matchlengthNCount[MaxML+1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog; size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted); - RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted); - /* Every match length code must have non-zero probability */ - FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); + RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE)), - dictionary_corrupted); + dictionary_corrupted, ""); + bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML); dictPtr += matchlengthHeaderSize; } { short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog; size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted); - RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted); - /* Every literal length code must have non-zero probability */ - FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); + RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE)), - dictionary_corrupted); + dictionary_corrupted, ""); + bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL); dictPtr += litlengthHeaderSize; } - RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted); + RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); bs->rep[0] = MEM_readLE32(dictPtr+0); bs->rep[1] = MEM_readLE32(dictPtr+4); bs->rep[2] = MEM_readLE32(dictPtr+8); @@ -2858,23 +4459,56 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ } - /* All offset values <= dictContentSize + 128 KB must be representable */ - FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); - /* All repCodes must be <= dictContentSize and != 0*/ + /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */ + bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)); + + /* All repCodes must be <= dictContentSize and != 0 */ { U32 u; for (u=0; u<3; u++) { - RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted); - RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted); - } } + RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); + RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); + } } } + + return dictPtr - (const BYTE*)dict; +} + +/* Dictionary format : + * See : + * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format + */ +/*! ZSTD_loadZstdDictionary() : + * @return : dictID, or an error code + * assumptions : magic number supposed already checked + * dictSize supposed >= 8 + */ +static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, + ZSTD_matchState_t* ms, + ZSTD_cwksp* ws, + ZSTD_CCtx_params const* params, + const void* dict, size_t dictSize, + ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp, + void* workspace) +{ + const BYTE* dictPtr = (const BYTE*)dict; + const BYTE* const dictEnd = dictPtr + dictSize; + size_t dictID; + size_t eSize; + ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= 8); + assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); - bs->entropy.huf.repeatMode = HUF_repeat_valid; - bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; - bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; - bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; + dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ ); + eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize); + FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed"); + dictPtr += eSize; + + { + size_t const dictContentSize = (size_t)(dictEnd - dictPtr); FORWARD_IF_ERROR(ZSTD_loadDictionaryContent( - ms, ws, params, dictPtr, dictContentSize, dtlm)); - return dictID; + ms, NULL, ws, params, dictPtr, dictContentSize, dtlm, tfp), ""); } + return dictID; } /** ZSTD_compress_insertDictionary() : @@ -2882,16 +4516,18 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, + ldmState_t* ls, ZSTD_cwksp* ws, const ZSTD_CCtx_params* params, const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp, void* workspace) { DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); if ((dict==NULL) || (dictSize<8)) { - RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); + RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); return 0; } @@ -2899,27 +4535,28 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, /* dict restricted modes */ if (dictContentType == ZSTD_dct_rawContent) - return ZSTD_loadDictionaryContent(ms, ws, params, dict, dictSize, dtlm); + return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm, tfp); if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { if (dictContentType == ZSTD_dct_auto) { DEBUGLOG(4, "raw content dictionary detected"); return ZSTD_loadDictionaryContent( - ms, ws, params, dict, dictSize, dtlm); + ms, ls, ws, params, dict, dictSize, dtlm, tfp); } - RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); + RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); assert(0); /* impossible */ } /* dict as full zstd dictionary */ return ZSTD_loadZstdDictionary( - bs, ms, ws, params, dict, dictSize, dtlm, workspace); + bs, ms, ws, params, dict, dictSize, dtlm, tfp, workspace); } #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB) -#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6) +#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL) /*! ZSTD_compressBegin_internal() : + * Assumption : either @dict OR @cdict (or none) is non-NULL, never both * @return : 0, or an error code */ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, @@ -2929,6 +4566,10 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { + size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize; +#if ZSTD_TRACE + cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; +#endif DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); @@ -2943,20 +4584,23 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); } - FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize, - ZSTDcrp_makeClean, zbuff) ); + FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, + dictContentSize, + ZSTDcrp_makeClean, zbuff) , ""); { size_t const dictID = cdict ? ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, - &cctx->workspace, params, cdict->dictContent, cdict->dictContentSize, - dictContentType, dtlm, cctx->entropyWorkspace) + &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent, + cdict->dictContentSize, cdict->dictContentType, dtlm, + ZSTD_tfp_forCCtx, cctx->entropyWorkspace) : ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, - &cctx->workspace, params, dict, dictSize, - dictContentType, dtlm, cctx->entropyWorkspace); - FORWARD_IF_ERROR(dictID); + &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize, + dictContentType, dtlm, ZSTD_tfp_forCCtx, cctx->entropyWorkspace); + FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); assert(dictID <= UINT_MAX); cctx->dictID = (U32)dictID; + cctx->dictContentSize = dictContentSize; } return 0; } @@ -2971,7 +4615,7 @@ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, { DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog); /* compression parameters verification and optimization */ - FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) ); + FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , ""); return ZSTD_compressBegin_internal(cctx, dict, dictSize, dictContentType, dtlm, cdict, @@ -2985,19 +4629,21 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params const cctxParams = - ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); + ZSTD_CCtx_params cctxParams; + ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL /*cdict*/, &cctxParams, pledgedSrcSize); } -size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) +size_t +ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); - ZSTD_CCtx_params const cctxParams = - ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); + ZSTD_CCtx_params cctxParams; + { ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); + ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel); + } DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); @@ -3024,7 +4670,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) /* special case : empty frame */ if (cctx->stage == ZSTDcs_init) { fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); - FORWARD_IF_ERROR(fhSize); + FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); dstCapacity -= fhSize; op += fhSize; cctx->stage = ZSTDcs_ongoing; @@ -3033,7 +4679,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) if (cctx->stage != ZSTDcs_ending) { /* write one last empty block, make it the "last" block */ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue"); MEM_writeLE32(op, cBlockHeader24); op += ZSTD_blockHeaderSize; dstCapacity -= ZSTD_blockHeaderSize; @@ -3041,7 +4687,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) if (cctx->appliedParams.fParams.checksumFlag) { U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum); MEM_writeLE32(op, checksum); op += 4; @@ -3051,6 +4697,30 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) return op-ostart; } +void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize) +{ +#if ZSTD_TRACE + if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) { + int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0; + ZSTD_Trace trace; + ZSTD_memset(&trace, 0, sizeof(trace)); + trace.version = ZSTD_VERSION_NUMBER; + trace.streaming = streaming; + trace.dictionaryID = cctx->dictID; + trace.dictionarySize = cctx->dictContentSize; + trace.uncompressedSize = cctx->consumedSrcSize; + trace.compressedSize = cctx->producedCSize + extraCSize; + trace.params = &cctx->appliedParams; + trace.cctx = cctx; + ZSTD_trace_compress_end(cctx->traceCtx, &trace); + } + cctx->traceCtx = 0; +#else + (void)cctx; + (void)extraCSize; +#endif +} + size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) @@ -3059,9 +4729,9 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 1 /* last chunk */); - FORWARD_IF_ERROR(cSize); + FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed"); endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); - FORWARD_IF_ERROR(endResult); + FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed"); assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); @@ -3073,26 +4743,10 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize); } + ZSTD_CCtx_trace(cctx, endResult); return cSize + endResult; } - -static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize, - ZSTD_parameters params) -{ - ZSTD_CCtx_params const cctxParams = - ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); - DEBUGLOG(4, "ZSTD_compress_internal"); - return ZSTD_compress_advanced_internal(cctx, - dst, dstCapacity, - src, srcSize, - dict, dictSize, - &cctxParams); -} - size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, @@ -3100,12 +4754,13 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, ZSTD_parameters params) { DEBUGLOG(4, "ZSTD_compress_advanced"); - FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams)); - return ZSTD_compress_internal(cctx, - dst, dstCapacity, - src, srcSize, - dict, dictSize, - params); + FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); + ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, ZSTD_NO_CLEVEL); + return ZSTD_compress_advanced_internal(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + &cctx->simpleApiParams); } /* Internal */ @@ -3119,7 +4774,7 @@ size_t ZSTD_compress_advanced_internal( DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize); FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, - params, srcSize, ZSTDb_not_buffered) ); + params, srcSize, ZSTDb_not_buffered) , ""); return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } @@ -3129,10 +4784,13 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0); - ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); - assert(params.fParams.contentSizeFlag == 1); - return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams); + { + ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); + assert(params.fParams.contentSizeFlag == 1); + ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel); + } + DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize); + return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams); } size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, @@ -3150,10 +4808,17 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, int compressionLevel) { size_t result; +#if ZSTD_COMPRESS_HEAPMODE + ZSTD_CCtx* cctx = ZSTD_createCCtx(); + RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed"); + result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel); + ZSTD_freeCCtx(cctx); +#else ZSTD_CCtx ctxBody; ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ +#endif return result; } @@ -3169,14 +4834,17 @@ size_t ZSTD_estimateCDictSize_advanced( DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) - + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + /* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small + * in case we are using DDS with row-hash. */ + + ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams), + /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *)))); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); } @@ -3194,20 +4862,22 @@ static size_t ZSTD_initCDict_internal( const void* dictBuffer, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams) + ZSTD_CCtx_params params) { DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); - assert(!ZSTD_checkCParams(cParams)); - cdict->matchState.cParams = cParams; + assert(!ZSTD_checkCParams(params.cParams)); + cdict->matchState.cParams = params.cParams; + cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch; if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { cdict->dictContent = dictBuffer; } else { void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*))); - RETURN_ERROR_IF(!internalBuffer, memory_allocation); + RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!"); cdict->dictContent = internalBuffer; - memcpy(internalBuffer, dictBuffer, dictSize); + ZSTD_memcpy(internalBuffer, dictBuffer, dictSize); } cdict->dictContentSize = dictSize; + cdict->dictContentType = dictContentType; cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE); @@ -3217,23 +4887,21 @@ static size_t ZSTD_initCDict_internal( FORWARD_IF_ERROR(ZSTD_reset_matchState( &cdict->matchState, &cdict->workspace, - &cParams, + ¶ms.cParams, + params.useRowMatchFinder, ZSTDcrp_makeClean, ZSTDirp_reset, - ZSTD_resetTarget_CDict)); + ZSTD_resetTarget_CDict), ""); /* (Maybe) load the dictionary * Skips loading the dictionary if it is < 8 bytes. */ - { ZSTD_CCtx_params params; - memset(¶ms, 0, sizeof(params)); - params.compressionLevel = ZSTD_CLEVEL_DEFAULT; + { params.compressionLevel = ZSTD_CLEVEL_DEFAULT; params.fParams.contentSizeFlag = 1; - params.cParams = cParams; { size_t const dictID = ZSTD_compress_insertDictionary( - &cdict->cBlockState, &cdict->matchState, &cdict->workspace, + &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace, ¶ms, cdict->dictContent, cdict->dictContentSize, - dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace); - FORWARD_IF_ERROR(dictID); + dictContentType, ZSTD_dtlm_full, ZSTD_tfp_forCDict, cdict->entropyWorkspace); + FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); assert(dictID <= (size_t)(U32)-1); cdict->dictID = (U32)dictID; } @@ -3242,66 +4910,129 @@ static size_t ZSTD_initCDict_internal( return 0; } -ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, +static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams, ZSTD_customMem customMem) + ZSTD_compressionParameters cParams, + ZSTD_paramSwitch_e useRowMatchFinder, + U32 enableDedicatedDictSearch, + ZSTD_customMem customMem) { - DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; { size_t const workspaceSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + - ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + + ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))); - void* const workspace = ZSTD_malloc(workspaceSize, customMem); + void* const workspace = ZSTD_customMalloc(workspaceSize, customMem); ZSTD_cwksp ws; ZSTD_CDict* cdict; if (!workspace) { - ZSTD_free(workspace, customMem); + ZSTD_customFree(workspace, customMem); return NULL; } - ZSTD_cwksp_init(&ws, workspace, workspaceSize); + ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); assert(cdict != NULL); ZSTD_cwksp_move(&cdict->workspace, &ws); cdict->customMem = customMem; - cdict->compressionLevel = 0; /* signals advanced API usage */ + cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ + cdict->useRowMatchFinder = useRowMatchFinder; + return cdict; + } +} - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, - dictBuffer, dictSize, - dictLoadMethod, dictContentType, - cParams) )) { - ZSTD_freeCDict(cdict); - return NULL; - } +ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem) +{ + ZSTD_CCtx_params cctxParams; + ZSTD_memset(&cctxParams, 0, sizeof(cctxParams)); + ZSTD_CCtxParams_init(&cctxParams, 0); + cctxParams.cParams = cParams; + cctxParams.customMem = customMem; + return ZSTD_createCDict_advanced2( + dictBuffer, dictSize, + dictLoadMethod, dictContentType, + &cctxParams, customMem); +} + +ZSTD_CDict* ZSTD_createCDict_advanced2( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + const ZSTD_CCtx_params* originalCctxParams, + ZSTD_customMem customMem) +{ + ZSTD_CCtx_params cctxParams = *originalCctxParams; + ZSTD_compressionParameters cParams; + ZSTD_CDict* cdict; - return cdict; + DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + + if (cctxParams.enableDedicatedDictSearch) { + cParams = ZSTD_dedicatedDictSearch_getCParams( + cctxParams.compressionLevel, dictSize); + ZSTD_overrideCParams(&cParams, &cctxParams.cParams); + } else { + cParams = ZSTD_getCParamsFromCCtxParams( + &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); } + + if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) { + /* Fall back to non-DDSS params */ + cctxParams.enableDedicatedDictSearch = 0; + cParams = ZSTD_getCParamsFromCCtxParams( + &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + } + + DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch); + cctxParams.cParams = cParams; + cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); + + cdict = ZSTD_createCDict_advanced_internal(dictSize, + dictLoadMethod, cctxParams.cParams, + cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch, + customMem); + + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, + dict, dictSize, + dictLoadMethod, dictContentType, + cctxParams) )) { + ZSTD_freeCDict(cdict); + return NULL; + } + + return cdict; } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); - ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, cParams, ZSTD_defaultCMem); if (cdict) - cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; return cdict; } ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); - return ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem); + if (cdict) + cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + return cdict; } size_t ZSTD_freeCDict(ZSTD_CDict* cdict) @@ -3311,7 +5042,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict); ZSTD_cwksp_free(&cdict->workspace, cMem); if (!cdictInWorkspace) { - ZSTD_free(cdict, cMem); + ZSTD_customFree(cdict, cMem); } return 0; } @@ -3337,19 +5068,22 @@ const ZSTD_CDict* ZSTD_initStaticCDict( ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams) { - size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); + ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams); + /* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */ + size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0); size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + matchStateSize; ZSTD_CDict* cdict; + ZSTD_CCtx_params params; if ((size_t)workspace & 7) return NULL; /* 8-aligned */ { ZSTD_cwksp ws; - ZSTD_cwksp_init(&ws, workspace, workspaceSize); + ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); if (cdict == NULL) return NULL; ZSTD_cwksp_move(&cdict->workspace, &ws); @@ -3359,10 +5093,15 @@ const ZSTD_CDict* ZSTD_initStaticCDict( (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); if (workspaceSize < neededSize) return NULL; + ZSTD_CCtxParams_init(¶ms, 0); + params.cParams = cParams; + params.useRowMatchFinder = useRowMatchFinder; + cdict->useRowMatchFinder = useRowMatchFinder; + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, dictLoadMethod, dictContentType, - cParams) )) + params) )) return NULL; return cdict; @@ -3374,61 +5113,98 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) return cdict->matchState.cParams; } -/* ZSTD_compressBegin_usingCDict_advanced() : - * cdict must be != NULL */ -size_t ZSTD_compressBegin_usingCDict_advanced( +/*! ZSTD_getDictID_fromCDict() : + * Provides the dictID of the dictionary loaded into `cdict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict) +{ + if (cdict==NULL) return 0; + return cdict->dictID; +} + +/* ZSTD_compressBegin_usingCDict_internal() : + * Implementation of various ZSTD_compressBegin_usingCDict* functions. + */ +static size_t ZSTD_compressBegin_usingCDict_internal( ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { - DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); - RETURN_ERROR_IF(cdict==NULL, dictionary_wrong); - { ZSTD_CCtx_params params = cctx->requestedParams; + ZSTD_CCtx_params cctxParams; + DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal"); + RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); + /* Initialize the cctxParams from the cdict */ + { + ZSTD_parameters params; + params.fParams = fParams; params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || cdict->compressionLevel == 0 ) - && (params.attachDictPref != ZSTD_dictForceLoad) ? + || cdict->compressionLevel == 0 ) ? ZSTD_getCParamsFromCDict(cdict) : ZSTD_getCParams(cdict->compressionLevel, pledgedSrcSize, cdict->dictContentSize); - /* Increase window log to fit the entire dictionary and source if the - * source size is known. Limit the increase to 19, which is the - * window log for compression level 1 with the largest source size. - */ - if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); - U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; - params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); - } - params.fParams = fParams; - return ZSTD_compressBegin_internal(cctx, - NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, - cdict, - ¶ms, pledgedSrcSize, - ZSTDb_not_buffered); + ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); + } + /* Increase window log to fit the entire dictionary and source if the + * source size is known. Limit the increase to 19, which is the + * window log for compression level 1 with the largest source size. + */ + if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { + U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); + U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; + cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); } + return ZSTD_compressBegin_internal(cctx, + NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, + cdict, + &cctxParams, pledgedSrcSize, + ZSTDb_not_buffered); +} + + +/* ZSTD_compressBegin_usingCDict_advanced() : + * This function is DEPRECATED. + * cdict must be != NULL */ +size_t ZSTD_compressBegin_usingCDict_advanced( + ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, + ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) +{ + return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize); } /* ZSTD_compressBegin_usingCDict() : - * pledgedSrcSize=0 means "unknown" - * if pledgedSrcSize>0, it will enable contentSizeFlag */ + * cdict must be != NULL */ size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); - return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); + return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); } -size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, +/*! ZSTD_compress_usingCDict_internal(): + * Implementation of various ZSTD_compress_usingCDict* functions. + */ +static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) { - FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */ + FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } +/*! ZSTD_compress_usingCDict_advanced(): + * This function is DEPRECATED. + */ +size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) +{ + return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); +} + /*! ZSTD_compress_usingCDict() : * Compression using a digested Dictionary. * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. @@ -3440,7 +5216,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); + return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); } @@ -3481,32 +5257,12 @@ size_t ZSTD_CStreamOutSize(void) return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, - const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, - const ZSTD_CDict* const cdict, - ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) +static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize) { - DEBUGLOG(4, "ZSTD_resetCStream_internal"); - /* Finalize the compression parameters */ - params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); - /* params are supposed to be fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); - assert(!((dict) && (cdict))); /* either dict or cdict, not both */ - - FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, - dict, dictSize, dictContentType, ZSTD_dtlm_fast, - cdict, - ¶ms, pledgedSrcSize, - ZSTDb_buffered) ); - - cctx->inToCompress = 0; - cctx->inBuffPos = 0; - cctx->inBuffTarget = cctx->blockSize - + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */ - cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; - cctx->streamStage = zcss_load; - cctx->frameEnded = 0; - return 0; /* ready to go */ + if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) + return ZSTD_cpm_attachDict; + else + return ZSTD_cpm_noAttachDict; } /* ZSTD_resetCStream(): @@ -3519,8 +5275,8 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss) */ U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); return 0; } @@ -3534,16 +5290,16 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTD_initCStream_internal"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); zcs->requestedParams = *params; assert(!((dict) && (cdict))); /* either dict or cdict, not both */ if (dict) { - FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); + FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); } else { /* Dictionary is cleared if !cdict */ - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); } return 0; } @@ -3556,10 +5312,10 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); zcs->requestedParams.fParams = fParams; - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); return 0; } @@ -3567,8 +5323,8 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) { DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); return 0; } @@ -3587,20 +5343,20 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, */ U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; DEBUGLOG(4, "ZSTD_initCStream_advanced"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); - FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); - zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, params); - FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); + FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); + ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, ¶ms); + FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); return 0; } size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) { DEBUGLOG(4, "ZSTD_initCStream_usingDict"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); - FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); return 0; } @@ -3612,19 +5368,19 @@ size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigne */ U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; DEBUGLOG(4, "ZSTD_initCStream_srcSize"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); return 0; } size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) { DEBUGLOG(4, "ZSTD_initCStream"); - FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); - FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); + FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); + FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); return 0; } @@ -3632,44 +5388,54 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) { - size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; - if (hintInSize==0) hintInSize = cctx->blockSize; - return hintInSize; -} - -static size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - size_t const length = MIN(dstCapacity, srcSize); - if (length) memcpy(dst, src, length); - return length; + if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { + return cctx->blockSize - cctx->stableIn_notConsumed; + } + assert(cctx->appliedParams.inBufferMode == ZSTD_bm_buffered); + { size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; + if (hintInSize==0) hintInSize = cctx->blockSize; + return hintInSize; + } } /** ZSTD_compressStream_generic(): * internal function for all *compressStream*() variants - * non-static, because can be called from zstdmt_compress.c - * @return : hint size for next input */ + * @return : hint size for next input to complete ongoing block */ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input, ZSTD_EndDirective const flushMode) { - const char* const istart = (const char*)input->src; - const char* const iend = istart + input->size; - const char* ip = istart + input->pos; - char* const ostart = (char*)output->dst; - char* const oend = ostart + output->size; - char* op = ostart + output->pos; + const char* const istart = (assert(input != NULL), (const char*)input->src); + const char* const iend = (istart != NULL) ? istart + input->size : istart; + const char* ip = (istart != NULL) ? istart + input->pos : istart; + char* const ostart = (assert(output != NULL), (char*)output->dst); + char* const oend = (ostart != NULL) ? ostart + output->size : ostart; + char* op = (ostart != NULL) ? ostart + output->pos : ostart; U32 someMoreWork = 1; /* check expectations */ - DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); - assert(zcs->inBuff != NULL); - assert(zcs->inBuffSize > 0); - assert(zcs->outBuff != NULL); - assert(zcs->outBuffSize > 0); - assert(output->pos <= output->size); + DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%i, srcSize = %zu", (int)flushMode, input->size - input->pos); + assert(zcs != NULL); + if (zcs->appliedParams.inBufferMode == ZSTD_bm_stable) { + assert(input->pos >= zcs->stableIn_notConsumed); + input->pos -= zcs->stableIn_notConsumed; + ip -= zcs->stableIn_notConsumed; + zcs->stableIn_notConsumed = 0; + } + if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { + assert(zcs->inBuff != NULL); + assert(zcs->inBuffSize > 0); + } + if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) { + assert(zcs->outBuff != NULL); + assert(zcs->outBuffSize > 0); + } + if (input->src == NULL) assert(input->size == 0); assert(input->pos <= input->size); + if (output->dst == NULL) assert(output->size == 0); + assert(output->pos <= output->size); + assert((U32)flushMode <= (U32)ZSTD_e_end); while (someMoreWork) { switch(zcs->streamStage) @@ -3679,26 +5445,28 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, case zcss_load: if ( (flushMode == ZSTD_e_end) - && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ + && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */ + || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */ && (zcs->inBuffPos == 0) ) { /* shortcut to compression pass directly into output buffer */ size_t const cSize = ZSTD_compressEnd(zcs, op, oend-op, ip, iend-ip); DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); - FORWARD_IF_ERROR(cSize); + FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed"); ip = iend; op += cSize; zcs->frameEnded = 1; ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); someMoreWork = 0; break; } - /* complete loading into inBuffer */ - { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; + /* complete loading into inBuffer in buffered mode */ + if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { + size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; size_t const loaded = ZSTD_limitCopy( zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip); zcs->inBuffPos += loaded; - ip += loaded; + if (ip) ip += loaded; if ( (flushMode == ZSTD_e_continue) && (zcs->inBuffPos < zcs->inBuffTarget) ) { /* not enough input to fill full block : stop here */ @@ -3709,34 +5477,62 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, /* empty */ someMoreWork = 0; break; } + } else { + assert(zcs->appliedParams.inBufferMode == ZSTD_bm_stable); + if ( (flushMode == ZSTD_e_continue) + && ( (size_t)(iend - ip) < zcs->blockSize) ) { + /* can't compress a full block : stop here */ + zcs->stableIn_notConsumed = (size_t)(iend - ip); + ip = iend; /* pretend to have consumed input */ + someMoreWork = 0; break; + } + if ( (flushMode == ZSTD_e_flush) + && (ip == iend) ) { + /* empty */ + someMoreWork = 0; break; + } } /* compress current block (note : this stage cannot be stopped in the middle) */ DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); - { void* cDst; + { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered); + void* cDst; size_t cSize; - size_t const iSize = zcs->inBuffPos - zcs->inToCompress; size_t oSize = oend-op; - unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); - if (oSize >= ZSTD_compressBound(iSize)) + size_t const iSize = inputBuffered ? zcs->inBuffPos - zcs->inToCompress + : MIN((size_t)(iend - ip), zcs->blockSize); + if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) cDst = op; /* compress into output buffer, to skip flush stage */ else cDst = zcs->outBuff, oSize = zcs->outBuffSize; - cSize = lastBlock ? - ZSTD_compressEnd(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize) : - ZSTD_compressContinue(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize); - FORWARD_IF_ERROR(cSize); - zcs->frameEnded = lastBlock; - /* prepare next block */ - zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; - if (zcs->inBuffTarget > zcs->inBuffSize) - zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; - DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", - (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); - if (!lastBlock) - assert(zcs->inBuffTarget <= zcs->inBuffSize); - zcs->inToCompress = zcs->inBuffPos; + if (inputBuffered) { + unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); + cSize = lastBlock ? + ZSTD_compressEnd(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize) : + ZSTD_compressContinue(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize); + FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); + zcs->frameEnded = lastBlock; + /* prepare next block */ + zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; + if (zcs->inBuffTarget > zcs->inBuffSize) + zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; + DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", + (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); + if (!lastBlock) + assert(zcs->inBuffTarget <= zcs->inBuffSize); + zcs->inToCompress = zcs->inBuffPos; + } else { /* !inputBuffered, hence ZSTD_bm_stable */ + unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip + iSize == iend); + cSize = lastBlock ? + ZSTD_compressEnd(zcs, cDst, oSize, ip, iSize) : + ZSTD_compressContinue(zcs, cDst, oSize, ip, iSize); + /* Consume the input prior to error checking to mirror buffered mode. */ + if (ip) ip += iSize; + FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); + zcs->frameEnded = lastBlock; + if (lastBlock) assert(ip == iend); + } if (cDst == op) { /* no need to flush */ op += cSize; if (zcs->frameEnded) { @@ -3750,15 +5546,17 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, zcs->outBuffFlushedSize = 0; zcs->streamStage = zcss_flush; /* pass-through to flush stage */ } - /* fall-through */ + ZSTD_FALLTHROUGH; case zcss_flush: DEBUGLOG(5, "flush stage"); + assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered); { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), zcs->outBuff + zcs->outBuffFlushedSize, toFlush); DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); - op += flushed; + if (flushed) + op += flushed; zcs->outBuffFlushedSize += flushed; if (toFlush!=flushed) { /* flush not fully completed, presumably because dst is too small */ @@ -3802,11 +5600,135 @@ static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx) size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) { - FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) ); + FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , ""); return ZSTD_nextInputSizeHint_MTorST(zcs); } +/* After a compression call set the expected input/output buffer. + * This is validated at the start of the next compression call. + */ +static void +ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, const ZSTD_outBuffer* output, const ZSTD_inBuffer* input) +{ + DEBUGLOG(5, "ZSTD_setBufferExpectations (for advanced stable in/out modes)"); + if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { + cctx->expectedInBuffer = *input; + } + if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { + cctx->expectedOutBufferSize = output->size - output->pos; + } +} + +/* Validate that the input/output buffers match the expectations set by + * ZSTD_setBufferExpectations. + */ +static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx, + ZSTD_outBuffer const* output, + ZSTD_inBuffer const* input, + ZSTD_EndDirective endOp) +{ + if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { + ZSTD_inBuffer const expect = cctx->expectedInBuffer; + if (expect.src != input->src || expect.pos != input->pos) + RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableInBuffer enabled but input differs!"); + } + (void)endOp; + if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { + size_t const outBufferSize = output->size - output->pos; + if (cctx->expectedOutBufferSize != outBufferSize) + RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableOutBuffer enabled but output size differs!"); + } + return 0; +} + +static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, + ZSTD_EndDirective endOp, + size_t inSize) +{ + ZSTD_CCtx_params params = cctx->requestedParams; + ZSTD_prefixDict const prefixDict = cctx->prefixDict; + FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ + ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ + assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ + if (cctx->cdict && !cctx->localDict.cdict) { + /* Let the cdict's compression level take priority over the requested params. + * But do not take the cdict's compression level if the "cdict" is actually a localDict + * generated from ZSTD_initLocalDict(). + */ + params.compressionLevel = cctx->cdict->compressionLevel; + } + DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); + if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-determine pledgedSrcSize */ + + { size_t const dictSize = prefixDict.dict + ? prefixDict.dictSize + : (cctx->cdict ? cctx->cdict->dictContentSize : 0); + ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, ¶ms, cctx->pledgedSrcSizePlusOne - 1); + params.cParams = ZSTD_getCParamsFromCCtxParams( + ¶ms, cctx->pledgedSrcSizePlusOne-1, + dictSize, mode); + } + + params.useBlockSplitter = ZSTD_resolveBlockSplitterMode(params.useBlockSplitter, ¶ms.cParams); + params.ldmParams.enableLdm = ZSTD_resolveEnableLdm(params.ldmParams.enableLdm, ¶ms.cParams); + params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, ¶ms.cParams); + +#ifdef ZSTD_MULTITHREAD + if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { + params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ + } + if (params.nbWorkers > 0) { +#if ZSTD_TRACE + cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; +#endif + /* mt context creation */ + if (cctx->mtctx == NULL) { + DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", + params.nbWorkers); + cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool); + RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!"); + } + /* mt compression */ + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); + FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( + cctx->mtctx, + prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, + cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , ""); + cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0; + cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize; + cctx->consumedSrcSize = 0; + cctx->producedCSize = 0; + cctx->streamStage = zcss_load; + cctx->appliedParams = params; + } else +#endif /* ZSTD_MULTITHREAD */ + { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1; + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, + prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast, + cctx->cdict, + ¶ms, pledgedSrcSize, + ZSTDb_buffered) , ""); + assert(cctx->appliedParams.nbWorkers == 0); + cctx->inToCompress = 0; + cctx->inBuffPos = 0; + if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) { + /* for small input: avoid automatic flush on reaching end of block, since + * it would require to add a 3-bytes null block to end frame + */ + cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize); + } else { + cctx->inBuffTarget = 0; + } + cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; + cctx->streamStage = zcss_load; + cctx->frameEnded = 0; + } + return 0; +} +/* @return provides a minimum amount of data remaining to be flushed from internal buffers + */ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, @@ -3814,82 +5736,95 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, { DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); /* check conditions */ - RETURN_ERROR_IF(output->pos > output->size, GENERIC); - RETURN_ERROR_IF(input->pos > input->size, GENERIC); - assert(cctx!=NULL); + RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer"); + RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer"); + RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective"); + assert(cctx != NULL); /* transparent initialization stage */ if (cctx->streamStage == zcss_init) { - ZSTD_CCtx_params params = cctx->requestedParams; - ZSTD_prefixDict const prefixDict = cctx->prefixDict; - FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) ); /* Init the local dict if present. */ - memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ - assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ - DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); - if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ - params.cParams = ZSTD_getCParamsFromCCtxParams( - &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); - - -#ifdef ZSTD_MULTITHREAD - if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { - params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ - } - if (params.nbWorkers > 0) { - /* mt context creation */ - if (cctx->mtctx == NULL) { - DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", - params.nbWorkers); - cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem); - RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation); + size_t const inputSize = input->size - input->pos; /* no obligation to start from pos==0 */ + size_t const totalInputSize = inputSize + cctx->stableIn_notConsumed; + if ( (cctx->requestedParams.inBufferMode == ZSTD_bm_stable) /* input is presumed stable, across invocations */ + && (endOp == ZSTD_e_continue) /* no flush requested, more input to come */ + && (totalInputSize < ZSTD_BLOCKSIZE_MAX) ) { /* not even reached one block yet */ + if (cctx->stableIn_notConsumed) { /* not the first time */ + /* check stable source guarantees */ + RETURN_ERROR_IF(input->src != cctx->expectedInBuffer.src, stabilityCondition_notRespected, "stableInBuffer condition not respected: wrong src pointer"); + RETURN_ERROR_IF(input->pos != cctx->expectedInBuffer.size, stabilityCondition_notRespected, "stableInBuffer condition not respected: externally modified pos"); } - /* mt compression */ - DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); - FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( - cctx->mtctx, - prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent, - cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); - cctx->streamStage = zcss_load; - cctx->appliedParams.nbWorkers = params.nbWorkers; - } else -#endif - { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx, - prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, - cctx->cdict, - params, cctx->pledgedSrcSizePlusOne-1) ); - assert(cctx->streamStage == zcss_load); - assert(cctx->appliedParams.nbWorkers == 0); - } } + /* pretend input was consumed, to give a sense forward progress */ + input->pos = input->size; + /* save stable inBuffer, for later control, and flush/end */ + cctx->expectedInBuffer = *input; + /* but actually input wasn't consumed, so keep track of position from where compression shall resume */ + cctx->stableIn_notConsumed += inputSize; + /* don't initialize yet, wait for the first block of flush() order, for better parameters adaptation */ + return ZSTD_FRAMEHEADERSIZE_MIN(cctx->requestedParams.format); /* at least some header to produce */ + } + FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, totalInputSize), "compressStream2 initialization failed"); + ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */ + } /* end of transparent initialization stage */ + FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers"); /* compression stage */ #ifdef ZSTD_MULTITHREAD if (cctx->appliedParams.nbWorkers > 0) { - int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end); size_t flushMin; - assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */); if (cctx->cParamsChanged) { ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); cctx->cParamsChanged = 0; } - do { + if (cctx->stableIn_notConsumed) { + assert(cctx->appliedParams.inBufferMode == ZSTD_bm_stable); + /* some early data was skipped - make it available for consumption */ + assert(input->pos >= cctx->stableIn_notConsumed); + input->pos -= cctx->stableIn_notConsumed; + cctx->stableIn_notConsumed = 0; + } + for (;;) { + size_t const ipos = input->pos; + size_t const opos = output->pos; flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); + cctx->consumedSrcSize += (U64)(input->pos - ipos); + cctx->producedCSize += (U64)(output->pos - opos); if ( ZSTD_isError(flushMin) || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ + if (flushMin == 0) + ZSTD_CCtx_trace(cctx, 0); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); } - FORWARD_IF_ERROR(flushMin); - } while (forceMaxProgress && flushMin != 0 && output->pos < output->size); + FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed"); + + if (endOp == ZSTD_e_continue) { + /* We only require some progress with ZSTD_e_continue, not maximal progress. + * We're done if we've consumed or produced any bytes, or either buffer is + * full. + */ + if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size) + break; + } else { + assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end); + /* We require maximal progress. We're done when the flush is complete or the + * output buffer is full. + */ + if (flushMin == 0 || output->pos == output->size) + break; + } + } DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); /* Either we don't require maximum forward progress, we've finished the * flush, or we are out of output space. */ - assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); + assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size); + ZSTD_setBufferExpectations(cctx, output, input); return flushMin; } -#endif - FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) ); +#endif /* ZSTD_MULTITHREAD */ + FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , ""); DEBUGLOG(5, "completed ZSTD_compressStream2"); + ZSTD_setBufferExpectations(cctx, output, input); return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ } @@ -3912,39 +5847,521 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { + ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode; + ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode; + DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); + /* Enable stable input/output buffers. */ + cctx->requestedParams.inBufferMode = ZSTD_bm_stable; + cctx->requestedParams.outBufferMode = ZSTD_bm_stable; { size_t oPos = 0; size_t iPos = 0; size_t const result = ZSTD_compressStream2_simpleArgs(cctx, dst, dstCapacity, &oPos, src, srcSize, &iPos, ZSTD_e_end); - FORWARD_IF_ERROR(result); + /* Reset to the original values. */ + cctx->requestedParams.inBufferMode = originalInBufferMode; + cctx->requestedParams.outBufferMode = originalOutBufferMode; + FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed"); if (result != 0) { /* compression not completed, due to lack of output space */ assert(oPos == dstCapacity); - RETURN_ERROR(dstSize_tooSmall); + RETURN_ERROR(dstSize_tooSmall, ""); } assert(iPos == srcSize); /* all input is expected consumed */ return oPos; } } +typedef struct { + U32 idx; /* Index in array of ZSTD_Sequence */ + U32 posInSequence; /* Position within sequence at idx */ + size_t posInSrc; /* Number of bytes given by sequences provided so far */ +} ZSTD_sequencePosition; + +/* ZSTD_validateSequence() : + * @offCode : is presumed to follow format required by ZSTD_storeSeq() + * @returns a ZSTD error code if sequence is not valid + */ +static size_t +ZSTD_validateSequence(U32 offCode, U32 matchLength, + size_t posInSrc, U32 windowLog, size_t dictSize) +{ + U32 const windowSize = 1 << windowLog; + /* posInSrc represents the amount of data the decoder would decode up to this point. + * As long as the amount of data decoded is less than or equal to window size, offsets may be + * larger than the total length of output decoded in order to reference the dict, even larger than + * window size. After output surpasses windowSize, we're limited to windowSize offsets again. + */ + size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; + RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), corruption_detected, "Offset too large!"); + RETURN_ERROR_IF(matchLength < MINMATCH, corruption_detected, "Matchlength too small"); + return 0; +} + +/* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */ +static U32 ZSTD_finalizeOffBase(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) +{ + U32 offBase = OFFSET_TO_OFFBASE(rawOffset); + + if (!ll0 && rawOffset == rep[0]) { + offBase = REPCODE1_TO_OFFBASE; + } else if (rawOffset == rep[1]) { + offBase = REPCODE_TO_OFFBASE(2 - ll0); + } else if (rawOffset == rep[2]) { + offBase = REPCODE_TO_OFFBASE(3 - ll0); + } else if (ll0 && rawOffset == rep[0] - 1) { + offBase = REPCODE3_TO_OFFBASE; + } + return offBase; +} + +/* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of + * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter. + */ +static size_t +ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, + ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize) +{ + U32 idx = seqPos->idx; + BYTE const* ip = (BYTE const*)(src); + const BYTE* const iend = ip + blockSize; + repcodes_t updatedRepcodes; + U32 dictSize; + + DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreExplicitBlockDelim (blockSize = %zu)", blockSize); + + if (cctx->cdict) { + dictSize = (U32)cctx->cdict->dictContentSize; + } else if (cctx->prefixDict.dict) { + dictSize = (U32)cctx->prefixDict.dictSize; + } else { + dictSize = 0; + } + ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); + for (; idx < inSeqsSize && (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0); ++idx) { + U32 const litLength = inSeqs[idx].litLength; + U32 const ll0 = (litLength == 0); + U32 const matchLength = inSeqs[idx].matchLength; + U32 const offBase = ZSTD_finalizeOffBase(inSeqs[idx].offset, updatedRepcodes.rep, ll0); + ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); + + DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); + if (cctx->appliedParams.validateSequences) { + seqPos->posInSrc += litLength + matchLength; + FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, seqPos->posInSrc, + cctx->appliedParams.cParams.windowLog, dictSize), + "Sequence validation failed"); + } + RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation, + "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); + ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); + ip += matchLength + litLength; + } + ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); + + if (inSeqs[idx].litLength) { + DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength); + ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength); + ip += inSeqs[idx].litLength; + seqPos->posInSrc += inSeqs[idx].litLength; + } + RETURN_ERROR_IF(ip != iend, corruption_detected, "Blocksize doesn't agree with block delimiter!"); + seqPos->idx = idx+1; + return 0; +} + +/* Returns the number of bytes to move the current read position back by. + * Only non-zero if we ended up splitting a sequence. + * Otherwise, it may return a ZSTD error if something went wrong. + * + * This function will attempt to scan through blockSize bytes + * represented by the sequences in @inSeqs, + * storing any (partial) sequences. + * + * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to + * avoid splitting a match, or to avoid splitting a match such that it would produce a match + * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block. + */ +static size_t +ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize) +{ + U32 idx = seqPos->idx; + U32 startPosInSequence = seqPos->posInSequence; + U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize; + size_t dictSize; + BYTE const* ip = (BYTE const*)(src); + BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */ + repcodes_t updatedRepcodes; + U32 bytesAdjustment = 0; + U32 finalMatchSplit = 0; + + if (cctx->cdict) { + dictSize = cctx->cdict->dictContentSize; + } else if (cctx->prefixDict.dict) { + dictSize = cctx->prefixDict.dictSize; + } else { + dictSize = 0; + } + DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreNoBlockDelim: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); + DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); + ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); + while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) { + const ZSTD_Sequence currSeq = inSeqs[idx]; + U32 litLength = currSeq.litLength; + U32 matchLength = currSeq.matchLength; + U32 const rawOffset = currSeq.offset; + U32 offBase; + + /* Modify the sequence depending on where endPosInSequence lies */ + if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) { + if (startPosInSequence >= litLength) { + startPosInSequence -= litLength; + litLength = 0; + matchLength -= startPosInSequence; + } else { + litLength -= startPosInSequence; + } + /* Move to the next sequence */ + endPosInSequence -= currSeq.litLength + currSeq.matchLength; + startPosInSequence = 0; + idx++; + } else { + /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence + does not reach the end of the match. So, we have to split the sequence */ + DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u", + currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence); + if (endPosInSequence > litLength) { + U32 firstHalfMatchLength; + litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence; + firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength; + if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) { + /* Only ever split the match if it is larger than the block size */ + U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence; + if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) { + /* Move the endPosInSequence backward so that it creates match of minMatch length */ + endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; + bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; + firstHalfMatchLength -= bytesAdjustment; + } + matchLength = firstHalfMatchLength; + /* Flag that we split the last match - after storing the sequence, exit the loop, + but keep the value of endPosInSequence */ + finalMatchSplit = 1; + } else { + /* Move the position in sequence backwards so that we don't split match, and break to store + * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence + * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so + * would cause the first half of the match to be too small + */ + bytesAdjustment = endPosInSequence - currSeq.litLength; + endPosInSequence = currSeq.litLength; + break; + } + } else { + /* This sequence ends inside the literals, break to store the last literals */ + break; + } + } + /* Check if this offset can be represented with a repcode */ + { U32 const ll0 = (litLength == 0); + offBase = ZSTD_finalizeOffBase(rawOffset, updatedRepcodes.rep, ll0); + ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); + } + + if (cctx->appliedParams.validateSequences) { + seqPos->posInSrc += litLength + matchLength; + FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, seqPos->posInSrc, + cctx->appliedParams.cParams.windowLog, dictSize), + "Sequence validation failed"); + } + DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); + RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation, + "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); + ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); + ip += matchLength + litLength; + } + DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); + assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength); + seqPos->idx = idx; + seqPos->posInSequence = endPosInSequence; + ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); + + iend -= bytesAdjustment; + if (ip != iend) { + /* Store any last literals */ + U32 lastLLSize = (U32)(iend - ip); + assert(ip <= iend); + DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize); + ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize); + seqPos->posInSrc += lastLLSize; + } + + return bytesAdjustment; +} + +typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize); +static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) +{ + ZSTD_sequenceCopier sequenceCopier = NULL; + assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode)); + if (mode == ZSTD_sf_explicitBlockDelimiters) { + return ZSTD_copySequencesToSeqStoreExplicitBlockDelim; + } else if (mode == ZSTD_sf_noBlockDelimiters) { + return ZSTD_copySequencesToSeqStoreNoBlockDelim; + } + assert(sequenceCopier != NULL); + return sequenceCopier; +} + +/* Discover the size of next block by searching for the delimiter. + * Note that a block delimiter **must** exist in this mode, + * otherwise it's an input error. + * The block size retrieved will be later compared to ensure it remains within bounds */ +static size_t +blockSize_explicitDelimiter(const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) +{ + int end = 0; + size_t blockSize = 0; + size_t spos = seqPos.idx; + DEBUGLOG(6, "blockSize_explicitDelimiter : seq %zu / %zu", spos, inSeqsSize); + assert(spos <= inSeqsSize); + while (spos < inSeqsSize) { + end = (inSeqs[spos].offset == 0); + blockSize += inSeqs[spos].litLength + inSeqs[spos].matchLength; + if (end) { + if (inSeqs[spos].matchLength != 0) + RETURN_ERROR(corruption_detected, "delimiter format error : both matchlength and offset must be == 0"); + break; + } + spos++; + } + if (!end) + RETURN_ERROR(corruption_detected, "Reached end of sequences without finding a block delimiter"); + return blockSize; +} + +/* More a "target" block size */ +static size_t blockSize_noDelimiter(size_t blockSize, size_t remaining) +{ + int const lastBlock = (remaining <= blockSize); + return lastBlock ? remaining : blockSize; +} + +static size_t determine_blockSize(ZSTD_sequenceFormat_e mode, + size_t blockSize, size_t remaining, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) +{ + DEBUGLOG(6, "determine_blockSize : remainingSize = %zu", remaining); + if (mode == ZSTD_sf_noBlockDelimiters) + return blockSize_noDelimiter(blockSize, remaining); + { size_t const explicitBlockSize = blockSize_explicitDelimiter(inSeqs, inSeqsSize, seqPos); + FORWARD_IF_ERROR(explicitBlockSize, "Error while determining block size with explicit delimiters"); + if (explicitBlockSize > blockSize) + RETURN_ERROR(corruption_detected, "sequences incorrectly define a too large block"); + if (explicitBlockSize > remaining) + RETURN_ERROR(srcSize_wrong, "sequences define a frame longer than source"); + return explicitBlockSize; + } +} + +/* Compress, block-by-block, all of the sequences given. + * + * Returns the cumulative size of all compressed blocks (including their headers), + * otherwise a ZSTD error. + */ +static size_t +ZSTD_compressSequences_internal(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize) +{ + size_t cSize = 0; + size_t remaining = srcSize; + ZSTD_sequencePosition seqPos = {0, 0, 0}; + + BYTE const* ip = (BYTE const*)src; + BYTE* op = (BYTE*)dst; + ZSTD_sequenceCopier const sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters); + + DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize); + /* Special case: empty frame */ + if (remaining == 0) { + U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header"); + MEM_writeLE32(op, cBlockHeader24); + op += ZSTD_blockHeaderSize; + dstCapacity -= ZSTD_blockHeaderSize; + cSize += ZSTD_blockHeaderSize; + } + + while (remaining) { + size_t compressedSeqsSize; + size_t cBlockSize; + size_t additionalByteAdjustment; + size_t blockSize = determine_blockSize(cctx->appliedParams.blockDelimiters, + cctx->blockSize, remaining, + inSeqs, inSeqsSize, seqPos); + U32 const lastBlock = (blockSize == remaining); + FORWARD_IF_ERROR(blockSize, "Error while trying to determine block size"); + assert(blockSize <= remaining); + ZSTD_resetSeqStore(&cctx->seqStore); + DEBUGLOG(5, "Working on new block. Blocksize: %zu (total:%zu)", blockSize, (ip - (const BYTE*)src) + blockSize); + + additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize); + FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy"); + blockSize -= additionalByteAdjustment; + + /* If blocks are too small, emit as a nocompress block */ + /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding + * additional 1. We need to revisit and change this logic to be more consistent */ + if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { + cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed"); + DEBUGLOG(5, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize); + cSize += cBlockSize; + ip += blockSize; + op += cBlockSize; + remaining -= blockSize; + dstCapacity -= cBlockSize; + continue; + } + + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "not enough dstCapacity to write a new compressed block"); + compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore, + &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy, + &cctx->appliedParams, + op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize, + blockSize, + cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + cctx->bmi2); + FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); + DEBUGLOG(5, "Compressed sequences size: %zu", compressedSeqsSize); + + if (!cctx->isFirstBlock && + ZSTD_maybeRLE(&cctx->seqStore) && + ZSTD_isRLE((BYTE const*)src, srcSize)) { + /* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + compressedSeqsSize = 1; + } + + if (compressedSeqsSize == 0) { + /* ZSTD_noCompressBlock writes the block header as well */ + cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cBlockSize, "ZSTD_noCompressBlock failed"); + DEBUGLOG(5, "Writing out nocompress block, size: %zu", cBlockSize); + } else if (compressedSeqsSize == 1) { + cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cBlockSize, "ZSTD_rleCompressBlock failed"); + DEBUGLOG(5, "Writing out RLE block, size: %zu", cBlockSize); + } else { + U32 cBlockHeader; + /* Error checking and repcodes update */ + ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState); + if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + + /* Write block header into beginning of block*/ + cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3); + MEM_writeLE24(op, cBlockHeader); + cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize; + DEBUGLOG(5, "Writing out compressed block, size: %zu", cBlockSize); + } + + cSize += cBlockSize; + + if (lastBlock) { + break; + } else { + ip += blockSize; + op += cBlockSize; + remaining -= blockSize; + dstCapacity -= cBlockSize; + cctx->isFirstBlock = 0; + } + DEBUGLOG(5, "cSize running total: %zu (remaining dstCapacity=%zu)", cSize, dstCapacity); + } + + DEBUGLOG(4, "cSize final total: %zu", cSize); + return cSize; +} + +size_t ZSTD_compressSequences(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize) +{ + BYTE* op = (BYTE*)dst; + size_t cSize = 0; + size_t compressedBlocksSize = 0; + size_t frameHeaderSize = 0; + + /* Transparent initialization stage, same as compressStream2() */ + DEBUGLOG(4, "ZSTD_compressSequences (dstCapacity=%zu)", dstCapacity); + assert(cctx != NULL); + FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed"); + /* Begin writing output, starting with frame header */ + frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID); + op += frameHeaderSize; + dstCapacity -= frameHeaderSize; + cSize += frameHeaderSize; + if (cctx->appliedParams.fParams.checksumFlag && srcSize) { + XXH64_update(&cctx->xxhState, src, srcSize); + } + /* cSize includes block header size and compressed sequences size */ + compressedBlocksSize = ZSTD_compressSequences_internal(cctx, + op, dstCapacity, + inSeqs, inSeqsSize, + src, srcSize); + FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!"); + cSize += compressedBlocksSize; + dstCapacity -= compressedBlocksSize; + + if (cctx->appliedParams.fParams.checksumFlag) { + U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); + DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum); + MEM_writeLE32((char*)dst + cSize, checksum); + cSize += 4; + } + + DEBUGLOG(4, "Final compressed size: %zu", cSize); + return cSize; +} + /*====== Finalize ======*/ +static ZSTD_inBuffer inBuffer_forEndFlush(const ZSTD_CStream* zcs) +{ + const ZSTD_inBuffer nullInput = { NULL, 0, 0 }; + const int stableInput = (zcs->appliedParams.inBufferMode == ZSTD_bm_stable); + return stableInput ? zcs->expectedInBuffer : nullInput; +} + /*! ZSTD_flushStream() : * @return : amount of data remaining to flush */ size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = { NULL, 0, 0 }; + ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); + input.size = input.pos; /* do not ingest more input during flush */ return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); } size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = { NULL, 0, 0 }; + ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); - FORWARD_IF_ERROR( remainingToFlush ); + FORWARD_IF_ERROR(remainingToFlush , "ZSTD_compressStream2(,,ZSTD_e_end) failed"); if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ /* single thread mode : attempt to calculate remaining to flush more precisely */ { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; @@ -3957,147 +6374,147 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) /*-===== Pre-defined compression levels =====-*/ +#include "clevels.h" -#define ZSTD_MAX_CLEVEL 22 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } +int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; } -static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { -{ /* "default" - for any srcSize > 256 KB */ - /* W, C, H, S, L, TL, strat */ - { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ - { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ - { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ - { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ - { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ - { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ - { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ - { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ - { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ - { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ - { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ - { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ - { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ - { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ - { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ - { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ - { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ - { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ - { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ - { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ - { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ - { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ - { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ -}, -{ /* for srcSize <= 256 KB */ - /* W, C, H, S, L, T, strat */ - { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ - { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ - { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ - { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ - { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ - { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ - { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ - { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ - { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ - { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 128 KB */ - /* W, C, H, S, L, T, strat */ - { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ - { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ - { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ - { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ - { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ - { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ - { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ - { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ - { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ - { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ - { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 16 KB */ - /* W, C, H, S, L, T, strat */ - { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ - { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ - { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ - { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ - { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ - { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ - { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ - { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ - { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ - { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ - { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ - { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ - { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ - { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ - { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ - { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -}; +static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) +{ + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); + switch (cParams.strategy) { + case ZSTD_fast: + case ZSTD_dfast: + break; + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; + break; + case ZSTD_btlazy2: + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + break; + } + return cParams; +} -/*! ZSTD_getCParams() : +static int ZSTD_dedicatedDictSearch_isSupported( + ZSTD_compressionParameters const* cParams) +{ + return (cParams->strategy >= ZSTD_greedy) + && (cParams->strategy <= ZSTD_lazy2) + && (cParams->hashLog > cParams->chainLog) + && (cParams->chainLog <= 24); +} + +/** + * Reverses the adjustment applied to cparams when enabling dedicated dict + * search. This is used to recover the params set to be used in the working + * context. (Otherwise, those tables would also grow.) + */ +static void ZSTD_dedicatedDictSearch_revertCParams( + ZSTD_compressionParameters* cParams) { + switch (cParams->strategy) { + case ZSTD_fast: + case ZSTD_dfast: + break; + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG; + if (cParams->hashLog < ZSTD_HASHLOG_MIN) { + cParams->hashLog = ZSTD_HASHLOG_MIN; + } + break; + case ZSTD_btlazy2: + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + break; + } +} + +static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) +{ + switch (mode) { + case ZSTD_cpm_unknown: + case ZSTD_cpm_noAttachDict: + case ZSTD_cpm_createCDict: + break; + case ZSTD_cpm_attachDict: + dictSize = 0; + break; + default: + assert(0); + break; + } + { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; + size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; + return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; + } +} + +/*! ZSTD_getCParams_internal() : * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. - * Size values are optional, provide 0 if not known or unused */ -ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) + * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown. + * Use dictSize == 0 for unknown or unused. + * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */ +static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { - size_t const addedSize = srcSizeHint ? 0 : 500; - U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : ZSTD_CONTENTSIZE_UNKNOWN; /* intentional overflow for srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN */ + U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode); U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); - int row = compressionLevel; - DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel); + int row; + DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel); + + /* row */ if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ - if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ - if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; + else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ + else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; + else row = compressionLevel; + { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; - if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ - return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); /* refine parameters based on srcSize & dictSize */ + DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy); + /* acceleration factor */ + if (compressionLevel < 0) { + int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel); + cp.targetLength = (unsigned)(-clampedCompressionLevel); + } + /* refine parameters based on srcSize & dictSize */ + return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode); } } +/*! ZSTD_getCParams() : + * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. + * Size values are optional, provide 0 if not known or unused */ +ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) +{ + if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; + return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); +} + /*! ZSTD_getParams() : * same idea as ZSTD_getCParams() * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). * Fields of `ZSTD_frameParameters` are set to default values */ -ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { +static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { ZSTD_parameters params; - ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); - memset(¶ms, 0, sizeof(params)); + ZSTD_memset(¶ms, 0, sizeof(params)); params.cParams = cParams; params.fParams.contentSizeFlag = 1; return params; } + +/*! ZSTD_getParams() : + * same idea as ZSTD_getCParams() + * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). + * Fields of `ZSTD_frameParameters` are set to default values */ +ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { + if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; + return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); +} diff --git a/native/zstd/compress/zstd_compress_internal.h b/native/zstd/compress/zstd_compress_internal.h old mode 100755 new mode 100644 index 14036f8..baa726f --- a/native/zstd/compress/zstd_compress_internal.h +++ b/native/zstd/compress/zstd_compress_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -18,17 +18,17 @@ /*-************************************* * Dependencies ***************************************/ -#include "zstd_internal.h" +#include "../common/zstd_internal.h" #include "zstd_cwksp.h" #ifdef ZSTD_MULTITHREAD # include "zstdmt_compress.h" #endif +#include "../common/bits.h" /* ZSTD_highbit32, ZSTD_NbCommonBytes */ #if defined (__cplusplus) extern "C" { #endif - /*-************************************* * Constants ***************************************/ @@ -64,7 +64,7 @@ typedef struct { } ZSTD_localDict; typedef struct { - U32 CTable[HUF_CTABLE_SIZE_U32(255)]; + HUF_CElt CTable[HUF_CTABLE_SIZE_ST(255)]; HUF_repeat repeatMode; } ZSTD_hufCTables_t; @@ -82,11 +82,75 @@ typedef struct { ZSTD_fseCTables_t fse; } ZSTD_entropyCTables_t; +/*********************************************** +* Entropy buffer statistics structs and funcs * +***********************************************/ +/** ZSTD_hufCTablesMetadata_t : + * Stores Literals Block Type for a super-block in hType, and + * huffman tree description in hufDesBuffer. + * hufDesSize refers to the size of huffman tree description in bytes. + * This metadata is populated in ZSTD_buildBlockEntropyStats_literals() */ typedef struct { - U32 off; - U32 len; + symbolEncodingType_e hType; + BYTE hufDesBuffer[ZSTD_MAX_HUF_HEADER_SIZE]; + size_t hufDesSize; +} ZSTD_hufCTablesMetadata_t; + +/** ZSTD_fseCTablesMetadata_t : + * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and + * fse tables in fseTablesBuffer. + * fseTablesSize refers to the size of fse tables in bytes. + * This metadata is populated in ZSTD_buildBlockEntropyStats_sequences() */ +typedef struct { + symbolEncodingType_e llType; + symbolEncodingType_e ofType; + symbolEncodingType_e mlType; + BYTE fseTablesBuffer[ZSTD_MAX_FSE_HEADERS_SIZE]; + size_t fseTablesSize; + size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ +} ZSTD_fseCTablesMetadata_t; + +typedef struct { + ZSTD_hufCTablesMetadata_t hufMetadata; + ZSTD_fseCTablesMetadata_t fseMetadata; +} ZSTD_entropyCTablesMetadata_t; + +/** ZSTD_buildBlockEntropyStats() : + * Builds entropy for the block. + * @return : 0 on success or error code */ +size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize); + +/********************************* +* Compression internals structs * +*********************************/ + +typedef struct { + U32 off; /* Offset sumtype code for the match, using ZSTD_storeSeq() format */ + U32 len; /* Raw length of match */ } ZSTD_match_t; +typedef struct { + U32 offset; /* Offset of sequence */ + U32 litLength; /* Length of literals prior to match */ + U32 matchLength; /* Raw length of match */ +} rawSeq; + +typedef struct { + rawSeq* seq; /* The start of the sequences */ + size_t pos; /* The index in seq where reading stopped. pos <= size. */ + size_t posInSequence; /* The position within the sequence at seq[pos] where reading + stopped. posInSequence <= seq[pos].litLength + seq[pos].matchLength */ + size_t size; /* The number of sequences. <= capacity. */ + size_t capacity; /* The capacity starting from `seq` pointer */ +} rawSeqStore_t; + +UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0}; + typedef struct { int price; U32 off; @@ -116,7 +180,7 @@ typedef struct { U32 offCodeSumBasePrice; /* to compare to log2(offreq) */ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */ - ZSTD_literalCompressionMode_e literalCompressionMode; + ZSTD_paramSwitch_e literalCompressionMode; } optState_t; typedef struct { @@ -125,14 +189,23 @@ typedef struct { } ZSTD_compressedBlockState_t; typedef struct { - BYTE const* nextSrc; /* next block here to continue on current prefix */ - BYTE const* base; /* All regular indexes relative to this position */ - BYTE const* dictBase; /* extDict indexes relative to this position */ - U32 dictLimit; /* below that point, need extDict */ - U32 lowLimit; /* below that point, no more valid data */ + BYTE const* nextSrc; /* next block here to continue on current prefix */ + BYTE const* base; /* All regular indexes relative to this position */ + BYTE const* dictBase; /* extDict indexes relative to this position */ + U32 dictLimit; /* below that point, need extDict */ + U32 lowLimit; /* below that point, no more valid data */ + U32 nbOverflowCorrections; /* Number of times overflow correction has run since + * ZSTD_window_init(). Useful for debugging coredumps + * and for ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY. + */ } ZSTD_window_t; +#define ZSTD_WINDOW_START_INDEX 2 + typedef struct ZSTD_matchState_t ZSTD_matchState_t; + +#define ZSTD_ROW_HASH_CACHE_SIZE 8 /* Size of prefetching hash cache for row-based matchfinder */ + struct ZSTD_matchState_t { ZSTD_window_t window; /* State for window round buffer management */ U32 loadedDictEnd; /* index of end of dictionary, within context's referential. @@ -144,12 +217,29 @@ struct ZSTD_matchState_t { */ U32 nextToUpdate; /* index from which to continue table update */ U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */ + + U32 rowHashLog; /* For row-based matchfinder: Hashlog based on nb of rows in the hashTable.*/ + U16* tagTable; /* For row-based matchFinder: A row-based table containing the hashes and head index. */ + U32 hashCache[ZSTD_ROW_HASH_CACHE_SIZE]; /* For row-based matchFinder: a cache of hashes to improve speed */ + U32* hashTable; U32* hashTable3; U32* chainTable; + + U32 forceNonContiguous; /* Non-zero if we should force non-contiguous load for the next window update. */ + + int dedicatedDictSearch; /* Indicates whether this matchState is using the + * dedicated dictionary search structure. + */ optState_t opt; /* optimal parser state */ const ZSTD_matchState_t* dictMatchState; ZSTD_compressionParameters cParams; + const rawSeqStore_t* ldmSeqStore; + + /* Controls prefetching in some dictMatchState matchfinders. + * This behavior is controlled from the cctx ms. + * This parameter has no effect in the cdict ms. */ + int prefetchCDictTables; }; typedef struct { @@ -163,16 +253,26 @@ typedef struct { U32 checksum; } ldmEntry_t; +typedef struct { + BYTE const* split; + U32 hash; + U32 checksum; + ldmEntry_t* bucket; +} ldmMatchCandidate_t; + +#define LDM_BATCH_SIZE 64 + typedef struct { ZSTD_window_t window; /* State for the window round buffer management */ ldmEntry_t* hashTable; + U32 loadedDictEnd; BYTE* bucketOffsets; /* Next position in bucket to insert entry */ - U64 hashPower; /* Used to compute the rolling hash. - * Depends on ldmParams.minMatchLength */ + size_t splitIndices[LDM_BATCH_SIZE]; + ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE]; } ldmState_t; typedef struct { - U32 enableLdm; /* 1 if enable long distance matching */ + ZSTD_paramSwitch_e enableLdm; /* ZSTD_ps_enable to enable LDM. ZSTD_ps_auto by default */ U32 hashLog; /* Log size of hashTable */ U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */ U32 minMatchLength; /* Minimum match length */ @@ -180,19 +280,6 @@ typedef struct { U32 windowLog; /* Window log for the LDM */ } ldmParams_t; -typedef struct { - U32 offset; - U32 litLength; - U32 matchLength; -} rawSeq; - -typedef struct { - rawSeq* seq; /* The start of the sequences */ - size_t pos; /* The position where reading stopped. <= size. */ - size_t size; /* The number of sequences. <= capacity. */ - size_t capacity; /* The capacity starting from `seq` pointer */ -} rawSeqStore_t; - typedef struct { int collectSequences; ZSTD_Sequence* seqStart; @@ -216,7 +303,7 @@ struct ZSTD_CCtx_params_s { * There is no guarantee that hint is close to actual source size */ ZSTD_dictAttachPref_e attachDictPref; - ZSTD_literalCompressionMode_e literalCompressionMode; + ZSTD_paramSwitch_e literalCompressionMode; /* Multithreading: used to pass parameters to mtctx */ int nbWorkers; @@ -227,17 +314,71 @@ struct ZSTD_CCtx_params_s { /* Long distance matching parameters */ ldmParams_t ldmParams; + /* Dedicated dict search algorithm trigger */ + int enableDedicatedDictSearch; + + /* Input/output buffer modes */ + ZSTD_bufferMode_e inBufferMode; + ZSTD_bufferMode_e outBufferMode; + + /* Sequence compression API */ + ZSTD_sequenceFormat_e blockDelimiters; + int validateSequences; + + /* Block splitting */ + ZSTD_paramSwitch_e useBlockSplitter; + + /* Param for deciding whether to use row-based matchfinder */ + ZSTD_paramSwitch_e useRowMatchFinder; + + /* Always load a dictionary in ext-dict mode (not prefix mode)? */ + int deterministicRefPrefix; + /* Internal use, for createCCtxParams() and freeCCtxParams() only */ ZSTD_customMem customMem; + + /* Controls prefetching in some dictMatchState matchfinders */ + ZSTD_paramSwitch_e prefetchCDictTables; }; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */ +#define COMPRESS_SEQUENCES_WORKSPACE_SIZE (sizeof(unsigned) * (MaxSeq + 2)) +#define ENTROPY_WORKSPACE_SIZE (HUF_WORKSPACE_SIZE + COMPRESS_SEQUENCES_WORKSPACE_SIZE) + +/** + * Indicates whether this compression proceeds directly from user-provided + * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or + * whether the context needs to buffer the input/output (ZSTDb_buffered). + */ +typedef enum { + ZSTDb_not_buffered, + ZSTDb_buffered +} ZSTD_buffered_policy_e; + +/** + * Struct that contains all elements of block splitter that should be allocated + * in a wksp. + */ +#define ZSTD_MAX_NB_BLOCK_SPLITS 196 +typedef struct { + seqStore_t fullSeqStoreChunk; + seqStore_t firstHalfSeqStore; + seqStore_t secondHalfSeqStore; + seqStore_t currSeqStore; + seqStore_t nextSeqStore; + + U32 partitions[ZSTD_MAX_NB_BLOCK_SPLITS]; + ZSTD_entropyCTablesMetadata_t entropyMetadata; +} ZSTD_blockSplitCtx; + struct ZSTD_CCtx_s { ZSTD_compressionStage_e stage; int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ ZSTD_CCtx_params requestedParams; ZSTD_CCtx_params appliedParams; + ZSTD_CCtx_params simpleApiParams; /* Param storage used by the simple API - not sticky. Must only be used in top-level simple API functions for storage. */ U32 dictID; + size_t dictContentSize; ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */ size_t blockSize; @@ -246,9 +387,11 @@ struct ZSTD_CCtx_s { unsigned long long producedCSize; XXH64_state_t xxhState; ZSTD_customMem customMem; + ZSTD_threadPool* pool; size_t staticSize; SeqCollector seqCollector; int isFirstBlock; + int initialized; seqStore_t seqStore; /* sequences storage ptrs */ ldmState_t ldmState; /* long distance matching state */ @@ -256,7 +399,10 @@ struct ZSTD_CCtx_s { size_t maxNbLdmSequences; rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */ ZSTD_blockState_t blockState; - U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ + U32* entropyWorkspace; /* entropy workspace of ENTROPY_WORKSPACE_SIZE bytes */ + + /* Whether we are streaming or not */ + ZSTD_buffered_policy_e bufferedPolicy; /* streaming */ char* inBuff; @@ -271,6 +417,11 @@ struct ZSTD_CCtx_s { ZSTD_cStreamStage streamStage; U32 frameEnded; + /* Stable in/out buffer verification */ + ZSTD_inBuffer expectedInBuffer; + size_t stableIn_notConsumed; /* nb bytes within stable input buffer that are said to be consumed but are not */ + size_t expectedOutBufferSize; + /* Dictionary */ ZSTD_localDict localDict; const ZSTD_CDict* cdict; @@ -280,17 +431,50 @@ struct ZSTD_CCtx_s { #ifdef ZSTD_MULTITHREAD ZSTDMT_CCtx* mtctx; #endif -}; -typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; + /* Tracing */ +#if ZSTD_TRACE + ZSTD_TraceCtx traceCtx; +#endif -typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e; + /* Workspace for block splitter */ + ZSTD_blockSplitCtx blockSplitCtx; +}; +typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; +typedef enum { ZSTD_tfp_forCCtx, ZSTD_tfp_forCDict } ZSTD_tableFillPurpose_e; + +typedef enum { + ZSTD_noDict = 0, + ZSTD_extDict = 1, + ZSTD_dictMatchState = 2, + ZSTD_dedicatedDictSearch = 3 +} ZSTD_dictMode_e; + +typedef enum { + ZSTD_cpm_noAttachDict = 0, /* Compression with ZSTD_noDict or ZSTD_extDict. + * In this mode we use both the srcSize and the dictSize + * when selecting and adjusting parameters. + */ + ZSTD_cpm_attachDict = 1, /* Compression with ZSTD_dictMatchState or ZSTD_dedicatedDictSearch. + * In this mode we only take the srcSize into account when selecting + * and adjusting parameters. + */ + ZSTD_cpm_createCDict = 2, /* Creating a CDict. + * In this mode we take both the source size and the dictionary size + * into account when selecting and adjusting the parameters. + */ + ZSTD_cpm_unknown = 3, /* ZSTD_getCParams, ZSTD_getParams, ZSTD_adjustParams. + * We don't know what these parameters are for. We default to the legacy + * behavior of taking both the source size and the dict size into account + * when selecting and adjusting parameters. + */ +} ZSTD_cParamMode_e; typedef size_t (*ZSTD_blockCompressor) ( ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode); +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e rowMatchfinderMode, ZSTD_dictMode_e dictMode); MEM_STATIC U32 ZSTD_LLcode(U32 litLength) @@ -336,6 +520,33 @@ MEM_STATIC int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value) return 1; } +/* ZSTD_noCompressBlock() : + * Writes uncompressed block to dst buffer from given src. + * Returns the size of the block */ +MEM_STATIC size_t +ZSTD_noCompressBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) +{ + U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); + DEBUGLOG(5, "ZSTD_noCompressBlock (srcSize=%zu, dstCapacity=%zu)", srcSize, dstCapacity); + RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, + dstSize_tooSmall, "dst buf too small for uncompressed block"); + MEM_writeLE24(dst, cBlockHeader24); + ZSTD_memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); + return ZSTD_blockHeaderSize + srcSize; +} + +MEM_STATIC size_t +ZSTD_rleCompressBlock(void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock) +{ + BYTE* const op = (BYTE*)dst; + U32 const cBlockHeader = lastBlock + (((U32)bt_rle)<<1) + (U32)(srcSize << 3); + RETURN_ERROR_IF(dstCapacity < 4, dstSize_tooSmall, ""); + MEM_writeLE24(op, cBlockHeader); + op[3] = src; + return 4; +} + + /* ZSTD_minGain() : * minimum compression required * to generate a compress block or a compressed literals section. @@ -348,12 +559,29 @@ MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) return (srcSize >> minlog) + 2; } +MEM_STATIC int ZSTD_literalsCompressionIsDisabled(const ZSTD_CCtx_params* cctxParams) +{ + switch (cctxParams->literalCompressionMode) { + case ZSTD_ps_enable: + return 0; + case ZSTD_ps_disable: + return 1; + default: + assert(0 /* impossible: pre-validated */); + ZSTD_FALLTHROUGH; + case ZSTD_ps_auto: + return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); + } +} + /*! ZSTD_safecopyLiterals() : * memcpy() function that won't read beyond more than WILDCOPY_OVERLENGTH bytes past ilimit_w. * Only called when the sequence ends past ilimit_w, so it only needs to be optimized for single * large copies. */ -static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) { +static void +ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) +{ assert(iend > ilimit_w); if (ip <= ilimit_w) { ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap); @@ -363,14 +591,28 @@ static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const ie while (ip < iend) *op++ = *ip++; } + +#define REPCODE1_TO_OFFBASE REPCODE_TO_OFFBASE(1) +#define REPCODE2_TO_OFFBASE REPCODE_TO_OFFBASE(2) +#define REPCODE3_TO_OFFBASE REPCODE_TO_OFFBASE(3) +#define REPCODE_TO_OFFBASE(r) (assert((r)>=1), assert((r)<=ZSTD_REP_NUM), (r)) /* accepts IDs 1,2,3 */ +#define OFFSET_TO_OFFBASE(o) (assert((o)>0), o + ZSTD_REP_NUM) +#define OFFBASE_IS_OFFSET(o) ((o) > ZSTD_REP_NUM) +#define OFFBASE_IS_REPCODE(o) ( 1 <= (o) && (o) <= ZSTD_REP_NUM) +#define OFFBASE_TO_OFFSET(o) (assert(OFFBASE_IS_OFFSET(o)), (o) - ZSTD_REP_NUM) +#define OFFBASE_TO_REPCODE(o) (assert(OFFBASE_IS_REPCODE(o)), (o)) /* returns ID 1,2,3 */ + /*! ZSTD_storeSeq() : - * Store a sequence (litlen, litPtr, offCode and mlBase) into seqStore_t. - * `offCode` : distance to match + ZSTD_REP_MOVE (values <= ZSTD_REP_MOVE are repCodes). - * `mlBase` : matchLength - MINMATCH - * Allowed to overread literals up to litLimit. + * Store a sequence (litlen, litPtr, offBase and matchLength) into seqStore_t. + * @offBase : Users should employ macros REPCODE_TO_OFFBASE() and OFFSET_TO_OFFBASE(). + * @matchLength : must be >= MINMATCH + * Allowed to over-read literals up to litLimit. */ -HINT_INLINE UNUSED_ATTR -void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, const BYTE* litLimit, U32 offCode, size_t mlBase) +HINT_INLINE UNUSED_ATTR void +ZSTD_storeSeq(seqStore_t* seqStorePtr, + size_t litLength, const BYTE* literals, const BYTE* litLimit, + U32 offBase, + size_t matchLength) { BYTE const* const litLimit_w = litLimit - WILDCOPY_OVERLENGTH; BYTE const* const litEnd = literals + litLength; @@ -378,8 +620,8 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera static const BYTE* g_start = NULL; if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */ { U32 const pos = (U32)((const BYTE*)literals - g_start); - DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u", - pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offCode); + DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offBase%7u", + pos, (U32)litLength, (U32)matchLength, (U32)offBase); } #endif assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq); @@ -389,9 +631,9 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera assert(literals + litLength <= litLimit); if (litEnd <= litLimit_w) { /* Common case we can use wildcopy. - * First copy 16 bytes, because literals are likely short. - */ - assert(WILDCOPY_OVERLENGTH >= 16); + * First copy 16 bytes, because literals are likely short. + */ + ZSTD_STATIC_ASSERT(WILDCOPY_OVERLENGTH >= 16); ZSTD_copy16(seqStorePtr->lit, literals); if (litLength > 16) { ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, (ptrdiff_t)litLength-16, ZSTD_no_overlap); @@ -403,99 +645,70 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera /* literal Length */ if (litLength>0xFFFF) { - assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ - seqStorePtr->longLengthID = 1; + assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ + seqStorePtr->longLengthType = ZSTD_llt_literalLength; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); } seqStorePtr->sequences[0].litLength = (U16)litLength; /* match offset */ - seqStorePtr->sequences[0].offset = offCode + 1; + seqStorePtr->sequences[0].offBase = offBase; /* match Length */ - if (mlBase>0xFFFF) { - assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ - seqStorePtr->longLengthID = 2; - seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + assert(matchLength >= MINMATCH); + { size_t const mlBase = matchLength - MINMATCH; + if (mlBase>0xFFFF) { + assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ + seqStorePtr->longLengthType = ZSTD_llt_matchLength; + seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + } + seqStorePtr->sequences[0].mlBase = (U16)mlBase; } - seqStorePtr->sequences[0].matchLength = (U16)mlBase; seqStorePtr->sequences++; } - -/*-************************************* -* Match length counter -***************************************/ -static unsigned ZSTD_NbCommonBytes (size_t val) -{ - if (MEM_isLittleEndian()) { - if (MEM_64bits()) { -# if defined(_MSC_VER) && defined(_WIN64) - unsigned long r = 0; - _BitScanForward64( &r, (U64)val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, - 0, 3, 1, 3, 1, 4, 2, 7, - 0, 2, 3, 6, 1, 5, 3, 5, - 1, 3, 4, 4, 2, 5, 6, 7, - 7, 0, 1, 2, 3, 3, 4, 6, - 2, 6, 5, 5, 3, 4, 5, 6, - 7, 1, 2, 4, 6, 4, 4, 5, - 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } else { /* 32 bits */ -# if defined(_MSC_VER) - unsigned long r=0; - _BitScanForward( &r, (U32)val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, - 3, 2, 2, 1, 3, 2, 0, 1, - 3, 3, 1, 2, 2, 2, 2, 0, - 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif +/* ZSTD_updateRep() : + * updates in-place @rep (array of repeat offsets) + * @offBase : sum-type, using numeric representation of ZSTD_storeSeq() + */ +MEM_STATIC void +ZSTD_updateRep(U32 rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) +{ + if (OFFBASE_IS_OFFSET(offBase)) { /* full offset */ + rep[2] = rep[1]; + rep[1] = rep[0]; + rep[0] = OFFBASE_TO_OFFSET(offBase); + } else { /* repcode */ + U32 const repCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; + if (repCode > 0) { /* note : if repCode==0, no change */ + U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; + rep[2] = (repCode >= 2) ? rep[1] : rep[2]; + rep[1] = rep[0]; + rep[0] = currentOffset; + } else { /* repCode == 0 */ + /* nothing to do */ } - } else { /* Big Endian CPU */ - if (MEM_64bits()) { -# if defined(_MSC_VER) && defined(_WIN64) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (__builtin_clzll(val) >> 3); -# else - unsigned r; - const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ - if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; -# endif - } else { /* 32 bits */ -# if defined(_MSC_VER) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; -# endif - } } + } +} + +typedef struct repcodes_s { + U32 rep[3]; +} repcodes_t; + +MEM_STATIC repcodes_t +ZSTD_newRep(U32 const rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) +{ + repcodes_t newReps; + ZSTD_memcpy(&newReps, rep, sizeof(newReps)); + ZSTD_updateRep(newReps.rep, offBase, ll0); + return newReps; } +/*-************************************* +* Match length counter +***************************************/ MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit) { const BYTE* const pStart = pIn; @@ -541,31 +754,36 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match, * Hashes ***************************************/ static const U32 prime3bytes = 506832829U; -static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; } +static U32 ZSTD_hash3(U32 u, U32 h) { assert(h <= 32); return ((u << (32-24)) * prime3bytes) >> (32-h) ; } MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */ static const U32 prime4bytes = 2654435761U; -static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; } -static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); } +static U32 ZSTD_hash4(U32 u, U32 h) { assert(h <= 32); return (u * prime4bytes) >> (32-h) ; } +static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_readLE32(ptr), h); } static const U64 prime5bytes = 889523592379ULL; -static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; } +static size_t ZSTD_hash5(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; } static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); } static const U64 prime6bytes = 227718039650203ULL; -static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } +static size_t ZSTD_hash6(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } static const U64 prime7bytes = 58295818150454627ULL; -static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; } +static size_t ZSTD_hash7(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; } static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); } static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL; -static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; } +static size_t ZSTD_hash8(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u) * prime8bytes) >> (64-h)) ; } static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); } -MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) +MEM_STATIC FORCE_INLINE_ATTR +size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) { + /* Although some of these hashes do support hBits up to 64, some do not. + * To be on the safe side, always avoid hBits > 32. */ + assert(hBits <= 32); + switch(mls) { default: @@ -661,6 +879,13 @@ MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window) window->dictLimit = end; } +MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window) +{ + return window.dictLimit == ZSTD_WINDOW_START_INDEX && + window.lowLimit == ZSTD_WINDOW_START_INDEX && + (window.nextSrc - window.base) == ZSTD_WINDOW_START_INDEX; +} + /** * ZSTD_window_hasExtDict(): * Returns non-zero if the window has a non-empty extDict. @@ -680,20 +905,76 @@ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms) return ZSTD_window_hasExtDict(ms->window) ? ZSTD_extDict : ms->dictMatchState != NULL ? - ZSTD_dictMatchState : + (ms->dictMatchState->dedicatedDictSearch ? ZSTD_dedicatedDictSearch : ZSTD_dictMatchState) : ZSTD_noDict; } +/* Defining this macro to non-zero tells zstd to run the overflow correction + * code much more frequently. This is very inefficient, and should only be + * used for tests and fuzzers. + */ +#ifndef ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY +# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 1 +# else +# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 0 +# endif +#endif + +/** + * ZSTD_window_canOverflowCorrect(): + * Returns non-zero if the indices are large enough for overflow correction + * to work correctly without impacting compression ratio. + */ +MEM_STATIC U32 ZSTD_window_canOverflowCorrect(ZSTD_window_t const window, + U32 cycleLog, + U32 maxDist, + U32 loadedDictEnd, + void const* src) +{ + U32 const cycleSize = 1u << cycleLog; + U32 const curr = (U32)((BYTE const*)src - window.base); + U32 const minIndexToOverflowCorrect = cycleSize + + MAX(maxDist, cycleSize) + + ZSTD_WINDOW_START_INDEX; + + /* Adjust the min index to backoff the overflow correction frequency, + * so we don't waste too much CPU in overflow correction. If this + * computation overflows we don't really care, we just need to make + * sure it is at least minIndexToOverflowCorrect. + */ + U32 const adjustment = window.nbOverflowCorrections + 1; + U32 const adjustedIndex = MAX(minIndexToOverflowCorrect * adjustment, + minIndexToOverflowCorrect); + U32 const indexLargeEnough = curr > adjustedIndex; + + /* Only overflow correct early if the dictionary is invalidated already, + * so we don't hurt compression ratio. + */ + U32 const dictionaryInvalidated = curr > maxDist + loadedDictEnd; + + return indexLargeEnough && dictionaryInvalidated; +} + /** * ZSTD_window_needOverflowCorrection(): * Returns non-zero if the indices are getting too large and need overflow * protection. */ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, + U32 cycleLog, + U32 maxDist, + U32 loadedDictEnd, + void const* src, void const* srcEnd) { - U32 const current = (U32)((BYTE const*)srcEnd - window.base); - return current > ZSTD_CURRENT_MAX; + U32 const curr = (U32)((BYTE const*)srcEnd - window.base); + if (ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { + if (ZSTD_window_canOverflowCorrect(window, cycleLog, maxDist, loadedDictEnd, src)) { + return 1; + } + } + return curr > ZSTD_CURRENT_MAX; } /** @@ -704,7 +985,6 @@ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, * * The least significant cycleLog bits of the indices must remain the same, * which may be 0. Every index up to maxDist in the past must be valid. - * NOTE: (maxDist & cycleMask) must be zero. */ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, U32 maxDist, void const* src) @@ -728,19 +1008,51 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, * 3. (cctx->lowLimit + 1< 3<<29 + 1<base); - U32 const newCurrent = (current & cycleMask) + maxDist; - U32 const correction = current - newCurrent; - assert((maxDist & cycleMask) == 0); - assert(current > newCurrent); - /* Loose bound, should be around 1<<29 (see above) */ - assert(correction > 1<<28); + U32 const cycleSize = 1u << cycleLog; + U32 const cycleMask = cycleSize - 1; + U32 const curr = (U32)((BYTE const*)src - window->base); + U32 const currentCycle = curr & cycleMask; + /* Ensure newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX. */ + U32 const currentCycleCorrection = currentCycle < ZSTD_WINDOW_START_INDEX + ? MAX(cycleSize, ZSTD_WINDOW_START_INDEX) + : 0; + U32 const newCurrent = currentCycle + + currentCycleCorrection + + MAX(maxDist, cycleSize); + U32 const correction = curr - newCurrent; + /* maxDist must be a power of two so that: + * (newCurrent & cycleMask) == (curr & cycleMask) + * This is required to not corrupt the chains / binary tree. + */ + assert((maxDist & (maxDist - 1)) == 0); + assert((curr & cycleMask) == (newCurrent & cycleMask)); + assert(curr > newCurrent); + if (!ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { + /* Loose bound, should be around 1<<29 (see above) */ + assert(correction > 1<<28); + } window->base += correction; window->dictBase += correction; - window->lowLimit -= correction; - window->dictLimit -= correction; + if (window->lowLimit < correction + ZSTD_WINDOW_START_INDEX) { + window->lowLimit = ZSTD_WINDOW_START_INDEX; + } else { + window->lowLimit -= correction; + } + if (window->dictLimit < correction + ZSTD_WINDOW_START_INDEX) { + window->dictLimit = ZSTD_WINDOW_START_INDEX; + } else { + window->dictLimit -= correction; + } + + /* Ensure we can still reference the full window. */ + assert(newCurrent >= maxDist); + assert(newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX); + /* Ensure that lowLimit and dictLimit didn't underflow. */ + assert(window->lowLimit <= newCurrent); + assert(window->dictLimit <= newCurrent); + + ++window->nbOverflowCorrections; DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, window->lowLimit); @@ -844,6 +1156,17 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, } } } } +MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) { + ZSTD_memset(window, 0, sizeof(*window)); + window->base = (BYTE const*)" "; + window->dictBase = (BYTE const*)" "; + ZSTD_STATIC_ASSERT(ZSTD_DUBT_UNSORTED_MARK < ZSTD_WINDOW_START_INDEX); /* Start above ZSTD_DUBT_UNSORTED_MARK */ + window->dictLimit = ZSTD_WINDOW_START_INDEX; /* start from >0, so that 1st position is valid */ + window->lowLimit = ZSTD_WINDOW_START_INDEX; /* it ensures first and later CCtx usages compress the same */ + window->nextSrc = window->base + ZSTD_WINDOW_START_INDEX; /* see issue #1241 */ + window->nbOverflowCorrections = 0; +} + /** * ZSTD_window_update(): * Updates the window by appending [src, src + srcSize) to the window. @@ -852,13 +1175,18 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, * Returns non-zero if the segment is contiguous. */ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, - void const* src, size_t srcSize) + void const* src, size_t srcSize, + int forceNonContiguous) { BYTE const* const ip = (BYTE const*)src; U32 contiguous = 1; DEBUGLOG(5, "ZSTD_window_update"); + if (srcSize == 0) + return contiguous; + assert(window->base != NULL); + assert(window->dictBase != NULL); /* Check if blocks follow each other */ - if (src != window->nextSrc) { + if (src != window->nextSrc || forceNonContiguous) { /* not contiguous */ size_t const distanceFromBase = (size_t)(window->nextSrc - window->base); DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit); @@ -867,7 +1195,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, window->dictLimit = (U32)distanceFromBase; window->dictBase = window->base; window->base = ip - distanceFromBase; - // ms->nextToUpdate = window->dictLimit; + /* ms->nextToUpdate = window->dictLimit; */ if (window->dictLimit - window->lowLimit < HASH_READ_SIZE) window->lowLimit = window->dictLimit; /* too small extDict */ contiguous = 0; } @@ -883,12 +1211,35 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, return contiguous; } -MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog) +/** + * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix. + */ +MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) +{ + U32 const maxDistance = 1U << windowLog; + U32 const lowestValid = ms->window.lowLimit; + U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + U32 const isDictionary = (ms->loadedDictEnd != 0); + /* When using a dictionary the entire dictionary is valid if a single byte of the dictionary + * is within the window. We invalidate the dictionary (and set loadedDictEnd to 0) when it isn't + * valid for the entire block. So this check is sufficient to find the lowest valid match index. + */ + U32 const matchLowest = isDictionary ? lowestValid : withinWindow; + return matchLowest; +} + +/** + * Returns the lowest allowed match index in the prefix. + */ +MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) { U32 const maxDistance = 1U << windowLog; - U32 const lowestValid = ms->window.lowLimit; - U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; + U32 const lowestValid = ms->window.dictLimit; + U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; U32 const isDictionary = (ms->loadedDictEnd != 0); + /* When computing the lowest prefix index we need to take the dictionary into account to handle + * the edge case where the dictionary and the source are contiguous in memory. + */ U32 const matchLowest = isDictionary ? lowestValid : withinWindow; return matchLowest; } @@ -926,11 +1277,61 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max) #endif +/* Short Cache */ + +/* Normally, zstd matchfinders follow this flow: + * 1. Compute hash at ip + * 2. Load index from hashTable[hash] + * 3. Check if *ip == *(base + index) + * In dictionary compression, loading *(base + index) is often an L2 or even L3 miss. + * + * Short cache is an optimization which allows us to avoid step 3 most of the time + * when the data doesn't actually match. With short cache, the flow becomes: + * 1. Compute (hash, currentTag) at ip. currentTag is an 8-bit independent hash at ip. + * 2. Load (index, matchTag) from hashTable[hash]. See ZSTD_writeTaggedIndex to understand how this works. + * 3. Only if currentTag == matchTag, check *ip == *(base + index). Otherwise, continue. + * + * Currently, short cache is only implemented in CDict hashtables. Thus, its use is limited to + * dictMatchState matchfinders. + */ +#define ZSTD_SHORT_CACHE_TAG_BITS 8 +#define ZSTD_SHORT_CACHE_TAG_MASK ((1u << ZSTD_SHORT_CACHE_TAG_BITS) - 1) + +/* Helper function for ZSTD_fillHashTable and ZSTD_fillDoubleHashTable. + * Unpacks hashAndTag into (hash, tag), then packs (index, tag) into hashTable[hash]. */ +MEM_STATIC void ZSTD_writeTaggedIndex(U32* const hashTable, size_t hashAndTag, U32 index) { + size_t const hash = hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const tag = (U32)(hashAndTag & ZSTD_SHORT_CACHE_TAG_MASK); + assert(index >> (32 - ZSTD_SHORT_CACHE_TAG_BITS) == 0); + hashTable[hash] = (index << ZSTD_SHORT_CACHE_TAG_BITS) | tag; +} + +/* Helper function for short cache matchfinders. + * Unpacks tag1 and tag2 from lower bits of packedTag1 and packedTag2, then checks if the tags match. */ +MEM_STATIC int ZSTD_comparePackedTags(size_t packedTag1, size_t packedTag2) { + U32 const tag1 = packedTag1 & ZSTD_SHORT_CACHE_TAG_MASK; + U32 const tag2 = packedTag2 & ZSTD_SHORT_CACHE_TAG_MASK; + return tag1 == tag2; +} #if defined (__cplusplus) } #endif +/* =============================================================== + * Shared internal declarations + * These prototypes may be called from sources not in lib/compress + * =============================================================== */ + +/* ZSTD_loadCEntropy() : + * dict : must point at beginning of a valid zstd dictionary. + * return : size of dictionary header (size of magic number + dict ID + entropy tables) + * assumptions : magic number supposed already checked + * and dictSize >= 8 */ +size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, + const void* const dict, size_t dictSize); + +void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs); /* ============================================================== * Private declarations @@ -940,9 +1341,10 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max) /* ZSTD_getCParamsFromCCtxParams() : * cParams are built depending on compressionLevel, src size hints, * LDM and manually set compression parameters. + * Note: srcSizeHint == 0 means 0! */ ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize); + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); /*! ZSTD_initCStream_internal() : * Private use only. Init streaming operation. @@ -999,5 +1401,13 @@ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity); */ size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq); +/** ZSTD_cycleLog() : + * condition for correct operation : hashLog > 1 */ +U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat); + +/** ZSTD_CCtx_trace() : + * Trace the end of a compression call. + */ +void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize); #endif /* ZSTD_COMPRESS_H */ diff --git a/native/zstd/compress/zstd_compress_literals.c b/native/zstd/compress/zstd_compress_literals.c old mode 100755 new mode 100644 index 6c13331..15bde09 --- a/native/zstd/compress/zstd_compress_literals.c +++ b/native/zstd/compress/zstd_compress_literals.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -13,12 +13,37 @@ ***************************************/ #include "zstd_compress_literals.h" + +/* ************************************************************** +* Debug Traces +****************************************************************/ +#if DEBUGLEVEL >= 2 + +static size_t showHexa(const void* src, size_t srcSize) +{ + const BYTE* const ip = (const BYTE*)src; + size_t u; + for (u=0; u31) + (srcSize>4095); - RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall); + DEBUGLOG(5, "ZSTD_noCompressLiterals: srcSize=%zu, dstCapacity=%zu", srcSize, dstCapacity); + + RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, ""); switch(flSize) { @@ -35,13 +60,14 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, assert(0); } - memcpy(ostart + flSize, src, srcSize); + ZSTD_memcpy(ostart + flSize, src, srcSize); + DEBUGLOG(5, "Raw (uncompressed) literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); return srcSize + flSize; } size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ @@ -62,6 +88,7 @@ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* } ostart[flSize] = *(const BYTE*)src; + DEBUGLOG(5, "RLE literals: %u -> %u", (U32)srcSize, (U32)flSize + 1); return flSize+1; } @@ -71,7 +98,8 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, void* dst, size_t dstCapacity, const void* src, size_t srcSize, void* entropyWorkspace, size_t entropyWorkspaceSize, - const int bmi2) + const int bmi2, + unsigned suspectUncompressible) { size_t const minGain = ZSTD_minGain(srcSize, strategy); size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); @@ -80,11 +108,13 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, symbolEncodingType_e hType = set_compressed; size_t cLitSize; - DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)", - disableLiteralCompression); + DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i, srcSize=%u, dstCapacity=%zu)", + disableLiteralCompression, (U32)srcSize, dstCapacity); + + DEBUGLOG(6, "Completed literals listing (%zu bytes)", showHexa(src, srcSize)); /* Prepare nextEntropy assuming reusing the existing table */ - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); if (disableLiteralCompression) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); @@ -97,29 +127,31 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression"); { HUF_repeat repeat = prevHuf->repeatMode; - int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; + int const preferRepeat = (strategy < ZSTD_lazy) ? srcSize <= 1024 : 0; + typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int, int, unsigned); + huf_compress_f huf_compress; if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; - cLitSize = singleStream ? - HUF_compress1X_repeat( - ostart+lhSize, dstCapacity-lhSize, src, srcSize, - 255, 11, entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) : - HUF_compress4X_repeat( - ostart+lhSize, dstCapacity-lhSize, src, srcSize, - 255, 11, entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2); + huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat; + cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize, + src, srcSize, + HUF_SYMBOLVALUE_MAX, LitHufLog, + entropyWorkspace, entropyWorkspaceSize, + (HUF_CElt*)nextHuf->CTable, + &repeat, preferRepeat, + bmi2, suspectUncompressible); if (repeat != HUF_repeat_none) { /* reused the existing table */ + DEBUGLOG(5, "Reusing previous huffman table"); hType = set_repeat; } } - if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) { + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); } if (cLitSize==1) { - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); } @@ -132,7 +164,7 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); + { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); MEM_writeLE24(ostart, lhc); break; } @@ -150,5 +182,6 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, default: /* not possible : lhSize is {3,4,5} */ assert(0); } + DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)srcSize, (U32)(lhSize+cLitSize)); return lhSize+cLitSize; } diff --git a/native/zstd/compress/zstd_compress_literals.h b/native/zstd/compress/zstd_compress_literals.h old mode 100755 new mode 100644 index 97273d7..9775fb9 --- a/native/zstd/compress/zstd_compress_literals.h +++ b/native/zstd/compress/zstd_compress_literals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -18,12 +18,14 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize); +/* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, ZSTD_hufCTables_t* nextHuf, ZSTD_strategy strategy, int disableLiteralCompression, void* dst, size_t dstCapacity, const void* src, size_t srcSize, void* entropyWorkspace, size_t entropyWorkspaceSize, - const int bmi2); + const int bmi2, + unsigned suspectUncompressible); #endif /* ZSTD_COMPRESS_LITERALS_H */ diff --git a/native/zstd/compress/zstd_compress_sequences.c b/native/zstd/compress/zstd_compress_sequences.c old mode 100755 new mode 100644 index 0ff7a26..2c1eee5 --- a/native/zstd/compress/zstd_compress_sequences.c +++ b/native/zstd/compress/zstd_compress_sequences.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -50,6 +50,19 @@ static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) { return maxSymbolValue; } +/** + * Returns true if we should use ncount=-1 else we should + * use ncount=1 for low probability symbols instead. + */ +static unsigned ZSTD_useLowProbCount(size_t const nbSeq) +{ + /* Heuristic: This should cover most blocks <= 16K and + * start to fade out after 16K to about 32K depending on + * compressibility. + */ + return nbSeq >= 2048; +} + /** * Returns the cost in bytes of encoding the normalized count header. * Returns an error if any of the helper functions return an error. @@ -60,7 +73,7 @@ static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max, BYTE wksp[FSE_NCOUNTBOUND]; S16 norm[MaxSeq + 1]; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); - FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max)); + FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max, ZSTD_useLowProbCount(nbSeq)), ""); return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog); } @@ -72,6 +85,8 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t { unsigned cost = 0; unsigned s; + + assert(total > 0); for (s = 0; s <= max; ++s) { unsigned norm = (unsigned)((256 * count[s]) / total); if (count[s] != 0 && norm == 0) @@ -86,7 +101,7 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t * Returns the cost in bits of encoding the distribution in count using ctable. * Returns an error if ctable cannot represent all the symbols in count. */ -static size_t ZSTD_fseBitCost( +size_t ZSTD_fseBitCost( FSE_CTable const* ctable, unsigned const* count, unsigned const max) @@ -96,18 +111,22 @@ static size_t ZSTD_fseBitCost( unsigned s; FSE_CState_t cstate; FSE_initCState(&cstate, ctable); - RETURN_ERROR_IF(ZSTD_getFSEMaxSymbolValue(ctable) < max, GENERIC, - "Repeat FSE_CTable has maxSymbolValue %u < %u", + if (ZSTD_getFSEMaxSymbolValue(ctable) < max) { + DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u", ZSTD_getFSEMaxSymbolValue(ctable), max); + return ERROR(GENERIC); + } for (s = 0; s <= max; ++s) { unsigned const tableLog = cstate.stateLog; unsigned const badCost = (tableLog + 1) << kAccuracyLog; unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog); if (count[s] == 0) continue; - RETURN_ERROR_IF(bitCost >= badCost, GENERIC, - "Repeat FSE_CTable has Prob[%u] == 0", s); - cost += count[s] * bitCost; + if (bitCost >= badCost) { + DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s); + return ERROR(GENERIC); + } + cost += (size_t)count[s] * bitCost; } return cost >> kAccuracyLog; } @@ -117,15 +136,15 @@ static size_t ZSTD_fseBitCost( * table described by norm. The max symbol support by norm is assumed >= max. * norm must be valid for every symbol with non-zero probability in count. */ -static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, - unsigned const* count, unsigned const max) +size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, + unsigned const* count, unsigned const max) { unsigned const shift = 8 - accuracyLog; size_t cost = 0; unsigned s; assert(accuracyLog <= 8); for (s = 0; s <= max; ++s) { - unsigned const normAcc = norm[s] != -1 ? norm[s] : 1; + unsigned const normAcc = (norm[s] != -1) ? (unsigned)norm[s] : 1; unsigned const norm256 = normAcc << shift; assert(norm256 > 0); assert(norm256 < 256); @@ -147,7 +166,7 @@ ZSTD_selectEncodingType( if (mostFrequent == nbSeq) { *repeatMode = FSE_repeat_none; if (isDefaultAllowed && nbSeq <= 2) { - /* Prefer set_basic over set_rle when there are 2 or less symbols, + /* Prefer set_basic over set_rle when there are 2 or fewer symbols, * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. * If basic encoding isn't possible, always choose RLE. */ @@ -215,6 +234,11 @@ ZSTD_selectEncodingType( return set_compressed; } +typedef struct { + S16 norm[MaxSeq + 1]; + U32 wksp[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(MaxSeq, MaxFSELog)]; +} ZSTD_BuildCTableWksp; + size_t ZSTD_buildCTable(void* dst, size_t dstCapacity, FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, @@ -230,18 +254,18 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, switch (type) { case set_rle: - FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max)); - RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall); + FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max), ""); + RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall, "not enough space"); *op = codeTable[0]; return 1; case set_repeat: - memcpy(nextCTable, prevCTable, prevCTableSize); + ZSTD_memcpy(nextCTable, prevCTable, prevCTableSize); return 0; case set_basic: - FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize)); /* note : could be pre-calculated */ + FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), ""); /* note : could be pre-calculated */ return 0; case set_compressed: { - S16 norm[MaxSeq + 1]; + ZSTD_BuildCTableWksp* wksp = (ZSTD_BuildCTableWksp*)entropyWorkspace; size_t nbSeq_1 = nbSeq; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); if (count[codeTable[nbSeq-1]] > 1) { @@ -249,14 +273,17 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, nbSeq_1--; } assert(nbSeq_1 > 1); - FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max)); - { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */ - FORWARD_IF_ERROR(NCountSize); - FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize)); + assert(entropyWorkspaceSize >= sizeof(ZSTD_BuildCTableWksp)); + (void)entropyWorkspaceSize; + FORWARD_IF_ERROR(FSE_normalizeCount(wksp->norm, tableLog, count, nbSeq_1, max, ZSTD_useLowProbCount(nbSeq_1)), "FSE_normalizeCount failed"); + assert(oend >= op); + { size_t const NCountSize = FSE_writeNCount(op, (size_t)(oend - op), wksp->norm, max, tableLog); /* overflow protected */ + FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed"); + FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, wksp->norm, max, tableLog, wksp->wksp, sizeof(wksp->wksp)), "FSE_buildCTable_wksp failed"); return NCountSize; } } - default: assert(0); RETURN_ERROR(GENERIC); + default: assert(0); RETURN_ERROR(GENERIC, "impossible to reach"); } } @@ -286,19 +313,19 @@ ZSTD_encodeSequences_body( FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]); + BIT_addBits(&blockStream, sequences[nbSeq-1].mlBase, ML_bits[mlCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); if (longOffsets) { U32 const ofBits = ofCodeTable[nbSeq-1]; - int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); + unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits); + BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, extraBits); BIT_flushBits(&blockStream); } - BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits, + BIT_addBits(&blockStream, sequences[nbSeq-1].offBase >> extraBits, ofBits - extraBits); } else { - BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); + BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, ofCodeTable[nbSeq-1]); } BIT_flushBits(&blockStream); @@ -312,8 +339,8 @@ ZSTD_encodeSequences_body( U32 const mlBits = ML_bits[mlCode]; DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u", (unsigned)sequences[n].litLength, - (unsigned)sequences[n].matchLength + MINMATCH, - (unsigned)sequences[n].offset); + (unsigned)sequences[n].mlBase + MINMATCH, + (unsigned)sequences[n].offBase); /* 32b*/ /* 64b*/ /* (7)*/ /* (7)*/ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ @@ -324,18 +351,18 @@ ZSTD_encodeSequences_body( BIT_flushBits(&blockStream); /* (7)*/ BIT_addBits(&blockStream, sequences[n].litLength, llBits); if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); + BIT_addBits(&blockStream, sequences[n].mlBase, mlBits); if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); if (longOffsets) { - int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); + unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[n].offset, extraBits); + BIT_addBits(&blockStream, sequences[n].offBase, extraBits); BIT_flushBits(&blockStream); /* (7)*/ } - BIT_addBits(&blockStream, sequences[n].offset >> extraBits, + BIT_addBits(&blockStream, sequences[n].offBase >> extraBits, ofBits - extraBits); /* 31 */ } else { - BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ + BIT_addBits(&blockStream, sequences[n].offBase, ofBits); /* 31 */ } BIT_flushBits(&blockStream); /* (7)*/ DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr)); @@ -372,7 +399,7 @@ ZSTD_encodeSequences_default( #if DYNAMIC_BMI2 -static TARGET_ATTRIBUTE("bmi2") size_t +static BMI2_TARGET_ATTRIBUTE size_t ZSTD_encodeSequences_bmi2( void* dst, size_t dstCapacity, FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, diff --git a/native/zstd/compress/zstd_compress_sequences.h b/native/zstd/compress/zstd_compress_sequences.h old mode 100755 new mode 100644 index 57e8e36..7991364 --- a/native/zstd/compress/zstd_compress_sequences.h +++ b/native/zstd/compress/zstd_compress_sequences.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,8 +11,8 @@ #ifndef ZSTD_COMPRESS_SEQUENCES_H #define ZSTD_COMPRESS_SEQUENCES_H -#include "fse.h" /* FSE_repeat, FSE_CTable */ -#include "zstd_internal.h" /* symbolEncodingType_e, ZSTD_strategy */ +#include "../common/fse.h" /* FSE_repeat, FSE_CTable */ +#include "../common/zstd_internal.h" /* symbolEncodingType_e, ZSTD_strategy */ typedef enum { ZSTD_defaultDisallowed = 0, @@ -44,4 +44,11 @@ size_t ZSTD_encodeSequences( FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2); +size_t ZSTD_fseBitCost( + FSE_CTable const* ctable, + unsigned const* count, + unsigned const max); + +size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, + unsigned const* count, unsigned const max); #endif /* ZSTD_COMPRESS_SEQUENCES_H */ diff --git a/native/zstd/compress/zstd_compress_superblock.c b/native/zstd/compress/zstd_compress_superblock.c new file mode 100644 index 0000000..eed58e7 --- /dev/null +++ b/native/zstd/compress/zstd_compress_superblock.c @@ -0,0 +1,579 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * 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. + */ + + /*-************************************* + * Dependencies + ***************************************/ +#include "zstd_compress_superblock.h" + +#include "../common/zstd_internal.h" /* ZSTD_getSequenceLength */ +#include "hist.h" /* HIST_countFast_wksp */ +#include "zstd_compress_internal.h" /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */ +#include "zstd_compress_sequences.h" +#include "zstd_compress_literals.h" + +/** ZSTD_compressSubBlock_literal() : + * Compresses literals section for a sub-block. + * When we have to write the Huffman table we will sometimes choose a header + * size larger than necessary. This is because we have to pick the header size + * before we know the table size + compressed size, so we have a bound on the + * table size. If we guessed incorrectly, we fall back to uncompressed literals. + * + * We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded + * in writing the header, otherwise it is set to 0. + * + * hufMetadata->hType has literals block type info. + * If it is set_basic, all sub-blocks literals section will be Raw_Literals_Block. + * If it is set_rle, all sub-blocks literals section will be RLE_Literals_Block. + * If it is set_compressed, first sub-block's literals section will be Compressed_Literals_Block + * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block + * and the following sub-blocks' literals sections will be Treeless_Literals_Block. + * @return : compressed size of literals section of a sub-block + * Or 0 if unable to compress. + * Or error code */ +static size_t +ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, + const ZSTD_hufCTablesMetadata_t* hufMetadata, + const BYTE* literals, size_t litSize, + void* dst, size_t dstSize, + const int bmi2, int writeEntropy, int* entropyWritten) +{ + size_t const header = writeEntropy ? 200 : 0; + size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header)); + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + dstSize; + BYTE* op = ostart + lhSize; + U32 const singleStream = lhSize == 3; + symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat; + size_t cLitSize = 0; + + (void)bmi2; /* TODO bmi2... */ + + DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy); + + *entropyWritten = 0; + if (litSize == 0 || hufMetadata->hType == set_basic) { + DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal"); + return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); + } else if (hufMetadata->hType == set_rle) { + DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal"); + return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize); + } + + assert(litSize > 0); + assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat); + + if (writeEntropy && hufMetadata->hType == set_compressed) { + ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); + op += hufMetadata->hufDesSize; + cLitSize += hufMetadata->hufDesSize; + DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize); + } + + /* TODO bmi2 */ + { const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable) + : HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable); + op += cSize; + cLitSize += cSize; + if (cSize == 0 || ERR_isError(cSize)) { + DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize)); + return 0; + } + /* If we expand and we aren't writing a header then emit uncompressed */ + if (!writeEntropy && cLitSize >= litSize) { + DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible"); + return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); + } + /* If we are writing headers then allow expansion that doesn't change our header size. */ + if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) { + assert(cLitSize > litSize); + DEBUGLOG(5, "Literals expanded beyond allowed header size"); + return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); + } + DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize); + } + + /* Build header */ + switch(lhSize) + { + case 3: /* 2 - 2 - 10 - 10 */ + { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); + MEM_writeLE24(ostart, lhc); + break; + } + case 4: /* 2 - 2 - 14 - 14 */ + { U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18); + MEM_writeLE32(ostart, lhc); + break; + } + case 5: /* 2 - 2 - 18 - 18 */ + { U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22); + MEM_writeLE32(ostart, lhc); + ostart[4] = (BYTE)(cLitSize >> 10); + break; + } + default: /* not possible : lhSize is {3,4,5} */ + assert(0); + } + *entropyWritten = 1; + DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart)); + return op-ostart; +} + +static size_t +ZSTD_seqDecompressedSize(seqStore_t const* seqStore, + const seqDef* sequences, size_t nbSeq, + size_t litSize, int lastSequence) +{ + const seqDef* const sstart = sequences; + const seqDef* const send = sequences + nbSeq; + const seqDef* sp = sstart; + size_t matchLengthSum = 0; + size_t litLengthSum = 0; + (void)(litLengthSum); /* suppress unused variable warning on some environments */ + while (send-sp > 0) { + ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp); + litLengthSum += seqLen.litLength; + matchLengthSum += seqLen.matchLength; + sp++; + } + assert(litLengthSum <= litSize); + if (!lastSequence) { + assert(litLengthSum == litSize); + } + return matchLengthSum + litSize; +} + +/** ZSTD_compressSubBlock_sequences() : + * Compresses sequences section for a sub-block. + * fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have + * symbol compression modes for the super-block. + * The first successfully compressed block will have these in its header. + * We set entropyWritten=1 when we succeed in compressing the sequences. + * The following sub-blocks will always have repeat mode. + * @return : compressed size of sequences section of a sub-block + * Or 0 if it is unable to compress + * Or error code. */ +static size_t +ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, + const ZSTD_fseCTablesMetadata_t* fseMetadata, + const seqDef* sequences, size_t nbSeq, + const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + const int bmi2, int writeEntropy, int* entropyWritten) +{ + const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + dstCapacity; + BYTE* op = ostart; + BYTE* seqHead; + + DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets); + + *entropyWritten = 0; + /* Sequences Header */ + RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, + dstSize_tooSmall, ""); + if (nbSeq < 0x7F) + *op++ = (BYTE)nbSeq; + else if (nbSeq < LONGNBSEQ) + op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; + else + op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; + if (nbSeq==0) { + return op - ostart; + } + + /* seqHead : flags for FSE encoding type */ + seqHead = op++; + + DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart)); + + if (writeEntropy) { + const U32 LLtype = fseMetadata->llType; + const U32 Offtype = fseMetadata->ofType; + const U32 MLtype = fseMetadata->mlType; + DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize); + *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); + ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); + op += fseMetadata->fseTablesSize; + } else { + const U32 repeat = set_repeat; + *seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2)); + } + + { size_t const bitstreamSize = ZSTD_encodeSequences( + op, oend - op, + fseTables->matchlengthCTable, mlCode, + fseTables->offcodeCTable, ofCode, + fseTables->litlengthCTable, llCode, + sequences, nbSeq, + longOffsets, bmi2); + FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); + op += bitstreamSize; + /* zstd versions <= 1.3.4 mistakenly report corruption when + * FSE_readNCount() receives a buffer < 4 bytes. + * Fixed by https://github.com/facebook/zstd/pull/1146. + * This can happen when the last set_compressed table present is 2 + * bytes and the bitstream is only one byte. + * In this exceedingly rare case, we will simply emit an uncompressed + * block, since it isn't worth optimizing. + */ +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) { + /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ + assert(fseMetadata->lastCountSize + bitstreamSize == 3); + DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " + "emitting an uncompressed block."); + return 0; + } +#endif + DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize); + } + + /* zstd versions <= 1.4.0 mistakenly report error when + * sequences section body size is less than 3 bytes. + * Fixed by https://github.com/facebook/zstd/pull/1664. + * This can happen when the previous sequences section block is compressed + * with rle mode and the current block's sequences section is compressed + * with repeat mode where sequences section body size can be 1 byte. + */ +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (op-seqHead < 4) { + DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting " + "an uncompressed block when sequences are < 4 bytes"); + return 0; + } +#endif + + *entropyWritten = 1; + return op - ostart; +} + +/** ZSTD_compressSubBlock() : + * Compresses a single sub-block. + * @return : compressed size of the sub-block + * Or 0 if it failed to compress. */ +static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, + const ZSTD_entropyCTablesMetadata_t* entropyMetadata, + const seqDef* sequences, size_t nbSeq, + const BYTE* literals, size_t litSize, + const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + const int bmi2, + int writeLitEntropy, int writeSeqEntropy, + int* litEntropyWritten, int* seqEntropyWritten, + U32 lastBlock) +{ + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + dstCapacity; + BYTE* op = ostart + ZSTD_blockHeaderSize; + DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)", + litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock); + { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable, + &entropyMetadata->hufMetadata, literals, litSize, + op, oend-op, bmi2, writeLitEntropy, litEntropyWritten); + FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed"); + if (cLitSize == 0) return 0; + op += cLitSize; + } + { size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse, + &entropyMetadata->fseMetadata, + sequences, nbSeq, + llCode, mlCode, ofCode, + cctxParams, + op, oend-op, + bmi2, writeSeqEntropy, seqEntropyWritten); + FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed"); + if (cSeqSize == 0) return 0; + op += cSeqSize; + } + /* Write block header */ + { size_t cSize = (op-ostart)-ZSTD_blockHeaderSize; + U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); + MEM_writeLE24(ostart, cBlockHeader24); + } + return op-ostart; +} + +static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize, + const ZSTD_hufCTables_t* huf, + const ZSTD_hufCTablesMetadata_t* hufMetadata, + void* workspace, size_t wkspSize, + int writeEntropy) +{ + unsigned* const countWksp = (unsigned*)workspace; + unsigned maxSymbolValue = 255; + size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ + + if (hufMetadata->hType == set_basic) return litSize; + else if (hufMetadata->hType == set_rle) return 1; + else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { + size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); + if (ZSTD_isError(largest)) return litSize; + { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); + if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; + return cLitSizeEstimate + literalSectionHeaderSize; + } } + assert(0); /* impossible */ + return 0; +} + +static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, + const BYTE* codeTable, unsigned maxCode, + size_t nbSeq, const FSE_CTable* fseCTable, + const U8* additionalBits, + short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, + void* workspace, size_t wkspSize) +{ + unsigned* const countWksp = (unsigned*)workspace; + const BYTE* ctp = codeTable; + const BYTE* const ctStart = ctp; + const BYTE* const ctEnd = ctStart + nbSeq; + size_t cSymbolTypeSizeEstimateInBits = 0; + unsigned max = maxCode; + + HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ + if (type == set_basic) { + /* We selected this encoding type, so it must be valid. */ + assert(max <= defaultMax); + cSymbolTypeSizeEstimateInBits = max <= defaultMax + ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max) + : ERROR(GENERIC); + } else if (type == set_rle) { + cSymbolTypeSizeEstimateInBits = 0; + } else if (type == set_compressed || type == set_repeat) { + cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); + } + if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10; + while (ctp < ctEnd) { + if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; + else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ + ctp++; + } + return cSymbolTypeSizeEstimateInBits / 8; +} + +static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable, + const BYTE* llCodeTable, + const BYTE* mlCodeTable, + size_t nbSeq, + const ZSTD_fseCTables_t* fseTables, + const ZSTD_fseCTablesMetadata_t* fseMetadata, + void* workspace, size_t wkspSize, + int writeEntropy) +{ + size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ + size_t cSeqSizeEstimate = 0; + if (nbSeq == 0) return sequencesSectionHeaderSize; + cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff, + nbSeq, fseTables->offcodeCTable, NULL, + OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, + workspace, wkspSize); + cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL, + nbSeq, fseTables->litlengthCTable, LL_bits, + LL_defaultNorm, LL_defaultNormLog, MaxLL, + workspace, wkspSize); + cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML, + nbSeq, fseTables->matchlengthCTable, ML_bits, + ML_defaultNorm, ML_defaultNormLog, MaxML, + workspace, wkspSize); + if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; + return cSeqSizeEstimate + sequencesSectionHeaderSize; +} + +static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, + const BYTE* ofCodeTable, + const BYTE* llCodeTable, + const BYTE* mlCodeTable, + size_t nbSeq, + const ZSTD_entropyCTables_t* entropy, + const ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize, + int writeLitEntropy, int writeSeqEntropy) { + size_t cSizeEstimate = 0; + cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize, + &entropy->huf, &entropyMetadata->hufMetadata, + workspace, wkspSize, writeLitEntropy); + cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, + nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, + workspace, wkspSize, writeSeqEntropy); + return cSizeEstimate + ZSTD_blockHeaderSize; +} + +static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata) +{ + if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle) + return 1; + if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle) + return 1; + if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle) + return 1; + return 0; +} + +/** ZSTD_compressSubBlock_multi() : + * Breaks super-block into multiple sub-blocks and compresses them. + * Entropy will be written to the first block. + * The following blocks will use repeat mode to compress. + * All sub-blocks are compressed blocks (no raw or rle blocks). + * @return : compressed size of the super block (which is multiple ZSTD blocks) + * Or 0 if it failed to compress. */ +static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, + const ZSTD_compressedBlockState_t* prevCBlock, + ZSTD_compressedBlockState_t* nextCBlock, + const ZSTD_entropyCTablesMetadata_t* entropyMetadata, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const int bmi2, U32 lastBlock, + void* workspace, size_t wkspSize) +{ + const seqDef* const sstart = seqStorePtr->sequencesStart; + const seqDef* const send = seqStorePtr->sequences; + const seqDef* sp = sstart; + const BYTE* const lstart = seqStorePtr->litStart; + const BYTE* const lend = seqStorePtr->lit; + const BYTE* lp = lstart; + BYTE const* ip = (BYTE const*)src; + BYTE const* const iend = ip + srcSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + dstCapacity; + BYTE* op = ostart; + const BYTE* llCodePtr = seqStorePtr->llCode; + const BYTE* mlCodePtr = seqStorePtr->mlCode; + const BYTE* ofCodePtr = seqStorePtr->ofCode; + size_t targetCBlockSize = cctxParams->targetCBlockSize; + size_t litSize, seqCount; + int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed; + int writeSeqEntropy = 1; + int lastSequence = 0; + + DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)", + (unsigned)(lend-lp), (unsigned)(send-sstart)); + + litSize = 0; + seqCount = 0; + do { + size_t cBlockSizeEstimate = 0; + if (sstart == send) { + lastSequence = 1; + } else { + const seqDef* const sequence = sp + seqCount; + lastSequence = sequence == send - 1; + litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength; + seqCount++; + } + if (lastSequence) { + assert(lp <= lend); + assert(litSize <= (size_t)(lend - lp)); + litSize = (size_t)(lend - lp); + } + /* I think there is an optimization opportunity here. + * Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful + * since it recalculates estimate from scratch. + * For example, it would recount literal distribution and symbol codes every time. + */ + cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount, + &nextCBlock->entropy, entropyMetadata, + workspace, wkspSize, writeLitEntropy, writeSeqEntropy); + if (cBlockSizeEstimate > targetCBlockSize || lastSequence) { + int litEntropyWritten = 0; + int seqEntropyWritten = 0; + const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence); + const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, + sp, seqCount, + lp, litSize, + llCodePtr, mlCodePtr, ofCodePtr, + cctxParams, + op, oend-op, + bmi2, writeLitEntropy, writeSeqEntropy, + &litEntropyWritten, &seqEntropyWritten, + lastBlock && lastSequence); + FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); + if (cSize > 0 && cSize < decompressedSize) { + DEBUGLOG(5, "Committed the sub-block"); + assert(ip + decompressedSize <= iend); + ip += decompressedSize; + sp += seqCount; + lp += litSize; + op += cSize; + llCodePtr += seqCount; + mlCodePtr += seqCount; + ofCodePtr += seqCount; + litSize = 0; + seqCount = 0; + /* Entropy only needs to be written once */ + if (litEntropyWritten) { + writeLitEntropy = 0; + } + if (seqEntropyWritten) { + writeSeqEntropy = 0; + } + } + } + } while (!lastSequence); + if (writeLitEntropy) { + DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten"); + ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); + } + if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) { + /* If we haven't written our entropy tables, then we've violated our contract and + * must emit an uncompressed block. + */ + DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten"); + return 0; + } + if (ip < iend) { + size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock); + DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip)); + FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); + assert(cSize != 0); + op += cSize; + /* We have to regenerate the repcodes because we've skipped some sequences */ + if (sp < send) { + seqDef const* seq; + repcodes_t rep; + ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep)); + for (seq = sstart; seq < sp; ++seq) { + ZSTD_updateRep(rep.rep, seq->offBase, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); + } + ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep)); + } + } + DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed"); + return op-ostart; +} + +size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + void const* src, size_t srcSize, + unsigned lastBlock) { + ZSTD_entropyCTablesMetadata_t entropyMetadata; + + FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore, + &zc->blockState.prevCBlock->entropy, + &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + &entropyMetadata, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); + + return ZSTD_compressSubBlock_multi(&zc->seqStore, + zc->blockState.prevCBlock, + zc->blockState.nextCBlock, + &entropyMetadata, + &zc->appliedParams, + dst, dstCapacity, + src, srcSize, + zc->bmi2, lastBlock, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */); +} diff --git a/native/zstd/compress/zstd_compress_superblock.h b/native/zstd/compress/zstd_compress_superblock.h new file mode 100644 index 0000000..176f9b1 --- /dev/null +++ b/native/zstd/compress/zstd_compress_superblock.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * 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. + */ + +#ifndef ZSTD_COMPRESS_ADVANCED_H +#define ZSTD_COMPRESS_ADVANCED_H + +/*-************************************* +* Dependencies +***************************************/ + +#include "../zstd.h" /* ZSTD_CCtx */ + +/*-************************************* +* Target Compressed Block Size +***************************************/ + +/* ZSTD_compressSuperBlock() : + * Used to compress a super block when targetCBlockSize is being used. + * The given block will be compressed into multiple sub blocks that are around targetCBlockSize. */ +size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + void const* src, size_t srcSize, + unsigned lastBlock); + +#endif /* ZSTD_COMPRESS_ADVANCED_H */ diff --git a/native/zstd/compress/zstd_cwksp.h b/native/zstd/compress/zstd_cwksp.h old mode 100755 new mode 100644 index fc9765b..47afe3d --- a/native/zstd/compress/zstd_cwksp.h +++ b/native/zstd/compress/zstd_cwksp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,7 +14,7 @@ /*-************************************* * Dependencies ***************************************/ -#include "zstd_internal.h" +#include "../common/zstd_internal.h" #if defined (__cplusplus) extern "C" { @@ -24,16 +24,6 @@ extern "C" { * Constants ***************************************/ -/* define "workspace is too large" as this number of times larger than needed */ -#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 - -/* when workspace is continuously too large - * during at least this number of times, - * context's memory usage is considered wasteful, - * because it's sized to handle a worst case scenario which rarely happens. - * In which case, resize it down to free some memory */ -#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 - /* Since the workspace is effectively its own little malloc implementation / * arena, when we run under ASAN, we should similarly insert redzones between * each internal element of the workspace, so ASAN will catch overruns that @@ -45,6 +35,10 @@ extern "C" { #define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128 #endif + +/* Set our tables and aligneds to align by 64 bytes */ +#define ZSTD_CWKSP_ALIGNMENT_BYTES 64 + /*-************************************* * Structures ***************************************/ @@ -54,6 +48,16 @@ typedef enum { ZSTD_cwksp_alloc_aligned } ZSTD_cwksp_alloc_phase_e; +/** + * Used to describe whether the workspace is statically allocated (and will not + * necessarily ever be freed), or if it's dynamically allocated and we can + * expect a well-formed caller to free this. + */ +typedef enum { + ZSTD_cwksp_dynamic_alloc, + ZSTD_cwksp_static_alloc +} ZSTD_cwksp_static_alloc_e; + /** * Zstd fits all its internal datastructures into a single continuous buffer, * so that it only needs to perform a single OS allocation (or so that a buffer @@ -102,7 +106,7 @@ typedef enum { * * - Static objects: this is optionally the enclosing ZSTD_CCtx or ZSTD_CDict, * so that literally everything fits in a single buffer. Note: if present, - * this must be the first object in the workspace, since ZSTD_free{CCtx, + * this must be the first object in the workspace, since ZSTD_customFree{CCtx, * CDict}() rely on a pointer comparison to see whether one or two frees are * required. * @@ -117,10 +121,11 @@ typedef enum { * - Tables: these are any of several different datastructures (hash tables, * chain tables, binary trees) that all respect a common format: they are * uint32_t arrays, all of whose values are between 0 and (nextSrc - base). - * Their sizes depend on the cparams. + * Their sizes depend on the cparams. These tables are 64-byte aligned. * * - Aligned: these buffers are used for various purposes that require 4 byte - * alignment, but don't require any initialization before they're used. + * alignment, but don't require any initialization before they're used. These + * buffers are each aligned to 64 bytes. * * - Buffers: these buffers are used for various purposes that don't require * any alignment or initialization before they're used. This means they can @@ -133,8 +138,7 @@ typedef enum { * * 1. Objects * 2. Buffers - * 3. Aligned - * 4. Tables + * 3. Aligned/Tables * * Attempts to reserve objects of different types out of order will fail. */ @@ -147,9 +151,10 @@ typedef struct { void* tableValidEnd; void* allocStart; - int allocFailed; + BYTE allocFailed; int workspaceOversizedDuration; ZSTD_cwksp_alloc_phase_e phase; + ZSTD_cwksp_static_alloc_e isStatic; } ZSTD_cwksp; /*-************************************* @@ -186,82 +191,166 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) { * Since tables aren't currently redzoned, you don't need to call through this * to figure out how much space you need for the matchState tables. Everything * else is though. + * + * Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size(). */ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) { -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + if (size == 0) + return 0; +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; #else return size; #endif } -MEM_STATIC void ZSTD_cwksp_internal_advance_phase( - ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) { +/** + * Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes. + * Used to determine the number of bytes required for a given "aligned". + */ +MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) { + return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES)); +} + +/** + * Returns the amount of additional space the cwksp must allocate + * for internal purposes (currently only alignment). + */ +MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) { + /* For alignment, the wksp will always allocate an additional n_1=[1, 64] bytes + * to align the beginning of tables section, as well as another n_2=[0, 63] bytes + * to align the beginning of the aligned section. + * + * n_1 + n_2 == 64 bytes if the cwksp is freshly allocated, due to tables and + * aligneds being sized in multiples of 64 bytes. + */ + size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES; + return slackSpace; +} + + +/** + * Return the number of additional bytes required to align a pointer to the given number of bytes. + * alignBytes must be a power of two. + */ +MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) { + size_t const alignBytesMask = alignBytes - 1; + size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask; + assert((alignBytes & alignBytesMask) == 0); + assert(bytes != ZSTD_CWKSP_ALIGNMENT_BYTES); + return bytes; +} + +/** + * Internal function. Do not use directly. + * Reserves the given number of bytes within the aligned/buffer segment of the wksp, + * which counts from the end of the wksp (as opposed to the object/table segment). + * + * Returns a pointer to the beginning of that space. + */ +MEM_STATIC void* +ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) +{ + void* const alloc = (BYTE*)ws->allocStart - bytes; + void* const bottom = ws->tableEnd; + DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining", + alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); + ZSTD_cwksp_assert_internal_consistency(ws); + assert(alloc >= bottom); + if (alloc < bottom) { + DEBUGLOG(4, "cwksp: alloc failed!"); + ws->allocFailed = 1; + return NULL; + } + /* the area is reserved from the end of wksp. + * If it overlaps with tableValidEnd, it voids guarantees on values' range */ + if (alloc < ws->tableValidEnd) { + ws->tableValidEnd = alloc; + } + ws->allocStart = alloc; + return alloc; +} + +/** + * Moves the cwksp to the next phase, and does any necessary allocations. + * cwksp initialization must necessarily go through each phase in order. + * Returns a 0 on success, or zstd error + */ +MEM_STATIC size_t +ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) +{ assert(phase >= ws->phase); if (phase > ws->phase) { + /* Going from allocating objects to allocating buffers */ if (ws->phase < ZSTD_cwksp_alloc_buffers && phase >= ZSTD_cwksp_alloc_buffers) { ws->tableValidEnd = ws->objectEnd; } + + /* Going from allocating buffers to allocating aligneds/tables */ if (ws->phase < ZSTD_cwksp_alloc_aligned && phase >= ZSTD_cwksp_alloc_aligned) { - /* If unaligned allocations down from a too-large top have left us - * unaligned, we need to realign our alloc ptr. Technically, this - * can consume space that is unaccounted for in the neededSpace - * calculation. However, I believe this can only happen when the - * workspace is too large, and specifically when it is too large - * by a larger margin than the space that will be consumed. */ - /* TODO: cleaner, compiler warning friendly way to do this??? */ - ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1)); - if (ws->allocStart < ws->tableValidEnd) { - ws->tableValidEnd = ws->allocStart; + { /* Align the start of the "aligned" to 64 bytes. Use [1, 64] bytes. */ + size_t const bytesToAlign = + ZSTD_CWKSP_ALIGNMENT_BYTES - ZSTD_cwksp_bytes_to_align_ptr(ws->allocStart, ZSTD_CWKSP_ALIGNMENT_BYTES); + DEBUGLOG(5, "reserving aligned alignment addtl space: %zu", bytesToAlign); + ZSTD_STATIC_ASSERT((ZSTD_CWKSP_ALIGNMENT_BYTES & (ZSTD_CWKSP_ALIGNMENT_BYTES - 1)) == 0); /* power of 2 */ + RETURN_ERROR_IF(!ZSTD_cwksp_reserve_internal_buffer_space(ws, bytesToAlign), + memory_allocation, "aligned phase - alignment initial allocation failed!"); } - } + { /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */ + void* const alloc = ws->objectEnd; + size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES); + void* const objectEnd = (BYTE*)alloc + bytesToAlign; + DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign); + RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation, + "table phase - alignment initial allocation failed!"); + ws->objectEnd = objectEnd; + ws->tableEnd = objectEnd; /* table area starts being empty */ + if (ws->tableValidEnd < ws->tableEnd) { + ws->tableValidEnd = ws->tableEnd; + } } } ws->phase = phase; + ZSTD_cwksp_assert_internal_consistency(ws); } + return 0; } /** * Returns whether this object/buffer/etc was allocated in this workspace. */ -MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) { +MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) +{ return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd); } /** * Internal function. Do not use directly. */ -MEM_STATIC void* ZSTD_cwksp_reserve_internal( - ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) { +MEM_STATIC void* +ZSTD_cwksp_reserve_internal(ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) +{ void* alloc; - void* bottom = ws->tableEnd; - ZSTD_cwksp_internal_advance_phase(ws, phase); - alloc = (BYTE *)ws->allocStart - bytes; + if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) { + return NULL; + } -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) /* over-reserve space */ - alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; + bytes += 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; #endif - DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining", - alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); - ZSTD_cwksp_assert_internal_consistency(ws); - assert(alloc >= bottom); - if (alloc < bottom) { - DEBUGLOG(4, "cwksp: alloc failed!"); - ws->allocFailed = 1; - return NULL; - } - if (alloc < ws->tableValidEnd) { - ws->tableValidEnd = alloc; - } - ws->allocStart = alloc; + alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes); -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on * either size. */ - alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; - __asan_unpoison_memory_region(alloc, bytes); + if (alloc) { + alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; + if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { + __asan_unpoison_memory_region(alloc, bytes); + } + } #endif return alloc; @@ -270,33 +359,44 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal( /** * Reserves and returns unaligned memory. */ -MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) { +MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) +{ return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers); } /** - * Reserves and returns memory sized on and aligned on sizeof(unsigned). + * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes). */ -MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) { - assert((bytes & (sizeof(U32)-1)) == 0); - return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned); +MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) +{ + void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES), + ZSTD_cwksp_alloc_aligned); + assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); + return ptr; } /** - * Aligned on sizeof(unsigned). These buffers have the special property that + * Aligned on 64 bytes. These buffers have the special property that * their values remain constrained, allowing us to re-use them without * memset()-ing them. */ -MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) { +MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) +{ const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned; - void* alloc = ws->tableEnd; - void* end = (BYTE *)alloc + bytes; - void* top = ws->allocStart; + void* alloc; + void* end; + void* top; + + if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) { + return NULL; + } + alloc = ws->tableEnd; + end = (BYTE *)alloc + bytes; + top = ws->allocStart; DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining", alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); assert((bytes & (sizeof(U32)-1)) == 0); - ZSTD_cwksp_internal_advance_phase(ws, phase); ZSTD_cwksp_assert_internal_consistency(ws); assert(end <= top); if (end > top) { @@ -306,35 +406,41 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) { } ws->tableEnd = end; -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - __asan_unpoison_memory_region(alloc, bytes); +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { + __asan_unpoison_memory_region(alloc, bytes); + } #endif + assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0); + assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); return alloc; } /** * Aligned on sizeof(void*). + * Note : should happen only once, at workspace first initialization */ -MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) { - size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); +MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) +{ + size_t const roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); void* alloc = ws->objectEnd; void* end = (BYTE*)alloc + roundedBytes; -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) /* over-reserve space */ end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; #endif - DEBUGLOG(5, + DEBUGLOG(4, "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining", alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes); - assert(((size_t)alloc & (sizeof(void*)-1)) == 0); - assert((bytes & (sizeof(void*)-1)) == 0); + assert((size_t)alloc % ZSTD_ALIGNOF(void*) == 0); + assert(bytes % ZSTD_ALIGNOF(void*) == 0); ZSTD_cwksp_assert_internal_consistency(ws); /* we must be in the first phase, no advance is possible */ if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) { - DEBUGLOG(4, "cwksp: object alloc failed!"); + DEBUGLOG(3, "cwksp: object alloc failed!"); ws->allocFailed = 1; return NULL; } @@ -342,20 +448,23 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) { ws->tableEnd = end; ws->tableValidEnd = end; -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on * either size. */ - alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; - __asan_unpoison_memory_region(alloc, bytes); + alloc = (BYTE*)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; + if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { + __asan_unpoison_memory_region(alloc, bytes); + } #endif return alloc; } -MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) { +MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) +{ DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty"); -#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) +#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) /* To validate that the table re-use logic is sound, and that we don't * access table space that we haven't cleaned, we re-"poison" the table * space every time we mark it dirty. */ @@ -390,7 +499,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { assert(ws->tableValidEnd >= ws->objectEnd); assert(ws->tableValidEnd <= ws->allocStart); if (ws->tableValidEnd < ws->tableEnd) { - memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd); + ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd)); } ZSTD_cwksp_mark_tables_clean(ws); } @@ -402,8 +511,12 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing tables!"); -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - { +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + /* We don't do this when the workspace is statically allocated, because + * when that is the case, we have no capability to hook into the end of the + * workspace's lifecycle to unpoison the memory. + */ + if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd; __asan_poison_memory_region(ws->objectEnd, size); } @@ -420,7 +533,7 @@ MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing!"); -#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) +#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) /* To validate that the context re-use logic is sound, and that we don't * access stuff that this compression hasn't initialized, we re-"poison" * the workspace (or at least the non-static, non-table parts of it) @@ -431,8 +544,12 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) { } #endif -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - { +#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + /* We don't do this when the workspace is statically allocated, because + * when that is the case, we have no capability to hook into the end of the + * workspace's lifecycle to unpoison the memory. + */ + if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) { size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd; __asan_poison_memory_region(ws->objectEnd, size); } @@ -452,7 +569,7 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) { * Any existing values in the workspace are ignored (the previously managed * buffer, if present, must be separately freed). */ -MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) { +MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_cwksp_static_alloc_e isStatic) { DEBUGLOG(4, "cwksp: init'ing workspace with %zd bytes", size); assert(((size_t)start & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ ws->workspace = start; @@ -460,39 +577,45 @@ MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) { ws->objectEnd = ws->workspace; ws->tableValidEnd = ws->objectEnd; ws->phase = ZSTD_cwksp_alloc_objects; + ws->isStatic = isStatic; ZSTD_cwksp_clear(ws); ws->workspaceOversizedDuration = 0; ZSTD_cwksp_assert_internal_consistency(ws); } MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem customMem) { - void* workspace = ZSTD_malloc(size, customMem); + void* workspace = ZSTD_customMalloc(size, customMem); DEBUGLOG(4, "cwksp: creating new workspace with %zd bytes", size); - RETURN_ERROR_IF(workspace == NULL, memory_allocation); - ZSTD_cwksp_init(ws, workspace, size); + RETURN_ERROR_IF(workspace == NULL, memory_allocation, "NULL pointer!"); + ZSTD_cwksp_init(ws, workspace, size, ZSTD_cwksp_dynamic_alloc); return 0; } MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) { void *ptr = ws->workspace; DEBUGLOG(4, "cwksp: freeing workspace"); - memset(ws, 0, sizeof(ZSTD_cwksp)); - ZSTD_free(ptr, customMem); + ZSTD_memset(ws, 0, sizeof(ZSTD_cwksp)); + ZSTD_customFree(ptr, customMem); } /** * Moves the management of a workspace from one cwksp to another. The src cwksp - * is left in an invalid state (src must be re-init()'ed before its used again). + * is left in an invalid state (src must be re-init()'ed before it's used again). */ MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) { *dst = *src; - memset(src, 0, sizeof(ZSTD_cwksp)); + ZSTD_memset(src, 0, sizeof(ZSTD_cwksp)); } MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) { return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace); } +MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) { + return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace) + + (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart); +} + MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { return ws->allocFailed; } @@ -501,6 +624,24 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { * Functions Checking Free Space ***************************************/ +/* ZSTD_alignmentSpaceWithinBounds() : + * Returns if the estimated space needed for a wksp is within an acceptable limit of the + * actual amount of space used. + */ +MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp* const ws, + size_t const estimatedSpace, int resizedWorkspace) { + if (resizedWorkspace) { + /* Resized/newly allocated wksp should have exact bounds */ + return ZSTD_cwksp_used(ws) == estimatedSpace; + } else { + /* Due to alignment, when reusing a workspace, we can actually consume 63 fewer or more bytes + * than estimatedSpace. See the comments in zstd_cwksp.h for details. + */ + return (ZSTD_cwksp_used(ws) >= estimatedSpace - 63) && (ZSTD_cwksp_used(ws) <= estimatedSpace + 63); + } +} + + MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) { return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd); } diff --git a/native/zstd/compress/zstd_double_fast.c b/native/zstd/compress/zstd_double_fast.c old mode 100755 new mode 100644 index a661a48..c2dbd54 --- a/native/zstd/compress/zstd_double_fast.c +++ b/native/zstd/compress/zstd_double_fast.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,8 +11,43 @@ #include "zstd_compress_internal.h" #include "zstd_double_fast.h" +static void ZSTD_fillDoubleHashTableForCDict(ZSTD_matchState_t* ms, + void const* end, ZSTD_dictTableLoadMethod_e dtlm) +{ + const ZSTD_compressionParameters* const cParams = &ms->cParams; + U32* const hashLarge = ms->hashTable; + U32 const hBitsL = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + U32 const mls = cParams->minMatch; + U32* const hashSmall = ms->chainTable; + U32 const hBitsS = cParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; + const BYTE* const base = ms->window.base; + const BYTE* ip = base + ms->nextToUpdate; + const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; + const U32 fastHashFillStep = 3; -void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, + /* Always insert every fastHashFillStep position into the hash tables. + * Insert the other positions into the large hash table if their entry + * is empty. + */ + for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { + U32 const curr = (U32)(ip - base); + U32 i; + for (i = 0; i < fastHashFillStep; ++i) { + size_t const smHashAndTag = ZSTD_hashPtr(ip + i, hBitsS, mls); + size_t const lgHashAndTag = ZSTD_hashPtr(ip + i, hBitsL, 8); + if (i == 0) { + ZSTD_writeTaggedIndex(hashSmall, smHashAndTag, curr + i); + } + if (i == 0 || hashLarge[lgHashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { + ZSTD_writeTaggedIndex(hashLarge, lgHashAndTag, curr + i); + } + /* Only load extra positions for ZSTD_dtlm_full */ + if (dtlm == ZSTD_dtlm_fast) + break; + } } +} + +static void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms, void const* end, ZSTD_dictTableLoadMethod_e dtlm) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -31,27 +66,249 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, * is empty. */ for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { - U32 const current = (U32)(ip - base); + U32 const curr = (U32)(ip - base); U32 i; for (i = 0; i < fastHashFillStep; ++i) { size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls); size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8); if (i == 0) - hashSmall[smHash] = current + i; + hashSmall[smHash] = curr + i; if (i == 0 || hashLarge[lgHash] == 0) - hashLarge[lgHash] = current + i; + hashLarge[lgHash] = curr + i; /* Only load extra positions for ZSTD_dtlm_full */ if (dtlm == ZSTD_dtlm_fast) break; - } } + } } +} + +void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, + const void* const end, + ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp) +{ + if (tfp == ZSTD_tfp_forCDict) { + ZSTD_fillDoubleHashTableForCDict(ms, end, dtlm); + } else { + ZSTD_fillDoubleHashTableForCCtx(ms, end, dtlm); + } } FORCE_INLINE_TEMPLATE -size_t ZSTD_compressBlock_doubleFast_generic( +size_t ZSTD_compressBlock_doubleFast_noDict_generic( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize, U32 const mls /* template */) +{ + ZSTD_compressionParameters const* cParams = &ms->cParams; + U32* const hashLong = ms->hashTable; + const U32 hBitsL = cParams->hashLog; + U32* const hashSmall = ms->chainTable; + const U32 hBitsS = cParams->chainLog; + const BYTE* const base = ms->window.base; + const BYTE* const istart = (const BYTE*)src; + const BYTE* anchor = istart; + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + /* presumes that, if there is a dictionary, it must be using Attach mode */ + const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); + const BYTE* const prefixLowest = base + prefixLowestIndex; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - HASH_READ_SIZE; + U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + + size_t mLength; + U32 offset; + U32 curr; + + /* how many positions to search before increasing step size */ + const size_t kStepIncr = 1 << kSearchStrength; + /* the position at which to increment the step size if no match is found */ + const BYTE* nextStep; + size_t step; /* the current step size */ + + size_t hl0; /* the long hash at ip */ + size_t hl1; /* the long hash at ip1 */ + + U32 idxl0; /* the long match index for ip */ + U32 idxl1; /* the long match index for ip1 */ + + const BYTE* matchl0; /* the long match for ip */ + const BYTE* matchs0; /* the short match for ip */ + const BYTE* matchl1; /* the long match for ip1 */ + + const BYTE* ip = istart; /* the current position */ + const BYTE* ip1; /* the next position */ + + DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_noDict_generic"); + + /* init */ + ip += ((ip - prefixLowest) == 0); + { + U32 const current = (U32)(ip - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); + U32 const maxRep = current - windowLow; + if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; + } + + /* Outer Loop: one iteration per match found and stored */ + while (1) { + step = 1; + nextStep = ip + kStepIncr; + ip1 = ip + step; + + if (ip1 > ilimit) { + goto _cleanup; + } + + hl0 = ZSTD_hashPtr(ip, hBitsL, 8); + idxl0 = hashLong[hl0]; + matchl0 = base + idxl0; + + /* Inner Loop: one iteration per search / position */ + do { + const size_t hs0 = ZSTD_hashPtr(ip, hBitsS, mls); + const U32 idxs0 = hashSmall[hs0]; + curr = (U32)(ip-base); + matchs0 = base + idxs0; + + hashLong[hl0] = hashSmall[hs0] = curr; /* update hash tables */ + + /* check noDict repcode */ + if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { + mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + goto _match_stored; + } + + hl1 = ZSTD_hashPtr(ip1, hBitsL, 8); + + if (idxl0 > prefixLowestIndex) { + /* check prefix long match */ + if (MEM_read64(matchl0) == MEM_read64(ip)) { + mLength = ZSTD_count(ip+8, matchl0+8, iend) + 8; + offset = (U32)(ip-matchl0); + while (((ip>anchor) & (matchl0>prefixLowest)) && (ip[-1] == matchl0[-1])) { ip--; matchl0--; mLength++; } /* catch up */ + goto _match_found; + } + } + + idxl1 = hashLong[hl1]; + matchl1 = base + idxl1; + + if (idxs0 > prefixLowestIndex) { + /* check prefix short match */ + if (MEM_read32(matchs0) == MEM_read32(ip)) { + goto _search_next_long; + } + } + + if (ip1 >= nextStep) { + PREFETCH_L1(ip1 + 64); + PREFETCH_L1(ip1 + 128); + step++; + nextStep += kStepIncr; + } + ip = ip1; + ip1 += step; + + hl0 = hl1; + idxl0 = idxl1; + matchl0 = matchl1; + #if defined(__aarch64__) + PREFETCH_L1(ip+256); + #endif + } while (ip1 <= ilimit); + +_cleanup: + /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), + * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ + offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; + + /* save reps for next block */ + rep[0] = offset_1 ? offset_1 : offsetSaved1; + rep[1] = offset_2 ? offset_2 : offsetSaved2; + + /* Return the last literals size */ + return (size_t)(iend - anchor); + +_search_next_long: + + /* check prefix long +1 match */ + if (idxl1 > prefixLowestIndex) { + if (MEM_read64(matchl1) == MEM_read64(ip1)) { + ip = ip1; + mLength = ZSTD_count(ip+8, matchl1+8, iend) + 8; + offset = (U32)(ip-matchl1); + while (((ip>anchor) & (matchl1>prefixLowest)) && (ip[-1] == matchl1[-1])) { ip--; matchl1--; mLength++; } /* catch up */ + goto _match_found; + } + } + + /* if no long +1 match, explore the short match we found */ + mLength = ZSTD_count(ip+4, matchs0+4, iend) + 4; + offset = (U32)(ip - matchs0); + while (((ip>anchor) & (matchs0>prefixLowest)) && (ip[-1] == matchs0[-1])) { ip--; matchs0--; mLength++; } /* catch up */ + + /* fall-through */ + +_match_found: /* requires ip, offset, mLength */ + offset_2 = offset_1; + offset_1 = offset; + + if (step < 4) { + /* It is unsafe to write this value back to the hashtable when ip1 is + * greater than or equal to the new ip we will have after we're done + * processing this match. Rather than perform that test directly + * (ip1 >= ip + mLength), which costs speed in practice, we do a simpler + * more predictable test. The minmatch even if we take a short match is + * 4 bytes, so as long as step, the distance between ip and ip1 + * (initially) is less than 4, we know ip1 < new ip. */ + hashLong[hl1] = (U32)(ip1 - base); + } + + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + +_match_stored: + /* match found */ + ip += mLength; + anchor = ip; + + if (ip <= ilimit) { + /* Complementary insertion */ + /* done after iLimit test, as candidates could be > iend-8 */ + { U32 const indexToInsert = curr+2; + hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; + hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); + hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; + hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base); + } + + /* check immediate repcode */ + while ( (ip <= ilimit) + && ( (offset_2>0) + & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { + /* store sequence */ + size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; + U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, rLength); + ip += rLength; + anchor = ip; + continue; /* faster when present ... (?) */ + } + } + } +} + + +FORCE_INLINE_TEMPLATE +size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls /* template */, ZSTD_dictMode_e const dictMode) + U32 const mls /* template */) { ZSTD_compressionParameters const* cParams = &ms->cParams; U32* const hashLong = ms->hashTable; @@ -63,63 +320,45 @@ size_t ZSTD_compressBlock_doubleFast_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - const U32 lowestValid = ms->window.dictLimit; - const U32 maxDistance = 1U << cParams->windowLog; /* presumes that, if there is a dictionary, it must be using Attach mode */ - const U32 prefixLowestIndex = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid; + const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); const BYTE* const prefixLowest = base + prefixLowestIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const ZSTD_compressionParameters* const dictCParams = - dictMode == ZSTD_dictMatchState ? - &dms->cParams : NULL; - const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ? - dms->hashTable : NULL; - const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ? - dms->chainTable : NULL; - const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ? - dms->window.dictLimit : 0; - const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? - dms->window.base : NULL; - const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ? - dictBase + dictStartIndex : NULL; - const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? - dms->window.nextSrc : NULL; - const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? - prefixLowestIndex - (U32)(dictEnd - dictBase) : - 0; - const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ? - dictCParams->hashLog : hBitsL; - const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ? - dictCParams->chainLog : hBitsS; - const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart); - - DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic"); - - assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState); + const ZSTD_compressionParameters* const dictCParams = &dms->cParams; + const U32* const dictHashLong = dms->hashTable; + const U32* const dictHashSmall = dms->chainTable; + const U32 dictStartIndex = dms->window.dictLimit; + const BYTE* const dictBase = dms->window.base; + const BYTE* const dictStart = dictBase + dictStartIndex; + const BYTE* const dictEnd = dms->window.nextSrc; + const U32 dictIndexDelta = prefixLowestIndex - (U32)(dictEnd - dictBase); + const U32 dictHBitsL = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + const U32 dictHBitsS = dictCParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; + const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart)); + + DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic"); /* if a dictionary is attached, it must be within window range */ - if (dictMode == ZSTD_dictMatchState) { - assert(lowestValid + maxDistance >= endIndex); + assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex); + + if (ms->prefetchCDictTables) { + size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); + size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32); + PREFETCH_AREA(dictHashLong, hashTableBytes) + PREFETCH_AREA(dictHashSmall, chainTableBytes) } /* init */ ip += (dictAndPrefixLength == 0); - if (dictMode == ZSTD_noDict) { - U32 const maxRep = (U32)(ip - prefixLowest); - if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; - } - if (dictMode == ZSTD_dictMatchState) { - /* dictMatchState repCode checks don't currently handle repCode == 0 - * disabling. */ - assert(offset_1 <= dictAndPrefixLength); - assert(offset_2 <= dictAndPrefixLength); - } + + /* dictMatchState repCode checks don't currently handle repCode == 0 + * disabling. */ + assert(offset_1 <= dictAndPrefixLength); + assert(offset_2 <= dictAndPrefixLength); /* Main Search Loop */ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ @@ -127,37 +366,30 @@ size_t ZSTD_compressBlock_doubleFast_generic( U32 offset; size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8); size_t const h = ZSTD_hashPtr(ip, hBitsS, mls); - size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8); - size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls); - U32 const current = (U32)(ip-base); + size_t const dictHashAndTagL = ZSTD_hashPtr(ip, dictHBitsL, 8); + size_t const dictHashAndTagS = ZSTD_hashPtr(ip, dictHBitsS, mls); + U32 const dictMatchIndexAndTagL = dictHashLong[dictHashAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS]; + U32 const dictMatchIndexAndTagS = dictHashSmall[dictHashAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS]; + int const dictTagsMatchL = ZSTD_comparePackedTags(dictMatchIndexAndTagL, dictHashAndTagL); + int const dictTagsMatchS = ZSTD_comparePackedTags(dictMatchIndexAndTagS, dictHashAndTagS); + U32 const curr = (U32)(ip-base); U32 const matchIndexL = hashLong[h2]; U32 matchIndexS = hashSmall[h]; const BYTE* matchLong = base + matchIndexL; const BYTE* match = base + matchIndexS; - const U32 repIndex = current + 1 - offset_1; - const BYTE* repMatch = (dictMode == ZSTD_dictMatchState - && repIndex < prefixLowestIndex) ? + const U32 repIndex = curr + 1 - offset_1; + const BYTE* repMatch = (repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; - hashLong[h2] = hashSmall[h] = current; /* update hash tables */ + hashLong[h2] = hashSmall[h] = curr; /* update hash tables */ - /* check dictMatchState repcode */ - if (dictMode == ZSTD_dictMatchState - && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) + /* check repcode */ + if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); - goto _match_stored; - } - - /* check noDict repcode */ - if ( dictMode == ZSTD_noDict - && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { - mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); goto _match_stored; } @@ -169,15 +401,15 @@ size_t ZSTD_compressBlock_doubleFast_generic( while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictMode == ZSTD_dictMatchState) { + } else if (dictTagsMatchL) { /* check dictMatchState long match */ - U32 const dictMatchIndexL = dictHashLong[dictHL]; + U32 const dictMatchIndexL = dictMatchIndexAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS; const BYTE* dictMatchL = dictBase + dictMatchIndexL; assert(dictMatchL < dictEnd); if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) { mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8; - offset = (U32)(current - dictMatchIndexL - dictIndexDelta); + offset = (U32)(curr - dictMatchIndexL - dictIndexDelta); while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */ goto _match_found; } } @@ -187,9 +419,9 @@ size_t ZSTD_compressBlock_doubleFast_generic( if (MEM_read32(match) == MEM_read32(ip)) { goto _search_next_long; } - } else if (dictMode == ZSTD_dictMatchState) { + } else if (dictTagsMatchS) { /* check dictMatchState short match */ - U32 const dictMatchIndexS = dictHashSmall[dictHS]; + U32 const dictMatchIndexS = dictMatchIndexAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS; match = dictBase + dictMatchIndexS; matchIndexS = dictMatchIndexS + dictIndexDelta; @@ -198,15 +430,19 @@ size_t ZSTD_compressBlock_doubleFast_generic( } } ip += ((ip-anchor) >> kSearchStrength) + 1; +#if defined(__aarch64__) + PREFETCH_L1(ip+256); +#endif continue; _search_next_long: - { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); - size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8); + size_t const dictHashAndTagL3 = ZSTD_hashPtr(ip+1, dictHBitsL, 8); U32 const matchIndexL3 = hashLong[hl3]; + U32 const dictMatchIndexAndTagL3 = dictHashLong[dictHashAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS]; + int const dictTagsMatchL3 = ZSTD_comparePackedTags(dictMatchIndexAndTagL3, dictHashAndTagL3); const BYTE* matchL3 = base + matchIndexL3; - hashLong[hl3] = current + 1; + hashLong[hl3] = curr + 1; /* check prefix long +1 match */ if (matchIndexL3 > prefixLowestIndex) { @@ -217,23 +453,23 @@ size_t ZSTD_compressBlock_doubleFast_generic( while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictMode == ZSTD_dictMatchState) { + } else if (dictTagsMatchL3) { /* check dict long +1 match */ - U32 const dictMatchIndexL3 = dictHashLong[dictHLNext]; + U32 const dictMatchIndexL3 = dictMatchIndexAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS; const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3; assert(dictMatchL3 < dictEnd); if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) { mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8; ip++; - offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta); + offset = (U32)(curr + 1 - dictMatchIndexL3 - dictIndexDelta); while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */ goto _match_found; } } } /* if no long +1 match, explore the short match we found */ - if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) { + if (matchIndexS < prefixLowestIndex) { mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4; - offset = (U32)(current - matchIndexS); + offset = (U32)(curr - matchIndexS); while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } else { mLength = ZSTD_count(ip+4, match+4, iend) + 4; @@ -241,13 +477,11 @@ size_t ZSTD_compressBlock_doubleFast_generic( while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } - /* fall-through */ - _match_found: offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); _match_stored: /* match found */ @@ -257,7 +491,7 @@ size_t ZSTD_compressBlock_doubleFast_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = current+2; + { U32 const indexToInsert = curr+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -265,53 +499,55 @@ size_t ZSTD_compressBlock_doubleFast_generic( } /* check immediate repcode */ - if (dictMode == ZSTD_dictMatchState) { - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); - U32 const repIndex2 = current2 - offset_2; - const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState - && repIndex2 < prefixLowestIndex ? - dictBase - dictIndexDelta + repIndex2 : - base + repIndex2; - if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; - U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; - ip += repLength2; - anchor = ip; - continue; - } - break; - } } - - if (dictMode == ZSTD_noDict) { - while ( (ip <= ilimit) - && ( (offset_2>0) - & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { - /* store sequence */ - size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, rLength-MINMATCH); - ip += rLength; + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - offset_2; + const BYTE* repMatch2 = repIndex2 < prefixLowestIndex ? + dictBase + repIndex2 - dictIndexDelta : + base + repIndex2; + if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; + U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; + ip += repLength2; anchor = ip; - continue; /* faster when present ... (?) */ - } } } + continue; + } + break; + } + } } /* while (ip < ilimit) */ /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved; - rep[1] = offset_2 ? offset_2 : offsetSaved; + rep[0] = offset_1; + rep[1] = offset_2; /* Return the last literals size */ return (size_t)(iend - anchor); } +#define ZSTD_GEN_DFAST_FN(dictMode, mls) \ + static size_t ZSTD_compressBlock_doubleFast_##dictMode##_##mls( \ + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ + void const* src, size_t srcSize) \ + { \ + return ZSTD_compressBlock_doubleFast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls); \ + } + +ZSTD_GEN_DFAST_FN(noDict, 4) +ZSTD_GEN_DFAST_FN(noDict, 5) +ZSTD_GEN_DFAST_FN(noDict, 6) +ZSTD_GEN_DFAST_FN(noDict, 7) + +ZSTD_GEN_DFAST_FN(dictMatchState, 4) +ZSTD_GEN_DFAST_FN(dictMatchState, 5) +ZSTD_GEN_DFAST_FN(dictMatchState, 6) +ZSTD_GEN_DFAST_FN(dictMatchState, 7) + size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -322,13 +558,13 @@ size_t ZSTD_compressBlock_doubleFast( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_4(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_5(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_6(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_7(ms, seqStore, rep, src, srcSize); } } @@ -342,13 +578,13 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_4(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_5(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_6(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_7(ms, seqStore, rep, src, srcSize); } } @@ -384,7 +620,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( /* if extDict is invalidated due to maxDistance, switch to "regular" variant */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast(ms, seqStore, rep, src, srcSize); /* Search Loop */ while (ip < ilimit) { /* < instead of <=, because (ip+1) */ @@ -398,31 +634,31 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base; const BYTE* matchLong = matchLongBase + matchLongIndex; - const U32 current = (U32)(ip-base); - const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */ + const U32 curr = (U32)(ip-base); + const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; size_t mLength; - hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */ + hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */ - & (repIndex > dictStartIndex)) + & (offset_1 <= curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); } else { if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) { const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart; U32 offset; mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8; - offset = current - matchLongIndex; + offset = curr - matchLongIndex; while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) { size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8); @@ -430,24 +666,24 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base; const BYTE* match3 = match3Base + matchIndex3; U32 offset; - hashLong[h3] = current + 1; + hashLong[h3] = curr + 1; if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) { const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8; ip++; - offset = current+1 - matchIndex3; + offset = curr+1 - matchIndex3; while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */ } else { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; - offset = current - matchIndex; + offset = curr - matchIndex; while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); } else { ip += ((ip-anchor) >> kSearchStrength) + 1; @@ -461,7 +697,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = current+2; + { U32 const indexToInsert = curr+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -474,12 +710,12 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */ - & (repIndex2 > dictStartIndex)) + & (offset_2 <= current2 - dictStartIndex)) && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; ip += repLength2; @@ -497,6 +733,10 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( return (size_t)(iend - anchor); } +ZSTD_GEN_DFAST_FN(extDict, 4) +ZSTD_GEN_DFAST_FN(extDict, 5) +ZSTD_GEN_DFAST_FN(extDict, 6) +ZSTD_GEN_DFAST_FN(extDict, 7) size_t ZSTD_compressBlock_doubleFast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -507,12 +747,12 @@ size_t ZSTD_compressBlock_doubleFast_extDict( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); + return ZSTD_compressBlock_doubleFast_extDict_4(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); + return ZSTD_compressBlock_doubleFast_extDict_5(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); + return ZSTD_compressBlock_doubleFast_extDict_6(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); + return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize); } } diff --git a/native/zstd/compress/zstd_double_fast.h b/native/zstd/compress/zstd_double_fast.h old mode 100755 new mode 100644 index 4fa31ac..6d8ee8c --- a/native/zstd/compress/zstd_double_fast.h +++ b/native/zstd/compress/zstd_double_fast.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,11 +15,12 @@ extern "C" { #endif -#include "mem.h" /* U32 */ +#include "../common/mem.h" /* U32 */ #include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm); + void const* end, ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp); size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); diff --git a/native/zstd/compress/zstd_fast.c b/native/zstd/compress/zstd_fast.c old mode 100755 new mode 100644 index 6dbefee..2911734 --- a/native/zstd/compress/zstd_fast.c +++ b/native/zstd/compress/zstd_fast.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,8 +11,42 @@ #include "zstd_compress_internal.h" /* ZSTD_hashPtr, ZSTD_count, ZSTD_storeSeq */ #include "zstd_fast.h" +static void ZSTD_fillHashTableForCDict(ZSTD_matchState_t* ms, + const void* const end, + ZSTD_dictTableLoadMethod_e dtlm) +{ + const ZSTD_compressionParameters* const cParams = &ms->cParams; + U32* const hashTable = ms->hashTable; + U32 const hBits = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + U32 const mls = cParams->minMatch; + const BYTE* const base = ms->window.base; + const BYTE* ip = base + ms->nextToUpdate; + const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; + const U32 fastHashFillStep = 3; -void ZSTD_fillHashTable(ZSTD_matchState_t* ms, + /* Currently, we always use ZSTD_dtlm_full for filling CDict tables. + * Feel free to remove this assert if there's a good reason! */ + assert(dtlm == ZSTD_dtlm_full); + + /* Always insert every fastHashFillStep position into the hash table. + * Insert the other positions if their hash entry is empty. + */ + for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { + U32 const curr = (U32)(ip - base); + { size_t const hashAndTag = ZSTD_hashPtr(ip, hBits, mls); + ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr); } + + if (dtlm == ZSTD_dtlm_fast) continue; + /* Only load extra positions for ZSTD_dtlm_full */ + { U32 p; + for (p = 1; p < fastHashFillStep; ++p) { + size_t const hashAndTag = ZSTD_hashPtr(ip + p, hBits, mls); + if (hashTable[hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { /* not yet filled */ + ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr + p); + } } } } +} + +static void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms, const void* const end, ZSTD_dictTableLoadMethod_e dtlm) { @@ -25,152 +59,365 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms, const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; const U32 fastHashFillStep = 3; + /* Currently, we always use ZSTD_dtlm_fast for filling CCtx tables. + * Feel free to remove this assert if there's a good reason! */ + assert(dtlm == ZSTD_dtlm_fast); + /* Always insert every fastHashFillStep position into the hash table. * Insert the other positions if their hash entry is empty. */ for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { - U32 const current = (U32)(ip - base); + U32 const curr = (U32)(ip - base); size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls); - hashTable[hash0] = current; + hashTable[hash0] = curr; if (dtlm == ZSTD_dtlm_fast) continue; /* Only load extra positions for ZSTD_dtlm_full */ { U32 p; for (p = 1; p < fastHashFillStep; ++p) { size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls); if (hashTable[hash] == 0) { /* not yet filled */ - hashTable[hash] = current + p; + hashTable[hash] = curr + p; } } } } } +void ZSTD_fillHashTable(ZSTD_matchState_t* ms, + const void* const end, + ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp) +{ + if (tfp == ZSTD_tfp_forCDict) { + ZSTD_fillHashTableForCDict(ms, end, dtlm); + } else { + ZSTD_fillHashTableForCCtx(ms, end, dtlm); + } +} + +/** + * If you squint hard enough (and ignore repcodes), the search operation at any + * given position is broken into 4 stages: + * + * 1. Hash (map position to hash value via input read) + * 2. Lookup (map hash val to index via hashtable read) + * 3. Load (map index to value at that position via input read) + * 4. Compare + * + * Each of these steps involves a memory read at an address which is computed + * from the previous step. This means these steps must be sequenced and their + * latencies are cumulative. + * + * Rather than do 1->2->3->4 sequentially for a single position before moving + * onto the next, this implementation interleaves these operations across the + * next few positions: + * + * R = Repcode Read & Compare + * H = Hash + * T = Table Lookup + * M = Match Read & Compare + * + * Pos | Time --> + * ----+------------------- + * N | ... M + * N+1 | ... TM + * N+2 | R H T M + * N+3 | H TM + * N+4 | R H T M + * N+5 | H ... + * N+6 | R ... + * + * This is very much analogous to the pipelining of execution in a CPU. And just + * like a CPU, we have to dump the pipeline when we find a match (i.e., take a + * branch). + * + * When this happens, we throw away our current state, and do the following prep + * to re-enter the loop: + * + * Pos | Time --> + * ----+------------------- + * N | H T + * N+1 | H + * + * This is also the work we do at the beginning to enter the loop initially. + */ FORCE_INLINE_TEMPLATE size_t -ZSTD_compressBlock_fast_generic( +ZSTD_compressBlock_fast_noDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls) + U32 const mls, U32 const hasStep) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; + size_t const stepSize = hasStep ? (cParams->targetLength + !(cParams->targetLength) + 1) : 2; const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - /* We check ip0 (ip + 0) and ip1 (ip + 1) each loop */ - const BYTE* ip0 = istart; - const BYTE* ip1; - const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - const U32 maxDistance = 1U << cParams->windowLog; - const U32 validStartIndex = ms->window.dictLimit; - const U32 prefixStartIndex = (endIndex - validStartIndex > maxDistance) ? endIndex - maxDistance : validStartIndex; + const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; - U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved = 0; - /* init */ + const BYTE* anchor = istart; + const BYTE* ip0 = istart; + const BYTE* ip1; + const BYTE* ip2; + const BYTE* ip3; + U32 current0; + + U32 rep_offset1 = rep[0]; + U32 rep_offset2 = rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + + size_t hash0; /* hash for ip0 */ + size_t hash1; /* hash for ip1 */ + U32 idx; /* match idx for ip0 */ + U32 mval; /* src value at match idx */ + + U32 offcode; + const BYTE* match0; + size_t mLength; + + /* ip0 and ip1 are always adjacent. The targetLength skipping and + * uncompressibility acceleration is applied to every other position, + * matching the behavior of #1562. step therefore represents the gap + * between pairs of positions, from ip0 to ip2 or ip1 to ip3. */ + size_t step; + const BYTE* nextStep; + const size_t kStepIncr = (1 << (kSearchStrength - 1)); + DEBUGLOG(5, "ZSTD_compressBlock_fast_generic"); ip0 += (ip0 == prefixStart); + { U32 const curr = (U32)(ip0 - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog); + U32 const maxRep = curr - windowLow; + if (rep_offset2 > maxRep) offsetSaved2 = rep_offset2, rep_offset2 = 0; + if (rep_offset1 > maxRep) offsetSaved1 = rep_offset1, rep_offset1 = 0; + } + + /* start each op */ +_start: /* Requires: ip0 */ + + step = stepSize; + nextStep = ip0 + kStepIncr; + + /* calculate positions, ip0 - anchor == 0, so we skip step calc */ ip1 = ip0 + 1; - { U32 const maxRep = (U32)(ip0 - prefixStart); - if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; + ip2 = ip0 + step; + ip3 = ip2 + 1; + + if (ip3 >= ilimit) { + goto _cleanup; } - /* Main Search Loop */ - while (ip1 < ilimit) { /* < instead of <=, because check at ip0+2 */ - size_t mLength; - BYTE const* ip2 = ip0 + 2; - size_t const h0 = ZSTD_hashPtr(ip0, hlog, mls); - U32 const val0 = MEM_read32(ip0); - size_t const h1 = ZSTD_hashPtr(ip1, hlog, mls); - U32 const val1 = MEM_read32(ip1); - U32 const current0 = (U32)(ip0-base); - U32 const current1 = (U32)(ip1-base); - U32 const matchIndex0 = hashTable[h0]; - U32 const matchIndex1 = hashTable[h1]; - BYTE const* repMatch = ip2-offset_1; - const BYTE* match0 = base + matchIndex0; - const BYTE* match1 = base + matchIndex1; - U32 offcode; - hashTable[h0] = current0; /* update hash table */ - hashTable[h1] = current1; /* update hash table */ - - assert(ip0 + 1 == ip1); - - if ((offset_1 > 0) & (MEM_read32(repMatch) == MEM_read32(ip2))) { - mLength = ip2[-1] == repMatch[-1] ? 1 : 0; - ip0 = ip2 - mLength; - match0 = repMatch - mLength; - offcode = 0; + hash0 = ZSTD_hashPtr(ip0, hlog, mls); + hash1 = ZSTD_hashPtr(ip1, hlog, mls); + + idx = hashTable[hash0]; + + do { + /* load repcode match for ip[2]*/ + const U32 rval = MEM_read32(ip2 - rep_offset1); + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + /* check repcode at ip[2] */ + if ((MEM_read32(ip2) == rval) & (rep_offset1 > 0)) { + ip0 = ip2; + match0 = ip0 - rep_offset1; + mLength = ip0[-1] == match0[-1]; + ip0 -= mLength; + match0 -= mLength; + offcode = REPCODE1_TO_OFFBASE; + mLength += 4; + + /* First write next hash table entry; we've already calculated it. + * This write is known to be safe because the ip1 is before the + * repcode (ip2). */ + hashTable[hash1] = (U32)(ip1 - base); + goto _match; } - if ((matchIndex0 > prefixStartIndex) && MEM_read32(match0) == val0) { - /* found a regular match */ + + /* load match for ip[0] */ + if (idx >= prefixStartIndex) { + mval = MEM_read32(base + idx); + } else { + mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ + } + + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + + /* First write next hash table entry; we've already calculated it. + * This write is known to be safe because the ip1 == ip0 + 1, so + * we know we will resume searching after ip1 */ + hashTable[hash1] = (U32)(ip1 - base); + goto _offset; } - if ((matchIndex1 > prefixStartIndex) && MEM_read32(match1) == val1) { - /* found a regular match after one literal */ - ip0 = ip1; - match0 = match1; + + /* lookup ip[1] */ + idx = hashTable[hash1]; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip3; + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + /* load match for ip[0] */ + if (idx >= prefixStartIndex) { + mval = MEM_read32(base + idx); + } else { + mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ + } + + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + + /* first write next hash table entry; we've already calculated it */ + if (step <= 4) { + /* We need to avoid writing an index into the hash table >= the + * position at which we will pick up our searching after we've + * taken this match. + * + * The minimum possible match has length 4, so the earliest ip0 + * can be after we take this match will be the current ip0 + 4. + * ip1 is ip0 + step - 1. If ip1 is >= ip0 + 4, we can't safely + * write this position. + */ + hashTable[hash1] = (U32)(ip1 - base); + } + goto _offset; } - { size_t const step = ((size_t)(ip0-anchor) >> (kSearchStrength - 1)) + stepSize; - assert(step >= 2); - ip0 += step; - ip1 += step; - continue; + + /* lookup ip[1] */ + idx = hashTable[hash1]; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip0 + step; + ip3 = ip1 + step; + + /* calculate step */ + if (ip2 >= nextStep) { + step++; + PREFETCH_L1(ip1 + 64); + PREFETCH_L1(ip1 + 128); + nextStep += kStepIncr; } -_offset: /* Requires: ip0, match0 */ - /* Compute the offset code */ - offset_2 = offset_1; - offset_1 = (U32)(ip0-match0); - offcode = offset_1 + ZSTD_REP_MOVE; - mLength = 0; - /* Count the backwards match length */ - while (((ip0>anchor) & (match0>prefixStart)) - && (ip0[-1] == match0[-1])) { ip0--; match0--; mLength++; } /* catch up */ + } while (ip3 < ilimit); + +_cleanup: + /* Note that there are probably still a couple positions we could search. + * However, it seems to be a meaningful performance hit to try to search + * them. So let's not. */ + + /* When the repcodes are outside of the prefix, we set them to zero before the loop. + * When the offsets are still zero, we need to restore them after the block to have a correct + * repcode history. If only one offset was invalid, it is easy. The tricky case is when both + * offsets were invalid. We need to figure out which offset to refill with. + * - If both offsets are zero they are in the same order. + * - If both offsets are non-zero, we won't restore the offsets from `offsetSaved[12]`. + * - If only one is zero, we need to decide which offset to restore. + * - If rep_offset1 is non-zero, then rep_offset2 must be offsetSaved1. + * - It is impossible for rep_offset2 to be non-zero. + * + * So if rep_offset1 started invalid (offsetSaved1 != 0) and became valid (rep_offset1 != 0), then + * set rep[0] = rep_offset1 and rep[1] = offsetSaved1. + */ + offsetSaved2 = ((offsetSaved1 != 0) && (rep_offset1 != 0)) ? offsetSaved1 : offsetSaved2; + + /* save reps for next block */ + rep[0] = rep_offset1 ? rep_offset1 : offsetSaved1; + rep[1] = rep_offset2 ? rep_offset2 : offsetSaved2; + + /* Return the last literals size */ + return (size_t)(iend - anchor); + +_offset: /* Requires: ip0, idx */ + + /* Compute the offset code. */ + match0 = base + idx; + rep_offset2 = rep_offset1; + rep_offset1 = (U32)(ip0-match0); + offcode = OFFSET_TO_OFFBASE(rep_offset1); + mLength = 4; + + /* Count the backwards match length. */ + while (((ip0>anchor) & (match0>prefixStart)) && (ip0[-1] == match0[-1])) { + ip0--; + match0--; + mLength++; + } _match: /* Requires: ip0, match0, offcode */ - /* Count the forward length */ - mLength += ZSTD_count(ip0+mLength+4, match0+mLength+4, iend) + 4; - ZSTD_storeSeq(seqStore, (size_t)(ip0-anchor), anchor, iend, offcode, mLength-MINMATCH); - /* match found */ - ip0 += mLength; - anchor = ip0; - ip1 = ip0 + 1; - if (ip0 <= ilimit) { - /* Fill Table */ - assert(base+current0+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + /* Count the forward length. */ + mLength += ZSTD_count(ip0 + mLength, match0 + mLength, iend); + + ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); - while ( ((ip0 <= ilimit) & (offset_2>0)) /* offset_2==0 means offset_2 is invalidated */ - && (MEM_read32(ip0) == MEM_read32(ip0 - offset_2)) ) { + ip0 += mLength; + anchor = ip0; + + /* Fill table and check for immediate repcode. */ + if (ip0 <= ilimit) { + /* Fill Table */ + assert(base+current0+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + + if (rep_offset2 > 0) { /* rep_offset2==0 means rep_offset2 is invalidated */ + while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - rep_offset2)) ) { /* store sequence */ - size_t const rLength = ZSTD_count(ip0+4, ip0+4-offset_2, iend) + 4; - { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ + size_t const rLength = ZSTD_count(ip0+4, ip0+4-rep_offset2, iend) + 4; + { U32 const tmpOff = rep_offset2; rep_offset2 = rep_offset1; rep_offset1 = tmpOff; } /* swap rep_offset2 <=> rep_offset1 */ hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); ip0 += rLength; - ip1 = ip0 + 1; - ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, 0 /*offCode*/, rLength-MINMATCH); + ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, REPCODE1_TO_OFFBASE, rLength); anchor = ip0; continue; /* faster when present (confirmed on gcc-8) ... (?) */ - } - } - } - - /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved; - rep[1] = offset_2 ? offset_2 : offsetSaved; + } } } - /* Return the last literals size */ - return (size_t)(iend - anchor); + goto _start; } +#define ZSTD_GEN_FAST_FN(dictMode, mls, step) \ + static size_t ZSTD_compressBlock_fast_##dictMode##_##mls##_##step( \ + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ + void const* src, size_t srcSize) \ + { \ + return ZSTD_compressBlock_fast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls, step); \ + } + +ZSTD_GEN_FAST_FN(noDict, 4, 1) +ZSTD_GEN_FAST_FN(noDict, 5, 1) +ZSTD_GEN_FAST_FN(noDict, 6, 1) +ZSTD_GEN_FAST_FN(noDict, 7, 1) + +ZSTD_GEN_FAST_FN(noDict, 4, 0) +ZSTD_GEN_FAST_FN(noDict, 5, 0) +ZSTD_GEN_FAST_FN(noDict, 6, 0) +ZSTD_GEN_FAST_FN(noDict, 7, 0) size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -178,24 +425,40 @@ size_t ZSTD_compressBlock_fast( { U32 const mls = ms->cParams.minMatch; assert(ms->dictMatchState == NULL); - switch(mls) - { - default: /* includes case 3 */ - case 4 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4); - case 5 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5); - case 6 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6); - case 7 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7); + if (ms->cParams.targetLength > 1) { + switch(mls) + { + default: /* includes case 3 */ + case 4 : + return ZSTD_compressBlock_fast_noDict_4_1(ms, seqStore, rep, src, srcSize); + case 5 : + return ZSTD_compressBlock_fast_noDict_5_1(ms, seqStore, rep, src, srcSize); + case 6 : + return ZSTD_compressBlock_fast_noDict_6_1(ms, seqStore, rep, src, srcSize); + case 7 : + return ZSTD_compressBlock_fast_noDict_7_1(ms, seqStore, rep, src, srcSize); + } + } else { + switch(mls) + { + default: /* includes case 3 */ + case 4 : + return ZSTD_compressBlock_fast_noDict_4_0(ms, seqStore, rep, src, srcSize); + case 5 : + return ZSTD_compressBlock_fast_noDict_5_0(ms, seqStore, rep, src, srcSize); + case 6 : + return ZSTD_compressBlock_fast_noDict_6_0(ms, seqStore, rep, src, srcSize); + case 7 : + return ZSTD_compressBlock_fast_noDict_7_0(ms, seqStore, rep, src, srcSize); + } + } } FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_fast_dictMatchState_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls) + void const* src, size_t srcSize, U32 const mls, U32 const hasStep) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; @@ -204,14 +467,14 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( U32 const stepSize = cParams->targetLength + !(cParams->targetLength); const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; + const BYTE* ip0 = istart; + const BYTE* ip1 = ip0 + stepSize; /* we assert below that stepSize >= 1 */ const BYTE* anchor = istart; const U32 prefixStartIndex = ms->window.dictLimit; const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; const ZSTD_compressionParameters* const dictCParams = &dms->cParams ; @@ -221,125 +484,182 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( const BYTE* const dictStart = dictBase + dictStartIndex; const BYTE* const dictEnd = dms->window.nextSrc; const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase); - const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); - const U32 dictHLog = dictCParams->hashLog; + const U32 dictAndPrefixLength = (U32)(istart - prefixStart + dictEnd - dictStart); + const U32 dictHBits = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; /* if a dictionary is still attached, it necessarily means that * it is within window size. So we just check it. */ const U32 maxDistance = 1U << cParams->windowLog; - const U32 endIndex = (U32)((size_t)(ip - base) + srcSize); + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); assert(endIndex - prefixStartIndex <= maxDistance); (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ - /* ensure there will be no no underflow + (void)hasStep; /* not currently specialized on whether it's accelerated */ + + /* ensure there will be no underflow * when translating a dict index into a local index */ assert(prefixStartIndex >= (U32)(dictEnd - dictBase)); + if (ms->prefetchCDictTables) { + size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); + PREFETCH_AREA(dictHashTable, hashTableBytes) + } + /* init */ DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic"); - ip += (dictAndPrefixLength == 0); + ip0 += (dictAndPrefixLength == 0); /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); - /* Main Search Loop */ - while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ + /* Outer search loop */ + assert(stepSize >= 1); + while (ip1 <= ilimit) { /* repcode check at (ip0 + 1) is safe because ip0 < ip1 */ size_t mLength; - size_t const h = ZSTD_hashPtr(ip, hlog, mls); - U32 const current = (U32)(ip-base); - U32 const matchIndex = hashTable[h]; - const BYTE* match = base + matchIndex; - const U32 repIndex = current + 1 - offset_1; - const BYTE* repMatch = (repIndex < prefixStartIndex) ? - dictBase + (repIndex - dictIndexDelta) : - base + repIndex; - hashTable[h] = current; /* update hash table */ - - if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ - && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { - const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); - } else if ( (matchIndex <= prefixStartIndex) ) { - size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); - U32 const dictMatchIndex = dictHashTable[dictHash]; - const BYTE* dictMatch = dictBase + dictMatchIndex; - if (dictMatchIndex <= dictStartIndex || - MEM_read32(dictMatch) != MEM_read32(ip)) { - assert(stepSize >= 1); - ip += ((ip-anchor) >> kSearchStrength) + stepSize; - continue; - } else { - /* found a dict match */ - U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta); - mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4; - while (((ip>anchor) & (dictMatch>dictStart)) - && (ip[-1] == dictMatch[-1])) { - ip--; dictMatch--; mLength++; + size_t hash0 = ZSTD_hashPtr(ip0, hlog, mls); + + size_t const dictHashAndTag0 = ZSTD_hashPtr(ip0, dictHBits, mls); + U32 dictMatchIndexAndTag = dictHashTable[dictHashAndTag0 >> ZSTD_SHORT_CACHE_TAG_BITS]; + int dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag0); + + U32 matchIndex = hashTable[hash0]; + U32 curr = (U32)(ip0 - base); + size_t step = stepSize; + const size_t kStepIncr = 1 << kSearchStrength; + const BYTE* nextStep = ip0 + kStepIncr; + + /* Inner search loop */ + while (1) { + const BYTE* match = base + matchIndex; + const U32 repIndex = curr + 1 - offset_1; + const BYTE* repMatch = (repIndex < prefixStartIndex) ? + dictBase + (repIndex - dictIndexDelta) : + base + repIndex; + const size_t hash1 = ZSTD_hashPtr(ip1, hlog, mls); + size_t const dictHashAndTag1 = ZSTD_hashPtr(ip1, dictHBits, mls); + hashTable[hash0] = curr; /* update hash table */ + + if (((U32) ((prefixStartIndex - 1) - repIndex) >= + 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ + && (MEM_read32(repMatch) == MEM_read32(ip0 + 1))) { + const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + mLength = ZSTD_count_2segments(ip0 + 1 + 4, repMatch + 4, iend, repMatchEnd, prefixStart) + 4; + ip0++; + ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + break; + } + + if (dictTagsMatch) { + /* Found a possible dict match */ + const U32 dictMatchIndex = dictMatchIndexAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; + const BYTE* dictMatch = dictBase + dictMatchIndex; + if (dictMatchIndex > dictStartIndex && + MEM_read32(dictMatch) == MEM_read32(ip0)) { + /* To replicate extDict parse behavior, we only use dict matches when the normal matchIndex is invalid */ + if (matchIndex <= prefixStartIndex) { + U32 const offset = (U32) (curr - dictMatchIndex - dictIndexDelta); + mLength = ZSTD_count_2segments(ip0 + 4, dictMatch + 4, iend, dictEnd, prefixStart) + 4; + while (((ip0 > anchor) & (dictMatch > dictStart)) + && (ip0[-1] == dictMatch[-1])) { + ip0--; + dictMatch--; + mLength++; + } /* catch up */ + offset_2 = offset_1; + offset_1 = offset; + ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + break; + } + } + } + + if (matchIndex > prefixStartIndex && MEM_read32(match) == MEM_read32(ip0)) { + /* found a regular match */ + U32 const offset = (U32) (ip0 - match); + mLength = ZSTD_count(ip0 + 4, match + 4, iend) + 4; + while (((ip0 > anchor) & (match > prefixStart)) + && (ip0[-1] == match[-1])) { + ip0--; + match--; + mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + break; } - } else if (MEM_read32(match) != MEM_read32(ip)) { - /* it's not a match, and we're not going to check the dictionary */ - assert(stepSize >= 1); - ip += ((ip-anchor) >> kSearchStrength) + stepSize; - continue; - } else { - /* found a regular match */ - U32 const offset = (U32)(ip-match); - mLength = ZSTD_count(ip+4, match+4, iend) + 4; - while (((ip>anchor) & (match>prefixStart)) - && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ - offset_2 = offset_1; - offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); - } + + /* Prepare for next iteration */ + dictMatchIndexAndTag = dictHashTable[dictHashAndTag1 >> ZSTD_SHORT_CACHE_TAG_BITS]; + dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag1); + matchIndex = hashTable[hash1]; + + if (ip1 >= nextStep) { + step++; + nextStep += kStepIncr; + } + ip0 = ip1; + ip1 = ip1 + step; + if (ip1 > ilimit) goto _cleanup; + + curr = (U32)(ip0 - base); + hash0 = hash1; + } /* end inner search loop */ /* match found */ - ip += mLength; - anchor = ip; + assert(mLength); + ip0 += mLength; + anchor = ip0; - if (ip <= ilimit) { + if (ip0 <= ilimit) { /* Fill Table */ - assert(base+current+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); + assert(base+curr+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2; /* here because curr+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); /* check immediate repcode */ - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); + while (ip0 <= ilimit) { + U32 const current2 = (U32)(ip0-base); U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase - dictIndexDelta + repIndex2 : base + repIndex2; if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + && (MEM_read32(repMatch2) == MEM_read32(ip0))) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); - hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; - ip += repLength2; - anchor = ip; + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = current2; + ip0 += repLength2; + anchor = ip0; continue; } break; } } + + /* Prepare for next iteration */ + assert(ip0 == anchor); + ip1 = ip0 + stepSize; } +_cleanup: /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved; - rep[1] = offset_2 ? offset_2 : offsetSaved; + rep[0] = offset_1; + rep[1] = offset_2; /* Return the last literals size */ return (size_t)(iend - anchor); } + +ZSTD_GEN_FAST_FN(dictMatchState, 4, 0) +ZSTD_GEN_FAST_FN(dictMatchState, 5, 0) +ZSTD_GEN_FAST_FN(dictMatchState, 6, 0) +ZSTD_GEN_FAST_FN(dictMatchState, 7, 0) + size_t ZSTD_compressBlock_fast_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -350,30 +670,29 @@ size_t ZSTD_compressBlock_fast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 4); + return ZSTD_compressBlock_fast_dictMatchState_4_0(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 5); + return ZSTD_compressBlock_fast_dictMatchState_5_0(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 6); + return ZSTD_compressBlock_fast_dictMatchState_6_0(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 7); + return ZSTD_compressBlock_fast_dictMatchState_7_0(ms, seqStore, rep, src, srcSize); } } static size_t ZSTD_compressBlock_fast_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls) + void const* src, size_t srcSize, U32 const mls, U32 const hasStep) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - U32 const stepSize = cParams->targetLength + !(cParams->targetLength); + size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog); @@ -386,99 +705,256 @@ static size_t ZSTD_compressBlock_fast_extDict_generic( const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - 8; U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + + const BYTE* ip0 = istart; + const BYTE* ip1; + const BYTE* ip2; + const BYTE* ip3; + U32 current0; + + + size_t hash0; /* hash for ip0 */ + size_t hash1; /* hash for ip1 */ + U32 idx; /* match idx for ip0 */ + const BYTE* idxBase; /* base pointer for idx */ + + U32 offcode; + const BYTE* match0; + size_t mLength; + const BYTE* matchEnd = 0; /* initialize to avoid warning, assert != 0 later */ + + size_t step; + const BYTE* nextStep; + const size_t kStepIncr = (1 << (kSearchStrength - 1)); + + (void)hasStep; /* not currently specialized on whether it's accelerated */ - DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic"); + DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic (offset_1=%u)", offset_1); /* switch to "regular" variant if extDict is invalidated due to maxDistance */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls); - - /* Search Loop */ - while (ip < ilimit) { /* < instead of <=, because (ip+1) */ - const size_t h = ZSTD_hashPtr(ip, hlog, mls); - const U32 matchIndex = hashTable[h]; - const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; - const BYTE* match = matchBase + matchIndex; - const U32 current = (U32)(ip-base); - const U32 repIndex = current + 1 - offset_1; - const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; - const BYTE* const repMatch = repBase + repIndex; - hashTable[h] = current; /* update hash table */ - assert(offset_1 <= current +1); /* check repIndex */ - - if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex)) - && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { - const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, rLength-MINMATCH); - ip += rLength; - anchor = ip; - } else { - if ( (matchIndex < dictStartIndex) || - (MEM_read32(match) != MEM_read32(ip)) ) { - assert(stepSize >= 1); - ip += ((ip-anchor) >> kSearchStrength) + stepSize; - continue; + return ZSTD_compressBlock_fast(ms, seqStore, rep, src, srcSize); + + { U32 const curr = (U32)(ip0 - base); + U32 const maxRep = curr - dictStartIndex; + if (offset_2 >= maxRep) offsetSaved2 = offset_2, offset_2 = 0; + if (offset_1 >= maxRep) offsetSaved1 = offset_1, offset_1 = 0; + } + + /* start each op */ +_start: /* Requires: ip0 */ + + step = stepSize; + nextStep = ip0 + kStepIncr; + + /* calculate positions, ip0 - anchor == 0, so we skip step calc */ + ip1 = ip0 + 1; + ip2 = ip0 + step; + ip3 = ip2 + 1; + + if (ip3 >= ilimit) { + goto _cleanup; + } + + hash0 = ZSTD_hashPtr(ip0, hlog, mls); + hash1 = ZSTD_hashPtr(ip1, hlog, mls); + + idx = hashTable[hash0]; + idxBase = idx < prefixStartIndex ? dictBase : base; + + do { + { /* load repcode match for ip[2] */ + U32 const current2 = (U32)(ip2 - base); + U32 const repIndex = current2 - offset_1; + const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; + U32 rval; + if ( ((U32)(prefixStartIndex - repIndex) >= 4) /* intentional underflow */ + & (offset_1 > 0) ) { + rval = MEM_read32(repBase + repIndex); + } else { + rval = MEM_read32(ip2) ^ 1; /* guaranteed to not match. */ } - { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; - const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; - U32 const offset = current - matchIndex; - size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; - while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ - offset_2 = offset_1; offset_1 = offset; /* update offset history */ - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); - ip += mLength; - anchor = ip; + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + /* check repcode at ip[2] */ + if (MEM_read32(ip2) == rval) { + ip0 = ip2; + match0 = repBase + repIndex; + matchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + assert((match0 != prefixStart) & (match0 != dictStart)); + mLength = ip0[-1] == match0[-1]; + ip0 -= mLength; + match0 -= mLength; + offcode = REPCODE1_TO_OFFBASE; + mLength += 4; + goto _match; } } - if (ip <= ilimit) { - /* Fill Table */ - hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; - hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); - /* check immediate repcode */ - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); - U32 const repIndex2 = current2 - offset_2; - const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; - if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */ - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; - { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, 0 /*offcode*/, repLength2-MINMATCH); - hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; - ip += repLength2; - anchor = ip; - continue; - } - break; - } } } + { /* load match for ip[0] */ + U32 const mval = idx >= dictStartIndex ? + MEM_read32(idxBase + idx) : + MEM_read32(ip0) ^ 1; /* guaranteed not to match */ + + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + goto _offset; + } } + + /* lookup ip[1] */ + idx = hashTable[hash1]; + idxBase = idx < prefixStartIndex ? dictBase : base; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip3; + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + { /* load match for ip[0] */ + U32 const mval = idx >= dictStartIndex ? + MEM_read32(idxBase + idx) : + MEM_read32(ip0) ^ 1; /* guaranteed not to match */ + + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + goto _offset; + } } + + /* lookup ip[1] */ + idx = hashTable[hash1]; + idxBase = idx < prefixStartIndex ? dictBase : base; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip0 + step; + ip3 = ip1 + step; + + /* calculate step */ + if (ip2 >= nextStep) { + step++; + PREFETCH_L1(ip1 + 64); + PREFETCH_L1(ip1 + 128); + nextStep += kStepIncr; + } + } while (ip3 < ilimit); + +_cleanup: + /* Note that there are probably still a couple positions we could search. + * However, it seems to be a meaningful performance hit to try to search + * them. So let's not. */ + + /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), + * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ + offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; /* save reps for next block */ - rep[0] = offset_1; - rep[1] = offset_2; + rep[0] = offset_1 ? offset_1 : offsetSaved1; + rep[1] = offset_2 ? offset_2 : offsetSaved2; /* Return the last literals size */ return (size_t)(iend - anchor); + +_offset: /* Requires: ip0, idx, idxBase */ + + /* Compute the offset code. */ + { U32 const offset = current0 - idx; + const BYTE* const lowMatchPtr = idx < prefixStartIndex ? dictStart : prefixStart; + matchEnd = idx < prefixStartIndex ? dictEnd : iend; + match0 = idxBase + idx; + offset_2 = offset_1; + offset_1 = offset; + offcode = OFFSET_TO_OFFBASE(offset); + mLength = 4; + + /* Count the backwards match length. */ + while (((ip0>anchor) & (match0>lowMatchPtr)) && (ip0[-1] == match0[-1])) { + ip0--; + match0--; + mLength++; + } } + +_match: /* Requires: ip0, match0, offcode, matchEnd */ + + /* Count the forward length. */ + assert(matchEnd != 0); + mLength += ZSTD_count_2segments(ip0 + mLength, match0 + mLength, iend, matchEnd, prefixStart); + + ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); + + ip0 += mLength; + anchor = ip0; + + /* write next hash table entry */ + if (ip1 < ip0) { + hashTable[hash1] = (U32)(ip1 - base); + } + + /* Fill table and check for immediate repcode. */ + if (ip0 <= ilimit) { + /* Fill Table */ + assert(base+current0+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + + while (ip0 <= ilimit) { + U32 const repIndex2 = (U32)(ip0-base) - offset_2; + const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; + if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (offset_2 > 0)) /* intentional underflow */ + && (MEM_read32(repMatch2) == MEM_read32(ip0)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); + ip0 += repLength2; + anchor = ip0; + continue; + } + break; + } } + + goto _start; } +ZSTD_GEN_FAST_FN(extDict, 4, 0) +ZSTD_GEN_FAST_FN(extDict, 5, 0) +ZSTD_GEN_FAST_FN(extDict, 6, 0) +ZSTD_GEN_FAST_FN(extDict, 7, 0) size_t ZSTD_compressBlock_fast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { U32 const mls = ms->cParams.minMatch; + assert(ms->dictMatchState == NULL); switch(mls) { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); + return ZSTD_compressBlock_fast_extDict_4_0(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); + return ZSTD_compressBlock_fast_extDict_5_0(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); + return ZSTD_compressBlock_fast_extDict_6_0(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); + return ZSTD_compressBlock_fast_extDict_7_0(ms, seqStore, rep, src, srcSize); } } diff --git a/native/zstd/compress/zstd_fast.h b/native/zstd/compress/zstd_fast.h old mode 100755 new mode 100644 index b74a88c..3bfeb2c --- a/native/zstd/compress/zstd_fast.h +++ b/native/zstd/compress/zstd_fast.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,11 +15,12 @@ extern "C" { #endif -#include "mem.h" /* U32 */ +#include "../common/mem.h" /* U32 */ #include "zstd_compress_internal.h" void ZSTD_fillHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm); + void const* end, ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp); size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); diff --git a/native/zstd/compress/zstd_lazy.c b/native/zstd/compress/zstd_lazy.c old mode 100755 new mode 100644 index 9ad7e03..e54b43c --- a/native/zstd/compress/zstd_lazy.c +++ b/native/zstd/compress/zstd_lazy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -10,6 +10,7 @@ #include "zstd_compress_internal.h" #include "zstd_lazy.h" +#include "../common/bits.h" /* ZSTD_countTrailingZeros64 */ /*-************************************* @@ -58,11 +59,11 @@ ZSTD_updateDUBT(ZSTD_matchState_t* ms, /** ZSTD_insertDUBT1() : * sort one already inserted but unsorted position - * assumption : current >= btlow == (current - btmask) + * assumption : curr >= btlow == (curr - btmask) * doesn't fail */ static void -ZSTD_insertDUBT1(ZSTD_matchState_t* ms, - U32 current, const BYTE* inputEnd, +ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, + U32 curr, const BYTE* inputEnd, U32 nbCompares, U32 btLow, const ZSTD_dictMode_e dictMode) { @@ -74,41 +75,41 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms, const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const U32 dictLimit = ms->window.dictLimit; - const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current; - const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit; + const BYTE* const ip = (curr>=dictLimit) ? base + curr : dictBase + curr; + const BYTE* const iend = (curr>=dictLimit) ? inputEnd : dictBase + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - U32* smallerPtr = bt + 2*(current&btMask); + U32* smallerPtr = bt + 2*(curr&btMask); U32* largerPtr = smallerPtr + 1; U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */ U32 dummy32; /* to be nullified at the end */ U32 const windowValid = ms->window.lowLimit; U32 const maxDistance = 1U << cParams->windowLog; - U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid; + U32 const windowLow = (curr - windowValid > maxDistance) ? curr - maxDistance : windowValid; DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)", - current, dictLimit, windowLow); - assert(current >= btLow); + curr, dictLimit, windowLow); + assert(curr >= btLow); assert(ip < iend); /* condition for ZSTD_count */ - while (nbCompares-- && (matchIndex > windowLow)) { + for (; nbCompares && (matchIndex > windowLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < current); + assert(matchIndex < curr); /* note : all candidates are now supposed sorted, * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */ if ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit) /* both in current segment*/ - || (current < dictLimit) /* both in extDict */) { + || (curr < dictLimit) /* both in extDict */) { const BYTE* const mBase = ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) ? base : dictBase; assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */ - || (current < dictLimit) ); + || (curr < dictLimit) ); match = mBase + matchIndex; matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); } else { @@ -119,7 +120,7 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms, } DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ", - current, matchIndex, (U32)matchLength); + curr, matchIndex, (U32)matchLength); if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */ @@ -151,7 +152,7 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms, static size_t ZSTD_DUBT_findBetterDictMatch ( - ZSTD_matchState_t* ms, + const ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, size_t* offsetPtr, size_t bestLength, @@ -168,7 +169,7 @@ ZSTD_DUBT_findBetterDictMatch ( const BYTE* const base = ms->window.base; const BYTE* const prefixStart = base + ms->window.dictLimit; - U32 const current = (U32)(ip-base); + U32 const curr = (U32)(ip-base); const BYTE* const dictBase = dms->window.base; const BYTE* const dictEnd = dms->window.nextSrc; U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base); @@ -185,7 +186,7 @@ ZSTD_DUBT_findBetterDictMatch ( (void)dictMode; assert(dictMode == ZSTD_dictMatchState); - while (nbCompares-- && (dictMatchIndex > dictLowLimit)) { + for (; nbCompares && (dictMatchIndex > dictLowLimit); --nbCompares) { U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dictBase + dictMatchIndex; @@ -195,10 +196,10 @@ ZSTD_DUBT_findBetterDictMatch ( if (matchLength > bestLength) { U32 matchIndex = dictMatchIndex + dictIndexDelta; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)", - current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex); - bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; + curr, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, OFFSET_TO_OFFBASE(curr - matchIndex), dictMatchIndex, matchIndex); + bestLength = matchLength, *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); } if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ @@ -218,9 +219,9 @@ ZSTD_DUBT_findBetterDictMatch ( } if (bestLength >= MINMATCH) { - U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; + U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offsetPtr); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - current, (U32)bestLength, (U32)*offsetPtr, mIndex); + curr, (U32)bestLength, (U32)*offsetPtr, mIndex); } return bestLength; @@ -230,7 +231,7 @@ ZSTD_DUBT_findBetterDictMatch ( static size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, - size_t* offsetPtr, + size_t* offBasePtr, U32 const mls, const ZSTD_dictMode_e dictMode) { @@ -241,13 +242,13 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 matchIndex = hashTable[h]; const BYTE* const base = ms->window.base; - U32 const current = (U32)(ip-base); - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); + U32 const curr = (U32)(ip-base); + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); U32* const bt = ms->chainTable; U32 const btLog = cParams->chainLog - 1; U32 const btMask = (1 << btLog) - 1; - U32 const btLow = (btMask >= current) ? 0 : current - btMask; + U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; U32 const unsortLimit = MAX(btLow, windowLow); U32* nextCandidate = bt + 2*(matchIndex&btMask); @@ -256,8 +257,9 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 nbCandidates = nbCompares; U32 previousCandidate = 0; - DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current); + DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", curr); assert(ip <= iend-8); /* required for h calculation */ + assert(dictMode != ZSTD_dedicatedDictSearch); /* reach end of unsorted candidates list */ while ( (matchIndex > unsortLimit) @@ -299,16 +301,16 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const U32 dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32* smallerPtr = bt + 2*(current&btMask); - U32* largerPtr = bt + 2*(current&btMask) + 1; - U32 matchEndIdx = current + 8 + 1; + U32* smallerPtr = bt + 2*(curr&btMask); + U32* largerPtr = bt + 2*(curr&btMask) + 1; + U32 matchEndIdx = curr + 8 + 1; U32 dummy32; /* to be nullified at the end */ size_t bestLength = 0; matchIndex = hashTable[h]; - hashTable[h] = current; /* Update Hash Table */ + hashTable[h] = curr; /* Update Hash Table */ - while (nbCompares-- && (matchIndex > windowLow)) { + for (; nbCompares && (matchIndex > windowLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match; @@ -326,8 +328,8 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, if (matchLength > bestLength) { if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) - bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr - matchIndex + 1) - ZSTD_highbit32((U32)*offBasePtr)) ) + bestLength = matchLength, *offBasePtr = OFFSET_TO_OFFBASE(curr - matchIndex); if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ if (dictMode == ZSTD_dictMatchState) { nbCompares = 0; /* in addition to avoiding checking any @@ -356,19 +358,20 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, *smallerPtr = *largerPtr = 0; + assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { bestLength = ZSTD_DUBT_findBetterDictMatch( ms, ip, iend, - offsetPtr, bestLength, nbCompares, + offBasePtr, bestLength, nbCompares, mls, dictMode); } - assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */ + assert(matchEndIdx > curr+8); /* ensure nextToUpdate is increased */ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ if (bestLength >= MINMATCH) { - U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; + U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offBasePtr); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - current, (U32)bestLength, (U32)*offsetPtr, mIndex); + curr, (U32)bestLength, (U32)*offBasePtr, mIndex); } return bestLength; } @@ -379,66 +382,232 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, FORCE_INLINE_TEMPLATE size_t ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, - size_t* offsetPtr, + size_t* offBasePtr, const U32 mls /* template */, const ZSTD_dictMode_e dictMode) { DEBUGLOG(7, "ZSTD_BtFindBestMatch"); if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ ZSTD_updateDUBT(ms, ip, iLimit, mls); - return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode); + return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offBasePtr, mls, dictMode); } +/*********************************** +* Dedicated dict search +***********************************/ -static size_t -ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) +void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip) { - switch(ms->cParams.minMatch) + const BYTE* const base = ms->window.base; + U32 const target = (U32)(ip - base); + U32* const hashTable = ms->hashTable; + U32* const chainTable = ms->chainTable; + U32 const chainSize = 1 << ms->cParams.chainLog; + U32 idx = ms->nextToUpdate; + U32 const minChain = chainSize < target - idx ? target - chainSize : idx; + U32 const bucketSize = 1 << ZSTD_LAZY_DDSS_BUCKET_LOG; + U32 const cacheSize = bucketSize - 1; + U32 const chainAttempts = (1 << ms->cParams.searchLog) - cacheSize; + U32 const chainLimit = chainAttempts > 255 ? 255 : chainAttempts; + + /* We know the hashtable is oversized by a factor of `bucketSize`. + * We are going to temporarily pretend `bucketSize == 1`, keeping only a + * single entry. We will use the rest of the space to construct a temporary + * chaintable. + */ + U32 const hashLog = ms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; + U32* const tmpHashTable = hashTable; + U32* const tmpChainTable = hashTable + ((size_t)1 << hashLog); + U32 const tmpChainSize = (U32)((1 << ZSTD_LAZY_DDSS_BUCKET_LOG) - 1) << hashLog; + U32 const tmpMinChain = tmpChainSize < target ? target - tmpChainSize : idx; + U32 hashIdx; + + assert(ms->cParams.chainLog <= 24); + assert(ms->cParams.hashLog > ms->cParams.chainLog); + assert(idx != 0); + assert(tmpMinChain <= minChain); + + /* fill conventional hash table and conventional chain table */ + for ( ; idx < target; idx++) { + U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch); + if (idx >= tmpMinChain) { + tmpChainTable[idx - tmpMinChain] = hashTable[h]; + } + tmpHashTable[h] = idx; + } + + /* sort chains into ddss chain table */ { - default : /* includes case 3 */ - case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); - case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); - case 7 : - case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); + U32 chainPos = 0; + for (hashIdx = 0; hashIdx < (1U << hashLog); hashIdx++) { + U32 count; + U32 countBeyondMinChain = 0; + U32 i = tmpHashTable[hashIdx]; + for (count = 0; i >= tmpMinChain && count < cacheSize; count++) { + /* skip through the chain to the first position that won't be + * in the hash cache bucket */ + if (i < minChain) { + countBeyondMinChain++; + } + i = tmpChainTable[i - tmpMinChain]; + } + if (count == cacheSize) { + for (count = 0; count < chainLimit;) { + if (i < minChain) { + if (!i || ++countBeyondMinChain > cacheSize) { + /* only allow pulling `cacheSize` number of entries + * into the cache or chainTable beyond `minChain`, + * to replace the entries pulled out of the + * chainTable into the cache. This lets us reach + * back further without increasing the total number + * of entries in the chainTable, guaranteeing the + * DDSS chain table will fit into the space + * allocated for the regular one. */ + break; + } + } + chainTable[chainPos++] = i; + count++; + if (i < tmpMinChain) { + break; + } + i = tmpChainTable[i - tmpMinChain]; + } + } else { + count = 0; + } + if (count) { + tmpHashTable[hashIdx] = ((chainPos - count) << 8) + count; + } else { + tmpHashTable[hashIdx] = 0; + } + } + assert(chainPos <= chainSize); /* I believe this is guaranteed... */ } + + /* move chain pointers into the last entry of each hash bucket */ + for (hashIdx = (1 << hashLog); hashIdx; ) { + U32 const bucketIdx = --hashIdx << ZSTD_LAZY_DDSS_BUCKET_LOG; + U32 const chainPackedPointer = tmpHashTable[hashIdx]; + U32 i; + for (i = 0; i < cacheSize; i++) { + hashTable[bucketIdx + i] = 0; + } + hashTable[bucketIdx + bucketSize - 1] = chainPackedPointer; + } + + /* fill the buckets of the hash table */ + for (idx = ms->nextToUpdate; idx < target; idx++) { + U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch) + << ZSTD_LAZY_DDSS_BUCKET_LOG; + U32 i; + /* Shift hash cache down 1. */ + for (i = cacheSize - 1; i; i--) + hashTable[h + i] = hashTable[h + i - 1]; + hashTable[h] = idx; + } + + ms->nextToUpdate = target; } +/* Returns the longest match length found in the dedicated dict search structure. + * If none are longer than the argument ml, then ml will be returned. + */ +FORCE_INLINE_TEMPLATE +size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nbAttempts, + const ZSTD_matchState_t* const dms, + const BYTE* const ip, const BYTE* const iLimit, + const BYTE* const prefixStart, const U32 curr, + const U32 dictLimit, const size_t ddsIdx) { + const U32 ddsLowestIndex = dms->window.dictLimit; + const BYTE* const ddsBase = dms->window.base; + const BYTE* const ddsEnd = dms->window.nextSrc; + const U32 ddsSize = (U32)(ddsEnd - ddsBase); + const U32 ddsIndexDelta = dictLimit - ddsSize; + const U32 bucketSize = (1 << ZSTD_LAZY_DDSS_BUCKET_LOG); + const U32 bucketLimit = nbAttempts < bucketSize - 1 ? nbAttempts : bucketSize - 1; + U32 ddsAttempt; + U32 matchIndex; + + for (ddsAttempt = 0; ddsAttempt < bucketSize - 1; ddsAttempt++) { + PREFETCH_L1(ddsBase + dms->hashTable[ddsIdx + ddsAttempt]); + } -static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) -{ - switch(ms->cParams.minMatch) { - default : /* includes case 3 */ - case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); - case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); - case 7 : - case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); + U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; + U32 const chainIndex = chainPackedPointer >> 8; + + PREFETCH_L1(&dms->chainTable[chainIndex]); } -} + for (ddsAttempt = 0; ddsAttempt < bucketLimit; ddsAttempt++) { + size_t currentMl=0; + const BYTE* match; + matchIndex = dms->hashTable[ddsIdx + ddsAttempt]; + match = ddsBase + matchIndex; + + if (!matchIndex) { + return ml; + } + + /* guaranteed by table construction */ + (void)ddsLowestIndex; + assert(matchIndex >= ddsLowestIndex); + assert(match+4 <= ddsEnd); + if (MEM_read32(match) == MEM_read32(ip)) { + /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; + } + + /* save best solution */ + if (currentMl > ml) { + ml = currentMl; + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); + if (ip+currentMl == iLimit) { + /* best possible, avoids read overflow on next attempt */ + return ml; + } + } + } -static size_t ZSTD_BtFindBestMatch_extDict_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) -{ - switch(ms->cParams.minMatch) { - default : /* includes case 3 */ - case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); - case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); - case 7 : - case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); + U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; + U32 chainIndex = chainPackedPointer >> 8; + U32 const chainLength = chainPackedPointer & 0xFF; + U32 const chainAttempts = nbAttempts - ddsAttempt; + U32 const chainLimit = chainAttempts > chainLength ? chainLength : chainAttempts; + U32 chainAttempt; + + for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++) { + PREFETCH_L1(ddsBase + dms->chainTable[chainIndex + chainAttempt]); + } + + for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++, chainIndex++) { + size_t currentMl=0; + const BYTE* match; + matchIndex = dms->chainTable[chainIndex]; + match = ddsBase + matchIndex; + + /* guaranteed by table construction */ + assert(matchIndex >= ddsLowestIndex); + assert(match+4 <= ddsEnd); + if (MEM_read32(match) == MEM_read32(ip)) { + /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; + } + + /* save best solution */ + if (currentMl > ml) { + ml = currentMl; + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); + if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ + } + } } + return ml; } - /* ********************************* * Hash Chain ***********************************/ @@ -446,7 +615,7 @@ static size_t ZSTD_BtFindBestMatch_extDict_selectMLS ( /* Update chains up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -static U32 ZSTD_insertAndFindFirstIndex_internal( +FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal( ZSTD_matchState_t* ms, const ZSTD_compressionParameters* const cParams, const BYTE* ip, U32 const mls) @@ -475,10 +644,9 @@ U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) { return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch); } - /* inlining is important to hardwire a hot branch (template emulation) */ FORCE_INLINE_TEMPLATE -size_t ZSTD_HcFindBestMatch_generic ( +size_t ZSTD_HcFindBestMatch( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, size_t* offsetPtr, @@ -493,20 +661,33 @@ size_t ZSTD_HcFindBestMatch_generic ( const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; - const U32 current = (U32)(ip-base); + const U32 curr = (U32)(ip-base); const U32 maxDistance = 1U << cParams->windowLog; const U32 lowestValid = ms->window.lowLimit; - const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; + const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; const U32 isDictionary = (ms->loadedDictEnd != 0); const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; - const U32 minChain = current > chainSize ? current - chainSize : 0; + const U32 minChain = curr > chainSize ? curr - chainSize : 0; U32 nbAttempts = 1U << cParams->searchLog; size_t ml=4-1; + const ZSTD_matchState_t* const dms = ms->dictMatchState; + const U32 ddsHashLog = dictMode == ZSTD_dedicatedDictSearch + ? dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG : 0; + const size_t ddsIdx = dictMode == ZSTD_dedicatedDictSearch + ? ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG : 0; + + U32 matchIndex; + + if (dictMode == ZSTD_dedicatedDictSearch) { + const U32* entry = &dms->hashTable[ddsIdx]; + PREFETCH_L1(entry); + } + /* HC4 match finder */ - U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls); + matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls); - for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>=lowLimit) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { const BYTE* const match = base + matchIndex; @@ -523,7 +704,7 @@ size_t ZSTD_HcFindBestMatch_generic ( /* save best solution */ if (currentMl > ml) { ml = currentMl; - *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; + *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } @@ -531,8 +712,11 @@ size_t ZSTD_HcFindBestMatch_generic ( matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask); } - if (dictMode == ZSTD_dictMatchState) { - const ZSTD_matchState_t* const dms = ms->dictMatchState; + assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ + if (dictMode == ZSTD_dedicatedDictSearch) { + ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts, dms, + ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); + } else if (dictMode == ZSTD_dictMatchState) { const U32* const dmsChainTable = dms->chainTable; const U32 dmsChainSize = (1 << dms->cParams.chainLog); const U32 dmsChainMask = dmsChainSize - 1; @@ -545,7 +729,7 @@ size_t ZSTD_HcFindBestMatch_generic ( matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)]; - for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>=dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; const BYTE* const match = dmsBase + matchIndex; assert(match+4 <= dmsEnd); @@ -555,11 +739,13 @@ size_t ZSTD_HcFindBestMatch_generic ( /* save best solution */ if (currentMl > ml) { ml = currentMl; - *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE; + assert(curr > matchIndex + dmsIndexDelta); + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } if (matchIndex <= dmsMinChain) break; + matchIndex = dmsChainTable[matchIndex & dmsChainMask]; } } @@ -567,59 +753,735 @@ size_t ZSTD_HcFindBestMatch_generic ( return ml; } +/* ********************************* +* (SIMD) Row-based matchfinder +***********************************/ +/* Constants for row-based hash */ +#define ZSTD_ROW_HASH_TAG_OFFSET 16 /* byte offset of hashes in the match state's tagTable from the beginning of a row */ +#define ZSTD_ROW_HASH_TAG_BITS 8 /* nb bits to use for the tag */ +#define ZSTD_ROW_HASH_TAG_MASK ((1u << ZSTD_ROW_HASH_TAG_BITS) - 1) +#define ZSTD_ROW_HASH_MAX_ENTRIES 64 /* absolute maximum number of entries per row, for all configurations */ + +#define ZSTD_ROW_HASH_CACHE_MASK (ZSTD_ROW_HASH_CACHE_SIZE - 1) -FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) +typedef U64 ZSTD_VecMask; /* Clarifies when we are interacting with a U64 representing a mask of matches */ + +/* ZSTD_VecMask_next(): + * Starting from the LSB, returns the idx of the next non-zero bit. + * Basically counting the nb of trailing zeroes. + */ +MEM_STATIC U32 ZSTD_VecMask_next(ZSTD_VecMask val) { + return ZSTD_countTrailingZeros64(val); +} + +/* ZSTD_rotateRight_*(): + * Rotates a bitfield to the right by "count" bits. + * https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts + */ +FORCE_INLINE_TEMPLATE +U64 ZSTD_rotateRight_U64(U64 const value, U32 count) { + assert(count < 64); + count &= 0x3F; /* for fickle pattern recognition */ + return (value >> count) | (U64)(value << ((0U - count) & 0x3F)); +} + +FORCE_INLINE_TEMPLATE +U32 ZSTD_rotateRight_U32(U32 const value, U32 count) { + assert(count < 32); + count &= 0x1F; /* for fickle pattern recognition */ + return (value >> count) | (U32)(value << ((0U - count) & 0x1F)); +} + +FORCE_INLINE_TEMPLATE +U16 ZSTD_rotateRight_U16(U16 const value, U32 count) { + assert(count < 16); + count &= 0x0F; /* for fickle pattern recognition */ + return (value >> count) | (U16)(value << ((0U - count) & 0x0F)); +} + +/* ZSTD_row_nextIndex(): + * Returns the next index to insert at within a tagTable row, and updates the "head" + * value to reflect the update. Essentially cycles backwards from [0, {entries per row}) + */ +FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextIndex(BYTE* const tagRow, U32 const rowMask) { + U32 const next = (*tagRow - 1) & rowMask; + *tagRow = (BYTE)next; + return next; +} + +/* ZSTD_isAligned(): + * Checks that a pointer is aligned to "align" bytes which must be a power of 2. + */ +MEM_STATIC int ZSTD_isAligned(void const* ptr, size_t align) { + assert((align & (align - 1)) == 0); + return (((size_t)ptr) & (align - 1)) == 0; +} + +/* ZSTD_row_prefetch(): + * Performs prefetching for the hashTable and tagTable at a given row. + */ +FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, U16 const* tagTable, U32 const relRow, U32 const rowLog) { + PREFETCH_L1(hashTable + relRow); + if (rowLog >= 5) { + PREFETCH_L1(hashTable + relRow + 16); + /* Note: prefetching more of the hash table does not appear to be beneficial for 128-entry rows */ + } + PREFETCH_L1(tagTable + relRow); + if (rowLog == 6) { + PREFETCH_L1(tagTable + relRow + 32); + } + assert(rowLog == 4 || rowLog == 5 || rowLog == 6); + assert(ZSTD_isAligned(hashTable + relRow, 64)); /* prefetched hash row always 64-byte aligned */ + assert(ZSTD_isAligned(tagTable + relRow, (size_t)1 << rowLog)); /* prefetched tagRow sits on correct multiple of bytes (32,64,128) */ +} + +/* ZSTD_row_fillHashCache(): + * Fill up the hash cache starting at idx, prefetching up to ZSTD_ROW_HASH_CACHE_SIZE entries, + * but not beyond iLimit. + */ +FORCE_INLINE_TEMPLATE void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base, + U32 const rowLog, U32 const mls, + U32 idx, const BYTE* const iLimit) { - switch(ms->cParams.minMatch) - { - default : /* includes case 3 */ - case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); - case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); - case 7 : - case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); + U32 const* const hashTable = ms->hashTable; + U16 const* const tagTable = ms->tagTable; + U32 const hashLog = ms->rowHashLog; + U32 const maxElemsToPrefetch = (base + idx) > iLimit ? 0 : (U32)(iLimit - (base + idx) + 1); + U32 const lim = idx + MIN(ZSTD_ROW_HASH_CACHE_SIZE, maxElemsToPrefetch); + + for (; idx < lim; ++idx) { + U32 const hash = (U32)ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls); + U32 const row = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); + ms->hashCache[idx & ZSTD_ROW_HASH_CACHE_MASK] = hash; } + + DEBUGLOG(6, "ZSTD_row_fillHashCache(): [%u %u %u %u %u %u %u %u]", ms->hashCache[0], ms->hashCache[1], + ms->hashCache[2], ms->hashCache[3], ms->hashCache[4], + ms->hashCache[5], ms->hashCache[6], ms->hashCache[7]); } +/* ZSTD_row_nextCachedHash(): + * Returns the hash of base + idx, and replaces the hash in the hash cache with the byte at + * base + idx + ZSTD_ROW_HASH_CACHE_SIZE. Also prefetches the appropriate rows from hashTable and tagTable. + */ +FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable, + U16 const* tagTable, BYTE const* base, + U32 idx, U32 const hashLog, + U32 const rowLog, U32 const mls) +{ + U32 const newHash = (U32)ZSTD_hashPtr(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls); + U32 const row = (newHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); + { U32 const hash = cache[idx & ZSTD_ROW_HASH_CACHE_MASK]; + cache[idx & ZSTD_ROW_HASH_CACHE_MASK] = newHash; + return hash; + } +} -static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) +/* ZSTD_row_update_internalImpl(): + * Updates the hash table with positions starting from updateStartIdx until updateEndIdx. + */ +FORCE_INLINE_TEMPLATE void ZSTD_row_update_internalImpl(ZSTD_matchState_t* ms, + U32 updateStartIdx, U32 const updateEndIdx, + U32 const mls, U32 const rowLog, + U32 const rowMask, U32 const useCache) { - switch(ms->cParams.minMatch) - { - default : /* includes case 3 */ - case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); - case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); - case 7 : - case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); + U32* const hashTable = ms->hashTable; + U16* const tagTable = ms->tagTable; + U32 const hashLog = ms->rowHashLog; + const BYTE* const base = ms->window.base; + + DEBUGLOG(6, "ZSTD_row_update_internalImpl(): updateStartIdx=%u, updateEndIdx=%u", updateStartIdx, updateEndIdx); + for (; updateStartIdx < updateEndIdx; ++updateStartIdx) { + U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, updateStartIdx, hashLog, rowLog, mls) + : (U32)ZSTD_hashPtr(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls); + U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + U32* const row = hashTable + relRow; + BYTE* tagRow = (BYTE*)(tagTable + relRow); /* Though tagTable is laid out as a table of U16, each tag is only 1 byte. + Explicit cast allows us to get exact desired position within each row */ + U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); + + assert(hash == ZSTD_hashPtr(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls)); + ((BYTE*)tagRow)[pos + ZSTD_ROW_HASH_TAG_OFFSET] = hash & ZSTD_ROW_HASH_TAG_MASK; + row[pos] = updateStartIdx; + } +} + +/* ZSTD_row_update_internal(): + * Inserts the byte at ip into the appropriate position in the hash table, and updates ms->nextToUpdate. + * Skips sections of long matches as is necessary. + */ +FORCE_INLINE_TEMPLATE void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip, + U32 const mls, U32 const rowLog, + U32 const rowMask, U32 const useCache) +{ + U32 idx = ms->nextToUpdate; + const BYTE* const base = ms->window.base; + const U32 target = (U32)(ip - base); + const U32 kSkipThreshold = 384; + const U32 kMaxMatchStartPositionsToUpdate = 96; + const U32 kMaxMatchEndPositionsToUpdate = 32; + + if (useCache) { + /* Only skip positions when using hash cache, i.e. + * if we are loading a dict, don't skip anything. + * If we decide to skip, then we only update a set number + * of positions at the beginning and end of the match. + */ + if (UNLIKELY(target - idx > kSkipThreshold)) { + U32 const bound = idx + kMaxMatchStartPositionsToUpdate; + ZSTD_row_update_internalImpl(ms, idx, bound, mls, rowLog, rowMask, useCache); + idx = target - kMaxMatchEndPositionsToUpdate; + ZSTD_row_fillHashCache(ms, base, rowLog, mls, idx, ip+1); + } } + assert(target >= idx); + ZSTD_row_update_internalImpl(ms, idx, target, mls, rowLog, rowMask, useCache); + ms->nextToUpdate = target; } +/* ZSTD_row_update(): + * External wrapper for ZSTD_row_update_internal(). Used for filling the hashtable during dictionary + * processing. + */ +void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip) { + const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); + const U32 rowMask = (1u << rowLog) - 1; + const U32 mls = MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */); + + DEBUGLOG(5, "ZSTD_row_update(), rowLog=%u", rowLog); + ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 0 /* don't use cache */); +} -FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( +/* Returns the mask width of bits group of which will be set to 1. Given not all + * architectures have easy movemask instruction, this helps to iterate over + * groups of bits easier and faster. + */ +FORCE_INLINE_TEMPLATE U32 +ZSTD_row_matchMaskGroupWidth(const U32 rowEntries) +{ + assert((rowEntries == 16) || (rowEntries == 32) || rowEntries == 64); + assert(rowEntries <= ZSTD_ROW_HASH_MAX_ENTRIES); + (void)rowEntries; +#if defined(ZSTD_ARCH_ARM_NEON) + /* NEON path only works for little endian */ + if (!MEM_isLittleEndian()) { + return 1; + } + if (rowEntries == 16) { + return 4; + } + if (rowEntries == 32) { + return 2; + } + if (rowEntries == 64) { + return 1; + } +#endif + return 1; +} + +#if defined(ZSTD_ARCH_X86_SSE2) +FORCE_INLINE_TEMPLATE ZSTD_VecMask +ZSTD_row_getSSEMask(int nbChunks, const BYTE* const src, const BYTE tag, const U32 head) +{ + const __m128i comparisonMask = _mm_set1_epi8((char)tag); + int matches[4] = {0}; + int i; + assert(nbChunks == 1 || nbChunks == 2 || nbChunks == 4); + for (i=0; i> chunkSize; + do { + size_t chunk = MEM_readST(&src[i]); + chunk ^= splatChar; + chunk = (((chunk | x80) - x01) | chunk) & x80; + matches <<= chunkSize; + matches |= (chunk * extractMagic) >> shiftAmount; + i -= chunkSize; + } while (i >= 0); + } else { /* big endian: reverse bits during extraction */ + const size_t msb = xFF ^ (xFF >> 1); + const size_t extractMagic = (msb / 0x1FF) | msb; + do { + size_t chunk = MEM_readST(&src[i]); + chunk ^= splatChar; + chunk = (((chunk | x80) - x01) | chunk) & x80; + matches <<= chunkSize; + matches |= ((chunk >> 7) * extractMagic) >> shiftAmount; + i -= chunkSize; + } while (i >= 0); + } + matches = ~matches; + if (rowEntries == 16) { + return ZSTD_rotateRight_U16((U16)matches, headGrouped); + } else if (rowEntries == 32) { + return ZSTD_rotateRight_U32((U32)matches, headGrouped); + } else { + return ZSTD_rotateRight_U64((U64)matches, headGrouped); + } + } +#endif +} + +/* The high-level approach of the SIMD row based match finder is as follows: + * - Figure out where to insert the new entry: + * - Generate a hash from a byte along with an additional 1-byte "short hash". The additional byte is our "tag" + * - The hashTable is effectively split into groups or "rows" of 16 or 32 entries of U32, and the hash determines + * which row to insert into. + * - Determine the correct position within the row to insert the entry into. Each row of 16 or 32 can + * be considered as a circular buffer with a "head" index that resides in the tagTable. + * - Also insert the "tag" into the equivalent row and position in the tagTable. + * - Note: The tagTable has 17 or 33 1-byte entries per row, due to 16 or 32 tags, and 1 "head" entry. + * The 17 or 33 entry rows are spaced out to occur every 32 or 64 bytes, respectively, + * for alignment/performance reasons, leaving some bytes unused. + * - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte "short hash" and + * generate a bitfield that we can cycle through to check the collisions in the hash table. + * - Pick the longest match. + */ +FORCE_INLINE_TEMPLATE +size_t ZSTD_RowFindBestMatch( ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) + const BYTE* const ip, const BYTE* const iLimit, + size_t* offsetPtr, + const U32 mls, const ZSTD_dictMode_e dictMode, + const U32 rowLog) { - switch(ms->cParams.minMatch) - { - default : /* includes case 3 */ - case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); - case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); - case 7 : - case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); + U32* const hashTable = ms->hashTable; + U16* const tagTable = ms->tagTable; + U32* const hashCache = ms->hashCache; + const U32 hashLog = ms->rowHashLog; + const ZSTD_compressionParameters* const cParams = &ms->cParams; + const BYTE* const base = ms->window.base; + const BYTE* const dictBase = ms->window.dictBase; + const U32 dictLimit = ms->window.dictLimit; + const BYTE* const prefixStart = base + dictLimit; + const BYTE* const dictEnd = dictBase + dictLimit; + const U32 curr = (U32)(ip-base); + const U32 maxDistance = 1U << cParams->windowLog; + const U32 lowestValid = ms->window.lowLimit; + const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + const U32 isDictionary = (ms->loadedDictEnd != 0); + const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; + const U32 rowEntries = (1U << rowLog); + const U32 rowMask = rowEntries - 1; + const U32 cappedSearchLog = MIN(cParams->searchLog, rowLog); /* nb of searches is capped at nb entries per row */ + const U32 groupWidth = ZSTD_row_matchMaskGroupWidth(rowEntries); + U32 nbAttempts = 1U << cappedSearchLog; + size_t ml=4-1; + + /* DMS/DDS variables that may be referenced laster */ + const ZSTD_matchState_t* const dms = ms->dictMatchState; + + /* Initialize the following variables to satisfy static analyzer */ + size_t ddsIdx = 0; + U32 ddsExtraAttempts = 0; /* cctx hash tables are limited in searches, but allow extra searches into DDS */ + U32 dmsTag = 0; + U32* dmsRow = NULL; + BYTE* dmsTagRow = NULL; + + if (dictMode == ZSTD_dedicatedDictSearch) { + const U32 ddsHashLog = dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; + { /* Prefetch DDS hashtable entry */ + ddsIdx = ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG; + PREFETCH_L1(&dms->hashTable[ddsIdx]); + } + ddsExtraAttempts = cParams->searchLog > rowLog ? 1U << (cParams->searchLog - rowLog) : 0; + } + + if (dictMode == ZSTD_dictMatchState) { + /* Prefetch DMS rows */ + U32* const dmsHashTable = dms->hashTable; + U16* const dmsTagTable = dms->tagTable; + U32 const dmsHash = (U32)ZSTD_hashPtr(ip, dms->rowHashLog + ZSTD_ROW_HASH_TAG_BITS, mls); + U32 const dmsRelRow = (dmsHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + dmsTag = dmsHash & ZSTD_ROW_HASH_TAG_MASK; + dmsTagRow = (BYTE*)(dmsTagTable + dmsRelRow); + dmsRow = dmsHashTable + dmsRelRow; + ZSTD_row_prefetch(dmsHashTable, dmsTagTable, dmsRelRow, rowLog); + } + + /* Update the hashTable and tagTable up to (but not including) ip */ + ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */); + { /* Get the hash for ip, compute the appropriate row */ + U32 const hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls); + U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + U32 const tag = hash & ZSTD_ROW_HASH_TAG_MASK; + U32* const row = hashTable + relRow; + BYTE* tagRow = (BYTE*)(tagTable + relRow); + U32 const headGrouped = (*tagRow & rowMask) * groupWidth; + U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; + size_t numMatches = 0; + size_t currMatch = 0; + ZSTD_VecMask matches = ZSTD_row_getMatchMask(tagRow, (BYTE)tag, headGrouped, rowEntries); + + /* Cycle through the matches and prefetch */ + for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) { + U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; + U32 const matchIndex = row[matchPos]; + assert(numMatches < rowEntries); + if (matchIndex < lowLimit) + break; + if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { + PREFETCH_L1(base + matchIndex); + } else { + PREFETCH_L1(dictBase + matchIndex); + } + matchBuffer[numMatches++] = matchIndex; + } + + /* Speed opt: insert current byte into hashtable too. This allows us to avoid one iteration of the loop + in ZSTD_row_update_internal() at the next search. */ + { + U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); + tagRow[pos + ZSTD_ROW_HASH_TAG_OFFSET] = (BYTE)tag; + row[pos] = ms->nextToUpdate++; + } + + /* Return the longest match */ + for (; currMatch < numMatches; ++currMatch) { + U32 const matchIndex = matchBuffer[currMatch]; + size_t currentMl=0; + assert(matchIndex < curr); + assert(matchIndex >= lowLimit); + + if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { + const BYTE* const match = base + matchIndex; + assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */ + if (match[ml] == ip[ml]) /* potentially better */ + currentMl = ZSTD_count(ip, match, iLimit); + } else { + const BYTE* const match = dictBase + matchIndex; + assert(match+4 <= dictEnd); + if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4; + } + + /* Save best solution */ + if (currentMl > ml) { + ml = currentMl; + *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); + if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ + } + } + } + + assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ + if (dictMode == ZSTD_dedicatedDictSearch) { + ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts + ddsExtraAttempts, dms, + ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); + } else if (dictMode == ZSTD_dictMatchState) { + /* TODO: Measure and potentially add prefetching to DMS */ + const U32 dmsLowestIndex = dms->window.dictLimit; + const BYTE* const dmsBase = dms->window.base; + const BYTE* const dmsEnd = dms->window.nextSrc; + const U32 dmsSize = (U32)(dmsEnd - dmsBase); + const U32 dmsIndexDelta = dictLimit - dmsSize; + + { U32 const headGrouped = (*dmsTagRow & rowMask) * groupWidth; + U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; + size_t numMatches = 0; + size_t currMatch = 0; + ZSTD_VecMask matches = ZSTD_row_getMatchMask(dmsTagRow, (BYTE)dmsTag, headGrouped, rowEntries); + + for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) { + U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; + U32 const matchIndex = dmsRow[matchPos]; + if (matchIndex < dmsLowestIndex) + break; + PREFETCH_L1(dmsBase + matchIndex); + matchBuffer[numMatches++] = matchIndex; + } + + /* Return the longest match */ + for (; currMatch < numMatches; ++currMatch) { + U32 const matchIndex = matchBuffer[currMatch]; + size_t currentMl=0; + assert(matchIndex >= dmsLowestIndex); + assert(matchIndex < curr); + + { const BYTE* const match = dmsBase + matchIndex; + assert(match+4 <= dmsEnd); + if (MEM_read32(match) == MEM_read32(ip)) + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4; + } + + if (currentMl > ml) { + ml = currentMl; + assert(curr > matchIndex + dmsIndexDelta); + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); + if (ip+currentMl == iLimit) break; + } + } + } } + return ml; } +typedef size_t (*searchMax_f)( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); + +/** + * This struct contains the functions necessary for lazy to search. + * Currently, that is only searchMax. However, it is still valuable to have the + * VTable because this makes it easier to add more functions to the VTable later. + * + * TODO: The start of the search function involves loading and calculating a + * bunch of constants from the ZSTD_matchState_t. These computations could be + * done in an initialization function, and saved somewhere in the match state. + * Then we could pass a pointer to the saved state instead of the match state, + * and avoid duplicate computations. + * + * TODO: Move the match re-winding into searchMax. This improves compression + * ratio, and unlocks further simplifications with the next TODO. + * + * TODO: Try moving the repcode search into searchMax. After the re-winding + * and repcode search are in searchMax, there is no more logic in the match + * finder loop that requires knowledge about the dictMode. So we should be + * able to avoid force inlining it, and we can join the extDict loop with + * the single segment loop. It should go in searchMax instead of its own + * function to avoid having multiple virtual function calls per search. + */ +typedef struct { + searchMax_f searchMax; +} ZSTD_LazyVTable; + +#define GEN_ZSTD_BT_VTABLE(dictMode, mls) \ + static size_t ZSTD_BtFindBestMatch_##dictMode##_##mls( \ + ZSTD_matchState_t* ms, \ + const BYTE* ip, const BYTE* const iLimit, \ + size_t* offBasePtr) \ + { \ + assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + return ZSTD_BtFindBestMatch(ms, ip, iLimit, offBasePtr, mls, ZSTD_##dictMode);\ + } \ + static const ZSTD_LazyVTable ZSTD_BtVTable_##dictMode##_##mls = { \ + ZSTD_BtFindBestMatch_##dictMode##_##mls \ + }; + +#define GEN_ZSTD_HC_VTABLE(dictMode, mls) \ + static size_t ZSTD_HcFindBestMatch_##dictMode##_##mls( \ + ZSTD_matchState_t* ms, \ + const BYTE* ip, const BYTE* const iLimit, \ + size_t* offsetPtr) \ + { \ + assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + return ZSTD_HcFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode); \ + } \ + static const ZSTD_LazyVTable ZSTD_HcVTable_##dictMode##_##mls = { \ + ZSTD_HcFindBestMatch_##dictMode##_##mls \ + }; + +#define GEN_ZSTD_ROW_VTABLE(dictMode, mls, rowLog) \ + static size_t ZSTD_RowFindBestMatch_##dictMode##_##mls##_##rowLog( \ + ZSTD_matchState_t* ms, \ + const BYTE* ip, const BYTE* const iLimit, \ + size_t* offsetPtr) \ + { \ + assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + assert(MAX(4, MIN(6, ms->cParams.searchLog)) == rowLog); \ + return ZSTD_RowFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode, rowLog); \ + } \ + static const ZSTD_LazyVTable ZSTD_RowVTable_##dictMode##_##mls##_##rowLog = { \ + ZSTD_RowFindBestMatch_##dictMode##_##mls##_##rowLog \ + }; + +#define ZSTD_FOR_EACH_ROWLOG(X, dictMode, mls) \ + X(dictMode, mls, 4) \ + X(dictMode, mls, 5) \ + X(dictMode, mls, 6) + +#define ZSTD_FOR_EACH_MLS_ROWLOG(X, dictMode) \ + ZSTD_FOR_EACH_ROWLOG(X, dictMode, 4) \ + ZSTD_FOR_EACH_ROWLOG(X, dictMode, 5) \ + ZSTD_FOR_EACH_ROWLOG(X, dictMode, 6) + +#define ZSTD_FOR_EACH_MLS(X, dictMode) \ + X(dictMode, 4) \ + X(dictMode, 5) \ + X(dictMode, 6) + +#define ZSTD_FOR_EACH_DICT_MODE(X, ...) \ + X(__VA_ARGS__, noDict) \ + X(__VA_ARGS__, extDict) \ + X(__VA_ARGS__, dictMatchState) \ + X(__VA_ARGS__, dedicatedDictSearch) + +/* Generate Row VTables for each combination of (dictMode, mls, rowLog) */ +ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS_ROWLOG, GEN_ZSTD_ROW_VTABLE) +/* Generate Binary Tree VTables for each combination of (dictMode, mls) */ +ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_BT_VTABLE) +/* Generate Hash Chain VTables for each combination of (dictMode, mls) */ +ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_HC_VTABLE) + +#define GEN_ZSTD_BT_VTABLE_ARRAY(dictMode) \ + { \ + &ZSTD_BtVTable_##dictMode##_4, \ + &ZSTD_BtVTable_##dictMode##_5, \ + &ZSTD_BtVTable_##dictMode##_6 \ + } + +#define GEN_ZSTD_HC_VTABLE_ARRAY(dictMode) \ + { \ + &ZSTD_HcVTable_##dictMode##_4, \ + &ZSTD_HcVTable_##dictMode##_5, \ + &ZSTD_HcVTable_##dictMode##_6 \ + } + +#define GEN_ZSTD_ROW_VTABLE_ARRAY_(dictMode, mls) \ + { \ + &ZSTD_RowVTable_##dictMode##_##mls##_4, \ + &ZSTD_RowVTable_##dictMode##_##mls##_5, \ + &ZSTD_RowVTable_##dictMode##_##mls##_6 \ + } + +#define GEN_ZSTD_ROW_VTABLE_ARRAY(dictMode) \ + { \ + GEN_ZSTD_ROW_VTABLE_ARRAY_(dictMode, 4), \ + GEN_ZSTD_ROW_VTABLE_ARRAY_(dictMode, 5), \ + GEN_ZSTD_ROW_VTABLE_ARRAY_(dictMode, 6) \ + } + +#define GEN_ZSTD_VTABLE_ARRAY(X) \ + { \ + X(noDict), \ + X(extDict), \ + X(dictMatchState), \ + X(dedicatedDictSearch) \ + } + /* ******************************* * Common parser - lazy strategy *********************************/ -typedef enum { search_hashChain, search_binaryTree } searchMethod_e; +typedef enum { search_hashChain=0, search_binaryTree=1, search_rowHash=2 } searchMethod_e; + +/** + * This table is indexed first by the four ZSTD_dictMode_e values, and then + * by the two searchMethod_e values. NULLs are placed for configurations + * that should never occur (extDict modes go to the other implementation + * below and there is no DDSS for binary tree search yet). + */ + +static ZSTD_LazyVTable const* +ZSTD_selectLazyVTable(ZSTD_matchState_t const* ms, searchMethod_e searchMethod, ZSTD_dictMode_e dictMode) +{ + /* Fill the Hc/Bt VTable arrays with the right functions for the (dictMode, mls) combination. */ + ZSTD_LazyVTable const* const hcVTables[4][3] = GEN_ZSTD_VTABLE_ARRAY(GEN_ZSTD_HC_VTABLE_ARRAY); + ZSTD_LazyVTable const* const btVTables[4][3] = GEN_ZSTD_VTABLE_ARRAY(GEN_ZSTD_BT_VTABLE_ARRAY); + /* Fill the Row VTable array with the right functions for the (dictMode, mls, rowLog) combination. */ + ZSTD_LazyVTable const* const rowVTables[4][3][3] = GEN_ZSTD_VTABLE_ARRAY(GEN_ZSTD_ROW_VTABLE_ARRAY); + + U32 const mls = MAX(4, MIN(6, ms->cParams.minMatch)); + U32 const rowLog = MAX(4, MIN(6, ms->cParams.searchLog)); + switch (searchMethod) { + case search_hashChain: + return hcVTables[dictMode][mls - 4]; + case search_binaryTree: + return btVTables[dictMode][mls - 4]; + case search_rowHash: + return rowVTables[dictMode][mls - 4][rowLog - 4]; + default: + return NULL; + } +} FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_lazy_generic( @@ -633,59 +1495,70 @@ ZSTD_compressBlock_lazy_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - 8; + const BYTE* const ilimit = (searchMethod == search_rowHash) ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; const BYTE* const base = ms->window.base; const U32 prefixLowestIndex = ms->window.dictLimit; const BYTE* const prefixLowest = base + prefixLowestIndex; - typedef size_t (*searchMax_f)( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); - searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ? - (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS - : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) : - (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS - : ZSTD_HcFindBestMatch_selectMLS); - U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0; + searchMax_f const searchMax = ZSTD_selectLazyVTable(ms, searchMethod, dictMode)->searchMax; + U32 offset_1 = rep[0], offset_2 = rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + const int isDMS = dictMode == ZSTD_dictMatchState; + const int isDDS = dictMode == ZSTD_dedicatedDictSearch; + const int isDxS = isDMS || isDDS; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ? - dms->window.dictLimit : 0; - const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? - dms->window.base : NULL; - const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ? - dictBase + dictLowestIndex : NULL; - const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? - dms->window.nextSrc : NULL; - const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? + const U32 dictLowestIndex = isDxS ? dms->window.dictLimit : 0; + const BYTE* const dictBase = isDxS ? dms->window.base : NULL; + const BYTE* const dictLowest = isDxS ? dictBase + dictLowestIndex : NULL; + const BYTE* const dictEnd = isDxS ? dms->window.nextSrc : NULL; + const U32 dictIndexDelta = isDxS ? prefixLowestIndex - (U32)(dictEnd - dictBase) : 0; - const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictLowest); + const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest)); - /* init */ + assert(searchMax != NULL); + + DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u) (searchFunc=%u)", (U32)dictMode, (U32)searchMethod); ip += (dictAndPrefixLength == 0); if (dictMode == ZSTD_noDict) { - U32 const maxRep = (U32)(ip - prefixLowest); - if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0; - if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0; + U32 const curr = (U32)(ip - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, ms->cParams.windowLog); + U32 const maxRep = curr - windowLow; + if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; } - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); } + if (searchMethod == search_rowHash) { + const U32 rowLog = MAX(4, MIN(6, ms->cParams.searchLog)); + ZSTD_row_fillHashCache(ms, base, rowLog, + MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */), + ms->nextToUpdate, ilimit); + } + /* Match Loop */ +#if defined(__GNUC__) && defined(__x86_64__) + /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the + * code alignment is perturbed. To fix the instability align the loop on 32-bytes. + */ + __asm__(".p2align 5"); +#endif while (ip < ilimit) { size_t matchLength=0; - size_t offset=0; + size_t offBase = REPCODE1_TO_OFFBASE; const BYTE* start=ip+1; + DEBUGLOG(7, "search baseline (depth 0)"); /* check repCode */ - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { const U32 repIndex = (U32)(ip - base) + 1 - offset_1; - const BYTE* repMatch = (dictMode == ZSTD_dictMatchState + const BYTE* repMatch = ((dictMode == ZSTD_dictMatchState || dictMode == ZSTD_dedicatedDictSearch) && repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; @@ -703,10 +1576,10 @@ ZSTD_compressBlock_lazy_generic( } /* first search (depth 0) */ - { size_t offsetFound = 999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); + { size_t offbaseFound = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offbaseFound); if (ml2 > matchLength) - matchLength = ml2, start = ip, offset=offsetFound; + matchLength = ml2, start = ip, offBase = offbaseFound; } if (matchLength < 4) { @@ -717,16 +1590,17 @@ ZSTD_compressBlock_lazy_generic( /* let's try to find a better solution */ if (depth>=1) while (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offBase) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -736,32 +1610,33 @@ ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } } - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); + { size_t ofbCandidate=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &ofbCandidate); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offBase) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -771,64 +1646,62 @@ ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } } - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); + { size_t ofbCandidate=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &ofbCandidate); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* NOTE: - * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior. - * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which - * overflows the pointer, which is undefined behavior. + * Pay attention that `start[-value]` can lead to strange undefined behavior + * notably if `value` is unsigned, resulting in a large positive `-value`. */ /* catch up */ - if (offset) { + if (OFFBASE_IS_OFFSET(offBase)) { if (dictMode == ZSTD_noDict) { - while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest)) - && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */ + while ( ((start > anchor) & (start - OFFBASE_TO_OFFSET(offBase) > prefixLowest)) + && (start[-1] == (start-OFFBASE_TO_OFFSET(offBase))[-1]) ) /* only search for offset within prefix */ { start--; matchLength++; } } - if (dictMode == ZSTD_dictMatchState) { - U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); + if (isDxS) { + U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex; const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ } - offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); + offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); } /* store sequence */ _storeSequence: - { size_t const litLength = start - anchor; - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); + { size_t const litLength = (size_t)(start - anchor); + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); anchor = ip = start + matchLength; } /* check immediate repcode */ - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { while (ip <= ilimit) { U32 const current2 = (U32)(ip-base); U32 const repIndex = current2 - offset_2; - const BYTE* repMatch = dictMode == ZSTD_dictMatchState - && repIndex < prefixLowestIndex ? + const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase - dictIndexDelta + repIndex : base + repIndex; if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */) && (MEM_read32(repMatch) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4; - offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); + offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); ip += matchLength; anchor = ip; continue; @@ -842,16 +1715,20 @@ ZSTD_compressBlock_lazy_generic( && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); + offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap repcodes */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ } } } - /* Save reps for next block */ - rep[0] = offset_1 ? offset_1 : savedOffset; - rep[1] = offset_2 ? offset_2 : savedOffset; + /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), + * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ + offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; + + /* save reps for next block */ + rep[0] = offset_1 ? offset_1 : offsetSaved1; + rep[1] = offset_2 ? offset_2 : offsetSaved2; /* Return the last literals size */ return (size_t)(iend - anchor); @@ -915,6 +1792,92 @@ size_t ZSTD_compressBlock_greedy_dictMatchState( } +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dedicatedDictSearch); +} + +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dedicatedDictSearch); +} + +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dedicatedDictSearch); +} + +/* Row-based matchfinder */ +size_t ZSTD_compressBlock_lazy2_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict); +} + +size_t ZSTD_compressBlock_lazy_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict); +} + +size_t ZSTD_compressBlock_greedy_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_noDict); +} + +size_t ZSTD_compressBlock_lazy2_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState); +} + +size_t ZSTD_compressBlock_lazy_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dictMatchState); +} + +size_t ZSTD_compressBlock_greedy_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState); +} + + +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dedicatedDictSearch); +} + +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch); +} + +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch); +} + FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_lazy_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, @@ -926,37 +1889,49 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - 8; + const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; const BYTE* const base = ms->window.base; const U32 dictLimit = ms->window.dictLimit; - const U32 lowestIndex = ms->window.lowLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictBase = ms->window.dictBase; const BYTE* const dictEnd = dictBase + dictLimit; - const BYTE* const dictStart = dictBase + lowestIndex; - - typedef size_t (*searchMax_f)( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); - searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS; + const BYTE* const dictStart = dictBase + ms->window.lowLimit; + const U32 windowLog = ms->cParams.windowLog; + const U32 rowLog = ms->cParams.searchLog < 5 ? 4 : 5; + searchMax_f const searchMax = ZSTD_selectLazyVTable(ms, searchMethod, ZSTD_extDict)->searchMax; U32 offset_1 = rep[0], offset_2 = rep[1]; + DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic (searchFunc=%u)", (U32)searchMethod); + /* init */ ip += (ip == prefixStart); + if (searchMethod == search_rowHash) { + ZSTD_row_fillHashCache(ms, base, rowLog, + MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */), + ms->nextToUpdate, ilimit); + } /* Match Loop */ +#if defined(__GNUC__) && defined(__x86_64__) + /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the + * code alignment is perturbed. To fix the instability align the loop on 32-bytes. + */ + __asm__(".p2align 5"); +#endif while (ip < ilimit) { size_t matchLength=0; - size_t offset=0; + size_t offBase = REPCODE1_TO_OFFBASE; const BYTE* start=ip+1; - U32 current = (U32)(ip-base); + U32 curr = (U32)(ip-base); /* check repCode */ - { const U32 repIndex = (U32)(current+1 - offset_1); + { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr+1, windowLog); + const U32 repIndex = (U32)(curr+1 - offset_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + & (offset_1 <= curr+1 - windowLow) ) /* note: we are searching at curr+1 */ if (MEM_read32(ip+1) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; @@ -965,13 +1940,13 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( } } /* first search (depth 0) */ - { size_t offsetFound = 999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); + { size_t ofbCandidate = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &ofbCandidate); if (ml2 > matchLength) - matchLength = ml2, start = ip, offset=offsetFound; + matchLength = ml2, start = ip, offBase = ofbCandidate; } - if (matchLength < 4) { + if (matchLength < 4) { ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */ continue; } @@ -980,93 +1955,100 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( if (depth>=1) while (ip= 3) & (repIndex > lowestIndex)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ + & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offset = 0, start = ip; + matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; } } /* search match, depth 1 */ - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); + { size_t ofbCandidate = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &ofbCandidate); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip= 3) & (repIndex > lowestIndex)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ + & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offset = 0, start = ip; + matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; } } /* search match, depth 2 */ - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); + { size_t ofbCandidate = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &ofbCandidate); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* catch up */ - if (offset) { - U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); + if (OFFBASE_IS_OFFSET(offBase)) { + U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex; const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ - offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); + offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); } /* store sequence */ _storeSequence: - { size_t const litLength = start - anchor; - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); + { size_t const litLength = (size_t)(start - anchor); + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); anchor = ip = start + matchLength; } /* check immediate repcode */ while (ip <= ilimit) { - const U32 repIndex = (U32)((ip-base) - offset_2); + const U32 repCurrent = (U32)(ip-base); + const U32 windowLow = ZSTD_getLowestMatchIndex(ms, repCurrent, windowLog); + const U32 repIndex = repCurrent - offset_2; const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ + & (offset_2 <= repCurrent - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; - offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); + offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset history */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ @@ -1113,3 +2095,26 @@ size_t ZSTD_compressBlock_btlazy2_extDict( { return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2); } + +size_t ZSTD_compressBlock_greedy_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0); +} + +size_t ZSTD_compressBlock_lazy_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) + +{ + return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1); +} + +size_t ZSTD_compressBlock_lazy2_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) + +{ + return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2); +} diff --git a/native/zstd/compress/zstd_lazy.h b/native/zstd/compress/zstd_lazy.h old mode 100755 new mode 100644 index bb17630..150f7b3 --- a/native/zstd/compress/zstd_lazy.h +++ b/native/zstd/compress/zstd_lazy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,7 +17,18 @@ extern "C" { #include "zstd_compress_internal.h" +/** + * Dedicated Dictionary Search Structure bucket log. In the + * ZSTD_dedicatedDictSearch mode, the hashTable has + * 2 ** ZSTD_LAZY_DDSS_BUCKET_LOG entries in each bucket, rather than just + * one. + */ +#define ZSTD_LAZY_DDSS_BUCKET_LOG 2 + U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip); +void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip); + +void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip); void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */ @@ -33,6 +44,15 @@ size_t ZSTD_compressBlock_lazy( size_t ZSTD_compressBlock_greedy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); size_t ZSTD_compressBlock_btlazy2_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -46,6 +66,34 @@ size_t ZSTD_compressBlock_lazy_dictMatchState( size_t ZSTD_compressBlock_greedy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); + +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); size_t ZSTD_compressBlock_greedy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -56,9 +104,19 @@ size_t ZSTD_compressBlock_lazy_extDict( size_t ZSTD_compressBlock_lazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); size_t ZSTD_compressBlock_btlazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); + #if defined (__cplusplus) } diff --git a/native/zstd/compress/zstd_ldm.c b/native/zstd/compress/zstd_ldm.c old mode 100755 new mode 100644 index c3312ad..c14c624 --- a/native/zstd/compress/zstd_ldm.c +++ b/native/zstd/compress/zstd_ldm.c @@ -1,22 +1,136 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * 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. */ #include "zstd_ldm.h" -#include "debug.h" +#include "../common/debug.h" +#include "../common/xxhash.h" #include "zstd_fast.h" /* ZSTD_fillHashTable() */ #include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */ +#include "zstd_ldm_geartab.h" #define LDM_BUCKET_SIZE_LOG 3 #define LDM_MIN_MATCH_LENGTH 64 #define LDM_HASH_RLOG 7 -#define LDM_HASH_CHAR_OFFSET 10 + +typedef struct { + U64 rolling; + U64 stopMask; +} ldmRollingHashState_t; + +/** ZSTD_ldm_gear_init(): + * + * Initializes the rolling hash state such that it will honor the + * settings in params. */ +static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params) +{ + unsigned maxBitsInMask = MIN(params->minMatchLength, 64); + unsigned hashRateLog = params->hashRateLog; + + state->rolling = ~(U32)0; + + /* The choice of the splitting criterion is subject to two conditions: + * 1. it has to trigger on average every 2^(hashRateLog) bytes; + * 2. ideally, it has to depend on a window of minMatchLength bytes. + * + * In the gear hash algorithm, bit n depends on the last n bytes; + * so in order to obtain a good quality splitting criterion it is + * preferable to use bits with high weight. + * + * To match condition 1 we use a mask with hashRateLog bits set + * and, because of the previous remark, we make sure these bits + * have the highest possible weight while still respecting + * condition 2. + */ + if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) { + state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog); + } else { + /* In this degenerate case we simply honor the hash rate. */ + state->stopMask = ((U64)1 << hashRateLog) - 1; + } +} + +/** ZSTD_ldm_gear_reset() + * Feeds [data, data + minMatchLength) into the hash without registering any + * splits. This effectively resets the hash state. This is used when skipping + * over data, either at the beginning of a block, or skipping sections. + */ +static void ZSTD_ldm_gear_reset(ldmRollingHashState_t* state, + BYTE const* data, size_t minMatchLength) +{ + U64 hash = state->rolling; + size_t n = 0; + +#define GEAR_ITER_ONCE() do { \ + hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ + n += 1; \ + } while (0) + while (n + 3 < minMatchLength) { + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + } + while (n < minMatchLength) { + GEAR_ITER_ONCE(); + } +#undef GEAR_ITER_ONCE +} + +/** ZSTD_ldm_gear_feed(): + * + * Registers in the splits array all the split points found in the first + * size bytes following the data pointer. This function terminates when + * either all the data has been processed or LDM_BATCH_SIZE splits are + * present in the splits array. + * + * Precondition: The splits array must not be full. + * Returns: The number of bytes processed. */ +static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state, + BYTE const* data, size_t size, + size_t* splits, unsigned* numSplits) +{ + size_t n; + U64 hash, mask; + + hash = state->rolling; + mask = state->stopMask; + n = 0; + +#define GEAR_ITER_ONCE() do { \ + hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ + n += 1; \ + if (UNLIKELY((hash & mask) == 0)) { \ + splits[*numSplits] = n; \ + *numSplits += 1; \ + if (*numSplits == LDM_BATCH_SIZE) \ + goto done; \ + } \ + } while (0) + + while (n + 3 < size) { + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + } + while (n < size) { + GEAR_ITER_ONCE(); + } + +#undef GEAR_ITER_ONCE + +done: + state->rolling = hash; + return n; +} void ZSTD_ldm_adjustParameters(ldmParams_t* params, ZSTD_compressionParameters const* cParams) @@ -26,13 +140,6 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, DEBUGLOG(4, "ZSTD_ldm_adjustParameters"); if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH; - if (cParams->strategy >= ZSTD_btopt) { - /* Get out of the way of the optimal parser */ - U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength); - assert(minMatch >= ZSTD_LDM_MINMATCH_MIN); - assert(minMatch <= ZSTD_LDM_MINMATCH_MAX); - params->minMatchLength = minMatch; - } if (params->hashLog == 0) { params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG); assert(params->hashLog <= ZSTD_HASHLOG_MAX); @@ -52,47 +159,12 @@ size_t ZSTD_ldm_getTableSize(ldmParams_t params) size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog); size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize) + ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t)); - return params.enableLdm ? totalSize : 0; + return params.enableLdm == ZSTD_ps_enable ? totalSize : 0; } size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize) { - return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0; -} - -/** ZSTD_ldm_getSmallHash() : - * numBits should be <= 32 - * If numBits==0, returns 0. - * @return : the most significant numBits of value. */ -static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) -{ - assert(numBits <= 32); - return numBits == 0 ? 0 : (U32)(value >> (64 - numBits)); -} - -/** ZSTD_ldm_getChecksum() : - * numBitsToDiscard should be <= 32 - * @return : the next most significant 32 bits after numBitsToDiscard */ -static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) -{ - assert(numBitsToDiscard <= 32); - return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; -} - -/** ZSTD_ldm_getTag() ; - * Given the hash, returns the most significant numTagBits bits - * after (32 + hbits) bits. - * - * If there are not enough bits remaining, return the last - * numTagBits bits. */ -static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) -{ - assert(numTagBits < 32 && hbits <= 32); - if (32 - hbits < numTagBits) { - return hash & (((U32)1 << numTagBits) - 1); - } else { - return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1); - } + return params.enableLdm == ZSTD_ps_enable ? (maxChunkSize / params.minMatchLength) : 0; } /** ZSTD_ldm_getBucket() : @@ -109,38 +181,12 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, size_t const hash, const ldmEntry_t entry, ldmParams_t const ldmParams) { - BYTE* const bucketOffsets = ldmState->bucketOffsets; - *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; - bucketOffsets[hash]++; - bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1; -} + BYTE* const pOffset = ldmState->bucketOffsets + hash; + unsigned const offset = *pOffset; + + *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry; + *pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1)); -/** ZSTD_ldm_makeEntryAndInsertByTag() : - * - * Gets the small hash, checksum, and tag from the rollingHash. - * - * If the tag matches (1 << ldmParams.hashRateLog)-1, then - * creates an ldmEntry from the offset, and inserts it into the hash table. - * - * hBits is the length of the small hash, which is the most significant hBits - * of rollingHash. The checksum is the next 32 most significant bits, followed - * by ldmParams.hashRateLog bits that make up the tag. */ -static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, - U64 const rollingHash, - U32 const hBits, - U32 const offset, - ldmParams_t const ldmParams) -{ - U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog); - U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1; - if (tag == tagMask) { - U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); - U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); - ldmEntry_t entry; - entry.offset = offset; - entry.checksum = checksum; - ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams); - } } /** ZSTD_ldm_countBackwardsMatch() : @@ -149,10 +195,10 @@ static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ static size_t ZSTD_ldm_countBackwardsMatch( const BYTE* pIn, const BYTE* pAnchor, - const BYTE* pMatch, const BYTE* pBase) + const BYTE* pMatch, const BYTE* pMatchBase) { size_t matchLength = 0; - while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { + while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) { pIn--; pMatch--; matchLength++; @@ -160,6 +206,27 @@ static size_t ZSTD_ldm_countBackwardsMatch( return matchLength; } +/** ZSTD_ldm_countBackwardsMatch_2segments() : + * Returns the number of bytes that match backwards from pMatch, + * even with the backwards match spanning 2 different segments. + * + * On reaching `pMatchBase`, start counting from mEnd */ +static size_t ZSTD_ldm_countBackwardsMatch_2segments( + const BYTE* pIn, const BYTE* pAnchor, + const BYTE* pMatch, const BYTE* pMatchBase, + const BYTE* pExtDictStart, const BYTE* pExtDictEnd) +{ + size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase); + if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) { + /* If backwards match is entirely in the extDict or prefix, immediately return */ + return matchLength; + } + DEBUGLOG(7, "ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength); + matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart); + DEBUGLOG(7, "final backwards match length = %zu", matchLength); + return matchLength; +} + /** ZSTD_ldm_fillFastTables() : * * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. @@ -175,11 +242,11 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, switch(ms->cParams.strategy) { case ZSTD_fast: - ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast); + ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); break; case ZSTD_dfast: - ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast); + ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); break; case ZSTD_greedy: @@ -197,30 +264,43 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, return 0; } -/** ZSTD_ldm_fillLdmHashTable() : - * - * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). - * lastHash is the rolling hash that corresponds to lastHashed. - * - * Returns the rolling hash corresponding to position iend-1. */ -static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, - U64 lastHash, const BYTE* lastHashed, - const BYTE* iend, const BYTE* base, - U32 hBits, ldmParams_t const ldmParams) +void ZSTD_ldm_fillHashTable( + ldmState_t* ldmState, const BYTE* ip, + const BYTE* iend, ldmParams_t const* params) { - U64 rollingHash = lastHash; - const BYTE* cur = lastHashed + 1; - - while (cur < iend) { - rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1], - cur[ldmParams.minMatchLength-1], - state->hashPower); - ZSTD_ldm_makeEntryAndInsertByTag(state, - rollingHash, hBits, - (U32)(cur - base), ldmParams); - ++cur; + U32 const minMatchLength = params->minMatchLength; + U32 const hBits = params->hashLog - params->bucketSizeLog; + BYTE const* const base = ldmState->window.base; + BYTE const* const istart = ip; + ldmRollingHashState_t hashState; + size_t* const splits = ldmState->splitIndices; + unsigned numSplits; + + DEBUGLOG(5, "ZSTD_ldm_fillHashTable"); + + ZSTD_ldm_gear_init(&hashState, params); + while (ip < iend) { + size_t hashed; + unsigned n; + + numSplits = 0; + hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits); + + for (n = 0; n < numSplits; n++) { + if (ip + splits[n] >= istart + minMatchLength) { + BYTE const* const split = ip + splits[n] - minMatchLength; + U64 const xxhash = XXH64(split, minMatchLength, 0); + U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); + ldmEntry_t entry; + + entry.offset = (U32)(split - base); + entry.checksum = (U32)(xxhash >> 32); + ZSTD_ldm_insertEntry(ldmState, hash, entry, *params); + } + } + + ip += hashed; } - return rollingHash; } @@ -231,10 +311,10 @@ static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, * (after a long match, only update tables a limited amount). */ static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor) { - U32 const current = (U32)(anchor - ms->window.base); - if (current > ms->nextToUpdate + 1024) { + U32 const curr = (U32)(anchor - ms->window.base); + if (curr > ms->nextToUpdate + 1024) { ms->nextToUpdate = - current - MIN(512, current - ms->nextToUpdate - 1024); + curr - MIN(512, curr - ms->nextToUpdate - 1024); } } @@ -245,11 +325,8 @@ static size_t ZSTD_ldm_generateSequences_internal( /* LDM parameters */ int const extDict = ZSTD_window_hasExtDict(ldmState->window); U32 const minMatchLength = params->minMatchLength; - U64 const hashPower = ldmState->hashPower; + U32 const entsPerBucket = 1U << params->bucketSizeLog; U32 const hBits = params->hashLog - params->bucketSizeLog; - U32 const ldmBucketSize = 1U << params->bucketSizeLog; - U32 const hashRateLog = params->hashRateLog; - U32 const ldmTagMask = (1U << params->hashRateLog) - 1; /* Prefix and extDict parameters */ U32 const dictLimit = ldmState->window.dictLimit; U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit; @@ -261,45 +338,69 @@ static size_t ZSTD_ldm_generateSequences_internal( /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; - BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE); + BYTE const* const ilimit = iend - HASH_READ_SIZE; /* Input positions */ BYTE const* anchor = istart; BYTE const* ip = istart; - /* Rolling hash */ - BYTE const* lastHashed = NULL; - U64 rollingHash = 0; - - while (ip <= ilimit) { - size_t mLength; - U32 const current = (U32)(ip - base); - size_t forwardMatchLength = 0, backwardMatchLength = 0; - ldmEntry_t* bestEntry = NULL; - if (ip != istart) { - rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0], - lastHashed[minMatchLength], - hashPower); - } else { - rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength); + /* Rolling hash state */ + ldmRollingHashState_t hashState; + /* Arrays for staged-processing */ + size_t* const splits = ldmState->splitIndices; + ldmMatchCandidate_t* const candidates = ldmState->matchCandidates; + unsigned numSplits; + + if (srcSize < minMatchLength) + return iend - anchor; + + /* Initialize the rolling hash state with the first minMatchLength bytes */ + ZSTD_ldm_gear_init(&hashState, params); + ZSTD_ldm_gear_reset(&hashState, ip, minMatchLength); + ip += minMatchLength; + + while (ip < ilimit) { + size_t hashed; + unsigned n; + + numSplits = 0; + hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip, + splits, &numSplits); + + for (n = 0; n < numSplits; n++) { + BYTE const* const split = ip + splits[n] - minMatchLength; + U64 const xxhash = XXH64(split, minMatchLength, 0); + U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); + + candidates[n].split = split; + candidates[n].hash = hash; + candidates[n].checksum = (U32)(xxhash >> 32); + candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params); + PREFETCH_L1(candidates[n].bucket); } - lastHashed = ip; - /* Do not insert and do not look for a match */ - if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) { - ip++; - continue; - } + for (n = 0; n < numSplits; n++) { + size_t forwardMatchLength = 0, backwardMatchLength = 0, + bestMatchLength = 0, mLength; + U32 offset; + BYTE const* const split = candidates[n].split; + U32 const checksum = candidates[n].checksum; + U32 const hash = candidates[n].hash; + ldmEntry_t* const bucket = candidates[n].bucket; + ldmEntry_t const* cur; + ldmEntry_t const* bestEntry = NULL; + ldmEntry_t newEntry; + + newEntry.offset = (U32)(split - base); + newEntry.checksum = checksum; + + /* If a split point would generate a sequence overlapping with + * the previous one, we merely register it in the hash table and + * move on */ + if (split < anchor) { + ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); + continue; + } - /* Get the best entry and compute the match lengths */ - { - ldmEntry_t* const bucket = - ZSTD_ldm_getBucket(ldmState, - ZSTD_ldm_getSmallHash(rollingHash, hBits), - *params); - ldmEntry_t* cur; - size_t bestMatchLength = 0; - U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); - - for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { + for (cur = bucket; cur < bucket + entsPerBucket; cur++) { size_t curForwardMatchLength, curBackwardMatchLength, curTotalMatchLength; if (cur->checksum != checksum || cur->offset <= lowestIndex) { @@ -313,30 +414,23 @@ static size_t ZSTD_ldm_generateSequences_internal( cur->offset < dictLimit ? dictEnd : iend; BYTE const* const lowMatchPtr = cur->offset < dictLimit ? dictStart : lowPrefixPtr; - - curForwardMatchLength = ZSTD_count_2segments( - ip, pMatch, iend, - matchEnd, lowPrefixPtr); + curForwardMatchLength = + ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr); if (curForwardMatchLength < minMatchLength) { continue; } - curBackwardMatchLength = - ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, - lowMatchPtr); - curTotalMatchLength = curForwardMatchLength + - curBackwardMatchLength; + curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments( + split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd); } else { /* !extDict */ BYTE const* const pMatch = base + cur->offset; - curForwardMatchLength = ZSTD_count(ip, pMatch, iend); + curForwardMatchLength = ZSTD_count(split, pMatch, iend); if (curForwardMatchLength < minMatchLength) { continue; } curBackwardMatchLength = - ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, - lowPrefixPtr); - curTotalMatchLength = curForwardMatchLength + - curBackwardMatchLength; + ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr); } + curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength; if (curTotalMatchLength > bestMatchLength) { bestMatchLength = curTotalMatchLength; @@ -345,57 +439,54 @@ static size_t ZSTD_ldm_generateSequences_internal( bestEntry = cur; } } - } - - /* No match found -- continue searching */ - if (bestEntry == NULL) { - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, - hBits, current, - *params); - ip++; - continue; - } - /* Match found */ - mLength = forwardMatchLength + backwardMatchLength; - ip -= backwardMatchLength; + /* No match found -- insert an entry into the hash table + * and process the next candidate match */ + if (bestEntry == NULL) { + ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); + continue; + } - { - /* Store the sequence: - * ip = current - backwardMatchLength - * The match is at (bestEntry->offset - backwardMatchLength) - */ - U32 const matchIndex = bestEntry->offset; - U32 const offset = current - matchIndex; - rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; - - /* Out of sequence storage */ - if (rawSeqStore->size == rawSeqStore->capacity) - return ERROR(dstSize_tooSmall); - seq->litLength = (U32)(ip - anchor); - seq->matchLength = (U32)mLength; - seq->offset = offset; - rawSeqStore->size++; - } + /* Match found */ + offset = (U32)(split - base) - bestEntry->offset; + mLength = forwardMatchLength + backwardMatchLength; + { + rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; + + /* Out of sequence storage */ + if (rawSeqStore->size == rawSeqStore->capacity) + return ERROR(dstSize_tooSmall); + seq->litLength = (U32)(split - backwardMatchLength - anchor); + seq->matchLength = (U32)mLength; + seq->offset = offset; + rawSeqStore->size++; + } - /* Insert the current entry into the hash table */ - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, - (U32)(lastHashed - base), - *params); + /* Insert the current entry into the hash table --- it must be + * done after the previous block to avoid clobbering bestEntry */ + ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); - assert(ip + backwardMatchLength == lastHashed); + anchor = split + forwardMatchLength; - /* Fill the hash table from lastHashed+1 to ip+mLength*/ - /* Heuristic: don't need to fill the entire table at end of block */ - if (ip + mLength <= ilimit) { - rollingHash = ZSTD_ldm_fillLdmHashTable( - ldmState, rollingHash, lastHashed, - ip + mLength, base, hBits, *params); - lastHashed = ip + mLength - 1; + /* If we find a match that ends after the data that we've hashed + * then we have a repeating, overlapping, pattern. E.g. all zeros. + * If one repetition of the pattern matches our `stopMask` then all + * repetitions will. We don't need to insert them all into out table, + * only the first one. So skip over overlapping matches. + * This is a major speed boost (20x) for compressing a single byte + * repeated, when that byte ends up in the table. + */ + if (anchor > ip + hashed) { + ZSTD_ldm_gear_reset(&hashState, anchor - minMatchLength, minMatchLength); + /* Continue the outer loop at anchor (ip + hashed == anchor). */ + ip = anchor - hashed; + break; + } } - ip += mLength; - anchor = ip; + + ip += hashed; } + return iend - anchor; } @@ -444,11 +535,13 @@ size_t ZSTD_ldm_generateSequences( assert(chunkStart < iend); /* 1. Perform overflow correction if necessary. */ - if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) { + if (ZSTD_window_needOverflowCorrection(ldmState->window, 0, maxDist, ldmState->loadedDictEnd, chunkStart, chunkEnd)) { U32 const ldmHSize = 1U << params->hashLog; U32 const correction = ZSTD_window_correctOverflow( &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart); ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction); + /* invalidate dictionaries on overflow correction */ + ldmState->loadedDictEnd = 0; } /* 2. We enforce the maximum offset allowed. * @@ -456,9 +549,15 @@ size_t ZSTD_ldm_generateSequences( * the window through early invalidation. * TODO: * Test the chunk size. * * Try invalidation after the sequence generation and test the - * the offset against maxDist directly. + * offset against maxDist directly. + * + * NOTE: Because of dictionaries + sequence splitting we MUST make sure + * that any offset used is valid at the END of the sequence, since it may + * be split into two sequences. This condition holds when using + * ZSTD_window_enforceMaxDist(), but if we move to checking offsets + * against maxDist directly, we'll have to carefully handle that case. */ - ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL, NULL); + ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, &ldmState->loadedDictEnd, NULL); /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */ newLeftoverSize = ZSTD_ldm_generateSequences_internal( ldmState, sequences, params, chunkStart, chunkSize); @@ -480,7 +579,9 @@ size_t ZSTD_ldm_generateSequences( return 0; } -void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) { +void +ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) +{ while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) { rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos; if (srcSize <= seq->litLength) { @@ -539,14 +640,32 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore, return sequence; } +void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) { + U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); + while (currPos && rawSeqStore->pos < rawSeqStore->size) { + rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; + if (currPos >= currSeq.litLength + currSeq.matchLength) { + currPos -= currSeq.litLength + currSeq.matchLength; + rawSeqStore->pos++; + } else { + rawSeqStore->posInSequence = currPos; + break; + } + } + if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { + rawSeqStore->posInSequence = 0; + } +} + size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize) { const ZSTD_compressionParameters* const cParams = &ms->cParams; unsigned const minMatch = cParams->minMatch; ZSTD_blockCompressor const blockCompressor = - ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms)); + ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms)); /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; @@ -554,9 +673,18 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, BYTE const* ip = istart; DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize); + /* If using opt parser, use LDMs only as candidates rather than always accepting them */ + if (cParams->strategy >= ZSTD_btopt) { + size_t lastLLSize; + ms->ldmSeqStore = rawSeqStore; + lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize); + ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore, srcSize); + return lastLLSize; + } + assert(rawSeqStore->pos <= rawSeqStore->size); assert(rawSeqStore->size <= rawSeqStore->capacity); - /* Loop through each sequence and apply the block compressor to the lits */ + /* Loop through each sequence and apply the block compressor to the literals */ while (rawSeqStore->pos < rawSeqStore->size && ip < iend) { /* maybeSplitSequence updates rawSeqStore->pos */ rawSeq const sequence = maybeSplitSequence(rawSeqStore, @@ -566,14 +694,13 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, if (sequence.offset == 0) break; - assert(sequence.offset <= (1U << cParams->windowLog)); assert(ip + sequence.litLength + sequence.matchLength <= iend); /* Fill tables for block compressor */ ZSTD_ldm_limitTableUpdate(ms, ip); ZSTD_ldm_fillFastTables(ms, ip); /* Run the block compressor */ - DEBUGLOG(5, "calling block compressor on segment of size %u", sequence.litLength); + DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength); { size_t const newLitLength = blockCompressor(ms, seqStore, rep, ip, sequence.litLength); @@ -584,8 +711,8 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, rep[0] = sequence.offset; /* Store the sequence */ ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend, - sequence.offset + ZSTD_REP_MOVE, - sequence.matchLength - MINMATCH); + OFFSET_TO_OFFBASE(sequence.offset), + sequence.matchLength); ip += sequence.matchLength; } } diff --git a/native/zstd/compress/zstd_ldm.h b/native/zstd/compress/zstd_ldm.h old mode 100755 new mode 100644 index a478461..4e68dbf --- a/native/zstd/compress/zstd_ldm.h +++ b/native/zstd/compress/zstd_ldm.h @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * 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. */ #ifndef ZSTD_LDM_H @@ -15,7 +16,7 @@ extern "C" { #endif #include "zstd_compress_internal.h" /* ldmParams_t, U32 */ -#include "zstd.h" /* ZSTD_CCtx, size_t */ +#include "../zstd.h" /* ZSTD_CCtx, size_t */ /*-************************************* * Long distance matching @@ -23,6 +24,10 @@ extern "C" { #define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT +void ZSTD_ldm_fillHashTable( + ldmState_t* state, const BYTE* ip, + const BYTE* iend, ldmParams_t const* params); + /** * ZSTD_ldm_generateSequences(): * @@ -61,6 +66,7 @@ size_t ZSTD_ldm_generateSequences( */ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize); /** @@ -68,11 +74,17 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, * * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`. * Avoids emitting matches less than `minMatch` bytes. - * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). + * Must be called for data that is not passed to ZSTD_ldm_blockCompress(). */ void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch); +/* ZSTD_ldm_skipRawSeqStoreBytes(): + * Moves forward in rawSeqStore by nbBytes, updating fields 'pos' and 'posInSequence'. + * Not to be used in conjunction with ZSTD_ldm_skipSequences(). + * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). + */ +void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes); /** ZSTD_ldm_getTableSize() : * Estimate the space needed for long distance matching tables or 0 if LDM is diff --git a/native/zstd/compress/zstd_ldm_geartab.h b/native/zstd/compress/zstd_ldm_geartab.h new file mode 100644 index 0000000..647f865 --- /dev/null +++ b/native/zstd/compress/zstd_ldm_geartab.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * 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. + */ + +#ifndef ZSTD_LDM_GEARTAB_H +#define ZSTD_LDM_GEARTAB_H + +#include "../common/compiler.h" /* UNUSED_ATTR */ +#include "../common/mem.h" /* U64 */ + +static UNUSED_ATTR const U64 ZSTD_ldm_gearTab[256] = { + 0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc, + 0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05, + 0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e, + 0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889, + 0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e, + 0x37b628620b628, 0x49a8d455d88caf5, 0x8556d711e6958140, + 0x4f7ae74fc605c1f, 0x829f0c3468bd3a20, 0x4ffdc885c625179e, + 0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f, + 0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391, + 0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210, + 0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be, + 0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a, + 0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b, + 0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4, + 0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb, + 0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312, + 0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01, + 0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc, + 0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967, + 0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553, + 0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f, + 0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2, + 0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d, + 0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a, + 0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74, + 0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3, + 0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1, + 0xff452823dbb010a, 0x9d42ed614f3dd267, 0x5b9313c06257c57b, + 0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568, + 0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a, + 0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1, + 0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9, + 0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463, + 0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba, + 0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9, + 0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61, + 0x24a5483879c453e3, 0x88026889192b4b9, 0x28da96671782dbec, + 0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6, + 0xbc135a0a704b70ba, 0x69cd868f7622ada, 0xbc37ba89e0b9c0ab, + 0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5, + 0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59, + 0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7, + 0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc, + 0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb, + 0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be, + 0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312, + 0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1, + 0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc, + 0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d, + 0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445, + 0x820d471e20b348e, 0x1874383cb83d46dc, 0x97edeec7a1efe11c, + 0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5, + 0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5, + 0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28, + 0xaf846af6ab7d0bf4, 0xe5af208eb666e49, 0x5e6622f73534cd6a, + 0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9, + 0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15, + 0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef, + 0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2, + 0x9f90e4c5fd508d8, 0xa34e5956fbaf3385, 0x2e2f8e151d3ef375, + 0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3, + 0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595, + 0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389, + 0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4, + 0x4228e364c5b5ed7, 0x9d7a3edf0da43911, 0x8edcfeda24686756, + 0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc, + 0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45, + 0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea, + 0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f, + 0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc, + 0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c, + 0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a, + 0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17, + 0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3, + 0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4, + 0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91, + 0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40, + 0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741, + 0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f, + 0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4, + 0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad, + 0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047, + 0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2, + 0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e, + 0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b, + 0x2b4da14f2613d8f4 +}; + +#endif /* ZSTD_LDM_GEARTAB_H */ diff --git a/native/zstd/compress/zstd_opt.c b/native/zstd/compress/zstd_opt.c old mode 100755 new mode 100644 index 2e50fca..800f87e --- a/native/zstd/compress/zstd_opt.c +++ b/native/zstd/compress/zstd_opt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. + * Copyright (c) Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,7 +14,6 @@ #define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */ -#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */ #define ZSTD_MAX_PRICE (1<<30) #define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ @@ -24,11 +23,11 @@ * Price functions for optimal parser ***************************************/ -#if 0 /* approximation at bit level */ +#if 0 /* approximation at bit level (for tests) */ # define BITCOST_ACCURACY 0 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat)) -#elif 0 /* fractional bit accuracy */ +# define WEIGHT(stat, opt) ((void)opt, ZSTD_bitWeight(stat)) +#elif 0 /* fractional bit accuracy (for tests) */ # define BITCOST_ACCURACY 8 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) # define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat)) @@ -66,7 +65,7 @@ MEM_STATIC double ZSTD_fCost(U32 price) static int ZSTD_compressedLiterals(optState_t const* const optPtr) { - return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed; + return optPtr->literalCompressionMode != ZSTD_ps_disable; } static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) @@ -79,25 +78,46 @@ static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) } -/* ZSTD_downscaleStat() : - * reduce all elements in table by a factor 2^(ZSTD_FREQ_DIV+malus) - * return the resulting sum of elements */ -static U32 ZSTD_downscaleStat(unsigned* table, U32 lastEltIndex, int malus) +static U32 sum_u32(const unsigned table[], size_t nbElts) +{ + size_t n; + U32 total = 0; + for (n=0; n 0 && ZSTD_FREQ_DIV+malus < 31); + DEBUGLOG(5, "ZSTD_downscaleStats (nbElts=%u, shift=%u)", (unsigned)lastEltIndex+1, (unsigned)shift); + assert(shift < 30); for (s=0; s> (ZSTD_FREQ_DIV+malus)); + table[s] = 1 + (table[s] >> shift); sum += table[s]; } return sum; } +/* ZSTD_scaleStats() : + * reduce all elements in table is sum too large + * return the resulting sum of elements */ +static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget) +{ + U32 const prevsum = sum_u32(table, lastEltIndex+1); + U32 const factor = prevsum >> logTarget; + DEBUGLOG(5, "ZSTD_scaleStats (nbElts=%u, target=%u)", (unsigned)lastEltIndex+1, (unsigned)logTarget); + assert(logTarget < 30); + if (factor <= 1) return prevsum; + return ZSTD_downscaleStats(table, lastEltIndex, ZSTD_highbit32(factor)); +} + /* ZSTD_rescaleFreqs() : * if first block (detected by optPtr->litLengthSum == 0) : init statistics * take hints from dictionary if there is one - * or init from zero, using src for literals stats, or flat 1 for match symbols + * and init from zero if there is none, + * using src for literals stats, and baseline stats for sequence symbols * otherwise downscale existing stats, to be used as seed for next block. */ static void @@ -126,7 +146,7 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, optPtr->litSum = 0; for (lit=0; lit<=MaxLit; lit++) { U32 const scaleLog = 11; /* scale to 2K */ - U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit); + U32 const bitCost = HUF_getNbBitsFromCTable(optPtr->symbolCosts->huf.CTable, lit); assert(bitCost <= scaleLog); optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; optPtr->litSum += optPtr->litFreq[lit]; @@ -174,14 +194,19 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, if (compressedLiterals) { unsigned lit = MaxLit; HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */ - optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); + optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8); } - { unsigned ll; - for (ll=0; ll<=MaxLL; ll++) - optPtr->litLengthFreq[ll] = 1; + { unsigned const baseLLfreqs[MaxLL+1] = { + 4, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 + }; + ZSTD_memcpy(optPtr->litLengthFreq, baseLLfreqs, sizeof(baseLLfreqs)); + optPtr->litLengthSum = sum_u32(baseLLfreqs, MaxLL+1); } - optPtr->litLengthSum = MaxLL+1; { unsigned ml; for (ml=0; ml<=MaxML; ml++) @@ -189,21 +214,26 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, } optPtr->matchLengthSum = MaxML+1; - { unsigned of; - for (of=0; of<=MaxOff; of++) - optPtr->offCodeFreq[of] = 1; + { unsigned const baseOFCfreqs[MaxOff+1] = { + 6, 2, 1, 1, 2, 3, 4, 4, + 4, 3, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 + }; + ZSTD_memcpy(optPtr->offCodeFreq, baseOFCfreqs, sizeof(baseOFCfreqs)); + optPtr->offCodeSum = sum_u32(baseOFCfreqs, MaxOff+1); } - optPtr->offCodeSum = MaxOff+1; + } } else { /* new block : re-use previous statistics, scaled down */ if (compressedLiterals) - optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); - optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0); - optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0); - optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0); + optPtr->litSum = ZSTD_scaleStats(optPtr->litFreq, MaxLit, 12); + optPtr->litLengthSum = ZSTD_scaleStats(optPtr->litLengthFreq, MaxLL, 11); + optPtr->matchLengthSum = ZSTD_scaleStats(optPtr->matchLengthFreq, MaxML, 11); + optPtr->offCodeSum = ZSTD_scaleStats(optPtr->offCodeFreq, MaxOff, 11); } ZSTD_setBasePrices(optPtr, optLevel); @@ -225,11 +255,14 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */ /* dynamic statistics */ - { U32 price = litLength * optPtr->litSumBasePrice; + { U32 price = optPtr->litSumBasePrice * litLength; + U32 const litPriceMax = optPtr->litSumBasePrice - BITCOST_MULTIPLIER; U32 u; + assert(optPtr->litSumBasePrice >= BITCOST_MULTIPLIER); for (u=0; u < litLength; u++) { - assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */ - price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel); + U32 litPrice = WEIGHT(optPtr->litFreq[literals[u]], optLevel); + if (UNLIKELY(litPrice > litPriceMax)) litPrice = litPriceMax; + price -= litPrice; } return price; } @@ -239,7 +272,16 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, * cost of literalLength symbol */ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel) { - if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel); + assert(litLength <= ZSTD_BLOCKSIZE_MAX); + if (optPtr->priceType == zop_predef) + return WEIGHT(litLength, optLevel); + /* We can't compute the litLength price for sizes >= ZSTD_BLOCKSIZE_MAX + * because it isn't representable in the zstd format. So instead just + * call it 1 bit more than ZSTD_BLOCKSIZE_MAX - 1. In this case the block + * would be all literals. + */ + if (litLength == ZSTD_BLOCKSIZE_MAX) + return BITCOST_MULTIPLIER + ZSTD_litLengthPrice(ZSTD_BLOCKSIZE_MAX - 1, optPtr, optLevel); /* dynamic statistics */ { U32 const llCode = ZSTD_LLcode(litLength); @@ -249,52 +291,20 @@ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optP } } -/* ZSTD_litLengthContribution() : - * @return ( cost(litlength) - cost(0) ) - * this value can then be added to rawLiteralsCost() - * to provide a cost which is directly comparable to a match ending at same position */ -static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel) -{ - if (optPtr->priceType >= zop_predef) return (int)WEIGHT(litLength, optLevel); - - /* dynamic statistics */ - { U32 const llCode = ZSTD_LLcode(litLength); - int const contribution = (int)(LL_bits[llCode] * BITCOST_MULTIPLIER) - + (int)WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */ - - (int)WEIGHT(optPtr->litLengthFreq[llCode], optLevel); -#if 1 - return contribution; -#else - return MAX(0, contribution); /* sometimes better, sometimes not ... */ -#endif - } -} - -/* ZSTD_literalsContribution() : - * creates a fake cost for the literals part of a sequence - * which can be compared to the ending cost of a match - * should a new match start at this position */ -static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength, - const optState_t* const optPtr, - int optLevel) -{ - int const contribution = (int)ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel) - + ZSTD_litLengthContribution(litLength, optPtr, optLevel); - return contribution; -} - /* ZSTD_getMatchPrice() : * Provides the cost of the match part (offset + matchLength) of a sequence * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence. - * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */ + * @offBase : sumtype, representing an offset or a repcode, and using numeric representation of ZSTD_storeSeq() + * @optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) + */ FORCE_INLINE_TEMPLATE U32 -ZSTD_getMatchPrice(U32 const offset, +ZSTD_getMatchPrice(U32 const offBase, U32 const matchLength, const optState_t* const optPtr, int const optLevel) { U32 price; - U32 const offCode = ZSTD_highbit32(offset+1); + U32 const offCode = ZSTD_highbit32(offBase); U32 const mlBase = matchLength - MINMATCH; assert(matchLength >= MINMATCH); @@ -318,10 +328,10 @@ ZSTD_getMatchPrice(U32 const offset, } /* ZSTD_updateStats() : - * assumption : literals + litLengtn <= iend */ + * assumption : literals + litLength <= iend */ static void ZSTD_updateStats(optState_t* const optPtr, U32 litLength, const BYTE* literals, - U32 offsetCode, U32 matchLength) + U32 offBase, U32 matchLength) { /* literals */ if (ZSTD_compressedLiterals(optPtr)) { @@ -337,8 +347,8 @@ static void ZSTD_updateStats(optState_t* const optPtr, optPtr->litLengthSum++; } - /* match offset code (0-2=>repCode; 3+=>offset+2) */ - { U32 const offCode = ZSTD_highbit32(offsetCode+1); + /* offset code : expected to follow storeSeq() numeric representation */ + { U32 const offCode = ZSTD_highbit32(offBase); assert(offCode <= MaxOff); optPtr->offCodeFreq[offCode]++; optPtr->offCodeSum++; @@ -372,7 +382,7 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) /* Update hashTable3 up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, +static U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms, U32* nextToUpdate3, const BYTE* const ip) { @@ -398,11 +408,13 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, * Binary Tree search ***************************************/ /** ZSTD_insertBt1() : add one or multiple positions to tree. - * ip : assumed <= iend-8 . + * @param ip assumed <= iend-8 . + * @param target The target of ZSTD_updateTree_internal() - we are filling to this position * @return : nb of positions added */ static U32 ZSTD_insertBt1( - ZSTD_matchState_t* ms, + const ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, + U32 const target, U32 const mls, const int extDict) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -420,32 +432,36 @@ static U32 ZSTD_insertBt1( const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - const U32 current = (U32)(ip-base); - const U32 btLow = btMask >= current ? 0 : current - btMask; - U32* smallerPtr = bt + 2*(current&btMask); + const U32 curr = (U32)(ip-base); + const U32 btLow = btMask >= curr ? 0 : curr - btMask; + U32* smallerPtr = bt + 2*(curr&btMask); U32* largerPtr = smallerPtr + 1; U32 dummy32; /* to be nullified at the end */ - U32 const windowLow = ms->window.lowLimit; - U32 matchEndIdx = current+8+1; + /* windowLow is based on target because + * we only need positions that will be in the window at the end of the tree update. + */ + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, target, cParams->windowLog); + U32 matchEndIdx = curr+8+1; size_t bestLength = 8; U32 nbCompares = 1U << cParams->searchLog; #ifdef ZSTD_C_PREDICT - U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); - U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1); + U32 predictedSmall = *(bt + 2*((curr-1)&btMask) + 0); + U32 predictedLarge = *(bt + 2*((curr-1)&btMask) + 1); predictedSmall += (predictedSmall>0); predictedLarge += (predictedLarge>0); #endif /* ZSTD_C_PREDICT */ - DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current); + DEBUGLOG(8, "ZSTD_insertBt1 (%u)", curr); + assert(curr <= target); assert(ip <= iend-8); /* required for h calculation */ - hashTable[h] = current; /* Update Hash Table */ + hashTable[h] = curr; /* Update Hash Table */ assert(windowLow > 0); - while (nbCompares-- && (matchIndex >= windowLow)) { + for (; nbCompares && (matchIndex >= windowLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < current); + assert(matchIndex < curr); #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ @@ -508,8 +524,8 @@ static U32 ZSTD_insertBt1( *smallerPtr = *largerPtr = 0; { U32 positions = 0; if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384)); /* speed optimization */ - assert(matchEndIdx > current + 8); - return MAX(positions, matchEndIdx - (current + 8)); + assert(matchEndIdx > curr + 8); + return MAX(positions, matchEndIdx - (curr + 8)); } } @@ -526,7 +542,7 @@ void ZSTD_updateTree_internal( idx, target, dictMode); while(idx < target) { - U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict); + U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, target, mls, dictMode == ZSTD_extDict); assert(idx < (U32)(idx + forward)); idx += forward; } @@ -553,7 +569,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( const ZSTD_compressionParameters* const cParams = &ms->cParams; U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); const BYTE* const base = ms->window.base; - U32 const current = (U32)(ip-base); + U32 const curr = (U32)(ip-base); U32 const hashLog = cParams->hashLog; U32 const minMatch = (mls==3) ? 3 : 4; U32* const hashTable = ms->hashTable; @@ -567,12 +583,12 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 const dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32 const btLow = (btMask >= current) ? 0 : current - btMask; - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); + U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); U32 const matchLow = windowLow ? windowLow : 1; - U32* smallerPtr = bt + 2*(current&btMask); - U32* largerPtr = bt + 2*(current&btMask) + 1; - U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */ + U32* smallerPtr = bt + 2*(curr&btMask); + U32* largerPtr = bt + 2*(curr&btMask) + 1; + U32 matchEndIdx = curr+8+1; /* farthest referenced position of any match => detects repetitive patterns */ U32 dummy32; /* to be nullified at the end */ U32 mnum = 0; U32 nbCompares = 1U << cParams->searchLog; @@ -591,7 +607,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit; size_t bestLength = lengthToBeat-1; - DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current); + DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", curr); /* check repCode */ assert(ll0 <= 1); /* necessarily 1 or 0 */ @@ -599,26 +615,29 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 repCode; for (repCode = ll0; repCode < lastR; repCode++) { U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - U32 const repIndex = current - repOffset; + U32 const repIndex = curr - repOffset; U32 repLen = 0; - assert(current >= dictLimit); - if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */ - if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) { + assert(curr >= dictLimit); + if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < curr-dictLimit) { /* equivalent to `curr > repIndex >= dictLimit` */ + /* We must validate the repcode offset because when we're using a dictionary the + * valid offset range shrinks when the dictionary goes out of bounds. + */ + if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) { repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch; } - } else { /* repIndex < dictLimit || repIndex >= current */ + } else { /* repIndex < dictLimit || repIndex >= curr */ const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ? dmsBase + repIndex - dmsIndexDelta : dictBase + repIndex; - assert(current >= windowLow); + assert(curr >= windowLow); if ( dictMode == ZSTD_extDict - && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */ + && ( ((repOffset-1) /*intentional overflow*/ < curr - windowLow) /* equivalent to `curr > repIndex >= windowLow` */ & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */) && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch; } if (dictMode == ZSTD_dictMatchState - && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */ + && ( ((repOffset-1) /*intentional overflow*/ < curr - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `curr > repIndex >= dmsLowLimit` */ & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch; @@ -628,7 +647,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u", repCode, ll0, repOffset, repLen); bestLength = repLen; - matches[mnum].off = repCode - ll0; + matches[mnum].off = REPCODE_TO_OFFBASE(repCode - ll0 + 1); /* expect value between 1 and 3 */ matches[mnum].len = (U32)repLen; mnum++; if ( (repLen > sufficient_len) @@ -640,7 +659,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( if ((mls == 3) /*static*/ && (bestLength < mls)) { U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip); if ((matchIndex3 >= matchLow) - & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { + & (curr - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { size_t mlen; if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) { const BYTE* const match = base + matchIndex3; @@ -655,26 +674,26 @@ U32 ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found small match with hlog3, of length %u", (U32)mlen); bestLength = mlen; - assert(current > matchIndex3); + assert(curr > matchIndex3); assert(mnum==0); /* no prior solution */ - matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE; + matches[0].off = OFFSET_TO_OFFBASE(curr - matchIndex3); matches[0].len = (U32)mlen; mnum = 1; if ( (mlen > sufficient_len) | (ip+mlen == iLimit) ) { /* best possible length */ - ms->nextToUpdate = current+1; /* skip insertion */ + ms->nextToUpdate = curr+1; /* skip insertion */ return 1; } } } /* no dictMatchState lookup: dicts don't have a populated HC3 table */ - } + } /* if (mls == 3) */ - hashTable[h] = current; /* Update Hash Table */ + hashTable[h] = curr; /* Update Hash Table */ - while (nbCompares-- && (matchIndex >= matchLow)) { + for (; nbCompares && (matchIndex >= matchLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); const BYTE* match; size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(current > matchIndex); + assert(curr > matchIndex); if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) { assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */ @@ -690,21 +709,20 @@ U32 ZSTD_insertBtAndGetAllMatches ( } if (matchLength > bestLength) { - DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)", - (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); + DEBUGLOG(8, "found match of length %u at distance %u (offBase=%u)", + (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); assert(matchEndIdx > matchIndex); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; + matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */ break; /* drop, to preserve bt consistency (miss a little bit of compression) */ - } - } + } } if (match[matchLength] < ip[matchLength]) { /* match smaller than current */ @@ -723,12 +741,13 @@ U32 ZSTD_insertBtAndGetAllMatches ( *smallerPtr = *largerPtr = 0; + assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls); U32 dictMatchIndex = dms->hashTable[dmsH]; const U32* const dmsBt = dms->chainTable; commonLengthSmaller = commonLengthLarger = 0; - while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) { + for (; nbCompares && (dictMatchIndex > dmsLowLimit); --nbCompares) { const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dmsBase + dictMatchIndex; @@ -738,19 +757,18 @@ U32 ZSTD_insertBtAndGetAllMatches ( if (matchLength > bestLength) { matchIndex = dictMatchIndex + dmsIndexDelta; - DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)", - (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); + DEBUGLOG(8, "found dms match of length %u at distance %u (offBase=%u)", + (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; + matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { break; /* drop, to guarantee consistency (miss a little bit of compression) */ - } - } + } } if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */ if (match[matchLength] < ip[matchLength]) { @@ -760,71 +778,242 @@ U32 ZSTD_insertBtAndGetAllMatches ( /* match is larger than current */ commonLengthLarger = matchLength; dictMatchIndex = nextPtr[0]; - } - } - } + } } } /* if (dictMode == ZSTD_dictMatchState) */ - assert(matchEndIdx > current+8); + assert(matchEndIdx > curr+8); ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ return mnum; } +typedef U32 (*ZSTD_getAllMatchesFn)( + ZSTD_match_t*, + ZSTD_matchState_t*, + U32*, + const BYTE*, + const BYTE*, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, + U32 const lengthToBeat); + +FORCE_INLINE_TEMPLATE U32 ZSTD_btGetAllMatches_internal( + ZSTD_match_t* matches, + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* ip, + const BYTE* const iHighLimit, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, + U32 const lengthToBeat, + const ZSTD_dictMode_e dictMode, + const U32 mls) +{ + assert(BOUNDED(3, ms->cParams.minMatch, 6) == mls); + DEBUGLOG(8, "ZSTD_BtGetAllMatches(dictMode=%d, mls=%u)", (int)dictMode, mls); + if (ip < ms->window.base + ms->nextToUpdate) + return 0; /* skipped area */ + ZSTD_updateTree_internal(ms, ip, iHighLimit, mls, dictMode); + return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, mls); +} + +#define ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls) ZSTD_btGetAllMatches_##dictMode##_##mls + +#define GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, mls) \ + static U32 ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls)( \ + ZSTD_match_t* matches, \ + ZSTD_matchState_t* ms, \ + U32* nextToUpdate3, \ + const BYTE* ip, \ + const BYTE* const iHighLimit, \ + const U32 rep[ZSTD_REP_NUM], \ + U32 const ll0, \ + U32 const lengthToBeat) \ + { \ + return ZSTD_btGetAllMatches_internal( \ + matches, ms, nextToUpdate3, ip, iHighLimit, \ + rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \ + } + +#define GEN_ZSTD_BT_GET_ALL_MATCHES(dictMode) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 3) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 4) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 5) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 6) + +GEN_ZSTD_BT_GET_ALL_MATCHES(noDict) +GEN_ZSTD_BT_GET_ALL_MATCHES(extDict) +GEN_ZSTD_BT_GET_ALL_MATCHES(dictMatchState) + +#define ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMode) \ + { \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 3), \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 4), \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 5), \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 6) \ + } -FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( - ZSTD_match_t* matches, /* store result (match found, increasing size) in this table */ - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, - U32 const lengthToBeat) +static ZSTD_getAllMatchesFn +ZSTD_selectBtGetAllMatches(ZSTD_matchState_t const* ms, ZSTD_dictMode_e const dictMode) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; - U32 const matchLengthSearch = cParams->minMatch; - DEBUGLOG(8, "ZSTD_BtGetAllMatches"); - if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode); - switch(matchLengthSearch) - { - case 3 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 3); - default : - case 4 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 4); - case 5 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 5); - case 7 : - case 6 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 6); + ZSTD_getAllMatchesFn const getAllMatchesFns[3][4] = { + ZSTD_BT_GET_ALL_MATCHES_ARRAY(noDict), + ZSTD_BT_GET_ALL_MATCHES_ARRAY(extDict), + ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMatchState) + }; + U32 const mls = BOUNDED(3, ms->cParams.minMatch, 6); + assert((U32)dictMode < 3); + assert(mls - 3 < 4); + return getAllMatchesFns[(int)dictMode][mls - 3]; +} + +/************************* +* LDM helper functions * +*************************/ + +/* Struct containing info needed to make decision about ldm inclusion */ +typedef struct { + rawSeqStore_t seqStore; /* External match candidates store for this block */ + U32 startPosInBlock; /* Start position of the current match candidate */ + U32 endPosInBlock; /* End position of the current match candidate */ + U32 offset; /* Offset of the match candidate */ +} ZSTD_optLdm_t; + +/* ZSTD_optLdm_skipRawSeqStoreBytes(): + * Moves forward in @rawSeqStore by @nbBytes, + * which will update the fields 'pos' and 'posInSequence'. + */ +static void ZSTD_optLdm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) +{ + U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); + while (currPos && rawSeqStore->pos < rawSeqStore->size) { + rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; + if (currPos >= currSeq.litLength + currSeq.matchLength) { + currPos -= currSeq.litLength + currSeq.matchLength; + rawSeqStore->pos++; + } else { + rawSeqStore->posInSequence = currPos; + break; + } + } + if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { + rawSeqStore->posInSequence = 0; + } +} + +/* ZSTD_opt_getNextMatchAndUpdateSeqStore(): + * Calculates the beginning and end of the next match in the current block. + * Updates 'pos' and 'posInSequence' of the ldmSeqStore. + */ +static void +ZSTD_opt_getNextMatchAndUpdateSeqStore(ZSTD_optLdm_t* optLdm, U32 currPosInBlock, + U32 blockBytesRemaining) +{ + rawSeq currSeq; + U32 currBlockEndPos; + U32 literalsBytesRemaining; + U32 matchBytesRemaining; + + /* Setting match end position to MAX to ensure we never use an LDM during this block */ + if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { + optLdm->startPosInBlock = UINT_MAX; + optLdm->endPosInBlock = UINT_MAX; + return; + } + /* Calculate appropriate bytes left in matchLength and litLength + * after adjusting based on ldmSeqStore->posInSequence */ + currSeq = optLdm->seqStore.seq[optLdm->seqStore.pos]; + assert(optLdm->seqStore.posInSequence <= currSeq.litLength + currSeq.matchLength); + currBlockEndPos = currPosInBlock + blockBytesRemaining; + literalsBytesRemaining = (optLdm->seqStore.posInSequence < currSeq.litLength) ? + currSeq.litLength - (U32)optLdm->seqStore.posInSequence : + 0; + matchBytesRemaining = (literalsBytesRemaining == 0) ? + currSeq.matchLength - ((U32)optLdm->seqStore.posInSequence - currSeq.litLength) : + currSeq.matchLength; + + /* If there are more literal bytes than bytes remaining in block, no ldm is possible */ + if (literalsBytesRemaining >= blockBytesRemaining) { + optLdm->startPosInBlock = UINT_MAX; + optLdm->endPosInBlock = UINT_MAX; + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, blockBytesRemaining); + return; + } + + /* Matches may be < MINMATCH by this process. In that case, we will reject them + when we are deciding whether or not to add the ldm */ + optLdm->startPosInBlock = currPosInBlock + literalsBytesRemaining; + optLdm->endPosInBlock = optLdm->startPosInBlock + matchBytesRemaining; + optLdm->offset = currSeq.offset; + + if (optLdm->endPosInBlock > currBlockEndPos) { + /* Match ends after the block ends, we can't use the whole match */ + optLdm->endPosInBlock = currBlockEndPos; + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, currBlockEndPos - currPosInBlock); + } else { + /* Consume nb of bytes equal to size of sequence left */ + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, literalsBytesRemaining + matchBytesRemaining); } } +/* ZSTD_optLdm_maybeAddMatch(): + * Adds a match if it's long enough, + * based on it's 'matchStartPosInBlock' and 'matchEndPosInBlock', + * into 'matches'. Maintains the correct ordering of 'matches'. + */ +static void ZSTD_optLdm_maybeAddMatch(ZSTD_match_t* matches, U32* nbMatches, + const ZSTD_optLdm_t* optLdm, U32 currPosInBlock) +{ + U32 const posDiff = currPosInBlock - optLdm->startPosInBlock; + /* Note: ZSTD_match_t actually contains offBase and matchLength (before subtracting MINMATCH) */ + U32 const candidateMatchLength = optLdm->endPosInBlock - optLdm->startPosInBlock - posDiff; + + /* Ensure that current block position is not outside of the match */ + if (currPosInBlock < optLdm->startPosInBlock + || currPosInBlock >= optLdm->endPosInBlock + || candidateMatchLength < MINMATCH) { + return; + } -/*-******************************* -* Optimal parser -*********************************/ -typedef struct repcodes_s { - U32 rep[3]; -} repcodes_t; + if (*nbMatches == 0 || ((candidateMatchLength > matches[*nbMatches-1].len) && *nbMatches < ZSTD_OPT_NUM)) { + U32 const candidateOffBase = OFFSET_TO_OFFBASE(optLdm->offset); + DEBUGLOG(6, "ZSTD_optLdm_maybeAddMatch(): Adding ldm candidate match (offBase: %u matchLength %u) at block position=%u", + candidateOffBase, candidateMatchLength, currPosInBlock); + matches[*nbMatches].len = candidateMatchLength; + matches[*nbMatches].off = candidateOffBase; + (*nbMatches)++; + } +} -static repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0) +/* ZSTD_optLdm_processMatchCandidate(): + * Wrapper function to update ldm seq store and call ldm functions as necessary. + */ +static void +ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm, + ZSTD_match_t* matches, U32* nbMatches, + U32 currPosInBlock, U32 remainingBytes) { - repcodes_t newReps; - if (offset >= ZSTD_REP_NUM) { /* full offset */ - newReps.rep[2] = rep[1]; - newReps.rep[1] = rep[0]; - newReps.rep[0] = offset - ZSTD_REP_MOVE; - } else { /* repcode */ - U32 const repCode = offset + ll0; - if (repCode > 0) { /* note : if repCode==0, no change */ - U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2]; - newReps.rep[1] = rep[0]; - newReps.rep[0] = currentOffset; - } else { /* repCode == 0 */ - memcpy(&newReps, rep, sizeof(newReps)); + if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { + return; + } + + if (currPosInBlock >= optLdm->endPosInBlock) { + if (currPosInBlock > optLdm->endPosInBlock) { + /* The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily + * at the end of a match from the ldm seq store, and will often be some bytes + * over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots" + */ + U32 const posOvershoot = currPosInBlock - optLdm->endPosInBlock; + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, posOvershoot); } + ZSTD_opt_getNextMatchAndUpdateSeqStore(optLdm, currPosInBlock, remainingBytes); } - return newReps; + ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock); } +/*-******************************* +* Optimal parser +*********************************/ + static U32 ZSTD_totalLen(ZSTD_optimal_t sol) { return sol.litlen + sol.mlen; @@ -839,7 +1028,7 @@ listStats(const U32* table, int lastEltID) int enb; for (enb=0; enb < nbElts; enb++) { (void)table; - //RAWLOG(2, "%3i:%3i, ", enb, table[enb]); + /* RAWLOG(2, "%3i:%3i, ", enb, table[enb]); */ RAWLOG(2, "%4i,", table[enb]); } RAWLOG(2, " \n"); @@ -865,6 +1054,8 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, const BYTE* const prefixStart = base + ms->window.dictLimit; const ZSTD_compressionParameters* const cParams = &ms->cParams; + ZSTD_getAllMatchesFn getAllMatches = ZSTD_selectBtGetAllMatches(ms, dictMode); + U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4; U32 nextToUpdate3 = ms->nextToUpdate; @@ -872,6 +1063,11 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, ZSTD_optimal_t* const opt = optStatePtr->priceTable; ZSTD_match_t* const matches = optStatePtr->matchTable; ZSTD_optimal_t lastSequence; + ZSTD_optLdm_t optLdm; + + optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore; + optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0; + ZSTD_opt_getNextMatchAndUpdateSeqStore(&optLdm, (U32)(ip-istart), (U32)(iend-ip)); /* init */ DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u", @@ -887,25 +1083,32 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* find first match */ { U32 const litlen = (U32)(ip - anchor); U32 const ll0 = !litlen; - U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch); + U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch); + ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, + (U32)(ip-istart), (U32)(iend - ip)); if (!nbMatches) { ip++; continue; } /* initialize opt[0] */ { U32 i ; for (i=0; i immediate encoding */ { U32 const maxML = matches[nbMatches-1].len; - U32 const maxOffset = matches[nbMatches-1].off; - DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new series", - nbMatches, maxML, maxOffset, (U32)(ip-prefixStart)); + U32 const maxOffBase = matches[nbMatches-1].off; + DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffBase=%u at cPos=%u => start new series", + nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart)); if (maxML > sufficient_len) { lastSequence.litlen = litlen; lastSequence.mlen = maxML; - lastSequence.off = maxOffset; + lastSequence.off = maxOffBase; DEBUGLOG(6, "large match (%u>%u), immediate encoding", maxML, sufficient_len); cur = 0; @@ -914,27 +1117,25 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, } } /* set prices for first matches starting position == 0 */ - { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); + assert(opt[0].price >= 0); + { U32 const literalsPrice = (U32)opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); U32 pos; U32 matchNb; for (pos = 1; pos < minMatch; pos++) { opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */ } for (matchNb = 0; matchNb < nbMatches; matchNb++) { - U32 const offset = matches[matchNb].off; + U32 const offBase = matches[matchNb].off; U32 const end = matches[matchNb].len; - repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0); for ( ; pos <= end ; pos++ ) { - U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel); + U32 const matchPrice = ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel); U32 const sequencePrice = literalsPrice + matchPrice; DEBUGLOG(7, "rPos:%u => set initial price : %.2f", pos, ZSTD_fCost(sequencePrice)); opt[pos].mlen = pos; - opt[pos].off = offset; + opt[pos].off = offBase; opt[pos].litlen = litlen; - opt[pos].price = sequencePrice; - ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory)); - memcpy(opt[pos].rep, &repHistory, sizeof(repHistory)); + opt[pos].price = (int)sequencePrice; } } last_pos = pos-1; } @@ -949,9 +1150,9 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* Fix current position with one literal if cheaper */ { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1; int const price = opt[cur-1].price - + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) - + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) - - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel); + + (int)ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) + + (int)ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) + - (int)ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel); assert(price < 1000000000); /* overflow check */ if (price <= opt[cur].price) { DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)", @@ -961,7 +1162,6 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, opt[cur].off = 0; opt[cur].litlen = litlen; opt[cur].price = price; - memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep)); } else { DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)", inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), @@ -969,6 +1169,21 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, } } + /* Set the repcodes of the current position. We must do it here + * because we rely on the repcodes of the 2nd to last sequence being + * correct to set the next chunks repcodes during the backward + * traversal. + */ + ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t)); + assert(cur >= opt[cur].mlen); + if (opt[cur].mlen != 0) { + U32 const prev = cur - opt[cur].mlen; + repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0); + ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t)); + } else { + ZSTD_memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t)); + } + /* last match must start at a minimum distance of 8 from oend */ if (inr > ilimit) continue; @@ -980,12 +1195,17 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */ } + assert(opt[cur].price >= 0); { U32 const ll0 = (opt[cur].mlen != 0); U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0; - U32 const previousPrice = opt[cur].price; + U32 const previousPrice = (U32)opt[cur].price; U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel); - U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch); + U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch); U32 matchNb; + + ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, + (U32)(inr-istart), (U32)(iend-inr)); + if (!nbMatches) { DEBUGLOG(7, "rPos:%u : no match found", cur); continue; @@ -1009,17 +1229,16 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* set prices using matches found at position == cur */ for (matchNb = 0; matchNb < nbMatches; matchNb++) { U32 const offset = matches[matchNb].off; - repcodes_t const repHistory = ZSTD_updateRep(opt[cur].rep, offset, ll0); U32 const lastML = matches[matchNb].len; U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch; U32 mlen; - DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u", + DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u", matchNb, matches[matchNb].off, lastML, litlen); for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */ U32 const pos = cur + mlen; - int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); + int const price = (int)basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); if ((pos > last_pos) || (price < opt[pos].price)) { DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)", @@ -1029,8 +1248,6 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, opt[pos].off = offset; opt[pos].litlen = litlen; opt[pos].price = price; - ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory)); - memcpy(opt[pos].rep, &repHistory, sizeof(repHistory)); } else { DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)", pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price)); @@ -1046,6 +1263,17 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ assert(opt[0].mlen == 0); + /* Set the next chunk's repcodes based on the repcodes of the beginning + * of the last match, and the last sequence. This avoids us having to + * update them while traversing the sequences. + */ + if (lastSequence.mlen != 0) { + repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0); + ZSTD_memcpy(rep, &reps, sizeof(reps)); + } else { + ZSTD_memcpy(rep, opt[cur].rep, sizeof(repcodes_t)); + } + { U32 const storeEnd = cur + 1; U32 storeStart = storeEnd; U32 seqPos = cur; @@ -1071,7 +1299,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, for (storePos=storeStart; storePos <= storeEnd; storePos++) { U32 const llen = opt[storePos].litlen; U32 const mlen = opt[storePos].mlen; - U32 const offCode = opt[storePos].off; + U32 const offBase = opt[storePos].off; U32 const advance = llen + mlen; DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u", anchor - istart, (unsigned)llen, (unsigned)mlen); @@ -1082,67 +1310,44 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, continue; /* will finish */ } - /* repcodes update : like ZSTD_updateRep(), but update in place */ - if (offCode >= ZSTD_REP_NUM) { /* full offset */ - rep[2] = rep[1]; - rep[1] = rep[0]; - rep[0] = offCode - ZSTD_REP_MOVE; - } else { /* repcode */ - U32 const repCode = offCode + (llen==0); - if (repCode) { /* note : if repCode==0, no change */ - U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - if (repCode >= 2) rep[2] = rep[1]; - rep[1] = rep[0]; - rep[0] = currentOffset; - } } - assert(anchor + llen <= iend); - ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen); - ZSTD_storeSeq(seqStore, llen, anchor, iend, offCode, mlen-MINMATCH); + ZSTD_updateStats(optStatePtr, llen, anchor, offBase, mlen); + ZSTD_storeSeq(seqStore, llen, anchor, iend, offBase, mlen); anchor += advance; ip = anchor; } } ZSTD_setBasePrices(optStatePtr, optLevel); } - } /* while (ip < ilimit) */ /* Return the last literals size */ return (size_t)(iend - anchor); } +static size_t ZSTD_compressBlock_opt0( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) +{ + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /* optLevel */, dictMode); +} + +static size_t ZSTD_compressBlock_opt2( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) +{ + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /* optLevel */, dictMode); +} size_t ZSTD_compressBlock_btopt( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btopt"); - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict); + return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_noDict); } -/* used in 2-pass strategy */ -static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus) -{ - U32 s, sum=0; - assert(ZSTD_FREQ_DIV+bonus >= 0); - for (s=0; slitSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0); - optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0); - optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0); - optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0); -} /* ZSTD_initStats_ultra(): * make a first compression pass, just to seed stats with more accurate starting values. @@ -1156,7 +1361,7 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms, const void* src, size_t srcSize) { U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */ - memcpy(tmpRep, rep, sizeof(tmpRep)); + ZSTD_memcpy(tmpRep, rep, sizeof(tmpRep)); DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize); assert(ms->opt.litLengthSum == 0); /* first block */ @@ -1164,7 +1369,7 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms, assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */ assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */ - ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/ + ZSTD_compressBlock_opt2(ms, seqStore, tmpRep, src, srcSize, ZSTD_noDict); /* generate stats into ms->opt*/ /* invalidate first scan from history */ ZSTD_resetSeqStore(seqStore); @@ -1173,8 +1378,6 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms, ms->window.lowLimit = ms->window.dictLimit; ms->nextToUpdate = ms->window.dictLimit; - /* re-inforce weight of collected statistics */ - ZSTD_upscaleStats(&ms->opt); } size_t ZSTD_compressBlock_btultra( @@ -1182,14 +1385,14 @@ size_t ZSTD_compressBlock_btultra( const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize); - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); } size_t ZSTD_compressBlock_btultra2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - U32 const current = (U32)((const BYTE*)src - ms->window.base); + U32 const curr = (U32)((const BYTE*)src - ms->window.base); DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize); /* 2-pass strategy: @@ -1204,41 +1407,41 @@ size_t ZSTD_compressBlock_btultra2( if ( (ms->opt.litLengthSum==0) /* first block */ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */ && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */ - && (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ + && (curr == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ && (srcSize > ZSTD_PREDEF_THRESHOLD) ) { ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize); } - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); } size_t ZSTD_compressBlock_btopt_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); } size_t ZSTD_compressBlock_btultra_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); } size_t ZSTD_compressBlock_btopt_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict); + return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_extDict); } size_t ZSTD_compressBlock_btultra_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_extDict); } /* note : no btultra2 variant for extDict nor dictMatchState, diff --git a/native/zstd/compress/zstd_opt.h b/native/zstd/compress/zstd_opt.h old mode 100755 new mode 100644 index 094f747..627255f --- a/native/zstd/compress/zstd_opt.h +++ b/native/zstd/compress/zstd_opt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/compress/zstdmt_compress.c b/native/zstd/compress/zstdmt_compress.c old mode 100755 new mode 100644 index bc3062b..0c10eb6 --- a/native/zstd/compress/zstdmt_compress.c +++ b/native/zstd/compress/zstdmt_compress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,11 +20,10 @@ /* ====== Dependencies ====== */ -#include /* memcpy, memset */ -#include /* INT_MAX, UINT_MAX */ -#include "mem.h" /* MEM_STATIC */ -#include "pool.h" /* threadpool */ -#include "threading.h" /* mutex */ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset, INT_MAX, UINT_MAX */ +#include "../common/mem.h" /* MEM_STATIC */ +#include "../common/pool.h" /* threadpool */ +#include "../common/threading.h" /* mutex */ #include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */ #include "zstd_ldm.h" #include "zstdmt_compress.h" @@ -103,14 +102,13 @@ typedef struct ZSTDMT_bufferPool_s { buffer_t bTable[1]; /* variable size */ } ZSTDMT_bufferPool; -static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbWorkers, ZSTD_customMem cMem) +static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned maxNbBuffers, ZSTD_customMem cMem) { - unsigned const maxNbBuffers = 2*nbWorkers + 3; - ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc( + ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_customCalloc( sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem); if (bufPool==NULL) return NULL; if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) { - ZSTD_free(bufPool, cMem); + ZSTD_customFree(bufPool, cMem); return NULL; } bufPool->bufferSize = 64 KB; @@ -127,10 +125,10 @@ static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) if (!bufPool) return; /* compatibility with free on NULL */ for (u=0; utotalBuffers; u++) { DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start); - ZSTD_free(bufPool->bTable[u].start, bufPool->cMem); + ZSTD_customFree(bufPool->bTable[u].start, bufPool->cMem); } ZSTD_pthread_mutex_destroy(&bufPool->poolMutex); - ZSTD_free(bufPool, bufPool->cMem); + ZSTD_customFree(bufPool, bufPool->cMem); } /* only works at initialization, not during compression */ @@ -161,9 +159,8 @@ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const } -static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, U32 nbWorkers) +static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, unsigned maxNbBuffers) { - unsigned const maxNbBuffers = 2*nbWorkers + 3; if (srcBufPool==NULL) return NULL; if (srcBufPool->totalBuffers >= maxNbBuffers) /* good enough */ return srcBufPool; @@ -172,7 +169,7 @@ static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, size_t const bSize = srcBufPool->bufferSize; /* forward parameters */ ZSTDMT_bufferPool* newBufPool; ZSTDMT_freeBufferPool(srcBufPool); - newBufPool = ZSTDMT_createBufferPool(nbWorkers, cMem); + newBufPool = ZSTDMT_createBufferPool(maxNbBuffers, cMem); if (newBufPool==NULL) return newBufPool; ZSTDMT_setBufferSize(newBufPool, bSize); return newBufPool; @@ -201,13 +198,13 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool) } /* size conditions not respected : scratch this buffer, create new one */ DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing"); - ZSTD_free(buf.start, bufPool->cMem); + ZSTD_customFree(buf.start, bufPool->cMem); } ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); /* create new buffer */ DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer"); { buffer_t buffer; - void* const start = ZSTD_malloc(bSize, bufPool->cMem); + void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); buffer.start = start; /* note : start can be NULL if malloc fails ! */ buffer.capacity = (start==NULL) ? 0 : bSize; if (start==NULL) { @@ -229,13 +226,13 @@ static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer) { size_t const bSize = bufPool->bufferSize; if (buffer.capacity < bSize) { - void* const start = ZSTD_malloc(bSize, bufPool->cMem); + void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); buffer_t newBuffer; newBuffer.start = start; newBuffer.capacity = start == NULL ? 0 : bSize; if (start != NULL) { assert(newBuffer.capacity >= buffer.capacity); - memcpy(newBuffer.start, buffer.start, buffer.capacity); + ZSTD_memcpy(newBuffer.start, buffer.start, buffer.capacity); DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize); return newBuffer; } @@ -261,13 +258,21 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); /* Reached bufferPool capacity (should not happen) */ DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing "); - ZSTD_free(buf.start, bufPool->cMem); + ZSTD_customFree(buf.start, bufPool->cMem); } +/* We need 2 output buffers per worker since each dstBuff must be flushed after it is released. + * The 3 additional buffers are as follows: + * 1 buffer for input loading + * 1 buffer for "next input" when submitting current one + * 1 buffer stuck in queue */ +#define BUF_POOL_MAX_NB_BUFFERS(nbWorkers) (2*(nbWorkers) + 3) -/* ===== Seq Pool Wrapper ====== */ +/* After a worker releases its rawSeqStore, it is immediately ready for reuse. + * So we only need one seq buffer per worker. */ +#define SEQ_POOL_MAX_NB_BUFFERS(nbWorkers) (nbWorkers) -static rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0}; +/* ===== Seq Pool Wrapper ====== */ typedef ZSTDMT_bufferPool ZSTDMT_seqPool; @@ -278,7 +283,7 @@ static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool) static rawSeqStore_t bufferToSeq(buffer_t buffer) { - rawSeqStore_t seq = {NULL, 0, 0, 0}; + rawSeqStore_t seq = kNullRawSeqStore; seq.seq = (rawSeq*)buffer.start; seq.capacity = buffer.capacity / sizeof(rawSeq); return seq; @@ -319,7 +324,7 @@ static void ZSTDMT_setNbSeq(ZSTDMT_seqPool* const seqPool, size_t const nbSeq) static ZSTDMT_seqPool* ZSTDMT_createSeqPool(unsigned nbWorkers, ZSTD_customMem cMem) { - ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(nbWorkers, cMem); + ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(SEQ_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); if (seqPool == NULL) return NULL; ZSTDMT_setNbSeq(seqPool, 0); return seqPool; @@ -332,7 +337,7 @@ static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool) static ZSTDMT_seqPool* ZSTDMT_expandSeqPool(ZSTDMT_seqPool* pool, U32 nbWorkers) { - return ZSTDMT_expandBufferPool(pool, nbWorkers); + return ZSTDMT_expandBufferPool(pool, SEQ_POOL_MAX_NB_BUFFERS(nbWorkers)); } @@ -354,7 +359,7 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) for (cid=0; cidtotalCCtx; cid++) ZSTD_freeCCtx(pool->cctx[cid]); /* note : compatible with free on NULL */ ZSTD_pthread_mutex_destroy(&pool->poolMutex); - ZSTD_free(pool, pool->cMem); + ZSTD_customFree(pool, pool->cMem); } /* ZSTDMT_createCCtxPool() : @@ -362,12 +367,12 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers, ZSTD_customMem cMem) { - ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc( + ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_customCalloc( sizeof(ZSTDMT_CCtxPool) + (nbWorkers-1)*sizeof(ZSTD_CCtx*), cMem); assert(nbWorkers > 0); if (!cctxPool) return NULL; if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) { - ZSTD_free(cctxPool, cMem); + ZSTD_customFree(cctxPool, cMem); return NULL; } cctxPool->cMem = cMem; @@ -461,52 +466,72 @@ typedef struct { ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */ } serialState_t; -static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* seqPool, ZSTD_CCtx_params params, size_t jobSize) +static int +ZSTDMT_serialState_reset(serialState_t* serialState, + ZSTDMT_seqPool* seqPool, + ZSTD_CCtx_params params, + size_t jobSize, + const void* dict, size_t const dictSize, + ZSTD_dictContentType_e dictContentType) { /* Adjust parameters */ - if (params.ldmParams.enableLdm) { + if (params.ldmParams.enableLdm == ZSTD_ps_enable) { DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10); ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); assert(params.ldmParams.hashRateLog < 32); - serialState->ldmState.hashPower = - ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); } else { - memset(¶ms.ldmParams, 0, sizeof(params.ldmParams)); + ZSTD_memset(¶ms.ldmParams, 0, sizeof(params.ldmParams)); } serialState->nextJobID = 0; if (params.fParams.checksumFlag) XXH64_reset(&serialState->xxhState, 0); - if (params.ldmParams.enableLdm) { + if (params.ldmParams.enableLdm == ZSTD_ps_enable) { ZSTD_customMem cMem = params.customMem; unsigned const hashLog = params.ldmParams.hashLog; size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t); unsigned const bucketLog = params.ldmParams.hashLog - params.ldmParams.bucketSizeLog; - size_t const bucketSize = (size_t)1 << bucketLog; unsigned const prevBucketLog = serialState->params.ldmParams.hashLog - serialState->params.ldmParams.bucketSizeLog; + size_t const numBuckets = (size_t)1 << bucketLog; /* Size the seq pool tables */ ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize)); /* Reset the window */ - ZSTD_window_clear(&serialState->ldmState.window); - serialState->ldmWindow = serialState->ldmState.window; + ZSTD_window_init(&serialState->ldmState.window); /* Resize tables and output space if necessary. */ if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) { - ZSTD_free(serialState->ldmState.hashTable, cMem); - serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_malloc(hashSize, cMem); + ZSTD_customFree(serialState->ldmState.hashTable, cMem); + serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_customMalloc(hashSize, cMem); } if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) { - ZSTD_free(serialState->ldmState.bucketOffsets, cMem); - serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_malloc(bucketSize, cMem); + ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); + serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(numBuckets, cMem); } if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets) return 1; /* Zero the tables */ - memset(serialState->ldmState.hashTable, 0, hashSize); - memset(serialState->ldmState.bucketOffsets, 0, bucketSize); + ZSTD_memset(serialState->ldmState.hashTable, 0, hashSize); + ZSTD_memset(serialState->ldmState.bucketOffsets, 0, numBuckets); + + /* Update window state and fill hash table with dict */ + serialState->ldmState.loadedDictEnd = 0; + if (dictSize > 0) { + if (dictContentType == ZSTD_dct_rawContent) { + BYTE const* const dictEnd = (const BYTE*)dict + dictSize; + ZSTD_window_update(&serialState->ldmState.window, dict, dictSize, /* forceNonContiguous */ 0); + ZSTD_ldm_fillHashTable(&serialState->ldmState, (const BYTE*)dict, dictEnd, ¶ms.ldmParams); + serialState->ldmState.loadedDictEnd = params.forceWindow ? 0 : (U32)(dictEnd - serialState->ldmState.window.base); + } else { + /* don't even load anything */ + } + } + + /* Initialize serialState's copy of ldmWindow. */ + serialState->ldmWindow = serialState->ldmState.window; } + serialState->params = params; serialState->params.jobSize = (U32)jobSize; return 0; @@ -515,7 +540,7 @@ static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* static int ZSTDMT_serialState_init(serialState_t* serialState) { int initError = 0; - memset(serialState, 0, sizeof(*serialState)); + ZSTD_memset(serialState, 0, sizeof(*serialState)); initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL); initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL); initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL); @@ -530,8 +555,8 @@ static void ZSTDMT_serialState_free(serialState_t* serialState) ZSTD_pthread_cond_destroy(&serialState->cond); ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex); ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond); - ZSTD_free(serialState->ldmState.hashTable, cMem); - ZSTD_free(serialState->ldmState.bucketOffsets, cMem); + ZSTD_customFree(serialState->ldmState.hashTable, cMem); + ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); } static void ZSTDMT_serialState_update(serialState_t* serialState, @@ -547,12 +572,12 @@ static void ZSTDMT_serialState_update(serialState_t* serialState, /* A future job may error and skip our job */ if (serialState->nextJobID == jobID) { /* It is now our turn, do any processing necessary */ - if (serialState->params.ldmParams.enableLdm) { + if (serialState->params.ldmParams.enableLdm == ZSTD_ps_enable) { size_t error; assert(seqStore.seq != NULL && seqStore.pos == 0 && seqStore.size == 0 && seqStore.capacity > 0); assert(src.size <= serialState->params.jobSize); - ZSTD_window_update(&serialState->ldmState.window, src.start, src.size); + ZSTD_window_update(&serialState->ldmState.window, src.start, src.size, /* forceNonContiguous */ 0); error = ZSTD_ldm_generateSequences( &serialState->ldmState, &seqStore, &serialState->params.ldmParams, src.start, src.size); @@ -577,7 +602,7 @@ static void ZSTDMT_serialState_update(serialState_t* serialState, if (seqStore.size > 0) { size_t const err = ZSTD_referenceExternalSequences( jobCCtx, seqStore.seq, seqStore.size); - assert(serialState->params.ldmParams.enableLdm); + assert(serialState->params.ldmParams.enableLdm == ZSTD_ps_enable); assert(!ZSTD_isError(err)); (void)err; } @@ -655,7 +680,7 @@ static void ZSTDMT_compressionJob(void* jobDescription) if (dstBuff.start==NULL) JOB_ERROR(ERROR(memory_allocation)); job->dstBuff = dstBuff; /* this value can be read in ZSTDMT_flush, when it copies the whole job */ } - if (jobParams.ldmParams.enableLdm && rawSeqStore.seq == NULL) + if (jobParams.ldmParams.enableLdm == ZSTD_ps_enable && rawSeqStore.seq == NULL) JOB_ERROR(ERROR(memory_allocation)); /* Don't compute the checksum for chunks, since we compute it externally, @@ -663,7 +688,9 @@ static void ZSTDMT_compressionJob(void* jobDescription) */ if (job->jobID != 0) jobParams.fParams.checksumFlag = 0; /* Don't run LDM for the chunks, since we handle it externally */ - jobParams.ldmParams.enableLdm = 0; + jobParams.ldmParams.enableLdm = ZSTD_ps_disable; + /* Correct nbWorkers to 0. */ + jobParams.nbWorkers = 0; /* init */ @@ -676,6 +703,10 @@ static void ZSTDMT_compressionJob(void* jobDescription) { size_t const forceWindowError = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob); if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError); } + if (!job->firstJob) { + size_t const err = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_deterministicRefPrefix, 0); + if (ZSTD_isError(err)) JOB_ERROR(err); + } { size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */ ZSTD_dtlm_fast, @@ -731,6 +762,13 @@ static void ZSTDMT_compressionJob(void* jobDescription) if (ZSTD_isError(cSize)) JOB_ERROR(cSize); lastCBlockSize = cSize; } } + if (!job->firstJob) { + /* Double check that we don't have an ext-dict, because then our + * repcode invalidation doesn't work. + */ + assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); + } + ZSTD_CCtx_trace(cctx, 0); _endJob: ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize); @@ -777,6 +815,15 @@ typedef struct { static const roundBuff_t kNullRoundBuff = {NULL, 0, 0}; #define RSYNC_LENGTH 32 +/* Don't create chunks smaller than the zstd block size. + * This stops us from regressing compression ratio too much, + * and ensures our output fits in ZSTD_compressBound(). + * + * If this is shrunk < ZSTD_BLOCKSIZELOG_MIN then + * ZSTD_COMPRESSBOUND() will need to be updated. + */ +#define RSYNC_MIN_BLOCK_LOG ZSTD_BLOCKSIZELOG_MAX +#define RSYNC_MIN_BLOCK_SIZE (1<params, nbWorkers); mtctx->cMem = cMem; mtctx->allJobsCompleted = 1; - mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem); + if (pool != NULL) { + mtctx->factory = pool; + mtctx->providedFactory = 1; + } + else { + mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem); + mtctx->providedFactory = 0; + } mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem); assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0); /* ensure nbJobs is a power of 2 */ mtctx->jobIDMask = nbJobs - 1; - mtctx->bufPool = ZSTDMT_createBufferPool(nbWorkers, cMem); + mtctx->bufPool = ZSTDMT_createBufferPool(BUF_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); mtctx->cctxPool = ZSTDMT_createCCtxPool(nbWorkers, cMem); mtctx->seqPool = ZSTDMT_createSeqPool(nbWorkers, cMem); initError = ZSTDMT_serialState_init(&mtctx->serial); @@ -903,22 +957,18 @@ MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers, return mtctx; } -ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem) +ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool) { #ifdef ZSTD_MULTITHREAD - return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem); + return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem, pool); #else (void)nbWorkers; (void)cMem; + (void)pool; return NULL; #endif } -ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers) -{ - return ZSTDMT_createCCtx_advanced(nbWorkers, ZSTD_defaultCMem); -} - /* ZSTDMT_releaseAllJobResources() : * note : ensure all workers are killed first ! */ @@ -935,7 +985,7 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); /* Clear the job description, but keep the mutex/cond */ - memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); + ZSTD_memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); mtctx->jobs[jobID].job_mutex = mutex; mtctx->jobs[jobID].job_cond = cond; } @@ -962,7 +1012,8 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx) size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) { if (mtctx==NULL) return 0; /* compatible with free on NULL */ - POOL_free(mtctx->factory); /* stop and free worker threads */ + if (!mtctx->providedFactory) + POOL_free(mtctx->factory); /* stop and free worker threads */ ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */ ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem); ZSTDMT_freeBufferPool(mtctx->bufPool); @@ -971,8 +1022,8 @@ size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) ZSTDMT_serialState_free(&mtctx->serial); ZSTD_freeCDict(mtctx->cdictLocal); if (mtctx->roundBuff.buffer) - ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem); - ZSTD_free(mtctx, mtctx->cMem); + ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); + ZSTD_customFree(mtctx, mtctx->cMem); return 0; } @@ -989,73 +1040,14 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx) + mtctx->roundBuff.capacity; } -/* Internal only */ -size_t -ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, - ZSTDMT_parameter parameter, - int value) -{ - DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter"); - switch(parameter) - { - case ZSTDMT_p_jobSize : - DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter : set jobSize to %i", value); - return ZSTD_CCtxParams_setParameter(params, ZSTD_c_jobSize, value); - case ZSTDMT_p_overlapLog : - DEBUGLOG(4, "ZSTDMT_p_overlapLog : %i", value); - return ZSTD_CCtxParams_setParameter(params, ZSTD_c_overlapLog, value); - case ZSTDMT_p_rsyncable : - DEBUGLOG(4, "ZSTD_p_rsyncable : %i", value); - return ZSTD_CCtxParams_setParameter(params, ZSTD_c_rsyncable, value); - default : - return ERROR(parameter_unsupported); - } -} - -size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value) -{ - DEBUGLOG(4, "ZSTDMT_setMTCtxParameter"); - return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value); -} - -size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value) -{ - switch (parameter) { - case ZSTDMT_p_jobSize: - return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_jobSize, value); - case ZSTDMT_p_overlapLog: - return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_overlapLog, value); - case ZSTDMT_p_rsyncable: - return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_rsyncable, value); - default: - return ERROR(parameter_unsupported); - } -} - -/* Sets parameters relevant to the compression job, - * initializing others to default values. */ -static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(const ZSTD_CCtx_params* params) -{ - ZSTD_CCtx_params jobParams = *params; - /* Clear parameters related to multithreading */ - jobParams.forceWindow = 0; - jobParams.nbWorkers = 0; - jobParams.jobSize = 0; - jobParams.overlapLog = 0; - jobParams.rsyncable = 0; - memset(&jobParams.ldmParams, 0, sizeof(ldmParams_t)); - memset(&jobParams.customMem, 0, sizeof(ZSTD_customMem)); - return jobParams; -} - /* ZSTDMT_resize() : * @return : error code if fails, 0 on success */ static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers) { if (POOL_resize(mtctx->factory, nbWorkers)) return ERROR(memory_allocation); - FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbWorkers) ); - mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, nbWorkers); + FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbWorkers) , ""); + mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, BUF_POOL_MAX_NB_BUFFERS(nbWorkers)); if (mtctx->bufPool == NULL) return ERROR(memory_allocation); mtctx->cctxPool = ZSTDMT_expandCCtxPool(mtctx->cctxPool, nbWorkers); if (mtctx->cctxPool == NULL) return ERROR(memory_allocation); @@ -1076,7 +1068,7 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)", compressionLevel); mtctx->params.compressionLevel = compressionLevel; - { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, 0, 0); + { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); cParams.windowLog = saved_wlog; mtctx->params.cParams = cParams; } @@ -1160,11 +1152,11 @@ size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx) static unsigned ZSTDMT_computeTargetJobLog(const ZSTD_CCtx_params* params) { unsigned jobLog; - if (params->ldmParams.enableLdm) { + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* In Long Range Mode, the windowLog is typically oversized. * In which case, it's preferable to determine the jobSize - * based on chainLog instead. */ - jobLog = MAX(21, params->cParams.chainLog + 4); + * based on cycleLog instead. */ + jobLog = MAX(21, ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy) + 3); } else { jobLog = MAX(20, params->cParams.windowLog + 2); } @@ -1204,7 +1196,7 @@ static size_t ZSTDMT_computeOverlapSize(const ZSTD_CCtx_params* params) int const overlapRLog = 9 - ZSTDMT_overlapLog(params->overlapLog, params->cParams.strategy); int ovLog = (overlapRLog >= 8) ? 0 : (params->cParams.windowLog - overlapRLog); assert(0 <= overlapRLog && overlapRLog <= 8); - if (params->ldmParams.enableLdm) { + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* In Long Range Mode, the windowLog is typically oversized. * In which case, it's preferable to determine the jobSize * based on chainLog instead. @@ -1218,172 +1210,6 @@ static size_t ZSTDMT_computeOverlapSize(const ZSTD_CCtx_params* params) return (ovLog==0) ? 0 : (size_t)1 << ovLog; } -static unsigned -ZSTDMT_computeNbJobs(const ZSTD_CCtx_params* params, size_t srcSize, unsigned nbWorkers) -{ - assert(nbWorkers>0); - { size_t const jobSizeTarget = (size_t)1 << ZSTDMT_computeTargetJobLog(params); - size_t const jobMaxSize = jobSizeTarget << 2; - size_t const passSizeMax = jobMaxSize * nbWorkers; - unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1; - unsigned const nbJobsLarge = multiplier * nbWorkers; - unsigned const nbJobsMax = (unsigned)(srcSize / jobSizeTarget) + 1; - unsigned const nbJobsSmall = MIN(nbJobsMax, nbWorkers); - return (multiplier>1) ? nbJobsLarge : nbJobsSmall; -} } - -/* ZSTDMT_compress_advanced_internal() : - * This is a blocking function : it will only give back control to caller after finishing its compression job. - */ -static size_t ZSTDMT_compress_advanced_internal( - ZSTDMT_CCtx* mtctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params) -{ - ZSTD_CCtx_params const jobParams = ZSTDMT_initJobCCtxParams(¶ms); - size_t const overlapSize = ZSTDMT_computeOverlapSize(¶ms); - unsigned const nbJobs = ZSTDMT_computeNbJobs(¶ms, srcSize, params.nbWorkers); - size_t const proposedJobSize = (srcSize + (nbJobs-1)) / nbJobs; - size_t const avgJobSize = (((proposedJobSize-1) & 0x1FFFF) < 0x7FFF) ? proposedJobSize + 0xFFFF : proposedJobSize; /* avoid too small last block */ - const char* const srcStart = (const char*)src; - size_t remainingSrcSize = srcSize; - unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbJobs : (unsigned)(dstCapacity / ZSTD_compressBound(avgJobSize)); /* presumes avgJobSize >= 256 KB, which should be the case */ - size_t frameStartPos = 0, dstBufferPos = 0; - assert(jobParams.nbWorkers == 0); - assert(mtctx->cctxPool->totalCCtx == params.nbWorkers); - - params.jobSize = (U32)avgJobSize; - DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbJobs=%2u (rawSize=%u bytes; fixedSize=%u) ", - nbJobs, (U32)proposedJobSize, (U32)avgJobSize); - - if ((nbJobs==1) | (params.nbWorkers<=1)) { /* fallback to single-thread mode : this is a blocking invocation anyway */ - ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; - DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: fallback to single-thread mode"); - if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams); - return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, &jobParams); - } - - assert(avgJobSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), required to compress directly into Dst (no additional buffer) */ - ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgJobSize) ); - if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, avgJobSize)) - return ERROR(memory_allocation); - - FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbJobs) ); /* only expands if necessary */ - - { unsigned u; - for (u=0; ujobs[u].prefix.start = srcStart + frameStartPos - dictSize; - mtctx->jobs[u].prefix.size = dictSize; - mtctx->jobs[u].src.start = srcStart + frameStartPos; - mtctx->jobs[u].src.size = jobSize; assert(jobSize > 0); /* avoid job.src.size == 0 */ - mtctx->jobs[u].consumed = 0; - mtctx->jobs[u].cSize = 0; - mtctx->jobs[u].cdict = (u==0) ? cdict : NULL; - mtctx->jobs[u].fullFrameSize = srcSize; - mtctx->jobs[u].params = jobParams; - /* do not calculate checksum within sections, but write it in header for first section */ - mtctx->jobs[u].dstBuff = dstBuffer; - mtctx->jobs[u].cctxPool = mtctx->cctxPool; - mtctx->jobs[u].bufPool = mtctx->bufPool; - mtctx->jobs[u].seqPool = mtctx->seqPool; - mtctx->jobs[u].serial = &mtctx->serial; - mtctx->jobs[u].jobID = u; - mtctx->jobs[u].firstJob = (u==0); - mtctx->jobs[u].lastJob = (u==nbJobs-1); - - DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u (%u bytes)", u, (U32)jobSize); - DEBUG_PRINTHEX(6, mtctx->jobs[u].prefix.start, 12); - POOL_add(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[u]); - - frameStartPos += jobSize; - dstBufferPos += dstBufferCapacity; - remainingSrcSize -= jobSize; - } } - - /* collect result */ - { size_t error = 0, dstPos = 0; - unsigned jobID; - for (jobID=0; jobIDjobs[jobID].job_mutex); - while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) { - DEBUGLOG(5, "waiting for jobCompleted signal from job %u", jobID); - ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex); - } - ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex); - DEBUGLOG(5, "ready to write job %u ", jobID); - - { size_t const cSize = mtctx->jobs[jobID].cSize; - if (ZSTD_isError(cSize)) error = cSize; - if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall); - if (jobID) { /* note : job 0 is written directly at dst, which is correct position */ - if (!error) - memmove((char*)dst + dstPos, mtctx->jobs[jobID].dstBuff.start, cSize); /* may overlap when job compressed within dst */ - if (jobID >= compressWithinDst) { /* job compressed into its own buffer, which must be released */ - DEBUGLOG(5, "releasing buffer %u>=%u", jobID, compressWithinDst); - ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); - } } - mtctx->jobs[jobID].dstBuff = g_nullBuffer; - mtctx->jobs[jobID].cSize = 0; - dstPos += cSize ; - } - } /* for (jobID=0; jobIDserial.xxhState); - if (dstPos + 4 > dstCapacity) { - error = ERROR(dstSize_tooSmall); - } else { - DEBUGLOG(4, "writing checksum : %08X \n", checksum); - MEM_writeLE32((char*)dst + dstPos, checksum); - dstPos += 4; - } } - - if (!error) DEBUGLOG(4, "compressed size : %u ", (U32)dstPos); - return error ? error : dstPos; - } -} - -size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, - ZSTD_parameters params, - int overlapLog) -{ - ZSTD_CCtx_params cctxParams = mtctx->params; - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; - assert(ZSTD_OVERLAPLOG_MIN <= overlapLog && overlapLog <= ZSTD_OVERLAPLOG_MAX); - cctxParams.overlapLog = overlapLog; - return ZSTDMT_compress_advanced_internal(mtctx, - dst, dstCapacity, - src, srcSize, - cdict, cctxParams); -} - - -size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - int compressionLevel) -{ - ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, 0); - int const overlapLog = ZSTDMT_overlapLog_default(params.cParams.strategy); - params.fParams.contentSizeFlag = 1; - return ZSTDMT_compress_advanced(mtctx, dst, dstCapacity, src, srcSize, NULL, params, overlapLog); -} - - /* ====================================== */ /* ======= Streaming API ======= */ /* ====================================== */ @@ -1403,21 +1229,11 @@ size_t ZSTDMT_initCStream_internal( /* init */ if (params.nbWorkers != mtctx->params.nbWorkers) - FORWARD_IF_ERROR( ZSTDMT_resize(mtctx, params.nbWorkers) ); + FORWARD_IF_ERROR( ZSTDMT_resize(mtctx, params.nbWorkers) , ""); if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN; if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = (size_t)ZSTDMT_JOBSIZE_MAX; - mtctx->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */ - if (mtctx->singleBlockingThread) { - ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(¶ms); - DEBUGLOG(5, "ZSTDMT_initCStream_internal: switch to single blocking thread mode"); - assert(singleThreadParams.nbWorkers == 0); - return ZSTD_initCStream_internal(mtctx->cctxPool->cctx[0], - dict, dictSize, cdict, - &singleThreadParams, pledgedSrcSize); - } - DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers); if (mtctx->allJobsCompleted == 0) { /* previous compression not correctly finished */ @@ -1451,9 +1267,11 @@ size_t ZSTDMT_initCStream_internal( if (params.rsyncable) { /* Aim for the targetsectionSize as the average job size. */ - U32 const jobSizeMB = (U32)(mtctx->targetSectionSize >> 20); - U32 const rsyncBits = ZSTD_highbit32(jobSizeMB) + 20; - assert(jobSizeMB >= 1); + U32 const jobSizeKB = (U32)(mtctx->targetSectionSize >> 10); + U32 const rsyncBits = (assert(jobSizeKB >= 1), ZSTD_highbit32(jobSizeKB) + 10); + /* We refuse to create jobs < RSYNC_MIN_BLOCK_SIZE bytes, so make sure our + * expected job size is at least 4x larger. */ + assert(rsyncBits >= RSYNC_MIN_BLOCK_LOG + 2); DEBUGLOG(4, "rsyncLog = %u", rsyncBits); mtctx->rsync.hash = 0; mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1; @@ -1465,7 +1283,7 @@ size_t ZSTDMT_initCStream_internal( ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize)); { /* If ldm is enabled we need windowSize space. */ - size_t const windowSize = mtctx->params.ldmParams.enableLdm ? (1U << mtctx->params.cParams.windowLog) : 0; + size_t const windowSize = mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable ? (1U << mtctx->params.cParams.windowLog) : 0; /* Two buffers of slack, plus extra space for the overlap * This is the minimum slack that LDM works with. One extra because * flush might waste up to targetSectionSize-1 bytes. Another extra @@ -1480,8 +1298,8 @@ size_t ZSTDMT_initCStream_internal( size_t const capacity = MAX(windowSize, sectionsSize) + slackSize; if (mtctx->roundBuff.capacity < capacity) { if (mtctx->roundBuff.buffer) - ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem); - mtctx->roundBuff.buffer = (BYTE*)ZSTD_malloc(capacity, mtctx->cMem); + ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); + mtctx->roundBuff.buffer = (BYTE*)ZSTD_customMalloc(capacity, mtctx->cMem); if (mtctx->roundBuff.buffer == NULL) { mtctx->roundBuff.capacity = 0; return ERROR(memory_allocation); @@ -1500,58 +1318,12 @@ size_t ZSTDMT_initCStream_internal( mtctx->allJobsCompleted = 0; mtctx->consumed = 0; mtctx->produced = 0; - if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize)) + if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize, + dict, dictSize, dictContentType)) return ERROR(memory_allocation); return 0; } -size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, - const void* dict, size_t dictSize, - ZSTD_parameters params, - unsigned long long pledgedSrcSize) -{ - ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */ - DEBUGLOG(4, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize); - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; - return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dct_auto, NULL, - cctxParams, pledgedSrcSize); -} - -size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, - const ZSTD_CDict* cdict, - ZSTD_frameParameters fParams, - unsigned long long pledgedSrcSize) -{ - ZSTD_CCtx_params cctxParams = mtctx->params; - if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ - cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict); - cctxParams.fParams = fParams; - return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dct_auto, cdict, - cctxParams, pledgedSrcSize); -} - - -/* ZSTDMT_resetCStream() : - * pledgedSrcSize can be zero == unknown (for the time being) - * prefer using ZSTD_CONTENTSIZE_UNKNOWN, - * as `0` might mean "empty" in the future */ -size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize) -{ - if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, 0, mtctx->params, - pledgedSrcSize); -} - -size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel) { - ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0); - ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */ - DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel); - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; - return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN); -} - /* ZSTDMT_writeLastEmptyBlock() * Write a single empty block with an end-of-frame to finish a frame. @@ -1714,9 +1486,11 @@ static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, u assert(mtctx->doneJobID < mtctx->nextJobID); assert(cSize >= mtctx->jobs[wJobID].dstFlushed); assert(mtctx->jobs[wJobID].dstBuff.start != NULL); - memcpy((char*)output->dst + output->pos, - (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed, - toFlush); + if (toFlush > 0) { + ZSTD_memcpy((char*)output->dst + output->pos, + (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed, + toFlush); + } output->pos += toFlush; mtctx->jobs[wJobID].dstFlushed += toFlush; /* can write : this value is only used by mtctx */ @@ -1784,17 +1558,21 @@ static range_t ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx) static int ZSTDMT_isOverlapped(buffer_t buffer, range_t range) { BYTE const* const bufferStart = (BYTE const*)buffer.start; - BYTE const* const bufferEnd = bufferStart + buffer.capacity; BYTE const* const rangeStart = (BYTE const*)range.start; - BYTE const* const rangeEnd = rangeStart + range.size; if (rangeStart == NULL || bufferStart == NULL) return 0; - /* Empty ranges cannot overlap */ - if (bufferStart == bufferEnd || rangeStart == rangeEnd) - return 0; - return bufferStart < rangeEnd && rangeStart < bufferEnd; + { + BYTE const* const bufferEnd = bufferStart + buffer.capacity; + BYTE const* const rangeEnd = rangeStart + range.size; + + /* Empty ranges cannot overlap */ + if (bufferStart == bufferEnd || rangeStart == rangeEnd) + return 0; + + return bufferStart < rangeEnd && rangeStart < bufferEnd; + } } static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window) @@ -1821,7 +1599,7 @@ static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window) static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, buffer_t buffer) { - if (mtctx->params.ldmParams.enableLdm) { + if (mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable) { ZSTD_pthread_mutex_t* mutex = &mtctx->serial.ldmWindowMutex; DEBUGLOG(5, "ZSTDMT_waitForLdmComplete"); DEBUGLOG(5, "source [0x%zx, 0x%zx)", @@ -1867,7 +1645,7 @@ static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx) return 0; } ZSTDMT_waitForLdmComplete(mtctx, buffer); - memmove(start, mtctx->inBuff.prefix.start, prefixSize); + ZSTD_memmove(start, mtctx->inBuff.prefix.start, prefixSize); mtctx->inBuff.prefix.start = start; mtctx->roundBuff.pos = prefixSize; } @@ -1924,6 +1702,11 @@ findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) if (!mtctx->params.rsyncable) /* Rsync is disabled. */ return syncPoint; + if (mtctx->inBuff.filled + input.size - input.pos < RSYNC_MIN_BLOCK_SIZE) + /* We don't emit synchronization points if it would produce too small blocks. + * We don't have enough input to find a synchronization point, so don't look. + */ + return syncPoint; if (mtctx->inBuff.filled + syncPoint.toLoad < RSYNC_LENGTH) /* Not enough to compute the hash. * We will miss any synchronization points in this RSYNC_LENGTH byte @@ -1934,23 +1717,41 @@ findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) */ return syncPoint; /* Initialize the loop variables. */ - if (mtctx->inBuff.filled >= RSYNC_LENGTH) { - /* We have enough bytes buffered to initialize the hash. + if (mtctx->inBuff.filled < RSYNC_MIN_BLOCK_SIZE) { + /* We don't need to scan the first RSYNC_MIN_BLOCK_SIZE positions + * because they can't possibly be a sync point. So we can start + * part way through the input buffer. + */ + pos = RSYNC_MIN_BLOCK_SIZE - mtctx->inBuff.filled; + if (pos >= RSYNC_LENGTH) { + prev = istart + pos - RSYNC_LENGTH; + hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); + } else { + assert(mtctx->inBuff.filled >= RSYNC_LENGTH); + prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; + hash = ZSTD_rollingHash_compute(prev + pos, (RSYNC_LENGTH - pos)); + hash = ZSTD_rollingHash_append(hash, istart, pos); + } + } else { + /* We have enough bytes buffered to initialize the hash, + * and have processed enough bytes to find a sync point. * Start scanning at the beginning of the input. */ + assert(mtctx->inBuff.filled >= RSYNC_MIN_BLOCK_SIZE); + assert(RSYNC_MIN_BLOCK_SIZE >= RSYNC_LENGTH); pos = 0; prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); - } else { - /* We don't have enough bytes buffered to initialize the hash, but - * we know we have at least RSYNC_LENGTH bytes total. - * Start scanning after the first RSYNC_LENGTH bytes less the bytes - * already buffered. - */ - pos = RSYNC_LENGTH - mtctx->inBuff.filled; - prev = (BYTE const*)mtctx->inBuff.buffer.start - pos; - hash = ZSTD_rollingHash_compute(mtctx->inBuff.buffer.start, mtctx->inBuff.filled); - hash = ZSTD_rollingHash_append(hash, istart, pos); + if ((hash & hitMask) == hitMask) { + /* We're already at a sync point so don't load any more until + * we're able to flush this sync point. + * This likely happened because the job table was full so we + * couldn't add our job. + */ + syncPoint.toLoad = 0; + syncPoint.flush = 1; + return syncPoint; + } } /* Starting with the hash of the previous RSYNC_LENGTH bytes, roll * through the input. If we hit a synchronization point, then cut the @@ -1960,16 +1761,24 @@ findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) * then a block will be emitted anyways, but this is okay, since if we * are already synchronized we will remain synchronized. */ + assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); for (; pos < syncPoint.toLoad; ++pos) { BYTE const toRemove = pos < RSYNC_LENGTH ? prev[pos] : istart[pos - RSYNC_LENGTH]; - /* if (pos >= RSYNC_LENGTH) assert(ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); */ + /* This assert is very expensive, and Debian compiles with asserts enabled. + * So disable it for now. We can get similar coverage by checking it at the + * beginning & end of the loop. + * assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); + */ hash = ZSTD_rollingHash_rotate(hash, toRemove, istart[pos], primePower); + assert(mtctx->inBuff.filled + pos >= RSYNC_MIN_BLOCK_SIZE); if ((hash & hitMask) == hitMask) { syncPoint.toLoad = pos + 1; syncPoint.flush = 1; + ++pos; /* for assert */ break; } } + assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); return syncPoint; } @@ -1995,34 +1804,11 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, assert(output->pos <= output->size); assert(input->pos <= input->size); - if (mtctx->singleBlockingThread) { /* delegate to single-thread (synchronous) */ - return ZSTD_compressStream2(mtctx->cctxPool->cctx[0], output, input, endOp); - } - if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { /* current frame being ended. Only flush/end are allowed */ return ERROR(stage_wrong); } - /* single-pass shortcut (note : synchronous-mode) */ - if ( (!mtctx->params.rsyncable) /* rsyncable mode is disabled */ - && (mtctx->nextJobID == 0) /* just started */ - && (mtctx->inBuff.filled == 0) /* nothing buffered */ - && (!mtctx->jobReady) /* no job already created */ - && (endOp == ZSTD_e_end) /* end order */ - && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough space in dst */ - size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx, - (char*)output->dst + output->pos, output->size - output->pos, - (const char*)input->src + input->pos, input->size - input->pos, - mtctx->cdict, mtctx->params); - if (ZSTD_isError(cSize)) return cSize; - input->pos = input->size; - output->pos += cSize; - mtctx->allJobsCompleted = 1; - mtctx->frameEnded = 1; - return 0; - } - /* fill input buffer */ if ( (!mtctx->jobReady) && (input->size > input->pos) ) { /* support NULL input */ @@ -2045,13 +1831,21 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize); DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u", (U32)syncPoint.toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize); - memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad); + ZSTD_memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad); input->pos += syncPoint.toLoad; mtctx->inBuff.filled += syncPoint.toLoad; forwardInputProgress = syncPoint.toLoad>0; } - if ((input->pos < input->size) && (endOp == ZSTD_e_end)) - endOp = ZSTD_e_flush; /* can't end now : not all input consumed */ + } + if ((input->pos < input->size) && (endOp == ZSTD_e_end)) { + /* Can't end yet because the input is not fully consumed. + * We are in one of these cases: + * - mtctx->inBuff is NULL & empty: we couldn't get an input buffer so don't create a new job. + * - We filled the input buffer: flush this job but don't end the frame. + * - We hit a synchronization point: flush this job but don't end the frame. + */ + assert(mtctx->inBuff.filled == 0 || mtctx->inBuff.filled == mtctx->targetSectionSize || mtctx->params.rsyncable); + endOp = ZSTD_e_flush; } if ( (mtctx->jobReady) @@ -2060,7 +1854,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, || ((endOp == ZSTD_e_end) && (!mtctx->frameEnded)) ) { /* must finish the frame with a zero-size block */ size_t const jobSize = mtctx->inBuff.filled; assert(mtctx->inBuff.filled <= mtctx->targetSectionSize); - FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) ); + FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) , ""); } /* check for potential compressed data ready to be flushed */ @@ -2070,47 +1864,3 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, return remainingToFlush; } } - - -size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input) -{ - FORWARD_IF_ERROR( ZSTDMT_compressStream_generic(mtctx, output, input, ZSTD_e_continue) ); - - /* recommended next input size : fill current input buffer */ - return mtctx->targetSectionSize - mtctx->inBuff.filled; /* note : could be zero when input buffer is fully filled and no more availability to create new job */ -} - - -static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_EndDirective endFrame) -{ - size_t const srcSize = mtctx->inBuff.filled; - DEBUGLOG(5, "ZSTDMT_flushStream_internal"); - - if ( mtctx->jobReady /* one job ready for a worker to pick up */ - || (srcSize > 0) /* still some data within input buffer */ - || ((endFrame==ZSTD_e_end) && !mtctx->frameEnded)) { /* need a last 0-size block to end frame */ - DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job (%u bytes, end:%u)", - (U32)srcSize, (U32)endFrame); - FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) ); - } - - /* check if there is any data available to flush */ - return ZSTDMT_flushProduced(mtctx, output, 1 /* blockToFlush */, endFrame); -} - - -size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output) -{ - DEBUGLOG(5, "ZSTDMT_flushStream"); - if (mtctx->singleBlockingThread) - return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output); - return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_flush); -} - -size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output) -{ - DEBUGLOG(4, "ZSTDMT_endStream"); - if (mtctx->singleBlockingThread) - return ZSTD_endStream(mtctx->cctxPool->cctx[0], output); - return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_end); -} diff --git a/native/zstd/compress/zstdmt_compress.h b/native/zstd/compress/zstdmt_compress.h old mode 100755 new mode 100644 index 12a5260..271eb1a --- a/native/zstd/compress/zstdmt_compress.h +++ b/native/zstd/compress/zstdmt_compress.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -19,113 +19,60 @@ /* Note : This is an internal API. * These APIs used to be exposed with ZSTDLIB_API, * because it used to be the only way to invoke MT compression. - * Now, it's recommended to use ZSTD_compress2 and ZSTD_compressStream2() - * instead. - * - * If you depend on these APIs and can't switch, then define - * ZSTD_LEGACY_MULTITHREADED_API when making the dynamic library. - * However, we may completely remove these functions in a future - * release, so please switch soon. + * Now, you must use ZSTD_compress2 and ZSTD_compressStream2() instead. * * This API requires ZSTD_MULTITHREAD to be defined during compilation, * otherwise ZSTDMT_createCCtx*() will fail. */ -#ifdef ZSTD_LEGACY_MULTITHREADED_API -# define ZSTDMT_API ZSTDLIB_API -#else -# define ZSTDMT_API -#endif - /* === Dependencies === */ -#include /* size_t */ +#include "../common/zstd_deps.h" /* size_t */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */ -#include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ +#include "../zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ /* === Constants === */ -#ifndef ZSTDMT_NBWORKERS_MAX -# define ZSTDMT_NBWORKERS_MAX 200 +#ifndef ZSTDMT_NBWORKERS_MAX /* a different value can be selected at compile time */ +# define ZSTDMT_NBWORKERS_MAX ((sizeof(void*)==4) /*32-bit*/ ? 64 : 256) #endif -#ifndef ZSTDMT_JOBSIZE_MIN -# define ZSTDMT_JOBSIZE_MIN (1 MB) +#ifndef ZSTDMT_JOBSIZE_MIN /* a different value can be selected at compile time */ +# define ZSTDMT_JOBSIZE_MIN (512 KB) #endif #define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30) #define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB)) +/* ======================================================== + * === Private interface, for use by ZSTD_compress.c === + * === Not exposed in libzstd. Never invoke directly === + * ======================================================== */ + /* === Memory management === */ typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx; /* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */ -ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers); -/* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */ -ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, - ZSTD_customMem cMem); -ZSTDMT_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); - -ZSTDMT_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); - - -/* === Simple one-pass compression function === */ - -ZSTDMT_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - int compressionLevel); - +ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, + ZSTD_customMem cMem, + ZSTD_threadPool *pool); +size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); +size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); /* === Streaming functions === */ -ZSTDMT_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel); -ZSTDMT_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it will change in the future to mean "empty" */ - -ZSTDMT_API size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx); -ZSTDMT_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input); - -ZSTDMT_API size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */ -ZSTDMT_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */ - - -/* === Advanced functions and parameters === */ - -ZSTDMT_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, - ZSTD_parameters params, - int overlapLog); - -ZSTDMT_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, - const void* dict, size_t dictSize, /* dict can be released after init, a local copy is preserved within zcs */ - ZSTD_parameters params, - unsigned long long pledgedSrcSize); /* pledgedSrcSize is optional and can be zero == unknown */ - -ZSTDMT_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, - const ZSTD_CDict* cdict, - ZSTD_frameParameters fparams, - unsigned long long pledgedSrcSize); /* note : zero means empty */ - -/* ZSTDMT_parameter : - * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */ -typedef enum { - ZSTDMT_p_jobSize, /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */ - ZSTDMT_p_overlapLog, /* Each job may reload a part of previous job to enhance compression ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window. This is a "sticky" parameter : its value will be re-used on next compression job */ - ZSTDMT_p_rsyncable /* Enables rsyncable mode. */ -} ZSTDMT_parameter; - -/* ZSTDMT_setMTCtxParameter() : - * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter. - * The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__ - * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions. - * @return : 0, or an error code (which can be tested using ZSTD_isError()) */ -ZSTDMT_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value); - -/* ZSTDMT_getMTCtxParameter() : - * Query the ZSTDMT_CCtx for a parameter value. - * @return : 0, or an error code (which can be tested using ZSTD_isError()) */ -ZSTDMT_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value); +size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx); +/*! ZSTDMT_initCStream_internal() : + * Private use only. Init streaming operation. + * expects params to be valid. + * must receive dict, or cdict, or none, but not both. + * mtctx can be freshly constructed or reused from a prior compression. + * If mtctx is reused, memory allocations from the prior compression may not be freed, + * even if they are not needed for the current compression. + * @return : 0, or an error code */ +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* mtctx, + const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); /*! ZSTDMT_compressStream_generic() : * Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream() @@ -134,16 +81,10 @@ ZSTDMT_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter * 0 if fully flushed * or an error code * note : needs to be init using any ZSTD_initCStream*() variant */ -ZSTDMT_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, - ZSTD_outBuffer* output, - ZSTD_inBuffer* input, - ZSTD_EndDirective endOp); - - -/* ======================================================== - * === Private interface, for use by ZSTD_compress.c === - * === Not exposed in libzstd. Never invoke directly === - * ======================================================== */ +size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); /*! ZSTDMT_toFlushNow() * Tell how many bytes are ready to be flushed immediately. @@ -153,15 +94,6 @@ ZSTDMT_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, * therefore flushing is limited by speed of oldest job. */ size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx); -/*! ZSTDMT_CCtxParam_setMTCtxParameter() - * like ZSTDMT_setMTCtxParameter(), but into a ZSTD_CCtx_Params */ -size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, int value); - -/*! ZSTDMT_CCtxParam_setNbWorkers() - * Set nbWorkers, and clamp it. - * Also reset jobSize and overlapLog */ -size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers); - /*! ZSTDMT_updateCParams_whileCompressing() : * Updates only a selected set of compression parameters, to remain compatible with current frame. * New parameters will be applied to next compression job. */ @@ -174,17 +106,6 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx); -/*! ZSTDMT_initCStream_internal() : - * Private use only. Init streaming operation. - * expects params to be valid. - * must receive dict, or cdict, or none, but not both. - * @return : 0, or an error code */ -size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, - const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); - - #if defined (__cplusplus) } #endif diff --git a/native/zstd/decompress/huf_decompress.c b/native/zstd/decompress/huf_decompress.c old mode 100755 new mode 100644 index bb2d0a9..c6fd928 --- a/native/zstd/decompress/huf_decompress.c +++ b/native/zstd/decompress/huf_decompress.c @@ -1,47 +1,35 @@ /* ****************************************************************** - huff0 huffman decoder, - part of Finite State Entropy library - Copyright (C) 2013-present, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * huff0 huffman decoder, + * part of Finite State Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * 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. ****************************************************************** */ /* ************************************************************** * Dependencies ****************************************************************/ -#include /* memcpy, memset */ -#include "compiler.h" -#include "bitstream.h" /* BIT_* */ -#include "fse.h" /* to compress headers */ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include "../common/compiler.h" +#include "../common/bitstream.h" /* BIT_* */ +#include "../common/fse.h" /* to compress headers */ #define HUF_STATIC_LINKING_ONLY -#include "huf.h" -#include "error_private.h" +#include "../common/huf.h" +#include "../common/error_private.h" +#include "../common/zstd_internal.h" +#include "../common/bits.h" /* ZSTD_highbit32, ZSTD_countTrailingZeros64 */ + +/* ************************************************************** +* Constants +****************************************************************/ + +#define HUF_DECODER_FAST_TABLELOG 11 /* ************************************************************** * Macros @@ -56,14 +44,35 @@ #error "Cannot force the use of the X1 and X2 decoders at the same time!" #endif +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && DYNAMIC_BMI2 +# define HUF_ASM_X86_64_BMI2_ATTRS BMI2_TARGET_ATTRIBUTE +#else +# define HUF_ASM_X86_64_BMI2_ATTRS +#endif + +#ifdef __cplusplus +# define HUF_EXTERN_C extern "C" +#else +# define HUF_EXTERN_C +#endif +#define HUF_ASM_DECL HUF_EXTERN_C + +#if DYNAMIC_BMI2 || (ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__)) +# define HUF_NEED_BMI2_FUNCTION 1 +#else +# define HUF_NEED_BMI2_FUNCTION 0 +#endif + +#if !(ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__)) +# define HUF_NEED_DEFAULT_FUNCTION 1 +#else +# define HUF_NEED_DEFAULT_FUNCTION 0 +#endif /* ************************************************************** * Error Management ****************************************************************/ #define HUF_isError ERR_isError -#ifndef CHECK_F -#define CHECK_F(f) { size_t const err_ = (f); if (HUF_isError(err_)) return err_; } -#endif /* ************************************************************** @@ -88,7 +97,7 @@ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ } \ \ - static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \ + static BMI2_TARGET_ATTRIBUTE size_t fn##_bmi2( \ void* dst, size_t dstSize, \ const void* cSrc, size_t cSrcSize, \ const HUF_DTable* DTable) \ @@ -126,82 +135,350 @@ typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) { DTableDesc dtd; - memcpy(&dtd, table, sizeof(dtd)); + ZSTD_memcpy(&dtd, table, sizeof(dtd)); return dtd; } +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +static size_t HUF_initDStream(BYTE const* ip) { + BYTE const lastByte = ip[7]; + size_t const bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; + size_t const value = MEM_readLEST(ip) | 1; + assert(bitsConsumed <= 8); + return value << bitsConsumed; +} +typedef struct { + BYTE const* ip[4]; + BYTE* op[4]; + U64 bits[4]; + void const* dt; + BYTE const* ilimit; + BYTE* oend; + BYTE const* iend[4]; +} HUF_DecompressAsmArgs; + +/** + * Initializes args for the asm decoding loop. + * @returns 0 on success + * 1 if the fallback implementation should be used. + * Or an error code on failure. + */ +static size_t HUF_DecompressAsmArgs_init(HUF_DecompressAsmArgs* args, void* dst, size_t dstSize, void const* src, size_t srcSize, const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; + + const BYTE* const ilimit = (const BYTE*)src + 6 + 8; + + BYTE* const oend = (BYTE*)dst + dstSize; + + /* The following condition is false on x32 platform, + * but HUF_asm is not compatible with this ABI */ + if (!(MEM_isLittleEndian() && !MEM_32bits())) return 1; + + /* strict minimum : jump table + 1 byte per stream */ + if (srcSize < 10) + return ERROR(corruption_detected); + + /* Must have at least 8 bytes per stream because we don't handle initializing smaller bit containers. + * If table log is not correct at this point, fallback to the old decoder. + * On small inputs we don't have enough data to trigger the fast loop, so use the old decoder. + */ + if (dtLog != HUF_DECODER_FAST_TABLELOG) + return 1; + + /* Read the jump table. */ + { + const BYTE* const istart = (const BYTE*)src; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = srcSize - (length1 + length2 + length3 + 6); + args->iend[0] = istart + 6; /* jumpTable */ + args->iend[1] = args->iend[0] + length1; + args->iend[2] = args->iend[1] + length2; + args->iend[3] = args->iend[2] + length3; + + /* HUF_initDStream() requires this, and this small of an input + * won't benefit from the ASM loop anyways. + * length1 must be >= 16 so that ip[0] >= ilimit before the loop + * starts. + */ + if (length1 < 16 || length2 < 8 || length3 < 8 || length4 < 8) + return 1; + if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ + } + /* ip[] contains the position that is currently loaded into bits[]. */ + args->ip[0] = args->iend[1] - sizeof(U64); + args->ip[1] = args->iend[2] - sizeof(U64); + args->ip[2] = args->iend[3] - sizeof(U64); + args->ip[3] = (BYTE const*)src + srcSize - sizeof(U64); + + /* op[] contains the output pointers. */ + args->op[0] = (BYTE*)dst; + args->op[1] = args->op[0] + (dstSize+3)/4; + args->op[2] = args->op[1] + (dstSize+3)/4; + args->op[3] = args->op[2] + (dstSize+3)/4; + + /* No point to call the ASM loop for tiny outputs. */ + if (args->op[3] >= oend) + return 1; + + /* bits[] is the bit container. + * It is read from the MSB down to the LSB. + * It is shifted left as it is read, and zeros are + * shifted in. After the lowest valid bit a 1 is + * set, so that CountTrailingZeros(bits[]) can be used + * to count how many bits we've consumed. + */ + args->bits[0] = HUF_initDStream(args->ip[0]); + args->bits[1] = HUF_initDStream(args->ip[1]); + args->bits[2] = HUF_initDStream(args->ip[2]); + args->bits[3] = HUF_initDStream(args->ip[3]); + + /* If ip[] >= ilimit, it is guaranteed to be safe to + * reload bits[]. It may be beyond its section, but is + * guaranteed to be valid (>= istart). + */ + args->ilimit = ilimit; + + args->oend = oend; + args->dt = dt; + + return 0; +} + +static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressAsmArgs const* args, int stream, BYTE* segmentEnd) +{ + /* Validate that we haven't overwritten. */ + if (args->op[stream] > segmentEnd) + return ERROR(corruption_detected); + /* Validate that we haven't read beyond iend[]. + * Note that ip[] may be < iend[] because the MSB is + * the next bit to read, and we may have consumed 100% + * of the stream, so down to iend[i] - 8 is valid. + */ + if (args->ip[stream] < args->iend[stream] - 8) + return ERROR(corruption_detected); + + /* Construct the BIT_DStream_t. */ + assert(sizeof(size_t) == 8); + bit->bitContainer = MEM_readLE64(args->ip[stream]); + bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]); + bit->start = (const char*)args->iend[0]; + bit->limitPtr = bit->start + sizeof(size_t); + bit->ptr = (const char*)args->ip[stream]; + + return 0; +} +#endif + #ifndef HUF_FORCE_DECOMPRESS_X2 /*-***************************/ /* single-symbol decoding */ /*-***************************/ -typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* single-symbol decoding */ +typedef struct { BYTE nbBits; BYTE byte; } HUF_DEltX1; /* single-symbol decoding */ + +/** + * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at + * a time. + */ +static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) { + U64 D4; + if (MEM_isLittleEndian()) { + D4 = (symbol << 8) + nbBits; + } else { + D4 = symbol + (nbBits << 8); + } + D4 *= 0x0001000100010001ULL; + return D4; +} + +/** + * Increase the tableLog to targetTableLog and rescales the stats. + * If tableLog > targetTableLog this is a no-op. + * @returns New tableLog + */ +static U32 HUF_rescaleStats(BYTE* huffWeight, U32* rankVal, U32 nbSymbols, U32 tableLog, U32 targetTableLog) +{ + if (tableLog > targetTableLog) + return tableLog; + if (tableLog < targetTableLog) { + U32 const scale = targetTableLog - tableLog; + U32 s; + /* Increase the weight for all non-zero probability symbols by scale. */ + for (s = 0; s < nbSymbols; ++s) { + huffWeight[s] += (BYTE)((huffWeight[s] == 0) ? 0 : scale); + } + /* Update rankVal to reflect the new weights. + * All weights except 0 get moved to weight + scale. + * Weights [1, scale] are empty. + */ + for (s = targetTableLog; s > scale; --s) { + rankVal[s] = rankVal[s - scale]; + } + for (s = scale; s > 0; --s) { + rankVal[s] = 0; + } + } + return targetTableLog; +} + +typedef struct { + U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + BYTE symbols[HUF_SYMBOLVALUE_MAX + 1]; + BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; +} HUF_ReadDTableX1_Workspace; + size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) +{ + return HUF_readDTableX1_wksp_bmi2(DTable, src, srcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + +size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2) { U32 tableLog = 0; U32 nbSymbols = 0; size_t iSize; void* const dtPtr = DTable + 1; HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr; + HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace; - U32* rankVal; - BYTE* huffWeight; - size_t spaceUsed32 = 0; - - rankVal = (U32 *)workSpace + spaceUsed32; - spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1; - huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32); - spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; - - if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); + DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp)); + if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge); DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); - /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); + iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), bmi2); if (HUF_isError(iSize)) return iSize; + /* Table header */ { DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 const maxTableLog = dtd.maxTableLog + 1; + U32 const targetTableLog = MIN(maxTableLog, HUF_DECODER_FAST_TABLELOG); + tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog); if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ dtd.tableType = 0; dtd.tableLog = (BYTE)tableLog; - memcpy(DTable, &dtd, sizeof(dtd)); + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); } - /* Calculate starting value for each rank */ - { U32 n, nextRankStart = 0; - for (n=1; n> 1; - U32 u; - HUF_DEltX1 D; - D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w); - for (u = rankVal[w]; u < rankVal[w] + length; u++) - dt[u] = D; - rankVal[w] += length; - } } + /* Compute symbols and rankStart given rankVal: + * + * rankVal already contains the number of values of each weight. + * + * symbols contains the symbols ordered by weight. First are the rankVal[0] + * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on. + * symbols[0] is filled (but unused) to avoid a branch. + * + * rankStart contains the offset where each rank belongs in the DTable. + * rankStart[0] is not filled because there are no entries in the table for + * weight 0. + */ + { + int n; + int nextRankStart = 0; + int const unroll = 4; + int const nLimit = (int)nbSymbols - unroll + 1; + for (n=0; n<(int)tableLog+1; n++) { + U32 const curr = nextRankStart; + nextRankStart += wksp->rankVal[n]; + wksp->rankStart[n] = curr; + } + for (n=0; n < nLimit; n += unroll) { + int u; + for (u=0; u < unroll; ++u) { + size_t const w = wksp->huffWeight[n+u]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u); + } + } + for (; n < (int)nbSymbols; ++n) { + size_t const w = wksp->huffWeight[n]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)n; + } + } + /* fill DTable + * We fill all entries of each weight in order. + * That way length is a constant for each iteration of the outer loop. + * We can switch based on the length to a different inner loop which is + * optimized for that particular case. + */ + { + U32 w; + int symbol=wksp->rankVal[0]; + int rankStart=0; + for (w=1; wrankVal[w]; + int const length = (1 << w) >> 1; + int uStart = rankStart; + BYTE const nbBits = (BYTE)(tableLog + 1 - w); + int s; + int u; + switch (length) { + case 1: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart] = D; + uStart += 1; + } + break; + case 2: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart+0] = D; + dt[uStart+1] = D; + uStart += 2; + } + break; + case 4: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + uStart += 4; + } + break; + case 8: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + MEM_write64(dt + uStart + 4, D4); + uStart += 8; + } + break; + default: + for (s=0; ssymbols[symbol + s], nbBits); + for (u=0; u < length; u += 16) { + MEM_write64(dt + uStart + u + 0, D4); + MEM_write64(dt + uStart + u + 4, D4); + MEM_write64(dt + uStart + u + 8, D4); + MEM_write64(dt + uStart + u + 12, D4); + } + assert(u == length); + uStart += length; + } + break; + } + symbol += symbolCount; + rankStart += symbolCount * length; + } + } return iSize; } -size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_readDTableX1_wksp(DTable, src, srcSize, - workSpace, sizeof(workSpace)); -} - FORCE_INLINE_TEMPLATE BYTE HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog) { @@ -228,11 +505,15 @@ HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, cons BYTE* const pStart = p; /* up to 4 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_1(p, bitDPtr); - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + if ((pEnd - p) > 3) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_1(p, bitDPtr); + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + } + } else { + BIT_reloadDStream(bitDPtr); } /* [0-3] symbols remaining */ @@ -282,6 +563,7 @@ HUF_decompress4X1_usingDTable_internal_body( { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - 3; const void* const dtPtr = DTable + 1; const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; @@ -306,39 +588,41 @@ HUF_decompress4X1_usingDTable_internal_body( BYTE* op2 = opStart2; BYTE* op3 = opStart3; BYTE* op4 = opStart4; - U32 endSignal = BIT_DStream_unfinished; DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; + U32 endSignal = 1; if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */ - endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); - while ( (endSignal==BIT_DStream_unfinished) && (op4<(oend-3)) ) { - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_1(op1, &bitD1); - HUF_DECODE_SYMBOLX1_1(op2, &bitD2); - HUF_DECODE_SYMBOLX1_1(op3, &bitD3); - HUF_DECODE_SYMBOLX1_1(op4, &bitD4); - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_0(op1, &bitD1); - HUF_DECODE_SYMBOLX1_0(op2, &bitD2); - HUF_DECODE_SYMBOLX1_0(op3, &bitD3); - HUF_DECODE_SYMBOLX1_0(op4, &bitD4); - BIT_reloadDStream(&bitD1); - BIT_reloadDStream(&bitD2); - BIT_reloadDStream(&bitD3); - BIT_reloadDStream(&bitD4); + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit) ; ) { + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_1(op1, &bitD1); + HUF_DECODE_SYMBOLX1_1(op2, &bitD2); + HUF_DECODE_SYMBOLX1_1(op3, &bitD3); + HUF_DECODE_SYMBOLX1_1(op4, &bitD4); + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_0(op1, &bitD1); + HUF_DECODE_SYMBOLX1_0(op2, &bitD2); + HUF_DECODE_SYMBOLX1_0(op3, &bitD3); + HUF_DECODE_SYMBOLX1_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + } } /* check corruption */ @@ -364,6 +648,79 @@ HUF_decompress4X1_usingDTable_internal_body( } } +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if HUF_NEED_DEFAULT_FUNCTION +static +size_t HUF_decompress4X1_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop(HUF_DecompressAsmArgs* args) ZSTDLIB_HIDDEN; + +static HUF_ASM_X86_64_BMI2_ATTRS +size_t +HUF_decompress4X1_usingDTable_internal_bmi2_asm( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressAsmArgs args; + { + size_t const ret = HUF_DecompressAsmArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret != 0) + return HUF_decompress4X1_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); + } + + assert(args.ip[0] >= args.ilimit); + HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop(&args); + + /* Our loop guarantees that ip[] >= ilimit and that we haven't + * overwritten any op[]. + */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bit streams one by one. */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + /* Decompress and validate that we've produced exactly the expected length. */ + args.op[i] += HUF_decodeStreamX1(args.op[i], &bit, segmentEnd, (HUF_DEltX1 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} +#endif /* ZSTD_ENABLE_ASM_X86_64_BMI2 */ typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize, const void *cSrc, @@ -371,8 +728,28 @@ typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize, const HUF_DTable *DTable); HUF_DGEN(HUF_decompress1X1_usingDTable_internal) -HUF_DGEN(HUF_decompress4X1_usingDTable_internal) +static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + return HUF_decompress4X1_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +# else + return HUF_decompress4X1_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); +# endif + } +#else + (void)bmi2; +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + return HUF_decompress4X1_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +#else + return HUF_decompress4X1_usingDTable_internal_default(dst, dstSize, cSrc, cSrcSize, DTable); +#endif +} size_t HUF_decompress1X1_usingDTable( @@ -400,20 +777,6 @@ size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, } -size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - -size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); - return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize); -} - size_t HUF_decompress4X1_usingDTable( void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, @@ -430,8 +793,7 @@ static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize, - workSpace, wkspSize); + size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; @@ -447,18 +809,6 @@ size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, } -size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} -size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); - return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); -} - #endif /* HUF_FORCE_DECOMPRESS_X2 */ @@ -469,209 +819,329 @@ size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cS /* *************************/ typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */ -typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; +typedef struct { BYTE symbol; } sortedSymbol_t; typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; +/** + * Constructs a HUF_DEltX2 in a U32. + */ +static U32 HUF_buildDEltX2U32(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + U32 seq; + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, sequence) == 0); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, nbBits) == 2); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, length) == 3); + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U32)); + if (MEM_isLittleEndian()) { + seq = level == 1 ? symbol : (baseSeq + (symbol << 8)); + return seq + (nbBits << 16) + ((U32)level << 24); + } else { + seq = level == 1 ? (symbol << 8) : ((baseSeq << 8) + symbol); + return (seq << 16) + (nbBits << 8) + (U32)level; + } +} -/* HUF_fillDTableX2Level2() : - * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ -static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed, - const U32* rankValOrigin, const int minWeight, - const sortedSymbol_t* sortedSymbols, const U32 sortedListSize, - U32 nbBitsBaseline, U16 baseSeq) +/** + * Constructs a HUF_DEltX2. + */ +static HUF_DEltX2 HUF_buildDEltX2(U32 symbol, U32 nbBits, U32 baseSeq, int level) { HUF_DEltX2 DElt; - U32 rankVal[HUF_TABLELOG_MAX + 1]; + U32 const val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + DEBUG_STATIC_ASSERT(sizeof(DElt) == sizeof(val)); + ZSTD_memcpy(&DElt, &val, sizeof(val)); + return DElt; +} - /* get pre-calculated rankVal */ - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); +/** + * Constructs 2 HUF_DEltX2s and packs them into a U64. + */ +static U64 HUF_buildDEltX2U64(U32 symbol, U32 nbBits, U16 baseSeq, int level) +{ + U32 DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + return (U64)DElt + ((U64)DElt << 32); +} - /* fill skipped values */ - if (minWeight>1) { - U32 i, skipSize = rankVal[minWeight]; - MEM_writeLE16(&(DElt.sequence), baseSeq); - DElt.nbBits = (BYTE)(consumed); - DElt.length = 1; - for (i = 0; i < skipSize; i++) - DTable[i] = DElt; +/** + * Fills the DTable rank with all the symbols from [begin, end) that are each + * nbBits long. + * + * @param DTableRank The start of the rank in the DTable. + * @param begin The first symbol to fill (inclusive). + * @param end The last symbol to fill (exclusive). + * @param nbBits Each symbol is nbBits long. + * @param tableLog The table log. + * @param baseSeq If level == 1 { 0 } else { the first level symbol } + * @param level The level in the table. Must be 1 or 2. + */ +static void HUF_fillDTableX2ForWeight( + HUF_DEltX2* DTableRank, + sortedSymbol_t const* begin, sortedSymbol_t const* end, + U32 nbBits, U32 tableLog, + U16 baseSeq, int const level) +{ + U32 const length = 1U << ((tableLog - nbBits) & 0x1F /* quiet static-analyzer */); + const sortedSymbol_t* ptr; + assert(level >= 1 && level <= 2); + switch (length) { + case 1: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + *DTableRank++ = DElt; + } + break; + case 2: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + DTableRank[0] = DElt; + DTableRank[1] = DElt; + DTableRank += 2; + } + break; + case 4: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + DTableRank += 4; + } + break; + case 8: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + DTableRank += 8; + } + break; + default: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + HUF_DEltX2* const DTableRankEnd = DTableRank + length; + for (; DTableRank != DTableRankEnd; DTableRank += 8) { + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + } + } + break; } +} - /* fill DTable */ - { U32 s; for (s=0; s= 1 */ +/* HUF_fillDTableX2Level2() : + * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ +static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 targetLog, const U32 consumedBits, + const U32* rankVal, const int minWeight, const int maxWeight1, + const sortedSymbol_t* sortedSymbols, U32 const* rankStart, + U32 nbBitsBaseline, U16 baseSeq) +{ + /* Fill skipped values (all positions up to rankVal[minWeight]). + * These are positions only get a single symbol because the combined weight + * is too large. + */ + if (minWeight>1) { + U32 const length = 1U << ((targetLog - consumedBits) & 0x1F /* quiet static-analyzer */); + U64 const DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, /* baseSeq */ 0, /* level */ 1); + int const skipSize = rankVal[minWeight]; + assert(length > 1); + assert((U32)skipSize < length); + switch (length) { + case 2: + assert(skipSize == 1); + ZSTD_memcpy(DTable, &DEltX2, sizeof(DEltX2)); + break; + case 4: + assert(skipSize <= 4); + ZSTD_memcpy(DTable + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + 2, &DEltX2, sizeof(DEltX2)); + break; + default: + { + int i; + for (i = 0; i < skipSize; i += 8) { + ZSTD_memcpy(DTable + i + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 6, &DEltX2, sizeof(DEltX2)); + } + } + } + } - rankVal[weight] += length; - } } + /* Fill each of the second level symbols by weight. */ + { + int w; + for (w = minWeight; w < maxWeight1; ++w) { + int const begin = rankStart[w]; + int const end = rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + U32 const totalBits = nbBits + consumedBits; + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedSymbols + begin, sortedSymbols + end, + totalBits, targetLog, + baseSeq, /* level */ 2); + } + } } - static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog, - const sortedSymbol_t* sortedList, const U32 sortedListSize, + const sortedSymbol_t* sortedList, const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline) { - U32 rankVal[HUF_TABLELOG_MAX + 1]; + U32* const rankVal = rankValOrigin[0]; const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ const U32 minBits = nbBitsBaseline - maxWeight; - U32 s; - - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); - - /* fill DTable */ - for (s=0; s= minBits) { /* enough room for a second symbol */ - U32 sortedRank; + int w; + int const wEnd = (int)maxWeight + 1; + + /* Fill DTable in order of weight. */ + for (w = 1; w < wEnd; ++w) { + int const begin = (int)rankStart[w]; + int const end = (int)rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + + if (targetLog-nbBits >= minBits) { + /* Enough room for a second symbol. */ + int start = rankVal[w]; + U32 const length = 1U << ((targetLog - nbBits) & 0x1F /* quiet static-analyzer */); int minWeight = nbBits + scaleLog; + int s; if (minWeight < 1) minWeight = 1; - sortedRank = rankStart[minWeight]; - HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits, - rankValOrigin[nbBits], minWeight, - sortedList+sortedRank, sortedListSize-sortedRank, - nbBitsBaseline, symbol); + /* Fill the DTable for every symbol of weight w. + * These symbols get at least 1 second symbol. + */ + for (s = begin; s != end; ++s) { + HUF_fillDTableX2Level2( + DTable + start, targetLog, nbBits, + rankValOrigin[nbBits], minWeight, wEnd, + sortedList, rankStart, + nbBitsBaseline, sortedList[s].symbol); + start += length; + } } else { - HUF_DEltX2 DElt; - MEM_writeLE16(&(DElt.sequence), symbol); - DElt.nbBits = (BYTE)(nbBits); - DElt.length = 1; - { U32 const end = start + length; - U32 u; - for (u = start; u < end; u++) DTable[u] = DElt; - } } - rankVal[weight] += length; + /* Only a single symbol. */ + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedList + begin, sortedList + end, + nbBits, targetLog, + /* baseSeq */ 0, /* level */ 1); + } } } +typedef struct { + rankValCol_t rankVal[HUF_TABLELOG_MAX]; + U32 rankStats[HUF_TABLELOG_MAX + 1]; + U32 rankStart0[HUF_TABLELOG_MAX + 3]; + sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; + BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; + U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; +} HUF_ReadDTableX2_Workspace; + size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) { - U32 tableLog, maxW, sizeOfSort, nbSymbols; + return HUF_readDTableX2_wksp_bmi2(DTable, src, srcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + +size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, int bmi2) +{ + U32 tableLog, maxW, nbSymbols; DTableDesc dtd = HUF_getDTableDesc(DTable); - U32 const maxTableLog = dtd.maxTableLog; + U32 maxTableLog = dtd.maxTableLog; size_t iSize; void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; U32 *rankStart; - rankValCol_t* rankVal; - U32* rankStats; - U32* rankStart0; - sortedSymbol_t* sortedSymbol; - BYTE* weightList; - size_t spaceUsed32 = 0; - - rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32); - spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2; - rankStats = (U32 *)workSpace + spaceUsed32; - spaceUsed32 += HUF_TABLELOG_MAX + 1; - rankStart0 = (U32 *)workSpace + spaceUsed32; - spaceUsed32 += HUF_TABLELOG_MAX + 2; - sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t); - spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2; - weightList = (BYTE *)((U32 *)workSpace + spaceUsed32); - spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; - - if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); - - rankStart = rankStart0 + 1; - memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1)); + HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace; + + if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC); + + rankStart = wksp->rankStart0 + 1; + ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats)); + ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0)); DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); - /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + /* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); + iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), bmi2); if (HUF_isError(iSize)) return iSize; /* check result */ if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ + if (tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG) maxTableLog = HUF_DECODER_FAST_TABLELOG; /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ /* Get start index of each weight */ { U32 w, nextRankStart = 0; for (w=1; wrankStats[w]; + rankStart[w] = curr; } rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ - sizeOfSort = nextRankStart; + rankStart[maxW+1] = nextRankStart; } /* sort symbols by weight */ { U32 s; for (s=0; sweightList[s]; U32 const r = rankStart[w]++; - sortedSymbol[r].symbol = (BYTE)s; - sortedSymbol[r].weight = (BYTE)w; + wksp->sortedSymbol[r].symbol = (BYTE)s; } rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ } /* Build rankVal */ - { U32* const rankVal0 = rankVal[0]; + { U32* const rankVal0 = wksp->rankVal[0]; { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */ U32 nextRankVal = 0; U32 w; for (w=1; wrankStats[w] << (w+rescale); + rankVal0[w] = curr; } } { U32 const minBits = tableLog+1 - maxW; U32 consumed; for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { - U32* const rankValPtr = rankVal[consumed]; + U32* const rankValPtr = wksp->rankVal[consumed]; U32 w; for (w = 1; w < maxW+1; w++) { rankValPtr[w] = rankVal0[w] >> consumed; } } } } HUF_fillDTableX2(dt, maxTableLog, - sortedSymbol, sizeOfSort, - rankStart0, rankVal, maxW, + wksp->sortedSymbol, + wksp->rankStart0, wksp->rankVal, maxW, tableLog+1); dtd.tableLog = (BYTE)maxTableLog; dtd.tableType = 1; - memcpy(DTable, &dtd, sizeof(dtd)); + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); return iSize; } -size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_readDTableX2_wksp(DTable, src, srcSize, - workSpace, sizeof(workSpace)); -} - FORCE_INLINE_TEMPLATE U32 HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 2); + ZSTD_memcpy(op, &dt[val].sequence, 2); BIT_skipBits(DStream, dt[val].nbBits); return dt[val].length; } @@ -680,15 +1150,17 @@ FORCE_INLINE_TEMPLATE U32 HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 1); - if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits); - else { + ZSTD_memcpy(op, &dt[val].sequence, 1); + if (dt[val].length==1) { + BIT_skipBits(DStream, dt[val].nbBits); + } else { if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { BIT_skipBits(DStream, dt[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); - } } + } + } return 1; } @@ -710,19 +1182,37 @@ HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, BYTE* const pStart = p; /* up to 8 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_1(p, bitDPtr); - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + if ((size_t)(pEnd - p) >= sizeof(bitDPtr->bitContainer)) { + if (dtLog <= 11 && MEM_64bits()) { + /* up to 10 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-9)) { + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } else { + /* up to 8 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } + } else { + BIT_reloadDStream(bitDPtr); } /* closer to end : up to 2 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + if ((size_t)(pEnd - p) >= 2) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - while (p <= pEnd-2) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + } if (p < pEnd) p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog); @@ -756,8 +1246,6 @@ HUF_decompress1X2_usingDTable_internal_body( /* decoded size */ return dstSize; } - - FORCE_INLINE_TEMPLATE size_t HUF_decompress4X2_usingDTable_internal_body( void* dst, size_t dstSize, @@ -769,6 +1257,7 @@ HUF_decompress4X2_usingDTable_internal_body( { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - (sizeof(size_t)-1); const void* const dtPtr = DTable+1; const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; @@ -793,37 +1282,65 @@ HUF_decompress4X2_usingDTable_internal_body( BYTE* op2 = opStart2; BYTE* op3 = opStart3; BYTE* op4 = opStart4; - U32 endSignal; + U32 endSignal = 1; DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* 16-32 symbols per loop (4-8 symbols per stream) */ - endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); - for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) { - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - - endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit); ) { +#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; +#else + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal = (U32)LIKELY((U32) + (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); +#endif + } } /* check corruption */ @@ -847,8 +1364,99 @@ HUF_decompress4X2_usingDTable_internal_body( } } +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if HUF_NEED_DEFAULT_FUNCTION +static +size_t HUF_decompress4X2_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop(HUF_DecompressAsmArgs* args) ZSTDLIB_HIDDEN; + +static HUF_ASM_X86_64_BMI2_ATTRS size_t +HUF_decompress4X2_usingDTable_internal_bmi2_asm( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) { + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressAsmArgs args; + { + size_t const ret = HUF_DecompressAsmArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret != 0) + return HUF_decompress4X2_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); + } + + assert(args.ip[0] >= args.ilimit); + HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop(&args); + + /* note : op4 already verified within main loop */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bitStreams one by one */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + args.op[i] += HUF_decodeStreamX2(args.op[i], &bit, segmentEnd, (HUF_DEltX2 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) + return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} +#endif /* ZSTD_ENABLE_ASM_X86_64_BMI2 */ + +static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + return HUF_decompress4X2_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +# else + return HUF_decompress4X2_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); +# endif + } +#else + (void)bmi2; +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + return HUF_decompress4X2_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +#else + return HUF_decompress4X2_usingDTable_internal_default(dst, dstSize, cSrc, cSrcSize, DTable); +#endif +} + HUF_DGEN(HUF_decompress1X2_usingDTable_internal) -HUF_DGEN(HUF_decompress4X2_usingDTable_internal) size_t HUF_decompress1X2_usingDTable( void* dst, size_t dstSize, @@ -876,20 +1484,6 @@ size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, } -size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - -size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); - return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); -} - size_t HUF_decompress4X2_usingDTable( void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, @@ -923,20 +1517,6 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, } -size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - -size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); - return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); -} - #endif /* HUF_FORCE_DECOMPRESS_X1 */ @@ -985,25 +1565,25 @@ size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, #if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; -static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = +static const algo_time_t algoTime[16 /* Quantization */][2 /* single, double */] = { /* single, double, quad */ - {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */ - {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */ - {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */ - {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */ - {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */ - {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */ - {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */ - {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */ - {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */ - {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */ - {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */ - {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */ - {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */ - {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */ - {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */ - {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */ + {{0,0}, {1,1}}, /* Q==0 : impossible */ + {{0,0}, {1,1}}, /* Q==1 : impossible */ + {{ 150,216}, { 381,119}}, /* Q == 2 : 12-18% */ + {{ 170,205}, { 514,112}}, /* Q == 3 : 18-25% */ + {{ 177,199}, { 539,110}}, /* Q == 4 : 25-32% */ + {{ 197,194}, { 644,107}}, /* Q == 5 : 32-38% */ + {{ 221,192}, { 735,107}}, /* Q == 6 : 38-44% */ + {{ 256,189}, { 881,106}}, /* Q == 7 : 44-50% */ + {{ 359,188}, {1167,109}}, /* Q == 8 : 50-56% */ + {{ 582,187}, {1570,114}}, /* Q == 9 : 56-62% */ + {{ 688,187}, {1712,122}}, /* Q ==10 : 62-69% */ + {{ 825,186}, {1965,136}}, /* Q ==11 : 69-75% */ + {{ 976,185}, {2131,150}}, /* Q ==12 : 75-81% */ + {{1180,186}, {2070,175}}, /* Q ==13 : 81-87% */ + {{1377,185}, {1731,202}}, /* Q ==14 : 87-93% */ + {{1412,185}, {1695,202}}, /* Q ==15 : 93-99% */ }; #endif @@ -1030,74 +1610,13 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize) U32 const D256 = (U32)(dstSize >> 8); U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); - DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */ + DTime1 += DTime1 >> 5; /* small advantage to algorithm using less memory, to reduce cache eviction */ return DTime1 < DTime0; } #endif } -typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); - -size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ -#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) - static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 }; -#endif - - /* validation checks */ - if (dstSize == 0) return ERROR(dstSize_tooSmall); - if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ - - { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); -#if defined(HUF_FORCE_DECOMPRESS_X1) - (void)algoNb; - assert(algoNb == 0); - return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize); -#elif defined(HUF_FORCE_DECOMPRESS_X2) - (void)algoNb; - assert(algoNb == 1); - return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize); -#else - return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); -#endif - } -} - -size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - /* validation checks */ - if (dstSize == 0) return ERROR(dstSize_tooSmall); - if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ - - { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); -#if defined(HUF_FORCE_DECOMPRESS_X1) - (void)algoNb; - assert(algoNb == 0); - return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); -#elif defined(HUF_FORCE_DECOMPRESS_X2) - (void)algoNb; - assert(algoNb == 1); - return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); -#else - return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : - HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; -#endif - } -} - -size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - - size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, @@ -1131,8 +1650,8 @@ size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); #if defined(HUF_FORCE_DECOMPRESS_X1) @@ -1154,14 +1673,6 @@ size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, } } -size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) { @@ -1185,7 +1696,7 @@ size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstS { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize); + size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; @@ -1232,3 +1743,149 @@ size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t ds #endif } } + +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX1_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX2_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); + +size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) + static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 }; +#endif + + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize); +#else + return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); +#endif + } +} + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#else + return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : + HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; +#endif + } +} + +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +#endif diff --git a/native/zstd/decompress/huf_decompress_amd64.S b/native/zstd/decompress/huf_decompress_amd64.S new file mode 100644 index 0000000..3f0e5c2 --- /dev/null +++ b/native/zstd/decompress/huf_decompress_amd64.S @@ -0,0 +1,574 @@ +/* + * Copyright (c) Facebook, Inc. + * 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. + */ + +#include "../common/portability_macros.h" + +/* Stack marking + * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart + */ +#if defined(__ELF__) && defined(__GNUC__) +.section .note.GNU-stack,"",%progbits +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +/* Calling convention: + * + * %rdi contains the first argument: HUF_DecompressAsmArgs*. + * %rbp isn't maintained (no frame pointer). + * %rsp contains the stack pointer that grows down. + * No red-zone is assumed, only addresses >= %rsp are used. + * All register contents are preserved. + * + * TODO: Support Windows calling convention. + */ + +ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) +ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) +ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) +ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) +.global HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop +.global HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop +.global _HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop +.global _HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop +.text + +/* Sets up register mappings for clarity. + * op[], bits[], dtable & ip[0] each get their own register. + * ip[1,2,3] & olimit alias var[]. + * %rax is a scratch register. + */ + +#define op0 rsi +#define op1 rbx +#define op2 rcx +#define op3 rdi + +#define ip0 r8 +#define ip1 r9 +#define ip2 r10 +#define ip3 r11 + +#define bits0 rbp +#define bits1 rdx +#define bits2 r12 +#define bits3 r13 +#define dtable r14 +#define olimit r15 + +/* var[] aliases ip[1,2,3] & olimit + * ip[1,2,3] are saved every iteration. + * olimit is only used in compute_olimit. + */ +#define var0 r15 +#define var1 r9 +#define var2 r10 +#define var3 r11 + +/* 32-bit var registers */ +#define vard0 r15d +#define vard1 r9d +#define vard2 r10d +#define vard3 r11d + +/* Calls X(N) for each stream 0, 1, 2, 3. */ +#define FOR_EACH_STREAM(X) \ + X(0); \ + X(1); \ + X(2); \ + X(3) + +/* Calls X(N, idx) for each stream 0, 1, 2, 3. */ +#define FOR_EACH_STREAM_WITH_INDEX(X, idx) \ + X(0, idx); \ + X(1, idx); \ + X(2, idx); \ + X(3, idx) + +/* Define both _HUF_* & HUF_* symbols because MacOS + * C symbols are prefixed with '_' & Linux symbols aren't. + */ +_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: +HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: + /* Save all registers - even if they are callee saved for simplicity. */ + push %rax + push %rbx + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + /* Read HUF_DecompressAsmArgs* args from %rax */ + movq %rdi, %rax + movq 0(%rax), %ip0 + movq 8(%rax), %ip1 + movq 16(%rax), %ip2 + movq 24(%rax), %ip3 + movq 32(%rax), %op0 + movq 40(%rax), %op1 + movq 48(%rax), %op2 + movq 56(%rax), %op3 + movq 64(%rax), %bits0 + movq 72(%rax), %bits1 + movq 80(%rax), %bits2 + movq 88(%rax), %bits3 + movq 96(%rax), %dtable + push %rax /* argument */ + push 104(%rax) /* ilimit */ + push 112(%rax) /* oend */ + push %olimit /* olimit space */ + + subq $24, %rsp + +.L_4X1_compute_olimit: + /* Computes how many iterations we can do safely + * %r15, %rax may be clobbered + * rbx, rdx must be saved + * op3 & ip0 mustn't be clobbered + */ + movq %rbx, 0(%rsp) + movq %rdx, 8(%rsp) + + movq 32(%rsp), %rax /* rax = oend */ + subq %op3, %rax /* rax = oend - op3 */ + + /* r15 = (oend - op3) / 5 */ + movabsq $-3689348814741910323, %rdx + mulq %rdx + movq %rdx, %r15 + shrq $2, %r15 + + movq %ip0, %rax /* rax = ip0 */ + movq 40(%rsp), %rdx /* rdx = ilimit */ + subq %rdx, %rax /* rax = ip0 - ilimit */ + movq %rax, %rbx /* rbx = ip0 - ilimit */ + + /* rdx = (ip0 - ilimit) / 7 */ + movabsq $2635249153387078803, %rdx + mulq %rdx + subq %rdx, %rbx + shrq %rbx + addq %rbx, %rdx + shrq $2, %rdx + + /* r15 = min(%rdx, %r15) */ + cmpq %rdx, %r15 + cmova %rdx, %r15 + + /* r15 = r15 * 5 */ + leaq (%r15, %r15, 4), %r15 + + /* olimit = op3 + r15 */ + addq %op3, %olimit + + movq 8(%rsp), %rdx + movq 0(%rsp), %rbx + + /* If (op3 + 20 > olimit) */ + movq %op3, %rax /* rax = op3 */ + addq $20, %rax /* rax = op3 + 20 */ + cmpq %rax, %olimit /* op3 + 20 > olimit */ + jb .L_4X1_exit + + /* If (ip1 < ip0) go to exit */ + cmpq %ip0, %ip1 + jb .L_4X1_exit + + /* If (ip2 < ip1) go to exit */ + cmpq %ip1, %ip2 + jb .L_4X1_exit + + /* If (ip3 < ip2) go to exit */ + cmpq %ip2, %ip3 + jb .L_4X1_exit + +/* Reads top 11 bits from bits[n] + * Loads dt[bits[n]] into var[n] + */ +#define GET_NEXT_DELT(n) \ + movq $53, %var##n; \ + shrxq %var##n, %bits##n, %var##n; \ + movzwl (%dtable,%var##n,2),%vard##n + +/* var[n] must contain the DTable entry computed with GET_NEXT_DELT + * Moves var[n] to %rax + * bits[n] <<= var[n] & 63 + * op[n][idx] = %rax >> 8 + * %ah is a way to access bits [8, 16) of %rax + */ +#define DECODE_FROM_DELT(n, idx) \ + movq %var##n, %rax; \ + shlxq %var##n, %bits##n, %bits##n; \ + movb %ah, idx(%op##n) + +/* Assumes GET_NEXT_DELT has been called. + * Calls DECODE_FROM_DELT then GET_NEXT_DELT + */ +#define DECODE_AND_GET_NEXT(n, idx) \ + DECODE_FROM_DELT(n, idx); \ + GET_NEXT_DELT(n) \ + +/* // ctz & nbBytes is stored in bits[n] + * // nbBits is stored in %rax + * ctz = CTZ[bits[n]] + * nbBits = ctz & 7 + * nbBytes = ctz >> 3 + * op[n] += 5 + * ip[n] -= nbBytes + * // Note: x86-64 is little-endian ==> no bswap + * bits[n] = MEM_readST(ip[n]) | 1 + * bits[n] <<= nbBits + */ +#define RELOAD_BITS(n) \ + bsfq %bits##n, %bits##n; \ + movq %bits##n, %rax; \ + andq $7, %rax; \ + shrq $3, %bits##n; \ + leaq 5(%op##n), %op##n; \ + subq %bits##n, %ip##n; \ + movq (%ip##n), %bits##n; \ + orq $1, %bits##n; \ + shlx %rax, %bits##n, %bits##n + + /* Store clobbered variables on the stack */ + movq %olimit, 24(%rsp) + movq %ip1, 0(%rsp) + movq %ip2, 8(%rsp) + movq %ip3, 16(%rsp) + + /* Call GET_NEXT_DELT for each stream */ + FOR_EACH_STREAM(GET_NEXT_DELT) + + .p2align 6 + +.L_4X1_loop_body: + /* Decode 5 symbols in each of the 4 streams (20 total) + * Must have called GET_NEXT_DELT for each stream + */ + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 0) + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 1) + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 2) + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 3) + FOR_EACH_STREAM_WITH_INDEX(DECODE_FROM_DELT, 4) + + /* Load ip[1,2,3] from stack (var[] aliases them) + * ip[] is needed for RELOAD_BITS + * Each will be stored back to the stack after RELOAD + */ + movq 0(%rsp), %ip1 + movq 8(%rsp), %ip2 + movq 16(%rsp), %ip3 + + /* Reload each stream & fetch the next table entry + * to prepare for the next iteration + */ + RELOAD_BITS(0) + GET_NEXT_DELT(0) + + RELOAD_BITS(1) + movq %ip1, 0(%rsp) + GET_NEXT_DELT(1) + + RELOAD_BITS(2) + movq %ip2, 8(%rsp) + GET_NEXT_DELT(2) + + RELOAD_BITS(3) + movq %ip3, 16(%rsp) + GET_NEXT_DELT(3) + + /* If op3 < olimit: continue the loop */ + cmp %op3, 24(%rsp) + ja .L_4X1_loop_body + + /* Reload ip[1,2,3] from stack */ + movq 0(%rsp), %ip1 + movq 8(%rsp), %ip2 + movq 16(%rsp), %ip3 + + /* Re-compute olimit */ + jmp .L_4X1_compute_olimit + +#undef GET_NEXT_DELT +#undef DECODE_FROM_DELT +#undef DECODE +#undef RELOAD_BITS +.L_4X1_exit: + addq $24, %rsp + + /* Restore stack (oend & olimit) */ + pop %rax /* olimit */ + pop %rax /* oend */ + pop %rax /* ilimit */ + pop %rax /* arg */ + + /* Save ip / op / bits */ + movq %ip0, 0(%rax) + movq %ip1, 8(%rax) + movq %ip2, 16(%rax) + movq %ip3, 24(%rax) + movq %op0, 32(%rax) + movq %op1, 40(%rax) + movq %op2, 48(%rax) + movq %op3, 56(%rax) + movq %bits0, 64(%rax) + movq %bits1, 72(%rax) + movq %bits2, 80(%rax) + movq %bits3, 88(%rax) + + /* Restore registers */ + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rbx + pop %rax + ret + +_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: +HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: + /* Save all registers - even if they are callee saved for simplicity. */ + push %rax + push %rbx + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + movq %rdi, %rax + movq 0(%rax), %ip0 + movq 8(%rax), %ip1 + movq 16(%rax), %ip2 + movq 24(%rax), %ip3 + movq 32(%rax), %op0 + movq 40(%rax), %op1 + movq 48(%rax), %op2 + movq 56(%rax), %op3 + movq 64(%rax), %bits0 + movq 72(%rax), %bits1 + movq 80(%rax), %bits2 + movq 88(%rax), %bits3 + movq 96(%rax), %dtable + push %rax /* argument */ + push %rax /* olimit */ + push 104(%rax) /* ilimit */ + + movq 112(%rax), %rax + push %rax /* oend3 */ + + movq %op3, %rax + push %rax /* oend2 */ + + movq %op2, %rax + push %rax /* oend1 */ + + movq %op1, %rax + push %rax /* oend0 */ + + /* Scratch space */ + subq $8, %rsp + +.L_4X2_compute_olimit: + /* Computes how many iterations we can do safely + * %r15, %rax may be clobbered + * rdx must be saved + * op[1,2,3,4] & ip0 mustn't be clobbered + */ + movq %rdx, 0(%rsp) + + /* We can consume up to 7 input bytes each iteration. */ + movq %ip0, %rax /* rax = ip0 */ + movq 40(%rsp), %rdx /* rdx = ilimit */ + subq %rdx, %rax /* rax = ip0 - ilimit */ + movq %rax, %r15 /* r15 = ip0 - ilimit */ + + /* rdx = rax / 7 */ + movabsq $2635249153387078803, %rdx + mulq %rdx + subq %rdx, %r15 + shrq %r15 + addq %r15, %rdx + shrq $2, %rdx + + /* r15 = (ip0 - ilimit) / 7 */ + movq %rdx, %r15 + + /* r15 = min(r15, min(oend0 - op0, oend1 - op1, oend2 - op2, oend3 - op3) / 10) */ + movq 8(%rsp), %rax /* rax = oend0 */ + subq %op0, %rax /* rax = oend0 - op0 */ + movq 16(%rsp), %rdx /* rdx = oend1 */ + subq %op1, %rdx /* rdx = oend1 - op1 */ + + cmpq %rax, %rdx + cmova %rax, %rdx /* rdx = min(%rdx, %rax) */ + + movq 24(%rsp), %rax /* rax = oend2 */ + subq %op2, %rax /* rax = oend2 - op2 */ + + cmpq %rax, %rdx + cmova %rax, %rdx /* rdx = min(%rdx, %rax) */ + + movq 32(%rsp), %rax /* rax = oend3 */ + subq %op3, %rax /* rax = oend3 - op3 */ + + cmpq %rax, %rdx + cmova %rax, %rdx /* rdx = min(%rdx, %rax) */ + + movabsq $-3689348814741910323, %rax + mulq %rdx + shrq $3, %rdx /* rdx = rdx / 10 */ + + /* r15 = min(%rdx, %r15) */ + cmpq %rdx, %r15 + cmova %rdx, %r15 + + /* olimit = op3 + 5 * r15 */ + movq %r15, %rax + leaq (%op3, %rax, 4), %olimit + addq %rax, %olimit + + movq 0(%rsp), %rdx + + /* If (op3 + 10 > olimit) */ + movq %op3, %rax /* rax = op3 */ + addq $10, %rax /* rax = op3 + 10 */ + cmpq %rax, %olimit /* op3 + 10 > olimit */ + jb .L_4X2_exit + + /* If (ip1 < ip0) go to exit */ + cmpq %ip0, %ip1 + jb .L_4X2_exit + + /* If (ip2 < ip1) go to exit */ + cmpq %ip1, %ip2 + jb .L_4X2_exit + + /* If (ip3 < ip2) go to exit */ + cmpq %ip2, %ip3 + jb .L_4X2_exit + +#define DECODE(n, idx) \ + movq %bits##n, %rax; \ + shrq $53, %rax; \ + movzwl 0(%dtable,%rax,4),%r8d; \ + movzbl 2(%dtable,%rax,4),%r15d; \ + movzbl 3(%dtable,%rax,4),%eax; \ + movw %r8w, (%op##n); \ + shlxq %r15, %bits##n, %bits##n; \ + addq %rax, %op##n + +#define RELOAD_BITS(n) \ + bsfq %bits##n, %bits##n; \ + movq %bits##n, %rax; \ + shrq $3, %bits##n; \ + andq $7, %rax; \ + subq %bits##n, %ip##n; \ + movq (%ip##n), %bits##n; \ + orq $1, %bits##n; \ + shlxq %rax, %bits##n, %bits##n + + + movq %olimit, 48(%rsp) + + .p2align 6 + +.L_4X2_loop_body: + /* We clobber r8, so store it on the stack */ + movq %r8, 0(%rsp) + + /* Decode 5 symbols from each of the 4 streams (20 symbols total). */ + FOR_EACH_STREAM_WITH_INDEX(DECODE, 0) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 1) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 2) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 3) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 4) + + /* Reload r8 */ + movq 0(%rsp), %r8 + + FOR_EACH_STREAM(RELOAD_BITS) + + cmp %op3, 48(%rsp) + ja .L_4X2_loop_body + jmp .L_4X2_compute_olimit + +#undef DECODE +#undef RELOAD_BITS +.L_4X2_exit: + addq $8, %rsp + /* Restore stack (oend & olimit) */ + pop %rax /* oend0 */ + pop %rax /* oend1 */ + pop %rax /* oend2 */ + pop %rax /* oend3 */ + pop %rax /* ilimit */ + pop %rax /* olimit */ + pop %rax /* arg */ + + /* Save ip / op / bits */ + movq %ip0, 0(%rax) + movq %ip1, 8(%rax) + movq %ip2, 16(%rax) + movq %ip3, 24(%rax) + movq %op0, 32(%rax) + movq %op1, 40(%rax) + movq %op2, 48(%rax) + movq %op3, 56(%rax) + movq %bits0, 64(%rax) + movq %bits1, 72(%rax) + movq %bits2, 80(%rax) + movq %bits3, 88(%rax) + + /* Restore registers */ + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rbx + pop %rax + ret + +#endif diff --git a/native/zstd/decompress/zstd_ddict.c b/native/zstd/decompress/zstd_ddict.c old mode 100755 new mode 100644 index 0af3d23..889764a --- a/native/zstd/decompress/zstd_ddict.c +++ b/native/zstd/decompress/zstd_ddict.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,18 +14,18 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* memcpy, memmove, memset */ -#include "cpu.h" /* bmi2 */ -#include "mem.h" /* low level memory routines */ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ #define FSE_STATIC_LINKING_ONLY -#include "fse.h" +#include "../common/fse.h" #define HUF_STATIC_LINKING_ONLY -#include "huf.h" +#include "../common/huf.h" #include "zstd_decompress_internal.h" #include "zstd_ddict.h" #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -# include "zstd_legacy.h" +# include "../legacy/zstd_legacy.h" #endif @@ -65,6 +65,10 @@ void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) dctx->virtualStart = ddict->dictContent; dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize; dctx->previousDstEnd = dctx->dictEnd; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif if (ddict->entropyPresent) { dctx->litEntropy = 1; dctx->fseEntropy = 1; @@ -107,7 +111,7 @@ ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict, /* load entropy tables */ RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy( &ddict->entropy, ddict->dictContent, ddict->dictSize)), - dictionary_corrupted); + dictionary_corrupted, ""); ddict->entropyPresent = 1; return 0; } @@ -123,17 +127,17 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, ddict->dictContent = dict; if (!dict) dictSize = 0; } else { - void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem); + void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); ddict->dictBuffer = internalBuffer; ddict->dictContent = internalBuffer; if (!internalBuffer) return ERROR(memory_allocation); - memcpy(internalBuffer, dict, dictSize); + ZSTD_memcpy(internalBuffer, dict, dictSize); } ddict->dictSize = dictSize; - ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ /* parse dictionary content */ - FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) ); + FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); return 0; } @@ -143,9 +147,9 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_customMem customMem) { - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem); + { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); if (ddict == NULL) return NULL; ddict->cMem = customMem; { size_t const initResult = ZSTD_initDDict_internal(ddict, @@ -194,7 +198,7 @@ const ZSTD_DDict* ZSTD_initStaticDDict( if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ if (sBufferSize < neededSpace) return NULL; if (dictLoadMethod == ZSTD_dlm_byCopy) { - memcpy(ddict+1, dict, dictSize); /* local copy */ + ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ dict = ddict+1; } if (ZSTD_isError( ZSTD_initDDict_internal(ddict, @@ -209,8 +213,8 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) { if (ddict==NULL) return 0; /* support free on NULL */ { ZSTD_customMem const cMem = ddict->cMem; - ZSTD_free(ddict->dictBuffer, cMem); - ZSTD_free(ddict, cMem); + ZSTD_customFree(ddict->dictBuffer, cMem); + ZSTD_customFree(ddict, cMem); return 0; } } diff --git a/native/zstd/decompress/zstd_ddict.h b/native/zstd/decompress/zstd_ddict.h old mode 100755 new mode 100644 index 0479d11..bd03268 --- a/native/zstd/decompress/zstd_ddict.h +++ b/native/zstd/decompress/zstd_ddict.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,8 +15,8 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* size_t */ -#include "zstd.h" /* ZSTD_DDict, and several public functions */ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* ZSTD_DDict, and several public functions */ /*-******************************************************* diff --git a/native/zstd/decompress/zstd_decompress.c b/native/zstd/decompress/zstd_decompress.c old mode 100755 new mode 100644 index dd4591b..5bd412d --- a/native/zstd/decompress/zstd_decompress.c +++ b/native/zstd/decompress/zstd_decompress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -55,23 +55,165 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* memcpy, memmove, memset */ -#include "cpu.h" /* bmi2 */ -#include "mem.h" /* low level memory routines */ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/mem.h" /* low level memory routines */ #define FSE_STATIC_LINKING_ONLY -#include "fse.h" +#include "../common/fse.h" #define HUF_STATIC_LINKING_ONLY -#include "huf.h" -#include "zstd_internal.h" /* blockProperties_t */ +#include "../common/huf.h" +#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ +#include "../common/zstd_internal.h" /* blockProperties_t */ #include "zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ +#include "../common/bits.h" /* ZSTD_highbit32 */ #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -# include "zstd_legacy.h" +# include "../legacy/zstd_legacy.h" #endif + +/************************************* + * Multiple DDicts Hashset internals * + *************************************/ + +#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4 +#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float. + * Currently, that means a 0.75 load factor. + * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded + * the load factor of the ddict hash set. + */ + +#define DDICT_HASHSET_TABLE_BASE_SIZE 64 +#define DDICT_HASHSET_RESIZE_FACTOR 2 + +/* Hash function to determine starting position of dict insertion within the table + * Returns an index between [0, hashSet->ddictPtrTableSize] + */ +static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) { + const U64 hash = XXH64(&dictID, sizeof(U32), 0); + /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */ + return hash & (hashSet->ddictPtrTableSize - 1); +} + +/* Adds DDict to a hashset without resizing it. + * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set. + * Returns 0 if successful, or a zstd error code if something went wrong. + */ +static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) { + const U32 dictID = ZSTD_getDictID_fromDDict(ddict); + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!"); + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + while (hashSet->ddictPtrTable[idx] != NULL) { + /* Replace existing ddict if inserting ddict with same dictID */ + if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) { + DEBUGLOG(4, "DictID already exists, replacing rather than adding"); + hashSet->ddictPtrTable[idx] = ddict; + return 0; + } + idx &= idxRangeMask; + idx++; + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + hashSet->ddictPtrTable[idx] = ddict; + hashSet->ddictPtrCount++; + return 0; +} + +/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and + * rehashes all values, allocates new table, frees old table. + * Returns 0 on success, otherwise a zstd error code. + */ +static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR; + const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem); + const ZSTD_DDict** oldTable = hashSet->ddictPtrTable; + size_t oldTableSize = hashSet->ddictPtrTableSize; + size_t i; + + DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize); + RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!"); + hashSet->ddictPtrTable = newTable; + hashSet->ddictPtrTableSize = newTableSize; + hashSet->ddictPtrCount = 0; + for (i = 0; i < oldTableSize; ++i) { + if (oldTable[i] != NULL) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), ""); + } + } + ZSTD_customFree((void*)oldTable, customMem); + DEBUGLOG(4, "Finished re-hash"); + return 0; +} + +/* Fetches a DDict with the given dictID + * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL. + */ +static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) { + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + for (;;) { + size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]); + if (currDictID == dictID || currDictID == 0) { + /* currDictID == 0 implies a NULL ddict entry */ + break; + } else { + idx &= idxRangeMask; /* Goes to start of table when we reach the end */ + idx++; + } + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + return hashSet->ddictPtrTable[idx]; +} + +/* Allocates space for and returns a ddict hash set + * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with. + * Returns NULL if allocation failed. + */ +static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) { + ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem); + DEBUGLOG(4, "Allocating new hash set"); + if (!ret) + return NULL; + ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem); + if (!ret->ddictPtrTable) { + ZSTD_customFree(ret, customMem); + return NULL; + } + ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE; + ret->ddictPtrCount = 0; + return ret; +} + +/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself. + * Note: The ZSTD_DDict* within the table are NOT freed. + */ +static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + DEBUGLOG(4, "Freeing ddict hash set"); + if (hashSet && hashSet->ddictPtrTable) { + ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem); + } + if (hashSet) { + ZSTD_customFree(hashSet, customMem); + } +} + +/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set. + * Returns 0 on success, or a ZSTD error. + */ +static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) { + DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize); + if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), ""); + } + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), ""); + return 0; +} + /*-************************************************************* * Context management ***************************************************************/ @@ -94,11 +236,19 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format) return startingInputLength; } +static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx) +{ + assert(dctx->streamStage == zdss_init); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + dctx->outBufferMode = ZSTD_bm_buffered; + dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; + dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict; +} + static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) { - dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */ dctx->staticSize = 0; - dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; dctx->ddict = NULL; dctx->ddictLocal = NULL; dctx->dictEnd = NULL; @@ -108,10 +258,20 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) dctx->inBuffSize = 0; dctx->outBuffSize = 0; dctx->streamStage = zdss_init; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) dctx->legacyContext = NULL; dctx->previousLegacyVersion = 0; +#endif dctx->noForwardProgress = 0; - dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); + dctx->oversizedDuration = 0; +#if DYNAMIC_BMI2 + dctx->bmi2 = ZSTD_cpuSupportsBmi2(); +#endif + dctx->ddictSet = NULL; + ZSTD_DCtx_resetParameters(dctx); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentEndForFuzzing = NULL; +#endif } ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) @@ -127,11 +287,10 @@ ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) return dctx; } -ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) -{ - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; +static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem); + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem); if (!dctx) return NULL; dctx->customMem = customMem; ZSTD_initDCtx_internal(dctx); @@ -139,10 +298,15 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) } } +ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + ZSTD_DCtx* ZSTD_createDCtx(void) { DEBUGLOG(3, "ZSTD_createDCtx"); - return ZSTD_createDCtx_advanced(ZSTD_defaultCMem); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); } static void ZSTD_clearDict(ZSTD_DCtx* dctx) @@ -159,13 +323,17 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx"); { ZSTD_customMem const cMem = dctx->customMem; ZSTD_clearDict(dctx); - ZSTD_free(dctx->inBuff, cMem); + ZSTD_customFree(dctx->inBuff, cMem); dctx->inBuff = NULL; #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (dctx->legacyContext) ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); #endif - ZSTD_free(dctx, cMem); + if (dctx->ddictSet) { + ZSTD_freeDDictHashSet(dctx->ddictSet, cMem); + dctx->ddictSet = NULL; + } + ZSTD_customFree(dctx, cMem); return 0; } } @@ -174,7 +342,30 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); - memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ + ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ +} + +/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on + * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then + * accordingly sets the ddict to be used to decompress the frame. + * + * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is. + * + * ZSTD_d_refMultipleDDicts must be enabled for this function to be called. + */ +static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) { + assert(dctx->refMultipleDDicts && dctx->ddictSet); + DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame"); + if (dctx->ddict) { + const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID); + if (frameDDict) { + DEBUGLOG(4, "DDict found!"); + ZSTD_clearDict(dctx); + dctx->dictID = dctx->fParams.dictID; + dctx->ddict = frameDDict; + dctx->dictUses = ZSTD_use_indefinitely; + } + } } @@ -200,6 +391,19 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) return 0; } +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + */ +unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } + return 0; +} + /** ZSTD_frameHeaderSize_internal() : * srcSize must be large enough to reach header size fields. * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless. @@ -208,7 +412,7 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format) { size_t const minInputSize = ZSTD_startingInputLength(format); - RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong); + RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, ""); { BYTE const fhd = ((const BYTE*)src)[minInputSize-1]; U32 const dictID= fhd & 3; @@ -235,28 +439,52 @@ size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless * @return : 0, `zfhPtr` is correctly filled, * >0, `srcSize` is too small, value is wanted `srcSize` amount, - * or an error code, which can be tested using ZSTD_isError() */ +** or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) { const BYTE* ip = (const BYTE*)src; size_t const minInputSize = ZSTD_startingInputLength(format); - memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */ - if (srcSize < minInputSize) return minInputSize; - RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter"); + DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize); + + if (srcSize > 0) { + /* note : technically could be considered an assert(), since it's an invalid entry */ + RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0"); + } + if (srcSize < minInputSize) { + if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) { + /* when receiving less than @minInputSize bytes, + * control these bytes at least correspond to a supported magic number + * in order to error out early if they don't. + **/ + size_t const toCopy = MIN(4, srcSize); + unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER); + assert(src != NULL); + ZSTD_memcpy(hbuf, src, toCopy); + if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) { + /* not a zstd frame : let's check if it's a skippable frame */ + MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START); + ZSTD_memcpy(hbuf, src, toCopy); + if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) { + RETURN_ERROR(prefix_unknown, + "first bytes don't correspond to any supported magic number"); + } } } + return minInputSize; + } + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */ if ( (format != ZSTD_f_zstd1_magicless) && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ if (srcSize < ZSTD_SKIPPABLEHEADERSIZE) return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */ - memset(zfhPtr, 0, sizeof(*zfhPtr)); + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE); zfhPtr->frameType = ZSTD_skippableFrame; return 0; } - RETURN_ERROR(prefix_unknown); + RETURN_ERROR(prefix_unknown, ""); } /* ensure there is enough `srcSize` to fully read/decode frame header */ @@ -280,13 +508,15 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s if (!singleSegment) { BYTE const wlByte = ip[pos++]; U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN; - RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge); + RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, ""); windowSize = (1ULL << windowLog); windowSize += (windowSize >> 3) * (wlByte&7); } switch(dictIDSizeCode) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : break; case 1 : dictID = ip[pos]; pos++; break; case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break; @@ -294,7 +524,9 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s } switch(fcsID) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : if (singleSegment) frameContentSize = ip[pos]; break; case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break; case 2 : frameContentSize = MEM_readLE32(ip+pos); break; @@ -323,7 +555,6 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1); } - /** ZSTD_getFrameContentSize() : * compatible with legacy mode * @return : decompressed size of the single frame pointed to be `src` if known, otherwise @@ -352,18 +583,49 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize) size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE; U32 sizeU32; - RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong); + RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, - frameParameter_unsupported); + frameParameter_unsupported, ""); { size_t const skippableSize = skippableHeaderSize + sizeU32; - RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong); + RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, ""); return skippableSize; } } +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize) +{ + U32 const magicNumber = MEM_readLE32(src); + size_t skippableFrameSize = readSkippableFrameSize(src, srcSize); + size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE; + + /* check input validity */ + RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, ""); + RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, ""); + RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, ""); + + /* deliver payload */ + if (skippableContentSize > 0 && dst != NULL) + ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize); + if (magicVariant != NULL) + *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START; + return skippableContentSize; +} + /** ZSTD_findDecompressedSize() : * compatible with legacy mode * `srcSize` must be the exact length of some number of ZSTD compressed and/or @@ -428,20 +690,29 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) /** ZSTD_decodeFrameHeader() : * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). + * If multiple DDict references are enabled, also will choose the correct DDict to use. * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) { size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format); if (ZSTD_isError(result)) return result; /* invalid header */ RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small"); + + /* Reference DDict requested by frame if dctx references multiple ddicts */ + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) { + ZSTD_DCtx_selectFrameDDict(dctx); + } + #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Skip the dictID check in fuzzing mode, because it makes the search * harder. */ RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), - dictionary_wrong); + dictionary_wrong, ""); #endif - if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0); + dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; + if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); + dctx->processedCSize += headerSize; return 0; } @@ -456,7 +727,7 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret) static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize) { ZSTD_frameSizeInfo frameSizeInfo; - memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); + ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (ZSTD_isLegacy(src, srcSize)) @@ -511,7 +782,7 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize ip += 4; } - frameSizeInfo.compressedSize = ip - ipstart; + frameSizeInfo.compressedSize = (size_t)(ip - ipstart); frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) ? zfh.frameContentSize : nbBlocks * zfh.blockSizeMax; @@ -559,23 +830,12 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) * Frame decoding ***************************************************************/ - -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst) -{ - if (dst != dctx->previousDstEnd) { /* not contiguous */ - dctx->dictEnd = dctx->previousDstEnd; - dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); - dctx->prefixStart = dst; - dctx->previousDstEnd = dst; - } -} - /** ZSTD_insertBlock() : * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */ size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize) { DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize); - ZSTD_checkContinuity(dctx, blockStart); + ZSTD_checkContinuity(dctx, blockStart, blockSize); dctx->previousDstEnd = (const char*)blockStart + blockSize; return blockSize; } @@ -585,12 +845,12 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_copyRawBlock"); + RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (srcSize == 0) return 0; - RETURN_ERROR(dstBuffer_null); + RETURN_ERROR(dstBuffer_null, ""); } - RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall); - memcpy(dst, src, srcSize); + ZSTD_memcpy(dst, src, srcSize); return srcSize; } @@ -598,15 +858,41 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, BYTE b, size_t regenSize) { + RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (regenSize == 0) return 0; - RETURN_ERROR(dstBuffer_null); + RETURN_ERROR(dstBuffer_null, ""); } - RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall); - memset(dst, b, regenSize); + ZSTD_memset(dst, b, regenSize); return regenSize; } +static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming) +{ +#if ZSTD_TRACE + if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { + ZSTD_Trace trace; + ZSTD_memset(&trace, 0, sizeof(trace)); + trace.version = ZSTD_VERSION_NUMBER; + trace.streaming = streaming; + if (dctx->ddict) { + trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); + trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); + trace.dictionaryIsCold = dctx->ddictIsCold; + } + trace.uncompressedSize = (size_t)uncompressedSize; + trace.compressedSize = (size_t)compressedSize; + trace.dctx = dctx; + ZSTD_trace_decompress_end(dctx->traceCtx, &trace); + } +#else + (void)dctx; + (void)uncompressedSize; + (void)compressedSize; + (void)streaming; +#endif +} + /*! ZSTD_decompressFrame() : * @dctx must be properly initialized @@ -616,9 +902,10 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void** srcPtr, size_t *srcSizePtr) { - const BYTE* ip = (const BYTE*)(*srcPtr); - BYTE* const ostart = (BYTE* const)dst; - BYTE* const oend = ostart + dstCapacity; + const BYTE* const istart = (const BYTE*)(*srcPtr); + const BYTE* ip = istart; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart; BYTE* op = ostart; size_t remainingSrcSize = *srcSizePtr; @@ -627,15 +914,15 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /* check */ RETURN_ERROR_IF( remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize, - srcSize_wrong); + srcSize_wrong, ""); /* Frame Header */ { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal( ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize, - srcSize_wrong); - FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) ); + srcSize_wrong, ""); + FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , ""); ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize; } @@ -648,28 +935,30 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, ip += ZSTD_blockHeaderSize; remainingSrcSize -= ZSTD_blockHeaderSize; - RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong); + RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, ""); switch(blockProperties.blockType) { case bt_compressed: - decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1); + decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1, not_streaming); break; case bt_raw : - decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize); + decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize); break; case bt_rle : - decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize); + decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize); break; case bt_reserved : default: - RETURN_ERROR(corruption_detected); + RETURN_ERROR(corruption_detected, "invalid block type"); } if (ZSTD_isError(decodedSize)) return decodedSize; - if (dctx->fParams.checksumFlag) + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, op, decodedSize); - op += decodedSize; + if (decodedSize != 0) + op += decodedSize; + assert(ip != NULL); ip += cBlockSize; remainingSrcSize -= cBlockSize; if (blockProperties.lastBlock) break; @@ -677,22 +966,24 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) { RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize, - corruption_detected); + corruption_detected, ""); } if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ - U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); - U32 checkRead; - RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong); - checkRead = MEM_readLE32(ip); - RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong); + RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); + if (!dctx->forceIgnoreChecksum) { + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + } ip += 4; remainingSrcSize -= 4; } - + ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0); /* Allow caller to get size read */ *srcPtr = ip; *srcSizePtr = remainingSrcSize; - return op-ostart; + return (size_t)(op-ostart); } static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, @@ -725,7 +1016,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); if (ZSTD_isError(decodedSize)) return decodedSize; - assert(decodedSize <=- dstCapacity); + assert(decodedSize <= dstCapacity); dst = (BYTE*)dst + decodedSize; dstCapacity -= decodedSize; @@ -741,7 +1032,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, (unsigned)magicNumber, ZSTD_MAGICNUMBER); if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { size_t const skippableSize = readSkippableFrameSize(src, srcSize); - FORWARD_IF_ERROR(skippableSize); + FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed"); assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; @@ -751,13 +1042,13 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, if (ddict) { /* we were called from ZSTD_decompress_usingDDict */ - FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict)); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), ""); } else { /* this will initialize correctly with no dict if dict == NULL, so * use this in all cases but ddict */ - FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize)); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), ""); } - ZSTD_checkContinuity(dctx, dst); + ZSTD_checkContinuity(dctx, dst, dstCapacity); { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &src, &srcSize); @@ -765,18 +1056,17 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown) && (moreThan1Frame==1), srcSize_wrong, - "at least one frame successfully completed, but following " - "bytes are garbage: it's more likely to be a srcSize error, " - "specifying more bytes than compressed size of frame(s). This " - "error message replaces ERROR(prefix_unknown), which would be " - "confusing, as the first header is actually correct. Note that " - "one could be unlucky, it might be a corruption error instead, " - "happening right at the place where we expect zstd magic " - "bytes. But this is _much_ less likely than a srcSize field " - "error."); + "At least one frame successfully completed, " + "but following bytes are garbage: " + "it's more likely to be a srcSize error, " + "specifying more input bytes than size of frame(s). " + "Note: one could be unlucky, it might be a corruption error instead, " + "happening right at the place where we expect zstd magic bytes. " + "But this is _much_ less likely than a srcSize field error."); if (ZSTD_isError(res)) return res; assert(res <= dstCapacity); - dst = (BYTE*)dst + res; + if (res != 0) + dst = (BYTE*)dst + res; dstCapacity -= res; } moreThan1Frame = 1; @@ -784,7 +1074,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed"); - return (BYTE*)dst - (BYTE*)dststart; + return (size_t)((BYTE*)dst - (BYTE*)dststart); } size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, @@ -801,7 +1091,7 @@ static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx) switch (dctx->dictUses) { default: assert(0 /* Impossible */); - /* fall-through */ + ZSTD_FALLTHROUGH; case ZSTD_dont_use: ZSTD_clearDict(dctx); return NULL; @@ -823,8 +1113,8 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr { #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) size_t regenSize; - ZSTD_DCtx* const dctx = ZSTD_createDCtx(); - RETURN_ERROR_IF(dctx==NULL, memory_allocation); + ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem); + RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!"); regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); ZSTD_freeDCtx(dctx); return regenSize; @@ -842,12 +1132,32 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr ****************************************/ size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } +/** + * Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we + * allow taking a partial block as the input. Currently only raw uncompressed blocks can + * be streamed. + * + * For blocks that can be streamed, this allows us to reduce the latency until we produce + * output, and avoid copying the input. + * + * @param inputSize - The total amount of input that the caller currently has. + */ +static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) { + if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock)) + return dctx->expected; + if (dctx->bType != bt_raw) + return dctx->expected; + return BOUNDED(1, inputSize, dctx->expected); +} + ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { switch(dctx->stage) { default: /* should not happen */ assert(0); + ZSTD_FALLTHROUGH; case ZSTDds_getFrameHeaderSize: + ZSTD_FALLTHROUGH; case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader; case ZSTDds_decodeBlockHeader: @@ -859,6 +1169,7 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { case ZSTDds_checkChecksum: return ZSTDnit_checksum; case ZSTDds_decodeSkippableHeader: + ZSTD_FALLTHROUGH; case ZSTDds_skipFrame: return ZSTDnit_skippableFrame; } @@ -874,8 +1185,10 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c { DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize); /* Sanity check */ - RETURN_ERROR_IF(srcSize != dctx->expected, srcSize_wrong, "not allowed"); - if (dstCapacity) ZSTD_checkContinuity(dctx, dst); + RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed"); + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + dctx->processedCSize += srcSize; switch (dctx->stage) { @@ -884,22 +1197,22 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c if (dctx->format == ZSTD_f_zstd1) { /* allows header */ assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ - memcpy(dctx->headerBuffer, src, srcSize); + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */ dctx->stage = ZSTDds_decodeSkippableHeader; return 0; } } dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; - memcpy(dctx->headerBuffer, src, srcSize); + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = dctx->headerSize - srcSize; dctx->stage = ZSTDds_decodeFrameHeader; return 0; case ZSTDds_decodeFrameHeader: assert(src != NULL); - memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); - FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize)); + ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), ""); dctx->expected = ZSTD_blockHeaderSize; dctx->stage = ZSTDds_decodeBlockHeader; return 0; @@ -940,51 +1253,67 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c { case bt_compressed: DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed"); - rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1); + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming); + dctx->expected = 0; /* Streaming not supported */ break; case bt_raw : + assert(srcSize <= dctx->expected); rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); + FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed"); + assert(rSize == srcSize); + dctx->expected -= rSize; break; case bt_rle : rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize); + dctx->expected = 0; /* Streaming not supported */ break; case bt_reserved : /* should never happen */ default: - RETURN_ERROR(corruption_detected); + RETURN_ERROR(corruption_detected, "invalid block type"); } - if (ZSTD_isError(rSize)) return rSize; + FORWARD_IF_ERROR(rSize, ""); RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); dctx->decodedSize += rSize; - if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize); + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); + dctx->previousDstEnd = (char*)dst + rSize; + + /* Stay on the same stage until we are finished streaming the block. */ + if (dctx->expected > 0) { + return rSize; + } if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */ DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize); RETURN_ERROR_IF( dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && dctx->decodedSize != dctx->fParams.frameContentSize, - corruption_detected); + corruption_detected, ""); if (dctx->fParams.checksumFlag) { /* another round for frame checksum */ dctx->expected = 4; dctx->stage = ZSTDds_checkChecksum; } else { + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); dctx->expected = 0; /* ends here */ dctx->stage = ZSTDds_getFrameHeaderSize; } } else { dctx->stage = ZSTDds_decodeBlockHeader; dctx->expected = ZSTD_blockHeaderSize; - dctx->previousDstEnd = (char*)dst + rSize; } return rSize; } case ZSTDds_checkChecksum: assert(srcSize == 4); /* guaranteed by dctx->expected */ - { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); - U32 const check32 = MEM_readLE32(src); - DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); - RETURN_ERROR_IF(check32 != h32, checksum_wrong); + { + if (dctx->validateChecksum) { + U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + } + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; return 0; @@ -993,7 +1322,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c case ZSTDds_decodeSkippableHeader: assert(src != NULL); assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE); - memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ + ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */ dctx->stage = ZSTDds_skipFrame; return 0; @@ -1005,7 +1334,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC); /* some compiler require default to do something */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ } } @@ -1016,6 +1345,10 @@ static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dict dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); dctx->prefixStart = dict; dctx->previousDstEnd = (const char*)dict + dictSize; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif return 0; } @@ -1029,7 +1362,7 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, const BYTE* dictPtr = (const BYTE*)dict; const BYTE* const dictEnd = dictPtr + dictSize; - RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted); + RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small"); assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */ dictPtr += 8; /* skip header = magic + dictID */ @@ -1045,63 +1378,69 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, workspace, workspaceSize); #else size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable, - dictPtr, dictEnd - dictPtr, + dictPtr, (size_t)(dictEnd - dictPtr), workspace, workspaceSize); #endif - RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted); + RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, ""); dictPtr += hSize; } { short offcodeNCount[MaxOff+1]; unsigned offcodeMaxValue = MaxOff, offcodeLog; - size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted); - RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted); - RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted); + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->OFTable, offcodeNCount, offcodeMaxValue, OF_base, OF_bits, - offcodeLog); + offcodeLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */0); dictPtr += offcodeHeaderSize; } { short matchlengthNCount[MaxML+1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog; - size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted); - RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted); - RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted); + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->MLTable, matchlengthNCount, matchlengthMaxValue, ML_base, ML_bits, - matchlengthLog); + matchlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); dictPtr += matchlengthHeaderSize; } { short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog; - size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); - RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted); - RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted); - RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted); + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->LLTable, litlengthNCount, litlengthMaxValue, LL_base, LL_bits, - litlengthLog); + litlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); dictPtr += litlengthHeaderSize; } - RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted); + RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); { int i; size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12)); for (i=0; i<3; i++) { U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4; RETURN_ERROR_IF(rep==0 || rep > dictContentSize, - dictionary_corrupted); + dictionary_corrupted, ""); entropy->rep[i] = rep; } } - return dictPtr - (const BYTE*)dict; + return (size_t)(dictPtr - (const BYTE*)dict); } static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) @@ -1115,7 +1454,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict /* load entropy tables */ { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize); - RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted); + RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, ""); dict = (const char*)dict + eSize; dictSize -= eSize; } @@ -1128,18 +1467,23 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { assert(dctx != NULL); +#if ZSTD_TRACE + dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; +#endif dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ dctx->stage = ZSTDds_getFrameHeaderSize; + dctx->processedCSize = 0; dctx->decodedSize = 0; dctx->previousDstEnd = NULL; dctx->prefixStart = NULL; dctx->virtualStart = NULL; dctx->dictEnd = NULL; - dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; + dctx->bType = bt_reserved; ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); - memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ dctx->LLTptr = dctx->entropy.LLTable; dctx->MLTptr = dctx->entropy.MLTable; dctx->OFTptr = dctx->entropy.OFTable; @@ -1149,11 +1493,11 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { - FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) ); + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); if (dict && dictSize) RETURN_ERROR_IF( ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)), - dictionary_corrupted); + dictionary_corrupted, ""); return 0; } @@ -1172,7 +1516,7 @@ size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) DEBUGLOG(4, "DDict is %s", dctx->ddictIsCold ? "~cold~" : "hot!"); } - FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) ); + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); if (ddict) { /* NULL ddict is equivalent to no dictionary */ ZSTD_copyDDictParameters(dctx, ddict); } @@ -1196,7 +1540,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) * This could for one of the following reasons : * - The frame does not require a dictionary (most common case). * - The frame was built with dictID intentionally removed. - * Needed dictionary is a hidden information. + * Needed dictionary is a hidden piece of information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, frame header could not be decoded. * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. @@ -1234,7 +1578,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, ZSTD_DStream* ZSTD_createDStream(void) { DEBUGLOG(3, "ZSTD_createDStream"); - return ZSTD_createDStream_advanced(ZSTD_defaultCMem); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); } ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) @@ -1244,7 +1588,7 @@ ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) { - return ZSTD_createDCtx_advanced(customMem); + return ZSTD_createDCtx_internal(customMem); } size_t ZSTD_freeDStream(ZSTD_DStream* zds) @@ -1263,11 +1607,11 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); ZSTD_clearDict(dctx); if (dict && dictSize != 0) { dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem); - RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation); + RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!"); dctx->ddict = dctx->ddictLocal; dctx->dictUses = ZSTD_use_indefinitely; } @@ -1286,7 +1630,7 @@ size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSi size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) { - FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType)); + FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), ""); dctx->dictUses = ZSTD_use_once; return 0; } @@ -1303,8 +1647,8 @@ size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSiz size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize) { DEBUGLOG(4, "ZSTD_initDStream_usingDict"); - FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) ); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , ""); return ZSTD_startingInputLength(zds->format); } @@ -1320,8 +1664,8 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds) * this function cannot fail */ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) { - FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) ); - FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) ); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , ""); return ZSTD_startingInputLength(dctx->format); } @@ -1330,18 +1674,28 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) * this function cannot fail */ size_t ZSTD_resetDStream(ZSTD_DStream* dctx) { - FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only)); + FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), ""); return ZSTD_startingInputLength(dctx->format); } size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); ZSTD_clearDict(dctx); if (ddict) { dctx->ddict = ddict; dctx->dictUses = ZSTD_use_indefinitely; + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) { + if (dctx->ddictSet == NULL) { + dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem); + if (!dctx->ddictSet) { + RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!"); + } + } + assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */ + FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), ""); + } } return 0; } @@ -1354,16 +1708,16 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize) ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax); size_t const min = (size_t)1 << bounds.lowerBound; size_t const max = (size_t)1 << bounds.upperBound; - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); - RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound); - RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, ""); + RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, ""); dctx->maxWindowSize = maxWindowSize; return 0; } size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) { - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format); } ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) @@ -1379,6 +1733,18 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) bounds.upperBound = (int)ZSTD_f_zstd1_magicless; ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); return bounds; + case ZSTD_d_stableOutBuffer: + bounds.lowerBound = (int)ZSTD_bm_buffered; + bounds.upperBound = (int)ZSTD_bm_stable; + return bounds; + case ZSTD_d_forceIgnoreChecksum: + bounds.lowerBound = (int)ZSTD_d_validateChecksum; + bounds.upperBound = (int)ZSTD_d_ignoreChecksum; + return bounds; + case ZSTD_d_refMultipleDDicts: + bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict; + bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts; + return bounds; default:; } bounds.error = ERROR(parameter_unsupported); @@ -1398,12 +1764,35 @@ static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value) } #define CHECK_DBOUNDS(p,v) { \ - RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound); \ + RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \ +} + +size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value) +{ + switch (param) { + case ZSTD_d_windowLogMax: + *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize); + return 0; + case ZSTD_d_format: + *value = (int)dctx->format; + return 0; + case ZSTD_d_stableOutBuffer: + *value = (int)dctx->outBufferMode; + return 0; + case ZSTD_d_forceIgnoreChecksum: + *value = (int)dctx->forceIgnoreChecksum; + return 0; + case ZSTD_d_refMultipleDDicts: + *value = (int)dctx->refMultipleDDicts; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); } size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); switch(dParam) { case ZSTD_d_windowLogMax: if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT; @@ -1414,9 +1803,24 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value CHECK_DBOUNDS(ZSTD_d_format, value); dctx->format = (ZSTD_format_e)value; return 0; + case ZSTD_d_stableOutBuffer: + CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); + dctx->outBufferMode = (ZSTD_bufferMode_e)value; + return 0; + case ZSTD_d_forceIgnoreChecksum: + CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); + dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; + return 0; + case ZSTD_d_refMultipleDDicts: + CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value); + if (dctx->staticSize != 0) { + RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!"); + } + dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value; + return 0; default:; } - RETURN_ERROR(parameter_unsupported); + RETURN_ERROR(parameter_unsupported, ""); } size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) @@ -1428,10 +1832,9 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) } if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { - RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong); + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); ZSTD_clearDict(dctx); - dctx->format = ZSTD_f_zstd1; - dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + ZSTD_DCtx_resetParameters(dctx); } return 0; } @@ -1445,11 +1848,12 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx) size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) { size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); - unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); + /* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/ + unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2); unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); size_t const minRBSize = (size_t) neededSize; RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize, - frameParameter_windowTooLarge); + frameParameter_windowTooLarge, ""); return minRBSize; } @@ -1467,30 +1871,94 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize) ZSTD_frameHeader zfh; size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize); if (ZSTD_isError(err)) return err; - RETURN_ERROR_IF(err>0, srcSize_wrong); + RETURN_ERROR_IF(err>0, srcSize_wrong, ""); RETURN_ERROR_IF(zfh.windowSize > windowSizeMax, - frameParameter_windowTooLarge); + frameParameter_windowTooLarge, ""); return ZSTD_estimateDStreamSize((size_t)zfh.windowSize); } /* ***** Decompression ***** */ -MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +{ + return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR; +} + +static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) { - size_t const length = MIN(dstCapacity, srcSize); - memcpy(dst, src, length); - return length; + if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize)) + zds->oversizedDuration++; + else + zds->oversizedDuration = 0; } +static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds) +{ + return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION; +} + +/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */ +static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output) +{ + ZSTD_outBuffer const expect = zds->expectedOutBuffer; + /* No requirement when ZSTD_obm_stable is not enabled. */ + if (zds->outBufferMode != ZSTD_bm_stable) + return 0; + /* Any buffer is allowed in zdss_init, this must be the same for every other call until + * the context is reset. + */ + if (zds->streamStage == zdss_init) + return 0; + /* The buffer must match our expectation exactly. */ + if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size) + return 0; + RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!"); +} + +/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream() + * and updates the stage and the output buffer state. This call is extracted so it can be + * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode. + * NOTE: You must break after calling this function since the streamStage is modified. + */ +static size_t ZSTD_decompressContinueStream( + ZSTD_DStream* zds, char** op, char* oend, + void const* src, size_t srcSize) { + int const isSkipFrame = ZSTD_isSkipFrame(zds); + if (zds->outBufferMode == ZSTD_bm_buffered) { + size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart; + size_t const decodedSize = ZSTD_decompressContinue(zds, + zds->outBuff + zds->outStart, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + if (!decodedSize && !isSkipFrame) { + zds->streamStage = zdss_read; + } else { + zds->outEnd = zds->outStart + decodedSize; + zds->streamStage = zdss_flush; + } + } else { + /* Write directly into the output buffer */ + size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op); + size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + *op += decodedSize; + /* Flushing is not needed. */ + zds->streamStage = zdss_read; + assert(*op <= oend); + assert(zds->outBufferMode == ZSTD_bm_stable); + } + return 0; +} size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input) { - const char* const istart = (const char*)(input->src) + input->pos; - const char* const iend = (const char*)(input->src) + input->size; + const char* const src = (const char*)input->src; + const char* const istart = input->pos != 0 ? src + input->pos : src; + const char* const iend = input->size != 0 ? src + input->size : src; const char* ip = istart; - char* const ostart = (char*)(output->dst) + output->pos; - char* const oend = (char*)(output->dst) + output->size; + char* const dst = (char*)output->dst; + char* const ostart = output->pos != 0 ? dst + output->pos : dst; + char* const oend = output->size != 0 ? dst + output->size : dst; char* op = ostart; U32 someMoreWork = 1; @@ -1506,6 +1974,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB "forbidden. out: pos: %u vs size: %u", (U32)output->pos, (U32)output->size); DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); + FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), ""); while (someMoreWork) { switch(zds->streamStage) @@ -1514,9 +1983,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB DEBUGLOG(5, "stage zdss_init => transparent reset "); zds->streamStage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) zds->legacyVersion = 0; +#endif zds->hostageByte = 0; - /* fall-through */ + zds->expectedOutBuffer = *output; + ZSTD_FALLTHROUGH; case zdss_loadHeader : DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip)); @@ -1530,7 +2002,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } #endif { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format); - DEBUGLOG(5, "header size : %u", (U32)hSize); + if (zds->refMultipleDDicts && zds->ddictSet) { + ZSTD_DCtx_selectFrameDDict(zds); + } if (ZSTD_isError(hSize)) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); @@ -1543,7 +2017,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB "legacy support is incompatible with static dctx"); FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext, zds->previousLegacyVersion, legacyVersion, - dict, dictSize)); + dict, dictSize), ""); zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input); if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */ @@ -1558,24 +2032,30 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB assert(iend >= ip); if (toLoad > remainingInput) { /* not enough input to load full header */ if (remainingInput > 0) { - memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); zds->lhSize += remainingInput; } input->pos = input->size; + /* check first few bytes */ + FORWARD_IF_ERROR( + ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format), + "First few bytes detected incorrect" ); + /* return hint input size */ return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ } assert(ip != NULL); - memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; break; } } /* check for single-pass mode opportunity */ - if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */ + if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && zds->fParams.frameType != ZSTD_skippableFrame && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { - size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart); + size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart)); if (cSize <= (size_t)(iend-istart)) { /* shortcut : using single-pass mode */ - size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, 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; DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()") ip = istart + cSize; @@ -1586,15 +2066,23 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB break; } } + /* Check output buffer is large enough for ZSTD_odm_stable. */ + if (zds->outBufferMode == ZSTD_bm_stable + && zds->fParams.frameType != ZSTD_skippableFrame + && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) { + RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small"); + } + /* Consume header (see ZSTDds_decodeFrameHeader) */ DEBUGLOG(4, "Consume header"); - FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds))); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), ""); if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE); zds->stage = ZSTDds_skipFrame; } else { - FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize)); + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), ""); zds->expected = ZSTD_blockHeaderSize; zds->stage = ZSTDds_decodeBlockHeader; } @@ -1605,40 +2093,48 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB (U32)(zds->maxWindowSize >> 10) ); zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize, - frameParameter_windowTooLarge); + frameParameter_windowTooLarge, ""); /* Adapt buffer sizes to frame header instructions */ { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); - size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize); - if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) { - size_t const bufferSize = neededInBuffSize + neededOutBuffSize; - DEBUGLOG(4, "inBuff : from %u to %u", - (U32)zds->inBuffSize, (U32)neededInBuffSize); - DEBUGLOG(4, "outBuff : from %u to %u", - (U32)zds->outBuffSize, (U32)neededOutBuffSize); - if (zds->staticSize) { /* static DCtx */ - DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); - assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ - RETURN_ERROR_IF( - bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), - memory_allocation); - } else { - ZSTD_free(zds->inBuff, zds->customMem); - zds->inBuffSize = 0; - zds->outBuffSize = 0; - zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem); - RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation); - } - zds->inBuffSize = neededInBuffSize; - zds->outBuff = zds->inBuff + zds->inBuffSize; - zds->outBuffSize = neededOutBuffSize; - } } + size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered + ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize) + : 0; + + ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize); + + { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize); + int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds); + + if (tooSmall || tooLarge) { + size_t const bufferSize = neededInBuffSize + neededOutBuffSize; + DEBUGLOG(4, "inBuff : from %u to %u", + (U32)zds->inBuffSize, (U32)neededInBuffSize); + DEBUGLOG(4, "outBuff : from %u to %u", + (U32)zds->outBuffSize, (U32)neededOutBuffSize); + if (zds->staticSize) { /* static DCtx */ + DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); + assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ + RETURN_ERROR_IF( + bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), + memory_allocation, ""); + } else { + ZSTD_customFree(zds->inBuff, zds->customMem); + zds->inBuffSize = 0; + zds->outBuffSize = 0; + zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem); + RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, ""); + } + zds->inBuffSize = neededInBuffSize; + zds->outBuff = zds->inBuff + zds->inBuffSize; + zds->outBuffSize = neededOutBuffSize; + } } } zds->streamStage = zdss_read; - /* fall-through */ + ZSTD_FALLTHROUGH; case zdss_read: DEBUGLOG(5, "stage zdss_read"); - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)); DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); if (neededInSize==0) { /* end of frame */ zds->streamStage = zdss_init; @@ -1646,53 +2142,43 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB break; } if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ - int const isSkipFrame = ZSTD_isSkipFrame(zds); - size_t const decodedSize = ZSTD_decompressContinue(zds, - zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), - ip, neededInSize); - if (ZSTD_isError(decodedSize)) return decodedSize; + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), ""); ip += neededInSize; - if (!decodedSize && !isSkipFrame) break; /* this was just a header */ - zds->outEnd = zds->outStart + decodedSize; - zds->streamStage = zdss_flush; + /* Function modifies the stage so we must break */ break; } } if (ip==iend) { someMoreWork = 0; break; } /* no more input */ zds->streamStage = zdss_load; - /* fall-through */ + ZSTD_FALLTHROUGH; case zdss_load: { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); size_t const toLoad = neededInSize - zds->inPos; int const isSkipFrame = ZSTD_isSkipFrame(zds); size_t loadedSize; + /* At this point we shouldn't be decompressing a block that we can stream. */ + assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip)); if (isSkipFrame) { loadedSize = MIN(toLoad, (size_t)(iend-ip)); } else { RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos, corruption_detected, "should never happen"); - loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip); + loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip)); } ip += loadedSize; zds->inPos += loadedSize; if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ /* decode loaded input */ - { size_t const decodedSize = ZSTD_decompressContinue(zds, - zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart, - zds->inBuff, neededInSize); - if (ZSTD_isError(decodedSize)) return decodedSize; - zds->inPos = 0; /* input is consumed */ - if (!decodedSize && !isSkipFrame) { zds->streamStage = zdss_read; break; } /* this was just a header */ - zds->outEnd = zds->outStart + decodedSize; - } } - zds->streamStage = zdss_flush; - /* fall-through */ - + zds->inPos = 0; /* input is consumed */ + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), ""); + /* Function modifies the stage so we must break */ + break; + } case zdss_flush: { size_t const toFlushSize = zds->outEnd - zds->outStart; - size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize); + size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize); op += flushedSize; zds->outStart += flushedSize; if (flushedSize == toFlushSize) { /* flush completed */ @@ -1712,17 +2198,21 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC); /* some compiler require default to do something */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ } } /* result */ input->pos = (size_t)(ip - (const char*)(input->src)); output->pos = (size_t)(op - (char*)(output->dst)); + + /* Update the expected output buffer for ZSTD_obm_stable. */ + zds->expectedOutBuffer = *output; + if ((ip==istart) && (op==ostart)) { /* no forward progress */ zds->noForwardProgress ++; if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) { - RETURN_ERROR_IF(op==oend, dstSize_tooSmall); - RETURN_ERROR_IF(ip==iend, srcSize_wrong); + RETURN_ERROR_IF(op==oend, dstSize_tooSmall, ""); + RETURN_ERROR_IF(ip==iend, srcSize_wrong, ""); assert(0); } } else { diff --git a/native/zstd/decompress/zstd_decompress_block.c b/native/zstd/decompress/zstd_decompress_block.c old mode 100755 new mode 100644 index 767e5f9..e1ff215 --- a/native/zstd/decompress/zstd_decompress_block.c +++ b/native/zstd/decompress/zstd_decompress_block.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,18 +14,19 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* memcpy, memmove, memset */ -#include "compiler.h" /* prefetch */ -#include "cpu.h" /* bmi2 */ -#include "mem.h" /* low level memory routines */ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/compiler.h" /* prefetch */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ #define FSE_STATIC_LINKING_ONLY -#include "fse.h" +#include "../common/fse.h" #define HUF_STATIC_LINKING_ONLY -#include "huf.h" -#include "zstd_internal.h" +#include "../common/huf.h" +#include "../common/zstd_internal.h" #include "zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd_decompress_block.h" +#include "../common/bits.h" /* ZSTD_highbit32 */ /*_******************************************************* * Macros @@ -44,7 +45,7 @@ /*_******************************************************* * Memory operations **********************************************************/ -static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } +static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } /*-************************************************************* @@ -56,7 +57,7 @@ static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong); + RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, ""); { U32 const cBlockHeader = MEM_readLE24(src); U32 const cSize = cBlockHeader >> 3; @@ -64,23 +65,64 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3); bpPtr->origSize = cSize; /* only useful for RLE */ if (bpPtr->blockType == bt_rle) return 1; - RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected); + RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, ""); return cSize; } } +/* Allocate buffer for literals, either overlapping current dst, or split between dst and litExtraBuffer, or stored entirely within litExtraBuffer */ +static void ZSTD_allocateLiteralsBuffer(ZSTD_DCtx* dctx, void* const dst, const size_t dstCapacity, const size_t litSize, + const streaming_operation streaming, const size_t expectedWriteSize, const unsigned splitImmediately) +{ + if (streaming == not_streaming && dstCapacity > ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH) + { + /* room for litbuffer to fit without read faulting */ + dctx->litBuffer = (BYTE*)dst + ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_in_dst; + } + else if (litSize > ZSTD_LITBUFFEREXTRASIZE) + { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + if (splitImmediately) { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize - ZSTD_LITBUFFEREXTRASIZE; + } + else { + /* initially this will be stored entirely in dst during huffman decoding, it will partially be shifted to litExtraBuffer after */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize; + dctx->litBufferEnd = (BYTE*)dst + expectedWriteSize; + } + dctx->litBufferLocation = ZSTD_split; + } + else + { + /* fits entirely within litExtraBuffer, so no split is necessary */ + dctx->litBuffer = dctx->litExtraBuffer; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + } +} /* Hidden declaration for fullbench */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, - const void* src, size_t srcSize); + const void* src, size_t srcSize, + void* dst, size_t dstCapacity, const streaming_operation streaming); /*! ZSTD_decodeLiteralsBlock() : + * Where it is possible to do so without being stomped by the output during decompression, the literals block will be stored + * in the dstBuffer. If there is room to do so, it will be stored in full in the excess dst space after where the current + * block will be output. Otherwise it will be stored at the end of the current dst blockspace, with a small portion being + * stored in dctx->litExtraBuffer to help keep it "ahead" of the current output write. + * * @return : nb of bytes read from src (< srcSize ) * note : symbol not declared but exposed for fullbench */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, - const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ + const void* src, size_t srcSize, /* note : srcSize < BLOCKSIZE */ + void* dst, size_t dstCapacity, const streaming_operation streaming) { DEBUGLOG(5, "ZSTD_decodeLiteralsBlock"); - RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected); + RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); { const BYTE* const istart = (const BYTE*) src; symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); @@ -89,16 +131,17 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, { case set_repeat: DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block"); - RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted); - /* fall-through */ + RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, ""); + ZSTD_FALLTHROUGH; case set_compressed: - RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3"); + RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need up to 5 for case 3"); { size_t lhSize, litSize, litCSize; U32 singleStream=0; U32 const lhlCode = (istart[0] >> 2) & 3; U32 const lhc = MEM_readLE32(istart); size_t hufSuccess; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); switch(lhlCode) { case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -121,8 +164,11 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); break; } - RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected); - RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected); + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 0); /* prefetch huffman table if cold */ if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) { @@ -133,11 +179,11 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (singleStream) { hufSuccess = HUF_decompress1X_usingDTable_bmi2( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, dctx->bmi2); + dctx->HUFptr, ZSTD_DCtx_get_bmi2(dctx)); } else { hufSuccess = HUF_decompress4X_usingDTable_bmi2( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, dctx->bmi2); + dctx->HUFptr, ZSTD_DCtx_get_bmi2(dctx)); } } else { if (singleStream) { @@ -150,29 +196,36 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), dctx->bmi2); + sizeof(dctx->workspace), ZSTD_DCtx_get_bmi2(dctx)); #endif } else { hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), dctx->bmi2); + sizeof(dctx->workspace), ZSTD_DCtx_get_bmi2(dctx)); } } + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litExtraBuffer, dctx->litBufferEnd - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memmove(dctx->litBuffer + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH, dctx->litBuffer, litSize - ZSTD_LITBUFFEREXTRASIZE); + dctx->litBuffer += ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd -= WILDCOPY_OVERLENGTH; + } - RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected); + RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, ""); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; dctx->litEntropy = 1; if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return litCSize + lhSize; } case set_basic: { size_t litSize, lhSize; U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -185,27 +238,41 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 3: lhSize = 3; + RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize = 3"); litSize = MEM_readLE24(istart) >> 4; break; } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ - RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected); - memcpy(dctx->litBuffer, istart+lhSize, litSize); + RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, ""); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memcpy(dctx->litExtraBuffer, istart + lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize); + } dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return lhSize+litSize; } /* direct reference into compressed stream */ dctx->litPtr = istart+lhSize; dctx->litSize = litSize; + dctx->litBufferEnd = dctx->litPtr + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; return lhSize+litSize; } case set_rle: { U32 const lhlCode = ((istart[0]) >> 2) & 3; size_t litSize, lhSize; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -214,16 +281,28 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 1: lhSize = 2; + RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 3"); litSize = MEM_readLE16(istart) >> 4; break; case 3: lhSize = 3; + RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 4"); litSize = MEM_readLE24(istart) >> 4; - RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4"); break; } - RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected); - memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memset(dctx->litExtraBuffer, istart[lhSize], ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize); + } dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; return lhSize+1; @@ -236,7 +315,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, /* Default FSE distribution tables. * These are pre-calculated FSE decoding tables using default distributions as defined in specification : - * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions + * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions * They were generated programmatically with following method : * - start from default distributions, present in /lib/common/zstd_internal.h * - generate tables normally, using ZSTD_buildFSETable() @@ -343,7 +422,7 @@ static const ZSTD_seqSymbol ML_defaultDTable[(1<nbBits = 0; cell->nextState = 0; assert(nbAddBits < 255); - cell->nbAdditionalBits = (BYTE)nbAddBits; + cell->nbAdditionalBits = nbAddBits; cell->baseValue = baseValue; } @@ -364,23 +443,26 @@ static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddB * generate FSE decoding table for one symbol (ll, ml or off) * cannot fail if input is valid => * all inputs are presumed validated at this stage */ -void -ZSTD_buildFSETable(ZSTD_seqSymbol* dt, +FORCE_INLINE_TEMPLATE +void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U32* nbAdditionalBits, - unsigned tableLog) + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize) { ZSTD_seqSymbol* const tableDecode = dt+1; - U16 symbolNext[MaxSeq+1]; - U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; - U32 highThreshold = tableSize-1; + + U16* symbolNext = (U16*)wksp; + BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1); + U32 highThreshold = tableSize - 1; + /* Sanity Checks */ assert(maxSymbolValue <= MaxSeq); assert(tableLog <= MaxFSELog); - + assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE); + (void)wkspSize; /* Init, lay down lowprob symbols */ { ZSTD_seqSymbol_header DTableH; DTableH.tableLog = tableLog; @@ -396,34 +478,127 @@ ZSTD_buildFSETable(ZSTD_seqSymbol* dt, assert(normalizedCounter[s]>=0); symbolNext[s] = (U16)normalizedCounter[s]; } } } - memcpy(dt, &DTableH, sizeof(DTableH)); + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - { U32 const tableMask = tableSize-1; + assert(tableSize <= 512); + /* Specialized symbol spreading for the case when there are + * no low probability (-1 count) symbols. When compressing + * small blocks we avoid low probability symbols to hit this + * case, since header decoding speed matters more. + */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ + while (UNLIKELY(position > highThreshold)) position = (position + step) & tableMask; /* lowprob area */ } } assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ } /* Build Decoding table */ - { U32 u; + { + U32 u; for (u=0; u max, corruption_detected); + RETURN_ERROR_IF(!srcSize, srcSize_wrong, ""); + RETURN_ERROR_IF((*(const BYTE*)src) > max, corruption_detected, ""); { U32 const symbol = *(const BYTE*)src; U32 const baseline = baseValue[symbol]; - U32 const nbBits = nbAdditionalBits[symbol]; + U8 const nbBits = nbAdditionalBits[symbol]; ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits); } *DTablePtr = DTableSpace; @@ -453,7 +629,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb *DTablePtr = defaultTable; return 0; case set_repeat: - RETURN_ERROR_IF(!flagRepeatTable, corruption_detected); + RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, ""); /* prefetch FSE table if used */ if (ddictIsCold && (nbSeq > 24 /* heuristic */)) { const void* const pStart = *DTablePtr; @@ -465,9 +641,9 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb { unsigned tableLog; S16 norm[MaxSeq+1]; size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); - RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected); - RETURN_ERROR_IF(tableLog > maxLog, corruption_detected); - ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog); + RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, ""); + RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, ""); + ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2); *DTablePtr = DTableSpace; return headerSize; } @@ -480,35 +656,36 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE* const)src; + const BYTE* const istart = (const BYTE*)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; int nbSeq; DEBUGLOG(5, "ZSTD_decodeSeqHeaders"); /* check */ - RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong); + RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, ""); /* SeqHead */ nbSeq = *ip++; if (!nbSeq) { *nbSeqPtr=0; - RETURN_ERROR_IF(srcSize != 1, srcSize_wrong); + RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, ""); return 1; } if (nbSeq > 0x7F) { if (nbSeq == 0xFF) { - RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong); - nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2; + RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, ""); + nbSeq = MEM_readLE16(ip) + LONGNBSEQ; + ip+=2; } else { - RETURN_ERROR_IF(ip >= iend, srcSize_wrong); + RETURN_ERROR_IF(ip >= iend, srcSize_wrong, ""); nbSeq = ((nbSeq-0x80)<<8) + *ip++; } } *nbSeqPtr = nbSeq; /* FSE table descriptors */ - RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong); /* minimum possible size: 1 byte for symbol encoding types */ + RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); @@ -520,8 +697,10 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip, iend-ip, LL_base, LL_bits, LL_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq); - RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected); + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += llhSize; } @@ -530,8 +709,10 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip, iend-ip, OF_base, OF_bits, OF_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq); - RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected); + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += ofhSize; } @@ -540,8 +721,10 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip, iend-ip, ML_base, ML_bits, ML_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq); - RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected); + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += mlhSize; } } @@ -554,7 +737,6 @@ typedef struct { size_t litLength; size_t matchLength; size_t offset; - const BYTE* match; } seq_t; typedef struct { @@ -568,9 +750,6 @@ typedef struct { ZSTD_fseState stateOffb; ZSTD_fseState stateML; size_t prevOffset[ZSTD_REP_NUM]; - const BYTE* prefixStart; - const BYTE* dictEnd; - size_t pos; } seqState_t; /*! ZSTD_overlapCopy8() : @@ -580,7 +759,7 @@ typedef struct { * Precondition: *ip <= *op * Postcondition: *op - *op >= 8 */ -static void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { +HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { assert(*ip <= *op); if (offset < 8) { /* close range match, overlap */ @@ -613,7 +792,7 @@ static void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. * The src buffer must be before the dst buffer. */ -static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { +static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { ptrdiff_t const diff = op - ip; BYTE* const oend = op + length; @@ -629,6 +808,7 @@ static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_ /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ assert(length >= 8); ZSTD_overlapCopy8(&op, &ip, diff); + length -= 8; assert(op - ip >= 8); assert(op <= oend); } @@ -643,8 +823,31 @@ static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_ assert(oend > oend_w); ZSTD_wildcopy(op, ip, oend_w - op, ovtype); ip += oend_w - op; - op = oend_w; + op += oend_w - op; + } + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + +/* ZSTD_safecopyDstBeforeSrc(): + * This version allows overlap with dst before src, or handles the non-overlap case with dst after src + * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ +static void ZSTD_safecopyDstBeforeSrc(BYTE* op, BYTE const* ip, ptrdiff_t length) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + if (length < 8 || diff > -8) { + /* Handle short lengths, close overlaps, and dst not before src. */ + while (op < oend) *op++ = *ip++; + return; } + + if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { + ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); + ip += oend - WILDCOPY_OVERLENGTH - op; + op += oend - WILDCOPY_OVERLENGTH - op; + } + /* Handle the leftovers. */ while (op < oend) *op++ = *ip++; } @@ -659,21 +862,21 @@ static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_ */ FORCE_NOINLINE size_t ZSTD_execSequenceEnd(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; - BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ const BYTE* const iLitEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; - /* bounds checks */ - assert(oLitEnd < oMatchEnd); - RETURN_ERROR_IF(oMatchEnd > oend, dstSize_tooSmall, "last match must fit within dstBuffer"); - RETURN_ERROR_IF(iLitEnd > litLimit, corruption_detected, "try to read beyond literal buffer"); + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); /* copy literals */ ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap); @@ -683,42 +886,199 @@ size_t ZSTD_execSequenceEnd(BYTE* op, /* copy Match */ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { /* offset beyond prefix */ - RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected); - match = dictEnd - (prefixStart-match); + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); if (match + sequence.matchLength <= dictEnd) { - memmove(oLitEnd, match, sequence.matchLength); + ZSTD_memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } } + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +/* ZSTD_execSequenceEndSplitLitBuffer(): + * This version is intended to be used during instances where the litBuffer is still split. It is kept separate to avoid performance impact for the good case. + */ +FORCE_NOINLINE +size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + RETURN_ERROR_IF(op > *litPtr && op < *litPtr + sequence.litLength, dstSize_tooSmall, "output should not catch up to and overwrite literal buffer"); + ZSTD_safecopyDstBeforeSrc(op, *litPtr, sequence.litLength); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); return sequenceLength; } HINT_INLINE size_t ZSTD_execSequence(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ - BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */ const BYTE* const iLitEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; - /* Errors and uncommon cases handled here. */ - assert(oLitEnd < oMatchEnd); - if (iLitEnd > litLimit || oMatchEnd > oend_w) + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + +#if defined(__aarch64__) + /* prefetch sequence starting from match that will be used for copy later */ + PREFETCH_L1(match); +#endif + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op + 16, (*litPtr) + 16, sequence.litLength - 16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + +HINT_INLINE +size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEndSplitLitBuffer(op, oend, oend_w, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); assert(iLitEnd <= litLimit /* Literal length is in bounds */); assert(oLitEnd <= oend_w /* Can wildcopy literals */); assert(oMatchEnd <= oend_w /* Can wildcopy matches */); @@ -729,7 +1089,7 @@ size_t ZSTD_execSequence(BYTE* op, */ assert(WILDCOPY_OVERLENGTH >= 16); ZSTD_copy16(op, (*litPtr)); - if (sequence.litLength > 16) { + if (UNLIKELY(sequence.litLength > 16)) { ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap); } op = oLitEnd; @@ -738,15 +1098,15 @@ size_t ZSTD_execSequence(BYTE* op, /* Copy Match */ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { /* offset beyond prefix -> go into extDict */ - RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected); + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); match = dictEnd + (match - prefixStart); if (match + sequence.matchLength <= dictEnd) { - memmove(oLitEnd, match, sequence.matchLength); + ZSTD_memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - memmove(oLitEnd, match, length1); + ZSTD_memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; match = prefixStart; @@ -760,7 +1120,7 @@ size_t ZSTD_execSequence(BYTE* op, /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy * without overlap checking. */ - if (sequence.offset >= WILDCOPY_VECLEN) { + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { /* We bet on a full wildcopy for matches, since we expect matches to be * longer than literals (in general). In silesia, ~10% of matches are longer * than 16 bytes. @@ -781,6 +1141,7 @@ size_t ZSTD_execSequence(BYTE* op, return sequenceLength; } + static void ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt) { @@ -794,12 +1155,10 @@ ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqS } FORCE_INLINE_TEMPLATE void -ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD) +ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 nextState, U32 nbBits) { - ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; size_t const lowBits = BIT_readBits(bitD, nbBits); - DStatePtr->state = DInfo.nextState + lowBits; + DStatePtr->state = nextState + lowBits; } /* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum @@ -814,102 +1173,196 @@ ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD) typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; -#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG FORCE_INLINE_TEMPLATE seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets) { seq_t seq; - U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits; - U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits; - U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits; - U32 const totalBits = llBits+mlBits+ofBits; - U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue; - U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue; - U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue; - - /* sequence */ - { size_t offset; - if (!ofBits) - offset = 0; - else { - ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); - assert(ofBits <= MaxOff); - if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { - U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed); - offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); - BIT_reloadDStream(&seqState->DStream); - if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); - assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */ - } else { - offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); - } - } + /* + * ZSTD_seqSymbol is a structure with a total of 64 bits wide. So it can be + * loaded in one operation and extracted its fields by simply shifting or + * bit-extracting on aarch64. + * GCC doesn't recognize this and generates more unnecessary ldr/ldrb/ldrh + * operations that cause performance drop. This can be avoided by using this + * ZSTD_memcpy hack. + */ +#if defined(__aarch64__) && (defined(__GNUC__) && !defined(__clang__)) + ZSTD_seqSymbol llDInfoS, mlDInfoS, ofDInfoS; + ZSTD_seqSymbol* const llDInfo = &llDInfoS; + ZSTD_seqSymbol* const mlDInfo = &mlDInfoS; + ZSTD_seqSymbol* const ofDInfo = &ofDInfoS; + ZSTD_memcpy(llDInfo, seqState->stateLL.table + seqState->stateLL.state, sizeof(ZSTD_seqSymbol)); + ZSTD_memcpy(mlDInfo, seqState->stateML.table + seqState->stateML.state, sizeof(ZSTD_seqSymbol)); + ZSTD_memcpy(ofDInfo, seqState->stateOffb.table + seqState->stateOffb.state, sizeof(ZSTD_seqSymbol)); +#else + const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; + const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; + const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; +#endif + seq.matchLength = mlDInfo->baseValue; + seq.litLength = llDInfo->baseValue; + { U32 const ofBase = ofDInfo->baseValue; + BYTE const llBits = llDInfo->nbAdditionalBits; + BYTE const mlBits = mlDInfo->nbAdditionalBits; + BYTE const ofBits = ofDInfo->nbAdditionalBits; + BYTE const totalBits = llBits+mlBits+ofBits; + + U16 const llNext = llDInfo->nextState; + U16 const mlNext = mlDInfo->nextState; + U16 const ofNext = ofDInfo->nextState; + U32 const llnbBits = llDInfo->nbBits; + U32 const mlnbBits = mlDInfo->nbBits; + U32 const ofnbBits = ofDInfo->nbBits; + /* + * As gcc has better branch and block analyzers, sometimes it is only + * valuable to mark likeliness for clang, it gives around 3-4% of + * performance. + */ - if (ofBits <= 1) { - offset += (llBase==0); - if (offset) { - size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; - temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ - if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + /* sequence */ + { size_t offset; + #if defined(__clang__) + if (LIKELY(ofBits > 1)) { + #else + if (ofBits > 1) { + #endif + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + assert(ofBits <= MaxOff); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed); + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); + assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */ + } else { + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } + seqState->prevOffset[2] = seqState->prevOffset[1]; seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset = temp; - } else { /* offset == 0 */ - offset = seqState->prevOffset[0]; - } - } else { - seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset; + seqState->prevOffset[0] = offset; + } else { + U32 const ll0 = (llDInfo->baseValue == 0); + if (LIKELY((ofBits == 0))) { + offset = seqState->prevOffset[ll0]; + seqState->prevOffset[1] = seqState->prevOffset[!ll0]; + seqState->prevOffset[0] = offset; + } else { + offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); + { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } } } + seq.offset = offset; } - seq.offset = offset; - } - seq.matchLength = mlBase - + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/) : 0); /* <= 16 bits */ - if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) - BIT_reloadDStream(&seqState->DStream); - if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) - BIT_reloadDStream(&seqState->DStream); - /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ - ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); - - seq.litLength = llBase - + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits/*>0*/) : 0); /* <= 16 bits */ - if (MEM_32bits()) - BIT_reloadDStream(&seqState->DStream); - - DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", - (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); - - /* ANS state update */ - ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ - ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ - ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ + #if defined(__clang__) + if (UNLIKELY(mlBits > 0)) + #else + if (mlBits > 0) + #endif + seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); + + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + + #if defined(__clang__) + if (UNLIKELY(llBits > 0)) + #else + if (llBits > 0) + #endif + seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); + + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); + + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + + ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ + } return seq; } +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +MEM_STATIC int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd) +{ + size_t const windowSize = dctx->fParams.windowSize; + /* No dictionary used. */ + if (dctx->dictContentEndForFuzzing == NULL) return 0; + /* Dictionary is our prefix. */ + if (prefixStart == dctx->dictContentBeginForFuzzing) return 1; + /* Dictionary is not our ext-dict. */ + if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0; + /* Dictionary is not within our window size. */ + if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0; + /* Dictionary is active. */ + return 1; +} + +MEM_STATIC void ZSTD_assertValidSequence( + ZSTD_DCtx const* dctx, + BYTE const* op, BYTE const* oend, + seq_t const seq, + BYTE const* prefixStart, BYTE const* virtualStart) +{ +#if DEBUGLEVEL >= 1 + size_t const windowSize = dctx->fParams.windowSize; + size_t const sequenceSize = seq.litLength + seq.matchLength; + BYTE const* const oLitEnd = op + seq.litLength; + DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + assert(op <= oend); + assert((size_t)(oend - op) >= sequenceSize); + assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX); + if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { + size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); + /* Offset must be within the dictionary. */ + assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); + assert(seq.offset <= windowSize + dictSize); + } else { + /* Offset must be within our window. */ + assert(seq.offset <= windowSize); + } +#else + (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart; +#endif +} +#endif + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + + FORCE_INLINE_TEMPLATE size_t DONT_VECTORIZE -ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, +ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* litBufferEnd = dctx->litBufferEnd; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const vBase = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - DEBUGLOG(5, "ZSTD_decompressSequences_body"); + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer"); + (void)frame; /* Regen sequences */ if (nbSeq) { @@ -918,38 +1371,279 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, { U32 i; for (i=0; ientropy.rep[i]; } RETURN_ERROR_IF( ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), - corruption_detected); + corruption_detected, ""); ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); ZSTD_STATIC_ASSERT( BIT_DStream_unfinished < BIT_DStream_completed && BIT_DStream_endOfBuffer < BIT_DStream_completed && BIT_DStream_completed < BIT_DStream_overflow); - for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) { - nbSeq--; - { seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); - size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); + /* decompress without overrunning litPtr begins */ + { + seq_t sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + /* Align the decompression loop to 32 + 16 bytes. + * + * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression + * speed swings based on the alignment of the decompression loop. This + * performance swing is caused by parts of the decompression loop falling + * out of the DSB. The entire decompression loop should fit in the DSB, + * when it can't we get much worse performance. You can measure if you've + * hit the good case or the bad case with this perf command for some + * compressed file test.zst: + * + * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ + * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst + * + * If you see most cycles served out of the MITE you've hit the bad case. + * If you see most cycles served out of the DSB you've hit the good case. + * If it is pretty even then you may be in an okay case. + * + * This issue has been reproduced on the following CPUs: + * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 + * Use Instruments->Counters to get DSB/MITE cycles. + * I never got performance swings, but I was able to + * go from the good case of mostly DSB to half of the + * cycles served from MITE. + * - Coffeelake: Intel i9-9900k + * - Coffeelake: Intel i7-9700k + * + * I haven't been able to reproduce the instability or DSB misses on any + * of the following CPUS: + * - Haswell + * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH + * - Skylake + * + * Alignment is done for each of the three major decompression loops: + * - ZSTD_decompressSequences_bodySplitLitBuffer - presplit section of the literal buffer + * - ZSTD_decompressSequences_bodySplitLitBuffer - postsplit section of the literal buffer + * - ZSTD_decompressSequences_body + * Alignment choices are made to minimize large swings on bad cases and influence on performance + * from changes external to this code, rather than to overoptimize on the current commit. + * + * If you are seeing performance stability this script can help test. + * It tests on 4 commits in zstd where I saw performance change. + * + * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 + */ +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); +# if __GNUC__ >= 7 + /* good for gcc-7, gcc-9, and gcc-11 */ + __asm__("nop"); + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 4"); +# if __GNUC__ == 8 || __GNUC__ == 10 + /* good for gcc-8 and gcc-10 */ + __asm__("nop"); + __asm__(".p2align 3"); +# endif +# endif +#endif + + /* Handle the initial state where litBuffer is currently split between dst and litExtraBuffer */ + for (; litPtr + sequence.litLength <= dctx->litBufferEnd; ) { + size_t const oneSeqSize = ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence.litLength - WILDCOPY_OVERLENGTH, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; - } } + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + } + + /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ + if (nbSeq > 0) { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence.litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (--nbSeq) + BIT_reloadDStream(&(seqState.DStream)); + } + } + } + + if (nbSeq > 0) /* there is remaining lit from extra buffer */ + { + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ != 7 + /* worse for gcc-7 better for gcc-8, gcc-9, and gcc-10 and clang */ + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# elif __GNUC__ >= 11 + __asm__(".p2align 3"); +# else + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for (; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } + } + + /* check if reached exact end */ + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer: after decode loop, remaining nbSeq : %i", nbSeq); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + if (dctx->litBufferLocation == ZSTD_split) /* split hasn't been reached yet, first get dst then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ostart + maxDstSize : dctx->litBuffer; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* const prefixStart = (const BYTE*)(dctx->prefixStart); + const BYTE* const vBase = (const BYTE*)(dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*)(dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_body: nbSeq = %d", nbSeq); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ >= 7 + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# else + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for ( ; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } /* check if reached exact end */ DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); - RETURN_ERROR_IF(nbSeq, corruption_detected); - RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); /* save reps for next block */ { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } } /* last literal segment */ { size_t const lastLLSize = litEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall); - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } } return op-ostart; @@ -959,157 +1653,180 @@ static size_t ZSTD_decompressSequences_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { - return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } -#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ - - -#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT -FORCE_INLINE_TEMPLATE seq_t -ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets) +static size_t +ZSTD_decompressSequencesSplitLitBuffer_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) { - seq_t seq; - U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits; - U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits; - U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits; - U32 const totalBits = llBits+mlBits+ofBits; - U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue; - U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue; - U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue; - - /* sequence */ - { size_t offset; - if (!ofBits) - offset = 0; - else { - ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); - assert(ofBits <= MaxOff); - if (MEM_32bits() && longOffsets) { - U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1); - offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); - if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream); - if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); - } else { - offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); - } - } + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ - if (ofBits <= 1) { - offset += (llBase==0); - if (offset) { - size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; - temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ - if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset = temp; - } else { - offset = seqState->prevOffset[0]; - } - } else { - seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset; - } - seq.offset = offset; - } +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT - seq.matchLength = mlBase + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */ - if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) - BIT_reloadDStream(&seqState->DStream); - if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) - BIT_reloadDStream(&seqState->DStream); - /* Verify that there is enough bits to read the rest of the data in 64-bit mode. */ - ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); - - seq.litLength = llBase + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */ - if (MEM_32bits()) - BIT_reloadDStream(&seqState->DStream); - - { size_t const pos = seqState->pos + seq.litLength; - const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart; - seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. - * No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */ - seqState->pos = pos + seq.matchLength; +FORCE_INLINE_TEMPLATE size_t +ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, + const BYTE* const prefixStart, const BYTE* const dictEnd) +{ + prefetchPos += sequence.litLength; + { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; + const BYTE* const match = matchBase + prefetchPos - sequence.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. + * No consequence though : memory address is only used for prefetching, not for dereferencing */ + PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ } - - /* ANS state update */ - ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ - ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ - ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ - - return seq; + return prefetchPos + sequence.matchLength; } +/* This decoding function employs prefetching + * to reduce latency impact of cache misses. + * It's generally employed when block contains a significant portion of long-distance matches + * or when coupled with a "cold" dictionary */ FORCE_INLINE_TEMPLATE size_t ZSTD_decompressSequencesLong_body( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE* const)dst; - BYTE* const oend = ostart + maxDstSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* litBufferEnd = dctx->litBufferEnd; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + (void)frame; /* Regen sequences */ if (nbSeq) { -#define STORED_SEQS 4 +#define STORED_SEQS 8 #define STORED_SEQS_MASK (STORED_SEQS-1) -#define ADVANCED_SEQS 4 +#define ADVANCED_SEQS STORED_SEQS seq_t sequences[STORED_SEQS]; int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); seqState_t seqState; int seqNb; + size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */ + dctx->fseEntropy = 1; { int i; for (i=0; ientropy.rep[i]; } - seqState.prefixStart = prefixStart; - seqState.pos = (size_t)(op-prefixStart); - seqState.dictEnd = dictEnd; + assert(dst != NULL); assert(iend >= ip); RETURN_ERROR_IF( ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), - corruption_detected); + corruption_detected, ""); ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); /* prepare in advance */ for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNblitBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) + { + /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } + else + { + /* lit buffer is either wholly contained in first or second split, or not split at all*/ + oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength - WILDCOPY_OVERLENGTH, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } } - RETURN_ERROR_IF(seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) + { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence->litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + else + { + size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence->litLength - WILDCOPY_OVERLENGTH, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } } /* save reps for next block */ @@ -1117,10 +1834,23 @@ ZSTD_decompressSequencesLong_body( } /* last literal segment */ - { size_t const lastLLSize = litEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall); - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; + if (dctx->litBufferLocation == ZSTD_split) /* first deplete literal buffer in dst, then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } } return op-ostart; @@ -1130,9 +1860,10 @@ static size_t ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1141,25 +1872,37 @@ ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, #if DYNAMIC_BMI2 #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG -static TARGET_ATTRIBUTE("bmi2") size_t +static BMI2_TARGET_ATTRIBUTE size_t DONT_VECTORIZE ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { - return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequencesSplitLitBuffer_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT -static TARGET_ATTRIBUTE("bmi2") size_t +static BMI2_TARGET_ATTRIBUTE size_t ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1169,21 +1912,37 @@ typedef size_t (*ZSTD_decompressSequences_t)( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset); + const ZSTD_longOffset_e isLongOffset, + const int frame); #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG static size_t ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { DEBUGLOG(5, "ZSTD_decompressSequences"); #if DYNAMIC_BMI2 - if (dctx->bmi2) { - return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif - return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static size_t +ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ @@ -1198,15 +1957,16 @@ static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { DEBUGLOG(5, "ZSTD_decompressSequencesLong"); #if DYNAMIC_BMI2 - if (dctx->bmi2) { - return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif - return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1240,11 +2000,10 @@ ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable) } #endif - size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const int frame) + const void* src, size_t srcSize, const int frame, const streaming_operation streaming) { /* blockType == blockCompressed */ const BYTE* ip = (const BYTE*)src; /* isLongOffset must be true if there are long offsets. @@ -1256,11 +2015,11 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)))); DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize); - RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong); + RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, ""); /* Decode literals section */ - { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); - DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : cSize=%u, nbLiterals=%zu", (U32)litCSize, dctx->litSize); if (ZSTD_isError(litCSize)) return litCSize; ip += litCSize; srcSize -= litCSize; @@ -1282,6 +2041,8 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, ip += seqHSize; srcSize -= seqHSize; + RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + #if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) if ( !usePrefetchDecoder @@ -1300,24 +2061,38 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, if (usePrefetchDecoder) #endif #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT - return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); #endif #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG /* else */ - return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); + if (dctx->litBufferLocation == ZSTD_split) + return ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + else + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); #endif } } +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) +{ + if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dst; + dctx->previousDstEnd = dst; + } +} + + size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { size_t dSize; - ZSTD_checkContinuity(dctx, dst); - dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0); + ZSTD_checkContinuity(dctx, dst, dstCapacity); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0, not_streaming); dctx->previousDstEnd = (char*)dst + dSize; return dSize; } diff --git a/native/zstd/decompress/zstd_decompress_block.h b/native/zstd/decompress/zstd_decompress_block.h old mode 100755 new mode 100644 index 7e92960..c61a9d0 --- a/native/zstd/decompress/zstd_decompress_block.h +++ b/native/zstd/decompress/zstd_decompress_block.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,9 +15,9 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* size_t */ -#include "zstd.h" /* DCtx, and some public functions */ -#include "zstd_internal.h" /* blockProperties_t, and some public functions */ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* DCtx, and some public functions */ +#include "../common/zstd_internal.h" /* blockProperties_t, and some public functions */ #include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */ @@ -33,6 +33,12 @@ */ + /* Streaming state is used to inform allocation of the literal buffer */ +typedef enum { + not_streaming = 0, + is_streaming = 1 +} streaming_operation; + /* ZSTD_decompressBlock_internal() : * decompress block, starting at `src`, * into destination buffer `dst`. @@ -41,19 +47,22 @@ */ size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const int frame); + const void* src, size_t srcSize, const int frame, const streaming_operation streaming); /* ZSTD_buildFSETable() : * generate FSE decoding table for one symbol (ll, ml or off) * this function must be called with valid parameters only * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) * in which case it cannot fail. + * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is + * defined in zstd_decompress_internal.h. * Internal use only. */ void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U32* nbAdditionalBits, - unsigned tableLog); + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize, + int bmi2); #endif /* ZSTD_DEC_BLOCK_H */ diff --git a/native/zstd/decompress/zstd_decompress_internal.h b/native/zstd/decompress/zstd_decompress_internal.h old mode 100755 new mode 100644 index ccbdfa0..91e9dce --- a/native/zstd/decompress/zstd_decompress_internal.h +++ b/native/zstd/decompress/zstd_decompress_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -19,34 +19,34 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "mem.h" /* BYTE, U16, U32 */ -#include "zstd_internal.h" /* ZSTD_seqSymbol */ +#include "../common/mem.h" /* BYTE, U16, U32 */ +#include "../common/zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ /*-******************************************************* * Constants *********************************************************/ -static const U32 LL_base[MaxLL+1] = { +static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000 }; -static const U32 OF_base[MaxOff+1] = { +static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; -static const U32 OF_bits[MaxOff+1] = { +static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; -static const U32 ML_base[MaxML+1] = { +static UNUSED_ATTR const U32 ML_base[MaxML+1] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, @@ -73,12 +73,17 @@ static const U32 ML_base[MaxML+1] = { #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 + typedef struct { ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ - HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */ U32 rep[ZSTD_REP_NUM]; + U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; } ZSTD_entropyDTables_t; typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, @@ -95,6 +100,29 @@ typedef enum { ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ } ZSTD_dictUses_e; +/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ +typedef struct { + const ZSTD_DDict** ddictPtrTable; + size_t ddictPtrTableSize; + size_t ddictPtrCount; +} ZSTD_DDictHashSet; + +#ifndef ZSTD_DECODER_INTERNAL_BUFFER +# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) +#endif + +#define ZSTD_LBMIN 64 +#define ZSTD_LBMAX (128 << 10) + +/* extra buffer, compensates when dst is not large enough to store litBuffer */ +#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) + +typedef enum { + ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ + ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ + ZSTD_split = 2 /* Split between litExtraBuffer and dst */ +} ZSTD_litLocation_e; + struct ZSTD_DCtx_s { const ZSTD_seqSymbol* LLTptr; @@ -109,6 +137,7 @@ struct ZSTD_DCtx_s const void* dictEnd; /* end of previous segment */ size_t expected; ZSTD_frameHeader fParams; + U64 processedCSize; U64 decodedSize; blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ ZSTD_dStage stage; @@ -117,12 +146,16 @@ struct ZSTD_DCtx_s XXH64_state_t xxhState; size_t headerSize; ZSTD_format_e format; + ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ + U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ const BYTE* litPtr; ZSTD_customMem customMem; size_t litSize; size_t rleSize; size_t staticSize; +#if DYNAMIC_BMI2 != 0 int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ +#endif /* dictionary */ ZSTD_DDict* ddictLocal; @@ -130,6 +163,8 @@ struct ZSTD_DCtx_s U32 dictID; int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ ZSTD_dictUses_e dictUses; + ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ + ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ /* streaming */ ZSTD_dStreamStage streamStage; @@ -142,17 +177,44 @@ struct ZSTD_DCtx_s size_t outStart; size_t outEnd; size_t lhSize; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) void* legacyContext; U32 previousLegacyVersion; U32 legacyVersion; +#endif U32 hostageByte; int noForwardProgress; + ZSTD_bufferMode_e outBufferMode; + ZSTD_outBuffer expectedOutBuffer; /* workspace */ - BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH]; + BYTE* litBuffer; + const BYTE* litBufferEnd; + ZSTD_litLocation_e litBufferLocation; + BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; + + size_t oversizedDuration; + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + void const* dictContentBeginForFuzzing; + void const* dictContentEndForFuzzing; +#endif + + /* Tracing */ +#if ZSTD_TRACE + ZSTD_TraceCtx traceCtx; +#endif }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ +MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { +#if DYNAMIC_BMI2 != 0 + return dctx->bmi2; +#else + (void)dctx; + return 0; +#endif +} /*-******************************************************* * Shared internal functions @@ -160,7 +222,7 @@ struct ZSTD_DCtx_s /*! ZSTD_loadDEntropy() : * dict : must point at beginning of a valid zstd dictionary. - * @return : size of entropy tables read */ + * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, const void* const dict, size_t const dictSize); @@ -169,7 +231,7 @@ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, * If yes, do nothing (continue on current segment). * If not, classify previous segment as "external dictionary", and start a new segment. * This function cannot fail. */ -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst); +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); #endif /* ZSTD_DECOMPRESS_INTERNAL_H */ diff --git a/native/zstd/deprecated/zbuff.h b/native/zstd/deprecated/zbuff.h old mode 100755 new mode 100644 index 04183ea..b83ea0f --- a/native/zstd/deprecated/zbuff.h +++ b/native/zstd/deprecated/zbuff.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -28,7 +28,7 @@ extern "C" { * Dependencies ***************************************/ #include /* size_t */ -#include "zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */ +#include "../zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */ /* *************************************************************** @@ -186,7 +186,7 @@ ZBUFF_DEPRECATED("use ZSTD_DStreamOutSize") size_t ZBUFF_recommendedDOutSize(voi /*--- Dependency ---*/ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_customMem */ -#include "zstd.h" +#include "../zstd.h" /*--- Custom memory allocator ---*/ diff --git a/native/zstd/deprecated/zbuff_common.c b/native/zstd/deprecated/zbuff_common.c old mode 100755 new mode 100644 index 661b9b0..e7d01a0 --- a/native/zstd/deprecated/zbuff_common.c +++ b/native/zstd/deprecated/zbuff_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,7 +11,7 @@ /*-************************************* * Dependencies ***************************************/ -#include "error_private.h" +#include "../common/error_private.h" #include "zbuff.h" /*-**************************************** diff --git a/native/zstd/deprecated/zbuff_compress.c b/native/zstd/deprecated/zbuff_compress.c old mode 100755 new mode 100644 index f39c60d..51cf158 --- a/native/zstd/deprecated/zbuff_compress.c +++ b/native/zstd/deprecated/zbuff_compress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,6 +15,7 @@ ***************************************/ #define ZBUFF_STATIC_LINKING_ONLY #include "zbuff.h" +#include "../common/error_private.h" /*-*********************************************************** @@ -73,13 +74,32 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, ZSTD_parameters params, unsigned long long pledgedSrcSize) { if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* preserve "0 == unknown" behavior */ - return ZSTD_initCStream_advanced(zbc, dict, dictSize, params, pledgedSrcSize); + FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setPledgedSrcSize(zbc, pledgedSrcSize), ""); + + FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_windowLog, params.cParams.windowLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_hashLog, params.cParams.hashLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_chainLog, params.cParams.chainLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_searchLog, params.cParams.searchLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_minMatch, params.cParams.minMatch), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_targetLength, params.cParams.targetLength), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_strategy, params.cParams.strategy), ""); + + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_contentSizeFlag, params.fParams.contentSizeFlag), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_checksumFlag, params.fParams.checksumFlag), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_dictIDFlag, params.fParams.noDictIDFlag), ""); + + FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); + return 0; } - size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel) { - return ZSTD_initCStream_usingDict(zbc, dict, dictSize, compressionLevel); + FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_compressionLevel, compressionLevel), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); + return 0; } size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel) diff --git a/native/zstd/deprecated/zbuff_decompress.c b/native/zstd/deprecated/zbuff_decompress.c old mode 100755 new mode 100644 index 923c22b..d73c0f3 --- a/native/zstd/deprecated/zbuff_decompress.c +++ b/native/zstd/deprecated/zbuff_decompress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/dictBuilder/cover.c b/native/zstd/dictBuilder/cover.c old mode 100755 new mode 100644 index 2e129dd..724675d --- a/native/zstd/dictBuilder/cover.c +++ b/native/zstd/dictBuilder/cover.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -26,47 +26,65 @@ #include /* memset */ #include /* clock */ -#include "mem.h" /* read */ -#include "pool.h" -#include "threading.h" -#include "cover.h" -#include "zstd_internal.h" /* includes zstd.h */ #ifndef ZDICT_STATIC_LINKING_ONLY -#define ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY #endif -#include "zdict.h" + +#include "../common/mem.h" /* read */ +#include "../common/pool.h" +#include "../common/threading.h" +#include "../common/zstd_internal.h" /* includes zstd.h */ +#include "../common/bits.h" /* ZSTD_highbit32 */ +#include "../zdict.h" +#include "cover.h" /*-************************************* * Constants ***************************************/ +/** +* There are 32bit indexes used to ref samples, so limit samples size to 4GB +* on 64bit builds. +* For 32bit builds we choose 1 GB. +* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large +* contiguous buffer, so 1GB is already a high limit. +*/ #define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) -#define DEFAULT_SPLITPOINT 1.0 +#define COVER_DEFAULT_SPLITPOINT 1.0 /*-************************************* * Console display ***************************************/ -static int g_displayLevel = 2; +#ifndef LOCALDISPLAYLEVEL +static int g_displayLevel = 0; +#endif +#undef DISPLAY #define DISPLAY(...) \ { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } +#undef LOCALDISPLAYLEVEL #define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ if (displayLevel >= l) { \ DISPLAY(__VA_ARGS__); \ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ +#undef DISPLAYLEVEL #define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) +#ifndef LOCALDISPLAYUPDATE +static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_time = 0; +#endif +#undef LOCALDISPLAYUPDATE #define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ if (displayLevel >= l) { \ - if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \ + if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ g_time = clock(); \ DISPLAY(__VA_ARGS__); \ } \ } +#undef DISPLAYUPDATE #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) -static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; /*-************************************* * Hash table @@ -120,9 +138,9 @@ static int COVER_map_init(COVER_map_t *map, U32 size) { /** * Internal hash function */ -static const U32 prime4bytes = 2654435761U; +static const U32 COVER_prime4bytes = 2654435761U; static U32 COVER_map_hash(COVER_map_t *map, U32 key) { - return (key * prime4bytes) >> (32 - map->sizeLog); + return (key * COVER_prime4bytes) >> (32 - map->sizeLog); } /** @@ -215,7 +233,7 @@ typedef struct { } COVER_ctx_t; /* We need a global context for qsort... */ -static COVER_ctx_t *g_ctx = NULL; +static COVER_ctx_t *g_coverCtx = NULL; /*-************************************* * Helper functions @@ -258,11 +276,11 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) { /** * Same as COVER_cmp() except ties are broken by pointer value - * NOTE: g_ctx must be set to call this function. A global is required because + * NOTE: g_coverCtx must be set to call this function. A global is required because * qsort doesn't take an opaque pointer. */ -static int COVER_strict_cmp(const void *lp, const void *rp) { - int result = COVER_cmp(g_ctx, lp, rp); +static int WIN_CDECL COVER_strict_cmp(const void *lp, const void *rp) { + int result = COVER_cmp(g_coverCtx, lp, rp); if (result == 0) { result = lp < rp ? -1 : 1; } @@ -271,8 +289,8 @@ static int COVER_strict_cmp(const void *lp, const void *rp) { /** * Faster version for d <= 8. */ -static int COVER_strict_cmp8(const void *lp, const void *rp) { - int result = COVER_cmp8(g_ctx, lp, rp); +static int WIN_CDECL COVER_strict_cmp8(const void *lp, const void *rp) { + int result = COVER_cmp8(g_coverCtx, lp, rp); if (result == 0) { result = lp < rp ? -1 : 1; } @@ -524,7 +542,7 @@ static void COVER_ctx_destroy(COVER_ctx_t *ctx) { /** * Prepare a context for dictionary building. - * The context is only dependent on the parameter `d` and can used multiple + * The context is only dependent on the parameter `d` and can be used multiple * times. * Returns 0 on success or error code on error. * The context must be destroyed with `COVER_ctx_destroy()`. @@ -603,7 +621,7 @@ static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer, /* qsort doesn't take an opaque pointer, so pass as a global. * On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is. */ - g_ctx = ctx; + g_coverCtx = ctx; #if defined(__OpenBSD__) mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); @@ -725,7 +743,7 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover( COVER_map_t activeDmers; parameters.splitPoint = 1.0; /* Initialize global data */ - g_displayLevel = parameters.zParams.notificationLevel; + g_displayLevel = (int)parameters.zParams.notificationLevel; /* Checks */ if (!COVER_checkParameters(parameters, dictBufferCapacity)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); @@ -946,7 +964,7 @@ void COVER_dictSelectionFree(COVER_dictSelection_t selection){ free(selection.dictContent); } -COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, +COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize) { @@ -954,8 +972,8 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t largestCompressed = 0; BYTE* customDictContentEnd = customDictContent + dictContentSize; - BYTE * largestDictbuffer = (BYTE *)malloc(dictContentSize); - BYTE * candidateDictBuffer = (BYTE *)malloc(dictContentSize); + BYTE * largestDictbuffer = (BYTE *)malloc(dictBufferCapacity); + BYTE * candidateDictBuffer = (BYTE *)malloc(dictBufferCapacity); double regressionTolerance = ((double)params.shrinkDictMaxRegression / 100.0) + 1.00; if (!largestDictbuffer || !candidateDictBuffer) { @@ -967,7 +985,7 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, /* Initial dictionary size and compressed size */ memcpy(largestDictbuffer, customDictContent, dictContentSize); dictContentSize = ZDICT_finalizeDictionary( - largestDictbuffer, dictContentSize, customDictContent, dictContentSize, + largestDictbuffer, dictBufferCapacity, customDictContent, dictContentSize, samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); if (ZDICT_isError(dictContentSize)) { @@ -1001,7 +1019,7 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, while (dictContentSize < largestDict) { memcpy(candidateDictBuffer, largestDictbuffer, largestDict); dictContentSize = ZDICT_finalizeDictionary( - candidateDictBuffer, dictContentSize, customDictContentEnd - dictContentSize, dictContentSize, + candidateDictBuffer, dictBufferCapacity, customDictContentEnd - dictContentSize, dictContentSize, samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); if (ZDICT_isError(dictContentSize)) { @@ -1053,18 +1071,19 @@ typedef struct COVER_tryParameters_data_s { * This function is thread safe if zstd is compiled with multithreaded support. * It takes its parameters as an *OWNING* opaque pointer to support threading. */ -static void COVER_tryParameters(void *opaque) { +static void COVER_tryParameters(void *opaque) +{ /* Save parameters as local variables */ - COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque; + COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t*)opaque; const COVER_ctx_t *const ctx = data->ctx; const ZDICT_cover_params_t parameters = data->parameters; size_t dictBufferCapacity = data->dictBufferCapacity; size_t totalCompressedSize = ERROR(GENERIC); /* Allocate space for hash table, dict, and freqs */ COVER_map_t activeDmers; - BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity); + BYTE* const dict = (BYTE*)malloc(dictBufferCapacity); COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); - U32 *freqs = (U32 *)malloc(ctx->suffixSize * sizeof(U32)); + U32* const freqs = (U32*)malloc(ctx->suffixSize * sizeof(U32)); if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); goto _cleanup; @@ -1079,7 +1098,7 @@ static void COVER_tryParameters(void *opaque) { { const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict, dictBufferCapacity, parameters); - selection = COVER_selectDict(dict + tail, dictBufferCapacity - tail, + selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbTrainSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, totalCompressedSize); @@ -1094,19 +1113,18 @@ static void COVER_tryParameters(void *opaque) { free(data); COVER_map_destroy(&activeDmers); COVER_dictSelectionFree(selection); - if (freqs) { - free(freqs); - } + free(freqs); } ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( - void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer, - const size_t *samplesSizes, unsigned nbSamples, - ZDICT_cover_params_t *parameters) { + void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t* parameters) +{ /* constants */ const unsigned nbThreads = parameters->nbThreads; const double splitPoint = - parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint; + parameters->splitPoint <= 0.0 ? COVER_DEFAULT_SPLITPOINT : parameters->splitPoint; const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; diff --git a/native/zstd/dictBuilder/cover.h b/native/zstd/dictBuilder/cover.h old mode 100755 new mode 100644 index d9e0636..1aacddd --- a/native/zstd/dictBuilder/cover.h +++ b/native/zstd/dictBuilder/cover.h @@ -1,15 +1,26 @@ +/* + * Copyright (c) Facebook, Inc. + * 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. + */ + +#ifndef ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY +#endif + #include /* fprintf */ #include /* malloc, free, qsort */ #include /* memset */ #include /* clock */ -#include "mem.h" /* read */ -#include "pool.h" -#include "threading.h" -#include "zstd_internal.h" /* includes zstd.h */ -#ifndef ZDICT_STATIC_LINKING_ONLY -#define ZDICT_STATIC_LINKING_ONLY -#endif -#include "zdict.h" +#include "../common/mem.h" /* read */ +#include "../common/pool.h" +#include "../common/threading.h" +#include "../common/zstd_internal.h" /* includes zstd.h */ +#include "../zdict.h" /** * COVER_best_t is used for two purposes: @@ -142,6 +153,6 @@ void COVER_dictSelectionFree(COVER_dictSelection_t selection); * smallest dictionary within a specified regression of the compressed size * from the largest dictionary. */ - COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, + COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize); diff --git a/native/zstd/dictBuilder/divsufsort.c b/native/zstd/dictBuilder/divsufsort.c old mode 100755 new mode 100644 index ead9220..a2870fb --- a/native/zstd/dictBuilder/divsufsort.c +++ b/native/zstd/dictBuilder/divsufsort.c @@ -1576,7 +1576,7 @@ sort_typeBstar(const unsigned char *T, int *SA, /* Construct the inverse suffix array of type B* suffixes using trsort. */ trsort(ISAb, SA, m, 1); - /* Set the sorted order of tyoe B* suffixes. */ + /* Set the sorted order of type B* suffixes. */ for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } if(0 <= i) { diff --git a/native/zstd/dictBuilder/divsufsort.h b/native/zstd/dictBuilder/divsufsort.h old mode 100755 new mode 100644 diff --git a/native/zstd/dictBuilder/fastcover.c b/native/zstd/dictBuilder/fastcover.c old mode 100755 new mode 100644 index 941bb5a..63a2cee --- a/native/zstd/dictBuilder/fastcover.c +++ b/native/zstd/dictBuilder/fastcover.c @@ -1,3 +1,13 @@ +/* + * Copyright (c) Facebook, Inc. + * 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. + */ + /*-************************************* * Dependencies ***************************************/ @@ -6,24 +16,33 @@ #include /* memset */ #include /* clock */ -#include "mem.h" /* read */ -#include "pool.h" -#include "threading.h" -#include "cover.h" -#include "zstd_internal.h" /* includes zstd.h */ #ifndef ZDICT_STATIC_LINKING_ONLY -#define ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY #endif -#include "zdict.h" + +#include "../common/mem.h" /* read */ +#include "../common/pool.h" +#include "../common/threading.h" +#include "../common/zstd_internal.h" /* includes zstd.h */ +#include "../compress/zstd_compress_internal.h" /* ZSTD_hash*() */ +#include "../zdict.h" +#include "cover.h" /*-************************************* * Constants ***************************************/ +/** +* There are 32bit indexes used to ref samples, so limit samples size to 4GB +* on 64bit builds. +* For 32bit builds we choose 1 GB. +* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large +* contiguous buffer, so 1GB is already a high limit. +*/ #define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) #define FASTCOVER_MAX_F 31 #define FASTCOVER_MAX_ACCEL 10 -#define DEFAULT_SPLITPOINT 0.75 +#define FASTCOVER_DEFAULT_SPLITPOINT 0.75 #define DEFAULT_F 20 #define DEFAULT_ACCEL 1 @@ -31,50 +50,50 @@ /*-************************************* * Console display ***************************************/ -static int g_displayLevel = 2; +#ifndef LOCALDISPLAYLEVEL +static int g_displayLevel = 0; +#endif +#undef DISPLAY #define DISPLAY(...) \ { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } +#undef LOCALDISPLAYLEVEL #define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ if (displayLevel >= l) { \ DISPLAY(__VA_ARGS__); \ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ +#undef DISPLAYLEVEL #define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) +#ifndef LOCALDISPLAYUPDATE +static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_time = 0; +#endif +#undef LOCALDISPLAYUPDATE #define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ if (displayLevel >= l) { \ - if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \ + if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ g_time = clock(); \ DISPLAY(__VA_ARGS__); \ } \ } +#undef DISPLAYUPDATE #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) -static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; /*-************************************* * Hash Functions ***************************************/ -static const U64 prime6bytes = 227718039650203ULL; -static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } -static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } - -static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL; -static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; } -static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); } - - /** - * Hash the d-byte value pointed to by p and mod 2^f + * Hash the d-byte value pointed to by p and mod 2^f into the frequency vector */ -static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 h, unsigned d) { +static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 f, unsigned d) { if (d == 6) { - return ZSTD_hash6Ptr(p, h) & ((1 << h) - 1); + return ZSTD_hash6Ptr(p, f); } - return ZSTD_hash8Ptr(p, h) & ((1 << h) - 1); + return ZSTD_hash8Ptr(p, f); } @@ -285,7 +304,7 @@ FASTCOVER_computeFrequency(U32* freqs, const FASTCOVER_ctx_t* ctx) /** * Prepare a context for dictionary building. - * The context is only dependent on the parameter `d` and can used multiple + * The context is only dependent on the parameter `d` and can be used multiple * times. * Returns 0 on success or error code on error. * The context must be destroyed with `FASTCOVER_ctx_destroy()`. @@ -451,20 +470,20 @@ typedef struct FASTCOVER_tryParameters_data_s { * This function is thread safe if zstd is compiled with multithreaded support. * It takes its parameters as an *OWNING* opaque pointer to support threading. */ -static void FASTCOVER_tryParameters(void *opaque) +static void FASTCOVER_tryParameters(void* opaque) { /* Save parameters as local variables */ - FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t *)opaque; + FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t*)opaque; const FASTCOVER_ctx_t *const ctx = data->ctx; const ZDICT_cover_params_t parameters = data->parameters; size_t dictBufferCapacity = data->dictBufferCapacity; size_t totalCompressedSize = ERROR(GENERIC); /* Initialize array to keep track of frequency of dmer within activeSegment */ - U16* segmentFreqs = (U16 *)calloc(((U64)1 << ctx->f), sizeof(U16)); + U16* segmentFreqs = (U16*)calloc(((U64)1 << ctx->f), sizeof(U16)); /* Allocate space for hash table, dict, and freqs */ - BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity); + BYTE *const dict = (BYTE*)malloc(dictBufferCapacity); COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); - U32 *freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32)); + U32* freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32)); if (!segmentFreqs || !dict || !freqs) { DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n"); goto _cleanup; @@ -476,7 +495,7 @@ static void FASTCOVER_tryParameters(void *opaque) parameters, segmentFreqs); const unsigned nbFinalizeSamples = (unsigned)(ctx->nbTrainSamples * ctx->accelParams.finalize / 100); - selection = COVER_selectDict(dict + tail, dictBufferCapacity - tail, + selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, ctx->samples, ctx->samplesSizes, nbFinalizeSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, totalCompressedSize); @@ -537,7 +556,7 @@ ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity, ZDICT_cover_params_t coverParams; FASTCOVER_accel_t accelParams; /* Initialize global data */ - g_displayLevel = parameters.zParams.notificationLevel; + g_displayLevel = (int)parameters.zParams.notificationLevel; /* Assign splitPoint and f if not provided */ parameters.splitPoint = 1.0; parameters.f = parameters.f == 0 ? DEFAULT_F : parameters.f; @@ -607,7 +626,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover( /* constants */ const unsigned nbThreads = parameters->nbThreads; const double splitPoint = - parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint; + parameters->splitPoint <= 0.0 ? FASTCOVER_DEFAULT_SPLITPOINT : parameters->splitPoint; const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; @@ -620,7 +639,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover( const unsigned accel = parameters->accel == 0 ? DEFAULT_ACCEL : parameters->accel; const unsigned shrinkDict = 0; /* Local variables */ - const int displayLevel = parameters->zParams.notificationLevel; + const int displayLevel = (int)parameters->zParams.notificationLevel; unsigned iteration = 1; unsigned d; unsigned k; @@ -704,7 +723,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover( data->parameters.splitPoint = splitPoint; data->parameters.steps = kSteps; data->parameters.shrinkDict = shrinkDict; - data->parameters.zParams.notificationLevel = g_displayLevel; + data->parameters.zParams.notificationLevel = (unsigned)g_displayLevel; /* Check the parameters */ if (!FASTCOVER_checkParameters(data->parameters, dictBufferCapacity, data->ctx->f, accel)) { diff --git a/native/zstd/dictBuilder/zdict.c b/native/zstd/dictBuilder/zdict.c old mode 100755 new mode 100644 index 4a263d8..a932276 --- a/native/zstd/dictBuilder/zdict.c +++ b/native/zstd/dictBuilder/zdict.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -23,9 +23,13 @@ /* Unix Large Files support (>4GB) */ #define _FILE_OFFSET_BITS 64 #if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */ +# ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE +# endif #elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ +# ifndef _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE +# endif #endif @@ -37,17 +41,20 @@ #include /* fprintf, fopen, ftello64 */ #include /* clock */ -#include "mem.h" /* read */ -#include "fse.h" /* FSE_normalizeCount, FSE_writeNCount */ -#define HUF_STATIC_LINKING_ONLY -#include "huf.h" /* HUF_buildCTable, HUF_writeCTable */ -#include "zstd_internal.h" /* includes zstd.h */ -#include "xxhash.h" /* XXH64 */ -#include "divsufsort.h" #ifndef ZDICT_STATIC_LINKING_ONLY # define ZDICT_STATIC_LINKING_ONLY #endif -#include "zdict.h" +#define HUF_STATIC_LINKING_ONLY + +#include "../common/mem.h" /* read */ +#include "../common/fse.h" /* FSE_normalizeCount, FSE_writeNCount */ +#include "../common/huf.h" /* HUF_buildCTable, HUF_writeCTable */ +#include "../common/zstd_internal.h" /* includes zstd.h */ +#include "../common/xxhash.h" /* XXH64 */ +#include "../compress/zstd_compress_internal.h" /* ZSTD_loadCEntropy() */ +#include "../zdict.h" +#include "divsufsort.h" +#include "../common/bits.h" /* ZSTD_NbCommonBytes */ /*-************************************* @@ -61,14 +68,15 @@ #define NOISELENGTH 32 -static const int g_compressionLevel_default = 3; static const U32 g_selectivity_default = 9; /*-************************************* * Console display ***************************************/ +#undef DISPLAY #define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } +#undef DISPLAYLEVEL #define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; } @@ -99,69 +107,30 @@ unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize) return MEM_readLE32((const char*)dictBuffer + 4); } - -/*-******************************************************** -* Dictionary training functions -**********************************************************/ -static unsigned ZDICT_NbCommonBytes (size_t val) +size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize) { - if (MEM_isLittleEndian()) { - if (MEM_64bits()) { -# if defined(_MSC_VER) && defined(_WIN64) - unsigned long r = 0; - _BitScanForward64( &r, (U64)val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } else { /* 32 bits */ -# if defined(_MSC_VER) - unsigned long r=0; - _BitScanForward( &r, (U32)val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif + size_t headerSize; + if (dictSize <= 8 || MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return ERROR(dictionary_corrupted); + + { ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t)); + U32* wksp = (U32*)malloc(HUF_WORKSPACE_SIZE); + if (!bs || !wksp) { + headerSize = ERROR(memory_allocation); + } else { + ZSTD_reset_compressedBlockState(bs); + headerSize = ZSTD_loadCEntropy(bs, wksp, dictBuffer, dictSize); } - } else { /* Big Endian CPU */ - if (MEM_64bits()) { -# if defined(_MSC_VER) && defined(_WIN64) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_clzll(val) >> 3); -# else - unsigned r; - const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ - if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; -# endif - } else { /* 32 bits */ -# if defined(_MSC_VER) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; -# endif - } } -} + free(bs); + free(wksp); + } + return headerSize; +} + +/*-******************************************************** +* Dictionary training functions +**********************************************************/ /*! ZDICT_count() : Count the nb of common bytes between 2 pointers. Note : this function presumes end of buffer followed by noisy guard band. @@ -176,7 +145,7 @@ static size_t ZDICT_count(const void* pIn, const void* pMatch) pMatch = (const char*)pMatch+sizeof(size_t); continue; } - pIn = (const char*)pIn+ZDICT_NbCommonBytes(diff); + pIn = (const char*)pIn+ZSTD_NbCommonBytes(diff); return (size_t)((const char*)pIn - pStart); } } @@ -208,7 +177,7 @@ static dictItem ZDICT_analyzePos( U32 savings[LLIMIT] = {0}; const BYTE* b = (const BYTE*)buffer; size_t maxLength = LLIMIT; - size_t pos = suffix[start]; + size_t pos = (size_t)suffix[start]; U32 end = start; dictItem solution; @@ -342,7 +311,7 @@ static dictItem ZDICT_analyzePos( savings[i] = savings[i-1] + (lengthList[i] * (i-3)); DISPLAYLEVEL(4, "Selected dict at position %u, of length %u : saves %u (ratio: %.2f) \n", - (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / maxLength); + (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / (double)maxLength); solution.pos = (U32)pos; solution.length = (U32)maxLength; @@ -352,7 +321,7 @@ static dictItem ZDICT_analyzePos( { U32 id; for (id=start; id= elt.pos) && (table[u].pos < elt.pos)) { /* overlap, existing < new */ /* append */ - int const addedLength = (int)eltEnd - (table[u].pos + table[u].length); + int const addedLength = (int)eltEnd - (int)(table[u].pos + table[u].length); table[u].savings += elt.length / 8; /* rough approx bonus */ if (addedLength > 0) { /* otherwise, elt fully included into existing */ table[u].length += addedLength; @@ -508,6 +477,7 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize, clock_t displayClock = 0; clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10; +# undef DISPLAYUPDATE # define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \ if (ZDICT_clockSpan(displayClock) > refreshRate) \ { displayClock = clock(); DISPLAY(__VA_ARGS__); \ @@ -588,12 +558,12 @@ typedef struct #define MAXREPOFFSET 1024 -static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params, +static void ZDICT_countEStats(EStats_ress_t esr, const ZSTD_parameters* params, unsigned* countLit, unsigned* offsetcodeCount, unsigned* matchlengthCount, unsigned* litlengthCount, U32* repOffsets, const void* src, size_t srcSize, U32 notificationLevel) { - size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params.cParams.windowLog); + size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params->cParams.windowLog); size_t cSize; if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */ @@ -634,8 +604,8 @@ static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params, if (nbSeq >= 2) { /* rep offsets */ const seqDef* const seq = seqStorePtr->sequencesStart; - U32 offset1 = seq[0].offset - 3; - U32 offset2 = seq[1].offset - 3; + U32 offset1 = seq[0].offBase - ZSTD_REP_NUM; + U32 offset2 = seq[1].offBase - ZSTD_REP_NUM; if (offset1 >= MAXREPOFFSET) offset1 = 0; if (offset2 >= MAXREPOFFSET) offset2 = 0; repOffsets[offset1] += 3; @@ -682,7 +652,7 @@ static void ZDICT_flatLit(unsigned* countLit) #define OFFCODE_MAX 30 /* only applicable to first block */ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, - unsigned compressionLevel, + int compressionLevel, const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, const void* dictBuffer, size_t dictBufferSize, unsigned notificationLevel) @@ -717,7 +687,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, memset(repOffset, 0, sizeof(repOffset)); repOffset[1] = repOffset[4] = repOffset[8] = 1; memset(bestRepOffset, 0, sizeof(bestRepOffset)); - if (compressionLevel==0) compressionLevel = g_compressionLevel_default; + if (compressionLevel==0) compressionLevel = ZSTD_CLEVEL_DEFAULT; params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize); esr.dict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, params.cParams, ZSTD_defaultCMem); @@ -731,13 +701,20 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, /* collect stats on all samples */ for (u=0; u= 4) { + /* writeStats */ + DISPLAYLEVEL(4, "Offset Code Frequencies : \n"); + for (u=0; u<=offcodeMax; u++) { + DISPLAYLEVEL(4, "%2u :%7u \n", u, offcodeCount[u]); + } } + /* analyze, build stats, starting with literals */ { size_t maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog); if (HUF_isError(maxNbBits)) { @@ -762,7 +739,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, /* note : the result of this phase should be used to better appreciate the impact on statistics */ total=0; for (u=0; u<=offcodeMax; u++) total+=offcodeCount[u]; - errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax); + errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax, /* useLowProbCount */ 1); if (FSE_isError(errorCode)) { eSize = errorCode; DISPLAYLEVEL(1, "FSE_normalizeCount error with offcodeCount \n"); @@ -771,7 +748,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, Offlog = (U32)errorCode; total=0; for (u=0; u<=MaxML; u++) total+=matchLengthCount[u]; - errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML); + errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML, /* useLowProbCount */ 1); if (FSE_isError(errorCode)) { eSize = errorCode; DISPLAYLEVEL(1, "FSE_normalizeCount error with matchLengthCount \n"); @@ -780,7 +757,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, mlLog = (U32)errorCode; total=0; for (u=0; u<=MaxLL; u++) total+=litLengthCount[u]; - errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL); + errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL, /* useLowProbCount */ 1); if (FSE_isError(errorCode)) { eSize = errorCode; DISPLAYLEVEL(1, "FSE_normalizeCount error with litLengthCount \n"); @@ -844,7 +821,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, MEM_writeLE32(dstPtr+8, bestRepOffset[2].offset); #else /* at this stage, we don't use the result of "most common first offset", - as the impact of statistics is not properly evaluated */ + * as the impact of statistics is not properly evaluated */ MEM_writeLE32(dstPtr+0, repStartValue[0]); MEM_writeLE32(dstPtr+4, repStartValue[1]); MEM_writeLE32(dstPtr+8, repStartValue[2]); @@ -860,6 +837,17 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, } +/** + * @returns the maximum repcode value + */ +static U32 ZDICT_maxRep(U32 const reps[ZSTD_REP_NUM]) +{ + U32 maxRep = reps[0]; + int r; + for (r = 1; r < ZSTD_REP_NUM; ++r) + maxRep = MAX(maxRep, reps[r]); + return maxRep; +} size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity, const void* customDictContent, size_t dictContentSize, @@ -869,13 +857,15 @@ size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity, size_t hSize; #define HBUFFSIZE 256 /* should prove large enough for all entropy headers */ BYTE header[HBUFFSIZE]; - int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel; + int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel; U32 const notificationLevel = params.notificationLevel; + /* The final dictionary content must be at least as large as the largest repcode */ + size_t const minContentSize = (size_t)ZDICT_maxRep(repStartValue); + size_t paddingSize; /* check conditions */ DEBUGLOG(4, "ZDICT_finalizeDictionary"); if (dictBufferCapacity < dictContentSize) return ERROR(dstSize_tooSmall); - if (dictContentSize < ZDICT_CONTENTSIZE_MIN) return ERROR(srcSize_wrong); if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) return ERROR(dstSize_tooSmall); /* dictionary header */ @@ -899,12 +889,43 @@ size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity, hSize += eSize; } - /* copy elements in final buffer ; note : src and dst buffer can overlap */ - if (hSize + dictContentSize > dictBufferCapacity) dictContentSize = dictBufferCapacity - hSize; - { size_t const dictSize = hSize + dictContentSize; - char* dictEnd = (char*)dictBuffer + dictSize; - memmove(dictEnd - dictContentSize, customDictContent, dictContentSize); - memcpy(dictBuffer, header, hSize); + /* Shrink the content size if it doesn't fit in the buffer */ + if (hSize + dictContentSize > dictBufferCapacity) { + dictContentSize = dictBufferCapacity - hSize; + } + + /* Pad the dictionary content with zeros if it is too small */ + if (dictContentSize < minContentSize) { + RETURN_ERROR_IF(hSize + minContentSize > dictBufferCapacity, dstSize_tooSmall, + "dictBufferCapacity too small to fit max repcode"); + paddingSize = minContentSize - dictContentSize; + } else { + paddingSize = 0; + } + + { + size_t const dictSize = hSize + paddingSize + dictContentSize; + + /* The dictionary consists of the header, optional padding, and the content. + * The padding comes before the content because the "best" position in the + * dictionary is the last byte. + */ + BYTE* const outDictHeader = (BYTE*)dictBuffer; + BYTE* const outDictPadding = outDictHeader + hSize; + BYTE* const outDictContent = outDictPadding + paddingSize; + + assert(dictSize <= dictBufferCapacity); + assert(outDictContent + dictContentSize == (BYTE*)dictBuffer + dictSize); + + /* First copy the customDictContent into its final location. + * `customDictContent` and `dictBuffer` may overlap, so we must + * do this before any other writes into the output buffer. + * Then copy the header & padding into the output buffer. + */ + memmove(outDictContent, customDictContent, dictContentSize); + memcpy(outDictHeader, header, hSize); + memset(outDictPadding, 0, paddingSize); + return dictSize; } } @@ -915,7 +936,7 @@ static size_t ZDICT_addEntropyTablesFromBuffer_advanced( const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, ZDICT_params_t params) { - int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel; + int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel; U32 const notificationLevel = params.notificationLevel; size_t hSize = 8; @@ -944,16 +965,11 @@ static size_t ZDICT_addEntropyTablesFromBuffer_advanced( return MIN(dictBufferCapacity, hSize+dictContentSize); } -/* Hidden declaration for dbio.c */ -size_t ZDICT_trainFromBuffer_unsafe_legacy( - void* dictBuffer, size_t maxDictSize, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_legacy_params_t params); /*! ZDICT_trainFromBuffer_unsafe_legacy() : -* Warning : `samplesBuffer` must be followed by noisy guard band. +* Warning : `samplesBuffer` must be followed by noisy guard band !!! * @return : size of dictionary, or an error code which can be tested with ZDICT_isError() */ -size_t ZDICT_trainFromBuffer_unsafe_legacy( +static size_t ZDICT_trainFromBuffer_unsafe_legacy( void* dictBuffer, size_t maxDictSize, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, ZDICT_legacy_params_t params) @@ -1090,8 +1106,8 @@ size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, memset(¶ms, 0, sizeof(params)); params.d = 8; params.steps = 4; - /* Default to level 6 since no compression level information is available */ - params.zParams.compressionLevel = 3; + /* Use default level since no compression level information is available */ + params.zParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; #if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1) params.zParams.notificationLevel = DEBUGLEVEL; #endif diff --git a/native/zstd/dll/example/Makefile b/native/zstd/dll/example/Makefile old mode 100755 new mode 100644 index 45d0db3..03b034d --- a/native/zstd/dll/example/Makefile +++ b/native/zstd/dll/example/Makefile @@ -1,10 +1,11 @@ # ################################################################ -# Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +# Copyright (c) Yann Collet, Facebook, Inc. # 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. # ################################################################ VOID := /dev/null diff --git a/native/zstd/dll/example/README.md b/native/zstd/dll/example/README.md old mode 100755 new mode 100644 index e231f59..46aec79 --- a/native/zstd/dll/example/README.md +++ b/native/zstd/dll/example/README.md @@ -1,23 +1,21 @@ -ZSTD Windows binary package -==================================== +# ZSTD Windows binary package -#### The package contents +## The package contents -- `zstd.exe` : Command Line Utility, supporting gzip-like arguments -- `dll\libzstd.dll` : The ZSTD dynamic library (DLL) -- `dll\libzstd.lib` : The import library of the ZSTD dynamic library (DLL) for Visual C++ -- `example\` : The example of usage of the ZSTD library -- `include\` : Header files required by the ZSTD library +- `zstd.exe` : Command Line Utility, supporting gzip-like arguments +- `dll\libzstd.dll` : The ZSTD dynamic library (DLL) +- `dll\libzstd.lib` : The import library of the ZSTD dynamic library (DLL) for Visual C++ +- `example\` : The example of usage of the ZSTD library +- `include\` : Header files required by the ZSTD library - `static\libzstd_static.lib` : The static ZSTD library (LIB) - -#### Usage of Command Line Interface +## Usage of Command Line Interface Command Line Interface (CLI) supports gzip-like arguments. By default CLI takes an input file and compresses it to an output file: -``` + Usage: zstd [arg] [input] [output] -``` + The full list of commands for CLI can be obtained with `-h` or `-H`. The ratio can be improved with commands from `-3` to `-16` but higher levels also have slower compression. CLI includes in-memory compression benchmark module with compression @@ -25,36 +23,32 @@ levels starting from `-b` and ending with `-e` with iteration time of `-i` secon CLI supports aggregation of parameters i.e. `-b1`, `-e18`, and `-i1` can be joined into `-b1e18i1`. - -#### The example of usage of static and dynamic ZSTD libraries with gcc/MinGW +## The example of usage of static and dynamic ZSTD libraries with gcc/MinGW Use `cd example` and `make` to build `fullbench-dll` and `fullbench-lib`. `fullbench-dll` uses a dynamic ZSTD library from the `dll` directory. `fullbench-lib` uses a static ZSTD library from the `lib` directory. - -#### Using ZSTD DLL with gcc/MinGW +## Using ZSTD DLL with gcc/MinGW The header files from `include\` and the dynamic library `dll\libzstd.dll` are required to compile a project using gcc/MinGW. The dynamic library has to be added to linking options. It means that if a project that uses ZSTD consists of a single `test-dll.c` file it should be linked with `dll\libzstd.dll`. For example: -``` + gcc $(CFLAGS) -Iinclude\ test-dll.c -o test-dll dll\libzstd.dll -``` -The compiled executable will require ZSTD DLL which is available at `dll\libzstd.dll`. +The compiled executable will require ZSTD DLL which is available at `dll\libzstd.dll`. -#### The example of usage of static and dynamic ZSTD libraries with Visual C++ +## The example of usage of static and dynamic ZSTD libraries with Visual C++ Open `example\fullbench-dll.sln` to compile `fullbench-dll` that uses a dynamic ZSTD library from the `dll` directory. The solution works with Visual C++ 2010 or newer. When one will open the solution with Visual C++ newer than 2010 -then the solution will upgraded to the current version. - +then the solution will be upgraded to the current version. -#### Using ZSTD DLL with Visual C++ +## Using ZSTD DLL with Visual C++ The header files from `include\` and the import library `dll\libzstd.lib` are required to compile a project using Visual C++. diff --git a/native/zstd/dll/example/build_package.bat b/native/zstd/dll/example/build_package.bat old mode 100755 new mode 100644 index 8baabc7..e410c63 --- a/native/zstd/dll/example/build_package.bat +++ b/native/zstd/dll/example/build_package.bat @@ -1,20 +1,20 @@ -@ECHO OFF -MKDIR bin\dll bin\static bin\example bin\include -COPY tests\fullbench.c bin\example\ -COPY programs\datagen.c bin\example\ -COPY programs\datagen.h bin\example\ -COPY programs\util.h bin\example\ -COPY programs\platform.h bin\example\ -COPY lib\common\mem.h bin\example\ -COPY lib\common\zstd_internal.h bin\example\ -COPY lib\common\error_private.h bin\example\ -COPY lib\common\xxhash.h bin\example\ -COPY lib\libzstd.a bin\static\libzstd_static.lib -COPY lib\dll\libzstd.* bin\dll\ -COPY lib\dll\example\Makefile bin\example\ -COPY lib\dll\example\fullbench-dll.* bin\example\ -COPY lib\dll\example\README.md bin\ -COPY lib\zstd.h bin\include\ -COPY lib\common\zstd_errors.h bin\include\ -COPY lib\dictBuilder\zdict.h bin\include\ -COPY programs\zstd.exe bin\zstd.exe +@ECHO OFF +MKDIR bin\dll bin\static bin\example bin\include +COPY tests\fullbench.c bin\example\ +COPY programs\datagen.c bin\example\ +COPY programs\datagen.h bin\example\ +COPY programs\util.h bin\example\ +COPY programs\platform.h bin\example\ +COPY lib\common\mem.h bin\example\ +COPY lib\common\zstd_internal.h bin\example\ +COPY lib\common\error_private.h bin\example\ +COPY lib\common\xxhash.h bin\example\ +COPY lib\libzstd.a bin\static\libzstd_static.lib +COPY lib\dll\libzstd.* bin\dll\ +COPY lib\dll\example\Makefile bin\example\ +COPY lib\dll\example\fullbench-dll.* bin\example\ +COPY lib\dll\example\README.md bin\ +COPY lib\zstd.h bin\include\ +COPY lib\common\zstd_errors.h bin\include\ +COPY lib\dictBuilder\zdict.h bin\include\ +COPY programs\zstd.exe bin\zstd.exe diff --git a/native/zstd/dll/example/fullbench-dll.sln b/native/zstd/dll/example/fullbench-dll.sln old mode 100755 new mode 100644 index 72e302e..ef8d4c0 --- a/native/zstd/dll/example/fullbench-dll.sln +++ b/native/zstd/dll/example/fullbench-dll.sln @@ -1,25 +1,25 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2012 for Windows Desktop -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench-dll", "fullbench-dll.vcxproj", "{13992FD2-077E-4954-B065-A428198201A9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.ActiveCfg = Debug|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.Build.0 = Debug|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.ActiveCfg = Debug|x64 - {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.Build.0 = Debug|x64 - {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.ActiveCfg = Release|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.Build.0 = Release|Win32 - {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.ActiveCfg = Release|x64 - {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench-dll", "fullbench-dll.vcxproj", "{13992FD2-077E-4954-B065-A428198201A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.ActiveCfg = Debug|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Debug|Win32.Build.0 = Debug|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.ActiveCfg = Debug|x64 + {13992FD2-077E-4954-B065-A428198201A9}.Debug|x64.Build.0 = Debug|x64 + {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.ActiveCfg = Release|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.Build.0 = Release|Win32 + {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.ActiveCfg = Release|x64 + {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/zstd/dll/example/fullbench-dll.vcxproj b/native/zstd/dll/example/fullbench-dll.vcxproj old mode 100755 new mode 100644 index 44bbaf7..fbea783 --- a/native/zstd/dll/example/fullbench-dll.vcxproj +++ b/native/zstd/dll/example/fullbench-dll.vcxproj @@ -1,181 +1,181 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {00000000-1CC8-4FD7-9281-6B8DBB9D3DF8} - Win32Proj - fullbench-dll - $(SolutionDir)bin\$(Platform)_$(Configuration)\ - $(SolutionDir)bin\obj\$(RootNamespace)_$(Platform)_$(Configuration)\ - - - - Application - true - MultiByte - - - Application - true - MultiByte - - - Application - false - true - MultiByte - - - Application - false - true - MultiByte - - - - - - - - - - - - - - - - - - - true - $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); - false - - - true - $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); - false - - - false - $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); - false - - - false - $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); - false - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) - true - false - ..\include - - - Console - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - libzstd.lib;%(AdditionalDependencies) - false - - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) - true - false - ..\include - - - Console - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - libzstd.lib;%(AdditionalDependencies) - - - - - Level4 - - - MaxSpeed - true - true - WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) - false - ..\include - false - MultiThreaded - - - Console - true - true - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - libzstd.lib;%(AdditionalDependencies) - false - - - - - Level4 - - - MaxSpeed - true - true - WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) - false - false - ..\include - MultiThreaded - - - Console - true - true - true - $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) - libzstd.lib;%(AdditionalDependencies) - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {00000000-1CC8-4FD7-9281-6B8DBB9D3DF8} + Win32Proj + fullbench-dll + $(SolutionDir)bin\$(Platform)_$(Configuration)\ + $(SolutionDir)bin\obj\$(RootNamespace)_$(Platform)_$(Configuration)\ + + + + Application + true + MultiByte + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); + false + + + true + $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); + false + + + false + $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); + false + + + false + $(IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\common;$(UniversalCRT_IncludePath); + false + + + + + + Level4 + Disabled + WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) + true + false + ..\include + + + Console + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + libzstd.lib;%(AdditionalDependencies) + false + + + + + + + Level4 + Disabled + WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) + true + false + ..\include + + + Console + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + libzstd.lib;%(AdditionalDependencies) + + + + + Level4 + + + MaxSpeed + true + true + WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) + false + ..\include + false + MultiThreaded + + + Console + true + true + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + libzstd.lib;%(AdditionalDependencies) + false + + + + + Level4 + + + MaxSpeed + true + true + WIN32;_DEBUG;_CONSOLE;ZSTD_DLL_IMPORT=1;%(PreprocessorDefinitions) + false + false + ..\include + MultiThreaded + + + Console + true + true + true + $(SolutionDir)..\dll;%(AdditionalLibraryDirectories) + libzstd.lib;%(AdditionalDependencies) + + + + + + + + + + + + \ No newline at end of file diff --git a/native/zstd/legacy/zstd_legacy.h b/native/zstd/legacy/zstd_legacy.h old mode 100755 new mode 100644 index 0dbd3c7..a6f1174 --- a/native/zstd/legacy/zstd_legacy.h +++ b/native/zstd/legacy/zstd_legacy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -18,9 +18,9 @@ extern "C" { /* ************************************* * Includes ***************************************/ -#include "mem.h" /* MEM_STATIC */ -#include "error_private.h" /* ERROR */ -#include "zstd_internal.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTD_frameSizeInfo */ +#include "../common/mem.h" /* MEM_STATIC */ +#include "../common/error_private.h" /* ERROR */ +#include "../common/zstd_internal.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTD_frameSizeInfo */ #if !defined (ZSTD_LEGACY_SUPPORT) || (ZSTD_LEGACY_SUPPORT == 0) # undef ZSTD_LEGACY_SUPPORT diff --git a/native/zstd/legacy/zstd_v01.c b/native/zstd/legacy/zstd_v01.c old mode 100755 new mode 100644 index 8112527..23caaef --- a/native/zstd/legacy/zstd_v01.c +++ b/native/zstd/legacy/zstd_v01.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,7 +14,7 @@ ******************************************/ #include /* size_t, ptrdiff_t */ #include "zstd_v01.h" -#include "error_private.h" +#include "../common/error_private.h" /****************************************** @@ -204,10 +204,7 @@ typedef signed long long S64; * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef FSE_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define FSE_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define FSE_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -257,7 +254,7 @@ static U64 FSE_read64(const void* memPtr) U64 val; memcpy(&val, memPtr, sizeof(val)); return val; } -#endif // FSE_FORCE_MEMORY_ACCESS +#endif /* FSE_FORCE_MEMORY_ACCESS */ static U16 FSE_readLE16(const void* memPtr) { @@ -343,8 +340,7 @@ FORCE_INLINE unsigned FSE_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ unsigned long r; - _BitScanReverse ( &r, val ); - return (unsigned) r; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; # elif defined(__GNUC__) && (GCC_VERSION >= 304) /* GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -1078,7 +1074,7 @@ static size_t HUF_decompress_usingDTable( /* -3% slower when non static */ BYTE* const ostart = (BYTE*) dst; BYTE* op = ostart; BYTE* const omax = op + maxDstSize; - BYTE* const olimit = omax-15; + BYTE* const olimit = maxDstSize < 15 ? op : omax-15; const void* ptr = DTable; const HUF_DElt* const dt = (const HUF_DElt*)(ptr)+1; @@ -1092,7 +1088,7 @@ static size_t HUF_decompress_usingDTable( /* -3% slower when non static */ const size_t length1 = FSE_readLE16(jumpTable); const size_t length2 = FSE_readLE16(jumpTable+1); const size_t length3 = FSE_readLE16(jumpTable+2); - const size_t length4 = cSrcSize - 6 - length1 - length2 - length3; // check coherency !! + const size_t length4 = cSrcSize - 6 - length1 - length2 - length3; /* check coherency !! */ const char* const start1 = (const char*)(cSrc) + 6; const char* const start2 = start1 + length1; const char* const start3 = start2 + length2; @@ -1150,11 +1146,11 @@ static size_t HUF_decompress_usingDTable( /* -3% slower when non static */ /* tail */ { - // bitTail = bitD1; // *much* slower : -20% !??! + /* bitTail = bitD1; */ /* *much* slower : -20% !??! */ FSE_DStream_t bitTail; bitTail.ptr = bitD1.ptr; bitTail.bitsConsumed = bitD1.bitsConsumed; - bitTail.bitContainer = bitD1.bitContainer; // required in case of FSE_DStream_endOfBuffer + bitTail.bitContainer = bitD1.bitContainer; /* required in case of FSE_DStream_endOfBuffer */ bitTail.start = start1; for ( ; (FSE_reloadDStream(&bitTail) < FSE_DStream_completed) && (op= 199901L /* C99 */ -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -1483,7 +1483,9 @@ static size_t ZSTDv01_getcBlockSize(const void* src, size_t srcSize, blockProper static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - memcpy(dst, src, srcSize); + if (srcSize > 0) { + memcpy(dst, src, srcSize); + } return srcSize; } @@ -1502,7 +1504,7 @@ static size_t ZSTD_decompressLiterals(void* ctx, if (srcSize <= 3) return ERROR(corruption_detected); litSize = ip[1] + (ip[0]<<8); - litSize += ((ip[-3] >> 3) & 7) << 16; // mmmmh.... + litSize += ((ip[-3] >> 3) & 7) << 16; /* mmmmh.... */ op = oend - litSize; (void)ctx; @@ -1541,7 +1543,9 @@ static size_t ZSTDv01_decodeLiteralsBlock(void* ctx, size_t rleSize = litbp.origSize; if (rleSize>maxDstSize) return ERROR(dstSize_tooSmall); if (!srcSize) return ERROR(srcSize_wrong); - memset(oend - rleSize, *ip, rleSize); + if (rleSize > 0) { + memset(oend - rleSize, *ip, rleSize); + } *litStart = oend - rleSize; *litSize = rleSize; ip++; @@ -1901,8 +1905,10 @@ static size_t ZSTD_decompressSequences( { size_t lastLLSize = litEnd - litPtr; if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (op != litPtr) memmove(op, litPtr, lastLLSize); - op += lastLLSize; + if (lastLLSize > 0) { + if (op != litPtr) memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } } } diff --git a/native/zstd/legacy/zstd_v01.h b/native/zstd/legacy/zstd_v01.h old mode 100755 new mode 100644 index 245f9dd..f777eb6 --- a/native/zstd/legacy/zstd_v01.h +++ b/native/zstd/legacy/zstd_v01.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/legacy/zstd_v02.c b/native/zstd/legacy/zstd_v02.c old mode 100755 new mode 100644 index c878379..6eadd39 --- a/native/zstd/legacy/zstd_v02.c +++ b/native/zstd/legacy/zstd_v02.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,7 +11,7 @@ #include /* size_t, ptrdiff_t */ #include "zstd_v02.h" -#include "error_private.h" +#include "../common/error_private.h" /****************************************** @@ -89,7 +89,11 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -125,10 +129,7 @@ extern "C" { * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -189,7 +190,7 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) memcpy(memPtr, &value, sizeof(value)); } -#endif // MEM_FORCE_MEMORY_ACCESS +#endif /* MEM_FORCE_MEMORY_ACCESS */ MEM_STATIC U16 MEM_readLE16(const void* memPtr) @@ -349,9 +350,8 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BIT_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; + unsigned long r; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -433,7 +433,7 @@ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) } /*! BIT_lookBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -453,7 +453,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) } /*!BIT_readBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { size_t value = BIT_lookBitsFast(bitD, nbBits); @@ -2836,7 +2836,9 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - memcpy(dst, src, srcSize); + if (srcSize > 0) { + memcpy(dst, src, srcSize); + } return srcSize; } @@ -3229,8 +3231,10 @@ static size_t ZSTD_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (op != litPtr) memmove(op, litPtr, lastLLSize); - op += lastLLSize; + if (lastLLSize > 0) { + if (op != litPtr) memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } } } diff --git a/native/zstd/legacy/zstd_v02.h b/native/zstd/legacy/zstd_v02.h old mode 100755 new mode 100644 index 9d7d8d9..1b37195 --- a/native/zstd/legacy/zstd_v02.h +++ b/native/zstd/legacy/zstd_v02.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/legacy/zstd_v03.c b/native/zstd/legacy/zstd_v03.c old mode 100755 new mode 100644 index 162bd63..72fc914 --- a/native/zstd/legacy/zstd_v03.c +++ b/native/zstd/legacy/zstd_v03.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,7 +11,7 @@ #include /* size_t, ptrdiff_t */ #include "zstd_v03.h" -#include "error_private.h" +#include "../common/error_private.h" /****************************************** @@ -90,7 +90,11 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -126,10 +130,7 @@ extern "C" { * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -191,7 +192,7 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) } -#endif // MEM_FORCE_MEMORY_ACCESS +#endif /* MEM_FORCE_MEMORY_ACCESS */ MEM_STATIC U16 MEM_readLE16(const void* memPtr) @@ -352,9 +353,8 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BIT_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; + unsigned long r; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -435,7 +435,7 @@ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) } /*! BIT_lookBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -455,7 +455,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) } /*!BIT_readBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { size_t value = BIT_lookBitsFast(bitD, nbBits); @@ -2477,7 +2477,9 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - memcpy(dst, src, srcSize); + if (srcSize > 0) { + memcpy(dst, src, srcSize); + } return srcSize; } @@ -2870,8 +2872,10 @@ static size_t ZSTD_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (op != litPtr) memmove(op, litPtr, lastLLSize); - op += lastLLSize; + if (lastLLSize > 0) { + if (op != litPtr) memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } } } diff --git a/native/zstd/legacy/zstd_v03.h b/native/zstd/legacy/zstd_v03.h old mode 100755 new mode 100644 index efd8c2b..7a00d43 --- a/native/zstd/legacy/zstd_v03.h +++ b/native/zstd/legacy/zstd_v03.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/legacy/zstd_v04.c b/native/zstd/legacy/zstd_v04.c old mode 100755 new mode 100644 index 4dec308..a2d281e --- a/native/zstd/legacy/zstd_v04.c +++ b/native/zstd/legacy/zstd_v04.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,7 +16,7 @@ #include /* memcpy */ #include "zstd_v04.h" -#include "error_private.h" +#include "../common/error_private.h" /* ****************************************************************** @@ -52,7 +52,11 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -74,7 +78,7 @@ extern "C" { /*-************************************* * Debug ***************************************/ -#include "debug.h" +#include "../common/debug.h" #ifndef assert # define assert(condition) ((void)0) #endif @@ -97,10 +101,7 @@ extern "C" { * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -161,7 +162,7 @@ MEM_STATIC void MEM_write16(void* memPtr, U16 value) memcpy(memPtr, &value, sizeof(value)); } -#endif // MEM_FORCE_MEMORY_ACCESS +#endif /* MEM_FORCE_MEMORY_ACCESS */ MEM_STATIC U16 MEM_readLE16(const void* memPtr) @@ -623,9 +624,8 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BIT_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; + unsigned long r; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -700,7 +700,7 @@ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) } /*! BIT_lookBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -720,7 +720,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) } /*!BIT_readBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { size_t value = BIT_lookBitsFast(bitD, nbBits); @@ -2603,7 +2603,9 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - memcpy(dst, src, srcSize); + if (srcSize > 0) { + memcpy(dst, src, srcSize); + } return srcSize; } @@ -3008,8 +3010,10 @@ static size_t ZSTD_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (op != litPtr) memcpy(op, litPtr, lastLLSize); - op += lastLLSize; + if (lastLLSize > 0) { + if (op != litPtr) memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } } } @@ -3407,7 +3411,9 @@ static size_t ZBUFF_decompressWithDictionary(ZBUFF_DCtx* zbc, const void* src, s static size_t ZBUFF_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { size_t length = MIN(maxDstSize, srcSize); - memcpy(dst, src, length); + if (length > 0) { + memcpy(dst, src, length); + } return length; } diff --git a/native/zstd/legacy/zstd_v04.h b/native/zstd/legacy/zstd_v04.h old mode 100755 new mode 100644 index bb5f3b7..66b97ab --- a/native/zstd/legacy/zstd_v04.h +++ b/native/zstd/legacy/zstd_v04.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/legacy/zstd_v05.c b/native/zstd/legacy/zstd_v05.c old mode 100755 new mode 100644 index 570e0ff..216c67d --- a/native/zstd/legacy/zstd_v05.c +++ b/native/zstd/legacy/zstd_v05.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,7 +11,7 @@ /*- Dependencies -*/ #include "zstd_v05.h" -#include "error_private.h" +#include "../common/error_private.h" /* ****************************************************************** @@ -80,7 +80,11 @@ extern "C" { * Basic Types *****************************************************************/ #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -116,10 +120,7 @@ extern "C" { * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -484,7 +485,7 @@ static const size_t ZSTDv05_frameHeaderSize_min = 5; #define FSEv05_ENCODING_DYNAMIC 3 -#define HufLog 12 +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ @@ -752,9 +753,8 @@ MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BITv05_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; + unsigned long r; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -826,7 +826,7 @@ MEM_STATIC size_t BITv05_lookBits(BITv05_DStream_t* bitD, U32 nbBits) } /*! BITv05_lookBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BITv05_lookBitsFast(BITv05_DStream_t* bitD, U32 nbBits) { const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -846,7 +846,7 @@ MEM_STATIC size_t BITv05_readBits(BITv05_DStream_t* bitD, unsigned nbBits) } /*!BITv05_readBitsFast : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits) { size_t value = BITv05_lookBitsFast(bitD, nbBits); @@ -1804,7 +1804,7 @@ static size_t HUFv05_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ if (iSize >= (242)) { /* RLE */ @@ -1879,7 +1879,7 @@ size_t HUFv05_readDTableX2 (U16* DTable, const void* src, size_t srcSize) HUFv05_DEltX2* const dt = (HUFv05_DEltX2*)dtPtr; HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX2) == sizeof(U16)); /* if compilation fails here, assertion is false */ - //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUFv05_readStats(huffWeight, HUFv05_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUFv05_isError(iSize)) return iSize; @@ -2210,7 +2210,7 @@ size_t HUFv05_readDTableX4 (unsigned* DTable, const void* src, size_t srcSize) HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX4) == sizeof(unsigned)); /* if compilation fails here, assertion is false */ if (memLog > HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge); - //memset(weightList, 0, sizeof(weightList)); /* is not necessary, even though some analyzer complain ... */ + /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUFv05_readStats(weightList, HUFv05_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUFv05_isError(iSize)) return iSize; @@ -2539,9 +2539,9 @@ size_t HUFv05_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); - //return HUFv05_decompress4X2(dst, dstSize, cSrc, cSrcSize); /* multi-streams single-symbol decoding */ - //return HUFv05_decompress4X4(dst, dstSize, cSrc, cSrcSize); /* multi-streams double-symbols decoding */ - //return HUFv05_decompress4X6(dst, dstSize, cSrc, cSrcSize); /* multi-streams quad-symbols decoding */ + /* return HUFv05_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ + /* return HUFv05_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ + /* return HUFv05_decompress4X6(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams quad-symbols decoding */ } /* zstd - standard compression library @@ -2645,7 +2645,7 @@ struct ZSTDv05_DCtx_s FSEv05_DTable LLTable[FSEv05_DTABLE_SIZE_U32(LLFSEv05Log)]; FSEv05_DTable OffTable[FSEv05_DTABLE_SIZE_U32(OffFSEv05Log)]; FSEv05_DTable MLTable[FSEv05_DTABLE_SIZE_U32(MLFSEv05Log)]; - unsigned hufTableX4[HUFv05_DTABLE_SIZE(HufLog)]; + unsigned hufTableX4[HUFv05_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -2673,7 +2673,7 @@ size_t ZSTDv05_decompressBegin(ZSTDv05_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTableX4[0] = HufLog; + dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; dctx->flagStaticTables = 0; return 0; } @@ -2829,7 +2829,7 @@ static size_t ZSTDv05_decodeFrameHeader_Part2(ZSTDv05_DCtx* zc, const void* src, static size_t ZSTDv05_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - const BYTE* const in = (const BYTE* const)src; + const BYTE* const in = (const BYTE*)src; BYTE headerFlags; U32 cSize; @@ -2998,7 +2998,7 @@ static size_t ZSTDv05_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t FSEv05_DTable* DTableLL, FSEv05_DTable* DTableML, FSEv05_DTable* DTableOffb, const void* src, size_t srcSize, U32 flagStaticTable) { - const BYTE* const istart = (const BYTE* const)src; + const BYTE* const istart = (const BYTE*)src; const BYTE* ip = istart; const BYTE* const iend = istart + srcSize; U32 LLtype, Offtype, MLtype; @@ -3306,7 +3306,7 @@ static size_t ZSTDv05_decompressSequences( { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; BYTE* const oend = ostart + maxDstSize; size_t errorCode, dumpsLength=0; @@ -3362,8 +3362,10 @@ static size_t ZSTDv05_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; + if (lastLLSize > 0) { + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } } return op-ostart; @@ -3417,7 +3419,7 @@ static size_t ZSTDv05_decompress_continueDCtx(ZSTDv05_DCtx* dctx, { const BYTE* ip = (const BYTE*)src; const BYTE* iend = ip + srcSize; - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; BYTE* const oend = ostart + maxDstSize; size_t remainingSize = srcSize; @@ -3791,7 +3793,9 @@ static size_t ZBUFFv05_blockHeaderSize = 3; static size_t ZBUFFv05_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { size_t length = MIN(maxDstSize, srcSize); - memcpy(dst, src, length); + if (length > 0) { + memcpy(dst, src, length); + } return length; } @@ -3928,7 +3932,7 @@ size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* zbc, void* dst, size_t* maxDst *maxDstSizePtr = 0; return headerSize - zbc->hPos; } - // zbc->stage = ZBUFFv05ds_decodeHeader; break; /* useless : stage follows */ + /* zbc->stage = ZBUFFv05ds_decodeHeader; break; */ /* useless : stage follows */ } /* fall-through */ case ZBUFFv05ds_decodeHeader: @@ -4001,7 +4005,7 @@ size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* zbc, void* dst, size_t* maxDst if (!decodedSize) { zbc->stage = ZBUFFv05ds_read; break; } /* this was just a header */ zbc->outEnd = zbc->outStart + decodedSize; zbc->stage = ZBUFFv05ds_flush; - // break; /* ZBUFFv05ds_flush follows */ + /* break; */ /* ZBUFFv05ds_flush follows */ } } /* fall-through */ diff --git a/native/zstd/legacy/zstd_v05.h b/native/zstd/legacy/zstd_v05.h old mode 100755 new mode 100644 index 4a97985..bd423bf --- a/native/zstd/legacy/zstd_v05.h +++ b/native/zstd/legacy/zstd_v05.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -19,7 +19,7 @@ extern "C" { * Dependencies ***************************************/ #include /* size_t */ -#include "mem.h" /* U64, U32 */ +#include "../common/mem.h" /* U64, U32 */ /* ************************************* diff --git a/native/zstd/legacy/zstd_v06.c b/native/zstd/legacy/zstd_v06.c old mode 100755 new mode 100644 index 2a08e8d..b224355 --- a/native/zstd/legacy/zstd_v06.c +++ b/native/zstd/legacy/zstd_v06.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,7 +14,7 @@ #include /* size_t, ptrdiff_t */ #include /* memcpy */ #include /* malloc, free, qsort */ -#include "error_private.h" +#include "../common/error_private.h" @@ -82,7 +82,11 @@ extern "C" { * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -118,10 +122,7 @@ extern "C" { * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -478,7 +479,7 @@ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ -#define HufLog 12 +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 #define IS_HUF 0 #define IS_PCH 1 @@ -856,9 +857,8 @@ MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BITv06_highbit32 ( U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; + unsigned long r; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -928,7 +928,7 @@ MEM_STATIC size_t BITv06_initDStream(BITv06_DStream_t* bitD, const void* srcBuff } /*! BITv06_lookBitsFast() : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BITv06_lookBitsFast(const BITv06_DStream_t* bitD, U32 nbBits) { U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -948,7 +948,7 @@ MEM_STATIC size_t BITv06_readBits(BITv06_DStream_t* bitD, U32 nbBits) } /*! BITv06_readBitsFast() : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, U32 nbBits) { size_t const value = BITv06_lookBitsFast(bitD, nbBits); @@ -1862,7 +1862,7 @@ MEM_STATIC size_t HUFv06_readStats(BYTE* huffWeight, size_t hwSize, U32* rankSta if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ if (iSize >= (242)) { /* RLE */ @@ -2014,7 +2014,7 @@ size_t HUFv06_readDTableX2 (U16* DTable, const void* src, size_t srcSize) HUFv06_DEltX2* const dt = (HUFv06_DEltX2*)dtPtr; HUFv06_STATIC_ASSERT(sizeof(HUFv06_DEltX2) == sizeof(U16)); /* if compilation fails here, assertion is false */ - //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUFv06_readStats(huffWeight, HUFv06_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUFv06_isError(iSize)) return iSize; @@ -2340,7 +2340,7 @@ size_t HUFv06_readDTableX4 (U32* DTable, const void* src, size_t srcSize) HUFv06_STATIC_ASSERT(sizeof(HUFv06_DEltX4) == sizeof(U32)); /* if compilation fails here, assertion is false */ if (memLog > HUFv06_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge); - //memset(weightList, 0, sizeof(weightList)); /* is not necessary, even though some analyzer complain ... */ + /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUFv06_readStats(weightList, HUFv06_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUFv06_isError(iSize)) return iSize; @@ -2664,13 +2664,13 @@ size_t HUFv06_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS { U32 algoNb = 0; if (Dtime[1] < Dtime[0]) algoNb = 1; - // if (Dtime[2] < Dtime[algoNb]) algoNb = 2; /* current speed of HUFv06_decompress4X6 is not good */ + /* if (Dtime[2] < Dtime[algoNb]) algoNb = 2; */ /* current speed of HUFv06_decompress4X6 is not good */ return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); } - //return HUFv06_decompress4X2(dst, dstSize, cSrc, cSrcSize); /* multi-streams single-symbol decoding */ - //return HUFv06_decompress4X4(dst, dstSize, cSrc, cSrcSize); /* multi-streams double-symbols decoding */ - //return HUFv06_decompress4X6(dst, dstSize, cSrc, cSrcSize); /* multi-streams quad-symbols decoding */ + /* return HUFv06_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ + /* return HUFv06_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ + /* return HUFv06_decompress4X6(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams quad-symbols decoding */ } /* Common functions of Zstd compression library @@ -2806,7 +2806,7 @@ struct ZSTDv06_DCtx_s FSEv06_DTable LLTable[FSEv06_DTABLE_SIZE_U32(LLFSELog)]; FSEv06_DTable OffTable[FSEv06_DTABLE_SIZE_U32(OffFSELog)]; FSEv06_DTable MLTable[FSEv06_DTABLE_SIZE_U32(MLFSELog)]; - unsigned hufTableX4[HUFv06_DTABLE_SIZE(HufLog)]; + unsigned hufTableX4[HUFv06_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -2834,7 +2834,7 @@ size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTableX4[0] = HufLog; + dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; dctx->flagRepeatTable = 0; return 0; } @@ -3025,7 +3025,7 @@ typedef struct * Provides the size of compressed block from block header `src` */ static size_t ZSTDv06_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - const BYTE* const in = (const BYTE* const)src; + const BYTE* const in = (const BYTE*)src; U32 cSize; if (srcSize < ZSTDv06_blockHeaderSize) return ERROR(srcSize_wrong); @@ -3219,7 +3219,7 @@ static size_t ZSTDv06_decodeSeqHeaders(int* nbSeqPtr, FSEv06_DTable* DTableLL, FSEv06_DTable* DTableML, FSEv06_DTable* DTableOffb, U32 flagRepeatTable, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE* const)src; + const BYTE* const istart = (const BYTE*)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; @@ -3441,7 +3441,7 @@ static size_t ZSTDv06_decompressSequences( { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; @@ -3501,8 +3501,10 @@ static size_t ZSTDv06_decompressSequences( { size_t const lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; + if (lastLLSize > 0) { + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } } return op-ostart; @@ -3555,7 +3557,7 @@ static size_t ZSTDv06_decompressFrame(ZSTDv06_DCtx* dctx, { const BYTE* ip = (const BYTE*)src; const BYTE* const iend = ip + srcSize; - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; BYTE* const oend = ostart + dstCapacity; size_t remainingSize = srcSize; @@ -4000,7 +4002,9 @@ size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* zbd) MEM_STATIC size_t ZBUFFv06_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { size_t length = MIN(dstCapacity, srcSize); - memcpy(dst, src, length); + if (length > 0) { + memcpy(dst, src, length); + } return length; } @@ -4109,7 +4113,7 @@ size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* zbd, if (!decodedSize) { zbd->stage = ZBUFFds_read; break; } /* this was just a header */ zbd->outEnd = zbd->outStart + decodedSize; zbd->stage = ZBUFFds_flush; - // break; /* ZBUFFds_flush follows */ + /* break; */ /* ZBUFFds_flush follows */ } } /* fall-through */ diff --git a/native/zstd/legacy/zstd_v06.h b/native/zstd/legacy/zstd_v06.h old mode 100755 new mode 100644 index 0781857..9e32b76 --- a/native/zstd/legacy/zstd_v06.h +++ b/native/zstd/legacy/zstd_v06.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/legacy/zstd_v07.c b/native/zstd/legacy/zstd_v07.c old mode 100755 new mode 100644 index a2eeff8..c12a091 --- a/native/zstd/legacy/zstd_v07.c +++ b/native/zstd/legacy/zstd_v07.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,14 +17,14 @@ #ifndef XXH_STATIC_LINKING_ONLY # define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ #endif -#include "xxhash.h" /* XXH64_* */ +#include "../common/xxhash.h" /* XXH64_* */ #include "zstd_v07.h" #define FSEv07_STATIC_LINKING_ONLY /* FSEv07_MIN_TABLELOG */ #define HUFv07_STATIC_LINKING_ONLY /* HUFv07_TABLELOG_ABSOLUTEMAX */ #define ZSTDv07_STATIC_LINKING_ONLY -#include "error_private.h" +#include "../common/error_private.h" #ifdef ZSTDv07_STATIC_LINKING_ONLY @@ -242,7 +242,11 @@ extern "C" { * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; typedef uint16_t U16; typedef int16_t S16; @@ -278,10 +282,7 @@ extern "C" { * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -526,9 +527,8 @@ MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, unsigned nbBits); MEM_STATIC unsigned BITv07_highbit32 (U32 val) { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; + unsigned long r; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ return __builtin_clz (val) ^ 31; # else /* Software version */ @@ -596,7 +596,7 @@ MEM_STATIC size_t BITv07_initDStream(BITv07_DStream_t* bitD, const void* srcBuff } /*! BITv07_lookBitsFast() : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BITv07_lookBitsFast(const BITv07_DStream_t* bitD, U32 nbBits) { U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; @@ -616,7 +616,7 @@ MEM_STATIC size_t BITv07_readBits(BITv07_DStream_t* bitD, U32 nbBits) } /*! BITv07_readBitsFast() : -* unsafe version; only works only if nbBits >= 1 */ +* unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, U32 nbBits) { size_t const value = BITv07_lookBitsFast(bitD, nbBits); @@ -1314,7 +1314,7 @@ size_t HUFv07_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ if (iSize >= (242)) { /* RLE */ @@ -1784,7 +1784,7 @@ size_t HUFv07_readDTableX2 (HUFv07_DTable* DTable, const void* src, size_t srcSi HUFv07_DEltX2* const dt = (HUFv07_DEltX2*)dtPtr; HUFv07_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUFv07_DTable)); - //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUFv07_readStats(huffWeight, HUFv07_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUFv07_isError(iSize)) return iSize; @@ -2148,7 +2148,7 @@ size_t HUFv07_readDTableX4 (HUFv07_DTable* DTable, const void* src, size_t srcSi HUFv07_STATIC_ASSERT(sizeof(HUFv07_DEltX4) == sizeof(HUFv07_DTable)); /* if compilation fails here, assertion is false */ if (maxTableLog > HUFv07_TABLELOG_ABSOLUTEMAX) return ERROR(tableLog_tooLarge); - //memset(weightList, 0, sizeof(weightList)); /* is not necessary, even though some analyzer complain ... */ + /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ iSize = HUFv07_readStats(weightList, HUFv07_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUFv07_isError(iSize)) return iSize; @@ -2530,8 +2530,8 @@ size_t HUFv07_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); } - //return HUFv07_decompress4X2(dst, dstSize, cSrc, cSrcSize); /* multi-streams single-symbol decoding */ - //return HUFv07_decompress4X4(dst, dstSize, cSrc, cSrcSize); /* multi-streams double-symbols decoding */ + /* return HUFv07_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ + /* return HUFv07_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ } size_t HUFv07_decompress4X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) @@ -2717,7 +2717,7 @@ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ -#define HufLog 12 +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 typedef enum { lbt_huffman, lbt_repeat, lbt_raw, lbt_rle } litBlockType_t; #define LONGNBSEQ 0x7F00 @@ -2931,7 +2931,7 @@ struct ZSTDv07_DCtx_s FSEv07_DTable LLTable[FSEv07_DTABLE_SIZE_U32(LLFSELog)]; FSEv07_DTable OffTable[FSEv07_DTABLE_SIZE_U32(OffFSELog)]; FSEv07_DTable MLTable[FSEv07_DTABLE_SIZE_U32(MLFSELog)]; - HUFv07_DTable hufTable[HUFv07_DTABLE_SIZE(HufLog)]; /* can accommodate HUFv07_decompress4X */ + HUFv07_DTable hufTable[HUFv07_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUFv07_decompress4X */ const void* previousDstEnd; const void* base; const void* vBase; @@ -2967,7 +2967,7 @@ size_t ZSTDv07_decompressBegin(ZSTDv07_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTable[0] = (HUFv07_DTable)((HufLog)*0x1000001); + dctx->hufTable[0] = (HUFv07_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; { int i; for (i=0; irep[i] = repStartValue[i]; } @@ -3254,7 +3254,7 @@ typedef struct * Provides the size of compressed block from block header `src` */ static size_t ZSTDv07_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - const BYTE* const in = (const BYTE* const)src; + const BYTE* const in = (const BYTE*)src; U32 cSize; if (srcSize < ZSTDv07_blockHeaderSize) return ERROR(srcSize_wrong); @@ -3272,7 +3272,9 @@ static size_t ZSTDv07_getcBlockSize(const void* src, size_t srcSize, blockProper static size_t ZSTDv07_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall); - memcpy(dst, src, srcSize); + if (srcSize > 0) { + memcpy(dst, src, srcSize); + } return srcSize; } @@ -3447,7 +3449,7 @@ static size_t ZSTDv07_decodeSeqHeaders(int* nbSeqPtr, FSEv07_DTable* DTableLL, FSEv07_DTable* DTableML, FSEv07_DTable* DTableOffb, U32 flagRepeatTable, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE* const)src; + const BYTE* const istart = (const BYTE*)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; @@ -3666,7 +3668,7 @@ static size_t ZSTDv07_decompressSequences( { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; @@ -3712,10 +3714,12 @@ static size_t ZSTDv07_decompressSequences( /* last literal segment */ { size_t const lastLLSize = litEnd - litPtr; - //if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ + /* if (litPtr > litEnd) return ERROR(corruption_detected); */ /* too many literals already used */ if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall); - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; + if (lastLLSize > 0) { + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } } return op-ostart; @@ -3776,7 +3780,9 @@ ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockS static size_t ZSTDv07_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t length) { if (length > dstCapacity) return ERROR(dstSize_tooSmall); - memset(dst, byte, length); + if (length > 0) { + memset(dst, byte, length); + } return length; } @@ -3789,7 +3795,7 @@ static size_t ZSTDv07_decompressFrame(ZSTDv07_DCtx* dctx, { const BYTE* ip = (const BYTE*)src; const BYTE* const iend = ip + srcSize; - BYTE* const ostart = (BYTE* const)dst; + BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstCapacity; BYTE* op = ostart; size_t remainingSize = srcSize; @@ -4378,7 +4384,9 @@ size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* zbd) MEM_STATIC size_t ZBUFFv07_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { size_t const length = MIN(dstCapacity, srcSize); - memcpy(dst, src, length); + if (length > 0) { + memcpy(dst, src, length); + } return length; } diff --git a/native/zstd/legacy/zstd_v07.h b/native/zstd/legacy/zstd_v07.h old mode 100755 new mode 100644 index a566c1d..bc35cfa --- a/native/zstd/legacy/zstd_v07.h +++ b/native/zstd/legacy/zstd_v07.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/native/zstd/libzstd.mk b/native/zstd/libzstd.mk new file mode 100644 index 0000000..df298d7 --- /dev/null +++ b/native/zstd/libzstd.mk @@ -0,0 +1,207 @@ +# ################################################################ +# Copyright (c) Yann Collet, Facebook, Inc. +# 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. +# ################################################################ + +################################################################## +# Input Variables +################################################################## + +# Zstd lib directory +LIBZSTD ?= ./ + +# Legacy support +ZSTD_LEGACY_SUPPORT ?= 5 +ZSTD_LEGACY_MULTITHREADED_API ?= 0 + +# Build size optimizations +HUF_FORCE_DECOMPRESS_X1 ?= 0 +HUF_FORCE_DECOMPRESS_X2 ?= 0 +ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT ?= 0 +ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG ?= 0 +ZSTD_NO_INLINE ?= 0 +ZSTD_STRIP_ERROR_STRINGS ?= 0 + +# Assembly support +ZSTD_NO_ASM ?= 0 + +################################################################## +# libzstd helpers +################################################################## + +VOID ?= /dev/null + +# Make 4.3 doesn't support '\#' anymore (https://lwn.net/Articles/810071/) +NUM_SYMBOL := \# + +# define silent mode as default (verbose mode with V=1 or VERBOSE=1) +$(V)$(VERBOSE).SILENT: + +# When cross-compiling from linux to windows, +# one might need to specify TARGET_SYSTEM as "Windows." +# Building from Fedora fails without it. +# (but Ubuntu and Debian don't need to set anything) +TARGET_SYSTEM ?= $(OS) + +# Version numbers +LIBVER_SRC := $(LIBZSTD)/zstd.h +LIBVER_MAJOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LIBVER_SRC)` +LIBVER_MINOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LIBVER_SRC)` +LIBVER_PATCH_SCRIPT:=`sed -n '/define ZSTD_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LIBVER_SRC)` +LIBVER_SCRIPT:= $(LIBVER_MAJOR_SCRIPT).$(LIBVER_MINOR_SCRIPT).$(LIBVER_PATCH_SCRIPT) +LIBVER_MAJOR := $(shell echo $(LIBVER_MAJOR_SCRIPT)) +LIBVER_MINOR := $(shell echo $(LIBVER_MINOR_SCRIPT)) +LIBVER_PATCH := $(shell echo $(LIBVER_PATCH_SCRIPT)) +LIBVER := $(shell echo $(LIBVER_SCRIPT)) +CCVER := $(shell $(CC) --version) +ZSTD_VERSION?= $(LIBVER) + +# ZSTD_LIB_MINIFY is a helper variable that +# configures a bunch of other variables to space-optimized defaults. +ZSTD_LIB_MINIFY ?= 0 +ifneq ($(ZSTD_LIB_MINIFY), 0) + HAVE_CC_OZ ?= $(shell echo "" | $(CC) -Oz -x c -c - -o /dev/null 2> /dev/null && echo 1 || echo 0) + ZSTD_LEGACY_SUPPORT ?= 0 + ZSTD_LIB_DEPRECATED ?= 0 + HUF_FORCE_DECOMPRESS_X1 ?= 1 + ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT ?= 1 + ZSTD_NO_INLINE ?= 1 + ZSTD_STRIP_ERROR_STRINGS ?= 1 +ifneq ($(HAVE_CC_OZ), 0) + # Some compilers (clang) support an even more space-optimized setting. + CFLAGS += -Oz +else + CFLAGS += -Os +endif + CFLAGS += -fno-stack-protector -fomit-frame-pointer -fno-ident \ + -DDYNAMIC_BMI2=0 -DNDEBUG +else + CFLAGS ?= -O3 +endif + +DEBUGLEVEL ?= 0 +CPPFLAGS += -DXXH_NAMESPACE=ZSTD_ -DDEBUGLEVEL=$(DEBUGLEVEL) +ifeq ($(TARGET_SYSTEM),Windows_NT) # MinGW assumed + CPPFLAGS += -D__USE_MINGW_ANSI_STDIO # compatibility with %zu formatting +endif +DEBUGFLAGS= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ + -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ + -Wstrict-prototypes -Wundef -Wpointer-arith \ + -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ + -Wredundant-decls -Wmissing-prototypes -Wc++-compat +CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) +ASFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) $(CFLAGS) +LDFLAGS += $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CFLAGS) $(ASFLAGS) $(LDFLAGS) + +ifndef ALREADY_APPENDED_NOEXECSTACK +export ALREADY_APPENDED_NOEXECSTACK := 1 +ifeq ($(shell echo "int main(int argc, char* argv[]) { (void)argc; (void)argv; return 0; }" | $(CC) $(FLAGS) -z noexecstack -x c -Werror - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) +LDFLAGS += -z noexecstack +endif +ifeq ($(shell echo | $(CC) $(FLAGS) -Wa,--noexecstack -x assembler -Werror -c - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) +CFLAGS += -Wa,--noexecstack +# CFLAGS are also added to ASFLAGS +else ifeq ($(shell echo | $(CC) $(FLAGS) -Qunused-arguments -Wa,--noexecstack -x assembler -Werror -c - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) +# See e.g.: https://github.com/android/ndk/issues/171 +CFLAGS += -Qunused-arguments -Wa,--noexecstack +# CFLAGS are also added to ASFLAGS +endif +endif + +ifeq ($(shell echo "int main(int argc, char* argv[]) { (void)argc; (void)argv; return 0; }" | $(CC) $(FLAGS) -z cet-report=error -x c -Werror - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) +LDFLAGS += -z cet-report=error +endif + +HAVE_COLORNEVER = $(shell echo a | grep --color=never a > /dev/null 2> /dev/null && echo 1 || echo 0) +GREP_OPTIONS ?= +ifeq ($HAVE_COLORNEVER, 1) + GREP_OPTIONS += --color=never +endif +GREP = grep $(GREP_OPTIONS) +SED_ERE_OPT ?= -E + +ZSTD_COMMON_FILES := $(sort $(wildcard $(LIBZSTD)/common/*.c)) +ZSTD_COMPRESS_FILES := $(sort $(wildcard $(LIBZSTD)/compress/*.c)) +ZSTD_DECOMPRESS_FILES := $(sort $(wildcard $(LIBZSTD)/decompress/*.c)) +ZSTD_DICTBUILDER_FILES := $(sort $(wildcard $(LIBZSTD)/dictBuilder/*.c)) +ZSTD_DEPRECATED_FILES := $(sort $(wildcard $(LIBZSTD)/deprecated/*.c)) +ZSTD_LEGACY_FILES := + +ZSTD_DECOMPRESS_AMD64_ASM_FILES := $(sort $(wildcard $(LIBZSTD)/decompress/*_amd64.S)) + +ifneq ($(ZSTD_NO_ASM), 0) + CPPFLAGS += -DZSTD_DISABLE_ASM +else + # Unconditionally add the ASM files they are disabled by + # macros in the .S file. + ZSTD_DECOMPRESS_FILES += $(ZSTD_DECOMPRESS_AMD64_ASM_FILES) +endif + +ifneq ($(HUF_FORCE_DECOMPRESS_X1), 0) + CFLAGS += -DHUF_FORCE_DECOMPRESS_X1 +endif + +ifneq ($(HUF_FORCE_DECOMPRESS_X2), 0) + CFLAGS += -DHUF_FORCE_DECOMPRESS_X2 +endif + +ifneq ($(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT), 0) + CFLAGS += -DZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +endif + +ifneq ($(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG), 0) + CFLAGS += -DZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +endif + +ifneq ($(ZSTD_NO_INLINE), 0) + CFLAGS += -DZSTD_NO_INLINE +endif + +ifneq ($(ZSTD_STRIP_ERROR_STRINGS), 0) + CFLAGS += -DZSTD_STRIP_ERROR_STRINGS +endif + +ifneq ($(ZSTD_LEGACY_MULTITHREADED_API), 0) + CFLAGS += -DZSTD_LEGACY_MULTITHREADED_API +endif + +ifneq ($(ZSTD_LEGACY_SUPPORT), 0) +ifeq ($(shell test $(ZSTD_LEGACY_SUPPORT) -lt 8; echo $$?), 0) + ZSTD_LEGACY_FILES += $(shell ls $(LIBZSTD)/legacy/*.c | $(GREP) 'v0[$(ZSTD_LEGACY_SUPPORT)-7]') +endif +endif +CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) + +UNAME := $(shell uname) + +ifndef BUILD_DIR +ifeq ($(UNAME), Darwin) + ifeq ($(shell md5 < /dev/null > /dev/null; echo $$?), 0) + HASH ?= md5 + endif +else ifeq ($(UNAME), FreeBSD) + HASH ?= gmd5sum +else ifeq ($(UNAME), NetBSD) + HASH ?= md5 -n +else ifeq ($(UNAME), OpenBSD) + HASH ?= md5 +endif +HASH ?= md5sum + +HASH_DIR = conf_$(shell echo $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(ZSTD_FILES) | $(HASH) | cut -f 1 -d " " ) +HAVE_HASH :=$(shell echo 1 | $(HASH) > /dev/null && echo 1 || echo 0) +ifeq ($(HAVE_HASH),0) + $(info warning : could not find HASH ($(HASH)), needed to differentiate builds using different flags) + BUILD_DIR := obj/generic_noconf +endif +endif # BUILD_DIR + +ZSTD_SUBDIR := $(LIBZSTD)/common $(LIBZSTD)/compress $(LIBZSTD)/decompress $(LIBZSTD)/dictBuilder $(LIBZSTD)/legacy $(LIBZSTD)/deprecated +vpath %.c $(ZSTD_SUBDIR) +vpath %.S $(ZSTD_SUBDIR) diff --git a/native/zstd/libzstd.pc.in b/native/zstd/libzstd.pc.in index e7880be..43ebaec 100644 --- a/native/zstd/libzstd.pc.in +++ b/native/zstd/libzstd.pc.in @@ -3,13 +3,14 @@ # BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) prefix=@PREFIX@ -exec_prefix=${prefix} -includedir=${prefix}/include -libdir=${exec_prefix}/lib +exec_prefix=@EXEC_PREFIX@ +includedir=@INCLUDEDIR@ +libdir=@LIBDIR@ Name: zstd Description: fast lossless compression algorithm library URL: http://www.zstd.net/ Version: @VERSION@ Libs: -L${libdir} -lzstd +Libs.private: @LIBS_PRIVATE@ Cflags: -I${includedir} diff --git a/native/zstd/module.modulemap b/native/zstd/module.modulemap new file mode 100644 index 0000000..bbb9397 --- /dev/null +++ b/native/zstd/module.modulemap @@ -0,0 +1,25 @@ +module libzstd [extern_c] { + header "zstd.h" + export * + config_macros [exhaustive] /* zstd.h */ \ + ZSTD_STATIC_LINKING_ONLY, \ + ZSTDLIB_VISIBLE, \ + ZSTD_DLL_EXPORT, \ + ZSTDLIB_STATIC_API, \ + ZSTD_DISABLE_DEPRECATE_WARNINGS, \ + ZSTD_CLEVEL_DEFAULT, \ + /* zdict.h */ ZDICT_STATIC_LINKING_ONLY, \ + ZDICTLIB_VISIBILITY, \ + ZDICT_DISABLE_DEPRECATE_WARNINGS, \ + /* zstd_errors.h */ ZSTDERRORLIB_VISIBILITY + + module dictbuilder [extern_c] { + header "zdict.h" + export * + } + + module errors [extern_c] { + header "zstd_errors.h" + export * + } +} diff --git a/native/zstd/zdict.h b/native/zstd/zdict.h new file mode 100644 index 0000000..8e21ba0 --- /dev/null +++ b/native/zstd/zdict.h @@ -0,0 +1,452 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * 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. + */ + +#ifndef DICTBUILDER_H_001 +#define DICTBUILDER_H_001 + +#if defined (__cplusplus) +extern "C" { +#endif + + +/*====== Dependencies ======*/ +#include /* size_t */ + + +/* ===== ZDICTLIB_API : control library symbols visibility ===== */ +#ifndef ZDICTLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZDICTLIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define ZDICTLIB_VISIBILITY +# endif +#endif +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBILITY +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZDICTLIB_API ZDICTLIB_VISIBILITY +#endif + +/******************************************************************************* + * Zstd dictionary builder + * + * FAQ + * === + * Why should I use a dictionary? + * ------------------------------ + * + * Zstd can use dictionaries to improve compression ratio of small data. + * Traditionally small files don't compress well because there is very little + * repetition in a single sample, since it is small. But, if you are compressing + * many similar files, like a bunch of JSON records that share the same + * structure, you can train a dictionary on ahead of time on some samples of + * these files. Then, zstd can use the dictionary to find repetitions that are + * present across samples. This can vastly improve compression ratio. + * + * When is a dictionary useful? + * ---------------------------- + * + * Dictionaries are useful when compressing many small files that are similar. + * The larger a file is, the less benefit a dictionary will have. Generally, + * we don't expect dictionary compression to be effective past 100KB. And the + * smaller a file is, the more we would expect the dictionary to help. + * + * How do I use a dictionary? + * -------------------------- + * + * Simply pass the dictionary to the zstd compressor with + * `ZSTD_CCtx_loadDictionary()`. The same dictionary must then be passed to + * the decompressor, using `ZSTD_DCtx_loadDictionary()`. There are other + * more advanced functions that allow selecting some options, see zstd.h for + * complete documentation. + * + * What is a zstd dictionary? + * -------------------------- + * + * A zstd dictionary has two pieces: Its header, and its content. The header + * contains a magic number, the dictionary ID, and entropy tables. These + * entropy tables allow zstd to save on header costs in the compressed file, + * which really matters for small data. The content is just bytes, which are + * repeated content that is common across many samples. + * + * What is a raw content dictionary? + * --------------------------------- + * + * A raw content dictionary is just bytes. It doesn't have a zstd dictionary + * header, a dictionary ID, or entropy tables. Any buffer is a valid raw + * content dictionary. + * + * How do I train a dictionary? + * ---------------------------- + * + * Gather samples from your use case. These samples should be similar to each + * other. If you have several use cases, you could try to train one dictionary + * per use case. + * + * Pass those samples to `ZDICT_trainFromBuffer()` and that will train your + * dictionary. There are a few advanced versions of this function, but this + * is a great starting point. If you want to further tune your dictionary + * you could try `ZDICT_optimizeTrainFromBuffer_cover()`. If that is too slow + * you can try `ZDICT_optimizeTrainFromBuffer_fastCover()`. + * + * If the dictionary training function fails, that is likely because you + * either passed too few samples, or a dictionary would not be effective + * for your data. Look at the messages that the dictionary trainer printed, + * if it doesn't say too few samples, then a dictionary would not be effective. + * + * How large should my dictionary be? + * ---------------------------------- + * + * A reasonable dictionary size, the `dictBufferCapacity`, is about 100KB. + * The zstd CLI defaults to a 110KB dictionary. You likely don't need a + * dictionary larger than that. But, most use cases can get away with a + * smaller dictionary. The advanced dictionary builders can automatically + * shrink the dictionary for you, and select the smallest size that doesn't + * hurt compression ratio too much. See the `shrinkDict` parameter. + * A smaller dictionary can save memory, and potentially speed up + * compression. + * + * How many samples should I provide to the dictionary builder? + * ------------------------------------------------------------ + * + * We generally recommend passing ~100x the size of the dictionary + * in samples. A few thousand should suffice. Having too few samples + * can hurt the dictionaries effectiveness. Having more samples will + * only improve the dictionaries effectiveness. But having too many + * samples can slow down the dictionary builder. + * + * How do I determine if a dictionary will be effective? + * ----------------------------------------------------- + * + * Simply train a dictionary and try it out. You can use zstd's built in + * benchmarking tool to test the dictionary effectiveness. + * + * # Benchmark levels 1-3 without a dictionary + * zstd -b1e3 -r /path/to/my/files + * # Benchmark levels 1-3 with a dictionary + * zstd -b1e3 -r /path/to/my/files -D /path/to/my/dictionary + * + * When should I retrain a dictionary? + * ----------------------------------- + * + * You should retrain a dictionary when its effectiveness drops. Dictionary + * effectiveness drops as the data you are compressing changes. Generally, we do + * expect dictionaries to "decay" over time, as your data changes, but the rate + * at which they decay depends on your use case. Internally, we regularly + * retrain dictionaries, and if the new dictionary performs significantly + * better than the old dictionary, we will ship the new dictionary. + * + * I have a raw content dictionary, how do I turn it into a zstd dictionary? + * ------------------------------------------------------------------------- + * + * If you have a raw content dictionary, e.g. by manually constructing it, or + * using a third-party dictionary builder, you can turn it into a zstd + * dictionary by using `ZDICT_finalizeDictionary()`. You'll also have to + * provide some samples of the data. It will add the zstd header to the + * raw content, which contains a dictionary ID and entropy tables, which + * will improve compression ratio, and allow zstd to write the dictionary ID + * into the frame, if you so choose. + * + * Do I have to use zstd's dictionary builder? + * ------------------------------------------- + * + * No! You can construct dictionary content however you please, it is just + * bytes. It will always be valid as a raw content dictionary. If you want + * a zstd dictionary, which can improve compression ratio, use + * `ZDICT_finalizeDictionary()`. + * + * What is the attack surface of a zstd dictionary? + * ------------------------------------------------ + * + * Zstd is heavily fuzz tested, including loading fuzzed dictionaries, so + * zstd should never crash, or access out-of-bounds memory no matter what + * the dictionary is. However, if an attacker can control the dictionary + * during decompression, they can cause zstd to generate arbitrary bytes, + * just like if they controlled the compressed data. + * + ******************************************************************************/ + + +/*! ZDICT_trainFromBuffer(): + * Train a dictionary from an array of samples. + * Redirect towards ZDICT_optimizeTrainFromBuffer_fastCover() single-threaded, with d=8, steps=4, + * f=20, and accel=1. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * Note: Dictionary training will fail if there are not enough samples to construct a + * dictionary, or if most of the samples are too small (< 8 bytes being the lower limit). + * If dictionary training fails, you should use zstd without a dictionary, as the dictionary + * would've been ineffective anyways. If you believe your samples would benefit from a dictionary + * please open an issue with details, and we can look into it. + * Note: ZDICT_trainFromBuffer()'s memory usage is about 6 MB. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples); + +typedef struct { + int compressionLevel; /*< optimize for a specific zstd compression level; 0 means default */ + unsigned notificationLevel; /*< Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ + unsigned dictID; /*< force dictID value; 0 means auto mode (32-bits random value) + * NOTE: The zstd format reserves some dictionary IDs for future use. + * You may use them in private settings, but be warned that they + * may be used by zstd in a public dictionary registry in the future. + * These dictionary IDs are: + * - low range : <= 32767 + * - high range : >= (2^31) + */ +} ZDICT_params_t; + +/*! ZDICT_finalizeDictionary(): + * Given a custom content as a basis for dictionary, and a set of samples, + * finalize dictionary by adding headers and statistics according to the zstd + * dictionary format. + * + * Samples must be stored concatenated in a flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each + * sample in order. The samples are used to construct the statistics, so they + * should be representative of what you will compress with this dictionary. + * + * The compression level can be set in `parameters`. You should pass the + * compression level you expect to use in production. The statistics for each + * compression level differ, so tuning the dictionary for the compression level + * can help quite a bit. + * + * You can set an explicit dictionary ID in `parameters`, or allow us to pick + * a random dictionary ID for you, but we can't guarantee no collisions. + * + * The dstDictBuffer and the dictContent may overlap, and the content will be + * appended to the end of the header. If the header + the content doesn't fit in + * maxDictSize the beginning of the content is truncated to make room, since it + * is presumed that the most profitable content is at the end of the dictionary, + * since that is the cheapest to reference. + * + * `maxDictSize` must be >= max(dictContentSize, ZSTD_DICTSIZE_MIN). + * + * @return: size of dictionary stored into `dstDictBuffer` (<= `maxDictSize`), + * or an error code, which can be tested by ZDICT_isError(). + * Note: ZDICT_finalizeDictionary() will push notifications into stderr if + * instructed to, using notificationLevel>0. + * NOTE: This function currently may fail in several edge cases including: + * * Not enough samples + * * Samples are uncompressible + * * Samples are all exactly the same + */ +ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dstDictBuffer, size_t maxDictSize, + const void* dictContent, size_t dictContentSize, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t parameters); + + +/*====== Helper functions ======*/ +ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize); /**< extracts dictID; @return zero if error (not a valid dictionary) */ +ZDICTLIB_API size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize); /* returns dict header size; returns a ZSTD error code on failure */ +ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode); +ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode); + + + +#ifdef ZDICT_STATIC_LINKING_ONLY + +/* ==================================================================================== + * The definitions in this section are considered experimental. + * They should never be used with a dynamic library, as they may change in the future. + * They are provided for advanced usages. + * Use them only in association with static linking. + * ==================================================================================== */ + +#define ZDICT_DICTSIZE_MIN 256 +/* Deprecated: Remove in v1.6.0 */ +#define ZDICT_CONTENTSIZE_MIN 128 + +/*! ZDICT_cover_params_t: + * k and d are the only required parameters. + * For others, value 0 means default. + */ +typedef struct { + unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ + unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ + unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ + unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ + double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (1.0), 1.0 when all samples are used for both training and testing */ + unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ + unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ + ZDICT_params_t zParams; +} ZDICT_cover_params_t; + +typedef struct { + unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ + unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ + unsigned f; /* log of size of frequency array : constraint: 0 < f <= 31 : 1 means default(20)*/ + unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ + unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ + double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (0.75), 1.0 when all samples are used for both training and testing */ + unsigned accel; /* Acceleration level: constraint: 0 < accel <= 10, higher means faster and less accurate, 0 means default(1) */ + unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ + unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ + + ZDICT_params_t zParams; +} ZDICT_fastCover_params_t; + +/*! ZDICT_trainFromBuffer_cover(): + * Train a dictionary from an array of samples using the COVER algorithm. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_trainFromBuffer_cover() requires about 9 bytes of memory for each input byte. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover( + void *dictBuffer, size_t dictBufferCapacity, + const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t parameters); + +/*! ZDICT_optimizeTrainFromBuffer_cover(): + * The same requirements as above hold for all the parameters except `parameters`. + * This function tries many parameter combinations and picks the best parameters. + * `*parameters` is filled with the best parameters found, + * dictionary constructed with those parameters is stored in `dictBuffer`. + * + * All of the parameters d, k, steps are optional. + * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. + * if steps is zero it defaults to its default value. + * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. + * + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * On success `*parameters` contains the parameters selected. + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_optimizeTrainFromBuffer_cover() requires about 8 bytes of memory for each input byte and additionally another 5 bytes of memory for each byte of memory for each thread. + */ +ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( + void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t* parameters); + +/*! ZDICT_trainFromBuffer_fastCover(): + * Train a dictionary from an array of samples using a modified version of COVER algorithm. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * d and k are required. + * All other parameters are optional, will use default values if not provided + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_trainFromBuffer_fastCover() requires 6 * 2^f bytes of memory. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, + size_t dictBufferCapacity, const void *samplesBuffer, + const size_t *samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t parameters); + +/*! ZDICT_optimizeTrainFromBuffer_fastCover(): + * The same requirements as above hold for all the parameters except `parameters`. + * This function tries many parameter combinations (specifically, k and d combinations) + * and picks the best parameters. `*parameters` is filled with the best parameters found, + * dictionary constructed with those parameters is stored in `dictBuffer`. + * All of the parameters d, k, steps, f, and accel are optional. + * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. + * if steps is zero it defaults to its default value. + * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. + * If f is zero, default value of 20 is used. + * If accel is zero, default value of 1 is used. + * + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * On success `*parameters` contains the parameters selected. + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_optimizeTrainFromBuffer_fastCover() requires about 6 * 2^f bytes of memory for each thread. + */ +ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer, + size_t dictBufferCapacity, const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t* parameters); + +typedef struct { + unsigned selectivityLevel; /* 0 means default; larger => select more => larger dictionary */ + ZDICT_params_t zParams; +} ZDICT_legacy_params_t; + +/*! ZDICT_trainFromBuffer_legacy(): + * Train a dictionary from an array of samples. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * `parameters` is optional and can be provided with values set to 0 to mean "default". + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + * Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0. + */ +ZDICTLIB_API size_t ZDICT_trainFromBuffer_legacy( + void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_legacy_params_t parameters); + + +/* Deprecation warnings */ +/* It is generally possible to disable deprecation warnings from compiler, + for example with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual. + Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */ +#ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS +# define ZDICT_DEPRECATED(message) ZDICTLIB_API /* disable deprecation warnings */ +#else +# define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZDICT_DEPRECATED(message) [[deprecated(message)]] ZDICTLIB_API +# elif defined(__clang__) || (ZDICT_GCC_VERSION >= 405) +# define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated(message))) +# elif (ZDICT_GCC_VERSION >= 301) +# define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZDICT_DEPRECATED(message) ZDICTLIB_API __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler") +# define ZDICT_DEPRECATED(message) ZDICTLIB_API +# endif +#endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */ + +ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead") +size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples); + + +#endif /* ZDICT_STATIC_LINKING_ONLY */ + +#if defined (__cplusplus) +} +#endif + +#endif /* DICTBUILDER_H_001 */ diff --git a/native/zstd/zstd.h b/native/zstd/zstd.h index 72080ea..65d5add 100644 --- a/native/zstd/zstd.h +++ b/native/zstd/zstd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,21 +20,45 @@ extern "C" { /* ===== ZSTDLIB_API : control library symbols visibility ===== */ -#ifndef ZSTDLIB_VISIBILITY -# if defined(__GNUC__) && (__GNUC__ >= 4) -# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default"))) +#ifndef ZSTDLIB_VISIBLE +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDLIB_VISIBLE __attribute__ ((visibility ("default"))) +# define ZSTDLIB_HIDDEN __attribute__ ((visibility ("hidden"))) # else -# define ZSTDLIB_VISIBILITY +# define ZSTDLIB_VISIBLE +# define ZSTDLIB_HIDDEN # endif #endif #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY +# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBLE #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZSTDLIB_API ZSTDLIB_VISIBILITY +# define ZSTDLIB_API ZSTDLIB_VISIBLE #endif +/* Deprecation warnings : + * Should these warnings be a problem, it is generally possible to disable them, + * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. + * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS. + */ +#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS +# define ZSTD_DEPRECATED(message) /* disable deprecation warnings */ +#else +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZSTD_DEPRECATED(message) [[deprecated(message)]] +# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) +# define ZSTD_DEPRECATED(message) __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ >= 3) +# define ZSTD_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZSTD_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler") +# define ZSTD_DEPRECATED(message) +# endif +#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */ + /******************************************************************************* Introduction @@ -71,17 +95,22 @@ extern "C" { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 -#define ZSTD_VERSION_MINOR 4 -#define ZSTD_VERSION_RELEASE 4 - +#define ZSTD_VERSION_MINOR 5 +#define ZSTD_VERSION_RELEASE 3 #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) -ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */ + +/*! ZSTD_versionNumber() : + * Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */ +ZSTDLIB_API unsigned ZSTD_versionNumber(void); #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE #define ZSTD_QUOTE(str) #str #define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) #define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) -ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */ + +/*! ZSTD_versionString() : + * Return runtime library version, like "1.4.5". Requires v1.3.0+. */ +ZSTDLIB_API const char* ZSTD_versionString(void); /* ************************************* * Default constant @@ -104,7 +133,6 @@ ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */ #define ZSTD_BLOCKSIZE_MAX (1<= first frame size * @return : the compressed size of the first frame starting at `src`, @@ -175,8 +205,9 @@ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize) ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ -ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed */ +ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ +ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */ /*************************************** @@ -194,7 +225,7 @@ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compres */ typedef struct ZSTD_CCtx_s ZSTD_CCtx; ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); -ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */ /*! ZSTD_compressCCtx() : * Same as ZSTD_compress(), using an explicit ZSTD_CCtx. @@ -217,7 +248,7 @@ ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, * Use one context per thread for parallel execution. */ typedef struct ZSTD_DCtx_s ZSTD_DCtx; ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); -ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */ /*! ZSTD_decompressDCtx() : * Same as ZSTD_decompress(), @@ -229,9 +260,9 @@ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, const void* src, size_t srcSize); -/*************************************** -* Advanced compression API -***************************************/ +/********************************************* +* Advanced compression API (Requires v1.4.0+) +**********************************************/ /* API design : * Parameters are pushed one by one into an existing context, @@ -242,7 +273,7 @@ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, * * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset(). * - * This API supercedes all other "advanced" API entry points in the experimental section. + * This API supersedes all other "advanced" API entry points in the experimental section. * In the future, we expect to remove from experimental API entry points which are redundant with this API. */ @@ -261,7 +292,6 @@ typedef enum { ZSTD_fast=1, Only the order (from fast to strong) is guaranteed */ } ZSTD_strategy; - typedef enum { /* compression parameters @@ -274,7 +304,10 @@ typedef enum { * Default level is ZSTD_CLEVEL_DEFAULT==3. * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT. * Note 1 : it's possible to pass a negative compression level. - * Note 2 : setting a level resets all other compression parameters to default */ + * Note 2 : setting a level does not automatically set all other compression parameters + * to default. Setting this will however eventually dynamically impact the compression + * parameters which have not been manually set. The manually set + * ones will 'stick'. */ /* Advanced compression parameters : * It's possible to pin down compression parameters to some specific values. * In which case, these values are no longer dynamically selected by the compressor */ @@ -324,14 +357,15 @@ typedef enum { * The higher the value of selected strategy, the more complex it is, * resulting in stronger and slower compression. * Special: value 0 means "use default strategy". */ - /* LDM mode parameters */ ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching. * This parameter is designed to improve compression ratio * for large inputs, by finding large matches at long distance. * It increases memory usage and window size. * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB - * except when expressly set to a different value. */ + * except when expressly set to a different value. + * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and + * compression strategy >= ZSTD_btopt (== compression level 16+) */ ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2. * Larger values increase memory usage and compression ratio, * but decrease compression speed. @@ -362,20 +396,24 @@ typedef enum { ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */ /* multi-threading parameters */ - /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). - * They return an error otherwise. */ + /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). + * Otherwise, trying to set any other value than default (0) will be a no-op and return an error. + * In a situation where it's unknown if the linked library supports multi-threading or not, + * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property. + */ ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel. - * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() : + * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() : * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller, - * while compression work is performed in parallel, within worker threads. + * while compression is performed in parallel, within worker thread(s). * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end : * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call). * More workers improve speed, but also increase memory usage. - * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */ + * Default value is `0`, aka "single-threaded mode" : no worker is spawned, + * compression is performed inside Caller's thread, and all invocations are blocking */ ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1. * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads. * 0 means default, which is dynamically determined based on compression parameters. - * Job size must be a minimum of overlap size, or 1 MB, whichever is largest. + * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest. * The minimum size is automatically and transparently enforced. */ ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size. * The overlap size is an amount of data reloaded from previous job at the beginning of a new job. @@ -400,6 +438,14 @@ typedef enum { * ZSTD_c_literalCompressionMode * ZSTD_c_targetCBlockSize * ZSTD_c_srcSizeHint + * ZSTD_c_enableDedicatedDictSearch + * ZSTD_c_stableInBuffer + * ZSTD_c_stableOutBuffer + * ZSTD_c_blockDelimiters + * ZSTD_c_validateSequences + * ZSTD_c_useBlockSplitter + * ZSTD_c_useRowMatchFinder + * ZSTD_c_prefetchCDictTables * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly; * also, the enums values themselves are unstable and can still change. @@ -410,7 +456,16 @@ typedef enum { ZSTD_c_experimentalParam4=1001, ZSTD_c_experimentalParam5=1002, ZSTD_c_experimentalParam6=1003, - ZSTD_c_experimentalParam7=1004 + ZSTD_c_experimentalParam7=1004, + ZSTD_c_experimentalParam8=1005, + ZSTD_c_experimentalParam9=1006, + ZSTD_c_experimentalParam10=1007, + ZSTD_c_experimentalParam11=1008, + ZSTD_c_experimentalParam12=1009, + ZSTD_c_experimentalParam13=1010, + ZSTD_c_experimentalParam14=1011, + ZSTD_c_experimentalParam15=1012, + ZSTD_c_experimentalParam16=1013 } ZSTD_cParameter; typedef struct { @@ -495,9 +550,9 @@ ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx, const void* src, size_t srcSize); -/*************************************** -* Advanced decompression API -***************************************/ +/*********************************************** +* Advanced decompression API (Requires v1.4.0+) +************************************************/ /* The advanced API pushes parameters one by one into an existing DCtx context. * Parameters are sticky, and remain valid for all following frames @@ -519,11 +574,17 @@ typedef enum { /* note : additional experimental parameters are also available * within the experimental section of the API. * At the time of this writing, they include : - * ZSTD_c_format + * ZSTD_d_format + * ZSTD_d_stableOutBuffer + * ZSTD_d_forceIgnoreChecksum + * ZSTD_d_refMultipleDDicts * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly */ - ZSTD_d_experimentalParam1=1000 + ZSTD_d_experimentalParam1=1000, + ZSTD_d_experimentalParam2=1001, + ZSTD_d_experimentalParam3=1002, + ZSTD_d_experimentalParam4=1003 } ZSTD_dParameter; @@ -637,7 +698,7 @@ typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */ /*===== ZSTD_CStream management functions =====*/ ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); -ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); +ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */ /*===== Streaming compression functions =====*/ typedef enum { @@ -653,14 +714,15 @@ typedef enum { : note : multithreaded compression will block to flush as much output as possible. */ } ZSTD_EndDirective; -/*! ZSTD_compressStream2() : +/*! ZSTD_compressStream2() : Requires v1.4.0+ * Behaves about the same as ZSTD_compressStream, with additional control on end directive. * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode) * - output->pos must be <= dstCapacity, input->pos must be <= srcSize * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. + * - endOp must be a valid directive * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller. - * - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available, + * - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available, * and then immediately returns, just indicating that there is some data remaining to be flushed. * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte. * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking. @@ -698,11 +760,11 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output /* ***************************************************************************** - * This following is a legacy streaming API. + * This following is a legacy streaming API, available since v1.0+ . * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). * It is redundant, but remains fully supported. - * Advanced parameters and dictionary compression can only be used through the - * new API. + * Streaming in combination with advanced parameters and dictionary compression + * can only be used through the new API. ******************************************************************************/ /*! @@ -757,17 +819,35 @@ typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same /* For compatibility with versions <= v1.2.0, prefer differentiating them. */ /*===== ZSTD_DStream management functions =====*/ ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); -ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); +ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */ /*===== Streaming decompression functions =====*/ -/* This function is redundant with the advanced API and equivalent to: +/*! ZSTD_initDStream() : + * Initialize/reset DStream state for new decompression operation. + * Call before new decompression operation using same DStream. * - * ZSTD_DCtx_reset(zds); + * Note : This function is redundant with the advanced API and equivalent to: + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); * ZSTD_DCtx_refDDict(zds, NULL); */ ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); +/*! ZSTD_decompressStream() : + * Streaming decompression function. + * Call repetitively to consume full input updating it as necessary. + * Funtion will update both input and output `pos` fields exposing current state via these fields: + * - `input.pos < input.size`, some input remaining and caller should provide remaining input + * on the next call. + * - `output.pos < output.size`, decoder finished and flushed all remaining buffers. + * - `output.pos == output.size`, potentially uncflushed data present in the internal buffers, + * call ZSTD_decompressStream() again to flush remaining data to output. + * Note : with no additional input, amount of data flushed <= ZSTD_BLOCKSIZE_MAX. + * + * @return : 0 when a frame is completly decoded and fully flushed, + * or an error code, which can be tested using ZSTD_isError(), + * or any other value > 0, which means there is some decoding or flushing to do to complete current frame. + */ ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ @@ -780,7 +860,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output /*! ZSTD_compress_usingDict() : * Compression at an explicit compression level using a Dictionary. * A dictionary can be any arbitrary data segment (also called a prefix), - * or a buffer with specified information (see dictBuilder/zdict.h). + * or a buffer with specified information (see zdict.h). * Note : This function loads the dictionary, resulting in significant startup delay. * It's intended for a dictionary used only once. * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */ @@ -823,7 +903,8 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize int compressionLevel); /*! ZSTD_freeCDict() : - * Function frees memory allocated by ZSTD_createCDict(). */ + * Function frees memory allocated by ZSTD_createCDict(). + * If a NULL pointer is passed, no operation is performed. */ ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); /*! ZSTD_compress_usingCDict() : @@ -845,7 +926,8 @@ typedef struct ZSTD_DDict_s ZSTD_DDict; ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); /*! ZSTD_freeDDict() : - * Function frees memory allocated with ZSTD_createDDict() */ + * Function frees memory allocated with ZSTD_createDDict() + * If a NULL pointer is passed, no operation is performed. */ ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); /*! ZSTD_decompress_usingDDict() : @@ -861,24 +943,30 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, * Dictionary helper functions *******************************/ -/*! ZSTD_getDictID_fromDict() : +/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+ * Provides the dictID stored within dictionary. * if @return == 0, the dictionary is not conformant with Zstandard specification. * It can still be loaded, but as a content-only dictionary. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize); -/*! ZSTD_getDictID_fromDDict() : +/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+ + * Provides the dictID of the dictionary loaded into `cdict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict); + +/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+ * Provides the dictID of the dictionary loaded into `ddict`. * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); -/*! ZSTD_getDictID_fromFrame() : +/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+ * Provides the dictID required to decompressed the frame stored within `src`. * If @return == 0, the dictID could not be decoded. * This could for one of the following reasons : * - The frame does not require a dictionary to be decoded (most common case). - * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information. + * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden piece of information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). * - This is not a Zstandard frame. @@ -887,16 +975,16 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); /******************************************************************************* - * Advanced dictionary and prefix API + * Advanced dictionary and prefix API (Requires v1.4.0+) * * This API allows dictionaries to be used with ZSTD_compress2(), - * ZSTD_compressStream2(), and ZSTD_decompress(). Dictionaries are sticky, and + * ZSTD_compressStream2(), and ZSTD_decompressDCtx(). Dictionaries are sticky, and * only reset with the context is reset with ZSTD_reset_parameters or * ZSTD_reset_session_and_parameters. Prefixes are single-use. ******************************************************************************/ -/*! ZSTD_CCtx_loadDictionary() : +/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+ * Create an internal CDict from `dict` buffer. * Decompression will have to use same dictionary. * @result : 0, or an error code (which can be tested with ZSTD_isError()). @@ -915,11 +1003,11 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); * to precisely select how dictionary content must be interpreted. */ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); -/*! ZSTD_CCtx_refCDict() : +/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+ * Reference a prepared dictionary, to be used for all next compressed frames. * Note that compression parameters are enforced from within CDict, * and supersede any compression parameter previously set within CCtx. - * The parameters ignored are labled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. + * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode. * The dictionary will remain valid for future compressed frames using same CCtx. * @result : 0, or an error code (which can be tested with ZSTD_isError()). @@ -929,7 +1017,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); -/*! ZSTD_CCtx_refPrefix() : +/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+ * Reference a prefix (single-usage dictionary) for next compressed frame. * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end). * Decompression will need same prefix to properly regenerate data. @@ -950,7 +1038,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize); -/*! ZSTD_DCtx_loadDictionary() : +/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+ * Create an internal DDict from dict buffer, * to be used to decompress next frames. * The dictionary remains valid for all future frames, until explicitly invalidated. @@ -967,9 +1055,16 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, */ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -/*! ZSTD_DCtx_refDDict() : +/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+ * Reference a prepared dictionary, to be used to decompress next frames. * The dictionary remains active for decompression of future frames using same DCtx. + * + * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function + * will store the DDict references in a table, and the DDict used for decompression + * will be determined at decompression time, as per the dict ID in the frame. + * The memory for the table is allocated on the first call to refDDict, and can be + * freed with ZSTD_freeDCtx(). + * * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Note 1 : Currently, only one dictionary can be managed. * Referencing a new dictionary effectively "discards" any previous one. @@ -978,7 +1073,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, s */ ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -/*! ZSTD_DCtx_refPrefix() : +/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+ * Reference a prefix (single-usage dictionary) to decompress next frame. * This is the reverse operation of ZSTD_CCtx_refPrefix(), * and must use the same prefix as the one used during compression. @@ -999,7 +1094,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, /* === Memory management === */ -/*! ZSTD_sizeof_*() : +/*! ZSTD_sizeof_*() : Requires v1.4.0+ * These functions give the _current_ memory usage of selected object. * Note that object memory usage can evolve (increase or decrease) over time. */ ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); @@ -1024,6 +1119,17 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); #if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) #define ZSTD_H_ZSTD_STATIC_LINKING_ONLY +/* This can be overridden externally to hide static symbols. */ +#ifndef ZSTDLIB_STATIC_API +# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllexport) ZSTDLIB_VISIBLE +# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllimport) ZSTDLIB_VISIBLE +# else +# define ZSTDLIB_STATIC_API ZSTDLIB_VISIBLE +# endif +#endif + /**************************************************************************************** * experimental API (static linking only) **************************************************************************************** @@ -1086,30 +1192,46 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); #define ZSTD_SRCSIZEHINT_MIN 0 #define ZSTD_SRCSIZEHINT_MAX INT_MAX -/* internal */ -#define ZSTD_HASHLOG3_MAX 17 - /* --- Advanced types --- */ typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params; typedef struct { - unsigned int matchPos; /* Match pos in dst */ - /* If seqDef.offset > 3, then this is seqDef.offset - 3 - * If seqDef.offset < 3, then this is the corresponding repeat offset - * But if seqDef.offset < 3 and litLength == 0, this is the - * repeat offset before the corresponding repeat offset - * And if seqDef.offset == 3 and litLength == 0, this is the - * most recent repeat offset - 1 - */ - unsigned int offset; - unsigned int litLength; /* Literal length */ - unsigned int matchLength; /* Match length */ - /* 0 when seq not rep and seqDef.offset otherwise - * when litLength == 0 this will be <= 4, otherwise <= 3 like normal - */ - unsigned int rep; + unsigned int offset; /* The offset of the match. (NOT the same as the offset code) + * If offset == 0 and matchLength == 0, this sequence represents the last + * literals in the block of litLength size. + */ + + unsigned int litLength; /* Literal length of the sequence. */ + unsigned int matchLength; /* Match length of the sequence. */ + + /* Note: Users of this API may provide a sequence with matchLength == litLength == offset == 0. + * In this case, we will treat the sequence as a marker for a block boundary. + */ + + unsigned int rep; /* Represents which repeat offset is represented by the field 'offset'. + * Ranges from [0, 3]. + * + * Repeat offsets are essentially previous offsets from previous sequences sorted in + * recency order. For more detail, see doc/zstd_compression_format.md + * + * If rep == 0, then 'offset' does not contain a repeat offset. + * If rep > 0: + * If litLength != 0: + * rep == 1 --> offset == repeat_offset_1 + * rep == 2 --> offset == repeat_offset_2 + * rep == 3 --> offset == repeat_offset_3 + * If litLength == 0: + * rep == 1 --> offset == repeat_offset_2 + * rep == 2 --> offset == repeat_offset_3 + * rep == 3 --> offset == repeat_offset_1 - 1 + * + * Note: This field is optional. ZSTD_generateSequences() will calculate the value of + * 'rep', but repeat offsets do not necessarily need to be calculated from an external + * sequence provider's perspective. For example, ZSTD_compressSequences() does not + * use this 'rep' field at all (as of now). + */ } ZSTD_Sequence; typedef struct { @@ -1151,6 +1273,18 @@ typedef enum { * Decoder cannot recognise automatically this format, requiring this instruction. */ } ZSTD_format_e; +typedef enum { + /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ + ZSTD_d_validateChecksum = 0, + ZSTD_d_ignoreChecksum = 1 +} ZSTD_forceIgnoreChecksum_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_refMultipleDDicts */ + ZSTD_rmd_refSingleDDict = 0, + ZSTD_rmd_refMultipleDDicts = 1 +} ZSTD_refMultipleDDicts_e; + typedef enum { /* Note: this enum and the behavior it controls are effectively internal * implementation details of the compressor. They are expected to continue @@ -1199,6 +1333,15 @@ typedef enum { ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ } ZSTD_literalCompressionMode_e; +typedef enum { + /* Note: This enum controls features which are conditionally beneficial. Zstd typically will make a final + * decision on whether or not to enable the feature (ZSTD_ps_auto), but setting the switch to ZSTD_ps_enable + * or ZSTD_ps_disable allow for a force enable/disable the feature. + */ + ZSTD_ps_auto = 0, /* Let the library automatically determine whether the feature shall be enabled */ + ZSTD_ps_enable = 1, /* Force-enable the feature */ + ZSTD_ps_disable = 2 /* Do not use the feature */ +} ZSTD_paramSwitch_e; /*************************************** * Frame size functions @@ -1225,14 +1368,14 @@ typedef enum { * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to * read each contained frame header. This is fast as most of the data is skipped, * however it does mean that all frame data must be present and valid. */ -ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); +ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); /*! ZSTD_decompressBound() : * `src` should point to the start of a series of ZSTD encoded and/or skippable frames * `srcSize` must be the _exact_ size of this series * (i.e. there should be a frame boundary at `src + srcSize`) * @return : - upper-bound for the decompressed size of all data in all successive frames - * - if an error occured: ZSTD_CONTENTSIZE_ERROR + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR * * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. @@ -1240,22 +1383,124 @@ ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: * upper-bound = # blocks * min(128 KB, Window_Size) */ -ZSTDLIB_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); +ZSTDLIB_STATIC_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); /*! ZSTD_frameHeaderSize() : * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. * @return : size of the Frame Header, * or an error code (if srcSize is too small) */ -ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); -/*! ZSTD_getSequences() : - * Extract sequences from the sequence store - * zc can be used to insert custom compression params. - * This function invokes ZSTD_compress2 - * @return : number of sequences extracted +typedef enum { + ZSTD_sf_noBlockDelimiters = 0, /* Representation of ZSTD_Sequence has no block delimiters, sequences only */ + ZSTD_sf_explicitBlockDelimiters = 1 /* Representation of ZSTD_Sequence contains explicit block delimiters */ +} ZSTD_sequenceFormat_e; + +/*! ZSTD_generateSequences() : + * Generate sequences using ZSTD_compress2(), given a source buffer. + * + * Each block will end with a dummy sequence + * with offset == 0, matchLength == 0, and litLength == length of last literals. + * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0) + * simply acts as a block delimiter. + * + * @zc can be used to insert custom compression params. + * This function invokes ZSTD_compress2(). + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_explicitBlockDelimiters + * @return : number of sequences generated */ -ZSTDLIB_API size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, - size_t outSeqsSize, const void* src, size_t srcSize); + +ZSTDLIB_STATIC_API size_t +ZSTD_generateSequences( ZSTD_CCtx* zc, + ZSTD_Sequence* outSeqs, size_t outSeqsSize, + const void* src, size_t srcSize); + +/*! ZSTD_mergeBlockDelimiters() : + * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals + * by merging them into the literals of the next sequence. + * + * As such, the final generated result has no explicit representation of block boundaries, + * and the final last literals segment is not represented in the sequences. + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters + * @return : number of sequences left after merging + */ +ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); + +/*! ZSTD_compressSequences() : + * Compress an array of ZSTD_Sequence, associated with @src buffer, into dst. + * @src contains the entire input (not just the literals). + * If @srcSize > sum(sequence.length), the remaining bytes are considered all literals + * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) + * The entire source is compressed into a single frame. + * + * The compression behavior changes based on cctx params. In particular: + * If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on + * the block size derived from the cctx, and sequences may be split. This is the default setting. + * + * If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided. + * + * If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined + * behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and return an error. + * + * In addition to the two adjustable experimental params, there are other important cctx params. + * - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN. + * - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression. + * - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset + * is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md + * + * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused. + * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly, + * and cannot emit an RLE block that disagrees with the repcode history + * @return : final compressed size, or a ZSTD error code. + */ +ZSTDLIB_STATIC_API size_t +ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize); + + +/*! ZSTD_writeSkippableFrame() : + * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * Skippable frames begin with a 4-byte magic number. There are 16 possible choices of magic number, + * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. + * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so + * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. + * + * Returns an error if destination buffer is not large enough, if the source size is not representable + * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, + const void* src, size_t srcSize, unsigned magicVariant); + +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize); + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + */ +ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); + /*************************************** @@ -1263,27 +1508,32 @@ ZSTDLIB_API size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, ***************************************/ /*! ZSTD_estimate*() : - * These functions make it possible to estimate memory usage of a future - * {D,C}Ctx, before its creation. - * - * ZSTD_estimateCCtxSize() will provide a budget large enough for any - * compression level up to selected one. Unlike ZSTD_estimateCStreamSize*(), - * this estimate does not include space for a window buffer, so this estimate - * is guaranteed to be enough for single-shot compressions, but not streaming - * compressions. It will however assume the input may be arbitrarily large, - * which is the worst case. If srcSize is known to always be small, - * ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation. - * ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with - * ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with - * ZSTD_CCtxParams_setParameter(). - * - * Note: only single-threaded compression is supported. This function will - * return an error code if ZSTD_c_nbWorkers is >= 1. */ -ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); + * These functions make it possible to estimate memory usage + * of a future {D,C}Ctx, before its creation. + * + * ZSTD_estimateCCtxSize() will provide a memory budget large enough + * for any compression level up to selected one. + * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate + * does not include space for a window buffer. + * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming. + * The estimate will assume the input may be arbitrarily large, + * which is the worst case. + * + * When srcSize can be bound by a known and rather "small" value, + * this fact can be used to provide a tighter estimation + * because the CCtx compression context will need less memory. + * This tighter estimation can be provided by more advanced functions + * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), + * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). + * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. + * + * Note 2 : only single-threaded compression is supported. + * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); /*! ZSTD_estimateCStreamSize() : * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. @@ -1298,20 +1548,20 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), * an internal ?Dict will be created, which additional size is not estimated here. * In this case, get total size by adding ZSTD_estimate?DictSize */ -ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); -ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t windowSize); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); /*! ZSTD_estimate?DictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. */ -ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); -ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); /*! ZSTD_initStatic*() : * Initialize an object using a pre-allocated fixed-size buffer. @@ -1334,20 +1584,20 @@ ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e * Limitation 2 : static cctx currently not compatible with multi-threading. * Limitation 3 : static dctx is incompatible with legacy support. */ -ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ -ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ -ZSTDLIB_API const ZSTD_CDict* ZSTD_initStaticCDict( +ZSTDLIB_STATIC_API const ZSTD_CDict* ZSTD_initStaticCDict( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams); -ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict( +ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, @@ -1362,25 +1612,55 @@ ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict( typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); typedef void (*ZSTD_freeFunction) (void* opaque, void* address); typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; -static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ +static +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif +ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ -ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams, ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_customMem customMem); +/*! Thread pool : + * These prototypes make it possible to share a thread pool among multiple compression contexts. + * This can limit resources for applications with multiple threads where each one uses + * a threaded compression mode (via ZSTD_c_nbWorkers parameter). + * ZSTD_createThreadPool creates a new thread pool with a given number of threads. + * Note that the lifetime of such pool must exist while being used. + * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value + * to use an internal thread pool). + * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer. + */ +typedef struct POOL_ctx_s ZSTD_threadPool; +ZSTDLIB_STATIC_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads); +ZSTDLIB_STATIC_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool); +/* + * This API is temporary and is expected to change or disappear in the future! + */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced2( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + const ZSTD_CCtx_params* cctxParams, + ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem); + /*************************************** * Advanced compression functions @@ -1392,22 +1672,22 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictS * As a consequence, `dictBuffer` **must** outlive CDict, * and its content must remain unmodified throughout the lifetime of CDict. * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ -ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. * `estimatedSrcSize` value is optional, select 0 if not known */ -ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); /*! ZSTD_getParams() : * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ -ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); +ZSTDLIB_STATIC_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); /*! ZSTD_checkCParams() : * Ensure param values remain within authorized range. * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ -ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); +ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); /*! ZSTD_adjustCParams() : * optimize params for a given `srcSize` and `dictSize`. @@ -1415,23 +1695,27 @@ ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); * `dictSize` must be `0` when there is no dictionary. * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. * This function never fails (wide contract) */ -ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); /*! ZSTD_compress_advanced() : * Note : this function is now DEPRECATED. * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. - * This prototype will be marked as deprecated and generate compilation warning on reaching v1.5.x */ -ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, + * This prototype will generate compilation warnings. */ +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_compress2") +size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict,size_t dictSize, ZSTD_parameters params); /*! ZSTD_compress_usingCDict_advanced() : - * Note : this function is now REDUNDANT. + * Note : this function is now DEPRECATED. * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. - * This prototype will be marked as deprecated and generate compilation warning in some future version */ -ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + * This prototype will generate compilation warnings. */ +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary") +size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTD_CDict* cdict, @@ -1441,18 +1725,18 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, /*! ZSTD_CCtx_loadDictionary_byReference() : * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); /*! ZSTD_CCtx_loadDictionary_advanced() : * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over * how to load the dictionary (by copy ? by reference ?) * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); /*! ZSTD_CCtx_refPrefix_advanced() : * Same as ZSTD_CCtx_refPrefix(), but gives finer control over * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); /* === experimental parameters === */ /* these parameters can be used with ZSTD_setParameter() @@ -1491,9 +1775,15 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre * See the comments on that enum for an explanation of the feature. */ #define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 -/* Controls how the literals are compressed (default is auto). - * The value must be of type ZSTD_literalCompressionMode_e. - * See ZSTD_literalCompressionMode_t enum definition for details. +/* Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never compress literals. + * Set to ZSTD_ps_enable to always compress literals. (Note: uncompressed literals + * may still be emitted if huffman is not beneficial to use.) + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * literals compression based on the compression parameters - specifically, + * negative compression levels do not use literal compression. */ #define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 @@ -1508,12 +1798,215 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre * but compression ratio may regress significantly if guess considerably underestimates */ #define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 +/* Controls whether the new and experimental "dedicated dictionary search + * structure" can be used. This feature is still rough around the edges, be + * prepared for surprising behavior! + * + * How to use it: + * + * When using a CDict, whether to use this feature or not is controlled at + * CDict creation, and it must be set in a CCtxParams set passed into that + * construction (via ZSTD_createCDict_advanced2()). A compression will then + * use the feature or not based on how the CDict was constructed; the value of + * this param, set in the CCtx, will have no effect. + * + * However, when a dictionary buffer is passed into a CCtx, such as via + * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control + * whether the CDict that is created internally can use the feature or not. + * + * What it does: + * + * Normally, the internal data structures of the CDict are analogous to what + * would be stored in a CCtx after compressing the contents of a dictionary. + * To an approximation, a compression using a dictionary can then use those + * data structures to simply continue what is effectively a streaming + * compression where the simulated compression of the dictionary left off. + * Which is to say, the search structures in the CDict are normally the same + * format as in the CCtx. + * + * It is possible to do better, since the CDict is not like a CCtx: the search + * structures are written once during CDict creation, and then are only read + * after that, while the search structures in the CCtx are both read and + * written as the compression goes along. This means we can choose a search + * structure for the dictionary that is read-optimized. + * + * This feature enables the use of that different structure. + * + * Note that some of the members of the ZSTD_compressionParameters struct have + * different semantics and constraints in the dedicated search structure. It is + * highly recommended that you simply set a compression level in the CCtxParams + * you pass into the CDict creation call, and avoid messing with the cParams + * directly. + * + * Effects: + * + * This will only have any effect when the selected ZSTD_strategy + * implementation supports this feature. Currently, that's limited to + * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2. + * + * Note that this means that the CDict tables can no longer be copied into the + * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be + * usable. The dictionary can only be attached or reloaded. + * + * In general, you should expect compression to be faster--sometimes very much + * so--and CDict creation to be slightly slower. Eventually, we will probably + * make this mode the default. + */ +#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8 + +/* ZSTD_c_stableInBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the compressor that input data presented with ZSTD_inBuffer + * will ALWAYS be the same between calls. + * Technically, the @src pointer must never be changed, + * and the @pos field can only be updated by zstd. + * However, it's possible to increase the @size field, + * allowing scenarios where more data can be appended after compressions starts. + * These conditions are checked by the compressor, + * and compression will fail if they are not respected. + * Also, data in the ZSTD_inBuffer within the range [src, src + pos) + * MUST not be modified during compression or it will result in data corruption. + * + * When this flag is enabled zstd won't allocate an input window buffer, + * because the user guarantees it can reference the ZSTD_inBuffer until + * the frame is complete. But, it will still allocate an output buffer + * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also + * avoid the memcpy() from the input buffer to the input window buffer. + * + * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, compression WILL fail if conditions are not respected. + * + * WARNING: The data in the ZSTD_inBuffer in the range [src, src + pos) MUST + * not be modified during compression or it will result in data corruption. + * This is because zstd needs to reference data in the ZSTD_inBuffer to find + * matches. Normally zstd maintains its own window buffer for this purpose, + * but passing this flag tells zstd to rely on user provided buffer instead. + */ +#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9 + +/* ZSTD_c_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells he compressor that the ZSTD_outBuffer will not be resized between + * calls. Specifically: (out.size - out.pos) will never grow. This gives the + * compressor the freedom to say: If the compressed data doesn't fit in the + * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to + * always decompress directly into the output buffer, instead of decompressing + * into an internal buffer and copying to the output buffer. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer. It will still allocate the + * input window buffer (see ZSTD_c_stableInBuffer). + * + * Zstd will check that (out.size - out.pos) never grows and return an error + * if it does. While not strictly necessary, this should prevent surprises. + */ +#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10 + +/* ZSTD_c_blockDelimiters + * Default is 0 == ZSTD_sf_noBlockDelimiters. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * + * Designates whether or not the given array of ZSTD_Sequence contains block delimiters + * and last literals, which are defined as sequences with offset == 0 and matchLength == 0. + * See the definition of ZSTD_Sequence for more specifics. + */ +#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11 + +/* ZSTD_c_validateSequences + * Default is 0 == disabled. Set to 1 to enable sequence validation. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * Designates whether or not we validate sequences provided to ZSTD_compressSequences() + * during function execution. + * + * Without validation, providing a sequence that does not conform to the zstd spec will cause + * undefined behavior, and may produce a corrupted block. + * + * With validation enabled, if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and + * return an error. + * + */ +#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12 + +/* ZSTD_c_useBlockSplitter + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use block splitter. + * Set to ZSTD_ps_enable to always use block splitter. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * block splitting based on the compression parameters. + */ +#define ZSTD_c_useBlockSplitter ZSTD_c_experimentalParam13 + +/* ZSTD_c_useRowMatchFinder + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use row-based matchfinder. + * Set to ZSTD_ps_enable to force usage of row-based matchfinder. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * the row-based matchfinder based on support for SIMD instructions and the window log. + * Note that this only pertains to compression strategies: greedy, lazy, and lazy2 + */ +#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14 + +/* ZSTD_c_deterministicRefPrefix + * Default is 0 == disabled. Set to 1 to enable. + * + * Zstd produces different results for prefix compression when the prefix is + * directly adjacent to the data about to be compressed vs. when it isn't. + * This is because zstd detects that the two buffers are contiguous and it can + * use a more efficient match finding algorithm. However, this produces different + * results than when the two buffers are non-contiguous. This flag forces zstd + * to always load the prefix in non-contiguous mode, even if it happens to be + * adjacent to the data, to guarantee determinism. + * + * If you really care about determinism when using a dictionary or prefix, + * like when doing delta compression, you should select this option. It comes + * at a speed penalty of about ~2.5% if the dictionary and data happened to be + * contiguous, and is free if they weren't contiguous. We don't expect that + * intentionally making the dictionary and data contiguous will be worth the + * cost to memcpy() the data. + */ +#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15 + +/* ZSTD_c_prefetchCDictTables + * Controlled with ZSTD_paramSwitch_e enum. Default is ZSTD_ps_auto. + * + * In some situations, zstd uses CDict tables in-place rather than copying them + * into the working context. (See docs on ZSTD_dictAttachPref_e above for details). + * In such situations, compression speed is seriously impacted when CDict tables are + * "cold" (outside CPU cache). This parameter instructs zstd to prefetch CDict tables + * when they are used in-place. + * + * For sufficiently small inputs, the cost of the prefetch will outweigh the benefit. + * For sufficiently large inputs, zstd will by default memcpy() CDict tables + * into the working context, so there is no need to prefetch. This parameter is + * targeted at a middle range of input sizes, where a prefetch is cheap enough to be + * useful but memcpy() is too expensive. The exact range of input sizes where this + * makes sense is best determined by careful experimentation. + * + * Note: for this parameter, ZSTD_ps_auto is currently equivalent to ZSTD_ps_disable, + * but in the future zstd may conditionally enable this feature via an auto-detection + * heuristic for cold CDicts. + * Use ZSTD_ps_disable to opt out of prefetching under any circumstances. + */ +#define ZSTD_c_prefetchCDictTables ZSTD_c_experimentalParam16 + /*! ZSTD_CCtx_getParameter() : * Get the requested compression parameter value, selected by enum ZSTD_cParameter, * and store it into int* value. * @return : 0, or an error code (which can be tested with ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); /*! ZSTD_CCtx_params : @@ -1528,45 +2021,47 @@ ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param * These parameters will be applied to * all subsequent frames. * - ZSTD_compressStream2() : Do compression using the CCtx. - * - ZSTD_freeCCtxParams() : Free the memory. + * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer. * * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() * for static allocation of CCtx for single-threaded compression. */ -ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); -ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_STATIC_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */ /*! ZSTD_CCtxParams_reset() : * Reset params to default values. */ -ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); /*! ZSTD_CCtxParams_init() : * Initializes the compression parameters of cctxParams according to * compression level. All other parameters are reset to their default values. */ -ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); /*! ZSTD_CCtxParams_init_advanced() : * Initializes the compression and frame parameters of cctxParams according to * params. All other parameters are reset to their default values. */ -ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); -/*! ZSTD_CCtxParams_setParameter() : +/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+ * Similar to ZSTD_CCtx_setParameter. * Set one compression parameter, selected by enum ZSTD_cParameter. - * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). - * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Parameters must be applied to a ZSTD_CCtx using + * ZSTD_CCtx_setParametersUsingCCtxParams(). + * @result : a code representing success or failure (which can be tested with + * ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); /*! ZSTD_CCtxParams_getParameter() : * Similar to ZSTD_CCtx_getParameter. * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); /*! ZSTD_CCtx_setParametersUsingCCtxParams() : * Apply a set of ZSTD_CCtx_params to the compression context. @@ -1575,7 +2070,7 @@ ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_c * if nbWorkers>=1, new parameters will be picked up at next job, * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). */ -ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); /*! ZSTD_compressStream2_simpleArgs() : @@ -1584,7 +2079,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( * This variant might be helpful for binders from dynamic languages * which have troubles handling structures containing memory pointers. */ -ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs ( +ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos, @@ -1600,33 +2095,33 @@ ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs ( * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. * Note 3 : Skippable Frame Identifiers are considered valid. */ -ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size); +ZSTDLIB_STATIC_API unsigned ZSTD_isFrame(const void* buffer, size_t size); /*! ZSTD_createDDict_byReference() : * Create a digested dictionary, ready to start decompression operation without startup delay. * Dictionary content is referenced, and therefore stays in dictBuffer. * It is important that dictBuffer outlives DDict, * it must remain read accessible throughout the lifetime of DDict */ -ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); /*! ZSTD_DCtx_loadDictionary_byReference() : * Same as ZSTD_DCtx_loadDictionary(), * but references `dict` content instead of copying it into `dctx`. * This saves memory if `dict` remains around., * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ -ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); /*! ZSTD_DCtx_loadDictionary_advanced() : * Same as ZSTD_DCtx_loadDictionary(), * but gives direct control over * how to load the dictionary (by copy ? by reference ?) * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ -ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); /*! ZSTD_DCtx_refPrefix_advanced() : * Same as ZSTD_DCtx_refPrefix(), but gives finer control over * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); /*! ZSTD_DCtx_setMaxWindowSize() : * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. @@ -1635,20 +2130,96 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* pre * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); + +/*! ZSTD_DCtx_getParameter() : + * Get the requested decompression parameter value, selected by enum ZSTD_dParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value); /* ZSTD_d_format * experimental parameter, * allowing selection between ZSTD_format_e input compression formats */ #define ZSTD_d_format ZSTD_d_experimentalParam1 +/* ZSTD_d_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the decompressor, and + * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer + * MUST be large enough to fit the entire decompressed frame. This will be + * checked when the frame content size is known. The data in the ZSTD_outBuffer + * in the range [dst, dst + pos) MUST not be modified during decompression + * or you will get data corruption. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer, but it will still allocate + * an input buffer large enough to fit any compressed block. This will also + * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. + * If you need to avoid the input buffer allocation use the buffer-less + * streaming API. + * + * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, decompression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST + * not be modified during decompression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate + * matches. Normally zstd maintains its own buffer for this purpose, but passing + * this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 + +/* ZSTD_d_forceIgnoreChecksum + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * Tells the decompressor to skip checksum validation during decompression, regardless + * of whether checksumming was specified during compression. This offers some + * slight performance benefits, and may be useful for debugging. + * Param has values of type ZSTD_forceIgnoreChecksum_e + */ +#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 + +/* ZSTD_d_refMultipleDDicts + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * If enabled and dctx is allocated on the heap, then additional memory will be allocated + * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict() + * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead + * store all references. At decompression time, the appropriate dictID is selected + * from the set of DDicts based on the dictID in the frame. + * + * Usage is simply calling ZSTD_refDDict() on multiple dict buffers. + * + * Param has values of byte ZSTD_refMultipleDDicts_e + * + * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory + * allocation for the hash table. ZSTD_freeDCtx() also frees this memory. + * Memory is allocated as per ZSTD_DCtx::customMem. + * + * Although this function allocates memory for the table, the user is still responsible for + * memory management of the underlying ZSTD_DDict* themselves. + */ +#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4 + /*! ZSTD_DCtx_setFormat() : + * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter(). * Instruct the decoder context about what kind of data to decode next. * This instruction is mandatory to decode data without a fully-formed header, * such ZSTD_f_zstd1_magicless for example. * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead") +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); /*! ZSTD_decompressStream_simpleArgs() : * Same as ZSTD_decompressStream(), @@ -1656,7 +2227,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); * This can be helpful for binders from dynamic languages * which have troubles handling structures containing memory pointers. */ -ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs ( +ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos); @@ -1670,8 +2241,9 @@ ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs ( ********************************************************************/ /*===== Advanced Streaming compression functions =====*/ -/**! ZSTD_initCStream_srcSize() : - * This function is deprecated, and equivalent to: + +/*! ZSTD_initCStream_srcSize() : + * This function is DEPRECATED, and equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); @@ -1680,15 +2252,16 @@ ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs ( * pledgedSrcSize must be correct. If it is not known at init time, use * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, * "0" also disables frame content size field. It may be enabled in the future. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + * This prototype will generate compilation warnings. */ -ZSTDLIB_API size_t -ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); -/**! ZSTD_initCStream_usingDict() : - * This function is deprecated, and is equivalent to: +/*! ZSTD_initCStream_usingDict() : + * This function is DEPRECATED, and is equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); @@ -1697,15 +2270,16 @@ ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, * dict == NULL or dictSize < 8, in which case no dict is used. * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + * This prototype will generate compilation warnings. */ -ZSTDLIB_API size_t -ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); -/**! ZSTD_initCStream_advanced() : - * This function is deprecated, and is approximately equivalent to: +/*! ZSTD_initCStream_advanced() : + * This function is DEPRECATED, and is approximately equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * // Pseudocode: Set each zstd parameter and leave the rest as-is. * for ((param, value) : params) { @@ -1717,25 +2291,28 @@ ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. * pledgedSrcSize must be correct. * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + * This prototype will generate compilation warnings. */ -ZSTDLIB_API size_t -ZSTD_initCStream_advanced(ZSTD_CStream* zcs, +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); -/**! ZSTD_initCStream_usingCDict() : - * This function is deprecated, and equivalent to: +/*! ZSTD_initCStream_usingCDict() : + * This function is DEPRECATED, and equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_refCDict(zcs, cdict); * * note : cdict will just be referenced, and must outlive compression session - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + * This prototype will generate compilation warnings. */ -ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); -/**! ZSTD_initCStream_usingCDict_advanced() : +/*! ZSTD_initCStream_usingCDict_advanced() : * This function is DEPRECATED, and is approximately equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * // Pseudocode: Set each zstd frame parameter and leave the rest as-is. @@ -1748,18 +2325,22 @@ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDi * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. * pledgedSrcSize must be correct. If srcSize is not known at init time, use * value ZSTD_CONTENTSIZE_UNKNOWN. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + * This prototype will generate compilation warnings. */ -ZSTDLIB_API size_t -ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /*! ZSTD_resetCStream() : - * This function is deprecated, and is equivalent to: + * This function is DEPRECATED, and is equivalent to: * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but + * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be + * explicitly specified. * * start a new frame, using same parameters from previous frame. * This is typically useful to skip dictionary loading stage, since it will re-use it in-place. @@ -1769,9 +2350,11 @@ ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. * @return : 0, or an error code (which can be tested using ZSTD_isError()) - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + * This prototype will generate compilation warnings. */ -ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); typedef struct { @@ -1789,7 +2372,7 @@ typedef struct { * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. * Aggregates progression inside active worker threads. */ -ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); +ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); /*! ZSTD_toFlushNow() : * Tell how many bytes are ready to be flushed immediately. @@ -1804,11 +2387,12 @@ ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx * therefore flush speed is limited by production speed of oldest job * irrespective of the speed of concurrent (and newer) jobs. */ -ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); +ZSTDLIB_STATIC_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); /*===== Advanced Streaming decompression functions =====*/ -/** + +/*! * This function is deprecated, and is equivalent to: * * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); @@ -1817,9 +2401,9 @@ ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); * note: no dictionary will be used if dict == NULL or dictSize < 8 * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); -/** +/*! * This function is deprecated, and is equivalent to: * * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); @@ -1828,9 +2412,9 @@ ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dic * note : ddict is referenced, it must outlive decompression session * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); -/** +/*! * This function is deprecated, and is equivalent to: * * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); @@ -1838,7 +2422,7 @@ ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDi * re-use decompression parameters from previous init; saves dictionary loading * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x */ -ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); +ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /********************************************************************* @@ -1857,9 +2441,7 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); ZSTD_CCtx object can be re-used multiple times within successive compression operations. Start by initializing a context. - Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression, - or ZSTD_compressBegin_advanced(), for finer parameter control. - It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx() + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression. Then, consume your input using ZSTD_compressContinue(). There are some important considerations to keep in mind when using this advanced function : @@ -1881,18 +2463,23 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); */ /*===== Buffer-less streaming compression functions =====*/ -ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); -ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); -ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ -ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ - -ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - - -/*- +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ +ZSTD_DEPRECATED("This function will likely be removed in the next minor release. It is misleading and has very limited utility.") +ZSTDLIB_STATIC_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_STATIC_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */ +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use advanced API to access custom parameters") +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTDLIB_STATIC_API +ZSTD_DEPRECATED("use advanced API to access custom parameters") +size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ +/** Buffer-less streaming decompression (synchronous mode) A ZSTD_DCtx object is required to track streaming operations. @@ -1982,24 +2569,25 @@ typedef struct { * @return : 0, `zfhPtr` is correctly filled, * >0, `srcSize` is too small, value is wanted `srcSize` amount, * or an error code, which can be tested using ZSTD_isError() */ -ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ /*! ZSTD_getFrameHeader_advanced() : * same as ZSTD_getFrameHeader(), * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ -ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); -ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); +ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); -ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); -ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); /* misc */ -ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); +ZSTD_DEPRECATED("This function will likely be removed in the next minor release. It is misleading and has very limited utility.") +ZSTDLIB_STATIC_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; -ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); @@ -2019,7 +2607,6 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); - It is necessary to init context before starting + compression : any ZSTD_compressBegin*() variant, including with dictionary + decompression : any ZSTD_decompressBegin*() variant, including with dictionary - + copyCCtx() and copyDCtx() can be used too - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + If input is larger than a block size, it's necessary to split input data into multiple blocks + For inputs larger than a single block, consider using regular ZSTD_compress() instead. @@ -2036,10 +2623,10 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); */ /*===== Raw zstd block functions =====*/ -ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); -ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ +ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); +ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ #endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ diff --git a/native/zstd/zstd_errors.h b/native/zstd/zstd_errors.h new file mode 100644 index 0000000..2ec0b0a --- /dev/null +++ b/native/zstd/zstd_errors.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * 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. + */ + +#ifndef ZSTD_ERRORS_H_398273423 +#define ZSTD_ERRORS_H_398273423 + +#if defined (__cplusplus) +extern "C" { +#endif + +/*===== dependency =====*/ +#include /* size_t */ + + +/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ +#ifndef ZSTDERRORLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define ZSTDERRORLIB_VISIBILITY +# endif +#endif +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY +#endif + +/*-********************************************* + * Error codes list + *-********************************************* + * Error codes _values_ are pinned down since v1.3.1 only. + * Therefore, don't rely on values if you may link to any version < v1.3.1. + * + * Only values < 100 are considered stable. + * + * note 1 : this API shall be used with static linking only. + * dynamic linking is not yet officially supported. + * note 2 : Prefer relying on the enum than on its value whenever possible + * This is the only supported way to use the error list < v1.3.1 + * note 3 : ZSTD_isError() is always correct, whatever the library version. + **********************************************/ +typedef enum { + ZSTD_error_no_error = 0, + ZSTD_error_GENERIC = 1, + ZSTD_error_prefix_unknown = 10, + ZSTD_error_version_unsupported = 12, + ZSTD_error_frameParameter_unsupported = 14, + ZSTD_error_frameParameter_windowTooLarge = 16, + ZSTD_error_corruption_detected = 20, + ZSTD_error_checksum_wrong = 22, + ZSTD_error_dictionary_corrupted = 30, + ZSTD_error_dictionary_wrong = 32, + ZSTD_error_dictionaryCreation_failed = 34, + ZSTD_error_parameter_unsupported = 40, + ZSTD_error_parameter_outOfBound = 42, + ZSTD_error_tableLog_tooLarge = 44, + ZSTD_error_maxSymbolValue_tooLarge = 46, + ZSTD_error_maxSymbolValue_tooSmall = 48, + ZSTD_error_stabilityCondition_notRespected = 50, + ZSTD_error_stage_wrong = 60, + ZSTD_error_init_missing = 62, + ZSTD_error_memory_allocation = 64, + ZSTD_error_workSpace_tooSmall= 66, + ZSTD_error_dstSize_tooSmall = 70, + ZSTD_error_srcSize_wrong = 72, + ZSTD_error_dstBuffer_null = 74, + /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ + ZSTD_error_frameIndex_tooLarge = 100, + ZSTD_error_seekableIO = 102, + ZSTD_error_dstBuffer_wrong = 104, + ZSTD_error_srcBuffer_wrong = 105, + ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ +} ZSTD_ErrorCode; + +/*! ZSTD_getErrorCode() : + convert a `size_t` function result into a `ZSTD_ErrorCode` enum type, + which can be used to compare with enum list published above */ +ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult); +ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ + + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_ERRORS_H_398273423 */ From 874bce1ecef6cfeb8fb0bd3a6c176e5242230187 Mon Sep 17 00:00:00 2001 From: giuseppe Date: Fri, 2 Sep 2022 09:55:38 +0200 Subject: [PATCH 03/10] lz4 v1.9.4/zstd 1.5.2 and arm detection to macOS --- native/cmake/CMakeLists.txt | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/native/cmake/CMakeLists.txt b/native/cmake/CMakeLists.txt index 0990b24..13d7ec6 100644 --- a/native/cmake/CMakeLists.txt +++ b/native/cmake/CMakeLists.txt @@ -15,6 +15,20 @@ IF( ${SIZEOF_VOID_P} STREQUAL "8" ) MESSAGE( STATUS "64 bit architecture detected size of void * is " ${SIZEOF_VOID_P}) ENDIF() +if(APPLE) + execute_process(COMMAND sysctl -q hw.optional.arm64 + OUTPUT_VARIABLE _sysctl_stdout + ERROR_VARIABLE _sysctl_stderr + RESULT_VARIABLE _sysctl_result + ) + + if(_sysctl_result EQUAL 0 AND _sysctl_stdout MATCHES "hw.optional.arm64: 1" AND APPLE_x86_64) + SET(CMAKE_SYSTEM_PROCESSOR "x86_64") + SET(CMAKE_OSX_ARCHITECTURES "x86_64") + MESSAGE(STATUS "x86_64 bit architecture has been configured - arm64 detected") + endif() +ENDIF(APPLE) + option(BUILD_TOOLS "Build the command line tools" ON) option(BUILD_LIBS "Build the JNI native library for hadoop-4mc" ON) @@ -30,32 +44,39 @@ IF (MSVC) add_definitions("/wd4711") ENDIF() +if (MSVC OR APPLE) + add_compile_options(-DZSTD_DISABLE_ASM) +endif(MSVC OR APPLE) + set(LZ4_DIR ../lz4/) set(ZSTD_DIR ../zstd/) set(PRG_DIR ../) -set(LZ4_SRCS ${LZ4_DIR}xxhash.h ${LZ4_DIR}xxhash.c ${LZ4_DIR}lz4.c ${LZ4_DIR}lz4hc.c ${LZ4_DIR}lz4.h ${LZ4_DIR}lz4hc.h ${LZ4_DIR}lz4mc.c ${LZ4_DIR}lz4mc.h) -set(ZSTD_SRCS ${ZSTD_DIR}common/entropy_common.c +set(LZ4_SRCS ${LZ4_DIR}xxhash.h ${LZ4_DIR}xxhash.c ${LZ4_DIR}lz4.c ${LZ4_DIR}lz4hc.c ${LZ4_DIR}lz4.h ${LZ4_DIR}lz4hc.h ${LZ4_DIR}lz4mc.c ${LZ4_DIR}lz4mc.h ${LZ4_DIR}lz4frame.h ${LZ4_DIR}lz4frame.c ${LZ4_DIR}lz4file.h ${LZ4_DIR}lz4file.c) +set(ZSTD_SRCS ${ZSTD_DIR}common/entropy_common.c ${ZSTD_DIR}common/error_private.c ${ZSTD_DIR}common/fse_decompress.c ${ZSTD_DIR}common/pool.c ${ZSTD_DIR}common/zstd_common.c - #${ZSTD_DIR}common/xxhash.c + ${ZSTD_DIR}common/xxhash.c ${ZSTD_DIR}compress/fse_compress.c ${ZSTD_DIR}compress/hist.c ${ZSTD_DIR}compress/huf_compress.c ${ZSTD_DIR}compress/zstd_compress.c ${ZSTD_DIR}compress/zstd_compress_literals.c ${ZSTD_DIR}compress/zstd_compress_sequences.c + ${ZSTD_DIR}compress/zstd_compress_superblock.c ${ZSTD_DIR}compress/zstd_double_fast.c ${ZSTD_DIR}compress/zstd_fast.c ${ZSTD_DIR}compress/zstd_lazy.c ${ZSTD_DIR}compress/zstd_ldm.c ${ZSTD_DIR}compress/zstd_opt.c + ${ZSTD_DIR}compress/zstdmt_compress.c ${ZSTD_DIR}decompress/huf_decompress.c ${ZSTD_DIR}decompress/zstd_ddict.c ${ZSTD_DIR}decompress/zstd_decompress_block.c ${ZSTD_DIR}decompress/zstd_decompress.c + ${ZSTD_DIR}decompress/huf_decompress_amd64.S ${ZSTD_DIR}deprecated/zbuff_compress.c ${ZSTD_DIR}deprecated/zbuff_decompress.c ${ZSTD_DIR}dictBuilder/cover.c @@ -96,7 +117,7 @@ endif() #warnings ADD_DEFINITIONS("-Wall") -ADD_DEFINITIONS("-DLZ4_VERSION=\"1.9.2\"") +ADD_DEFINITIONS("-DLZ4_VERSION=\"1.9.4\"") INCLUDE_DIRECTORIES (${LZ4_DIR}) From 849ebad06d441f8048c94911ab74f23b7acc5e1a Mon Sep 17 00:00:00 2001 From: Scip88 Date: Fri, 2 Sep 2022 17:36:57 +0200 Subject: [PATCH 04/10] improve gitignore & fix maven dependency on example --- .gitignore | 5 +++++ java/examples/pom.xml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bd14613..84b3b24 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,8 @@ java/*/target # Ignore native binaries native/4mc native/libhadoop-4mc.so.* +/.idea/ +/java/examples/examples.iml +/java/.idea/ +/java/hadoop-4mc/hadoop-4mc.iml +/java/parent.iml diff --git a/java/examples/pom.xml b/java/examples/pom.xml index 361dc95..4891403 100644 --- a/java/examples/pom.xml +++ b/java/examples/pom.xml @@ -23,7 +23,7 @@ com.hadoop.fourmc hadoop-4mc - 2.0.0 + 2.2.0 From 7fa613c6a195badbe05aec88d3c4d4eab1d9b7e8 Mon Sep 17 00:00:00 2001 From: Scip88 Date: Fri, 2 Sep 2022 17:52:14 +0200 Subject: [PATCH 05/10] complete rename for java / jni classes --- Readme.md | 8 +++--- java/examples/pom.xml | 4 +-- .../adapter/FourMcEbProtoInputFormat.java | 4 +-- .../adapter/FourMcEbProtoOutputFormat.java | 4 +-- .../adapter/FourMzEbProtoInputFormat.java | 4 +-- .../adapter/FourMzEbProtoOutputFormat.java | 4 +-- .../protobuf/lz4/TestProtobufIO.java | 18 ++++++------- .../protobuf/zstd/TestProtobufIO.java | 18 ++++++------- .../mapreduce/text/lz4/TestTextInput.java | 12 ++++----- .../mapreduce/text/zstd/TestTextInput.java | 16 ++++++------ .../fourmc/protobuf/USER.java | 16 ++++++------ .../spark/protobuf/TestProtobufInput.java | 10 ++++---- java/examples/src/main/resources/user.proto | 4 +-- java/hadoop-4mc/pom.xml | 8 ++++-- .../compression/fourmc/FourMcBlockIndex.java | 2 +- .../compression/fourmc/FourMcCodec.java | 2 +- .../compression/fourmc/FourMcHighCodec.java | 2 +- .../fourmc/FourMcInputFormatUtil.java | 2 +- .../compression/fourmc/FourMcInputStream.java | 2 +- .../compression/fourmc/FourMcMediumCodec.java | 2 +- .../fourmc/FourMcNativeCodeLoader.java | 4 +-- .../fourmc/FourMcOutputStream.java | 2 +- .../compression/fourmc/FourMcUltraCodec.java | 2 +- .../compression/fourmc/FourMzBlockIndex.java | 2 +- .../compression/fourmc/FourMzCodec.java | 2 +- .../compression/fourmc/FourMzHighCodec.java | 2 +- .../compression/fourmc/FourMzInputStream.java | 2 +- .../compression/fourmc/FourMzMediumCodec.java | 2 +- .../fourmc/FourMzOutputStream.java | 2 +- .../compression/fourmc/FourMzUltraCodec.java | 2 +- .../compression/fourmc/Lz4Codec.java | 2 +- .../compression/fourmc/Lz4Compressor.java | 4 +-- .../compression/fourmc/Lz4Decompressor.java | 4 +-- .../compression/fourmc/Lz4HighCodec.java | 2 +- .../compression/fourmc/Lz4HighCompressor.java | 2 +- .../compression/fourmc/Lz4MediumCodec.java | 2 +- .../fourmc/Lz4MediumCompressor.java | 2 +- .../compression/fourmc/Lz4UltraCodec.java | 2 +- .../fourmc/Lz4UltraCompressor.java | 2 +- .../compression/fourmc/ZstCodec.java | 6 ++--- .../compression/fourmc/ZstdCodec.java | 2 +- .../compression/fourmc/ZstdCompressor.java | 4 +-- .../compression/fourmc/ZstdDecompressor.java | 4 +-- .../compression/fourmc/ZstdHighCodec.java | 2 +- .../fourmc/ZstdHighCompressor.java | 2 +- .../compression/fourmc/ZstdMediumCodec.java | 2 +- .../fourmc/ZstdMediumCompressor.java | 2 +- .../compression/fourmc/ZstdUltraCodec.java | 2 +- .../fourmc/ZstdUltraCompressor.java | 2 +- .../fourmc/util/DirectBufferPool.java | 2 +- .../compression/fourmc/util/HadoopUtils.java | 2 +- .../compression/fourmc/zstd/Zstd.java | 4 +-- .../fourmc/zstd/ZstdStreamCompressor.java | 2 +- .../fourmc/zstd/ZstdStreamDecompressor.java | 2 +- .../mapreduce/FourMcInputFormat.java | 10 ++++---- .../mapreduce/FourMcLineRecordReader.java | 4 +-- .../mapreduce/FourMcTextInputFormat.java | 2 +- .../mapreduce/FourMzInputFormat.java | 8 +++--- .../mapreduce/FourMzLineRecordReader.java | 4 +-- .../mapreduce/FourMzTextInputFormat.java | 2 +- ...apache.hadoop.io.compress.CompressionCodec | 24 +++++++++--------- .../fourmc/darwin/x86_64/libhadoop-4mc.dylib | Bin .../fourmc/linux/amd64/libhadoop-4mc.so | Bin .../fourmc/linux/i386/libhadoop-4mc.so | Bin .../fourmc/win32/amd64/libhadoop-4mc.dll | Bin .../fourmc/win32/i386/libhadoop-4mc.dll | Bin .../fourmc/TestFourMcBlockIndex.java | 2 +- .../compression/fourmc/TestFourMcCodec.java | 4 +-- java/pom.xml | 2 +- native/jniCompressor.c | 24 +++++++++--------- native/jniDecompressor.c | 10 ++++---- native/jniZStreamCompressor.c | 12 ++++----- native/jniZStreamDecompressor.c | 10 ++++---- native/jniZstd.c | 12 ++++----- native/jniZstdCompressor.c | 12 ++++----- native/jniZstdDecompressor.c | 6 ++--- 76 files changed, 189 insertions(+), 185 deletions(-) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/elephantbird/adapter/FourMcEbProtoInputFormat.java (96%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/elephantbird/adapter/FourMcEbProtoOutputFormat.java (97%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/elephantbird/adapter/FourMzEbProtoInputFormat.java (96%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/elephantbird/adapter/FourMzEbProtoOutputFormat.java (97%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/mapreduce/protobuf/lz4/TestProtobufIO.java (88%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/mapreduce/protobuf/zstd/TestProtobufIO.java (88%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/mapreduce/text/lz4/TestTextInput.java (91%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/mapreduce/text/zstd/TestTextInput.java (86%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/protobuf/USER.java (98%) rename java/examples/src/main/java/com/{hadoop => fing}/fourmc/spark/protobuf/TestProtobufInput.java (94%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcBlockIndex.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcCodec.java (97%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcHighCodec.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcInputFormatUtil.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcInputStream.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcMediumCodec.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcNativeCodeLoader.java (95%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcOutputStream.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMcUltraCodec.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMzBlockIndex.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMzCodec.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMzHighCodec.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMzInputStream.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMzMediumCodec.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMzOutputStream.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/FourMzUltraCodec.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4Codec.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4Compressor.java (95%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4Decompressor.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4HighCodec.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4HighCompressor.java (95%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4MediumCodec.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4MediumCompressor.java (95%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4UltraCodec.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/Lz4UltraCompressor.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstCodec.java (97%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdCodec.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdCompressor.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdDecompressor.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdHighCodec.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdHighCompressor.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdMediumCodec.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdMediumCompressor.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdUltraCodec.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/ZstdUltraCompressor.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/util/DirectBufferPool.java (95%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/util/HadoopUtils.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/zstd/Zstd.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/zstd/ZstdStreamCompressor.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/compression/fourmc/zstd/ZstdStreamDecompressor.java (99%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/mapreduce/FourMcInputFormat.java (93%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/mapreduce/FourMcLineRecordReader.java (95%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/mapreduce/FourMcTextInputFormat.java (96%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/mapreduce/FourMzInputFormat.java (97%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/mapreduce/FourMzLineRecordReader.java (98%) rename java/hadoop-4mc/src/main/java/com/{hadoop => fing}/mapreduce/FourMzTextInputFormat.java (98%) rename java/hadoop-4mc/src/main/resources/com/{hadoop => fing}/compression/fourmc/darwin/x86_64/libhadoop-4mc.dylib (100%) rename java/hadoop-4mc/src/main/resources/com/{hadoop => fing}/compression/fourmc/linux/amd64/libhadoop-4mc.so (100%) rename java/hadoop-4mc/src/main/resources/com/{hadoop => fing}/compression/fourmc/linux/i386/libhadoop-4mc.so (100%) rename java/hadoop-4mc/src/main/resources/com/{hadoop => fing}/compression/fourmc/win32/amd64/libhadoop-4mc.dll (100%) rename java/hadoop-4mc/src/main/resources/com/{hadoop => fing}/compression/fourmc/win32/i386/libhadoop-4mc.dll (100%) rename java/hadoop-4mc/src/test/java/com/{hadoop => fing}/compression/fourmc/TestFourMcBlockIndex.java (95%) rename java/hadoop-4mc/src/test/java/com/{hadoop => fing}/compression/fourmc/TestFourMcCodec.java (97%) diff --git a/Readme.md b/Readme.md index 0f6c475..ff16114 100644 --- a/Readme.md +++ b/Readme.md @@ -80,10 +80,10 @@ Enabling codecs has no difference from usual, i.e. by adding them to configurati org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.BZip2Codec, com.hadoop.compression.lzo.LzoCodec,com.hadoop.compression.lzo.LzopCodec, - com.hadoop.compression.fourmc.Lz4Codec,com.hadoop.compression.fourmc.Lz4MediumCodec,com.hadoop.compression.fourmc.Lz4HighCodec,com.hadoop.compression.fourmc.Lz4UltraCodec, - com.hadoop.compression.fourmc.FourMcCodec,com.hadoop.compression.fourmc.FourMcMediumCodec,com.hadoop.compression.fourmc.FourMcHighCodec,com.hadoop.compression.fourmc.FourMcUltraCodec, + com.fing.compression.fourmc.Lz4Codec,com.fing.compression.fourmc.Lz4MediumCodec,com.fing.compression.fourmc.Lz4HighCodec,com.fing.compression.fourmc.Lz4UltraCodec, + com.fing.compression.fourmc.FourMcCodec,com.fing.compression.fourmc.FourMcMediumCodec,com.fing.compression.fourmc.FourMcHighCodec,com.fing.compression.fourmc.FourMcUltraCodec, - com.hadoop.compression.fourmc.FourMzCodec,com.hadoop.compression.fourmc.FourMzMediumCodec,com.hadoop.compression.fourmc.FourMzHighCodec,com.hadoop.compression.fourmc.FourMzUltraCodec + com.fing.compression.fourmc.FourMzCodec,com.fing.compression.fourmc.FourMzMediumCodec,com.fing.compression.fourmc.FourMzHighCodec,com.fing.compression.fourmc.FourMzUltraCodec ``` @@ -116,7 +116,7 @@ filepath = 'gs://data/foo.4mc' # This will read the file and partition it as it loads data = sc.newAPIHadoopFile( filepath -, 'com.hadoop.mapreduce.FourMcTextInputFormat' +, 'com.fing.mapreduce.FourMcTextInputFormat' , 'org.apache.hadoop.io.LongWritable' , 'org.apache.hadoop.io.Text' ) diff --git a/java/examples/pom.xml b/java/examples/pom.xml index 4891403..d9a42ba 100644 --- a/java/examples/pom.xml +++ b/java/examples/pom.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - com.hadoop.fourmc + com.fing.fourmc parent 1.0 @@ -21,7 +21,7 @@ - com.hadoop.fourmc + com.fing.fourmc hadoop-4mc 2.2.0 diff --git a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMcEbProtoInputFormat.java b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMcEbProtoInputFormat.java similarity index 96% rename from java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMcEbProtoInputFormat.java rename to java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMcEbProtoInputFormat.java index 6287ecc..5429757 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMcEbProtoInputFormat.java +++ b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMcEbProtoInputFormat.java @@ -1,7 +1,7 @@ -package com.hadoop.fourmc.elephantbird.adapter; +package com.fing.fourmc.elephantbird.adapter; import com.google.protobuf.Message; -import com.hadoop.mapreduce.FourMcInputFormat; +import com.fing.mapreduce.FourMcInputFormat; import com.twitter.elephantbird.mapreduce.input.LzoProtobufBlockRecordReader; import com.twitter.elephantbird.mapreduce.io.BinaryWritable; import com.twitter.elephantbird.util.HadoopCompat; diff --git a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMcEbProtoOutputFormat.java b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMcEbProtoOutputFormat.java similarity index 97% rename from java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMcEbProtoOutputFormat.java rename to java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMcEbProtoOutputFormat.java index c61db3f..9336193 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMcEbProtoOutputFormat.java +++ b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMcEbProtoOutputFormat.java @@ -1,7 +1,7 @@ -package com.hadoop.fourmc.elephantbird.adapter; +package com.fing.fourmc.elephantbird.adapter; import com.google.protobuf.Message; -import com.hadoop.compression.fourmc.Lz4Codec; +import com.fing.compression.fourmc.Lz4Codec; import com.twitter.elephantbird.mapreduce.io.ProtobufBlockWriter; import com.twitter.elephantbird.mapreduce.io.ProtobufWritable; import com.twitter.elephantbird.mapreduce.output.LzoBinaryBlockRecordWriter; diff --git a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMzEbProtoInputFormat.java b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMzEbProtoInputFormat.java similarity index 96% rename from java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMzEbProtoInputFormat.java rename to java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMzEbProtoInputFormat.java index beb0654..6134382 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMzEbProtoInputFormat.java +++ b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMzEbProtoInputFormat.java @@ -1,7 +1,7 @@ -package com.hadoop.fourmc.elephantbird.adapter; +package com.fing.fourmc.elephantbird.adapter; import com.google.protobuf.Message; -import com.hadoop.mapreduce.FourMzInputFormat; +import com.fing.mapreduce.FourMzInputFormat; import com.twitter.elephantbird.mapreduce.input.LzoProtobufBlockRecordReader; import com.twitter.elephantbird.mapreduce.io.BinaryWritable; import com.twitter.elephantbird.util.HadoopUtils; diff --git a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMzEbProtoOutputFormat.java b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMzEbProtoOutputFormat.java similarity index 97% rename from java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMzEbProtoOutputFormat.java rename to java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMzEbProtoOutputFormat.java index 06675e4..bd6ee9b 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/elephantbird/adapter/FourMzEbProtoOutputFormat.java +++ b/java/examples/src/main/java/com/fing/fourmc/elephantbird/adapter/FourMzEbProtoOutputFormat.java @@ -1,7 +1,7 @@ -package com.hadoop.fourmc.elephantbird.adapter; +package com.fing.fourmc.elephantbird.adapter; import com.google.protobuf.Message; -import com.hadoop.compression.fourmc.ZstdCodec; +import com.fing.compression.fourmc.ZstdCodec; import com.twitter.elephantbird.mapreduce.io.ProtobufBlockWriter; import com.twitter.elephantbird.mapreduce.io.ProtobufWritable; import com.twitter.elephantbird.mapreduce.output.LzoBinaryBlockRecordWriter; diff --git a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/protobuf/lz4/TestProtobufIO.java b/java/examples/src/main/java/com/fing/fourmc/mapreduce/protobuf/lz4/TestProtobufIO.java similarity index 88% rename from java/examples/src/main/java/com/hadoop/fourmc/mapreduce/protobuf/lz4/TestProtobufIO.java rename to java/examples/src/main/java/com/fing/fourmc/mapreduce/protobuf/lz4/TestProtobufIO.java index a42124c..aa9231e 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/protobuf/lz4/TestProtobufIO.java +++ b/java/examples/src/main/java/com/fing/fourmc/mapreduce/protobuf/lz4/TestProtobufIO.java @@ -1,12 +1,12 @@ -package com.hadoop.fourmc.mapreduce.protobuf.lz4; - -import com.hadoop.compression.fourmc.FourMcCodec; -import com.hadoop.compression.fourmc.FourMcHighCodec; -import com.hadoop.compression.fourmc.FourMcMediumCodec; -import com.hadoop.compression.fourmc.FourMcUltraCodec; -import com.hadoop.fourmc.elephantbird.adapter.FourMcEbProtoInputFormat; -import com.hadoop.fourmc.elephantbird.adapter.FourMcEbProtoOutputFormat; -import com.hadoop.fourmc.protobuf.USER; +package com.fing.fourmc.mapreduce.protobuf.lz4; + +import com.fing.compression.fourmc.FourMcCodec; +import com.fing.compression.fourmc.FourMcHighCodec; +import com.fing.compression.fourmc.FourMcMediumCodec; +import com.fing.compression.fourmc.FourMcUltraCodec; +import com.fing.fourmc.elephantbird.adapter.FourMcEbProtoInputFormat; +import com.fing.fourmc.elephantbird.adapter.FourMcEbProtoOutputFormat; +import com.fing.fourmc.protobuf.USER; import com.twitter.elephantbird.mapreduce.io.ProtobufWritable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; diff --git a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/protobuf/zstd/TestProtobufIO.java b/java/examples/src/main/java/com/fing/fourmc/mapreduce/protobuf/zstd/TestProtobufIO.java similarity index 88% rename from java/examples/src/main/java/com/hadoop/fourmc/mapreduce/protobuf/zstd/TestProtobufIO.java rename to java/examples/src/main/java/com/fing/fourmc/mapreduce/protobuf/zstd/TestProtobufIO.java index a23e646..09fbd84 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/protobuf/zstd/TestProtobufIO.java +++ b/java/examples/src/main/java/com/fing/fourmc/mapreduce/protobuf/zstd/TestProtobufIO.java @@ -1,12 +1,12 @@ -package com.hadoop.fourmc.mapreduce.protobuf.zstd; - -import com.hadoop.compression.fourmc.FourMzCodec; -import com.hadoop.compression.fourmc.FourMzHighCodec; -import com.hadoop.compression.fourmc.FourMzMediumCodec; -import com.hadoop.compression.fourmc.FourMzUltraCodec; -import com.hadoop.fourmc.elephantbird.adapter.FourMzEbProtoInputFormat; -import com.hadoop.fourmc.elephantbird.adapter.FourMzEbProtoOutputFormat; -import com.hadoop.fourmc.protobuf.USER; +package com.fing.fourmc.mapreduce.protobuf.zstd; + +import com.fing.compression.fourmc.FourMzCodec; +import com.fing.compression.fourmc.FourMzHighCodec; +import com.fing.compression.fourmc.FourMzMediumCodec; +import com.fing.compression.fourmc.FourMzUltraCodec; +import com.fing.fourmc.elephantbird.adapter.FourMzEbProtoInputFormat; +import com.fing.fourmc.elephantbird.adapter.FourMzEbProtoOutputFormat; +import com.fing.fourmc.protobuf.USER; import com.twitter.elephantbird.mapreduce.io.ProtobufWritable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; diff --git a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/text/lz4/TestTextInput.java b/java/examples/src/main/java/com/fing/fourmc/mapreduce/text/lz4/TestTextInput.java similarity index 91% rename from java/examples/src/main/java/com/hadoop/fourmc/mapreduce/text/lz4/TestTextInput.java rename to java/examples/src/main/java/com/fing/fourmc/mapreduce/text/lz4/TestTextInput.java index ff20fd7..fb51483 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/text/lz4/TestTextInput.java +++ b/java/examples/src/main/java/com/fing/fourmc/mapreduce/text/lz4/TestTextInput.java @@ -1,10 +1,10 @@ -package com.hadoop.fourmc.mapreduce.text.lz4; +package com.fing.fourmc.mapreduce.text.lz4; -import com.hadoop.compression.fourmc.FourMcCodec; -import com.hadoop.compression.fourmc.FourMcHighCodec; -import com.hadoop.compression.fourmc.FourMcMediumCodec; -import com.hadoop.compression.fourmc.FourMcUltraCodec; -import com.hadoop.mapreduce.FourMcTextInputFormat; +import com.fing.compression.fourmc.FourMcCodec; +import com.fing.compression.fourmc.FourMcHighCodec; +import com.fing.compression.fourmc.FourMcMediumCodec; +import com.fing.compression.fourmc.FourMcUltraCodec; +import com.fing.mapreduce.FourMcTextInputFormat; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; diff --git a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/text/zstd/TestTextInput.java b/java/examples/src/main/java/com/fing/fourmc/mapreduce/text/zstd/TestTextInput.java similarity index 86% rename from java/examples/src/main/java/com/hadoop/fourmc/mapreduce/text/zstd/TestTextInput.java rename to java/examples/src/main/java/com/fing/fourmc/mapreduce/text/zstd/TestTextInput.java index 25517e9..9931a0b 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/mapreduce/text/zstd/TestTextInput.java +++ b/java/examples/src/main/java/com/fing/fourmc/mapreduce/text/zstd/TestTextInput.java @@ -1,10 +1,10 @@ -package com.hadoop.fourmc.mapreduce.text.zstd; +package com.fing.fourmc.mapreduce.text.zstd; -import com.hadoop.compression.fourmc.FourMzCodec; -import com.hadoop.compression.fourmc.FourMzHighCodec; -import com.hadoop.compression.fourmc.FourMzMediumCodec; -import com.hadoop.compression.fourmc.FourMzUltraCodec; -import com.hadoop.mapreduce.FourMzTextInputFormat; +import com.fing.compression.fourmc.FourMzCodec; +import com.fing.compression.fourmc.FourMzHighCodec; +import com.fing.compression.fourmc.FourMzMediumCodec; +import com.fing.compression.fourmc.FourMzUltraCodec; +import com.fing.mapreduce.FourMzTextInputFormat; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; @@ -46,7 +46,7 @@ public int runTest(String[] args, Configuration conf) throws Exception { job.setJobName("4mz.TestTextInput"); job.setJarByClass(getClass()); - job.setMapperClass(com.hadoop.fourmc.mapreduce.text.zstd.TestTextInput.TestMapper.class); + job.setMapperClass(com.fing.fourmc.mapreduce.text.zstd.TestTextInput.TestMapper.class); job.setNumReduceTasks(0); job.setInputFormatClass(FourMzTextInputFormat.class); @@ -86,7 +86,7 @@ public int runTest(String[] args, Configuration conf) throws Exception { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); //args = new GenericOptionsParser(conf, args).getRemainingArgs(); - com.hadoop.fourmc.mapreduce.text.zstd.TestTextInput runner = new com.hadoop.fourmc.mapreduce.text.zstd.TestTextInput(); + com.fing.fourmc.mapreduce.text.zstd.TestTextInput runner = new com.fing.fourmc.mapreduce.text.zstd.TestTextInput(); if (args.length < 3) { System.out.println( diff --git a/java/examples/src/main/java/com/hadoop/fourmc/protobuf/USER.java b/java/examples/src/main/java/com/fing/fourmc/protobuf/USER.java similarity index 98% rename from java/examples/src/main/java/com/hadoop/fourmc/protobuf/USER.java rename to java/examples/src/main/java/com/fing/fourmc/protobuf/USER.java index a97bb90..d0635ff 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/protobuf/USER.java +++ b/java/examples/src/main/java/com/fing/fourmc/protobuf/USER.java @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: user.proto -package com.hadoop.fourmc.protobuf; +package com.fing.fourmc.protobuf; public final class USER { private USER() {} @@ -87,7 +87,7 @@ public interface UserOrBuilder getTagsBytes(int index); } /** - * Protobuf type {@code com.hadoop.fourmc.protobuf.User} + * Protobuf type {@code com.fing.fourmc.protobuf.User} */ public static final class User extends com.google.protobuf.GeneratedMessage @@ -534,7 +534,7 @@ protected Builder newBuilderForType( return builder; } /** - * Protobuf type {@code com.hadoop.fourmc.protobuf.User} + * Protobuf type {@code com.fing.fourmc.protobuf.User} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder @@ -551,7 +551,7 @@ public static final class Builder extends User.class, Builder.class); } - // Construct using com.hadoop.fourmc.protobuf.USER.User.newBuilder() + // Construct using com.fing.fourmc.protobuf.USER.User.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -1054,7 +1054,7 @@ public Builder addTagsBytes( return this; } - // @@protoc_insertion_point(builder_scope:com.hadoop.fourmc.protobuf.User) + // @@protoc_insertion_point(builder_scope:com.fing.fourmc.protobuf.User) } static { @@ -1062,7 +1062,7 @@ public Builder addTagsBytes( defaultInstance.initFields(); } - // @@protoc_insertion_point(class_scope:com.hadoop.fourmc.protobuf.User) + // @@protoc_insertion_point(class_scope:com.fing.fourmc.protobuf.User) } private static com.google.protobuf.Descriptors.Descriptor @@ -1079,10 +1079,10 @@ public Builder addTagsBytes( descriptor; static { String[] descriptorData = { - "\n\nuser.proto\022\032com.hadoop.fourmc.protobuf" + + "\n\nuser.proto\022\032com.fing.fourmc.protobuf" + "\"S\n\004User\022\016\n\006userId\030\001 \002(\t\022\014\n\004name\030\002 \001(\t\022\014" + "\n\004type\030\003 \001(\t\022\021\n\tbirthDate\030\004 \001(\003\022\014\n\004tags\030" + - "\005 \003(\tB$\n\032com.hadoop.fourmc.protobufB\004USE" + + "\005 \003(\tB$\n\032com.fing.fourmc.protobufB\004USE" + "RH\001" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = diff --git a/java/examples/src/main/java/com/hadoop/fourmc/spark/protobuf/TestProtobufInput.java b/java/examples/src/main/java/com/fing/fourmc/spark/protobuf/TestProtobufInput.java similarity index 94% rename from java/examples/src/main/java/com/hadoop/fourmc/spark/protobuf/TestProtobufInput.java rename to java/examples/src/main/java/com/fing/fourmc/spark/protobuf/TestProtobufInput.java index e1311a4..66c020f 100644 --- a/java/examples/src/main/java/com/hadoop/fourmc/spark/protobuf/TestProtobufInput.java +++ b/java/examples/src/main/java/com/fing/fourmc/spark/protobuf/TestProtobufInput.java @@ -1,9 +1,9 @@ -package com.hadoop.fourmc.spark.protobuf; +package com.fing.fourmc.spark.protobuf; -import com.hadoop.compression.fourmc.FourMzHighCodec; -import com.hadoop.fourmc.elephantbird.adapter.FourMzEbProtoInputFormat; -import com.hadoop.fourmc.elephantbird.adapter.FourMzEbProtoOutputFormat; -import com.hadoop.fourmc.protobuf.USER; +import com.fing.compression.fourmc.FourMzHighCodec; +import com.fing.fourmc.elephantbird.adapter.FourMzEbProtoInputFormat; +import com.fing.fourmc.elephantbird.adapter.FourMzEbProtoOutputFormat; +import com.fing.fourmc.protobuf.USER; import com.twitter.elephantbird.mapreduce.io.ProtobufWritable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; diff --git a/java/examples/src/main/resources/user.proto b/java/examples/src/main/resources/user.proto index 9b57264..9da6efe 100644 --- a/java/examples/src/main/resources/user.proto +++ b/java/examples/src/main/resources/user.proto @@ -1,6 +1,6 @@ -package com.hadoop.fourmc.protobuf; +package com.fing.fourmc.protobuf; -option java_package = "com.hadoop.fourmc.protobuf"; +option java_package = "com.fing.fourmc.protobuf"; option java_outer_classname = "USER"; option optimize_for = SPEED; diff --git a/java/hadoop-4mc/pom.xml b/java/hadoop-4mc/pom.xml index e2e33bd..851ba19 100644 --- a/java/hadoop-4mc/pom.xml +++ b/java/hadoop-4mc/pom.xml @@ -2,7 +2,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - com.hadoop.fourmc + com.fing.fourmc parent 1.0 @@ -18,7 +18,7 @@ 1.7 - com.hadoop.fourmc + com.fing.fourmc hadoop-4mc 2.2.0 jar @@ -55,6 +55,10 @@ BuzzL Tommaso Latini + + Scip88 + Francesco Scipioni + diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcBlockIndex.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcBlockIndex.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcBlockIndex.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcBlockIndex.java index 29dda91..4d880c8 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcBlockIndex.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcBlockIndex.java @@ -32,7 +32,7 @@ - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcCodec.java similarity index 97% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcCodec.java index b4433e1..9dfeb01 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.CompressionInputStream; import org.apache.hadoop.io.compress.CompressionOutputStream; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcHighCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcHighCodec.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcHighCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcHighCodec.java index 36e6eaf..54c360b 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcHighCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcHighCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.Compressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcInputFormatUtil.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcInputFormatUtil.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcInputFormatUtil.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcInputFormatUtil.java index 4bee54a..f95ab48 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcInputFormatUtil.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcInputFormatUtil.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.conf.Configuration; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcInputStream.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcInputStream.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcInputStream.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcInputStream.java index 4e6c33d..9eb0e4b 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcInputStream.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcInputStream.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcMediumCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcMediumCodec.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcMediumCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcMediumCodec.java index e9bec84..717ff5b 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcMediumCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcMediumCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.Compressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcNativeCodeLoader.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcNativeCodeLoader.java similarity index 95% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcNativeCodeLoader.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcNativeCodeLoader.java index 94f4e68..dde621e 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcNativeCodeLoader.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcNativeCodeLoader.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -50,7 +50,7 @@ public class FourMcNativeCodeLoader { * thus ignoring the embedded libraries inside jar. */ public static final String USE_BINARIES_ON_LIB_PATH = - "com.hadoop.compression.fourmc.use.libpath"; + "com.fing.compression.fourmc.use.libpath"; private enum OS { WINDOWS("win32", "dll"), LINUX("linux", "so"), MAC("darwin", "dylib"), SOLARIS("solaris", "so"); diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcOutputStream.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcOutputStream.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcOutputStream.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcOutputStream.java index b68bd77..1d6e0af 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcOutputStream.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcOutputStream.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcUltraCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcUltraCodec.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcUltraCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcUltraCodec.java index d87f853..cd94949 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMcUltraCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMcUltraCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.Compressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzBlockIndex.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzBlockIndex.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzBlockIndex.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzBlockIndex.java index e83887c..31d0c1f 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzBlockIndex.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzBlockIndex.java @@ -32,7 +32,7 @@ - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzCodec.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzCodec.java index 886e825..fe05e94 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.CompressionInputStream; import org.apache.hadoop.io.compress.CompressionOutputStream; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzHighCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzHighCodec.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzHighCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzHighCodec.java index 632c22a..3f1ca3d 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzHighCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzHighCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.Compressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzInputStream.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzInputStream.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzInputStream.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzInputStream.java index 35f14a3..59554f7 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzInputStream.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzInputStream.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzMediumCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzMediumCodec.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzMediumCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzMediumCodec.java index 20da81e..5d1bdeb 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzMediumCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzMediumCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.Compressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzOutputStream.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzOutputStream.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzOutputStream.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzOutputStream.java index 43e29ae..690c0c7 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzOutputStream.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzOutputStream.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzUltraCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzUltraCodec.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzUltraCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzUltraCodec.java index 55e7af4..0e46764 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/FourMzUltraCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/FourMzUltraCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.hadoop.io.compress.Compressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Codec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Codec.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Codec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Codec.java index 46e4c1d..08b1234 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Codec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Codec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Compressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Compressor.java similarity index 95% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Compressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Compressor.java index a138658..d75eb6a 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Compressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Compressor.java @@ -31,9 +31,9 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; -import com.hadoop.compression.fourmc.util.DirectBufferPool; +import com.fing.compression.fourmc.util.DirectBufferPool; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Decompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Decompressor.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Decompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Decompressor.java index b945377..867b77a 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4Decompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4Decompressor.java @@ -31,9 +31,9 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; -import com.hadoop.compression.fourmc.util.DirectBufferPool; +import com.fing.compression.fourmc.util.DirectBufferPool; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.io.compress.Decompressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4HighCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4HighCodec.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4HighCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4HighCodec.java index 8f4603f..b441e75 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4HighCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4HighCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4HighCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4HighCompressor.java similarity index 95% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4HighCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4HighCompressor.java index 5459b4a..4bde79e 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4HighCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4HighCompressor.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; /** * Provides LZ4 compression at HC: High Compression (LZ4 HC level 4). diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4MediumCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4MediumCodec.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4MediumCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4MediumCodec.java index d8782c1..2596784 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4MediumCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4MediumCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4MediumCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4MediumCompressor.java similarity index 95% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4MediumCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4MediumCompressor.java index 72903ed..62a4634 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4MediumCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4MediumCompressor.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; /** * Provides LZ4 compression at MC: Medium Compression (LZ4 MC). diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4UltraCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4UltraCodec.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4UltraCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4UltraCodec.java index aa8cb1e..2cb79d3 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4UltraCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4UltraCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4UltraCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4UltraCompressor.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4UltraCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4UltraCompressor.java index d70293f..81dd43c 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/Lz4UltraCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/Lz4UltraCompressor.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; /** * Provides LZ4 compression at UC: Ultra Compression (LZ4 HC level 8). diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstCodec.java similarity index 97% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstCodec.java index bffd671..07e403f 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstCodec.java @@ -24,7 +24,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,8 +36,8 @@ import java.io.InputStream; import java.io.OutputStream; -import com.hadoop.compression.fourmc.zstd.ZstdStreamCompressor; -import com.hadoop.compression.fourmc.zstd.ZstdStreamDecompressor; +import com.fing.compression.fourmc.zstd.ZstdStreamCompressor; +import com.fing.compression.fourmc.zstd.ZstdStreamDecompressor; /** * A {@link org.apache.hadoop.io.compress.CompressionCodec} for a streaming diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdCodec.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdCodec.java index 117c196..0fab293 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdCodec.java @@ -40,7 +40,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdCompressor.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdCompressor.java index 402e6c1..2433c9e 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdCompressor.java @@ -40,9 +40,9 @@ * of patent rights can be found in the PATENTS file in the same directory. * **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; -import com.hadoop.compression.fourmc.util.DirectBufferPool; +import com.fing.compression.fourmc.util.DirectBufferPool; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdDecompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdDecompressor.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdDecompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdDecompressor.java index 325fa6f..13ecbd1 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdDecompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdDecompressor.java @@ -31,9 +31,9 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; -import com.hadoop.compression.fourmc.util.DirectBufferPool; +import com.fing.compression.fourmc.util.DirectBufferPool; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.io.compress.Decompressor; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdHighCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdHighCodec.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdHighCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdHighCodec.java index cc3ba2c..89cdd1b 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdHighCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdHighCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdHighCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdHighCompressor.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdHighCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdHighCompressor.java index a9f98b0..91a0e14 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdHighCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdHighCompressor.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; /** * Provides ZSTD compression at HC: High Compression (ZSTD level 6). diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdMediumCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdMediumCodec.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdMediumCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdMediumCodec.java index d4ee432..e2276c3 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdMediumCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdMediumCodec.java @@ -31,7 +31,7 @@ You can contact Zstd lib author at : - Zstd source repository : http://code.google.com/p/Zstd/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdMediumCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdMediumCompressor.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdMediumCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdMediumCompressor.java index 14c2b29..622dd9e 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdMediumCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdMediumCompressor.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; /** * Provides ZSTD compression at MC: Medium Compression (ZSTD default level = 3). diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdUltraCodec.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdUltraCodec.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdUltraCodec.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdUltraCodec.java index 6888dfb..66322c0 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdUltraCodec.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdUltraCodec.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdUltraCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdUltraCompressor.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdUltraCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdUltraCompressor.java index 7ff9642..94744f0 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/ZstdUltraCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/ZstdUltraCompressor.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; /** * Provides ZSTD compression at UC: Ultra Compression (ZSTD HC level 12). diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/util/DirectBufferPool.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/util/DirectBufferPool.java similarity index 95% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/util/DirectBufferPool.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/util/DirectBufferPool.java index e18be7d..4979868 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/util/DirectBufferPool.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/util/DirectBufferPool.java @@ -1,4 +1,4 @@ -package com.hadoop.compression.fourmc.util; +package com.fing.compression.fourmc.util; import java.nio.ByteBuffer; import java.util.HashMap; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/util/HadoopUtils.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/util/HadoopUtils.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/util/HadoopUtils.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/util/HadoopUtils.java index 541a938..5b8b03d 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/util/HadoopUtils.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/util/HadoopUtils.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.compression.fourmc.util; +package com.fing.compression.fourmc.util; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.mapreduce.JobContext; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/Zstd.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/Zstd.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/Zstd.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/Zstd.java index 975c40e..4522f3b 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/Zstd.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/Zstd.java @@ -25,12 +25,12 @@ * */ -package com.hadoop.compression.fourmc.zstd; +package com.fing.compression.fourmc.zstd; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.hadoop.compression.fourmc.FourMcNativeCodeLoader; +import com.fing.compression.fourmc.FourMcNativeCodeLoader; /** * @author Xianjin YE diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/ZstdStreamCompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/ZstdStreamCompressor.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/ZstdStreamCompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/ZstdStreamCompressor.java index 0ff11a2..b70d4b3 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/ZstdStreamCompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/ZstdStreamCompressor.java @@ -25,7 +25,7 @@ * */ -package com.hadoop.compression.fourmc.zstd; +package com.fing.compression.fourmc.zstd; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/ZstdStreamDecompressor.java b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/ZstdStreamDecompressor.java similarity index 99% rename from java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/ZstdStreamDecompressor.java rename to java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/ZstdStreamDecompressor.java index d9a371b..064f5b6 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/compression/fourmc/zstd/ZstdStreamDecompressor.java +++ b/java/hadoop-4mc/src/main/java/com/fing/compression/fourmc/zstd/ZstdStreamDecompressor.java @@ -24,7 +24,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -package com.hadoop.compression.fourmc.zstd; +package com.fing.compression.fourmc.zstd; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcInputFormat.java b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcInputFormat.java similarity index 93% rename from java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcInputFormat.java rename to java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcInputFormat.java index 5e56c90..6d4f7c9 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcInputFormat.java +++ b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcInputFormat.java @@ -31,11 +31,11 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.mapreduce; +package com.fing.mapreduce; -import com.hadoop.compression.fourmc.FourMcBlockIndex; -import com.hadoop.compression.fourmc.FourMcInputFormatUtil; -import com.hadoop.compression.fourmc.util.HadoopUtils; +import com.fing.compression.fourmc.FourMcBlockIndex; +import com.fing.compression.fourmc.FourMcInputFormatUtil; +import com.fing.compression.fourmc.util.HadoopUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -59,7 +59,7 @@ * This is the base class, mainly managing input splits, leveraging 4mc block index. * * Subclasses must only make sure to provide an implementation of createRecordReader. - * See {@link com.hadoop.mapreduce.FourMcTextInputFormat} as example reading text files. + * See {@link com.fing.mapreduce.FourMcTextInputFormat} as example reading text files. * * Note: unlikely default hadoop, but exactly like the EB version * this recursively examines directories for matching files. diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcLineRecordReader.java b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcLineRecordReader.java similarity index 95% rename from java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcLineRecordReader.java rename to java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcLineRecordReader.java index 0366e5f..4c2c2f0 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcLineRecordReader.java +++ b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcLineRecordReader.java @@ -31,9 +31,9 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.mapreduce; +package com.fing.mapreduce; -import com.hadoop.compression.fourmc.util.HadoopUtils; +import com.fing.compression.fourmc.util.HadoopUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileSystem; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcTextInputFormat.java b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcTextInputFormat.java similarity index 96% rename from java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcTextInputFormat.java rename to java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcTextInputFormat.java index b6e4f81..1560cf2 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMcTextInputFormat.java +++ b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMcTextInputFormat.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.mapreduce; +package com.fing.mapreduce; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzInputFormat.java b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzInputFormat.java similarity index 97% rename from java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzInputFormat.java rename to java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzInputFormat.java index 906d2d5..1ca6912 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzInputFormat.java +++ b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzInputFormat.java @@ -31,11 +31,11 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.mapreduce; +package com.fing.mapreduce; -import com.hadoop.compression.fourmc.FourMcInputFormatUtil; -import com.hadoop.compression.fourmc.FourMzBlockIndex; -import com.hadoop.compression.fourmc.util.HadoopUtils; +import com.fing.compression.fourmc.FourMcInputFormatUtil; +import com.fing.compression.fourmc.FourMzBlockIndex; +import com.fing.compression.fourmc.util.HadoopUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzLineRecordReader.java b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzLineRecordReader.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzLineRecordReader.java rename to java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzLineRecordReader.java index d8b6691..1380af6 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzLineRecordReader.java +++ b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzLineRecordReader.java @@ -31,9 +31,9 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.mapreduce; +package com.fing.mapreduce; -import com.hadoop.compression.fourmc.util.HadoopUtils; +import com.fing.compression.fourmc.util.HadoopUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileSystem; diff --git a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzTextInputFormat.java b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzTextInputFormat.java similarity index 98% rename from java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzTextInputFormat.java rename to java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzTextInputFormat.java index 372248b..81198ab 100644 --- a/java/hadoop-4mc/src/main/java/com/hadoop/mapreduce/FourMzTextInputFormat.java +++ b/java/hadoop-4mc/src/main/java/com/fing/mapreduce/FourMzTextInputFormat.java @@ -31,7 +31,7 @@ You can contact LZ4 lib author at : - LZ4 source repository : http://code.google.com/p/lz4/ **/ -package com.hadoop.mapreduce; +package com.fing.mapreduce; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; diff --git a/java/hadoop-4mc/src/main/resources/META-INF/services/org.apache.hadoop.io.compress.CompressionCodec b/java/hadoop-4mc/src/main/resources/META-INF/services/org.apache.hadoop.io.compress.CompressionCodec index 1a9fc7a..d956a94 100644 --- a/java/hadoop-4mc/src/main/resources/META-INF/services/org.apache.hadoop.io.compress.CompressionCodec +++ b/java/hadoop-4mc/src/main/resources/META-INF/services/org.apache.hadoop.io.compress.CompressionCodec @@ -1,12 +1,12 @@ -com.hadoop.compression.fourmc.FourMcCodec -com.hadoop.compression.fourmc.FourMcHighCodec -com.hadoop.compression.fourmc.FourMcMediumCodec -com.hadoop.compression.fourmc.FourMcUltraCodec -com.hadoop.compression.fourmc.FourMzCodec -com.hadoop.compression.fourmc.FourMzHighCodec -com.hadoop.compression.fourmc.FourMzMediumCodec -com.hadoop.compression.fourmc.FourMzUltraCodec -com.hadoop.compression.fourmc.Lz4Codec -com.hadoop.compression.fourmc.Lz4HighCodec -com.hadoop.compression.fourmc.Lz4MediumCodec -com.hadoop.compression.fourmc.Lz4UltraCodec +com.fing.compression.fourmc.FourMcCodec +com.fing.compression.fourmc.FourMcHighCodec +com.fing.compression.fourmc.FourMcMediumCodec +com.fing.compression.fourmc.FourMcUltraCodec +com.fing.compression.fourmc.FourMzCodec +com.fing.compression.fourmc.FourMzHighCodec +com.fing.compression.fourmc.FourMzMediumCodec +com.fing.compression.fourmc.FourMzUltraCodec +com.fing.compression.fourmc.Lz4Codec +com.fing.compression.fourmc.Lz4HighCodec +com.fing.compression.fourmc.Lz4MediumCodec +com.fing.compression.fourmc.Lz4UltraCodec diff --git a/java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/darwin/x86_64/libhadoop-4mc.dylib b/java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/darwin/x86_64/libhadoop-4mc.dylib similarity index 100% rename from java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/darwin/x86_64/libhadoop-4mc.dylib rename to java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/darwin/x86_64/libhadoop-4mc.dylib diff --git a/java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/linux/amd64/libhadoop-4mc.so b/java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/linux/amd64/libhadoop-4mc.so similarity index 100% rename from java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/linux/amd64/libhadoop-4mc.so rename to java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/linux/amd64/libhadoop-4mc.so diff --git a/java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/linux/i386/libhadoop-4mc.so b/java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/linux/i386/libhadoop-4mc.so similarity index 100% rename from java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/linux/i386/libhadoop-4mc.so rename to java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/linux/i386/libhadoop-4mc.so diff --git a/java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/win32/amd64/libhadoop-4mc.dll b/java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/win32/amd64/libhadoop-4mc.dll similarity index 100% rename from java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/win32/amd64/libhadoop-4mc.dll rename to java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/win32/amd64/libhadoop-4mc.dll diff --git a/java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/win32/i386/libhadoop-4mc.dll b/java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/win32/i386/libhadoop-4mc.dll similarity index 100% rename from java/hadoop-4mc/src/main/resources/com/hadoop/compression/fourmc/win32/i386/libhadoop-4mc.dll rename to java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/win32/i386/libhadoop-4mc.dll diff --git a/java/hadoop-4mc/src/test/java/com/hadoop/compression/fourmc/TestFourMcBlockIndex.java b/java/hadoop-4mc/src/test/java/com/fing/compression/fourmc/TestFourMcBlockIndex.java similarity index 95% rename from java/hadoop-4mc/src/test/java/com/hadoop/compression/fourmc/TestFourMcBlockIndex.java rename to java/hadoop-4mc/src/test/java/com/fing/compression/fourmc/TestFourMcBlockIndex.java index 6d4d530..c01b6de 100644 --- a/java/hadoop-4mc/src/test/java/com/hadoop/compression/fourmc/TestFourMcBlockIndex.java +++ b/java/hadoop-4mc/src/test/java/com/fing/compression/fourmc/TestFourMcBlockIndex.java @@ -1,4 +1,4 @@ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import junit.framework.Test; diff --git a/java/hadoop-4mc/src/test/java/com/hadoop/compression/fourmc/TestFourMcCodec.java b/java/hadoop-4mc/src/test/java/com/fing/compression/fourmc/TestFourMcCodec.java similarity index 97% rename from java/hadoop-4mc/src/test/java/com/hadoop/compression/fourmc/TestFourMcCodec.java rename to java/hadoop-4mc/src/test/java/com/fing/compression/fourmc/TestFourMcCodec.java index e3164c8..702a032 100644 --- a/java/hadoop-4mc/src/test/java/com/hadoop/compression/fourmc/TestFourMcCodec.java +++ b/java/hadoop-4mc/src/test/java/com/fing/compression/fourmc/TestFourMcCodec.java @@ -1,4 +1,4 @@ -package com.hadoop.compression.fourmc; +package com.fing.compression.fourmc; import java.io.*; import java.util.Random; @@ -26,7 +26,7 @@ public class TestFourMcCodec extends TestCase{ public void testZstdCodec() throws IOException { assertTrue(FourMcNativeCodeLoader.isNativeCodeLoaded()); - codecTest(conf, seed, count * 10, "com.hadoop.compression.fourmc.ZstdCodec"); + codecTest(conf, seed, count * 10, "com.fing.compression.fourmc.ZstdCodec"); } private static void codecTest(Configuration conf, int seed, int count, diff --git a/java/pom.xml b/java/pom.xml index 6906917..3f8e65f 100755 --- a/java/pom.xml +++ b/java/pom.xml @@ -2,7 +2,7 @@ - com.hadoop.fourmc + com.fing.fourmc parent 1.0 diff --git a/native/jniCompressor.c b/native/jniCompressor.c index 561e651..83ae4bd 100644 --- a/native/jniCompressor.c +++ b/native/jniCompressor.c @@ -55,7 +55,7 @@ static jfieldID Lz4Compressor_directBufferSize; JNIEXPORT void JNICALL -Java_com_hadoop_compression_fourmc_Lz4Compressor_initIDs( +Java_com_fing_compression_fourmc_Lz4Compressor_initIDs( JNIEnv *env, jclass class ) { @@ -70,7 +70,7 @@ Java_com_hadoop_compression_fourmc_Lz4Compressor_initIDs( JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirect( +Java_com_fing_compression_fourmc_Lz4Compressor_compressBytesDirect( JNIEnv *env, jobject this) { int r; @@ -94,8 +94,8 @@ Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirect( (*env)->SetIntField(env, this, Lz4Compressor_uncompressedDirectBufLen, 0); } else { char exception_msg[EXCEPTION_STRING_MAXLEN]; - PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "%s returned: %d", "LZ4_compress", r); - PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); + PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "%s returned: %d", "LZ4_compress", r); + PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); THROW(env, "java/lang/InternalError", exception_msg); } @@ -103,7 +103,7 @@ Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirect( } JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirectMC( +Java_com_fing_compression_fourmc_Lz4Compressor_compressBytesDirectMC( JNIEnv *env, jobject this) { int r; @@ -126,8 +126,8 @@ Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirectMC( (*env)->SetIntField(env, this, Lz4Compressor_uncompressedDirectBufLen, 0); } else { char exception_msg[EXCEPTION_STRING_MAXLEN]; - PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "%s returned: %d", "LZ4_compressMC", r); - PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); + PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "%s returned: %d", "LZ4_compressMC", r); + PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); THROW(env, "java/lang/InternalError", exception_msg); } @@ -136,7 +136,7 @@ Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirectMC( JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirectHC( +Java_com_fing_compression_fourmc_Lz4Compressor_compressBytesDirectHC( JNIEnv *env, jobject this, jint clevel) { int r; @@ -159,8 +159,8 @@ Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirectHC( (*env)->SetIntField(env, this, Lz4Compressor_uncompressedDirectBufLen, 0); } else { char exception_msg[EXCEPTION_STRING_MAXLEN]; - PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "%s returned: %d", "LZ4_compressHC2", r); - PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); + PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "%s returned: %d", "LZ4_compressHC2", r); + PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); THROW(env, "java/lang/InternalError", exception_msg); } @@ -168,14 +168,14 @@ Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBytesDirectHC( } -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_Lz4Compressor_compressBound +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_Lz4Compressor_compressBound (JNIEnv *env, jclass cls, jint forSize) { return LZ4_compressBound(forSize); } -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_Lz4Compressor_xxhash32 +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_Lz4Compressor_xxhash32 (JNIEnv *env, jclass cls, jbyteArray buf, jint off, jint len, jint seed) { char* in; diff --git a/native/jniDecompressor.c b/native/jniDecompressor.c index 67cd8da..da5bcb9 100644 --- a/native/jniDecompressor.c +++ b/native/jniDecompressor.c @@ -54,7 +54,7 @@ static jfieldID Lz4Decompressor_directBufferSize; JNIEXPORT void JNICALL -Java_com_hadoop_compression_fourmc_Lz4Decompressor_initIDs(JNIEnv *env, jclass class) { +Java_com_fing_compression_fourmc_Lz4Decompressor_initIDs(JNIEnv *env, jclass class) { Lz4Decompressor_finished = (*env)->GetFieldID(env, class, "finished", "Z"); Lz4Decompressor_compressedDirectBuf = (*env)->GetFieldID(env, class,"compressedDirectBuf", "Ljava/nio/Buffer;"); @@ -65,7 +65,7 @@ Java_com_hadoop_compression_fourmc_Lz4Decompressor_initIDs(JNIEnv *env, jclass c JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_Lz4Decompressor_decompressBytesDirect( +Java_com_fing_compression_fourmc_Lz4Decompressor_decompressBytesDirect( JNIEnv *env, jobject this) { int outputSize; @@ -91,15 +91,15 @@ Java_com_hadoop_compression_fourmc_Lz4Decompressor_decompressBytesDirect( (*env)->SetIntField(env, this, Lz4Decompressor_compressedDirectBufLen, 0); } else { char exception_msg[EXCEPTION_STRING_MAXLEN]; - PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "LZ4_decompress_safe returned: %d", outputSize); - PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); + PORTABLE_SNPRINTF_START(exception_msg, EXCEPTION_STRING_MAXLEN, "LZ4_decompress_safe returned: %d", outputSize); + PORTABLE_SNPRINTF_END(exception_msg, EXCEPTION_STRING_MAXLEN); THROW(env, "java/lang/InternalError", exception_msg); } return outputSize; } -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_Lz4Decompressor_xxhash32 +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_Lz4Decompressor_xxhash32 (JNIEnv *env, jclass cls, jbyteArray buf, jint off, jint len, jint seed) { char* in; diff --git a/native/jniZStreamCompressor.c b/native/jniZStreamCompressor.c index b1bb25f..06b9887 100644 --- a/native/jniZStreamCompressor.c +++ b/native/jniZStreamCompressor.c @@ -49,7 +49,7 @@ static jfieldID o_buff_len_id; * Method: initIDs * Signature: ()V */ -JNIEXPORT void JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompressor_initIDs +JNIEXPORT void JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamCompressor_initIDs (JNIEnv *env, jclass obj) { src_pos_id = (*env)->GetFieldID(env, obj, "srcPos", "J"); dst_pos_id = (*env)->GetFieldID(env, obj, "dstPos", "J"); @@ -62,7 +62,7 @@ JNIEXPORT void JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompres * Method: createCStream * Signature: ()J */ -JNIEXPORT jlong JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompressor_createCStream +JNIEXPORT jlong JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamCompressor_createCStream (JNIEnv *env, jclass obj) { return (jlong) ZSTD_createCStream(); } @@ -73,7 +73,7 @@ JNIEXPORT jlong JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompre * Method: freeCStream * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompressor_freeCStream +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamCompressor_freeCStream (JNIEnv *env, jclass obj, jlong stream) { return (jint) ZSTD_freeCStream((ZSTD_CStream *) stream); } @@ -83,7 +83,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompres * Method: initCStream * Signature: (JI)I */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompressor_initCStream +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamCompressor_initCStream (JNIEnv *env, jclass obj, jlong stream, jint level) { return (jint) ZSTD_initCStream((ZSTD_CStream *) stream, level); } @@ -93,7 +93,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompres * Method: compressStream * Signature: (JLjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;I)I */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompressor_compressStream +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamCompressor_compressStream (JNIEnv *env, jobject this, jlong stream, jobject dst, jint dst_size, jobject src, jint src_size) { size_t size = (size_t)(0 - ZSTD_error_memory_allocation); @@ -120,7 +120,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompres * Method: endStream * Signature: (JLjava/nio/ByteBuffer;II)I */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamCompressor_endStream +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamCompressor_endStream (JNIEnv *env, jobject this, jlong stream, jobject dst, jint dst_offset, jint dst_size) { size_t size = (size_t)(0 - ZSTD_error_memory_allocation); diff --git a/native/jniZStreamDecompressor.c b/native/jniZStreamDecompressor.c index f75181d..8f1f829 100644 --- a/native/jniZStreamDecompressor.c +++ b/native/jniZStreamDecompressor.c @@ -50,7 +50,7 @@ static jfieldID o_buff_len_id; * Method: initIDs * Signature: ()V */ -JNIEXPORT void JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompressor_initIDs +JNIEXPORT void JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamDecompressor_initIDs (JNIEnv *env, jclass obj) { src_pos_id = (*env)->GetFieldID(env, obj, "srcPos", "J"); dst_pos_id = (*env)->GetFieldID(env, obj, "dstPos", "J"); @@ -63,7 +63,7 @@ JNIEXPORT void JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompr * Method: createDStream * Signature: ()J */ -JNIEXPORT jlong JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompressor_createDStream +JNIEXPORT jlong JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamDecompressor_createDStream (JNIEnv *env, jclass obj) { return (jlong) ZSTD_createDStream(); } @@ -74,7 +74,7 @@ JNIEXPORT jlong JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecomp * Method: freeDStream * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompressor_freeDStream +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamDecompressor_freeDStream (JNIEnv *env, jclass obj, jlong stream) { return (jint) ZSTD_freeDStream((ZSTD_DStream *) stream); } @@ -84,7 +84,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompr * Method: initDStream * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompressor_initDStream +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamDecompressor_initDStream (JNIEnv *env, jclass obj, jlong stream) { return (jint) ZSTD_initDStream((ZSTD_DStream *) stream); } @@ -94,7 +94,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompr * Method: decompressStream * Signature: (JLjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;II)I */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_ZstdStreamDecompressor_decompressStream +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_ZstdStreamDecompressor_decompressStream (JNIEnv *env, jobject this, jlong stream, jobject dst, jint dst_size, jobject src, jint src_size) { size_t size = (size_t)(0-ZSTD_error_memory_allocation); diff --git a/native/jniZstd.c b/native/jniZstd.c index 8e22f1e..d8abe92 100644 --- a/native/jniZstd.c +++ b/native/jniZstd.c @@ -46,7 +46,7 @@ * Method: isError * Signature: (J)I */ -JNIEXPORT jboolean JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_isError +JNIEXPORT jboolean JNICALL Java_com_fing_compression_fourmc_zstd_Zstd_isError (JNIEnv *env, jclass obj, jlong code) { return ZSTD_isError((size_t) code) != 0; } @@ -56,7 +56,7 @@ JNIEXPORT jboolean JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_isError * Method: getErrorName * Signature: (J)Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_getErrorName +JNIEXPORT jstring JNICALL Java_com_fing_compression_fourmc_zstd_Zstd_getErrorName (JNIEnv *env, jclass obj, jlong code) { const char *msg = ZSTD_getErrorName(code); return (*env)->NewStringUTF(env, msg); @@ -71,7 +71,7 @@ JNIEXPORT jstring JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_getErrorN * Method: cStreamInSize * Signature: ()J */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_cStreamInSize +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_Zstd_cStreamInSize (JNIEnv *env, jclass obj) { return (jint) ZSTD_CStreamInSize(); } @@ -81,7 +81,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_cStreamInSiz * Method: cStreamOutSize * Signature: ()J */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_cStreamOutSize +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_Zstd_cStreamOutSize (JNIEnv *env, jclass obj) { return (jint) ZSTD_CStreamOutSize(); } @@ -91,7 +91,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_cStreamOutSi * Method: dStreamInSize * Signature: ()J */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_dStreamInSize +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_Zstd_dStreamInSize (JNIEnv *env, jclass obj) { return (jint) ZSTD_DStreamInSize(); } @@ -101,7 +101,7 @@ JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_dStreamInSiz * Method: dStreamOutSize * Signature: ()J */ -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_zstd_Zstd_dStreamOutSize +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_zstd_Zstd_dStreamOutSize (JNIEnv *env, jclass obj) { return (jint) ZSTD_DStreamOutSize(); } diff --git a/native/jniZstdCompressor.c b/native/jniZstdCompressor.c index 0d0d72f..462186d 100644 --- a/native/jniZstdCompressor.c +++ b/native/jniZstdCompressor.c @@ -57,7 +57,7 @@ static jfieldID ZstdCompressor_directBufferSize; JNIEXPORT void JNICALL -Java_com_hadoop_compression_fourmc_ZstdCompressor_initIDs( +Java_com_fing_compression_fourmc_ZstdCompressor_initIDs( JNIEnv *env, jclass class ) { @@ -72,7 +72,7 @@ Java_com_hadoop_compression_fourmc_ZstdCompressor_initIDs( JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_ZstdCompressor_compressBytesDirect( +Java_com_fing_compression_fourmc_ZstdCompressor_compressBytesDirect( JNIEnv *env, jobject this) { size_t r; @@ -106,7 +106,7 @@ Java_com_hadoop_compression_fourmc_ZstdCompressor_compressBytesDirect( } JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_ZstdCompressor_compressBytesDirectMC( +Java_com_fing_compression_fourmc_ZstdCompressor_compressBytesDirectMC( JNIEnv *env, jobject this) { size_t r; @@ -140,7 +140,7 @@ Java_com_hadoop_compression_fourmc_ZstdCompressor_compressBytesDirectMC( JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_ZstdCompressor_compressBytesDirectHC( +Java_com_fing_compression_fourmc_ZstdCompressor_compressBytesDirectHC( JNIEnv *env, jobject this, jint clevel) { size_t r; @@ -173,14 +173,14 @@ Java_com_hadoop_compression_fourmc_ZstdCompressor_compressBytesDirectHC( } -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_ZstdCompressor_compressBound +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_ZstdCompressor_compressBound (JNIEnv *env, jclass cls, jint forSize) { return ZSTD_compressBound(forSize); } -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_ZstdCompressor_xxhash32 +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_ZstdCompressor_xxhash32 (JNIEnv *env, jclass cls, jbyteArray buf, jint off, jint len, jint seed) { char* in; diff --git a/native/jniZstdDecompressor.c b/native/jniZstdDecompressor.c index 2053826..6cdfd1a 100644 --- a/native/jniZstdDecompressor.c +++ b/native/jniZstdDecompressor.c @@ -56,7 +56,7 @@ static jfieldID ZstdDecompressor_directBufferSize; JNIEXPORT void JNICALL -Java_com_hadoop_compression_fourmc_ZstdDecompressor_initIDs(JNIEnv *env, jclass class) { +Java_com_fing_compression_fourmc_ZstdDecompressor_initIDs(JNIEnv *env, jclass class) { ZstdDecompressor_finished = (*env)->GetFieldID(env, class, "finished", "Z"); ZstdDecompressor_compressedDirectBuf = (*env)->GetFieldID(env, class,"compressedDirectBuf", "Ljava/nio/Buffer;"); @@ -67,7 +67,7 @@ Java_com_hadoop_compression_fourmc_ZstdDecompressor_initIDs(JNIEnv *env, jclass JNIEXPORT jint JNICALL -Java_com_hadoop_compression_fourmc_ZstdDecompressor_decompressBytesDirect( +Java_com_fing_compression_fourmc_ZstdDecompressor_decompressBytesDirect( JNIEnv *env, jobject this) { int outputSize; @@ -101,7 +101,7 @@ Java_com_hadoop_compression_fourmc_ZstdDecompressor_decompressBytesDirect( return outputSize; } -JNIEXPORT jint JNICALL Java_com_hadoop_compression_fourmc_ZstdDecompressor_xxhash32 +JNIEXPORT jint JNICALL Java_com_fing_compression_fourmc_ZstdDecompressor_xxhash32 (JNIEnv *env, jclass cls, jbyteArray buf, jint off, jint len, jint seed) { char* in; From d990b6f3ad8d0ee7f4f53d1df3a45872b640e8e0 Mon Sep 17 00:00:00 2001 From: noodlesbad Date: Fri, 2 Sep 2022 18:27:45 +0200 Subject: [PATCH 06/10] adding darwin native libraries and tools (x86_64/arm64) as well --- .../fourmc/darwin/arm64/libhadoop-4mc.dylib | Bin 0 -> 932784 bytes .../fourmc/darwin/x86_64/libhadoop-4mc.dylib | Bin 957808 -> 1124344 bytes tool/darwin/arm64/4mc | Bin 0 -> 930048 bytes tool/darwin/x86_64/4mc | Bin 962216 -> 1120608 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/darwin/arm64/libhadoop-4mc.dylib create mode 100755 tool/darwin/arm64/4mc diff --git a/java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/darwin/arm64/libhadoop-4mc.dylib b/java/hadoop-4mc/src/main/resources/com/fing/compression/fourmc/darwin/arm64/libhadoop-4mc.dylib new file mode 100755 index 0000000000000000000000000000000000000000..64fc7e9f8c3cdea3cd2539c6f7d859009acd6906 GIT binary patch literal 932784 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

EKV;^LQQ8y9I0NR;!t*$1>INXG9% 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ÐM>?jp`*h!SFXIb@n-Y`S=X2HCbfJW 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�loHzb~D5KAqgH7#DZp&XgiJi}vcplhef+@x)HD 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 z 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∈z7Dx(&Tl&JABuea;!8u7fy|sBaT6;yOqL@nkir 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

?PXj*#cowh-uo&>1f+fJu1O5(p0q~-Nmw=Z7 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 literal 957808 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 z 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%0DP)AKop+ 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%0Dr11B@J}>v3Q&5}({~$vAGPJL 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�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%0AL^SNbO{V`sWgLdj;$L3nGvB-}SeH)8!xZ*KC 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

L~DEBf1^rljG=9cPk7aJz7za6bkc&a8~xT~ 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πdp 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%0A^hhA{wc&V?CgPK2hW-@)(oy6 zSD_xSrys$-5BEx4dD>tvPGdm6NgwIlkjDSqP0FBUl6K447S`WbZOc4^By@8qED{4s zOaAgagMJsm`&{sDv`>3!oa-)gA`;KreDch=hX+7j zhO_5lEWTkJzF~j-)&cmh1IalJBIgty%)OT#nqqI(YP7P~r?l9Z4^nn;idNRdeOQB5 zetknrCG$ke-k4&)6F6O#B5dBYuq2;-qv7`M8+KMMqfC#6S{`D zNu&MsH19y>rTl!bJMbBJ9xQQ(!S2Rsrao#NtQt?uPW4Vo&hcfUk3AQ+yZ6V_5a=V6ECcBiwkron%$TiAzTooc*|aqbm(^p0P#$2K`}nd>4kIV+D&u6p*A@1pz3scvS^ z?)wrLYp4sn2bwGQPHCcBp((N>kseqvm(?!CkNgn+J z?9l;cA8pJ_T1ne2#Jlc&f2!{oxq)fbH|&xa*aGa!TAPhLtlE)l#KGeI8%2Kaa0k}> zZ(_Ncy-9T6>e0i}yjvoDR{U!}I9+{I8SyWPLsfZ*lZ^gBnhU?dX{_CI`SZX>8g)sW z%Z1Jne*}AR?lkHYxtBOs6?Mp*9mzvUuHs$db~|6}e5z{8s2Vr%EXK!%Tw+;{IL1lh zcC8Qao-dL*g+H*5-sZfBB16|I?}`-Vn`g_ek@+vl|*xYg0-`@|7j%{bycGY8b% zu~Dme&xNgfCwVh?{`g3(=H07AZw#*2k|eh}p#DAL*~4N?-3+g_mf)wbo;o#A^>>1g z`D4|xV#&jes!I5LWNw;+`3?)ge+S7S&CXF{gruBDFS15_x~9FpIma^`lKkWz>j}(ivE>rd#+3QMN)x2d|^S> z1IY#D;pJ02S*kq?zg+gQD};ZC=3-l|JkPUh@rv|a0S>7+cwfoyE$TL1~ybpf=h;hzNjzpG{$GE+rfmRc`n(lW)5e^Ybt8C= zZLzMuR?~)!ziu%9nV-3CHdp3QTuPtbuT;Oioa^rf#2LP~>^bY#U9J7wr?W^v6lpohodgM{(5O1s=D?jD4iSV!Wc`V)S9&HfY;6Yet5QhsQ3t_oW&4MQk{RO*CUlrf*BsLVB8#lauoSq=DGjE$7 z*VI0e{b(XIuNvH|KNXq23EA*6Iw2Xn&8AQC{TXz>d@r!H^L;b(i(|uL4S0rrlsH*k zrY2kQ:bG*hp5wYHOa4__(#L02T5+}>IaW|;R#5)ZfTy1_Ed*S*c8Z=9J zch&kIpStfzbD;D{+mLKu8!^|J&}3xm$|H;ZdhdGnzV$9r$}2KP`!$j?Sj6E>nb5iL zUFP+|CqWsQk?|gQ4+rlX!MlpI7swfNGWTwyn$oaQUB~ac{4)6|ei}cWpRHl53afc~ zBr#R^CR6GDJ&a558T0l=@NK4VqpH~UbPhTgKTvp0_U%cEu@}fVv={sfFZ`bVSaae1W5Ka< zH9dlB7{BYw)byoFuerUfZh9g2vVXZ!T6>oCQ{ZRc{!Ztrk2YSx`E%6QE@N4Y7Cm0q zyfc^^x)EB=U{2*5;W6GUwqDX6aGz@~uZv7hQZH@-4ynWapPh3nfTydU*rmPu8Gb`) z!yu!d`r(E2Rr)z{_@;tbuKoF4HR461ztZpD4BuMtuBN8XRBHM_{txE&&m(pgECt7R zE8yUH7aZt2=|j@nCLF1~;0TNBg5wQ`?rj5q793U|nzbN2GQLS&dycRlG4OnWP4FUk zemQ)&SI!Vgj(B-W%CGH9bABDWH2c@Fe7d~pUH0# zzX$lAEk9s*fZrm1u_HDXe84rC->dw#@_T+td_mi)hz&0=XFB%&hz;TT9lv_-lK6r* z%;#^K&m(yLKF`OQ&&Qk3HJ-Qdyv=-m#(dt7=O6Gq=DWfAWA$MDu{=M+^QC6_pP1!s zJU`C!b>{O&&F5h}f0ySo%;z)B=Q_`i@qD~pZ@4^GYZw`CYZw*wz_WitPnWYVO(}b) zyI<>^`*Rh4O^s`q_Z4E^ZQ$|?_)Pu_AHRS+?ukNYhYj~0*M>D|54q0?Zc|L$js%Z_ z*Xy~4;!^M@__Sasq)!UDwW%Ns3xjz6DbL%?@@LHQUA$(NA8(eAqkKE%Q;^@@d^Lo3pYv|1S=Ud@x`y&R!1M1U zHWsuoP6XE0O@DCsuM0Xx{ByzQYt{5Ck^gZ@t7+%{Ps5)n7+0p%ywCmbko$4yuTQzZ zd&EmTXB`yx#l?7S z@Z5VEdaax13|hf+2Cd*ZgGQG8UX16$;T4hBalLphmggd8&!E%RneQyVv-os|`P||= zi%$i=a=ugxxQZL`Lc#wUzNO$eu%hd0&d3!Uy~lMC_}QAIUTk4+HbZ|kbk2EIJ6Gk`u#;P#4tS_6WnExj6MDYhJiGlEZ z`I02nz6igkSn1yM_W6_Rqt!&2H=o*H&CM-Z(vim;x*LC_X1N$I*09IvboTkoj8*MU zY}MVGwrm@@|D(yOy#!mNfHRJKt88=Dk*Da?bpLD2J8Xz@_36CfOFjh9&&`_pLKsT@m~uj$#HAQ$A~#?(G@W% znF~CSvICHb;5whrZf5TH{D0eaJ?#n)_I@t?>q|a5Z8qX15y(6l1W^Vs?9BLnfp9@W`DmS073 z?%87cE;y2Tf9F@`Q*R#i=hDtJ+WQ`|djso}Y=-O}h*J{_;#JKC+L)iLmgVs648js^ z@cKC3&2y;3Hy5qwXoKGaBBx<$QaN;d2l~ul&Tl94l|{~$)y2+~Iggdd*{G7GlNZ^; zy@e|A?HS|U8J{C(GsbY;j9r+@wSw!VTo-ap;+oBMIM)=eX4^4mJ10t;ZBfqr05bNU z(1v}=CjMD-dP~iIF3|>g57E!l#s z)&})~_`%1Em*5B63_tj}1b4TE><6ORpAk zWlqzpZm!7Bt4S`-J2KmC>ojzhwCRb8%D;m?+KI`ZCMH(^KMh7F3BS3(z4Q}#ocP{o z6*x&eB9S#o`#E>waPd7IMSLGlpDzWkt?)YWqak*5{_R{31A_}*0R}_wu3Z6S74Zs;__O3@}B7I>XXDC1(u>Hdww{u zq@!ckF?OVCkxhxfa(cV&YbVCSUcil&LuJklYn!;X+Sq3peN%L{^vI`MG@l(mU)H&% z!dvg6(`?AmN&Ju~)|#EfZ&F;(rTjuc zUe;9mY4{*-J$$hfUMu0p1ck#`T@kv}e8BY1a2W>f7l62ef73 zU@9=a!t*@fb@E+0{XU&?;7fS86@6b5sWM8ytM#qm?}vQ9gy-$(=-#-^5!^;ed$08P z=0=`J^UeHgRr_e>I;5A{=KPp>P#G@O|K_6mJ5J*de>zTbu)|%uQ&f8s_J)%(e>Ot*QoYSxlYgrIS*-ZPP^vh7wvSy z&vHiZd@b6461$*`|DV}7#~qoKJ$ldDMo28XB#W~Eh9Qp^$oce!X$|A^IqbJk7@XK9 z$BjMDn||w*`*!cOJ7DHE1z!3@+Bxc zW6}Wc0Io9TBodOGcCd5qQCqCv&UL;m(!al{lXVuVi8TT3P0%9KrY%clP9QP&!zW|h z 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