From daffe435c0f8d24bb767cf1152ab9f4506ce9a3e Mon Sep 17 00:00:00 2001
From: Shawn Landden
Date: Thu, 21 Dec 2017 15:41:58 -0800
Subject: [PATCH 001/255] meson: support differn't legacy levels.
Default to v0.4.0+
---
contrib/meson/meson.build | 38 ++++++++++++++++++++++-----------
contrib/meson/meson_options.txt | 2 +-
2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/contrib/meson/meson.build b/contrib/meson/meson.build
index 5ff370fa7..ce3fb83e3 100644
--- a/contrib/meson/meson.build
+++ b/contrib/meson/meson.build
@@ -38,21 +38,35 @@ libzstd_srcs = [
libzstd_includes = [include_directories(common_dir, dictbuilder_dir, compress_dir, lib_dir)]
-if get_option('legacy_support')
- message('Enabling legacy support')
- libzstd_cflags = ['-DZSTD_LEGACY_SUPPORT=4']
+legacy = get_option('legacy_support')
+if legacy != 'false'
+ message('Enabling legacy support back to version 0.' + legacy)
+ legacy_int = legacy.to_int()
+ libzstd_cflags = ['-DZSTD_LEGACY_SUPPORT=' + legacy]
legacy_dir = join_paths(lib_dir, 'legacy')
libzstd_includes += [include_directories(legacy_dir)]
- libzstd_srcs += [
- join_paths(legacy_dir, 'zstd_v01.c'),
- join_paths(legacy_dir, 'zstd_v02.c'),
- join_paths(legacy_dir, 'zstd_v03.c'),
- join_paths(legacy_dir, 'zstd_v04.c'),
- join_paths(legacy_dir, 'zstd_v05.c'),
- join_paths(legacy_dir, 'zstd_v06.c'),
- join_paths(legacy_dir, 'zstd_v07.c')
- ]
+ if legacy_int <= 1
+ libzstd_srcs += join_paths(legacy_dir, 'zstd_v01.c')
+ endif
+ if legacy_int <= 2
+ libzstd_srcs += join_paths(legacy_dir, 'zstd_v02.c')
+ endif
+ if legacy_int <= 3
+ libzstd_srcs += join_paths(legacy_dir, 'zstd_v03.c')
+ endif
+ if legacy_int <= 4
+ libzstd_srcs += join_paths(legacy_dir, 'zstd_v04.c')
+ endif
+ if legacy_int <= 5
+ libzstd_srcs += join_paths(legacy_dir, 'zstd_v05.c')
+ endif
+ if legacy_int <= 6
+ libzstd_srcs += join_paths(legacy_dir, 'zstd_v06.c')
+ endif
+ if legacy_int <= 7
+ libzstd_srcs += join_paths(legacy_dir, 'zstd_v07.c')
+ endif
else
libzstd_cflags = []
endif
diff --git a/contrib/meson/meson_options.txt b/contrib/meson/meson_options.txt
index 0a12f43e1..de9fea073 100644
--- a/contrib/meson/meson_options.txt
+++ b/contrib/meson/meson_options.txt
@@ -1,2 +1,2 @@
option('multithread', type: 'boolean', value: false)
-option('legacy_support', type: 'boolean', value: false)
+option('legacy_support', type: 'string', value: '4')
From 914d9838795c6d797a3a98e2cccf735ea1661f52 Mon Sep 17 00:00:00 2001
From: Shawn Landden
Date: Thu, 21 Dec 2017 16:15:12 -0800
Subject: [PATCH 002/255] fix unbounded range
I think you meant 8 MiB or smaller, instead of an unbounded (and illogical) range
---
doc/zstd_compression_format.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/zstd_compression_format.md b/doc/zstd_compression_format.md
index 86a7ace91..7bf36c491 100644
--- a/doc/zstd_compression_format.md
+++ b/doc/zstd_compression_format.md
@@ -257,7 +257,7 @@ a decoder is allowed to reject a compressed frame
which requests a memory size beyond decoder's authorized range.
For improved interoperability,
-decoders are recommended to be compatible with `Window_Size >= 8 MB`,
+decoders are recommended to be compatible with `Window_Size <= 8 MB`,
and encoders are recommended to not request more than 8 MB.
It's merely a recommendation though,
decoders are free to support larger or lower limits,
From 6ff43c00511577cdd1f1b560965d5c2104821897 Mon Sep 17 00:00:00 2001
From: Shawn Landden
Date: Sun, 24 Dec 2017 10:05:43 -0800
Subject: [PATCH 003/255] get soversion right
---
contrib/meson/meson.build | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/contrib/meson/meson.build b/contrib/meson/meson.build
index ce3fb83e3..b045c9944 100644
--- a/contrib/meson/meson.build
+++ b/contrib/meson/meson.build
@@ -84,7 +84,9 @@ libzstd = library('zstd',
include_directories: libzstd_includes,
c_args: libzstd_cflags,
dependencies: libzstd_deps,
- install: true)
+ install: true,
+ soversion: '1',
+ )
programs_dir = join_paths('..', '..', 'programs')
From c707c6e9f27e2720c69d7461a50fdc74e4f4889f Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 27 Dec 2017 13:32:05 +0100
Subject: [PATCH 004/255] fix: bench can accept hlog custom parameter
was ignored during initialization
---
programs/bench.c | 1 +
programs/zstdcli.c | 5 +++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/programs/bench.c b/programs/bench.c
index 5d2568f10..843920c89 100644
--- a/programs/bench.c
+++ b/programs/bench.c
@@ -307,6 +307,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog);
}
ZSTD_CCtx_setParameter(ctx, ZSTD_p_windowLog, comprParams->windowLog);
+ ZSTD_CCtx_setParameter(ctx, ZSTD_p_hashLog, comprParams->hashLog);
ZSTD_CCtx_setParameter(ctx, ZSTD_p_chainLog, comprParams->chainLog);
ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog);
ZSTD_CCtx_setParameter(ctx, ZSTD_p_minMatch, comprParams->searchLength);
diff --git a/programs/zstdcli.c b/programs/zstdcli.c
index 7e29998b0..eae208c52 100644
--- a/programs/zstdcli.c
+++ b/programs/zstdcli.c
@@ -318,12 +318,13 @@ static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressi
if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmslen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=") || longCommandWArg(&stringPtr, "ldmblog=")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
if (longCommandWArg(&stringPtr, "ldmHashEveryLog=") || longCommandWArg(&stringPtr, "ldmhevery=")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
+ DISPLAYLEVEL(4, "invalid compression parameter \n");
return 0;
}
+ DISPLAYLEVEL(4, "windowLog=%d, chainLog=%d, hashLog=%d, searchLog=%d \n", params->windowLog, params->chainLog, params->hashLog, params->searchLog);
+ DISPLAYLEVEL(4, "searchLength=%d, targetLength=%d, strategy=%d \n", params->searchLength, params->targetLength, params->strategy);
if (stringPtr[0] != 0) return 0; /* check the end of string */
- DISPLAYLEVEL(4, "windowLog=%d\nchainLog=%d\nhashLog=%d\nsearchLog=%d\n", params->windowLog, params->chainLog, params->hashLog, params->searchLog);
- DISPLAYLEVEL(4, "searchLength=%d\ntargetLength=%d\nstrategy=%d\n", params->searchLength, params->targetLength, params->strategy);
return 1;
}
From 2126ca8a5f3a4cb2a19c5b2923f4f9bb7f41f630 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 27 Dec 2017 17:49:18 +0100
Subject: [PATCH 005/255] %.o objects files in /tests
Recipe in /tests rebuild everything from source for each target.
zstd is still a "small" project, so it's not prohibitive,
yet, rebuilding same files over and over represents substantial redundant work.
This patch replaces *.c files from /lib by their corresponding *.o files.
They cannot be compiled and stored directly within /lib,
since /tests triggers additional debug capabilities unwelcome in release binary.
So the resulting *.o are stored directly within /tests.
It turns out, it's difficult to find several target using *exactly* the same rules.
Using only the default rules (debug enabled, multi-threading disabled, no legacy)
a surprisingly small amount of targets share their work.
It's because, in many cases there are additional modifications requested :
some targets are 32-bits, some enable multi-threading, some enable legacy support,
some disable asserts, some want different kind of sanitizer, etc.
I created 2 sets of object files : with and without multithreading.
Several targets share their work, saving compilation time when running `make all`.
Also, obviously, when modifying one source file, only this one needs rebuilding.
For targets requiring some different setting, build from source *.c remain the rule.
The new rules have been tested within `-j` parallel compilation, and work fine with it.
---
tests/Makefile | 129 ++++++++++++++++++++++++++++--------------
tests/namespaceTest.c | 24 --------
2 files changed, 87 insertions(+), 66 deletions(-)
delete mode 100644 tests/namespaceTest.c
diff --git a/tests/Makefile b/tests/Makefile
index 853f4ee89..258212db1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -21,7 +21,7 @@
ZSTDDIR = ../lib
PRGDIR = ../programs
PYTHON ?= python3
-TESTARTEFACT := versionsTest namespaceTest
+TESTARTEFACT := versionsTest
DEBUGLEVEL ?= 1
DEBUGFLAGS = -g -DZSTD_DEBUG=$(DEBUGLEVEL)
@@ -44,6 +44,16 @@ ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES)
ZBUFF_FILES := $(ZSTDDIR)/deprecated/*.c
ZDICT_FILES := $(ZSTDDIR)/dictBuilder/*.c
+ZSTD_F1 := $(wildcard $(ZSTD_FILES))
+ZSTD_OBJ1 := $(subst $(ZSTDDIR)/common/,zstdm_,$(ZSTD_F1))
+ZSTD_OBJ2 := $(subst $(ZSTDDIR)/compress/,zstdc_,$(ZSTD_OBJ1))
+ZSTD_OBJ3 := $(subst $(ZSTDDIR)/decompress/,zstdd_,$(ZSTD_OBJ2))
+ZSTD_OBJECTS := $(ZSTD_OBJ3:.c=.o)
+
+ZSTDMT_OBJ1 := $(subst $(ZSTDDIR)/common/,zstdmt_m_,$(ZSTD_F1))
+ZSTDMT_OBJ2 := $(subst $(ZSTDDIR)/compress/,zstdmt_c_,$(ZSTDMT_OBJ1))
+ZSTDMT_OBJ3 := $(subst $(ZSTDDIR)/decompress/,zstdmt_d_,$(ZSTDMT_OBJ2))
+ZSTDMT_OBJECTS := $(ZSTDMT_OBJ3:.c=.o)
# Define *.exe as extension for Windows systems
ifneq (,$(filter Windows%,$(OS)))
@@ -63,11 +73,12 @@ FUZZERTEST ?= -T200s
ZSTDRTTEST = --test-large-data
DECODECORPUS_TESTTIME ?= -T30
-.PHONY: default all all32 allnothread dll clean test test32 test-all namespaceTest versionsTest
+.PHONY: default all all32 allnothread dll clean test test32 test-all versionsTest
default: fullbench
+ @echo $(ZSTDMT_OBJECTS)
-all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus
+all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus roundTripCrash
all32: fullbench32 fuzzer32 zstreamtest32
@@ -87,35 +98,69 @@ zstd-nolegacy:
gzstd:
$(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 MOREFLAGS="$(DEBUGFLAGS)"
+.PHONY:
+zstd-dll :
+ $(MAKE) -C $(ZSTDDIR) libzstd
+
+.PHONY:
+zstd-staticLib :
+ $(MAKE) -C $(ZSTDDIR) libzstd.a
+
+zstdm_%.o : $(ZSTDDIR)/common/%.c
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+zstdc_%.o : $(ZSTDDIR)/compress/%.c
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+zstdd_%.o : $(ZSTDDIR)/decompress/%.c
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+zstdmt%.o : CPPFLAGS += -DZSTD_MULTITHREAD=1
+
+zstdmt_m_%.o : $(ZSTDDIR)/common/%.c
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+zstdmt_c_%.o : $(ZSTDDIR)/compress/%.c
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+zstdmt_d_%.o : $(ZSTDDIR)/decompress/%.c
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
fullbench32: CPPFLAGS += -m32
fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP)
fullbench fullbench32 : LDFLAGS += $(MULTITHREAD_LD)
fullbench fullbench32 : DEBUGFLAGS = # turn off assert() for speed measurements
-fullbench fullbench32 : $(ZSTD_FILES) $(PRGDIR)/datagen.c fullbench.c
+fullbench fullbench32 : $(ZSTD_FILES)
+fullbench fullbench32 : $(PRGDIR)/datagen.c fullbench.c
$(CC) $(FLAGS) $^ -o $@$(EXT)
-fullbench-lib: $(PRGDIR)/datagen.c fullbench.c
- $(MAKE) -C $(ZSTDDIR) libzstd.a
- $(CC) $(FLAGS) $^ -o $@$(EXT) $(ZSTDDIR)/libzstd.a
+fullbench-lib : zstd-staticLib
+fullbench-lib : $(PRGDIR)/datagen.c fullbench.c
+ $(CC) $(FLAGS) $(filter %.c,$^) -o $@$(EXT) $(ZSTDDIR)/libzstd.a
+# note : broken : requires unavailable symbols
+fullbench-dll : zstd-dll
+fullbench-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
fullbench-dll: $(PRGDIR)/datagen.c fullbench.c
- $(MAKE) -C $(ZSTDDIR) libzstd
- $(CC) $(FLAGS) $^ -o $@$(EXT) -DZSTD_DLL_IMPORT=1 $(ZSTDDIR)/dll/libzstd.dll
+# $(CC) $(FLAGS) $(filter %.c,$^) -o $@$(EXT) -DZSTD_DLL_IMPORT=1 $(ZSTDDIR)/dll/libzstd.dll
+ $(CC) $(FLAGS) $(filter %.c,$^) -o $@$(EXT)
-fuzzer : CPPFLAGS += $(MULTITHREAD_CPP)
-fuzzer : LDFLAGS += $(MULTITHREAD_LD)
+fuzzer : CPPFLAGS += $(MULTITHREAD_CPP)
+fuzzer : LDFLAGS += $(MULTITHREAD_LD)
fuzzer32: CFLAGS += -m32
-fuzzer fuzzer32 : $(ZSTD_FILES) $(ZDICT_FILES) $(PRGDIR)/datagen.c fuzzer.c
+fuzzer : $(ZSTDMT_OBJECTS)
+fuzzer32: $(ZSTD_FILES)
+fuzzer fuzzer32 : $(ZDICT_FILES) $(PRGDIR)/datagen.c fuzzer.c
$(CC) $(FLAGS) $^ -o $@$(EXT)
+fuzzer-dll : zstd-dll
fuzzer-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
fuzzer-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c fuzzer.c
- $(MAKE) -C $(ZSTDDIR) libzstd
- $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@$(EXT)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(filter %.c,$^) $(LDFLAGS) -o $@$(EXT)
zbufftest : CPPFLAGS += -I$(ZSTDDIR)/deprecated
zbufftest : CFLAGS += -Wno-deprecated-declarations # required to silence deprecation warnings
-zbufftest : $(ZSTD_FILES) $(ZBUFF_FILES) $(PRGDIR)/datagen.c zbufftest.c
+zbufftest : $(ZSTD_OBJECTS) $(ZBUFF_FILES) $(PRGDIR)/datagen.c zbufftest.c
$(CC) $(FLAGS) $^ -o $@$(EXT)
zbufftest32 : CPPFLAGS += -I$(ZSTDDIR)/deprecated
@@ -123,18 +168,22 @@ zbufftest32 : CFLAGS += -Wno-deprecated-declarations -m32
zbufftest32 : $(ZSTD_FILES) $(ZBUFF_FILES) $(PRGDIR)/datagen.c zbufftest.c
$(CC) $(FLAGS) $^ -o $@$(EXT)
+zbufftest-dll : zstd-dll
zbufftest-dll : CPPFLAGS += -I$(ZSTDDIR)/deprecated
zbufftest-dll : CFLAGS += -Wno-deprecated-declarations # required to silence deprecation warnings
zbufftest-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
zbufftest-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c zbufftest.c
- $(MAKE) -C $(ZSTDDIR) libzstd
- $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@$(EXT)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(filter %.c,$^) $(LDFLAGS) -o $@$(EXT)
-ZSTREAMFILES := $(ZSTD_FILES) $(ZDICT_FILES) $(PRGDIR)/datagen.c seqgen.c zstreamtest.c
+ZSTREAM_LOCAL_FILES := $(PRGDIR)/datagen.c seqgen.c zstreamtest.c
+ZSTREAM_PROPER_FILES := $(ZDICT_FILES) $(ZSTREAM_LOCAL_FILES)
+ZSTREAMFILES := $(ZSTD_FILES) $(ZSTREAM_PROPER_FILES)
zstreamtest32 : CFLAGS += -m32
zstreamtest zstreamtest32 : CPPFLAGS += $(MULTITHREAD_CPP)
zstreamtest zstreamtest32 : LDFLAGS += $(MULTITHREAD_LD)
-zstreamtest zstreamtest32 : $(ZSTREAMFILES)
+zstreamtest : $(ZSTDMT_OBJECTS) $(ZSTREAM_PROPER_FILES)
+zstreamtest32 : $(ZSTREAMFILES)
+zstreamtest zstreamtest32 :
$(CC) $(FLAGS) $^ -o $@$(EXT)
zstreamtest_asan : CFLAGS += -fsanitize=address
@@ -145,51 +194,47 @@ zstreamtest_tsan : CFLAGS += -fsanitize=thread
zstreamtest_tsan : $(ZSTREAMFILES)
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
+zstreamtest-dll : zstd-dll
zstreamtest-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
-zstreamtest-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c zstreamtest.c
- $(MAKE) -C $(ZSTDDIR) libzstd
- $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@$(EXT)
+zstreamtest-dll : $(ZSTDDIR)/common/xxhash.c # xxh symbols not exposed from dll
+zstreamtest-dll : $(ZSTREAM_LOCAL_FILES)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(filter %.c,$^) $(LDFLAGS) -o $@$(EXT)
-paramgrill : DEBUGFLAGS =
+paramgrill : DEBUGFLAGS = # turn off assert() for speed measurements
paramgrill : $(ZSTD_FILES) $(PRGDIR)/datagen.c paramgrill.c
- $(CC) $(FLAGS) $^ -lm -o $@$(EXT)
+ $(CC) $(FLAGS) $^ -lm -o $@$(EXT)
datagen : $(PRGDIR)/datagen.c datagencli.c
- $(CC) $(FLAGS) $^ -o $@$(EXT)
+ $(CC) $(FLAGS) $^ -o $@$(EXT)
-roundTripCrash : $(ZSTD_FILES) roundTripCrash.c
- $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
+roundTripCrash : $(ZSTD_OBJECTS) roundTripCrash.c
+ $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
-longmatch : $(ZSTD_FILES) longmatch.c
- $(CC) $(FLAGS) $^ -o $@$(EXT)
+longmatch : $(ZSTD_OBJECTS) longmatch.c
+ $(CC) $(FLAGS) $^ -o $@$(EXT)
-invalidDictionaries : $(ZSTD_FILES) invalidDictionaries.c
- $(CC) $(FLAGS) $^ -o $@$(EXT)
+invalidDictionaries : $(ZSTD_OBJECTS) invalidDictionaries.c
+ $(CC) $(FLAGS) $^ -o $@$(EXT)
legacy : CFLAGS+= -DZSTD_LEGACY_SUPPORT=4
legacy : CPPFLAGS+= -I$(ZSTDDIR)/legacy
legacy : $(ZSTD_FILES) $(wildcard $(ZSTDDIR)/legacy/*.c) legacy.c
- $(CC) $(FLAGS) $^ -o $@$(EXT)
+ $(CC) $(FLAGS) $^ -o $@$(EXT)
-decodecorpus : $(filter-out $(ZSTDDIR)/compress/zstd_compress.c, $(wildcard $(ZSTD_FILES))) $(ZDICT_FILES) decodecorpus.c
- $(CC) $(FLAGS) $^ -o $@$(EXT) -lm
+decodecorpus : $(filter-out zstdc_zstd_compress.o, $(ZSTD_OBJECTS)) $(ZDICT_FILES) decodecorpus.c
+ $(CC) $(FLAGS) $^ -o $@$(EXT) -lm
-symbols : symbols.c
- $(MAKE) -C $(ZSTDDIR) libzstd
+symbols : symbols.c zstd-dll
ifneq (,$(filter Windows%,$(OS)))
cp $(ZSTDDIR)/dll/libzstd.dll .
- $(CC) $(FLAGS) $^ -o $@$(EXT) -DZSTD_DLL_IMPORT=1 libzstd.dll
+ $(CC) $(FLAGS) $< -o $@$(EXT) -DZSTD_DLL_IMPORT=1 libzstd.dll
else
- $(CC) $(FLAGS) $^ -o $@$(EXT) -Wl,-rpath=$(ZSTDDIR) $(ZSTDDIR)/libzstd.so
+ $(CC) $(FLAGS) $< -o $@$(EXT) -Wl,-rpath=$(ZSTDDIR) $(ZSTDDIR)/libzstd.so # broken on Mac
endif
poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c $(ZSTDDIR)/common/zstd_common.c $(ZSTDDIR)/common/error_private.c
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
-namespaceTest:
- if $(CC) namespaceTest.c ../lib/common/xxhash.c -o $@ ; then echo compilation should fail; exit 1 ; fi
- $(RM) $@
-
versionsTest: clean
$(PYTHON) test-zstd-versions.py
diff --git a/tests/namespaceTest.c b/tests/namespaceTest.c
deleted file mode 100644
index 5b7095f67..000000000
--- a/tests/namespaceTest.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2016-present, 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 /* size_t */
-#include /* strlen */
-
-/* symbol definition */
-extern unsigned XXH32(const void* src, size_t srcSize, unsigned seed);
-
-int main(int argc, const char** argv)
-{
- const char* exename = argv[0];
- unsigned result = XXH32(exename, strlen(exename), argc);
- return !result;
-}
From 63aebdf9ea7a04e3965389fcdbfe5bfb94a0cc12 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 27 Dec 2017 19:27:54 +0100
Subject: [PATCH 006/255] windows ci : removed fullbench-dll from appveyor
the test is broken
previous version was too Windows-specific.
It needs to be either refactored to be cross-platform,
or be removed if it doesn't bring any value
(which is indeed unclear).
---
appveyor.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/appveyor.yml b/appveyor.yml
index 0f9142b47..7d6ca99bb 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -9,7 +9,7 @@
- COMPILER: "gcc"
HOST: "mingw"
PLATFORM: "x64"
- SCRIPT: "make allzstd MOREFLAGS=-static && make -C tests test-symbols fullbench-dll fullbench-lib"
+ SCRIPT: "make allzstd MOREFLAGS=-static && make -C tests test-symbols fullbench-lib"
ARTIFACT: "true"
BUILD: "true"
- COMPILER: "gcc"
From 5235d8d6ba523ee655f4966f95f59987f13cfae9 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Thu, 28 Dec 2017 16:58:57 +0100
Subject: [PATCH 007/255] first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1< 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
---
lib/compress/zstd_compress.c | 6 +-
lib/compress/zstd_lazy.c | 317 +++++++++++++++++++----------------
lib/compress/zstd_lazy.h | 5 +-
lib/compress/zstd_opt.c | 141 ++++++++++++++++
lib/compress/zstd_opt.h | 3 +
5 files changed, 322 insertions(+), 150 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 8d1629246..bafc1ce95 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -1922,6 +1922,10 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
break;
case ZSTD_btlazy2:
+ if (srcSize >= HASH_READ_SIZE)
+ ZSTD_updateDUBT(zc, iend-HASH_READ_SIZE, iend, zc->appliedParams.cParams.searchLength);
+ break;
+
case ZSTD_btopt:
case ZSTD_btultra:
if (srcSize >= HASH_READ_SIZE)
@@ -2974,7 +2978,7 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
{ 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
{ 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
{ 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
- { 22, 21, 22, 4, 5, 16, ZSTD_btlazy2 }, /* level 15 */
+ { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
{ 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */
{ 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */
{ 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 6d4804961..431157741 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -15,73 +15,85 @@
/*-*************************************
* Binary Tree search
***************************************/
-/** ZSTD_insertBt1() : add one or multiple positions to tree.
- * ip : assumed <= iend-8 .
- * @return : nb of positions added */
-static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- U32 nbCompares, U32 const mls, U32 const extDict)
+#define ZSTD_DUBT_UNSORTED ((U32)(-1))
+
+void ZSTD_updateDUBT(ZSTD_CCtx* zc,
+ const BYTE* ip, const BYTE* iend,
+ U32 mls)
+{
+ U32* const hashTable = zc->hashTable;
+ U32 const hashLog = zc->appliedParams.cParams.hashLog;
+
+ U32* const bt = zc->chainTable;
+ U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+
+ const BYTE* const base = zc->base;
+ U32 const target = (U32)(ip - base);
+ U32 idx = zc->nextToUpdate;
+
+ DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u ",
+ idx, target);
+ assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
+ (void)iend;
+
+
+ assert(idx >= zc->dictLimit); /* condition for valid base+idx */
+ for ( ; idx < target ; idx++) {
+ size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls); /* assumption : ip + 8 <= iend */
+ U32 const matchIndex = hashTable[h];
+
+ U32* const nextCandidatePtr = bt + 2*(idx&btMask);
+ U32* const sortMarkPtr = nextCandidatePtr + 1;
+
+ hashTable[h] = idx; /* Update Hash Table */
+ *nextCandidatePtr = matchIndex; /* update BT like a chain */
+ *sortMarkPtr = ZSTD_DUBT_UNSORTED;
+ }
+ zc->nextToUpdate = target;
+}
+
+
+/** ZSTD_insertDUBT1() :
+ * sort one already inserted but unsorted position
+ * assumption : current >= btlow == (current - btmask)
+ * doesn't fail */
+static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
+ U32 current, const BYTE* iend,
+ U32 nbCompares, U32 btLow, int extDict)
{
- U32* const hashTable = zc->hashTable;
- U32 const hashLog = zc->appliedParams.cParams.hashLog;
- size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
U32* const bt = zc->chainTable;
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
U32 const btMask = (1 << btLog) - 1;
- U32 matchIndex = hashTable[h];
size_t commonLengthSmaller=0, commonLengthLarger=0;
const BYTE* const base = zc->base;
+ const BYTE* const ip = base + current;
const BYTE* const dictBase = zc->dictBase;
const U32 dictLimit = zc->dictLimit;
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);
U32* largerPtr = smallerPtr + 1;
+ U32 matchIndex = *smallerPtr;
U32 dummy32; /* to be nullified at the end */
U32 const windowLow = zc->lowLimit;
- U32 matchEndIdx = current+8+1;
- size_t bestLength = 8;
-#ifdef ZSTD_C_PREDICT
- U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
- U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
- predictedSmall += (predictedSmall>0);
- predictedLarge += (predictedLarge>0);
-#endif /* ZSTD_C_PREDICT */
- DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
+ DEBUGLOG(8, "ZSTD_insertDUBT1 (%u)", current);
+ assert(current >= btLow);
- assert(ip <= iend-8); /* required for h calculation */
- hashTable[h] = current; /* Update Hash Table */
+ if (extDict && (current < dictLimit)) { /* do not sort candidates in _extDict (simplification, for easier ZSTD_count, detrimental to compression ratio in streaming mode) */
+ *largerPtr = *smallerPtr = 0;
+ return;
+ }
+ assert(current >= dictLimit); /* ip=base+current within current memory segment */
while (nbCompares-- && (matchIndex > windowLow)) {
U32* const nextPtr = bt + 2*(matchIndex & btMask);
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u", current, matchIndex);
assert(matchIndex < current);
-#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 */
- if (matchIndex == predictedSmall) {
- /* no need to check length, result known */
- *smallerPtr = matchIndex;
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
- predictedSmall = predictPtr[1] + (predictPtr[1]>0);
- continue;
- }
- if (matchIndex == predictedLarge) {
- *largerPtr = matchIndex;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- predictedLarge = predictPtr[0] + (predictPtr[0]>0);
- continue;
- }
-#endif
-
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
assert(matchIndex+matchLength >= dictLimit); /* might be wrong if extDict is incorrectly set to 0 */
match = base + matchIndex;
@@ -93,12 +105,6 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
}
- if (matchLength > bestLength) {
- bestLength = matchLength;
- if (matchLength > matchEndIdx - matchIndex)
- matchEndIdx = 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 */
}
@@ -108,6 +114,8 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
*smallerPtr = matchIndex; /* update smaller idx */
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ DEBUGLOG(8, "ZSTD_insertDUBT1: selecting next candidate from %u (>btLow=%u) => %u",
+ matchIndex, btLow, nextPtr[1]);
smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
} else {
@@ -115,125 +123,142 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
*largerPtr = matchIndex;
commonLengthLarger = matchLength;
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ DEBUGLOG(8, "ZSTD_insertDUBT1: selecting next candidate from %u (>btLow=%u) => %u",
+ matchIndex, btLow, nextPtr[0]);
largerPtr = nextPtr;
matchIndex = nextPtr[0];
} }
*smallerPtr = *largerPtr = 0;
- if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
- assert(matchEndIdx > current + 8);
- return matchEndIdx - (current + 8);
-}
-
-FORCE_INLINE_TEMPLATE
-void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- const U32 nbCompares, const U32 mls, const U32 extDict)
-{
- const BYTE* const base = zc->base;
- U32 const target = (U32)(ip - base);
- U32 idx = zc->nextToUpdate;
- DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (extDict:%u)",
- idx, target, extDict);
-
- while(idx < target)
- idx += ZSTD_insertBt1(zc, base+idx, iend, nbCompares, mls, extDict);
- zc->nextToUpdate = target;
-}
-
-void ZSTD_updateTree(ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- const U32 nbCompares, const U32 mls)
-{
- ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
-}
-
-void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- const U32 nbCompares, const U32 mls)
-{
- ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 1 /*extDict*/);
}
static size_t ZSTD_insertBtAndFindBestMatch (
- ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- size_t* offsetPtr,
- U32 nbCompares, const U32 mls,
- U32 extDict)
+ ZSTD_CCtx* zc,
+ const BYTE* const ip, const BYTE* const iend,
+ size_t* offsetPtr,
+ U32 nbCompares, const U32 mls,
+ U32 extDict)
{
U32* const hashTable = zc->hashTable;
U32 const hashLog = zc->appliedParams.cParams.hashLog;
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 matchIndex = hashTable[h];
+
+ const BYTE* const base = zc->base;
+ U32 const current = (U32)(ip-base);
+
U32* const bt = zc->chainTable;
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
U32 const btMask = (1 << btLog) - 1;
- U32 matchIndex = hashTable[h];
- size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const base = zc->base;
- const BYTE* const dictBase = zc->dictBase;
- const U32 dictLimit = zc->dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const U32 current = (U32)(ip-base);
- const U32 btLow = btMask >= current ? 0 : current - btMask;
- const U32 windowLow = zc->lowLimit;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = bt + 2*(current&btMask) + 1;
- U32 matchEndIdx = current+8+1;
- U32 dummy32; /* to be nullified at the end */
- size_t bestLength = 0;
+ U32 const btLow = (btMask >= current) ? 0 : current - btMask;
+ U32* nextCandidate = bt + 2*(matchIndex&btMask);
+ U32* unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+ U32 nbCandidates = nbCompares;
+ U32 previousCandidate = 0;
+
+ DEBUGLOG(7, "ZSTD_insertBtAndFindBestMatch (%u) ", current);
assert(ip <= iend-8); /* required for h calculation */
- hashTable[h] = current; /* Update Hash Table */
- while (nbCompares-- && (matchIndex > windowLow)) {
- U32* const nextPtr = bt + 2*(matchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- const BYTE* match;
+ /* reach end of unsorted candidates list */
+ while ( (matchIndex > btLow)
+ && (*unsortedMark == ZSTD_DUBT_UNSORTED)
+ && (nbCandidates > 1) ) {
+ DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: candidate %u is unsorted",
+ matchIndex);
+ *unsortedMark = previousCandidate;
+ previousCandidate = matchIndex;
+ matchIndex = *nextCandidate;
+ nextCandidate = bt + 2*(matchIndex&btMask);
+ unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+ nbCandidates --;
+ }
- if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
- match = base + matchIndex;
- matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
- } else {
- match = dictBase + matchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
- }
+ if ( (matchIndex > btLow)
+ && (*unsortedMark==ZSTD_DUBT_UNSORTED) ) {
+ DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: nullify last unsorted candidate %u",
+ matchIndex);
+ *nextCandidate = *unsortedMark = 0; /* nullify last candidate if it's still unsorted (note : detrimental to compression ratio) */
+ }
- 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 (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
- break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ /* batch sort stacked candidates */
+ matchIndex = previousCandidate;
+ while (matchIndex) { /* will end on matchIndex == 0 */
+ U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
+ U32 const nextCandidateIdx = *nextCandidateIdxPtr;
+ ZSTD_insertDUBT1(zc, matchIndex, iend,
+ nbCandidates, btLow, extDict);
+ matchIndex = nextCandidateIdx;
+ nbCandidates++;
+ }
+
+ /* find longest match */
+ { size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const dictBase = zc->dictBase;
+ const U32 dictLimit = zc->dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const U32 windowLow = zc->lowLimit;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = bt + 2*(current&btMask) + 1;
+ U32 matchEndIdx = current+8+1;
+ U32 dummy32; /* to be nullified at the end */
+ size_t bestLength = 0;
+
+ matchIndex = hashTable[h];
+ hashTable[h] = current; /* Update Hash Table */
+
+ while (nbCompares-- && (matchIndex > windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match;
+
+ if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
+ match = base + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
}
- }
- if (match[matchLength] < ip[matchLength]) {
- /* match is smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
- } else {
- /* match is larger than current */
- *largerPtr = matchIndex;
- commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- } }
+ 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 (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ }
+ }
- *smallerPtr = *largerPtr = 0;
+ if (match[matchLength] < ip[matchLength]) {
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
- assert(matchEndIdx > current+8);
- zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
- return bestLength;
+ *smallerPtr = *largerPtr = 0;
+
+ assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
+ zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
+ if (bestLength)
+ DEBUGLOG(7, "ZSTD_insertBtAndFindBestMatch(%u) : found match of length %u",
+ current, (U32)bestLength);
+ return bestLength;
+ }
}
@@ -245,7 +270,7 @@ static size_t ZSTD_BtFindBestMatch (
const U32 maxNbAttempts, const U32 mls)
{
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
- ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
+ ZSTD_updateDUBT(zc, ip, iLimit, mls);
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
}
@@ -275,7 +300,7 @@ static size_t ZSTD_BtFindBestMatch_extDict (
const U32 maxNbAttempts, const U32 mls)
{
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
- ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
+ ZSTD_updateDUBT(zc, ip, iLimit, mls);
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
}
diff --git a/lib/compress/zstd_lazy.h b/lib/compress/zstd_lazy.h
index 74e1fd697..8918e5ca4 100644
--- a/lib/compress/zstd_lazy.h
+++ b/lib/compress/zstd_lazy.h
@@ -18,9 +18,8 @@ extern "C" {
#include "mem.h" /* U32 */
#include "zstd.h" /* ZSTD_CCtx, size_t */
-U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls);
-void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
-void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
+U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls); /* used in ZSTD_loadDictionaryContent() */
+void ZSTD_updateDUBT(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iend, U32 mls); /* used in ZSTD_loadDictionaryContent() */
size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c
index 7171ff537..6af5c7111 100644
--- a/lib/compress/zstd_opt.c
+++ b/lib/compress/zstd_opt.c
@@ -265,6 +265,147 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* const cctx, const BYTE*
/*-*************************************
* Binary Tree search
***************************************/
+/** ZSTD_insertBt1() : add one or multiple positions to tree.
+ * ip : assumed <= iend-8 .
+ * @return : nb of positions added */
+static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
+ const BYTE* const ip, const BYTE* const iend,
+ U32 nbCompares, U32 const mls, U32 const extDict)
+{
+ U32* const hashTable = zc->hashTable;
+ U32 const hashLog = zc->appliedParams.cParams.hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32* const bt = zc->chainTable;
+ U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 matchIndex = hashTable[h];
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const base = zc->base;
+ const BYTE* const dictBase = zc->dictBase;
+ const U32 dictLimit = zc->dictLimit;
+ 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);
+ U32* largerPtr = smallerPtr + 1;
+ U32 dummy32; /* to be nullified at the end */
+ U32 const windowLow = zc->lowLimit;
+ U32 matchEndIdx = current+8+1;
+ size_t bestLength = 8;
+#ifdef ZSTD_C_PREDICT
+ U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
+ U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
+ predictedSmall += (predictedSmall>0);
+ predictedLarge += (predictedLarge>0);
+#endif /* ZSTD_C_PREDICT */
+
+ DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
+
+ assert(ip <= iend-8); /* required for h calculation */
+ hashTable[h] = current; /* Update Hash Table */
+
+ while (nbCompares-- && (matchIndex > windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ assert(matchIndex < current);
+
+#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 */
+ if (matchIndex == predictedSmall) {
+ /* no need to check length, result known */
+ *smallerPtr = matchIndex;
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ predictedSmall = predictPtr[1] + (predictPtr[1]>0);
+ continue;
+ }
+ if (matchIndex == predictedLarge) {
+ *largerPtr = matchIndex;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ predictedLarge = predictPtr[0] + (predictPtr[0]>0);
+ continue;
+ }
+#endif
+
+ if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
+ assert(matchIndex+matchLength >= dictLimit); /* might be wrong if extDict is incorrectly set to 0 */
+ match = base + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ }
+
+ if (matchLength > bestLength) {
+ bestLength = matchLength;
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = 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 */
+ }
+
+ if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
+ matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+ if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
+ assert(matchEndIdx > current + 8);
+ return matchEndIdx - (current + 8);
+}
+
+FORCE_INLINE_TEMPLATE
+void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
+ const BYTE* const ip, const BYTE* const iend,
+ const U32 nbCompares, const U32 mls, const U32 extDict)
+{
+ const BYTE* const base = zc->base;
+ U32 const target = (U32)(ip - base);
+ U32 idx = zc->nextToUpdate;
+ DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (extDict:%u)",
+ idx, target, extDict);
+
+ while(idx < target)
+ idx += ZSTD_insertBt1(zc, base+idx, iend, nbCompares, mls, extDict);
+ zc->nextToUpdate = target;
+}
+
+void ZSTD_updateTree(ZSTD_CCtx* zc,
+ const BYTE* const ip, const BYTE* const iend,
+ const U32 nbCompares, const U32 mls)
+{
+ ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
+}
+
+void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
+ const BYTE* const ip, const BYTE* const iend,
+ const U32 nbCompares, const U32 mls)
+{
+ ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 1 /*extDict*/);
+}
+
+
FORCE_INLINE_TEMPLATE
U32 ZSTD_insertBtAndGetAllMatches (
ZSTD_CCtx* zc,
diff --git a/lib/compress/zstd_opt.h b/lib/compress/zstd_opt.h
index 82e810c29..b803a0f2e 100644
--- a/lib/compress/zstd_opt.h
+++ b/lib/compress/zstd_opt.h
@@ -15,8 +15,11 @@
extern "C" {
#endif
+#include "mem.h" /* U32 */
#include "zstd.h" /* ZSTD_CCtx, size_t */
+void ZSTD_updateTree(ZSTD_CCtx* ctx, const BYTE* ip, const BYTE* iend, U32 nbCompares, U32 mls); /* used in ZSTD_loadDictionaryContent() */
+
size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
From ffc335bccf4ae80311a6fbe0e687d0198cb35a64 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Fri, 29 Dec 2017 14:39:49 +0100
Subject: [PATCH 008/255] complete ignore list
fuzz tests artifacts
---
tests/fuzz/.gitignore | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tests/fuzz/.gitignore b/tests/fuzz/.gitignore
index 4ff28de98..9409cf837 100644
--- a/tests/fuzz/.gitignore
+++ b/tests/fuzz/.gitignore
@@ -2,4 +2,7 @@
corpora
block_decompress
block_round_trip
+simple_decompress
simple_round_trip
+stream_decompress
+stream_round_trip
From f36da5b4d9f6e382c7045124c015fdeaec7345ca Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Fri, 29 Dec 2017 14:40:33 +0100
Subject: [PATCH 009/255] minor speed optimization : index overflow prevention
new code supposed to be easier to auto-vectorize
---
lib/compress/zstd_compress.c | 81 ++++++++++++++++++++----------------
1 file changed, 46 insertions(+), 35 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index bafc1ce95..91e281660 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -59,18 +59,16 @@ ZSTD_CCtx* ZSTD_createCCtx(void)
ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
{
- ZSTD_CCtx* cctx;
-
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
-
- cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
- if (!cctx) return NULL;
- cctx->customMem = customMem;
- cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
- cctx->requestedParams.fParams.contentSizeFlag = 1;
ZSTD_STATIC_ASSERT(zcss_init==0);
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
- return cctx;
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+ { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
+ if (!cctx) return NULL;
+ cctx->customMem = customMem;
+ cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
+ cctx->requestedParams.fParams.contentSizeFlag = 1;
+ return cctx;
+ }
}
ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
@@ -95,13 +93,10 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
{
if (cctx==NULL) return 0; /* support free on NULL */
if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
- ZSTD_free(cctx->workSpace, cctx->customMem);
- cctx->workSpace = NULL;
- ZSTD_freeCDict(cctx->cdictLocal);
- cctx->cdictLocal = NULL;
+ ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL;
+ ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL;
#ifdef ZSTD_MULTITHREAD
- ZSTDMT_freeCCtx(cctx->mtctx);
- cctx->mtctx = NULL;
+ ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
#endif
ZSTD_free(cctx, cctx->customMem);
return 0; /* reserved as a potential error code in the future */
@@ -122,10 +117,6 @@ static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
{
if (cctx==NULL) return 0; /* support sizeof on NULL */
- DEBUGLOG(3, "sizeof(*cctx) : %u", (U32)sizeof(*cctx));
- DEBUGLOG(3, "workSpaceSize (including streaming buffers): %u", (U32)cctx->workSpaceSize);
- DEBUGLOG(3, "inner cdict : %u", (U32)ZSTD_sizeof_CDict(cctx->cdictLocal));
- DEBUGLOG(3, "inner MTCTX : %u", (U32)ZSTD_sizeof_mtctx(cctx));
return sizeof(*cctx) + cctx->workSpaceSize
+ ZSTD_sizeof_CDict(cctx->cdictLocal)
+ ZSTD_sizeof_mtctx(cctx);
@@ -1085,15 +1076,31 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long
}
+#define ZSTD_ROWSIZE 16
+/*! ZSTD_reduceTable_internal() :
+ * reduce table indexes by `reducerValue`
+ * presume table size is a multiple of ZSTD_ROWSIZE.
+ * Helps auto-vectorization */
+static void ZSTD_reduceTable_internal (U32* const table, int const nbRows, U32 const reducerValue)
+{
+ int cellNb = 0;
+ int rowNb;
+ for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
+ int column;
+ for (column=0; columnappliedParams.cParams.hashLog;
- ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
+ { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
+ ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);
+ }
- { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((U32)1 << zc->appliedParams.cParams.chainLog);
- ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
+ if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
+ U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
+ ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
+ }
- { U32 const h3Size = (zc->hashLog3) ? (U32)1 << zc->hashLog3 : 0;
- ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
+ if (zc->hashLog3) {
+ U32 const h3Size = (U32)1 << zc->hashLog3;
+ ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue);
+ }
- { if (zc->appliedParams.ldmParams.enableLdm) {
- U32 const ldmHSize = (U32)1 << zc->appliedParams.ldmParams.hashLog;
- ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue);
- }
+ if (zc->appliedParams.ldmParams.enableLdm) {
+ U32 const ldmHSize = (U32)1 << zc->appliedParams.ldmParams.hashLog;
+ ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue);
}
}
From 64482c2c9756cbe4f0003ee92fa0955aead7a6b8 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Fri, 29 Dec 2017 17:04:37 +0100
Subject: [PATCH 010/255] fixed bug in dubt
the chain of unsorted candidates could grow beyond lowLimit.
---
lib/compress/zstd_compress.c | 42 ++--
lib/compress/zstd_lazy.c | 22 ++-
tests/fuzzer.c | 371 ++++++++++++++++++-----------------
3 files changed, 228 insertions(+), 207 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 91e281660..01d1b5d74 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -752,9 +752,9 @@ static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t blockSize1,
size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize));
size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0;
- DEBUGLOG(4, "ZSTD_sufficientBuff: windowSize2=%u from wlog=%u",
+ DEBUGLOG(4, "ZSTD_sufficientBuff: is windowSize2=%u <= wlog1=%u",
(U32)windowSize2, cParams2.windowLog);
- DEBUGLOG(4, "ZSTD_sufficientBuff: blockSize2 %u <=? blockSize1 %u",
+ DEBUGLOG(4, "ZSTD_sufficientBuff: is blockSize2=%u <= blockSize1=%u",
(U32)blockSize2, (U32)blockSize1);
return (blockSize2 <= blockSize1) /* seqStore space depends on blockSize */
& (neededBufferSize2 <= bufferSize1);
@@ -777,10 +777,12 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
* reuse CCtx without reset (note : requires no dictionary) */
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
{
- U32 const end = (U32)(cctx->nextSrc - cctx->base);
+ size_t const endT = (size_t)(cctx->nextSrc - cctx->base);
+ U32 const end = (U32)endT;
size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
- DEBUGLOG(4, "ZSTD_continueCCtx");
+ DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
+ assert(endT < (3U<<30));
cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
cctx->appliedParams = params;
@@ -912,12 +914,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->entropy->offcode_repeatMode = FSE_repeat_none;
zc->entropy->matchlength_repeatMode = FSE_repeat_none;
zc->entropy->litlength_repeatMode = FSE_repeat_none;
- zc->nextToUpdate = 1;
- zc->nextSrc = NULL;
zc->base = NULL;
zc->dictBase = NULL;
- zc->dictLimit = 0;
zc->lowLimit = 0;
+ zc->dictLimit = 0;
+ zc->nextToUpdate = 1;
+ zc->nextSrc = NULL;
{ int i; for (i=0; iseqStore.rep[i] = repStartValue[i]; }
zc->hashLog3 = hashLog3;
zc->optState.litLengthSum = 0;
@@ -925,7 +927,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
ptr = zc->entropy + 1;
/* opt parser space */
- if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
+ if ((params.cParams.strategy == ZSTD_btopt) | (params.cParams.strategy == ZSTD_btultra)) {
DEBUGLOG(4, "reserving optimal parser space");
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
zc->optState.litFreq = (U32*)ptr;
@@ -1643,9 +1645,12 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
ssPtr->longLengthID = 0;
}
-static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
{
- DEBUGLOG(5, "ZSTD_compressBlock_internal : dstCapacity = %u", (U32)dstCapacity);
+ DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u) (dictLimit=%u, nextToUpdate=%u)",
+ (U32)dstCapacity, zc->dictLimit, zc->nextToUpdate);
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1)
return 0; /* don't even attempt compression below a certain srcSize */
ZSTD_resetSeqStore(&(zc->seqStore));
@@ -1737,13 +1742,17 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
cctx->dictLimit -= correction;
if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
else cctx->nextToUpdate -= correction;
- DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x\n", correction, cctx->lowLimit);
+ DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, cctx->lowLimit);
}
/* enforce maxDist */
if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
+ if (cctx->dictLimit < cctx->lowLimit)
+ DEBUGLOG(2, "ZSTD_compress_frameChunk : update dictLimit from %u to %u ",
+ cctx->dictLimit, cctx->lowLimit);
if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
+ if (cctx->nextToUpdate < cctx->lowLimit) cctx->nextToUpdate = cctx->lowLimit;
}
{ size_t cSize = ZSTD_compressBlock_internal(cctx,
@@ -1846,8 +1855,9 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
/* Check if blocks follow each other */
if (src != cctx->nextSrc) {
- /* not contiguous */
size_t const distanceFromBase = (size_t)(cctx->nextSrc - cctx->base);
+ DEBUGLOG(5, "ZSTD_compressContinue_internal: non contiguous blocks, new segment starts at %u",
+ cctx->dictLimit);
cctx->lowLimit = cctx->dictLimit;
assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
cctx->dictLimit = (U32)distanceFromBase;
@@ -1879,6 +1889,7 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize)
{
+ DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (U32)srcSize);
return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
}
@@ -2144,10 +2155,10 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
{
- ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
+ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
ZSTD_CCtx_params const cctxParams =
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
- DEBUGLOG(4, "ZSTD_compressBegin_usingDict");
+ DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (U32)dictSize);
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
}
@@ -2275,6 +2286,7 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, co
size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
{
+ DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (U32)srcSize);
return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
}
@@ -2885,7 +2897,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
if (params.nbThreads > 1) {
if (cctx->mtctx == NULL || (params.nbThreads != ZSTDMT_getNbThreads(cctx->mtctx))) {
DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbThreads=%u (previous: %u)",
- params.nbThreads, ZSTDMT_getNbThreads(cctx->mtctx));
+ params.nbThreads, (unsigned)ZSTDMT_getNbThreads(cctx->mtctx));
ZSTDMT_freeCCtx(cctx->mtctx);
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 431157741..5249c5e58 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -32,12 +32,12 @@ void ZSTD_updateDUBT(ZSTD_CCtx* zc,
U32 const target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
- DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u ",
- idx, target);
+ if (idx != target)
+ DEBUGLOG(2, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
+ idx, target, zc->dictLimit);
assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
(void)iend;
-
assert(idx >= zc->dictLimit); /* condition for valid base+idx */
for ( ; idx < target ; idx++) {
size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls); /* assumption : ip + 8 <= iend */
@@ -79,10 +79,11 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
U32 dummy32; /* to be nullified at the end */
U32 const windowLow = zc->lowLimit;
- DEBUGLOG(8, "ZSTD_insertDUBT1 (%u)", current);
+ DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
+ current, dictLimit, windowLow);
assert(current >= btLow);
- if (extDict && (current < dictLimit)) { /* do not sort candidates in _extDict (simplification, for easier ZSTD_count, detrimental to compression ratio in streaming mode) */
+ if (extDict && (current < dictLimit)) { /* candidates in _extDict are not sorted (simplification, for easier ZSTD_count, detrimental to compression ratio in streaming mode) */
*largerPtr = *smallerPtr = 0;
return;
}
@@ -147,11 +148,13 @@ static size_t ZSTD_insertBtAndFindBestMatch (
const BYTE* const base = zc->base;
U32 const current = (U32)(ip-base);
+ U32 const windowLow = zc->lowLimit;
U32* const bt = zc->chainTable;
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
U32 const btMask = (1 << btLog) - 1;
U32 const btLow = (btMask >= current) ? 0 : current - btMask;
+ U32 const unsortLimit = MAX(btLow, windowLow);
U32* nextCandidate = bt + 2*(matchIndex&btMask);
U32* unsortedMark = bt + 2*(matchIndex&btMask) + 1;
@@ -162,7 +165,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
assert(ip <= iend-8); /* required for h calculation */
/* reach end of unsorted candidates list */
- while ( (matchIndex > btLow)
+ while ( (matchIndex > unsortLimit)
&& (*unsortedMark == ZSTD_DUBT_UNSORTED)
&& (nbCandidates > 1) ) {
DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: candidate %u is unsorted",
@@ -175,11 +178,11 @@ static size_t ZSTD_insertBtAndFindBestMatch (
nbCandidates --;
}
- if ( (matchIndex > btLow)
+ if ( (matchIndex > unsortLimit)
&& (*unsortedMark==ZSTD_DUBT_UNSORTED) ) {
DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: nullify last unsorted candidate %u",
matchIndex);
- *nextCandidate = *unsortedMark = 0; /* nullify last candidate if it's still unsorted (note : detrimental to compression ratio) */
+ *nextCandidate = *unsortedMark = 0; /* nullify next candidate if it's still unsorted (note : simplification, detrimental to compression ratio, beneficial for speed) */
}
/* batch sort stacked candidates */
@@ -188,7 +191,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
U32 const nextCandidateIdx = *nextCandidateIdxPtr;
ZSTD_insertDUBT1(zc, matchIndex, iend,
- nbCandidates, btLow, extDict);
+ nbCandidates, unsortLimit, extDict);
matchIndex = nextCandidateIdx;
nbCandidates++;
}
@@ -199,7 +202,6 @@ static size_t ZSTD_insertBtAndFindBestMatch (
const U32 dictLimit = zc->dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const prefixStart = base + dictLimit;
- const U32 windowLow = zc->lowLimit;
U32* smallerPtr = bt + 2*(current&btMask);
U32* largerPtr = bt + 2*(current&btMask) + 1;
U32 matchEndIdx = current+8+1;
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 141bf6548..3e911d7ca 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -286,91 +286,91 @@ static int basicUnitTests(U32 seed, double compressibility)
RDG_genBuffer(CNBuffer, CNBuffSize, compressibility, 0., seed);
/* Basic tests */
- DISPLAYLEVEL(4, "test%3i : ZSTD_getErrorName : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : ZSTD_getErrorName : ", testNb++);
{ const char* errorString = ZSTD_getErrorName(0);
- DISPLAYLEVEL(4, "OK : %s \n", errorString);
+ DISPLAYLEVEL(3, "OK : %s \n", errorString);
}
- DISPLAYLEVEL(4, "test%3i : ZSTD_getErrorName with wrong value : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : ZSTD_getErrorName with wrong value : ", testNb++);
{ const char* errorString = ZSTD_getErrorName(499);
- DISPLAYLEVEL(4, "OK : %s \n", errorString);
+ DISPLAYLEVEL(3, "OK : %s \n", errorString);
}
- DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, (U32)CNBuffSize);
+ DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, (U32)CNBuffSize);
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
if (cctx==NULL) goto _output_error;
CHECKPLUS(r, ZSTD_compressCCtx(cctx,
compressedBuffer, compressedBufferSize,
CNBuffer, CNBuffSize, 1),
cSize=r );
- DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
+ DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
- DISPLAYLEVEL(4, "test%3i : size of cctx for level 1 : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : size of cctx for level 1 : ", testNb++);
{ size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
- DISPLAYLEVEL(4, "%u bytes \n", (U32)cctxSize);
+ DISPLAYLEVEL(3, "%u bytes \n", (U32)cctxSize);
}
ZSTD_freeCCtx(cctx);
}
- DISPLAYLEVEL(4, "test%3i : ZSTD_getFrameContentSize test : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : ZSTD_getFrameContentSize test : ", testNb++);
{ unsigned long long const rSize = ZSTD_getFrameContentSize(compressedBuffer, cSize);
if (rSize != CNBuffSize) goto _output_error;
}
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : ZSTD_findDecompressedSize test : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : ZSTD_findDecompressedSize test : ", testNb++);
{ unsigned long long const rSize = ZSTD_findDecompressedSize(compressedBuffer, cSize);
if (rSize != CNBuffSize) goto _output_error;
}
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, (U32)CNBuffSize);
+ DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, (U32)CNBuffSize);
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize);
if (r != CNBuffSize) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
{ size_t u;
for (u=0; u (1U << 20)) goto _output_error;
ZSTD_freeCCtx(cctx);
}
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%di : re-use CCtx with expanding block size : ", testNb++);
+ DISPLAYLEVEL(3, "test%3d : re-use CCtx with expanding block size : ", testNb++);
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
ZSTD_parameters const params = ZSTD_getParams(1, ZSTD_CONTENTSIZE_UNKNOWN, 0);
assert(params.fParams.contentSizeFlag == 1); /* block size will be adapted if pledgedSrcSize is enabled */
@@ -385,11 +385,11 @@ static int basicUnitTests(U32 seed, double compressibility)
}
ZSTD_freeCCtx(cctx);
}
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
/* Static CCtx tests */
#define STATIC_CCTX_LEVEL 3
- DISPLAYLEVEL(4, "test%3i : create static CCtx for level %u :", testNb++, STATIC_CCTX_LEVEL);
+ DISPLAYLEVEL(3, "test%3i : create static CCtx for level %u :", testNb++, STATIC_CCTX_LEVEL);
{ size_t const staticCCtxSize = ZSTD_estimateCStreamSize(STATIC_CCTX_LEVEL);
void* const staticCCtxBuffer = malloc(staticCCtxSize);
size_t const staticDCtxSize = ZSTD_estimateDCtxSize();
@@ -404,57 +404,57 @@ static int basicUnitTests(U32 seed, double compressibility)
{ ZSTD_CCtx* staticCCtx = ZSTD_initStaticCCtx(staticCCtxBuffer, staticCCtxSize);
ZSTD_DCtx* staticDCtx = ZSTD_initStaticDCtx(staticDCtxBuffer, staticDCtxSize);
if ((staticCCtx==NULL) || (staticDCtx==NULL)) goto _output_error;
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : init CCtx for level %u : ", testNb++, STATIC_CCTX_LEVEL);
+ DISPLAYLEVEL(3, "test%3i : init CCtx for level %u : ", testNb++, STATIC_CCTX_LEVEL);
{ size_t const r = ZSTD_compressBegin(staticCCtx, STATIC_CCTX_LEVEL);
if (ZSTD_isError(r)) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : simple compression test with static CCtx : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : simple compression test with static CCtx : ", testNb++);
CHECKPLUS(r, ZSTD_compressCCtx(staticCCtx,
compressedBuffer, compressedBufferSize,
CNBuffer, CNBuffSize, STATIC_CCTX_LEVEL),
cSize=r );
- DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n",
+ DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n",
(U32)cSize, (double)cSize/CNBuffSize*100);
- DISPLAYLEVEL(4, "test%3i : simple decompression test with static DCtx : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : simple decompression test with static DCtx : ", testNb++);
{ size_t const r = ZSTD_decompressDCtx(staticDCtx,
decodedBuffer, CNBuffSize,
compressedBuffer, cSize);
if (r != CNBuffSize) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
{ size_t u;
for (u=0; u same size */
}
- DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
+ DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
- DISPLAYLEVEL(4, "test%3i : frame built with duplicated context should be decompressible : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : frame built with duplicated context should be decompressible : ", testNb++);
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
decodedBuffer, CNBuffSize,
compressedBuffer, cSize,
CNBuffer, dictSize),
if (r != CNBuffSize - dictSize) goto _output_error);
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : decompress with DDict : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : decompress with DDict : ", testNb++);
{ ZSTD_DDict* const ddict = ZSTD_createDDict(CNBuffer, dictSize);
size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, ddict);
if (r != CNBuffSize - dictSize) goto _output_error;
- DISPLAYLEVEL(4, "OK (size of DDict : %u) \n", (U32)ZSTD_sizeof_DDict(ddict));
+ DISPLAYLEVEL(3, "OK (size of DDict : %u) \n", (U32)ZSTD_sizeof_DDict(ddict));
ZSTD_freeDDict(ddict);
}
- DISPLAYLEVEL(4, "test%3i : decompress with static DDict : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : decompress with static DDict : ", testNb++);
{ size_t const ddictBufferSize = ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
void* ddictBuffer = malloc(ddictBufferSize);
if (ddictBuffer == NULL) goto _output_error;
@@ -633,10 +632,10 @@ static int basicUnitTests(U32 seed, double compressibility)
if (r != CNBuffSize - dictSize) goto _output_error;
}
free(ddictBuffer);
- DISPLAYLEVEL(4, "OK (size of static DDict : %u) \n", (U32)ddictBufferSize);
+ DISPLAYLEVEL(3, "OK (size of static DDict : %u) \n", (U32)ddictBufferSize);
}
- DISPLAYLEVEL(4, "test%3i : check content size on duplicated context : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : check content size on duplicated context : ", testNb++);
{ size_t const testSize = CNBuffSize / 3;
{ ZSTD_parameters p = ZSTD_getParams(2, testSize, dictSize);
p.fParams.contentSizeFlag = 1;
@@ -651,7 +650,7 @@ static int basicUnitTests(U32 seed, double compressibility)
if (ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize)) goto _output_error;
if ((zfh.frameContentSize != testSize) && (zfh.frameContentSize != 0)) goto _output_error;
} }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
ZSTD_freeCCtx(ctxOrig);
ZSTD_freeCCtx(ctxDuplicated);
@@ -673,79 +672,79 @@ static int basicUnitTests(U32 seed, double compressibility)
goto _output_error;
}
- DISPLAYLEVEL(4, "test%3i : dictBuilder : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : dictBuilder : ", testNb++);
{ U32 u; for (u=0; u %u bytes)\n", (U32)inputSize, (U32)cSize);
+ DISPLAYLEVEL(3, "OK (compress : %u -> %u bytes)\n", (U32)inputSize, (U32)cSize);
- DISPLAYLEVEL(4, "test%3i : decompress normally (should fail) : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : decompress normally (should fail) : ", testNb++);
{ size_t const decodeResult = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize);
if (ZSTD_getErrorCode(decodeResult) != ZSTD_error_prefix_unknown) goto _output_error;
- DISPLAYLEVEL(4, "OK : %s \n", ZSTD_getErrorName(decodeResult));
+ DISPLAYLEVEL(3, "OK : %s \n", ZSTD_getErrorName(decodeResult));
}
- DISPLAYLEVEL(4, "test%3i : decompress with magic-less instruction : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : decompress with magic-less instruction : ", testNb++);
ZSTD_DCtx_reset(dctx);
CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) );
{ ZSTD_inBuffer in = { compressedBuffer, cSize, 0 };
@@ -1019,7 +1018,7 @@ static int basicUnitTests(U32 seed, double compressibility)
if (result != 0) goto _output_error;
if (in.pos != in.size) goto _output_error;
if (out.pos != inputSize) goto _output_error;
- DISPLAYLEVEL(4, "OK : regenerated %u bytes \n", (U32)out.pos);
+ DISPLAYLEVEL(3, "OK : regenerated %u bytes \n", (U32)out.pos);
}
ZSTD_freeCCtx(cctx);
@@ -1032,21 +1031,21 @@ static int basicUnitTests(U32 seed, double compressibility)
size_t cSize2;
/* basic block compression */
- DISPLAYLEVEL(4, "test%3i : Block compression test : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : Block compression test : ", testNb++);
CHECK( ZSTD_compressBegin(cctx, 5) );
CHECK( ZSTD_getBlockSize(cctx) >= blockSize);
cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
if (ZSTD_isError(cSize)) goto _output_error;
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : Block decompression test : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : Block decompression test : ", testNb++);
CHECK( ZSTD_decompressBegin(dctx) );
{ CHECK_V(r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
if (r != blockSize) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
/* dictionary block compression */
- DISPLAYLEVEL(4, "test%3i : Dictionary Block compression test : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : Dictionary Block compression test : ", testNb++);
CHECK( ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5) );
cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
if (ZSTD_isError(cSize)) goto _output_error;
@@ -1056,16 +1055,16 @@ static int basicUnitTests(U32 seed, double compressibility)
cSize2 = ZSTD_compressBlock(cctx, (char*)compressedBuffer+cSize+blockSize, ZSTD_compressBound(blockSize),
(char*)CNBuffer+dictSize+2*blockSize, blockSize);
if (ZSTD_isError(cSize2)) goto _output_error;
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : Dictionary Block decompression test : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : Dictionary Block decompression test : ", testNb++);
CHECK( ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize) );
{ CHECK_V( r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
if (r != blockSize) goto _output_error; }
ZSTD_insertBlock(dctx, (char*)decodedBuffer+blockSize, blockSize); /* insert non-compressed block into dctx history */
{ CHECK_V( r, ZSTD_decompressBlock(dctx, (char*)decodedBuffer+2*blockSize, CNBuffSize, (char*)compressedBuffer+cSize+blockSize, cSize2) );
if (r != blockSize) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
ZSTD_freeCCtx(cctx);
}
@@ -1073,7 +1072,7 @@ static int basicUnitTests(U32 seed, double compressibility)
/* long rle test */
{ size_t sampleSize = 0;
- DISPLAYLEVEL(4, "test%3i : Long RLE test : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : Long RLE test : ", testNb++);
RDG_genBuffer(CNBuffer, sampleSize, compressibility, 0., seed+1);
memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
sampleSize += 256 KB - 1;
@@ -1083,21 +1082,21 @@ static int basicUnitTests(U32 seed, double compressibility)
if (ZSTD_isError(cSize)) goto _output_error;
{ CHECK_V(regenSize, ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize));
if (regenSize!=sampleSize) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
}
/* All zeroes test (test bug #137) */
#define ZEROESLENGTH 100
- DISPLAYLEVEL(4, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
+ DISPLAYLEVEL(3, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
memset(CNBuffer, 0, ZEROESLENGTH);
{ CHECK_V(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1) );
cSize = r; }
- DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/ZEROESLENGTH*100);
+ DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/ZEROESLENGTH*100);
- DISPLAYLEVEL(4, "test%3i : decompress %u zeroes : ", testNb++, ZEROESLENGTH);
+ DISPLAYLEVEL(3, "test%3i : decompress %u zeroes : ", testNb++, ZEROESLENGTH);
{ CHECK_V(r, ZSTD_decompress(decodedBuffer, ZEROESLENGTH, compressedBuffer, cSize) );
if (r != ZEROESLENGTH) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
/* nbSeq limit test */
#define _3BYTESTESTLENGTH 131000
@@ -1124,18 +1123,18 @@ static int basicUnitTests(U32 seed, double compressibility)
((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
} } }
- DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : compress lots 3-bytes sequences : ", testNb++);
{ CHECK_V(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH),
CNBuffer, _3BYTESTESTLENGTH, 19) );
cSize = r; }
- DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
+ DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
- DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
{ CHECK_V(r, ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize) );
if (r != _3BYTESTESTLENGTH) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
- DISPLAYLEVEL(4, "test%3i : incompressible data and ill suited dictionary : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : incompressible data and ill suited dictionary : ", testNb++);
RDG_genBuffer(CNBuffer, CNBuffSize, 0.0, 0.1, seed);
{ /* Train a dictionary on low characters */
size_t dictSize = 16 KB;
@@ -1168,25 +1167,25 @@ static int basicUnitTests(U32 seed, double compressibility)
free(dictBuffer);
free(samplesSizes);
}
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
/* findFrameCompressedSize on skippable frames */
- DISPLAYLEVEL(4, "test%3i : frame compressed size of skippable frame : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : frame compressed size of skippable frame : ", testNb++);
{ const char* frame = "\x50\x2a\x4d\x18\x05\x0\x0\0abcde";
size_t const frameSrcSize = 13;
if (ZSTD_findFrameCompressedSize(frame, frameSrcSize) != frameSrcSize) goto _output_error; }
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
/* error string tests */
- DISPLAYLEVEL(4, "test%3i : testing ZSTD error code strings : ", testNb++);
+ DISPLAYLEVEL(3, "test%3i : testing ZSTD error code strings : ", testNb++);
if (strcmp("No error detected", ZSTD_getErrorName((ZSTD_ErrorCode)(0-ZSTD_error_no_error))) != 0) goto _output_error;
if (strcmp("No error detected", ZSTD_getErrorString(ZSTD_error_no_error)) != 0) goto _output_error;
if (strcmp("Unspecified error code", ZSTD_getErrorString((ZSTD_ErrorCode)(0-ZSTD_error_GENERIC))) != 0) goto _output_error;
if (strcmp("Error (generic)", ZSTD_getErrorName((size_t)0-ZSTD_error_GENERIC)) != 0) goto _output_error;
if (strcmp("Error (generic)", ZSTD_getErrorString(ZSTD_error_GENERIC)) != 0) goto _output_error;
if (strcmp("No error detected", ZSTD_getErrorName(ZSTD_error_GENERIC)) != 0) goto _output_error;
- DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(3, "OK \n");
_end:
free(CNBuffer);
@@ -1369,6 +1368,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
}
/* successful decompression test */
+ DISPLAYLEVEL(5, "fuzzer t%u: simple decompression test \n", testNb);
{ size_t const margin = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
size_t const dSize = ZSTD_decompress(dstBuffer, sampleSize + margin, cBuffer, cSize);
CHECK(dSize != sampleSize, "ZSTD_decompress failed (%s) (srcSize : %u ; cSize : %u)", ZSTD_getErrorName(dSize), (U32)sampleSize, (U32)cSize);
@@ -1379,6 +1379,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
free(sampleBuffer); /* no longer useful after this point */
/* truncated src decompression test */
+ DISPLAYLEVEL(5, "fuzzer t%u: decompression of truncated source \n", testNb);
{ size_t const missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
size_t const tooSmallSize = cSize - missing;
void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch read overflows */
@@ -1390,6 +1391,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
}
/* too small dst decompression test */
+ DISPLAYLEVEL(5, "fuzzer t%u: decompress into too small dst buffer \n", testNb);
if (sampleSize > 3) {
size_t const missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
size_t const tooSmallSize = sampleSize - missing;
@@ -1425,6 +1427,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
} } }
/* decompress noisy source */
+ DISPLAYLEVEL(5, "fuzzer t%u: decompress noisy source \n", testNb);
{ U32 const endMark = 0xA9B1C3D6;
memcpy(dstBuffer+sampleSize, &endMark, 4);
{ size_t const decompressResult = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
@@ -1436,8 +1439,8 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
} } } /* noisy src decompression test */
- /*===== Streaming compression test, scattered segments and dictionary =====*/
-
+ /*===== Bufferless streaming compression test, scattered segments and dictionary =====*/
+ DISPLAYLEVEL(5, "fuzzer t%u: Bufferless streaming compression test \n", testNb);
{ U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
int const cLevel = (FUZ_rand(&lseed) %
@@ -1450,10 +1453,13 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
dictSize = FUZ_rLogLength(&lseed, dictLog); /* needed also for decompression */
dict = srcBuffer + (FUZ_rand(&lseed) % (srcBufferSize - dictSize));
+ DISPLAYLEVEL(6, "fuzzer t%u: Compressing up to <=%u bytes at level %i with dictionary size %u \n",
+ testNb, (U32)maxTestSize, cLevel, (U32)dictSize);
+
if (FUZ_rand(&lseed) & 0xF) {
CHECK_Z ( ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel) );
} else {
- ZSTD_compressionParameters const cPar = ZSTD_getCParams(cLevel, 0, dictSize);
+ ZSTD_compressionParameters const cPar = ZSTD_getCParams(cLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
ZSTD_frameParameters const fPar = { FUZ_rand(&lseed)&1 /* contentSizeFlag */,
!(FUZ_rand(&lseed)&3) /* contentChecksumFlag*/,
0 /*NodictID*/ }; /* note : since dictionary is fake, dictIDflag has no impact */
@@ -1491,6 +1497,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
}
/* streaming decompression test */
+ DISPLAYLEVEL(5, "fuzzer t%u: Bufferless streaming decompression test \n", testNb);
/* ensure memory requirement is good enough (should always be true) */
{ ZSTD_frameHeader zfh;
CHECK( ZSTD_getFrameHeader(&zfh, cBuffer, ZSTD_frameHeaderSize_max),
@@ -1633,7 +1640,7 @@ int main(int argc, const char** argv)
case 'v':
argument++;
- g_displayLevel = 4;
+ g_displayLevel++;
break;
case 'q':
From 4c7f137bd2790815b3536776bbd86556bcdc9066 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Fri, 29 Dec 2017 17:40:36 +0100
Subject: [PATCH 011/255] add test case which reliably produces btlazy2 rescale
overflow bug
The unsorted_mark is handled like any index,
which fails after a rescale.
---
tests/playTests.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/playTests.sh b/tests/playTests.sh
index c93c58fe8..fa1efeb59 100755
--- a/tests/playTests.sh
+++ b/tests/playTests.sh
@@ -712,6 +712,7 @@ roundTripTest -g18000018 -P94 18
roundTripTest -g18000019 -P96 19
roundTripTest -g5000000000 -P99 1
+roundTripTest -g1700000000 -P0 "1 --zstd=strategy=6" # ensure btlazy2 can survive an overflow rescale
fileRoundTripTest -g4193M -P99 1
From 02f64ef955997c450fbd80fbbeb31bf77c55cd56 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Fri, 29 Dec 2017 19:08:51 +0100
Subject: [PATCH 012/255] btlazy2: fixed interaction between unsortedMark and
reduceTable
---
lib/compress/zstd_compress.c | 10 +++++++--
lib/compress/zstd_lazy.c | 39 +++++++++++++++++++++++++++++++-----
lib/compress/zstd_lazy.h | 1 +
tests/fuzzer.c | 7 ++++---
4 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 01d1b5d74..4e05e287c 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -1125,8 +1125,15 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);
}
+ if (zc->appliedParams.cParams.strategy != ZSTD_btlazy2) {
+ U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
+ ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
+ }
+
if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
+ if (zc->appliedParams.cParams.strategy != ZSTD_btlazy2)
+ ZSTD_preserveUnsortedMark(zc->chainTable, chainSize, reducerValue);
ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
}
@@ -1749,7 +1756,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
if (cctx->dictLimit < cctx->lowLimit)
- DEBUGLOG(2, "ZSTD_compress_frameChunk : update dictLimit from %u to %u ",
+ DEBUGLOG(5, "ZSTD_compress_frameChunk : update dictLimit from %u to %u ",
cctx->dictLimit, cctx->lowLimit);
if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
if (cctx->nextToUpdate < cctx->lowLimit) cctx->nextToUpdate = cctx->lowLimit;
@@ -2210,7 +2217,6 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
return op-ostart;
}
-
size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize)
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 5249c5e58..1ed63b9de 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -15,7 +15,36 @@
/*-*************************************
* Binary Tree search
***************************************/
-#define ZSTD_DUBT_UNSORTED ((U32)(-1))
+#define ZSTD_DUBT_UNSORTED_MARK 1 /* note : index 1 will now be confused with "unsorted" if sorted as larger than its predecessor.
+ It's not a big deal though : the candidate will just be considered unsorted, and be sorted again.
+ Additionnally, candidate position 1 will be lost.
+ But candidate 1 cannot hide a large tree of candidates, so it's a moderate loss.
+ The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled by a table re-use using a different strategy */
+
+#define ZSTD_ROWSIZE 16
+/*! ZSTD_preserveUnsortedMark_internal() :
+ * Helps auto-vectorization */
+static void ZSTD_preserveUnsortedMark_internal (U32* const table, int const nbRows, U32 const reducerValue)
+{
+ int cellNb = 0;
+ int rowNb;
+ for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
+ int column;
+ for (column=0; columnnextToUpdate;
if (idx != target)
- DEBUGLOG(2, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
+ DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
idx, target, zc->dictLimit);
assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
(void)iend;
@@ -48,7 +77,7 @@ void ZSTD_updateDUBT(ZSTD_CCtx* zc,
hashTable[h] = idx; /* Update Hash Table */
*nextCandidatePtr = matchIndex; /* update BT like a chain */
- *sortMarkPtr = ZSTD_DUBT_UNSORTED;
+ *sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK;
}
zc->nextToUpdate = target;
}
@@ -166,7 +195,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
/* reach end of unsorted candidates list */
while ( (matchIndex > unsortLimit)
- && (*unsortedMark == ZSTD_DUBT_UNSORTED)
+ && (*unsortedMark == ZSTD_DUBT_UNSORTED_MARK)
&& (nbCandidates > 1) ) {
DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: candidate %u is unsorted",
matchIndex);
@@ -179,7 +208,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
}
if ( (matchIndex > unsortLimit)
- && (*unsortedMark==ZSTD_DUBT_UNSORTED) ) {
+ && (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: nullify last unsorted candidate %u",
matchIndex);
*nextCandidate = *unsortedMark = 0; /* nullify next candidate if it's still unsorted (note : simplification, detrimental to compression ratio, beneficial for speed) */
diff --git a/lib/compress/zstd_lazy.h b/lib/compress/zstd_lazy.h
index 8918e5ca4..5c02f1661 100644
--- a/lib/compress/zstd_lazy.h
+++ b/lib/compress/zstd_lazy.h
@@ -20,6 +20,7 @@ extern "C" {
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls); /* used in ZSTD_loadDictionaryContent() */
void ZSTD_updateDUBT(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iend, U32 mls); /* used in ZSTD_loadDictionaryContent() */
+void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK */
size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 3e911d7ca..c599a15de 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -63,7 +63,7 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
- if (g_displayLevel>=4) fflush(stderr); } }
+ if (g_displayLevel>=4) fflush(stdout); } }
/*-*******************************************************
* Fuzzer functions
@@ -1337,10 +1337,11 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
crcOrig = XXH64(sampleBuffer, sampleSize, 0);
/* compression tests */
- { unsigned const cLevel =
+ { int const cLevel =
( FUZ_rand(&lseed) %
(ZSTD_maxCLevel() - (FUZ_highbit32((U32)sampleSize) / cLevelLimiter)) )
- + 1;
+ + 1;
+ DISPLAYLEVEL(5, "fuzzer t%u: Simple compression test (level %i) \n", testNb, cLevel);
cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed : %s", ZSTD_getErrorName(cSize));
From d228b6b0d0c83cbec268f4917fe3480bccdf362c Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Fri, 29 Dec 2017 19:14:18 +0100
Subject: [PATCH 013/255] btlazy2 : optimization for dictionary compression
we want the dictionary table to be fully sorted,
not just lazily filled.
Dictionary loading is a bit more intensive,
but it saves cpu cycles for match search during compression.
---
lib/compress/zstd_compress.c | 6 +-----
tests/playTests.sh | 5 +++++
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 4e05e287c..32d15116b 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -1950,11 +1950,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
break;
- case ZSTD_btlazy2:
- if (srcSize >= HASH_READ_SIZE)
- ZSTD_updateDUBT(zc, iend-HASH_READ_SIZE, iend, zc->appliedParams.cParams.searchLength);
- break;
-
+ case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
case ZSTD_btopt:
case ZSTD_btultra:
if (srcSize >= HASH_READ_SIZE)
diff --git a/tests/playTests.sh b/tests/playTests.sh
index fa1efeb59..ee93b10a5 100755
--- a/tests/playTests.sh
+++ b/tests/playTests.sh
@@ -322,9 +322,14 @@ $ECHO "- Create first dictionary "
TESTFILE=../programs/zstdcli.c
$ZSTD --train *.c ../programs/*.c -o tmpDict
cp $TESTFILE tmp
+$ECHO "- Dictionary compression roundtrip"
$ZSTD -f tmp -D tmpDict
$ZSTD -d tmp.zst -D tmpDict -fo result
$DIFF $TESTFILE result
+$ECHO "- Dictionary compression with btlazy2 strategy"
+$ZSTD -f tmp -D tmpDict --zstd=strategy=6
+$ZSTD -d tmp.zst -D tmpDict -fo result
+$DIFF $TESTFILE result
if [ -n "$hasMT" ]
then
$ECHO "- Test dictionary compression with multithreading "
From ea41b580eb20848e9383b705be34341d6f950fa8 Mon Sep 17 00:00:00 2001
From: Shawn Landden
Date: Sun, 24 Dec 2017 16:01:15 -0800
Subject: [PATCH 014/255] meson: allow -Dlegacy_support=true, fix
-Dlegacy_support=0
---
contrib/meson/meson.build | 10 ++++++++++
contrib/meson/meson_options.txt | 3 ++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/contrib/meson/meson.build b/contrib/meson/meson.build
index b045c9944..079c045a1 100644
--- a/contrib/meson/meson.build
+++ b/contrib/meson/meson.build
@@ -39,9 +39,19 @@ libzstd_srcs = [
libzstd_includes = [include_directories(common_dir, dictbuilder_dir, compress_dir, lib_dir)]
legacy = get_option('legacy_support')
+if legacy == '0'
+ legacy = 'false'
+endif
if legacy != 'false'
+ if legacy == 'true'
+ legacy = '1'
+ endif
+ #See ZSTD_LEGACY_SUPPORT of programs/README.md
message('Enabling legacy support back to version 0.' + legacy)
legacy_int = legacy.to_int()
+ if legacy_int > 7
+ legacy_int = 7
+ endif
libzstd_cflags = ['-DZSTD_LEGACY_SUPPORT=' + legacy]
legacy_dir = join_paths(lib_dir, 'legacy')
diff --git a/contrib/meson/meson_options.txt b/contrib/meson/meson_options.txt
index de9fea073..99845c8aa 100644
--- a/contrib/meson/meson_options.txt
+++ b/contrib/meson/meson_options.txt
@@ -1,2 +1,3 @@
option('multithread', type: 'boolean', value: false)
-option('legacy_support', type: 'string', value: '4')
+option('legacy_support', type: 'string', value: '4',
+ description: 'True or false, or 7 to 1 for v0.7+ to v0.1+.')
From eb52e2f45e91bfea0531b2e23ca13c44a0837b83 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 30 Dec 2017 11:13:52 +0100
Subject: [PATCH 015/255] simplify ZSTD_preserveUnsortedMark() implementation
since no compiler attempts to auto-vectorize it.
---
lib/compress/zstd_lazy.c | 25 ++++++-------------------
1 file changed, 6 insertions(+), 19 deletions(-)
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 1ed63b9de..2688a78d5 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -21,29 +21,16 @@
But candidate 1 cannot hide a large tree of candidates, so it's a moderate loss.
The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled by a table re-use using a different strategy */
-#define ZSTD_ROWSIZE 16
-/*! ZSTD_preserveUnsortedMark_internal() :
- * Helps auto-vectorization */
-static void ZSTD_preserveUnsortedMark_internal (U32* const table, int const nbRows, U32 const reducerValue)
-{
- int cellNb = 0;
- int rowNb;
- for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
- int column;
- for (column=0; column
Date: Sat, 30 Dec 2017 11:37:18 +0100
Subject: [PATCH 016/255] updated compression level table for btlazy2
now selected for levels 13, 14 and 15.
Also : dropped the requirement for monotonic memory budget increase of compression levels,,
which was required for ZSTD_estimateCCtxSize()
in order to ensure that a memory budget for level L is large enough for any level <= L.
This condition is now ensured at run time inside ZSTD_estimateCCtxSize().
---
lib/compress/zstd_compress.c | 58 ++++++++++++++++--------------------
1 file changed, 26 insertions(+), 32 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 32d15116b..96cd0c2a2 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -687,12 +687,23 @@ size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms);
}
-size_t ZSTD_estimateCCtxSize(int compressionLevel)
+static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
{
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
return ZSTD_estimateCCtxSize_usingCParams(cParams);
}
+size_t ZSTD_estimateCCtxSize(int compressionLevel)
+{
+ int level;
+ size_t memBudget = 0;
+ for (level=1; level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
{
if (params->nbThreads > 1) { return ERROR(GENERIC); }
@@ -712,11 +723,21 @@ size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
}
-size_t ZSTD_estimateCStreamSize(int compressionLevel) {
+static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) {
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
return ZSTD_estimateCStreamSize_usingCParams(cParams);
}
+size_t ZSTD_estimateCStreamSize(int compressionLevel) {
+ int level;
+ size_t memBudget = 0;
+ for (level=1; level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
ZSTD_compressionParameters cParams2)
{
@@ -3001,9 +3022,9 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
{ 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
{ 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
{ 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
- { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
- { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
- { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
+ { 22, 21, 22, 4, 5, 16, ZSTD_btlazy2 }, /* level 13 */
+ { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 14 */
+ { 22, 22, 22, 6, 5, 16, ZSTD_btlazy2 }, /* level 15 */
{ 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */
{ 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */
{ 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */
@@ -3092,24 +3113,6 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
},
};
-#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
-/* This function just controls
- * the monotonic memory budget increase of ZSTD_defaultCParameters[0].
- * Run once, on first ZSTD_getCParams() usage, if ZSTD_DEBUG is enabled
- */
-MEM_STATIC void ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget(void)
-{
- int level;
- for (level=1; level=1)
- static int g_monotonicTest = 1;
- if (g_monotonicTest) {
- ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget();
- g_monotonicTest=0;
- }
-#endif
-
DEBUGLOG(4, "ZSTD_getCParams: cLevel=%i, srcSize=%u, dictSize=%u => table %u",
compressionLevel, (U32)srcSizeHint, (U32)dictSize, tableID);
if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
From a68b76afefec6876f8e8a538155109a5aeac0143 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 30 Dec 2017 11:37:18 +0100
Subject: [PATCH 017/255] updated compression level table for btlazy2
now selected for levels 13, 14 and 15.
Also : dropped the requirement for monotonic memory budget increase of compression levels,,
which was required for ZSTD_estimateCCtxSize()
in order to ensure that a memory budget for level L is large enough for any level <= L.
This condition is now ensured at run time inside ZSTD_estimateCCtxSize().
---
lib/compress/zstd_compress.c | 60 ++++++++++++++++--------------------
1 file changed, 27 insertions(+), 33 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 32d15116b..a804efca5 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -687,12 +687,23 @@ size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms);
}
-size_t ZSTD_estimateCCtxSize(int compressionLevel)
+static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
{
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
return ZSTD_estimateCCtxSize_usingCParams(cParams);
}
+size_t ZSTD_estimateCCtxSize(int compressionLevel)
+{
+ int level;
+ size_t memBudget = 0;
+ for (level=1; level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
{
if (params->nbThreads > 1) { return ERROR(GENERIC); }
@@ -712,11 +723,21 @@ size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
}
-size_t ZSTD_estimateCStreamSize(int compressionLevel) {
+static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) {
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
return ZSTD_estimateCStreamSize_usingCParams(cParams);
}
+size_t ZSTD_estimateCStreamSize(int compressionLevel) {
+ int level;
+ size_t memBudget = 0;
+ for (level=1; level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
ZSTD_compressionParameters cParams2)
{
@@ -3001,9 +3022,9 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
{ 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
{ 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
{ 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
- { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
- { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
- { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
+ { 22, 21, 22, 4, 5, 16, ZSTD_btlazy2 }, /* level 13 */
+ { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 14 */
+ { 22, 22, 22, 6, 5, 16, ZSTD_btlazy2 }, /* level 15 */
{ 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */
{ 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */
{ 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */
@@ -3092,41 +3113,14 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
},
};
-#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
-/* This function just controls
- * the monotonic memory budget increase of ZSTD_defaultCParameters[0].
- * Run once, on first ZSTD_getCParams() usage, if ZSTD_DEBUG is enabled
- */
-MEM_STATIC void ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget(void)
-{
- int level;
- for (level=1; level=1)
- static int g_monotonicTest = 1;
- if (g_monotonicTest) {
- ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget();
- g_monotonicTest=0;
- }
-#endif
-
DEBUGLOG(4, "ZSTD_getCParams: cLevel=%i, srcSize=%u, dictSize=%u => table %u",
compressionLevel, (U32)srcSizeHint, (U32)dictSize, tableID);
if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
From f597f556752ec1d0defe6aa6e9d6470f5f73509c Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 30 Dec 2017 15:12:59 +0100
Subject: [PATCH 018/255] improved btlazy2 : list of unsorted candidates can
reach extDict
It used to stop on reaching extDict, for simplification.
As a consequence, there was a small loss of performance each time the round buffer would restart from beginning.
It's not a large difference though, just several hundreds of bytes on silesia.
This patch fixes it.
---
lib/compress/zstd_lazy.c | 43 +++++++++++++++++++-------------
lib/decompress/zstd_decompress.c | 5 ++++
2 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 2688a78d5..9385bf423 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -62,6 +62,7 @@ void ZSTD_updateDUBT(ZSTD_CCtx* zc,
U32* const nextCandidatePtr = bt + 2*(idx&btMask);
U32* const sortMarkPtr = nextCandidatePtr + 1;
+ DEBUGLOG(8, "ZSTD_updateDUBT: insert %u", idx);
hashTable[h] = idx; /* Update Hash Table */
*nextCandidatePtr = matchIndex; /* update BT like a chain */
*sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK;
@@ -75,7 +76,7 @@ void ZSTD_updateDUBT(ZSTD_CCtx* zc,
* assumption : current >= btlow == (current - btmask)
* doesn't fail */
static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
- U32 current, const BYTE* iend,
+ U32 current, const BYTE* inputEnd,
U32 nbCompares, U32 btLow, int extDict)
{
U32* const bt = zc->chainTable;
@@ -83,9 +84,10 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
U32 const btMask = (1 << btLog) - 1;
size_t commonLengthSmaller=0, commonLengthLarger=0;
const BYTE* const base = zc->base;
- const BYTE* const ip = base + current;
const BYTE* const dictBase = zc->dictBase;
const U32 dictLimit = zc->dictLimit;
+ const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
+ const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const prefixStart = base + dictLimit;
const BYTE* match;
@@ -98,22 +100,20 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
current, dictLimit, windowLow);
assert(current >= btLow);
-
- if (extDict && (current < dictLimit)) { /* candidates in _extDict are not sorted (simplification, for easier ZSTD_count, detrimental to compression ratio in streaming mode) */
- *largerPtr = *smallerPtr = 0;
- return;
- }
- assert(current >= dictLimit); /* ip=base+current within current memory segment */
+ assert(ip < iend); /* condition for ZSTD_count */
while (nbCompares-- && (matchIndex > windowLow)) {
U32* const nextPtr = bt + 2*(matchIndex & btMask);
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u", current, matchIndex);
assert(matchIndex < current);
- if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
- assert(matchIndex+matchLength >= dictLimit); /* might be wrong if extDict is incorrectly set to 0 */
- match = base + matchIndex;
+ if ( (!extDict)
+ || (matchIndex+matchLength >= dictLimit) /* both in current segment*/
+ || (current < dictLimit) /* both in extDict */) {
+ const BYTE* const mBase = !extDict || (matchIndex >= dictLimit) ? base : dictBase;
+ assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */
+ || (current < dictLimit) );
+ match = mBase + matchIndex;
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
} else {
match = dictBase + matchIndex;
@@ -122,6 +122,9 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
}
+ DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ",
+ current, 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 */
}
@@ -131,7 +134,7 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
*smallerPtr = matchIndex; /* update smaller idx */
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
- DEBUGLOG(8, "ZSTD_insertDUBT1: selecting next candidate from %u (>btLow=%u) => %u",
+ DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is smaller : next => %u",
matchIndex, btLow, nextPtr[1]);
smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
@@ -140,7 +143,7 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
*largerPtr = matchIndex;
commonLengthLarger = matchLength;
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
- DEBUGLOG(8, "ZSTD_insertDUBT1: selecting next candidate from %u (>btLow=%u) => %u",
+ DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is larger => %u",
matchIndex, btLow, nextPtr[0]);
largerPtr = nextPtr;
matchIndex = nextPtr[0];
@@ -196,7 +199,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
if ( (matchIndex > unsortLimit)
&& (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
- DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: nullify last unsorted candidate %u",
+ DEBUGLOG(7, "ZSTD_insertBtAndFindBestMatch: nullify last unsorted candidate %u",
matchIndex);
*nextCandidate = *unsortedMark = 0; /* nullify next candidate if it's still unsorted (note : simplification, detrimental to compression ratio, beneficial for speed) */
}
@@ -272,9 +275,11 @@ static size_t ZSTD_insertBtAndFindBestMatch (
assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
- if (bestLength)
- DEBUGLOG(7, "ZSTD_insertBtAndFindBestMatch(%u) : found match of length %u",
- current, (U32)bestLength);
+ if (bestLength >= MINMATCH) {
+ U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+ DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+ current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+ }
return bestLength;
}
}
@@ -287,6 +292,7 @@ static size_t ZSTD_BtFindBestMatch (
size_t* offsetPtr,
const U32 maxNbAttempts, const U32 mls)
{
+ DEBUGLOG(7, "ZSTD_BtFindBestMatch");
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
ZSTD_updateDUBT(zc, ip, iLimit, mls);
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
@@ -317,6 +323,7 @@ static size_t ZSTD_BtFindBestMatch_extDict (
size_t* offsetPtr,
const U32 maxNbAttempts, const U32 mls)
{
+ DEBUGLOG(7, "ZSTD_BtFindBestMatch_extDict");
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
ZSTD_updateDUBT(zc, ip, iLimit, mls);
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
index a59d94411..ab6c2edc5 100644
--- a/lib/decompress/zstd_decompress.c
+++ b/lib/decompress/zstd_decompress.c
@@ -204,6 +204,7 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
ZSTD_DCtx* ZSTD_createDCtx(void)
{
+ DEBUGLOG(3, "ZSTD_createDCtx");
return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
}
@@ -2247,6 +2248,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
ZSTD_DStream* ZSTD_createDStream(void)
{
+ DEBUGLOG(3, "ZSTD_createDStream");
return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
}
@@ -2273,6 +2275,7 @@ size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
{
+ DEBUGLOG(4, "ZSTD_initDStream_usingDict");
zds->streamStage = zdss_loadHeader;
zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
ZSTD_freeDDict(zds->ddictLocal);
@@ -2289,6 +2292,7 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
/* note : this variant can't fail */
size_t ZSTD_initDStream(ZSTD_DStream* zds)
{
+ DEBUGLOG(4, "ZSTD_initDStream");
return ZSTD_initDStream_usingDict(zds, NULL, 0);
}
@@ -2304,6 +2308,7 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict)
size_t ZSTD_resetDStream(ZSTD_DStream* zds)
{
+ DEBUGLOG(4, "ZSTD_resetDStream");
zds->streamStage = zdss_loadHeader;
zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
zds->legacyVersion = 0;
From 00db4dbbb345ffd4e85d0360439333ee7107277b Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 30 Dec 2017 15:42:28 +0100
Subject: [PATCH 019/255] fixed minor argument property for Visual
---
lib/compress/zstd_opt.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c
index 6af5c7111..04824ccf2 100644
--- a/lib/compress/zstd_opt.c
+++ b/lib/compress/zstd_opt.c
@@ -10,7 +10,6 @@
#include "zstd_compress_internal.h"
#include "zstd_opt.h"
-#include "zstd_lazy.h" /* ZSTD_updateTree, ZSTD_updateTree_extDict */
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats. Also used for matchSum (?) */
@@ -392,13 +391,13 @@ void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
}
void ZSTD_updateTree(ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- const U32 nbCompares, const U32 mls)
+ const BYTE* ip, const BYTE* iend,
+ U32 nbCompares, U32 mls)
{
ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
}
-void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
+static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
const BYTE* const ip, const BYTE* const iend,
const U32 nbCompares, const U32 mls)
{
From 2eff2171366239a129c35aae4cd610661770e812 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sun, 31 Dec 2017 15:50:00 +0100
Subject: [PATCH 020/255] updated /lib documentation
---
lib/README.md | 57 +++++++++++++++++++++++++++++----------------------
1 file changed, 32 insertions(+), 25 deletions(-)
diff --git a/lib/README.md b/lib/README.md
index df136c486..8a13b4e3d 100644
--- a/lib/README.md
+++ b/lib/README.md
@@ -2,16 +2,19 @@ Zstandard library files
================================
The __lib__ directory is split into several sub-directories,
-in order to make it easier to select or exclude specific features.
+in order to make it easier to select or exclude features.
#### Building
-`Makefile` script is provided, supporting the standard set of commands,
-directories, and variables (see https://www.gnu.org/prep/standards/html_node/Command-Variables.html).
+`Makefile` script is provided, supporting all standard [Makefile conventions](https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html#Makefile-Conventions),
+including commands variables, staged install, directory variables and standard targets.
- `make` : generates both static and dynamic libraries
- `make install` : install libraries in default system directories
+`libzstd` default scope includes compression, decompression, dictionary building,
+and decoding support for legacy formats >= v0.4.0.
+
#### API
@@ -27,29 +30,37 @@ Optional advanced features are exposed via :
- `ZSTD_STATIC_LINKING_ONLY` : if this macro is defined _before_ including `zstd.h`,
it unlocks access to advanced experimental API,
exposed in second part of `zstd.h`.
- These APIs shall ___never be used with dynamic library___ !
- They are not "stable", their definition may change in the future.
+ These APIs are not "stable", their definition may change in the future.
+ As a consequencem, it shall ___never be used with dynamic library___ !
Only static linking is allowed.
#### Modular build
+It's possible to compile only a limited set of features.
+
- Directory `lib/common` is always required, for all variants.
- Compression source code lies in `lib/compress`
- Decompression source code lies in `lib/decompress`
- It's possible to include only `compress` or only `decompress`, they don't depend on each other.
- `lib/dictBuilder` : makes it possible to generate dictionaries from a set of samples.
- The API is exposed in `lib/dictBuilder/zdict.h`.
- This module depends on both `lib/common` and `lib/compress` .
-- `lib/legacy` : source code to decompress older zstd formats, starting from `v0.1`.
- This module depends on `lib/common` and `lib/decompress`.
- To enable this feature, it's necessary to define `ZSTD_LEGACY_SUPPORT = 1` during compilation.
- Typically, with `gcc`, add argument `-DZSTD_LEGACY_SUPPORT=1`.
- Using higher number limits the number of version supported.
- For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats starting from v0.2+".
- The API is exposed in `lib/legacy/zstd_legacy.h`.
- Each version also provides a (dedicated) set of advanced API.
- For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` .
+ The API is exposed in `lib/dictBuilder/zdict.h`.
+ This module depends on both `lib/common` and `lib/compress` .
+- `lib/legacy` : source code to decompress legacy zstd formats, starting from `v0.1.0`.
+ This module depends on `lib/common` and `lib/decompress`.
+ To enable this feature, it's required to define `ZSTD_LEGACY_SUPPORT` during compilation.
+ Typically, with `gcc`, add argument `-DZSTD_LEGACY_SUPPORT=1`.
+ Using higher number limits versions supported.
+ For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats >= v0.2.0".
+ `ZSTD_LEGACY_SUPPORT=3` means : "support legacy formats >= v0.3.0", and so on.
+ Starting v0.8.0, all versions of `zstd` produce frames compliant with specification.
+ As a consequence, `ZSTD_LEGACY_SUPPORT=8` (or more) doesn't trigger legacy support.
+ Also, `ZSTD_LEGACY_SUPPORT=0` means "do __not__ support legacy formats".
+ Once enabled, this capability is transparently triggered within decompression functions.
+ It's also possible to invoke directly legacy API, as exposed in `lib/legacy/zstd_legacy.h`.
+ Each version also provides an additional dedicated set of advanced API.
+ For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` .
+ Note : `lib/legacy` only supports _decoding_ legacy formats.
#### Multithreading support
@@ -57,19 +68,16 @@ Optional advanced features are exposed via :
Multithreading is disabled by default when building with `make`.
Enabling multithreading requires 2 conditions :
- set macro `ZSTD_MULTITHREAD`
-- on POSIX systems : compile with pthread (`-pthread` compilation flag for `gcc` for example)
+- on POSIX systems : compile with pthread (`-pthread` compilation flag for `gcc`)
Both conditions are automatically triggered by invoking `make lib-mt` target.
Note that, when linking a POSIX program with a multithreaded version of `libzstd`,
it's necessary to trigger `-pthread` flag during link stage.
-Multithreading capabilities are exposed via :
-- private API `lib/compress/zstdmt_compress.h`.
- Symbols defined in this header are currently exposed in `libzstd`, hence usable.
- Note however that this API is planned to be locked and remain strictly internal in the future.
-- advanced API `ZSTD_compress_generic()`, defined in `lib/zstd.h`, experimental section.
- This API is still considered experimental, but is designed to be labelled "stable" at some point in the future.
- It's the recommended entry point for multi-threading operations.
+Multithreading capabilities are exposed
+via [advanced API `ZSTD_compress_generic()` defined in `lib/zstd.h`](https://github.com/facebook/zstd/blob/dev/lib/zstd.h#L919).
+This API is still considered experimental,
+but is expected to become "stable" at some point in the future.
#### Windows : using MinGW+MSYS to create DLL
@@ -92,7 +100,6 @@ The compiled executable will require ZSTD DLL which is available at `dll\libzstd
Obsolete API on their way out are stored in directory `lib/deprecated`.
At this stage, it contains older streaming prototypes, in `lib/deprecated/zbuff.h`.
-Presence in this directory is temporary.
These prototypes will be removed in some future version.
Consider migrating code towards supported streaming API exposed in `zstd.h`.
From e0596715dcf57cd431394d923d63dfe5aaf49749 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?=
Date: Tue, 2 Jan 2018 15:17:32 +0000
Subject: [PATCH 021/255] zstd: fix crash when not overwriting existing files
This fixes the following crash:
$ touch exists
$ programs/zstd -r examples/ -o exists
zstd: exists already exists; not overwritten
Segmentation fault (core dumped)
* programs/fileio.c (FIO_compressMultipleFilenames):
Handle the case where we're not overwriting the destination.
Reported at https://bugzilla.redhat.com/1530049
---
programs/fileio.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/programs/fileio.c b/programs/fileio.c
index b57ce14d2..f9c9087ba 100644
--- a/programs/fileio.c
+++ b/programs/fileio.c
@@ -951,10 +951,14 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
if (outFileName != NULL) {
unsigned u;
ress.dstFile = FIO_openDstFile(outFileName);
- for (u=0; u
Date: Wed, 3 Jan 2018 14:02:44 -0800
Subject: [PATCH 022/255] Add test case for PR #972
---
tests/playTests.sh | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tests/playTests.sh b/tests/playTests.sh
index c93c58fe8..b5ffadc23 100755
--- a/tests/playTests.sh
+++ b/tests/playTests.sh
@@ -190,6 +190,13 @@ $ZSTD -t tmp1.zst tmp2.zst
$ZSTD -dc tmp1.zst tmp2.zst
$ZSTD tmp1.zst tmp2.zst -o "$INTOVOID"
$ZSTD -d tmp1.zst tmp2.zst -o tmp
+touch tmpexists
+$ZSTD tmp1 tmp2 -f -o tmpexists
+$ZSTD tmp1 tmp2 -o tmpexists && die "should have refused to overwrite"
+# Bug: PR #972
+if [ "$?" -eq 139 ]; then
+ die "should not have segfaulted"
+fi
rm tmp*
From fd63140e1c79369e6d1e90bf1849569e1477f4ec Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Fri, 5 Jan 2018 11:44:25 -0800
Subject: [PATCH 023/255] [util] Refuse to set file stat on non-regular file
---
programs/util.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/programs/util.h b/programs/util.h
index af1fa7fca..4f22236a9 100644
--- a/programs/util.h
+++ b/programs/util.h
@@ -246,11 +246,17 @@ UTIL_STATIC void UTIL_waitForNextTick(void)
#endif
+UTIL_STATIC int UTIL_isRegularFile(const char* infilename);
+
+
UTIL_STATIC int UTIL_setFileStat(const char *filename, stat_t *statbuf)
{
int res = 0;
struct utimbuf timebuf;
+ if (!UTIL_isRegularFile(filename))
+ return -1;
+
timebuf.actime = time(NULL);
timebuf.modtime = statbuf->st_mtime;
res += utime(filename, &timebuf); /* set access and modification times */
From 282ad05e0a4214e429682062716ccd9ad5bafc23 Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Fri, 5 Jan 2018 11:44:45 -0800
Subject: [PATCH 024/255] [fileio] Use FIO_remove() everywhere for safety
---
programs/fileio.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/programs/fileio.c b/programs/fileio.c
index f9c9087ba..71b87d4d5 100644
--- a/programs/fileio.c
+++ b/programs/fileio.c
@@ -139,7 +139,10 @@ static void INThandler(int sig)
#if !defined(_MSC_VER)
signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio */
#endif
- if (g_artefact) remove(g_artefact);
+ if (g_artefact) {
+ assert(UTIL_isRegularFile(g_artefact));
+ remove(g_artefact);
+ }
DISPLAY("\n");
exit(2);
}
@@ -861,7 +864,7 @@ static int FIO_compressFilename_srcFile(cRess_t ress,
* delete both the source and destination files.
*/
clearHandler();
- if (remove(srcFileName))
+ if (FIO_remove(srcFileName))
EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno));
}
return result;
@@ -899,10 +902,12 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
result=1;
}
if (result!=0) { /* remove operation artefact */
- if (remove(dstFileName))
+ if (FIO_remove(dstFileName))
EXM_THROW(1, "zstd: %s: %s", dstFileName, strerror(errno));
}
- else if (strcmp (dstFileName, stdoutmark) && stat_result)
+ else if ( strcmp(dstFileName, stdoutmark)
+ && strcmp(dstFileName, nulmark)
+ && stat_result)
UTIL_setFileStat(dstFileName, &statbuf);
return result;
@@ -1575,7 +1580,7 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const ch
* delete both the source and destination files.
*/
clearHandler();
- if (remove(srcFileName)) {
+ if (FIO_remove(srcFileName)) {
/* failed to remove src file */
DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno));
return 1;
@@ -1618,7 +1623,7 @@ static int FIO_decompressDstFile(dRess_t ress,
if ( (result != 0) /* operation failure */
&& strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */
&& strcmp(dstFileName, stdoutmark) ) /* special case : don't remove() stdout */
- remove(dstFileName); /* remove decompression artefact; note don't do anything special if remove() fails */
+ FIO_remove(dstFileName); /* remove decompression artefact; note don't do anything special if remove() fails */
else { /* operation success */
if ( strcmp(dstFileName, stdoutmark) /* special case : don't chmod stdout */
&& strcmp(dstFileName, nulmark) /* special case : don't chmod /dev/null */
From ed9611dc62bb1376012d229b0e6f7f974f5266db Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Fri, 5 Jan 2018 11:49:55 -0800
Subject: [PATCH 025/255] [fileio] Don't call FIO_remove() on stdout or
/dev/null
---
programs/fileio.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/programs/fileio.c b/programs/fileio.c
index 71b87d4d5..887cbeb37 100644
--- a/programs/fileio.c
+++ b/programs/fileio.c
@@ -901,10 +901,10 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno));
result=1;
}
- if (result!=0) { /* remove operation artefact */
- if (FIO_remove(dstFileName))
- EXM_THROW(1, "zstd: %s: %s", dstFileName, strerror(errno));
- }
+ if ( (result != 0) /* operation failure */
+ && strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null */
+ && strcmp(dstFileName, stdoutmark) ) /* special case : don't remove() stdout */
+ FIO_remove(dstFileName); /* remove compression artefact; note don't do anything special if remove() fails */
else if ( strcmp(dstFileName, stdoutmark)
&& strcmp(dstFileName, nulmark)
&& stat_result)
From 3d578eef0c899200e407b737726bd181e6ecd5af Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 6 Jan 2018 07:13:09 +0100
Subject: [PATCH 026/255] minor tests/Makefile change, as suggested by
@terrelln
https://github.com/facebook/zstd/pull/965#discussion_r160008006
---
tests/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Makefile b/tests/Makefile
index 258212db1..48ae17538 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -115,7 +115,7 @@ zstdc_%.o : $(ZSTDDIR)/compress/%.c
zstdd_%.o : $(ZSTDDIR)/decompress/%.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
-zstdmt%.o : CPPFLAGS += -DZSTD_MULTITHREAD=1
+zstdmt%.o : CPPFLAGS += $(MULTITHREAD_CPP)
zstdmt_m_%.o : $(ZSTDDIR)/common/%.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
From a927fae2a190fda3b72845e3f795664c4c4ab16a Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 6 Jan 2018 12:31:26 +0100
Subject: [PATCH 027/255] fixed ZSTD_reduceIndex()
following suggestions from @terrelln.
Also added some comments to present logic behind ZSTD_preserveUnsortedMark().
---
lib/compress/zstd_compress.c | 7 +------
lib/compress/zstd_lazy.c | 18 +++++++++++++++---
tests/playTests.sh | 1 +
3 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index a804efca5..108229dea 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -1146,14 +1146,9 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);
}
- if (zc->appliedParams.cParams.strategy != ZSTD_btlazy2) {
- U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
- ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
- }
-
if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
- if (zc->appliedParams.cParams.strategy != ZSTD_btlazy2)
+ if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
ZSTD_preserveUnsortedMark(zc->chainTable, chainSize, reducerValue);
ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
}
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 9385bf423..7261cffcf 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -22,9 +22,21 @@
The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled by a table re-use using a different strategy */
/*! ZSTD_preserveUnsortedMark() :
- * pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK
- * before ZSTD_reduceTable()
- * sp that final operation preserves its value */
+ * pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK before ZSTD_reduceTable()
+ * so that combined operation preserves its value.
+ * Without it, ZSTD_DUBT_UNSORTED_MARK==1 would be squashed to 0.
+ * As a consequence, the list of unsorted elements would stop on the first element,
+ * removing candidates, resulting in a negligible loss to compression ratio
+ * (since overflow protection with ZSTD_reduceTable() is relatively rare).
+ * Another potential risk is that a position will be promoted from *unsorted*
+ * to *sorted=>smaller:0*, meaning the next candidate will be considered smaller.
+ * This could be wrong, and result in data corruption.
+ * On second thought, this corruption might be impossible,
+ * because unsorted elements are always at the beginning of the list,
+ * and squashing to zero reduce the list to a single element,
+ * which needs to be sorted anyway.
+ * I haven't spent much thoughts into this possible scenario,
+ * and just felt it was safer to implement ZSTD_preserveUnsortedMark() */
void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue)
{
U32 u;
diff --git a/tests/playTests.sh b/tests/playTests.sh
index ee93b10a5..bb68e6529 100755
--- a/tests/playTests.sh
+++ b/tests/playTests.sh
@@ -93,6 +93,7 @@ else
hasMT="true"
fi
+
$ECHO "\n===> simple tests "
./datagen > tmp
From b17fb488b0fd57e7b3c028a54ffd87c1f6878045 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 6 Jan 2018 20:50:36 +0100
Subject: [PATCH 028/255] fixed msan test
a pointer calculation was wrong in a corner case
---
lib/compress/zstd_lazy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 7261cffcf..4af843d1b 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -122,7 +122,7 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
if ( (!extDict)
|| (matchIndex+matchLength >= dictLimit) /* both in current segment*/
|| (current < dictLimit) /* both in extDict */) {
- const BYTE* const mBase = !extDict || (matchIndex >= dictLimit) ? base : dictBase;
+ const BYTE* const mBase = !extDict || ((matchIndex+matchLength) >= dictLimit) ? base : dictBase;
assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */
|| (current < dictLimit) );
match = mBase + matchIndex;
From 3ea156368c4b49c0c445c307acba44e98c21c1a6 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 10 Jan 2018 08:47:19 -0800
Subject: [PATCH 029/255] API doc : grouped ZSTD_initStatic*() together
within "memory management" category.
---
lib/compress/zstd_compress.c | 1 -
lib/zstd.h | 173 ++++++++++++++---------------------
2 files changed, 69 insertions(+), 105 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 8d1629246..ef7d3a343 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -2416,7 +2416,6 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
+ cctxSize;
ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
void* ptr;
- DEBUGLOG(4, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
(U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
diff --git a/lib/zstd.h b/lib/zstd.h
index 9ac0a73dc..9971d4762 100644
--- a/lib/zstd.h
+++ b/lib/zstd.h
@@ -45,11 +45,11 @@ extern "C" {
Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory.
Compression can be done in:
- a single step (described as Simple API)
- - a single step, reusing a context (described as Explicit memory management)
+ - a single step, reusing a context (described as Explicit context)
- unbounded multiple steps (described as Streaming compression)
The compression ratio achievable on small data can be highly improved using a dictionary in:
- a single step (described as Simple dictionary API)
- - a single step, reusing a dictionary (described as Fast dictionary API)
+ - a single step, reusing a dictionary (described as Bulk-processing dictionary API)
Advanced experimental functions can be accessed using #define ZSTD_STATIC_LINKING_ONLY before including zstd.h.
Advanced experimental APIs shall never be used with a dynamic library.
@@ -68,7 +68,7 @@ ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll versio
#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); /* v1.3.0 */
+ZSTDLIB_API const char* ZSTD_versionString(void); /* added in v1.3.0 */
/***************************************
@@ -92,7 +92,7 @@ ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity,
ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
const void* src, size_t compressedSize);
-/*! ZSTD_getFrameContentSize() : v1.3.0
+/*! ZSTD_getFrameContentSize() : added in v1.3.0
* `src` should point to the start of a ZSTD encoded frame.
* `srcSize` must be at least as large as the frame header.
* hint : any size >= `ZSTD_frameHeaderSize_max` is large enough.
@@ -120,26 +120,24 @@ ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t
/*! ZSTD_getDecompressedSize() :
* NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
- * Both functions work the same way,
- * but ZSTD_getDecompressedSize() blends
- * "empty", "unknown" and "error" results in the same return value (0),
- * while ZSTD_getFrameContentSize() distinguishes them.
- *
- * 'src' is the start of a zstd compressed frame.
- * @return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise. */
+ * Both functions work the same way, but ZSTD_getDecompressedSize() blends
+ * "empty", "unknown" and "error" results to the same return value (0),
+ * while ZSTD_getFrameContentSize() gives them separate return values.
+ * `src` is the start of a zstd compressed frame.
+ * @return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise. */
ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
/*====== Helper functions ======*/
#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */
-ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */
+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_maxCLevel(void); /*!< maximum compression level available */
/***************************************
-* Explicit memory management
+* Explicit context
***************************************/
/*= Compression context
* When compressing many times,
@@ -345,7 +343,7 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output
* *******************************************************************************/
typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same object (>= v1.3.0) */
- /* Continue to distinguish them for compatibility with versions <= v1.2.0 */
+ /* For compatibility with versions <= v1.2.0, continue to consider them separated. */
/*===== ZSTD_DStream management functions =====*/
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
@@ -375,7 +373,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output
/* --- Constants ---*/
#define ZSTD_MAGICNUMBER 0xFD2FB528 /* >= v0.8.0 */
#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U
-#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* v0.7+ */
+#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* >= v0.7.0 */
#define ZSTD_WINDOWLOG_MAX_32 30
#define ZSTD_WINDOWLOG_MAX_64 31
@@ -432,6 +430,18 @@ typedef struct {
typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
+typedef enum {
+ ZSTD_dm_auto=0, /* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
+ ZSTD_dm_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
+ ZSTD_dm_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */
+} ZSTD_dictMode_e;
+
+typedef enum {
+ ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */
+ ZSTD_dlm_byRef, /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
+} ZSTD_dictLoadMethod_e;
+
+
/*--- Custom memory allocation functions ---*/
typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
@@ -483,12 +493,12 @@ ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
/***************************************
-* Context memory usage
+* Memory management
***************************************/
/*! ZSTD_sizeof_*() :
* These functions give the current memory usage of selected object.
- * Object memory usage can evolve when re-used multiple times. */
+ * Object memory usage can evolve when re-used. */
ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
@@ -504,7 +514,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
* 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_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
- * Note : CCtx estimation is only correct for single-threaded compression */
+ * Note : CCtx size estimation is only correct for single-threaded compression. */
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);
@@ -516,7 +526,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
* If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
* ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
* ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
- * Note : CStream estimation is only correct for single-threaded compression.
+ * Note : CStream size estimation is only correct for single-threaded compression.
* ZSTD_DStream memory budget depends on window Size.
* This information can be passed manually, using ZSTD_estimateDStreamSize,
* or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
@@ -529,20 +539,53 @@ ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_para
ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
-typedef enum {
- ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */
- ZSTD_dlm_byRef, /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
-} ZSTD_dictLoadMethod_e;
-
/*! ZSTD_estimate?DictSize() :
* ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
- * ZSTD_estimateCStreamSize_advanced_usingCParams() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced().
- * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller
+ * 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);
+/*! ZSTD_initStatic*() :
+ * Initialize an object using a pre-allocated fixed-size buffer.
+ * workspace: The memory area to emplace the object into.
+ * Provided pointer *must be 8-bytes aligned*.
+ * Buffer must outlive object.
+ * workspaceSize: Use ZSTD_estimate*Size() to determine
+ * how large workspace must be to support target scenario.
+ * @return : pointer to object (same address as workspace, just different type),
+ * or NULL if error (size too small, incorrect alignment, etc.)
+ * Note : zstd will never resize nor malloc() when using a static buffer.
+ * If the object requires more memory than available,
+ * zstd will just error out (typically ZSTD_error_memory_allocation).
+ * Note 2 : there is no corresponding "free" function.
+ * Since workspace is allocated externally, it must be freed externally too.
+ * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level
+ * into its associated cParams.
+ * Limitation 1 : currently not compatible with internal dictionary creation, triggered by
+ * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict().
+ * 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_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_API ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictMode_e dictMode,
+ ZSTD_compressionParameters cParams);
+
+ZSTDLIB_API ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod);
+
+
/***************************************
* Advanced compression functions
@@ -551,35 +594,12 @@ ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e
* Create a ZSTD compression context using external alloc and free functions */
ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
-/*! ZSTD_initStaticCCtx() : initialize a fixed-size zstd compression context
- * workspace: The memory area to emplace the context into.
- * Provided pointer must 8-bytes aligned.
- * It must outlive context usage.
- * workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize()
- * to determine how large workspace must be to support scenario.
- * @return : pointer to ZSTD_CCtx* (same address as workspace, but different type),
- * or NULL if error (typically size too small)
- * Note : zstd will never resize nor malloc() when using a static cctx.
- * If it needs more memory than available, it will simply error out.
- * Note 2 : there is no corresponding "free" function.
- * Since workspace was allocated externally, it must be freed externally too.
- * Limitation 1 : currently not compatible with internal CDict creation, such as
- * ZSTD_CCtx_loadDictionary() or ZSTD_initCStream_usingDict().
- * Limitation 2 : currently not compatible with multi-threading
- */
-ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
-
-
/*! ZSTD_createCDict_byReference() :
* Create a digested dictionary for compression
* Dictionary content is simply referenced, and therefore stays in dictBuffer.
* It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict */
ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
-typedef enum { ZSTD_dm_auto=0, /* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
- ZSTD_dm_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
- ZSTD_dm_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */
-} ZSTD_dictMode_e;
/*! ZSTD_createCDict_advanced() :
* Create a ZSTD_CDict using external alloc and free, and customized compression parameters */
ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
@@ -588,26 +608,6 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictS
ZSTD_compressionParameters cParams,
ZSTD_customMem customMem);
-/*! ZSTD_initStaticCDict() :
- * Generate a digested dictionary in provided memory area.
- * workspace: The memory area to emplace the dictionary into.
- * Provided pointer must 8-bytes aligned.
- * It must outlive dictionary usage.
- * workspaceSize: Use ZSTD_estimateCDictSize()
- * to determine how large workspace must be.
- * cParams : use ZSTD_getCParams() to transform a compression level
- * into its relevants cParams.
- * @return : pointer to ZSTD_CDict* (same address as workspace, but different type),
- * or NULL if error (typically, size too small).
- * Note : there is no corresponding "free" function.
- * Since workspace was allocated externally, it must be freed externally.
- */
-ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict(
- void* workspace, size_t workspaceSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode,
- ZSTD_compressionParameters cParams);
-
/*! ZSTD_getCParams() :
* @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
* `estimatedSrcSize` value is optional, select 0 if not known */
@@ -656,24 +656,6 @@ ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);
* Create a ZSTD decompression context using external alloc and free functions */
ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
-/*! ZSTD_initStaticDCtx() : initialize a fixed-size zstd decompression context
- * workspace: The memory area to emplace the context into.
- * Provided pointer must 8-bytes aligned.
- * It must outlive context usage.
- * workspaceSize: Use ZSTD_estimateDCtxSize() or ZSTD_estimateDStreamSize()
- * to determine how large workspace must be to support scenario.
- * @return : pointer to ZSTD_DCtx* (same address as workspace, but different type),
- * or NULL if error (typically size too small)
- * Note : zstd will never resize nor malloc() when using a static dctx.
- * If it needs more memory than available, it will simply error out.
- * Note 2 : static dctx is incompatible with legacy support
- * Note 3 : there is no corresponding "free" function.
- * Since workspace was allocated externally, it must be freed externally.
- * Limitation : currently not compatible with internal DDict creation,
- * such as ZSTD_initDStream_usingDict().
- */
-ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize);
-
/*! ZSTD_createDDict_byReference() :
* Create a digested dictionary, ready to start decompression operation without startup delay.
* Dictionary content is referenced, and therefore stays in dictBuffer.
@@ -687,21 +669,6 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictS
ZSTD_dictLoadMethod_e dictLoadMethod,
ZSTD_customMem customMem);
-/*! ZSTD_initStaticDDict() :
- * Generate a digested dictionary in provided memory area.
- * workspace: The memory area to emplace the dictionary into.
- * Provided pointer must 8-bytes aligned.
- * It must outlive dictionary usage.
- * workspaceSize: Use ZSTD_estimateDDictSize()
- * to determine how large workspace must be.
- * @return : pointer to ZSTD_DDict*, or NULL if error (size too small)
- * Note : there is no corresponding "free" function.
- * Since workspace was allocated externally, it must be freed externally.
- */
-ZSTDLIB_API ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod);
-
/*! ZSTD_getDictID_fromDict() :
* Provides the dictID stored within dictionary.
* if @return == 0, the dictionary is not conformant with Zstandard specification.
@@ -733,7 +700,6 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
/*===== Advanced Streaming compression functions =====*/
ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
-ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */
ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< 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. */
ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
@@ -755,7 +721,6 @@ ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledg
/*===== Advanced Streaming decompression functions =====*/
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
-ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); /* obsolete : this API will be removed in a future version */
ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
From 292eeb672f8c4bec47191b9e1929c5e06d107a10 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 10 Jan 2018 09:07:47 -0800
Subject: [PATCH 030/255] api doc : grouped all ZSTD_create*_advanced()
functions together
in a new "custom memory allocator" paragraph
which is itself part of "memory management" category.
This makes it simpler to see the relation between the type and its usages.
---
lib/zstd.h | 61 +++++++++++++++++++++++++-----------------------------
1 file changed, 28 insertions(+), 33 deletions(-)
diff --git a/lib/zstd.h b/lib/zstd.h
index 9971d4762..c19496d02 100644
--- a/lib/zstd.h
+++ b/lib/zstd.h
@@ -442,13 +442,6 @@ typedef enum {
} ZSTD_dictLoadMethod_e;
-/*--- Custom memory allocation functions ---*/
-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;
-/* use this constant to defer to stdlib's functions */
-static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL };
-
/***************************************
* Frame size functions
@@ -585,14 +578,36 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSi
const void* dict, size_t dictSize,
ZSTD_dictLoadMethod_e dictLoadMethod);
+/*! Custom memory allocation :
+ * These prototypes make it possible to pass your own allocation/free functions.
+ * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below.
+ * All allocation/free operations will be completed using these custom variants instead of regular ones.
+ */
+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 */
+
+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_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictMode_e dictMode,
+ ZSTD_compressionParameters cParams,
+ ZSTD_customMem customMem);
+
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_customMem customMem);
+
/***************************************
* Advanced compression functions
***************************************/
-/*! ZSTD_createCCtx_advanced() :
- * Create a ZSTD compression context using external alloc and free functions */
-ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
/*! ZSTD_createCDict_byReference() :
* Create a digested dictionary for compression
@@ -600,14 +615,6 @@ ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
* It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict */
ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
-/*! ZSTD_createCDict_advanced() :
- * Create a ZSTD_CDict using external alloc and free, and customized compression parameters */
-ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictMode_e dictMode,
- ZSTD_compressionParameters cParams,
- ZSTD_customMem customMem);
-
/*! ZSTD_getCParams() :
* @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
* `estimatedSrcSize` value is optional, select 0 if not known */
@@ -652,10 +659,6 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
* Note 3 : Skippable Frame Identifiers are considered valid. */
ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);
-/*! ZSTD_createDCtx_advanced() :
- * Create a ZSTD decompression context using external alloc and free functions */
-ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
-
/*! ZSTD_createDDict_byReference() :
* Create a digested dictionary, ready to start decompression operation without startup delay.
* Dictionary content is referenced, and therefore stays in dictBuffer.
@@ -663,11 +666,6 @@ ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
* it must remain read accessible throughout the lifetime of DDict */
ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
-/*! ZSTD_createDDict_advanced() :
- * Create a ZSTD_DDict using external alloc and free, optionally by reference */
-ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_customMem customMem);
/*! ZSTD_getDictID_fromDict() :
* Provides the dictID stored within dictionary.
@@ -699,7 +697,6 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
********************************************************************/
/*===== Advanced Streaming compression functions =====*/
-ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< 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. */
ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
@@ -720,7 +717,6 @@ ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledg
/*===== Advanced Streaming decompression functions =====*/
-ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); /* obsolete : this API will be removed in a future version */
ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
@@ -891,8 +887,7 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
*
* This API is intended to replace all others experimental API.
* It can basically do all other use cases, and even new ones.
- * In constrast with _advanced() variants, it stands a reasonable chance to become "stable",
- * after a good testing period.
+ * It stands a reasonable chance to become "stable", after a good testing period.
*/
/* note on naming convention :
@@ -1137,7 +1132,7 @@ ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
* All parameters are back to default values.
* It's possible to modify compression parameters after a reset.
*/
-ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx); /* Not ready yet ! */
+ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);
/*! ZSTD_compress_generic_simpleArgs() :
@@ -1354,7 +1349,7 @@ ZSTDLIB_API void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);
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_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 */
From 0e88f6e97b62bbb66f5ac917c7d560dfb7ca4dab Mon Sep 17 00:00:00 2001
From: conor42
Date: Thu, 11 Jan 2018 11:42:58 +1000
Subject: [PATCH 031/255] Fix break condition in decompression noise test
The bug prevents noise being added
---
tests/fuzzer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 141bf6548..0f82ee61e 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -1412,7 +1412,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
size_t const skipLength = FUZ_rand(&lseed) & mask;
pos += skipLength;
}
- if (pos <= cSize) break;
+ if (pos >= cSize) break;
/* add noise */
{ U32 const nbBitsCodes = FUZ_rand(&lseed) % maxNbBits;
U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
From ff795580f2e9acb02d1a68b9e2f1d4a17a4e3343 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 10 Jan 2018 20:33:45 -0800
Subject: [PATCH 032/255] fixed bug #976, reported by @indygreg
constants in zstd.h should not depend on MIN() macro which existence is not guaranteed.
Added a test to check the specific constants.
The test is a bit too specific.
But I have found no way to control a more generic "are all macro already defined" condition,
especially as this is a valid construction (the missing macro might be defined later, intentionnally).
---
lib/zstd.h | 4 ++--
tests/fuzzer.c | 13 ++++++++++---
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/lib/zstd.h b/lib/zstd.h
index c19496d02..a84490d99 100644
--- a/lib/zstd.h
+++ b/lib/zstd.h
@@ -379,9 +379,9 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output
#define ZSTD_WINDOWLOG_MAX_64 31
#define ZSTD_WINDOWLOG_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64))
#define ZSTD_WINDOWLOG_MIN 10
-#define ZSTD_HASHLOG_MAX MIN(ZSTD_WINDOWLOG_MAX, 30)
+#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30)
#define ZSTD_HASHLOG_MIN 6
-#define ZSTD_CHAINLOG_MAX MIN(ZSTD_WINDOWLOG_MAX+1, 30)
+#define ZSTD_CHAINLOG_MAX ((ZSTD_WINDOWLOG_MAX < 29) ? ZSTD_WINDOWLOG_MAX+1 : 30)
#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
#define ZSTD_HASHLOG3_MAX 17
#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 141bf6548..13e856be0 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -65,11 +65,18 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
if (g_displayLevel>=4) fflush(stderr); } }
-/*-*******************************************************
-* Fuzzer functions
-*********************************************************/
+
#undef MIN
#undef MAX
+void FUZ_bug976()
+{ /* these constants shall not depend on MIN() macro */
+ assert(ZSTD_HASHLOG_MAX < 31);
+ assert(ZSTD_CHAINLOG_MAX < 31);
+}
+
+/*-*******************************************************
+* Internal functions
+*********************************************************/
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
From 2103a62b3d4b7c092021d7c21c0d2db7ad760841 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Thu, 11 Jan 2018 04:49:19 -0800
Subject: [PATCH 033/255] fixed minor warning on prototype definition
---
tests/fuzzer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 13e856be0..e0817e903 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -68,7 +68,7 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
#undef MIN
#undef MAX
-void FUZ_bug976()
+void FUZ_bug976(void)
{ /* these constants shall not depend on MIN() macro */
assert(ZSTD_HASHLOG_MAX < 31);
assert(ZSTD_CHAINLOG_MAX < 31);
From 218e9fe0fc25cc8bfd362d0086e23d070fbf9f5c Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Thu, 11 Jan 2018 09:42:38 -0800
Subject: [PATCH 034/255] added a test case for dictBuilder failure
cyclic data set makes the entropy stage fails
now, onto a fix for #304 ...
---
lib/compress/zstd_compress.c | 2 +-
lib/dictBuilder/cover.c | 21 ++++----
lib/dictBuilder/zdict.c | 97 ++++++++++++++++++++----------------
lib/dictBuilder/zdict.h | 85 +++++++++++++++----------------
tests/fuzzer.c | 9 ++++
5 files changed, 120 insertions(+), 94 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index ef7d3a343..b9e0ec44d 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -2869,7 +2869,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
if (params.nbThreads > 1) {
if (cctx->mtctx == NULL || (params.nbThreads != ZSTDMT_getNbThreads(cctx->mtctx))) {
DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbThreads=%u (previous: %u)",
- params.nbThreads, ZSTDMT_getNbThreads(cctx->mtctx));
+ params.nbThreads, (U32)ZSTDMT_getNbThreads(cctx->mtctx));
ZSTDMT_freeCCtx(cctx->mtctx);
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c
index efdffddbf..b68370671 100644
--- a/lib/dictBuilder/cover.c
+++ b/lib/dictBuilder/cover.c
@@ -537,8 +537,8 @@ static int COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
/* Checks */
if (totalSamplesSize < MAX(d, sizeof(U64)) ||
totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) {
- DISPLAYLEVEL(1, "Total samples size is too large, maximum size is %u MB\n",
- (COVER_MAX_SAMPLES_SIZE >> 20));
+ DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n",
+ (U32)(totalSamplesSize>>20), (COVER_MAX_SAMPLES_SIZE >> 20));
return 0;
}
/* Zero the context */
@@ -651,12 +651,16 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
}
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) {
- BYTE *const dict = (BYTE *)dictBuffer;
+ void *dictBuffer, size_t dictBufferCapacity,
+ const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+ ZDICT_cover_params_t parameters)
+{
+ BYTE* const dict = (BYTE*)dictBuffer;
COVER_ctx_t ctx;
COVER_map_t activeDmers;
+
+ /* Initialize global data */
+ g_displayLevel = parameters.zParams.notificationLevel;
/* Checks */
if (!COVER_checkParameters(parameters, dictBufferCapacity)) {
DISPLAYLEVEL(1, "Cover parameters incorrect\n");
@@ -671,8 +675,6 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
ZDICT_DICTSIZE_MIN);
return ERROR(dstSize_tooSmall);
}
- /* Initialize global data */
- g_displayLevel = parameters.zParams.notificationLevel;
/* Initialize context and activeDmers */
if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
parameters.d)) {
@@ -947,6 +949,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
unsigned k;
COVER_best_t best;
POOL_ctx *pool = NULL;
+
/* Checks */
if (kMinK < kMaxD || kMaxK < kMinK) {
LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
@@ -1004,7 +1007,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
data->parameters.k = k;
data->parameters.d = d;
data->parameters.steps = kSteps;
- data->parameters.zParams.notificationLevel = g_displayLevel;
+ data->parameters.zParams.notificationLevel = displayLevel;
/* Check the parameters */
if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) {
DISPLAYLEVEL(1, "Cover parameters incorrect\n");
diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c
index e8f454045..3a1649419 100644
--- a/lib/dictBuilder/zdict.c
+++ b/lib/dictBuilder/zdict.c
@@ -207,7 +207,6 @@ static dictItem ZDICT_analyzePos(
U32 cumulLength[LLIMIT] = {0};
U32 savings[LLIMIT] = {0};
const BYTE* b = (const BYTE*)buffer;
- size_t length;
size_t maxLength = LLIMIT;
size_t pos = suffix[start];
U32 end = start;
@@ -222,26 +221,30 @@ static dictItem ZDICT_analyzePos(
||(MEM_read16(b+pos+1) == MEM_read16(b+pos+3))
||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) {
/* skip and mark segment */
- U16 u16 = MEM_read16(b+pos+4);
- U32 u, e = 6;
- while (MEM_read16(b+pos+e) == u16) e+=2 ;
- if (b[pos+e] == b[pos+e-1]) e++;
- for (u=1; u=MINMATCHLENGTH);
+ { size_t length;
+ do {
+ end++;
+ length = ZDICT_count(b + pos, b + suffix[end]);
+ } while (length >= MINMATCHLENGTH);
+ }
/* look backward */
- do {
- length = ZDICT_count(b + pos, b + *(suffix+start-1));
- if (length >=MINMATCHLENGTH) start--;
- } while(length >= MINMATCHLENGTH);
+ { size_t length;
+ do {
+ length = ZDICT_count(b + pos, b + *(suffix+start-1));
+ if (length >=MINMATCHLENGTH) start--;
+ } while(length >= MINMATCHLENGTH);
+ }
/* exit if not found a minimum nb of repetitions */
if (end-start < minRatio) {
@@ -268,7 +271,7 @@ static dictItem ZDICT_analyzePos(
U32 selectedCount = 0;
U32 selectedID = currentID;
for (id =refinedStart; id < refinedEnd; id++) {
- if (b[ suffix[id] + searchLength] != currentChar) {
+ if (b[suffix[id] + searchLength] != currentChar) {
if (currentCount > selectedCount) {
selectedCount = currentCount;
selectedID = currentID;
@@ -297,20 +300,23 @@ static dictItem ZDICT_analyzePos(
memset(lengthList, 0, sizeof(lengthList));
/* look forward */
- do {
- end++;
- length = ZDICT_count(b + pos, b + suffix[end]);
- if (length >= LLIMIT) length = LLIMIT-1;
- lengthList[length]++;
- } while (length >=MINMATCHLENGTH);
+ { size_t length;
+ do {
+ end++;
+ length = ZDICT_count(b + pos, b + suffix[end]);
+ if (length >= LLIMIT) length = LLIMIT-1;
+ lengthList[length]++;
+ } while (length >=MINMATCHLENGTH);
+ }
/* look backward */
- length = MINMATCHLENGTH;
- while ((length >= MINMATCHLENGTH) & (start > 0)) {
- length = ZDICT_count(b + pos, b + suffix[start - 1]);
- if (length >= LLIMIT) length = LLIMIT - 1;
- lengthList[length]++;
- if (length >= MINMATCHLENGTH) start--;
+ { size_t length = MINMATCHLENGTH;
+ while ((length >= MINMATCHLENGTH) & (start > 0)) {
+ length = ZDICT_count(b + pos, b + suffix[start - 1]);
+ if (length >= LLIMIT) length = LLIMIT - 1;
+ lengthList[length]++;
+ if (length >= MINMATCHLENGTH) start--;
+ }
}
/* largest useful length */
@@ -345,12 +351,12 @@ static dictItem ZDICT_analyzePos(
/* mark positions done */
{ U32 id;
for (id=start; id solution.length) length = solution.length;
}
pEnd = (U32)(testedPos + length);
@@ -575,29 +581,30 @@ static void ZDICT_fillNoise(void* buffer, size_t length)
typedef struct
{
- ZSTD_CCtx* ref;
- ZSTD_CCtx* zc;
+ ZSTD_CCtx* ref; /* contains reference to dictionary */
+ ZSTD_CCtx* zc; /* working context */
void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */
} EStats_ress_t;
#define MAXREPOFFSET 1024
static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params,
- U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* litlengthCount, U32* repOffsets,
- const void* src, size_t srcSize, U32 notificationLevel)
+ U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* 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 cSize;
if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */
- { size_t const errorCode = ZSTD_copyCCtx(esr.zc, esr.ref, 0);
- if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_copyCCtx failed \n"); return; }
+ { size_t const errorCode = ZSTD_copyCCtx(esr.zc, esr.ref, 0);
+ if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_copyCCtx failed \n"); return; }
}
cSize = ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize);
if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (U32)srcSize); return; }
if (cSize) { /* if == 0; block is not compressible */
- const seqStore_t* seqStorePtr = ZSTD_getSeqStore(esr.zc);
+ const seqStore_t* const seqStorePtr = ZSTD_getSeqStore(esr.zc);
/* literals stats */
{ const BYTE* bytePtr;
@@ -688,6 +695,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
BYTE* dstPtr = (BYTE*)dstBuffer;
/* init */
+ DEBUGLOG(4, "ZDICT_analyzeEntropy");
esr.ref = ZSTD_createCCtx();
esr.zc = ZSTD_createCCtx();
esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX);
@@ -713,7 +721,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
goto _cleanup;
} }
- /* collect stats on all files */
+ /* collect stats on all samples */
for (u=0; u=1)
+ params.zParams.notificationLevel = ZSTD_DEBUG;
+#endif
return ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, dictBufferCapacity,
- samplesBuffer, samplesSizes,
- nbSamples, ¶ms);
+ samplesBuffer, samplesSizes, nbSamples,
+ ¶ms);
}
size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
- const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)
{
ZDICT_params_t params;
memset(¶ms, 0, sizeof(params));
diff --git a/lib/dictBuilder/zdict.h b/lib/dictBuilder/zdict.h
index 5f0000b1c..92f66415f 100644
--- a/lib/dictBuilder/zdict.h
+++ b/lib/dictBuilder/zdict.h
@@ -38,21 +38,21 @@ extern "C" {
/*! ZDICT_trainFromBuffer():
- * Train a dictionary from an array of samples.
- * Uses ZDICT_optimizeTrainFromBuffer_cover() single-threaded, with d=8 and steps=4.
- * 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`.
+ * Train a dictionary from an array of samples.
+ * Redirect towards ZDICT_optimizeTrainFromBuffer_cover() single-threaded, with d=8 and steps=4.
+ * 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: ZDICT_trainFromBuffer() requires about 9 bytes of memory for each input byte.
- * Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
- * It's obviously possible to target smaller or larger ones, just by specifying different `dictBufferCapacity`.
- * In general, it's recommended to provide a few thousands samples, but this can vary a lot.
+ * or an error code, which can be tested with ZDICT_isError().
+ * Note: ZDICT_trainFromBuffer() 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(void* dictBuffer, size_t dictBufferCapacity,
- const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples);
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples);
/*====== Helper functions ======*/
@@ -72,14 +72,14 @@ ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode);
* ==================================================================================== */
typedef struct {
- int compressionLevel; /* 0 means default; target a specific zstd compression level */
- unsigned notificationLevel; /* Write to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */
- unsigned dictID; /* 0 means auto mode (32-bits random value); other : force dictID value */
+ 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) */
} ZDICT_params_t;
/*! ZDICT_cover_params_t:
- * For all values 0 means default.
* 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+] */
@@ -91,28 +91,28 @@ typedef struct {
/*! 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`.
+ * 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().
- * 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 obviously possible to target smaller or larger ones, just by specifying different `dictBufferCapacity`.
- * In general, it's recommended to provide a few thousands samples, but this can vary a lot.
+ * or an error code, which can be tested with ZDICT_isError().
+ * 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,
+ 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, and the dictionary
- * constructed with those parameters is stored in `dictBuffer`.
+ * `*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, 10, 12, 14, 16}.
@@ -125,9 +125,9 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
* 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);
+ void* dictBuffer, size_t dictBufferCapacity,
+ const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+ ZDICT_cover_params_t* parameters);
/*! ZDICT_finalizeDictionary():
* Given a custom content as a basis for dictionary, and a set of samples,
@@ -157,22 +157,23 @@ typedef struct {
} 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`.
+ * 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().
- * Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
- * It's obviously possible to target smaller or larger ones, just by specifying different `dictBufferCapacity`.
- * In general, it's recommended to provide a few thousands samples, but this can vary a lot.
+ * or an error code, which can be tested with ZDICT_isError().
+ * 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.
+ * 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);
+ 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,
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 141bf6548..7198329a8 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -673,6 +673,15 @@ static int basicUnitTests(U32 seed, double compressibility)
goto _output_error;
}
+ DISPLAYLEVEL(4, "test%3i : dictBuilder on cyclic data : ", testNb++);
+ assert(compressedBufferSize >= totalSampleSize);
+ { U32 u; for (u=0; u
Date: Thu, 11 Jan 2018 11:16:32 -0800
Subject: [PATCH 035/255] fixed #304
Pathological samples may result in literal section being incompressible.
This case is now detected,
and literal distribution is replaced by one that can be written into the dictionary.
---
lib/common/huf.h | 4 ++--
lib/compress/huf_compress.c | 1 +
lib/dictBuilder/zdict.c | 32 +++++++++++++++++++++++++-------
tests/fuzzer.c | 18 ++++++++++--------
4 files changed, 38 insertions(+), 17 deletions(-)
diff --git a/lib/common/huf.h b/lib/common/huf.h
index 522bf9b6c..1cead357a 100644
--- a/lib/common/huf.h
+++ b/lib/common/huf.h
@@ -206,10 +206,10 @@ The following API allows targeting specific sub-functions for advanced tasks.
For example, it's possible to compress several blocks using the same 'CTable',
or to save and regenerate 'CTable' using external methods.
*/
-/* FSE_count() : find it within "fse.h" */
+/* FSE_count() : exposed within "fse.h" */
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);
+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_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c
index 5692d56e0..cfc5a98bb 100644
--- a/lib/compress/huf_compress.c
+++ b/lib/compress/huf_compress.c
@@ -405,6 +405,7 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValu
}
/** 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 U32* count, U32 maxSymbolValue, U32 maxNbBits)
diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c
index 3a1649419..2380599c9 100644
--- a/lib/dictBuilder/zdict.c
+++ b/lib/dictBuilder/zdict.c
@@ -666,6 +666,18 @@ static void ZDICT_insertSortCount(offsetCount_t table[ZSTD_REP_NUM+1], U32 val,
}
}
+/* ZDICT_flatLit() :
+ * rewrite `countLit` to contain a mostly flat but still compressible distribution of literals.
+ * necessary to avoid generating a non-compressible distribution that HUF_writeCTable() cannot encode.
+ */
+static void ZDICT_flatLit(U32* countLit)
+{
+ int u;
+ for (u=1; u<256; u++) countLit[u] = 2;
+ countLit[0] = 4;
+ countLit[253] = 1;
+ countLit[254] = 1;
+}
#define OFFCODE_MAX 30 /* only applicable to first block */
static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
@@ -730,14 +742,20 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
pos += fileSizes[u];
}
- /* analyze */
- errorCode = HUF_buildCTable (hufTable, countLit, 255, huffLog);
- if (HUF_isError(errorCode)) {
- eSize = ERROR(GENERIC);
- DISPLAYLEVEL(1, " HUF_buildCTable error \n");
- goto _cleanup;
+ /* analyze, build stats, starting with literals */
+ { size_t maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
+ if (HUF_isError(maxNbBits)) {
+ eSize = ERROR(GENERIC);
+ DISPLAYLEVEL(1, " HUF_buildCTable error \n");
+ goto _cleanup;
+ }
+ if (maxNbBits==8) { /* not compressible : will fail on HUF_writeCTable() */
+ ZDICT_flatLit(countLit); /* replace distribution by a fake "mostly flat but still compressible" distribution, that HUF_writeCTable() can encode */
+ maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
+ assert(maxNbBits==9);
+ }
+ huffLog = (U32)maxNbBits;
}
- huffLog = (U32)errorCode;
/* looking for most common first offsets */
{ U32 offset;
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 7198329a8..acb670b10 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -659,12 +659,13 @@ static int basicUnitTests(U32 seed, double compressibility)
/* Dictionary and dictBuilder tests */
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
- size_t dictSize = 16 KB;
- void* dictBuffer = malloc(dictSize);
+ size_t const dictBufferCapacity = 16 KB;
+ void* dictBuffer = malloc(dictBufferCapacity);
size_t const totalSampleSize = 1 MB;
size_t const sampleUnitSize = 8 KB;
U32 const nbSamples = (U32)(totalSampleSize / sampleUnitSize);
size_t* const samplesSizes = (size_t*) malloc(nbSamples * sizeof(size_t));
+ size_t dictSize;
U32 dictID;
if (dictBuffer==NULL || samplesSizes==NULL) {
@@ -675,16 +676,17 @@ static int basicUnitTests(U32 seed, double compressibility)
DISPLAYLEVEL(4, "test%3i : dictBuilder on cyclic data : ", testNb++);
assert(compressedBufferSize >= totalSampleSize);
- { U32 u; for (u=0; u
Date: Thu, 11 Jan 2018 11:29:28 -0800
Subject: [PATCH 036/255] added warning message
when pathological dataset is detected
(note : cover_optimize needs -v to display the warning)
---
lib/dictBuilder/cover.c | 2 +-
lib/dictBuilder/zdict.c | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c
index b68370671..b5a3957a9 100644
--- a/lib/dictBuilder/cover.c
+++ b/lib/dictBuilder/cover.c
@@ -1007,7 +1007,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
data->parameters.k = k;
data->parameters.d = d;
data->parameters.steps = kSteps;
- data->parameters.zParams.notificationLevel = displayLevel;
+ data->parameters.zParams.notificationLevel = g_displayLevel;
/* Check the parameters */
if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) {
DISPLAYLEVEL(1, "Cover parameters incorrect\n");
diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c
index 2380599c9..7d24e4991 100644
--- a/lib/dictBuilder/zdict.c
+++ b/lib/dictBuilder/zdict.c
@@ -750,6 +750,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
goto _cleanup;
}
if (maxNbBits==8) { /* not compressible : will fail on HUF_writeCTable() */
+ DISPLAYLEVEL(2, "warning : pathological dataset : literals are not compressible : samples are noisy or too regular \n");
ZDICT_flatLit(countLit); /* replace distribution by a fake "mostly flat but still compressible" distribution, that HUF_writeCTable() can encode */
maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
assert(maxNbBits==9);
@@ -1052,8 +1053,9 @@ size_t ZDICT_trainFromBuffer_unsafe_legacy(
}
-/* issue : samplesBuffer need to be followed by a noisy guard band.
-* work around : duplicate the buffer, and add the noise */
+/* ZDICT_trainFromBuffer_legacy() :
+ * issue : samplesBuffer need to be followed by a noisy guard band.
+ * work around : duplicate the buffer, and add the noise */
size_t ZDICT_trainFromBuffer_legacy(void* dictBuffer, size_t dictBufferCapacity,
const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
ZDICT_legacy_params_t params)
From b9a14900ff95965868c5c21276cf59d509cd35a1 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Thu, 11 Jan 2018 12:38:31 -0800
Subject: [PATCH 037/255] changed function name to ZSTD_DUBT_findBestMatch()
---
lib/compress/zstd_lazy.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 4af843d1b..1d575804a 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -165,7 +165,7 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
}
-static size_t ZSTD_insertBtAndFindBestMatch (
+static size_t ZSTD_DUBT_findBestMatch (
ZSTD_CCtx* zc,
const BYTE* const ip, const BYTE* const iend,
size_t* offsetPtr,
@@ -192,14 +192,14 @@ static size_t ZSTD_insertBtAndFindBestMatch (
U32 nbCandidates = nbCompares;
U32 previousCandidate = 0;
- DEBUGLOG(7, "ZSTD_insertBtAndFindBestMatch (%u) ", current);
+ DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current);
assert(ip <= iend-8); /* required for h calculation */
/* reach end of unsorted candidates list */
while ( (matchIndex > unsortLimit)
&& (*unsortedMark == ZSTD_DUBT_UNSORTED_MARK)
&& (nbCandidates > 1) ) {
- DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch: candidate %u is unsorted",
+ DEBUGLOG(8, "ZSTD_DUBT_findBestMatch: candidate %u is unsorted",
matchIndex);
*unsortedMark = previousCandidate;
previousCandidate = matchIndex;
@@ -211,7 +211,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
if ( (matchIndex > unsortLimit)
&& (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
- DEBUGLOG(7, "ZSTD_insertBtAndFindBestMatch: nullify last unsorted candidate %u",
+ DEBUGLOG(7, "ZSTD_DUBT_findBestMatch: nullify last unsorted candidate %u",
matchIndex);
*nextCandidate = *unsortedMark = 0; /* nullify next candidate if it's still unsorted (note : simplification, detrimental to compression ratio, beneficial for speed) */
}
@@ -289,7 +289,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
if (bestLength >= MINMATCH) {
U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
- DEBUGLOG(8, "ZSTD_insertBtAndFindBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+ DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
current, (U32)bestLength, (U32)*offsetPtr, mIndex);
}
return bestLength;
@@ -307,7 +307,7 @@ static size_t ZSTD_BtFindBestMatch (
DEBUGLOG(7, "ZSTD_BtFindBestMatch");
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
ZSTD_updateDUBT(zc, ip, iLimit, mls);
- return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
+ return ZSTD_DUBT_findBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
}
@@ -338,7 +338,7 @@ static size_t ZSTD_BtFindBestMatch_extDict (
DEBUGLOG(7, "ZSTD_BtFindBestMatch_extDict");
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
ZSTD_updateDUBT(zc, ip, iLimit, mls);
- return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
+ return ZSTD_DUBT_findBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
}
From b610b777d39c9eee139e7b73f32db5e2eafbd2e9 Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Thu, 11 Jan 2018 14:35:04 -0800
Subject: [PATCH 038/255] Increase windowLog from CDict based on the srcSize
when known
---
lib/compress/zstd_compress.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index b9e0ec44d..d11fbeb3c 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -2453,6 +2453,15 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
if (cdict==NULL) return ERROR(dictionary_wrong);
{ ZSTD_CCtx_params params = cctx->requestedParams;
params.cParams = ZSTD_getCParamsFromCDict(cdict);
+ /* 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_dm_auto,
From 4b7c4e5f41cdb3e6c670f1fcc7932e4028b52af3 Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Thu, 11 Jan 2018 16:45:16 -0800
Subject: [PATCH 039/255] Add test for cdict window log adjustment
---
tests/fuzzer.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 024a583ba..21d7d21a3 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -1206,6 +1206,28 @@ static int basicUnitTests(U32 seed, double compressibility)
if (strcmp("No error detected", ZSTD_getErrorName(ZSTD_error_GENERIC)) != 0) goto _output_error;
DISPLAYLEVEL(4, "OK \n");
+ DISPLAYLEVEL(4, "test%3i : testing ZSTD dictionary sizes : ", testNb++);
+ RDG_genBuffer(CNBuffer, CNBuffSize, compressibility, 0., seed);
+ {
+ size_t const size = MIN(128 KB, CNBuffSize);
+ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
+ ZSTD_CDict* const lgCDict = ZSTD_createCDict(CNBuffer, size, 1);
+ ZSTD_CDict* const smCDict = ZSTD_createCDict(CNBuffer, 1 KB, 1);
+ ZSTD_frameHeader lgHeader;
+ ZSTD_frameHeader smHeader;
+
+ CHECK_Z(ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize, CNBuffer, size, lgCDict));
+ CHECK_Z(ZSTD_getFrameHeader(&lgHeader, compressedBuffer, compressedBufferSize));
+ CHECK_Z(ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize, CNBuffer, size, smCDict));
+ CHECK_Z(ZSTD_getFrameHeader(&smHeader, compressedBuffer, compressedBufferSize));
+
+ if (lgHeader.windowSize != smHeader.windowSize) goto _output_error;
+
+ ZSTD_freeCDict(smCDict);
+ ZSTD_freeCDict(lgCDict);
+ ZSTD_freeCCtx(cctx);
+ }
+
_end:
free(CNBuffer);
free(compressedBuffer);
From 9a211d1f05bd8cb6cb80780bf1880c23204b7b68 Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Fri, 12 Jan 2018 12:26:47 -0800
Subject: [PATCH 040/255] Load more dictionary positions into table if empty
If the hash table is empty load positions into the hash table
that we would otherwise skip.
| Level | Data Set | Improvement |
|-------|--------------|-------------|
| 1 | github | 0.44% |
| 1 | hg-changelog | 0.13% |
| 1 | hg-commands | 1.28% |
| 1 | hg-manifest | 0.70% |
| 3 | github | 0.74% |
| 3 | hg-changelog | 0.87% |
| 3 | hg-commands | 1.74% |
| 3 | hg-manifest | 0.23% |
---
lib/compress/zstd_double_fast.c | 21 ++++++++++++++++-----
lib/compress/zstd_fast.c | 16 ++++++++++++----
2 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/lib/compress/zstd_double_fast.c b/lib/compress/zstd_double_fast.c
index fee5127c3..a6d8ad889 100644
--- a/lib/compress/zstd_double_fast.c
+++ b/lib/compress/zstd_double_fast.c
@@ -21,12 +21,23 @@ void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls)
const BYTE* const base = cctx->base;
const BYTE* ip = base + cctx->nextToUpdate;
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
- const size_t fastHashFillStep = 3;
+ const U32 fastHashFillStep = 3;
- while(ip <= iend) {
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
- hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
- ip += fastHashFillStep;
+ /* 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 current = (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;
+ if (i == 0 || hashLarge[lgHash] == 0)
+ hashLarge[lgHash] = current + i;
+ }
}
}
diff --git a/lib/compress/zstd_fast.c b/lib/compress/zstd_fast.c
index 7b56c3d6a..6497a2d8b 100644
--- a/lib/compress/zstd_fast.c
+++ b/lib/compress/zstd_fast.c
@@ -19,11 +19,19 @@ void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
const BYTE* const base = zc->base;
const BYTE* ip = base + zc->nextToUpdate;
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
- const size_t fastHashFillStep = 3;
+ const U32 fastHashFillStep = 3;
- while(ip <= iend) {
- hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
- ip += fastHashFillStep;
+ /* Always insert every fastHashFillStep position into the hash table.
+ * Insert the other positions if their hash entry is empty.
+ */
+ for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
+ U32 const current = (U32)(ip - base);
+ U32 i;
+ for (i = 0; i < fastHashFillStep; ++i) {
+ size_t const hash = ZSTD_hashPtr(ip + i, hBits, mls);
+ if (i == 0 || hashTable[hash] == 0)
+ hashTable[hash] = current + i;
+ }
}
}
From 58ecf13e025c3601391d0c001ef2369eaa0d747c Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 13 Jan 2018 13:18:57 -0800
Subject: [PATCH 041/255] zstdmt : can compress at block granularity
offering perspective of more accurate progression report.
---
lib/compress/zstdmt_compress.c | 101 +++++++++++++++++++++------------
programs/fileio.c | 2 +-
2 files changed, 67 insertions(+), 36 deletions(-)
diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
index e51edf124..3a5b58a72 100644
--- a/lib/compress/zstdmt_compress.c
+++ b/lib/compress/zstdmt_compress.c
@@ -22,6 +22,7 @@
/* ====== Dependencies ====== */
#include /* memcpy, memset */
+#include /* INT_MAX */
#include "pool.h" /* threadpool */
#include "threading.h" /* mutex */
#include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
@@ -129,7 +130,7 @@ static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
{
size_t const poolSize = sizeof(*bufPool)
- + (bufPool->totalBuffers - 1) * sizeof(buffer_t);
+ + (bufPool->totalBuffers - 1) * sizeof(buffer_t);
unsigned u;
size_t totalBufferSize = 0;
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
@@ -201,20 +202,6 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
ZSTD_free(buf.start, bufPool->cMem);
}
-/* Sets parameters relevant to the compression job, initializing others to
- * default values. Notably, nbThreads should probably be zero. */
-static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
-{
- ZSTD_CCtx_params jobParams;
- memset(&jobParams, 0, sizeof(jobParams));
-
- jobParams.cParams = params.cParams;
- jobParams.fParams = params.fParams;
- jobParams.compressionLevel = params.compressionLevel;
-
- jobParams.ldmParams = params.ldmParams;
- return jobParams;
-}
/* ===== CCtx Pool ===== */
/* a single CCtx Pool can be invoked from multiple threads in parallel */
@@ -305,13 +292,16 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
}
-/* ===== Thread worker ===== */
+/* ------------------------------------------ */
+/* ===== Thread worker ===== */
+/* ------------------------------------------ */
typedef struct {
buffer_t src;
const void* srcStart;
size_t prefixSize;
size_t srcSize;
+ size_t readSize;
buffer_t dstBuff;
size_t cSize;
size_t dstFlushed;
@@ -328,21 +318,19 @@ typedef struct {
unsigned long long fullFrameSize;
} ZSTDMT_jobDescription;
-/* ZSTDMT_compressChunk() : POOL_function type */
+/* ZSTDMT_compressChunk() is a POOL_function type */
void ZSTDMT_compressChunk(void* jobDescription)
{
ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool);
const void* const src = (const char*)job->srcStart + job->prefixSize;
buffer_t dstBuff = job->dstBuff;
- DEBUGLOG(5, "ZSTDMT_compressChunk: job (first:%u) (last:%u) : prefixSize %u, srcSize %u ",
- job->firstChunk, job->lastChunk, (U32)job->prefixSize, (U32)job->srcSize);
+ /* ressources */
if (cctx==NULL) {
job->cSize = ERROR(memory_allocation);
goto _endJob;
}
-
if (dstBuff.start == NULL) {
dstBuff = ZSTDMT_getBuffer(job->bufPool);
if (dstBuff.start==NULL) {
@@ -350,30 +338,26 @@ void ZSTDMT_compressChunk(void* jobDescription)
goto _endJob;
}
job->dstBuff = dstBuff;
- DEBUGLOG(5, "ZSTDMT_compressChunk: received dstBuff of size %u", (U32)dstBuff.size);
}
+ /* init */
if (job->cdict) {
size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dm_auto, job->cdict, job->params, job->fullFrameSize);
- DEBUGLOG(4, "ZSTDMT_compressChunk: init using CDict (windowLog=%u)", job->params.cParams.windowLog);
assert(job->firstChunk); /* only allowed for first job */
if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
} else { /* srcStart points at reloaded section */
U64 const pledgedSrcSize = job->firstChunk ? job->fullFrameSize : ZSTD_CONTENTSIZE_UNKNOWN;
ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */
- size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
- if (ZSTD_isError(forceWindowError)) {
- DEBUGLOG(5, "ZSTD_CCtxParam_setParameter error : %s ", ZSTD_getErrorName(forceWindowError));
- job->cSize = forceWindowError;
- goto _endJob;
- }
- DEBUGLOG(5, "ZSTDMT_compressChunk: invoking ZSTD_compressBegin_advanced_internal with windowLog = %u ", jobParams.cParams.windowLog);
+ { size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
+ if (ZSTD_isError(forceWindowError)) {
+ job->cSize = forceWindowError;
+ goto _endJob;
+ } }
{ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
job->srcStart, job->prefixSize, ZSTD_dm_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
NULL,
jobParams, pledgedSrcSize);
if (ZSTD_isError(initError)) {
- DEBUGLOG(5, "ZSTD_compressBegin_advanced_internal error : %s ", ZSTD_getErrorName(initError));
job->cSize = initError;
goto _endJob;
} }
@@ -384,19 +368,50 @@ void ZSTDMT_compressChunk(void* jobDescription)
ZSTD_invalidateRepCodes(cctx);
}
- DEBUGLOG(5, "Compressing into dstBuff of size %u", (U32)dstBuff.size);
- DEBUG_PRINTHEX(6, job->srcStart, 12);
+ /* compress */
+#if 1
job->cSize = (job->lastChunk) ?
ZSTD_compressEnd (cctx, dstBuff.start, dstBuff.size, src, job->srcSize) :
ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, job->srcSize);
- DEBUGLOG(5, "compressed %u bytes into %u bytes (first:%u) (last:%u) ",
- (unsigned)job->srcSize, (unsigned)job->cSize, job->firstChunk, job->lastChunk);
- DEBUGLOG(5, "dstBuff.size : %u ; => %s ", (U32)dstBuff.size, ZSTD_getErrorName(job->cSize));
+#else
+ if (sizeof(size_t) > sizeof(int))
+ assert(job->srcSize < ((size_t)INT_MAX) * ZSTD_BLOCKSIZE_MAX); /* check overflow */
+ { int const nbBlocks = (int)((job->srcSize + (ZSTD_BLOCKSIZE_MAX-1)) / ZSTD_BLOCKSIZE_MAX);
+ const BYTE* ip = (const BYTE*) src;
+ BYTE* const ostart = (BYTE*)dstBuff.start;
+ BYTE* op = ostart;
+ BYTE* oend = op + dstBuff.size;
+ int blockNb;
+ job->cSize = 0;
+ for (blockNb = 0; blockNb < nbBlocks-1; blockNb++) {
+ size_t const cSize = ZSTD_compressContinue(cctx, op, oend-op, ip, ZSTD_BLOCKSIZE_MAX);
+ if (ZSTD_isError(cSize)) { job->cSize = cSize; goto _endJob; }
+ ip += ZSTD_BLOCKSIZE_MAX;
+ op += cSize; assert(op < oend);
+ /* stats */
+ job->cSize += cSize;
+ job->readSize = ZSTD_BLOCKSIZE_MAX * (blockNb+1);
+ }
+ /* last block */
+ { size_t const lastBlockSize1 = job->srcSize & (ZSTD_BLOCKSIZE_MAX-1);
+ size_t const lastBlockSize = (lastBlockSize1==0) ? ZSTD_BLOCKSIZE_MAX : lastBlockSize1;
+ size_t const cSize = (job->lastChunk) ?
+ ZSTD_compressEnd (cctx, op, oend-op, ip, lastBlockSize) :
+ ZSTD_compressContinue(cctx, op, oend-op, ip, lastBlockSize);
+ if (ZSTD_isError(cSize)) { job->cSize = cSize; goto _endJob; }
+ /* stats */
+ job->cSize += cSize;
+ job->readSize = ZSTD_BLOCKSIZE_MAX * (blockNb+1);
+ }
+ }
+#endif
_endJob:
+ /* release */
ZSTDMT_releaseCCtx(job->cctxPool, cctx);
ZSTDMT_releaseBuffer(job->bufPool, job->src);
job->src = g_nullBuffer; job->srcStart = NULL;
+ /* report */
ZSTD_PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex);
job->jobCompleted = 1;
job->jobScanned = 0;
@@ -440,6 +455,21 @@ struct ZSTDMT_CCtx_s {
const ZSTD_CDict* cdict;
};
+/* Sets parameters relevant to the compression job, initializing others to
+ * default values. Notably, nbThreads should probably be zero. */
+static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
+{
+ ZSTD_CCtx_params jobParams;
+ memset(&jobParams, 0, sizeof(jobParams));
+
+ jobParams.cParams = params.cParams;
+ jobParams.fParams = params.fParams;
+ jobParams.compressionLevel = params.compressionLevel;
+
+ jobParams.ldmParams = params.ldmParams;
+ return jobParams;
+}
+
static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customMem cMem)
{
U32 const nbJobsLog2 = ZSTD_highbit32(*nbJobsPtr) + 1;
@@ -908,6 +938,7 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
zcs->jobs[jobID].src = zcs->inBuff.buffer;
zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start;
zcs->jobs[jobID].srcSize = srcSize;
+ zcs->jobs[jobID].readSize = 0;
zcs->jobs[jobID].prefixSize = zcs->dictSize;
assert(zcs->inBuff.filled >= srcSize + zcs->dictSize);
zcs->jobs[jobID].params = zcs->params;
diff --git a/programs/fileio.c b/programs/fileio.c
index 887cbeb37..3ae2d4057 100644
--- a/programs/fileio.c
+++ b/programs/fileio.c
@@ -828,7 +828,7 @@ finish:
/* Status */
DISPLAYLEVEL(2, "\r%79s\r", "");
DISPLAYLEVEL(2,"%-20s :%6.2f%% (%6llu => %6llu bytes, %s) \n", srcFileName,
- (double)compressedfilesize/(readsize+(!readsize) /* avoid div by zero */ )*100,
+ (double)compressedfilesize / (readsize+(!readsize)/*avoid div by zero*/) * 100,
(unsigned long long)readsize, (unsigned long long) compressedfilesize,
dstFileName);
From f8a05932b9bfd504614b15b8898eaaa3e3b8520b Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 13 Jan 2018 21:54:21 -0800
Subject: [PATCH 042/255] added `make list` capability to `tests/Makefile`
---
tests/Makefile | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tests/Makefile b/tests/Makefile
index 48ae17538..852ea7379 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -292,15 +292,23 @@ ifneq (,$(filter $(shell uname),SunOS))
DIFF:=gdiff
endif
+.PHONY: list
+list:
+ @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
+
+.PHONY: zstd-playTests
zstd-playTests: datagen
file $(ZSTD)
ZSTD="$(QEMU_SYS) $(ZSTD)" ./playTests.sh $(ZSTDRTTEST)
+.PHONY: shortest
shortest: ZSTDRTTEST=
shortest: test-zstd
+.PHONY: fuzztest
fuzztest: test-fuzzer test-zstream test-decodecorpus
+.PHONY: test
test: test-zstd test-fullbench test-fuzzer test-zstream test-invalidDictionaries test-legacy test-decodecorpus
ifeq ($(QEMU_SYS),)
test: test-pool
From 99a0a8bbd2c2faa7f90dd755f4523f669086cb99 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sat, 13 Jan 2018 22:00:05 -0800
Subject: [PATCH 043/255] tests/Makefile : fixed target allnothread
ensures MT is disabled
---
tests/Makefile | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tests/Makefile b/tests/Makefile
index 852ea7379..4acc7962f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -82,6 +82,8 @@ all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus roundTripCrash
all32: fullbench32 fuzzer32 zstreamtest32
+allnothread: MULTITHREAD_CPP=
+allnothread: MULTITHREAD_LD=
allnothread: fullbench fuzzer paramgrill datagen decodecorpus
dll: fuzzer-dll zstreamtest-dll
From 4792ac6689d8e27d2f9aab4535d7efc8964180f0 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sun, 14 Jan 2018 14:09:17 -0800
Subject: [PATCH 044/255] make -C tests legacy : minor flag alteration
ZSTD_LEGACY_SUPPORT is a macro constant,
so it should be part of CPPFLAGS, instead of CFLAGS
---
tests/Makefile | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tests/Makefile b/tests/Makefile
index 4acc7962f..95d0bf549 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -218,8 +218,7 @@ longmatch : $(ZSTD_OBJECTS) longmatch.c
invalidDictionaries : $(ZSTD_OBJECTS) invalidDictionaries.c
$(CC) $(FLAGS) $^ -o $@$(EXT)
-legacy : CFLAGS+= -DZSTD_LEGACY_SUPPORT=4
-legacy : CPPFLAGS+= -I$(ZSTDDIR)/legacy
+legacy : CPPFLAGS += -I$(ZSTDDIR)/legacy -DZSTD_LEGACY_SUPPORT=4
legacy : $(ZSTD_FILES) $(wildcard $(ZSTDDIR)/legacy/*.c) legacy.c
$(CC) $(FLAGS) $^ -o $@$(EXT)
From f6e17b8c7a27ffc5e51209ba698bc3462790f823 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sun, 14 Jan 2018 17:03:45 -0800
Subject: [PATCH 045/255] added tests/checkTag
compared provided tag with current libzstd version
---
tests/.gitignore | 1 +
tests/Makefile | 6 ++++-
tests/checkTag.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 71 insertions(+), 1 deletion(-)
create mode 100644 tests/checkTag.c
diff --git a/tests/.gitignore b/tests/.gitignore
index b16e26e3d..a06fa20be 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -23,6 +23,7 @@ decodecorpus
pool
poolTests
invalidDictionaries
+checkTag
# Tmp test directory
zstdtest
diff --git a/tests/Makefile b/tests/Makefile
index 95d0bf549..a1289440b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -236,9 +236,13 @@ endif
poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c $(ZSTDDIR)/common/zstd_common.c $(ZSTDDIR)/common/error_private.c
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
+.PHONY: versionsTest
versionsTest: clean
$(PYTHON) test-zstd-versions.py
+checkTag: checkTag.c $(ZSTDDIR)/zstd.h
+ $(CC) $(FLAGS) $< -o $@$(EXT)
+
clean:
$(MAKE) -C $(ZSTDDIR) clean
@$(RM) -fR $(TESTARTEFACT)
@@ -251,7 +255,7 @@ clean:
zstreamtest$(EXT) zstreamtest32$(EXT) \
datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) longmatch$(EXT) \
symbols$(EXT) invalidDictionaries$(EXT) legacy$(EXT) poolTests$(EXT) \
- decodecorpus$(EXT)
+ decodecorpus$(EXT) checkTag$(EXT)
@echo Cleaning completed
diff --git a/tests/checkTag.c b/tests/checkTag.c
new file mode 100644
index 000000000..fda3fd1f9
--- /dev/null
+++ b/tests/checkTag.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018-present, 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.
+ */
+
+/* checkTag : validation tool for libzstd
+ * command :
+ * $ ./checkTag tag
+ * checkTag validates tags of following format : v[0-9].[0-9].[0-9]{any}
+ * The tag is then compared to zstd version number.
+ * They are compatible if first 3 digits are identical.
+ * Anything beyond that is free, and doesn't impact validation.
+ * Example : tag v1.8.1.2 is compatible with version 1.8.1
+ * When tag and version are not compatible, program exits with error code 1.
+ * When they are compatible, it exists with a code 0.
+ * checkTag is intended to be used in automated testing environment.
+ */
+
+#include /* printf */
+#include /* strlen, strncmp */
+#include "zstd.h" /* ZSTD_VERSION_STRING */
+
+
+/* validate() :
+ * @return 1 if tag is compatible, 0 if not.
+ */
+static int validate(const char* const tag)
+{
+ size_t const tagLength = strlen(tag);
+ size_t const verLength = strlen(ZSTD_VERSION_STRING);
+
+ if (tagLength < 2) return 0;
+ if (tag[0] != 'v') return 0;
+ if (tagLength <= verLength) return 0;
+
+ if (strncmp(ZSTD_VERSION_STRING, tag+1, verLength)) return 0;
+
+ return 1;
+}
+
+int main(int argc, const char** argv)
+{
+ const char* const exeName = argv[0];
+ const char* const tag = argv[1];
+ if (argc!=2) {
+ printf("incorrect usage : %s tag \n", exeName);
+ return 2;
+ }
+
+ printf("Version : %s \n", ZSTD_VERSION_STRING);
+ printf("Tag : %s \n", tag);
+
+ if (validate(tag)) {
+ printf("OK : tag is compatible with zstd version \n");
+ return 0;
+ }
+
+ printf("!! error : tag and versions are not compatible !! \n");
+ return 1;
+}
From 815eddeda4cb0d428a83a889fbfddfbf377e5fb6 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Sun, 14 Jan 2018 17:06:21 -0800
Subject: [PATCH 046/255] added tag-triggered test
ensure tag and libzstd version are compatible
---
.travis.yml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index 48d9ac3a6..e6fe49cac 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,6 +26,10 @@ matrix:
- env: Cmd='make lz4install && make -C tests test-lz4'
+ # tag-specific test
+ - if: tag =~ ^v[0-9]\.[0-9]
+ env: Cmd='make -C tests checkTag && tests/checkTag $TRAVIS_BRANCH'
+
git:
depth: 1
From 403e2db139d81a00a5b2da10d22dec56e41225c4 Mon Sep 17 00:00:00 2001
From: Alexey Ivanov
Date: Mon, 15 Jan 2018 22:48:46 +0300
Subject: [PATCH 047/255] CMake: use GNUInstallDirs for library install dir
Libraries now will be installed in the correct directory on x86_64 linux systems,
and can be changed with `-DCMAKE_INSTALL_LIBDIR=` option.
---
build/cmake/CMakeLists.txt | 7 +++++++
build/cmake/lib/CMakeLists.txt | 10 ++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt
index 8e8824e7c..7361bc8a6 100644
--- a/build/cmake/CMakeLists.txt
+++ b/build/cmake/CMakeLists.txt
@@ -11,6 +11,7 @@ PROJECT(zstd)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
SET(ZSTD_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../..")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
+INCLUDE(GNUInstallDirs)
#-----------------------------------------------------------------------------
# Add extra compilation flags
@@ -21,6 +22,12 @@ ADD_ZSTD_COMPILATION_FLAGS()
# Always hide XXHash symbols
ADD_DEFINITIONS(-DXXH_NAMESPACE=ZSTD_)
+#-----------------------------------------------------------------------------
+# Installation variables
+#-----------------------------------------------------------------------------
+MESSAGE(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
+MESSAGE(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
+
#-----------------------------------------------------------------------------
# Options
#-----------------------------------------------------------------------------
diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt
index fd20bdb87..3435e1bb3 100644
--- a/build/cmake/lib/CMakeLists.txt
+++ b/build/cmake/lib/CMakeLists.txt
@@ -146,7 +146,7 @@ ENDIF (ZSTD_BUILD_STATIC)
IF (UNIX)
# pkg-config
SET(PREFIX "${CMAKE_INSTALL_PREFIX}")
- SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib")
+ SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
SET(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include")
SET(VERSION "${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE}")
ADD_CUSTOM_TARGET(libzstd.pc ALL
@@ -155,7 +155,7 @@ IF (UNIX)
-P "${CMAKE_CURRENT_SOURCE_DIR}/pkgconfig.cmake"
COMMENT "Creating pkg-config file")
- INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/libzstd.pc" DESTINATION "share/pkgconfig")
+ INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/libzstd.pc" DESTINATION "${LIBDIR}/pkgconfig")
ENDIF (UNIX)
# install target
@@ -167,10 +167,12 @@ INSTALL(FILES
DESTINATION "include")
IF (ZSTD_BUILD_SHARED)
- INSTALL(TARGETS libzstd_shared RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib")
+ INSTALL(TARGETS libzstd_shared RUNTIME DESTINATION "bin"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
ENDIF()
IF (ZSTD_BUILD_STATIC)
- INSTALL(TARGETS libzstd_static ARCHIVE DESTINATION "lib")
+ INSTALL(TARGETS libzstd_static ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
ENDIF (ZSTD_BUILD_STATIC)
# uninstall target
From 887cd4e35eda262c13a2751e31aa751fc787b067 Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Tue, 12 Dec 2017 16:51:00 -0800
Subject: [PATCH 048/255] Split ZSTD_CCtx into smaller sub-structures
---
lib/common/zstd_internal.h | 2 -
lib/compress/zstd_compress.c | 515 +++++++++++++++-----------
lib/compress/zstd_compress_internal.h | 46 ++-
lib/compress/zstd_double_fast.c | 115 +++---
lib/compress/zstd_double_fast.h | 15 +-
lib/compress/zstd_fast.c | 119 +++---
lib/compress/zstd_fast.h | 16 +-
lib/compress/zstd_lazy.c | 316 ++++++++--------
lib/compress/zstd_lazy.h | 41 +-
lib/compress/zstd_ldm.c | 183 ++++-----
lib/compress/zstd_ldm.h | 10 +-
lib/compress/zstd_opt.c | 163 ++++----
lib/compress/zstd_opt.h | 23 +-
13 files changed, 844 insertions(+), 720 deletions(-)
diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
index 5d2900eb7..49f19a010 100644
--- a/lib/common/zstd_internal.h
+++ b/lib/common/zstd_internal.h
@@ -228,8 +228,6 @@ typedef struct {
BYTE* ofCode;
U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
U32 longLengthPos;
- U32 rep[ZSTD_REP_NUM];
- U32 repToConfirm[ZSTD_REP_NUM];
} seqStore_t;
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 101c689a9..eba0baad0 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -81,11 +81,15 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
cctx->workSpace = (void*)(cctx+1);
cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
- /* entropy space (never moves) */
- if (cctx->workSpaceSize < sizeof(ZSTD_entropyCTables_t)) return NULL;
+ /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
+ if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_blockState_t)) return NULL;
assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
- cctx->entropy = (ZSTD_entropyCTables_t*)cctx->workSpace;
-
+ cctx->prevBlock = (ZSTD_blockState_t*)cctx->workSpace;
+ cctx->nextBlock = cctx->prevBlock + 1;
+ {
+ void* const ptr = cctx->nextBlock + 1;
+ cctx->entropyWorkspace = (U32*)ptr;
+ }
return cctx;
}
@@ -660,7 +664,8 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
U32 const hashLog3 = (cParams.searchLength>3) ?
0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
size_t const h3Size = ((size_t)1) << hashLog3;
- size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
+ size_t const entropySpace = HUF_WORKSPACE_SIZE;
+ size_t const blockStateSpace = 2 * sizeof(ZSTD_blockState_t);
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
size_t const optBudget =
@@ -672,7 +677,7 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
params->ldmParams.bucketSizeLog) : 0;
- size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
+ size_t const neededSpace = entropySpace + blockStateSpace + tableSpace + tokenSpace +
optSpace + ldmSpace;
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
@@ -794,16 +799,41 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
}
+static void ZSTD_resetBlockState(ZSTD_blockState_t* bs)
+{
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; ++i)
+ bs->rep[i] = repStartValue[i];
+ bs->entropy.hufCTable_repeatMode = HUF_repeat_none;
+ bs->entropy.offcode_repeatMode = FSE_repeat_none;
+ bs->entropy.matchlength_repeatMode = FSE_repeat_none;
+ bs->entropy.litlength_repeatMode = FSE_repeat_none;
+}
+
+/*! ZSTD_invalidateMatchState()
+ * Invalidate all the matches in the match finder tables.
+ * Requires nextSrc and base to be set (can be NULL).
+ */
+static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
+{
+ size_t const endT = (size_t)(ms->nextSrc - ms->base);
+ U32 const end = (U32)endT;
+ assert(endT < (3U<<30));
+
+ ms->lowLimit = end;
+ ms->dictLimit = end;
+ ms->nextToUpdate = end + 1;
+ ms->loadedDictEnd = 0;
+ ms->opt.litLengthSum = 0; /* force reset of btopt stats */
+}
+
/*! ZSTD_continueCCtx() :
* reuse CCtx without reset (note : requires no dictionary) */
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
{
- size_t const endT = (size_t)(cctx->nextSrc - cctx->base);
- U32 const end = (U32)endT;
size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
- assert(endT < (3U<<30));
cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
cctx->appliedParams = params;
@@ -813,14 +843,10 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
cctx->appliedParams.fParams.contentSizeFlag = 0;
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
(U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
- cctx->lowLimit = end;
- cctx->dictLimit = end;
- cctx->nextToUpdate = end+1;
cctx->stage = ZSTDcs_init;
cctx->dictID = 0;
- cctx->loadedDictEnd = 0;
- { int i; for (i=0; iseqStore.rep[i] = repStartValue[i]; }
- cctx->optState.litLengthSum = 0; /* force reset of btopt stats */
+ ZSTD_invalidateMatchState(&cctx->matchState);
+ ZSTD_resetBlockState(cctx->prevBlock);
XXH64_reset(&cctx->xxhState, 0);
return 0;
}
@@ -846,10 +872,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->appliedParams.cParams.windowLog, (U32)zc->blockSize);
assert(!(params.ldmParams.enableLdm &&
params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET));
- zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
- zc->entropy->offcode_repeatMode = FSE_repeat_none;
- zc->entropy->matchlength_repeatMode = FSE_repeat_none;
- zc->entropy->litlength_repeatMode = FSE_repeat_none;
return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
} }
DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
@@ -880,7 +902,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
void* ptr;
/* Check if workSpace is large enough, alloc a new one if needed */
- { size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
+ { size_t const entropySpace = HUF_WORKSPACE_SIZE;
+ size_t const blockStateSpace = 2 * sizeof(ZSTD_blockState_t);
size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<>10), (U32)(tableSpace>>10), (U32)(bufferSpace>>10));
@@ -911,10 +934,13 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->workSpaceSize = neededSpace;
ptr = zc->workSpace;
- /* entropy space */
+ /* Statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
- assert(zc->workSpaceSize >= sizeof(ZSTD_entropyCTables_t));
- zc->entropy = (ZSTD_entropyCTables_t*)zc->workSpace;
+ assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_blockState_t));
+ zc->prevBlock = (ZSTD_blockState_t*)zc->workSpace;
+ zc->nextBlock = zc->prevBlock + 1;
+ ptr = zc->nextBlock + 1;
+ zc->entropyWorkspace = (U32*)ptr;
} }
/* init params */
@@ -930,36 +956,31 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
XXH64_reset(&zc->xxhState, 0);
zc->stage = ZSTDcs_init;
zc->dictID = 0;
- zc->loadedDictEnd = 0;
- zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
- zc->entropy->offcode_repeatMode = FSE_repeat_none;
- zc->entropy->matchlength_repeatMode = FSE_repeat_none;
- zc->entropy->litlength_repeatMode = FSE_repeat_none;
- zc->base = NULL;
- zc->dictBase = NULL;
- zc->lowLimit = 0;
- zc->dictLimit = 0;
- zc->nextToUpdate = 1;
- zc->nextSrc = NULL;
- { int i; for (i=0; iseqStore.rep[i] = repStartValue[i]; }
- zc->hashLog3 = hashLog3;
- zc->optState.litLengthSum = 0;
- ptr = zc->entropy + 1;
+ zc->matchState.nextSrc = NULL;
+ zc->matchState.base = NULL;
+ zc->matchState.dictBase = NULL;
+ zc->matchState.hashLog3 = hashLog3;
+ ZSTD_invalidateMatchState(&zc->matchState);
+
+ ZSTD_resetBlockState(zc->prevBlock);
+
+ ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
/* opt parser space */
if ((params.cParams.strategy == ZSTD_btopt) | (params.cParams.strategy == ZSTD_btultra)) {
+ optState_t* opt = &zc->matchState.opt;
DEBUGLOG(4, "reserving optimal parser space");
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
- zc->optState.litFreq = (U32*)ptr;
- zc->optState.litLengthFreq = zc->optState.litFreq + (1<optState.matchLengthFreq = zc->optState.litLengthFreq + (MaxLL+1);
- zc->optState.offCodeFreq = zc->optState.matchLengthFreq + (MaxML+1);
- ptr = zc->optState.offCodeFreq + (MaxOff+1);
- zc->optState.matchTable = (ZSTD_match_t*)ptr;
- ptr = zc->optState.matchTable + ZSTD_OPT_NUM+1;
- zc->optState.priceTable = (ZSTD_optimal_t*)ptr;
- ptr = zc->optState.priceTable + ZSTD_OPT_NUM+1;
+ opt->litFreq = (U32*)ptr;
+ opt->litLengthFreq = opt->litFreq + (1<matchLengthFreq = opt->litLengthFreq + (MaxLL+1);
+ opt->offCodeFreq = opt->matchLengthFreq + (MaxML+1);
+ ptr = opt->offCodeFreq + (MaxOff+1);
+ opt->matchTable = (ZSTD_match_t*)ptr;
+ ptr = opt->matchTable + ZSTD_OPT_NUM+1;
+ opt->priceTable = (ZSTD_optimal_t*)ptr;
+ ptr = opt->priceTable + ZSTD_OPT_NUM+1;
}
/* ldm hash table */
@@ -976,10 +997,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
- zc->hashTable = (U32*)(ptr);
- zc->chainTable = zc->hashTable + hSize;
- zc->hashTable3 = zc->chainTable + chainSize;
- ptr = zc->hashTable3 + h3Size;
+ zc->matchState.hashTable = (U32*)(ptr);
+ zc->matchState.chainTable = zc->matchState.hashTable + hSize;
+ zc->matchState.hashTable3 = zc->matchState.chainTable + chainSize;
+ ptr = zc->matchState.hashTable3 + h3Size;
/* sequences storage */
zc->seqStore.sequencesStart = (seqDef*)ptr;
@@ -1016,7 +1037,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
* do not use with extDict variant ! */
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
int i;
- for (i=0; iseqStore.rep[i] = 0;
+ for (i=0; iprevBlock->rep[i] = 0;
+ assert(/* !extDict */ cctx->matchState.lowLimit == cctx->matchState.dictLimit);
}
@@ -1050,32 +1072,30 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
/* copy tables */
{ size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
- size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
+ size_t const h3Size = (size_t)1 << srcCCtx->matchState.hashLog3;
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
- assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
- assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
- memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
+ assert((U32*)dstCCtx->matchState.chainTable == (U32*)dstCCtx->matchState.hashTable + hSize); /* chainTable must follow hashTable */
+ assert((U32*)dstCCtx->matchState.hashTable3 == (U32*)dstCCtx->matchState.chainTable + chainSize);
+ memcpy(dstCCtx->matchState.hashTable, srcCCtx->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
}
/* copy dictionary offsets */
- dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
- dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
- dstCCtx->nextSrc = srcCCtx->nextSrc;
- dstCCtx->base = srcCCtx->base;
- dstCCtx->dictBase = srcCCtx->dictBase;
- dstCCtx->dictLimit = srcCCtx->dictLimit;
- dstCCtx->lowLimit = srcCCtx->lowLimit;
- dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
- dstCCtx->dictID = srcCCtx->dictID;
-
- /* copy entropy tables */
- memcpy(dstCCtx->entropy, srcCCtx->entropy, sizeof(ZSTD_entropyCTables_t));
- /* copy repcodes */
{
- int i;
- for (i = 0; i < ZSTD_REP_NUM; ++i)
- dstCCtx->seqStore.rep[i] = srcCCtx->seqStore.rep[i];
+ ZSTD_matchState_t const* srcMatchState = &srcCCtx->matchState;
+ ZSTD_matchState_t* dstMatchState = &dstCCtx->matchState;
+ dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+ dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
+ dstMatchState->nextSrc = srcMatchState->nextSrc;
+ dstMatchState->base = srcMatchState->base;
+ dstMatchState->dictBase = srcMatchState->dictBase;
+ dstMatchState->dictLimit = srcMatchState->dictLimit;
+ dstMatchState->lowLimit = srcMatchState->lowLimit;
+ dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
}
+ dstCCtx->dictID = srcCCtx->dictID;
+
+ /* copy block state */
+ memcpy(dstCCtx->prevBlock, srcCCtx->prevBlock, sizeof(*srcCCtx->prevBlock));
return 0;
}
@@ -1142,20 +1162,21 @@ static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
* rescale all indexes to avoid future overflow (indexes are U32) */
static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
{
+ ZSTD_matchState_t* const ms = &zc->matchState;
{ U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
- ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);
+ ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
}
if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
- ZSTD_preserveUnsortedMark(zc->chainTable, chainSize, reducerValue);
- ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
+ ZSTD_preserveUnsortedMark(ms->chainTable, chainSize, reducerValue);
+ ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
}
- if (zc->hashLog3) {
- U32 const h3Size = (U32)1 << zc->hashLog3;
- ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue);
+ if (ms->hashLog3) {
+ U32 const h3Size = (U32)1 << ms->hashLog3;
+ ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
}
if (zc->appliedParams.ldmParams.enableLdm) {
@@ -1235,10 +1256,12 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, cons
static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
-static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
+static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
ZSTD_strategy strategy,
void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
+ const void* src, size_t srcSize,
+ U32* workspace)
{
size_t const minGain = ZSTD_minGain(srcSize);
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
@@ -1247,34 +1270,45 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
symbolEncodingType_e hType = set_compressed;
size_t cLitSize;
+ /* Prepare nextEntropy assuming reusing the existing table */
+ nextEntropy->hufCTable_repeatMode = prevEntropy->hufCTable_repeatMode;
+ memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable,
+ sizeof(prevEntropy->hufCTable));
/* small ? don't even attempt compression (speed opt) */
# define LITERAL_NOENTROPY 63
- { size_t const minLitSize = entropy->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
+ { size_t const minLitSize = prevEntropy->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
}
if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
- { HUF_repeat repeat = entropy->hufCTable_repeatMode;
+ { HUF_repeat repeat = prevEntropy->hufCTable_repeatMode;
int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
- entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat)
+ workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat)
: HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
- entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat);
- if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
- else { entropy->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
+ workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat);
+ if (repeat != HUF_repeat_none) {
+ /* reused the existing table */
+ hType = set_repeat;
+ }
}
if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
- entropy->hufCTable_repeatMode = HUF_repeat_none;
+ memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
}
if (cLitSize==1) {
- entropy->hufCTable_repeatMode = HUF_repeat_none;
+ memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
}
+ if (hType == set_compressed) {
+ /* using a newly constructed table */
+ nextEntropy->hufCTable_repeatMode = HUF_repeat_check;
+ }
+
/* Build header */
switch(lhSize)
{
@@ -1368,10 +1402,11 @@ symbolEncodingType_e ZSTD_selectEncodingType(
MEM_STATIC
size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
- FSE_CTable* CTable, U32 FSELog, symbolEncodingType_e type,
+ FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
U32* count, U32 max,
BYTE const* codeTable, size_t nbSeq,
S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
+ FSE_CTable const* prevCTable, size_t prevCTableSize,
void* workspace, size_t workspaceSize)
{
BYTE* op = (BYTE*)dst;
@@ -1380,12 +1415,13 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
switch (type) {
case set_rle:
*op = codeTable[0];
- CHECK_F(FSE_buildCTable_rle(CTable, (BYTE)max));
+ CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max));
return 1;
case set_repeat:
+ memcpy(nextCTable, prevCTable, prevCTableSize);
return 0;
case set_basic:
- CHECK_F(FSE_buildCTable_wksp(CTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
+ CHECK_F(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
return 0;
case set_compressed: {
S16 norm[MaxSeq + 1];
@@ -1399,7 +1435,7 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
{ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
if (FSE_isError(NCountSize)) return NCountSize;
- CHECK_F(FSE_buildCTable_wksp(CTable, norm, max, tableLog, workspace, workspaceSize));
+ CHECK_F(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize));
return NCountSize;
}
}
@@ -1492,15 +1528,16 @@ size_t ZSTD_encodeSequences(
}
MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
- ZSTD_entropyCTables_t* entropy,
+ ZSTD_entropyCTables_t const* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
ZSTD_compressionParameters const* cParams,
- void* dst, size_t dstCapacity)
+ void* dst, size_t dstCapacity, U32* workspace)
{
const int longOffsets = cParams->windowLog > STREAM_ACCUMULATOR_MIN;
U32 count[MaxSeq+1];
- FSE_CTable* CTable_LitLength = entropy->litlengthCTable;
- FSE_CTable* CTable_OffsetBits = entropy->offcodeCTable;
- FSE_CTable* CTable_MatchLength = entropy->matchlengthCTable;
+ FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
+ FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
+ FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
const seqDef* const sequences = seqStorePtr->sequencesStart;
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
@@ -1512,13 +1549,14 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
BYTE* seqHead;
- ZSTD_STATIC_ASSERT(sizeof(entropy->workspace) >= (1<= (1<litStart;
size_t const litSize = seqStorePtr->lit - literals;
- size_t const cSize = ZSTD_compressLiterals(
- entropy, cParams->strategy, op, dstCapacity, literals, litSize);
+ size_t const cSize = ZSTD_compressLiterals(prevEntropy, nextEntropy,
+ cParams->strategy, op, dstCapacity, literals, litSize,
+ workspace);
if (ZSTD_isError(cSize))
return cSize;
assert(cSize <= dstCapacity);
@@ -1533,7 +1571,15 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
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;
+ if (nbSeq==0) {
+ memcpy(nextEntropy->litlengthCTable, prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable));
+ nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
+ memcpy(nextEntropy->offcodeCTable, prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable));
+ nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
+ memcpy(nextEntropy->matchlengthCTable, prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable));
+ nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
+ return op - ostart;
+ }
/* seqHead : flags for FSE encoding type */
seqHead = op++;
@@ -1542,36 +1588,42 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
ZSTD_seqToCodes(seqStorePtr);
/* build CTable for Literal Lengths */
{ U32 max = MaxLL;
- size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace);
+ size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace);
DEBUGLOG(5, "Building LL table");
- LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
+ nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
+ LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
- entropy->workspace, sizeof(entropy->workspace));
+ prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
+ workspace, HUF_WORKSPACE_SIZE);
if (ZSTD_isError(countSize)) return countSize;
op += countSize;
} }
/* build CTable for Offsets */
{ U32 max = MaxOff;
- size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace);
+ size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace);
/* 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");
- Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
+ nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
+ Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
- entropy->workspace, sizeof(entropy->workspace));
+ prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
+ workspace, HUF_WORKSPACE_SIZE);
if (ZSTD_isError(countSize)) return countSize;
op += countSize;
} }
/* build CTable for MatchLengths */
{ U32 max = MaxML;
- size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace);
+ size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace);
DEBUGLOG(5, "Building ML table");
- MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
+ nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
+ MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
- entropy->workspace, sizeof(entropy->workspace));
+ prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
+ workspace, HUF_WORKSPACE_SIZE);
if (ZSTD_isError(countSize)) return countSize;
op += countSize;
} }
@@ -1593,13 +1645,15 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
}
MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
- ZSTD_entropyCTables_t* entropy,
+ ZSTD_entropyCTables_t const* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
ZSTD_compressionParameters const* cParams,
void* dst, size_t dstCapacity,
- size_t srcSize)
+ size_t srcSize, U32* workspace)
{
- size_t const cSize = ZSTD_compressSequences_internal(seqStorePtr, entropy, cParams,
- dst, dstCapacity);
+ size_t const cSize = ZSTD_compressSequences_internal(
+ seqStorePtr, prevEntropy, nextEntropy, cParams, dst, dstCapacity,
+ workspace);
/* If the srcSize <= dstCapacity, then there is enough space to write a
* raw uncompressed block. Since we ran out of space, the block must not
* be compressible, so fall back to a raw uncompressed block.
@@ -1607,34 +1661,28 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
int const uncompressibleError = (cSize == ERROR(dstSize_tooSmall)) && (srcSize <= dstCapacity);
if (ZSTD_isError(cSize) && !uncompressibleError)
return cSize;
- /* We check that dictionaries have offset codes available for the first
- * block. After the first block, the offcode table might not have large
- * enough codes to represent the offsets in the data.
- */
- if (entropy->offcode_repeatMode == FSE_repeat_valid)
- entropy->offcode_repeatMode = FSE_repeat_check;
/* Check compressibility */
{ size_t const minGain = ZSTD_minGain(srcSize); /* note : fixed formula, maybe should depend on compression level, or strategy */
size_t const maxCSize = srcSize - minGain;
if (cSize >= maxCSize || uncompressibleError) {
- entropy->hufCTable_repeatMode = HUF_repeat_none;
- entropy->offcode_repeatMode = FSE_repeat_none;
- entropy->matchlength_repeatMode = FSE_repeat_none;
- entropy->litlength_repeatMode = FSE_repeat_none;
return 0; /* block not compressed */
} }
assert(!ZSTD_isError(cSize));
- /* block is compressed => confirm repcodes in history */
- { int i; for (i=0; irep[i] = seqStorePtr->repToConfirm[i]; }
+ /* We check that dictionaries have offset codes available for the first
+ * block. After the first block, the offcode table might not have large
+ * enough codes to represent the offsets in the data.
+ */
+ if (nextEntropy->offcode_repeatMode == FSE_repeat_valid)
+ nextEntropy->offcode_repeatMode = FSE_repeat_check;
+
return cSize;
}
/* ZSTD_selectBlockCompressor() :
* Not static, but internal use only (used by long distance matcher)
* assumption : strat is a valid strategy */
-typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
{
static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
@@ -1673,30 +1721,54 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
const void* src, size_t srcSize)
{
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u) (dictLimit=%u, nextToUpdate=%u)",
- (U32)dstCapacity, zc->dictLimit, zc->nextToUpdate);
+ (U32)dstCapacity, zc->matchState.dictLimit, zc->matchState.nextToUpdate);
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1)
return 0; /* don't even attempt compression below a certain srcSize */
ZSTD_resetSeqStore(&(zc->seqStore));
/* limited update after a very long match */
- { const BYTE* const base = zc->base;
+ { const BYTE* const base = zc->matchState.base;
const BYTE* const istart = (const BYTE*)src;
const U32 current = (U32)(istart-base);
- if (current > zc->nextToUpdate + 384)
- zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384));
+ if (current > zc->matchState.nextToUpdate + 384)
+ zc->matchState.nextToUpdate = current - MIN(192, (U32)(current - zc->matchState.nextToUpdate - 384));
}
/* find and store sequences */
- { U32 const extDict = zc->lowLimit < zc->dictLimit;
- const ZSTD_blockCompressor blockCompressor =
- zc->appliedParams.ldmParams.enableLdm
- ? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
- : ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
- size_t const lastLLSize = blockCompressor(zc, src, srcSize);
- const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
- ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
+ {
+ U32 const extDict = zc->matchState.lowLimit < zc->matchState.dictLimit;
+ size_t lastLLSize;
+ { int i; for (i = 0; i < ZSTD_REP_NUM; ++i) zc->nextBlock->rep[i] = zc->prevBlock->rep[i]; }
+ if (zc->appliedParams.ldmParams.enableLdm) {
+ typedef size_t (*ZSTD_ldmBlockCompressor)(
+ ldmState_t* ldms, ZSTD_matchState_t* ms, seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM], ZSTD_CCtx_params const* params,
+ void const* src, size_t srcSize);
+ ZSTD_ldmBlockCompressor const ldmBlockCompressor = extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm;
+
+ lastLLSize = ldmBlockCompressor(&zc->ldmState, &zc->matchState, &zc->seqStore, zc->nextBlock->rep, &zc->appliedParams, src, srcSize);
+ } else {
+ ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
+
+ lastLLSize = blockCompressor(&zc->matchState, &zc->seqStore, zc->nextBlock->rep, &zc->appliedParams.cParams, src, srcSize);
+ }
+ {
+ const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
+ ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
+ }
}
/* encode */
- return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize);
+ {
+ size_t const cSize = ZSTD_compressSequences(&zc->seqStore, &zc->prevBlock->entropy, &zc->nextBlock->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize, zc->entropyWorkspace);
+ if (ZSTD_isError(cSize) || cSize == 0)
+ return cSize;
+ /* confirm repcodes and entropy tables */
+ {
+ ZSTD_blockState_t* const tmp = zc->prevBlock;
+ zc->prevBlock = zc->nextBlock;
+ zc->nextBlock = tmp;
+ }
+ return cSize;
+ }
}
@@ -1725,6 +1797,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
XXH64_update(&cctx->xxhState, src, srcSize);
while (remaining) {
+ ZSTD_matchState_t* const ms = &cctx->matchState;
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
@@ -1748,9 +1821,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
* 3. cctx->lowLimit < 1<<32:
* windowLog <= 31 ==> 3<<29 + 1<lowLimit > (3U<<29)) {
+ if (ms->lowLimit > (3U<<29)) {
U32 const cycleMask = ((U32)1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1;
- U32 const current = (U32)(ip - cctx->base);
+ U32 const current = (U32)(ip - cctx->matchState.base);
U32 const newCurrent = (current & cycleMask) + ((U32)1 << cctx->appliedParams.cParams.windowLog);
U32 const correction = current - newCurrent;
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
@@ -1759,23 +1832,23 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
assert(current > newCurrent);
assert(correction > 1<<28); /* Loose bound, should be about 1<<29 */
ZSTD_reduceIndex(cctx, correction);
- cctx->base += correction;
- cctx->dictBase += correction;
- cctx->lowLimit -= correction;
- cctx->dictLimit -= correction;
- if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
- else cctx->nextToUpdate -= correction;
- DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, cctx->lowLimit);
+ ms->base += correction;
+ ms->dictBase += correction;
+ ms->lowLimit -= correction;
+ ms->dictLimit -= correction;
+ if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
+ else ms->nextToUpdate -= correction;
+ DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, ms->lowLimit);
}
/* enforce maxDist */
- if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
- U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
- if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
- if (cctx->dictLimit < cctx->lowLimit)
+ if ((U32)(ip+blockSize - ms->base) > ms->loadedDictEnd + maxDist) {
+ U32 const newLowLimit = (U32)(ip+blockSize - ms->base) - maxDist;
+ if (ms->lowLimit < newLowLimit) ms->lowLimit = newLowLimit;
+ if (ms->dictLimit < ms->lowLimit)
DEBUGLOG(5, "ZSTD_compress_frameChunk : update dictLimit from %u to %u ",
- cctx->dictLimit, cctx->lowLimit);
- if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
- if (cctx->nextToUpdate < cctx->lowLimit) cctx->nextToUpdate = cctx->lowLimit;
+ ms->dictLimit, ms->lowLimit);
+ if (ms->dictLimit < ms->lowLimit) ms->dictLimit = ms->lowLimit;
+ if (ms->nextToUpdate < ms->lowLimit) ms->nextToUpdate = ms->lowLimit;
}
{ size_t cSize = ZSTD_compressBlock_internal(cctx,
@@ -1854,12 +1927,38 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
}
+static void ZSTD_manageWindowContinuity(ZSTD_matchState_t* ms, void const* src, size_t srcSize)
+{
+ const BYTE* const ip = (const BYTE*) src;
+
+ /* Check if blocks follow each other */
+ if (src != ms->nextSrc) {
+ /* not contiguous */
+ size_t const distanceFromBase = (size_t)(ms->nextSrc - ms->base);
+ DEBUGLOG(5, "ZSTD_manageWindowContinuity: non contiguous blocks, new segment starts at %u", ms->dictLimit);
+ ms->lowLimit = ms->dictLimit;
+ assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
+ ms->dictLimit = (U32)distanceFromBase;
+ ms->dictBase = ms->base;
+ ms->base = ip - distanceFromBase;
+ ms->nextToUpdate = ms->dictLimit;
+ if (ms->dictLimit - ms->lowLimit < HASH_READ_SIZE) ms->lowLimit = ms->dictLimit; /* too small extDict */
+ }
+ ms->nextSrc = ip + srcSize;
+ /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
+ if ((ip+srcSize > ms->dictBase + ms->lowLimit) & (ip < ms->dictBase + ms->dictLimit)) {
+ ptrdiff_t const highInputIdx = (ip + srcSize) - ms->dictBase;
+ U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)ms->dictLimit) ? ms->dictLimit : (U32)highInputIdx;
+ ms->lowLimit = lowLimitMax;
+ }
+}
+
+
static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
U32 frame, U32 lastFrameChunk)
{
- const BYTE* const ip = (const BYTE*) src;
size_t fhSize = 0;
DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u", cctx->stage);
@@ -1876,27 +1975,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
- /* Check if blocks follow each other */
- if (src != cctx->nextSrc) {
- size_t const distanceFromBase = (size_t)(cctx->nextSrc - cctx->base);
- DEBUGLOG(5, "ZSTD_compressContinue_internal: non contiguous blocks, new segment starts at %u",
- cctx->dictLimit);
- cctx->lowLimit = cctx->dictLimit;
- assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
- cctx->dictLimit = (U32)distanceFromBase;
- cctx->dictBase = cctx->base;
- cctx->base = ip - distanceFromBase;
- cctx->nextToUpdate = cctx->dictLimit;
- if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
- }
- cctx->nextSrc = ip + srcSize;
-
- /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
- if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
- ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
- U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
- cctx->lowLimit = lowLimitMax;
- }
+ ZSTD_manageWindowContinuity(&cctx->matchState, src, srcSize);
DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize);
{ size_t const cSize = frame ?
@@ -1934,50 +2013,51 @@ size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const
/*! ZSTD_loadDictionaryContent() :
* @return : 0, or an error code
*/
-static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
+static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* src, size_t srcSize)
{
const BYTE* const ip = (const BYTE*) src;
const BYTE* const iend = ip + srcSize;
+ ZSTD_compressionParameters const* cParams = ¶ms->cParams;
/* input becomes current prefix */
- zc->lowLimit = zc->dictLimit;
- zc->dictLimit = (U32)(zc->nextSrc - zc->base);
- zc->dictBase = zc->base;
- zc->base = ip - zc->dictLimit;
- zc->nextToUpdate = zc->dictLimit;
- zc->loadedDictEnd = zc->appliedParams.forceWindow ? 0 : (U32)(iend - zc->base);
+ ms->lowLimit = ms->dictLimit;
+ ms->dictLimit = (U32)(ms->nextSrc - ms->base);
+ ms->dictBase = ms->base;
+ ms->base = ip - ms->dictLimit;
+ ms->nextToUpdate = ms->dictLimit;
+ ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->base);
- zc->nextSrc = iend;
+ ms->nextSrc = iend;
if (srcSize <= HASH_READ_SIZE) return 0;
- switch(zc->appliedParams.cParams.strategy)
+ switch(params->cParams.strategy)
{
case ZSTD_fast:
- ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
+ ZSTD_fillHashTable(ms, cParams, iend);
break;
case ZSTD_dfast:
- ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
+ ZSTD_fillDoubleHashTable(ms, cParams, iend);
break;
case ZSTD_greedy:
case ZSTD_lazy:
case ZSTD_lazy2:
if (srcSize >= HASH_READ_SIZE)
- ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
+ ZSTD_insertAndFindFirstIndex(ms, cParams, iend-HASH_READ_SIZE);
break;
case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
case ZSTD_btopt:
case ZSTD_btultra:
if (srcSize >= HASH_READ_SIZE)
- ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, (U32)1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
+ ZSTD_updateTree(ms, cParams, iend-HASH_READ_SIZE, iend);
break;
default:
assert(0); /* not possible : not a valid strategy id */
}
- zc->nextToUpdate = (U32)(iend - zc->base);
+ ms->nextToUpdate = (U32)(iend - ms->base);
return 0;
}
@@ -2001,25 +2081,26 @@ static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSym
* https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
*/
/*! ZSTD_loadZstdDictionary() :
- * @return : 0, or an error code
+ * @return : dictID, or an error code
* assumptions : magic number supposed already checked
* dictSize supposed > 8
*/
-static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+static size_t ZSTD_loadZstdDictionary(ZSTD_blockState_t* bs, ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, void* workspace)
{
const BYTE* dictPtr = (const BYTE*)dict;
const BYTE* const dictEnd = dictPtr + dictSize;
short offcodeNCount[MaxOff+1];
unsigned offcodeMaxValue = MaxOff;
+ size_t dictID;
- ZSTD_STATIC_ASSERT(sizeof(cctx->entropy->workspace) >= (1<= (1<dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
+ dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
dictPtr += 4;
{ unsigned maxSymbolValue = 255;
- size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
+ size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
dictPtr += hufHeaderSize;
@@ -2030,7 +2111,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
/* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
- CHECK_E( FSE_buildCTable_wksp(cctx->entropy->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
+ CHECK_E( FSE_buildCTable_wksp(bs->entropy.offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, workspace, HUF_WORKSPACE_SIZE),
dictionary_corrupted);
dictPtr += offcodeHeaderSize;
}
@@ -2042,7 +2123,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
/* Every match length code must have non-zero probability */
CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
- CHECK_E( FSE_buildCTable_wksp(cctx->entropy->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
+ CHECK_E( FSE_buildCTable_wksp(bs->entropy.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE),
dictionary_corrupted);
dictPtr += matchlengthHeaderSize;
}
@@ -2054,15 +2135,15 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
/* Every literal length code must have non-zero probability */
CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
- CHECK_E( FSE_buildCTable_wksp(cctx->entropy->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
+ CHECK_E( FSE_buildCTable_wksp(bs->entropy.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE),
dictionary_corrupted);
dictPtr += litlengthHeaderSize;
}
if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
- cctx->seqStore.rep[0] = MEM_readLE32(dictPtr+0);
- cctx->seqStore.rep[1] = MEM_readLE32(dictPtr+4);
- cctx->seqStore.rep[2] = MEM_readLE32(dictPtr+8);
+ bs->rep[0] = MEM_readLE32(dictPtr+0);
+ bs->rep[1] = MEM_readLE32(dictPtr+4);
+ bs->rep[2] = MEM_readLE32(dictPtr+8);
dictPtr += 12;
{ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
@@ -2076,15 +2157,16 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
/* All repCodes must be <= dictContentSize and != 0*/
{ U32 u;
for (u=0; u<3; u++) {
- if (cctx->seqStore.rep[u] == 0) return ERROR(dictionary_corrupted);
- if (cctx->seqStore.rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
+ if (bs->rep[u] == 0) return ERROR(dictionary_corrupted);
+ if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
} }
- cctx->entropy->hufCTable_repeatMode = HUF_repeat_valid;
- cctx->entropy->offcode_repeatMode = FSE_repeat_valid;
- cctx->entropy->matchlength_repeatMode = FSE_repeat_valid;
- cctx->entropy->litlength_repeatMode = FSE_repeat_valid;
- return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
+ bs->entropy.hufCTable_repeatMode = HUF_repeat_valid;
+ bs->entropy.offcode_repeatMode = FSE_repeat_valid;
+ bs->entropy.matchlength_repeatMode = FSE_repeat_valid;
+ bs->entropy.litlength_repeatMode = FSE_repeat_valid;
+ CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize));
+ return dictID;
}
}
@@ -2099,12 +2181,12 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
/* dict restricted modes */
if (dictMode==ZSTD_dm_rawContent)
- return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
+ return ZSTD_loadDictionaryContent(&cctx->matchState, &cctx->appliedParams, dict, dictSize);
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
if (dictMode == ZSTD_dm_auto) {
DEBUGLOG(4, "raw content dictionary detected");
- return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
+ return ZSTD_loadDictionaryContent(&cctx->matchState, &cctx->appliedParams, dict, dictSize);
}
if (dictMode == ZSTD_dm_fullDict)
return ERROR(dictionary_wrong);
@@ -2112,7 +2194,12 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
}
/* dict as full zstd dictionary */
- return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
+ {
+ size_t const dictID = ZSTD_loadZstdDictionary(cctx->prevBlock, &cctx->matchState, &cctx->appliedParams, dict, dictSize, cctx->entropyWorkspace);
+ if (ZSTD_isError(dictID)) return dictID;
+ cctx->dictID = (U32)dictID;
+ }
+ return 0;
}
/*! ZSTD_compressBegin_internal() :
diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h
index f104fe981..7a7b1db1d 100644
--- a/lib/compress/zstd_compress_internal.h
+++ b/lib/compress/zstd_compress_internal.h
@@ -51,13 +51,17 @@ typedef struct {
FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
- U32 workspace[HUF_WORKSPACE_SIZE_U32];
HUF_repeat hufCTable_repeatMode;
FSE_repeat offcode_repeatMode;
FSE_repeat matchlength_repeatMode;
FSE_repeat litlength_repeatMode;
} ZSTD_entropyCTables_t;
+typedef struct {
+ ZSTD_entropyCTables_t entropy;
+ U32 rep[ZSTD_REP_NUM];
+} ZSTD_blockState_t;
+
typedef struct {
U32 off;
U32 len;
@@ -93,6 +97,22 @@ typedef struct {
U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */
} optState_t;
+typedef struct {
+ BYTE const* nextSrc; /* next block here to continue on current prefix */ /* TODO: Does this belong here? */
+ 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 data */
+ U32 nextToUpdate; /* index from which to continue table update */
+ U32 nextToUpdate3; /* index from which to continue table update */
+ U32 hashLog3; /* dispatch table : larger == faster, more memory */
+ U32 loadedDictEnd; /* index of end of dictionary */ /* TODO: Does this belong here? */
+ U32* hashTable;
+ U32* hashTable3;
+ U32* chainTable;
+ optState_t opt; /* optimal parser state */
+} ZSTD_matchState_t;
+
typedef struct {
U32 offset;
U32 checksum;
@@ -136,15 +156,6 @@ struct ZSTD_CCtx_params_s {
}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
struct ZSTD_CCtx_s {
- const BYTE* nextSrc; /* next block here to continue on current prefix */
- const BYTE* base; /* All regular indexes relative to this position */
- const BYTE* dictBase; /* extDict indexes relative to this position */
- U32 dictLimit; /* below that point, need extDict */
- U32 lowLimit; /* below that point, no more data */
- U32 nextToUpdate; /* index from which to continue dictionary update */
- U32 nextToUpdate3; /* index from which to continue dictionary update */
- U32 hashLog3; /* dispatch table : larger == faster, more memory */
- U32 loadedDictEnd; /* index of end of dictionary */
ZSTD_compressionStage_e stage;
U32 dictID;
ZSTD_CCtx_params requestedParams;
@@ -159,12 +170,11 @@ struct ZSTD_CCtx_s {
size_t staticSize;
seqStore_t seqStore; /* sequences storage ptrs */
- optState_t optState;
ldmState_t ldmState; /* long distance matching state */
- U32* hashTable;
- U32* hashTable3;
- U32* chainTable;
- ZSTD_entropyCTables_t* entropy;
+ ZSTD_matchState_t matchState;
+ ZSTD_blockState_t* prevBlock;
+ ZSTD_blockState_t* nextBlock;
+ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
/* streaming */
char* inBuff;
@@ -191,6 +201,12 @@ struct ZSTD_CCtx_s {
};
+typedef size_t (*ZSTD_blockCompressor) (
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict);
+
+
MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
{
static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
diff --git a/lib/compress/zstd_double_fast.c b/lib/compress/zstd_double_fast.c
index a6d8ad889..834a64b00 100644
--- a/lib/compress/zstd_double_fast.c
+++ b/lib/compress/zstd_double_fast.c
@@ -12,14 +12,17 @@
#include "zstd_double_fast.h"
-void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls)
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+ ZSTD_compressionParameters const* cParams,
+ void const* end)
{
- U32* const hashLarge = cctx->hashTable;
- U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
- U32* const hashSmall = cctx->chainTable;
- U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
- const BYTE* const base = cctx->base;
- const BYTE* ip = base + cctx->nextToUpdate;
+ U32* const hashLarge = ms->hashTable;
+ U32 const hBitsL = cParams->hashLog;
+ U32 const mls = cParams->searchLength;
+ U32* const hashSmall = ms->chainTable;
+ U32 const hBitsS = cParams->chainLog;
+ const BYTE* const base = ms->base;
+ const BYTE* ip = base + ms->nextToUpdate;
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
const U32 fastHashFillStep = 3;
@@ -43,24 +46,24 @@ void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls)
FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
- const void* src, size_t srcSize,
- const U32 mls)
+size_t ZSTD_compressBlock_doubleFast_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
+ U32 const mls /* template */)
{
- U32* const hashLong = cctx->hashTable;
- const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
- U32* const hashSmall = cctx->chainTable;
- const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
- seqStore_t* seqStorePtr = &(cctx->seqStore);
- const BYTE* const base = cctx->base;
+ 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->base;
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
- const U32 lowestIndex = cctx->dictLimit;
+ const U32 lowestIndex = ms->dictLimit;
const BYTE* const lowest = base + lowestIndex;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - HASH_READ_SIZE;
- U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
+ U32 offset_1=rep[0], offset_2=rep[1];
U32 offsetSaved = 0;
/* init */
@@ -87,7 +90,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
/* favor repcode */
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
ip++;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
} else {
U32 offset;
if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
@@ -117,7 +120,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
}
/* match found */
@@ -140,61 +143,63 @@ size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
{ 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(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
ip += rLength;
anchor = ip;
continue; /* faster when present ... (?) */
} } }
/* save reps for next block */
- seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
- seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
+ rep[0] = offset_1 ? offset_1 : offsetSaved;
+ rep[1] = offset_2 ? offset_2 : offsetSaved;
/* Return the last literals size */
return iend - anchor;
}
-size_t ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_doubleFast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- const U32 mls = ctx->appliedParams.cParams.searchLength;
+ const U32 mls = cParams->searchLength;
switch(mls)
{
default: /* includes case 3 */
case 4 :
- return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4);
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4);
case 5 :
- return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5);
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5);
case 6 :
- return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6);
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6);
case 7 :
- return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7);
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7);
}
}
-static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 mls)
+static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
+ U32 const mls /* template */)
{
- U32* const hashLong = ctx->hashTable;
- U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
- U32* const hashSmall = ctx->chainTable;
- U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const base = ctx->base;
- const BYTE* const dictBase = ctx->dictBase;
+ U32* const hashLong = ms->hashTable;
+ U32 const hBitsL = cParams->hashLog;
+ U32* const hashSmall = ms->chainTable;
+ U32 const hBitsS = cParams->chainLog;
+ const BYTE* const base = ms->base;
+ const BYTE* const dictBase = ms->dictBase;
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
- const U32 lowestIndex = ctx->lowLimit;
+ const U32 lowestIndex = ms->lowLimit;
const BYTE* const dictStart = dictBase + lowestIndex;
- const U32 dictLimit = ctx->dictLimit;
+ const U32 dictLimit = ms->dictLimit;
const BYTE* const lowPrefixPtr = base + dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
- U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
+ U32 offset_1=rep[0], offset_2=rep[1];
/* Search Loop */
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
@@ -220,7 +225,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
ip++;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
} else {
if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
@@ -231,7 +236,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
} else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
@@ -256,7 +261,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
}
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
} else {
ip += ((ip-anchor) >> g_searchStrength) + 1;
@@ -283,7 +288,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
ip += repLength2;
@@ -294,27 +299,29 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
} } }
/* save reps for next block */
- seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
+ rep[0] = offset_1;
+ rep[1] = offset_2;
/* Return the last literals size */
return iend - anchor;
}
-size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_doubleFast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- U32 const mls = ctx->appliedParams.cParams.searchLength;
+ U32 const mls = cParams->searchLength;
switch(mls)
{
default: /* includes case 3 */
case 4 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4);
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 4);
case 5 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5);
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 5);
case 6 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6);
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 6);
case 7 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7);
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 7);
}
}
diff --git a/lib/compress/zstd_double_fast.h b/lib/compress/zstd_double_fast.h
index 75e041580..6d80b2774 100644
--- a/lib/compress/zstd_double_fast.h
+++ b/lib/compress/zstd_double_fast.h
@@ -16,11 +16,18 @@ extern "C" {
#endif
#include "mem.h" /* U32 */
-#include "zstd.h" /* ZSTD_CCtx, size_t */
+#include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */
+
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+ ZSTD_compressionParameters const* cParams,
+ void const* end);
+size_t ZSTD_compressBlock_doubleFast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_doubleFast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
-void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls);
-size_t ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
#if defined (__cplusplus)
}
diff --git a/lib/compress/zstd_fast.c b/lib/compress/zstd_fast.c
index 6497a2d8b..8941326e1 100644
--- a/lib/compress/zstd_fast.c
+++ b/lib/compress/zstd_fast.c
@@ -12,12 +12,15 @@
#include "zstd_fast.h"
-void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+ ZSTD_compressionParameters const* cParams,
+ void const* end)
{
- U32* const hashTable = zc->hashTable;
- U32 const hBits = zc->appliedParams.cParams.hashLog;
- const BYTE* const base = zc->base;
- const BYTE* ip = base + zc->nextToUpdate;
+ U32* const hashTable = ms->hashTable;
+ U32 const hBits = cParams->hashLog;
+ U32 const mls = cParams->searchLength;
+ const BYTE* const base = ms->base;
+ const BYTE* ip = base + ms->nextToUpdate;
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
const U32 fastHashFillStep = 3;
@@ -35,24 +38,22 @@ void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
}
}
-
FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
- const void* src, size_t srcSize,
- const U32 mls)
+size_t ZSTD_compressBlock_fast_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize,
+ U32 const hlog, U32 const mls)
{
- U32* const hashTable = cctx->hashTable;
- U32 const hBits = cctx->appliedParams.cParams.hashLog;
- seqStore_t* seqStorePtr = &(cctx->seqStore);
- const BYTE* const base = cctx->base;
+ U32* const hashTable = ms->hashTable;
+ const BYTE* const base = ms->base;
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
- const U32 lowestIndex = cctx->dictLimit;
+ const U32 lowestIndex = ms->dictLimit;
const BYTE* const lowest = base + lowestIndex;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - HASH_READ_SIZE;
- U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
+ U32 offset_1=rep[0], offset_2=rep[1];
U32 offsetSaved = 0;
/* init */
@@ -65,7 +66,7 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
/* Main Search Loop */
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
size_t mLength;
- size_t const h = ZSTD_hashPtr(ip, hBits, mls);
+ 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;
@@ -74,7 +75,7 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
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(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
} else {
U32 offset;
if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
@@ -87,7 +88,7 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
}
/* match found */
@@ -96,8 +97,8 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
if (ip <= ilimit) {
/* Fill Table */
- hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
- hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
+ 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);
/* check immediate repcode */
while ( (ip <= ilimit)
&& ( (offset_2>0)
@@ -105,65 +106,66 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
/* 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 */
- hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
+ hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
ip += rLength;
anchor = ip;
continue; /* faster when present ... (?) */
} } }
/* save reps for next block */
- seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
- seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
+ rep[0] = offset_1 ? offset_1 : offsetSaved;
+ rep[1] = offset_2 ? offset_2 : offsetSaved;
/* Return the last literals size */
return iend - anchor;
}
-size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_fast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- const U32 mls = ctx->appliedParams.cParams.searchLength;
+ U32 const hlog = cParams->hashLog;
+ U32 const mls = cParams->searchLength;
switch(mls)
{
default: /* includes case 3 */
case 4 :
- return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4);
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, 4);
case 5 :
- return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5);
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, 5);
case 6 :
- return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6);
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, 6);
case 7 :
- return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7);
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, 7);
}
}
-static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 mls)
+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 hlog, U32 const mls)
{
- U32* hashTable = ctx->hashTable;
- const U32 hBits = ctx->appliedParams.cParams.hashLog;
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const base = ctx->base;
- const BYTE* const dictBase = ctx->dictBase;
+ U32* hashTable = ms->hashTable;
+ const BYTE* const base = ms->base;
+ const BYTE* const dictBase = ms->dictBase;
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
- const U32 lowestIndex = ctx->lowLimit;
+ const U32 lowestIndex = ms->lowLimit;
const BYTE* const dictStart = dictBase + lowestIndex;
- const U32 dictLimit = ctx->dictLimit;
+ const U32 dictLimit = ms->dictLimit;
const BYTE* const lowPrefixPtr = base + dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
- U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
+ U32 offset_1=rep[0], offset_2=rep[1];
/* Search Loop */
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
- const size_t h = ZSTD_hashPtr(ip, hBits, mls);
+ const size_t h = ZSTD_hashPtr(ip, hlog, mls);
const U32 matchIndex = hashTable[h];
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
const BYTE* match = matchBase + matchIndex;
@@ -179,7 +181,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
ip++;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
} else {
if ( (matchIndex < lowestIndex) ||
(MEM_read32(match) != MEM_read32(ip)) ) {
@@ -194,7 +196,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
offset = current - matchIndex;
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
} }
/* found a match : store it */
@@ -203,8 +205,8 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
if (ip <= ilimit) {
/* Fill Table */
- hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
- hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
+ 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);
@@ -215,8 +217,8 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
- hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+ hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
ip += repLength2;
anchor = ip;
continue;
@@ -225,27 +227,30 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
} } }
/* save reps for next block */
- seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
+ rep[0] = offset_1;
+ rep[1] = offset_2;
/* Return the last literals size */
return iend - anchor;
}
-size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_fast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- U32 const mls = ctx->appliedParams.cParams.searchLength;
+ U32 const hlog = cParams->hashLog;
+ U32 const mls = cParams->searchLength;
switch(mls)
{
default: /* includes case 3 */
case 4 :
- return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4);
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, 4);
case 5 :
- return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5);
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, 5);
case 6 :
- return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6);
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, 6);
case 7 :
- return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7);
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, 7);
}
}
diff --git a/lib/compress/zstd_fast.h b/lib/compress/zstd_fast.h
index d8b777195..f0438ad5b 100644
--- a/lib/compress/zstd_fast.h
+++ b/lib/compress/zstd_fast.h
@@ -16,13 +16,17 @@ extern "C" {
#endif
#include "mem.h" /* U32 */
-#include "zstd.h" /* ZSTD_CCtx, size_t */
+#include "zstd_compress_internal.h"
-void ZSTD_fillHashTable(ZSTD_CCtx* zc, const void* end, const U32 mls);
-size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize);
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+ ZSTD_compressionParameters const* cParams,
+ void const* end);
+size_t ZSTD_compressBlock_fast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_fast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
#if defined (__cplusplus)
}
diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
index 1d575804a..7f59eb34a 100644
--- a/lib/compress/zstd_lazy.c
+++ b/lib/compress/zstd_lazy.c
@@ -45,28 +45,29 @@ void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const redu
table[u] = ZSTD_DUBT_UNSORTED_MARK + reducerValue;
}
-void ZSTD_updateDUBT(ZSTD_CCtx* zc,
+void ZSTD_updateDUBT(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* ip, const BYTE* iend,
U32 mls)
{
- U32* const hashTable = zc->hashTable;
- U32 const hashLog = zc->appliedParams.cParams.hashLog;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
- U32* const bt = zc->chainTable;
- U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
U32 const btMask = (1 << btLog) - 1;
- const BYTE* const base = zc->base;
+ const BYTE* const base = ms->base;
U32 const target = (U32)(ip - base);
- U32 idx = zc->nextToUpdate;
+ U32 idx = ms->nextToUpdate;
if (idx != target)
DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
- idx, target, zc->dictLimit);
+ idx, target, ms->dictLimit);
assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
(void)iend;
- assert(idx >= zc->dictLimit); /* condition for valid base+idx */
+ assert(idx >= ms->dictLimit); /* condition for valid base+idx */
for ( ; idx < target ; idx++) {
size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls); /* assumption : ip + 8 <= iend */
U32 const matchIndex = hashTable[h];
@@ -79,7 +80,7 @@ void ZSTD_updateDUBT(ZSTD_CCtx* zc,
*nextCandidatePtr = matchIndex; /* update BT like a chain */
*sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK;
}
- zc->nextToUpdate = target;
+ ms->nextToUpdate = target;
}
@@ -87,17 +88,18 @@ void ZSTD_updateDUBT(ZSTD_CCtx* zc,
* sort one already inserted but unsorted position
* assumption : current >= btlow == (current - btmask)
* doesn't fail */
-static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
+static void ZSTD_insertDUBT1(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
U32 current, const BYTE* inputEnd,
U32 nbCompares, U32 btLow, int extDict)
{
- U32* const bt = zc->chainTable;
- U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
U32 const btMask = (1 << btLog) - 1;
size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const base = zc->base;
- const BYTE* const dictBase = zc->dictBase;
- const U32 dictLimit = zc->dictLimit;
+ const BYTE* const base = ms->base;
+ const BYTE* const dictBase = ms->dictBase;
+ const U32 dictLimit = ms->dictLimit;
const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
@@ -107,7 +109,7 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
U32* largerPtr = smallerPtr + 1;
U32 matchIndex = *smallerPtr;
U32 dummy32; /* to be nullified at the end */
- U32 const windowLow = zc->lowLimit;
+ U32 const windowLow = ms->lowLimit;
DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
current, dictLimit, windowLow);
@@ -166,29 +168,30 @@ static void ZSTD_insertDUBT1(ZSTD_CCtx* zc,
static size_t ZSTD_DUBT_findBestMatch (
- ZSTD_CCtx* zc,
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* const ip, const BYTE* const iend,
size_t* offsetPtr,
- U32 nbCompares, const U32 mls,
- U32 extDict)
+ U32 const mls,
+ U32 const extDict)
{
- U32* const hashTable = zc->hashTable;
- U32 const hashLog = zc->appliedParams.cParams.hashLog;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
U32 matchIndex = hashTable[h];
- const BYTE* const base = zc->base;
+ const BYTE* const base = ms->base;
U32 const current = (U32)(ip-base);
- U32 const windowLow = zc->lowLimit;
+ U32 const windowLow = ms->lowLimit;
- U32* const bt = zc->chainTable;
- U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+ 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 unsortLimit = MAX(btLow, windowLow);
U32* nextCandidate = bt + 2*(matchIndex&btMask);
U32* unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+ U32 nbCompares = 1U << cParams->searchLog;
U32 nbCandidates = nbCompares;
U32 previousCandidate = 0;
@@ -221,7 +224,7 @@ static size_t ZSTD_DUBT_findBestMatch (
while (matchIndex) { /* will end on matchIndex == 0 */
U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
U32 const nextCandidateIdx = *nextCandidateIdxPtr;
- ZSTD_insertDUBT1(zc, matchIndex, iend,
+ ZSTD_insertDUBT1(ms, cParams, matchIndex, iend,
nbCandidates, unsortLimit, extDict);
matchIndex = nextCandidateIdx;
nbCandidates++;
@@ -229,8 +232,8 @@ static size_t ZSTD_DUBT_findBestMatch (
/* find longest match */
{ size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const dictBase = zc->dictBase;
- const U32 dictLimit = zc->dictLimit;
+ const BYTE* const dictBase = ms->dictBase;
+ const U32 dictLimit = ms->dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const prefixStart = base + dictLimit;
U32* smallerPtr = bt + 2*(current&btMask);
@@ -286,7 +289,7 @@ static size_t ZSTD_DUBT_findBestMatch (
*smallerPtr = *largerPtr = 0;
assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
- zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
+ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
if (bestLength >= MINMATCH) {
U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
@@ -299,62 +302,60 @@ static size_t ZSTD_DUBT_findBestMatch (
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
static size_t ZSTD_BtFindBestMatch (
- ZSTD_CCtx* zc,
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* const ip, const BYTE* const iLimit,
size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 mls)
+ const U32 mls /* template */)
{
DEBUGLOG(7, "ZSTD_BtFindBestMatch");
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
- ZSTD_updateDUBT(zc, ip, iLimit, mls);
- return ZSTD_DUBT_findBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
+ if (ip < ms->base + ms->nextToUpdate) return 0; /* skipped area */
+ ZSTD_updateDUBT(ms, cParams, ip, iLimit, mls);
+ return ZSTD_DUBT_findBestMatch(ms, cParams, ip, iLimit, offsetPtr, mls, 0);
}
static size_t ZSTD_BtFindBestMatch_selectMLS (
- ZSTD_CCtx* zc, /* Index table will be updated */
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 matchLengthSearch)
+ size_t* offsetPtr)
{
- switch(matchLengthSearch)
+ switch(cParams->searchLength)
{
default : /* includes case 3 */
- case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
- case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
+ case 4 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 4);
+ case 5 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 5);
case 7 :
- case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
+ case 6 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 6);
}
}
/** Tree updater, providing best match */
static size_t ZSTD_BtFindBestMatch_extDict (
- ZSTD_CCtx* zc,
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* const ip, const BYTE* const iLimit,
size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 mls)
+ const U32 mls)
{
DEBUGLOG(7, "ZSTD_BtFindBestMatch_extDict");
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
- ZSTD_updateDUBT(zc, ip, iLimit, mls);
- return ZSTD_DUBT_findBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
+ if (ip < ms->base + ms->nextToUpdate) return 0; /* skipped area */
+ ZSTD_updateDUBT(ms, cParams, ip, iLimit, mls);
+ return ZSTD_DUBT_findBestMatch(ms, cParams, ip, iLimit, offsetPtr, mls, 1);
}
static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
- ZSTD_CCtx* zc, /* Index table will be updated */
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 matchLengthSearch)
+ size_t* offsetPtr)
{
- switch(matchLengthSearch)
+ switch(cParams->searchLength)
{
default : /* includes case 3 */
- case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
- case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
+ case 4 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 4);
+ case 5 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 5);
case 7 :
- case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
+ case 6 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 6);
}
}
@@ -367,15 +368,17 @@ static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
/* Update chains up to ip (excluded)
Assumption : always within prefix (i.e. not within extDict) */
-U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
+static U32 ZSTD_insertAndFindFirstIndex_internal(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
+ const BYTE* ip, U32 const mls)
{
- U32* const hashTable = zc->hashTable;
- const U32 hashLog = zc->appliedParams.cParams.hashLog;
- U32* const chainTable = zc->chainTable;
- const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
- const BYTE* const base = zc->base;
+ U32* const hashTable = ms->hashTable;
+ const U32 hashLog = cParams->hashLog;
+ U32* const chainTable = ms->chainTable;
+ const U32 chainMask = (1 << cParams->chainLog) - 1;
+ const BYTE* const base = ms->base;
const U32 target = (U32)(ip - base);
- U32 idx = zc->nextToUpdate;
+ U32 idx = ms->nextToUpdate;
while(idx < target) { /* catch up */
size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
@@ -384,35 +387,42 @@ U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
idx++;
}
- zc->nextToUpdate = target;
+ ms->nextToUpdate = target;
return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
}
+U32 ZSTD_insertAndFindFirstIndex(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
+ const BYTE* ip)
+{
+ return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, cParams->searchLength);
+}
+
/* inlining is important to hardwire a hot branch (template emulation) */
FORCE_INLINE_TEMPLATE
size_t ZSTD_HcFindBestMatch_generic (
- ZSTD_CCtx* zc, /* Index table will be updated */
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* const ip, const BYTE* const iLimit,
size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 mls, const U32 extDict)
+ const U32 mls, const U32 extDict)
{
- U32* const chainTable = zc->chainTable;
- const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
+ U32* const chainTable = ms->chainTable;
+ const U32 chainSize = (1 << cParams->chainLog);
const U32 chainMask = chainSize-1;
- const BYTE* const base = zc->base;
- const BYTE* const dictBase = zc->dictBase;
- const U32 dictLimit = zc->dictLimit;
+ const BYTE* const base = ms->base;
+ const BYTE* const dictBase = ms->dictBase;
+ const U32 dictLimit = ms->dictLimit;
const BYTE* const prefixStart = base + dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
- const U32 lowLimit = zc->lowLimit;
+ const U32 lowLimit = ms->lowLimit;
const U32 current = (U32)(ip-base);
const U32 minChain = current > chainSize ? current - chainSize : 0;
- int nbAttempts=maxNbAttempts;
+ U32 nbAttempts = 1U << cParams->searchLog;
size_t ml=4-1;
/* HC4 match finder */
- U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
+ U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
size_t currentMl=0;
@@ -443,35 +453,33 @@ size_t ZSTD_HcFindBestMatch_generic (
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
- ZSTD_CCtx* zc,
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 matchLengthSearch)
+ size_t* offsetPtr)
{
- switch(matchLengthSearch)
+ switch(cParams->searchLength)
{
default : /* includes case 3 */
- case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
- case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, 0);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, 0);
case 7 :
- case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 6, 0);
}
}
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
- ZSTD_CCtx* const zc,
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* ip, const BYTE* const iLimit,
- size_t* const offsetPtr,
- U32 const maxNbAttempts, U32 const matchLengthSearch)
+ size_t* const offsetPtr)
{
- switch(matchLengthSearch)
+ switch(cParams->searchLength)
{
default : /* includes case 3 */
- case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
- case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, 1);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, 1);
case 7 :
- case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 6, 1);
}
}
@@ -480,30 +488,29 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
* Common parser - lazy strategy
*********************************/
FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 searchMethod, const U32 depth)
+size_t ZSTD_compressBlock_lazy_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams,
+ const void* src, size_t srcSize,
+ const U32 searchMethod, const U32 depth)
{
- seqStore_t* seqStorePtr = &(ctx->seqStore);
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ctx->base + ctx->dictLimit;
+ const BYTE* const base = ms->base + ms->dictLimit;
- U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
- U32 const mls = ctx->appliedParams.cParams.searchLength;
-
- typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
- size_t* offsetPtr,
- U32 maxNbAttempts, U32 matchLengthSearch);
+ typedef size_t (*searchMax_f)(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
+ const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
- U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0;
+ U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
/* init */
ip += (ip==base);
- ctx->nextToUpdate3 = ctx->nextToUpdate;
+ ms->nextToUpdate3 = ms->nextToUpdate;
{ U32 const maxRep = (U32)(ip-base);
if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
@@ -524,7 +531,7 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
/* first search (depth 0) */
{ size_t offsetFound = 99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
+ size_t const ml2 = searchMax(ms, cParams, ip, iend, &offsetFound);
if (ml2 > matchLength)
matchLength = ml2, start = ip, offset=offsetFound;
}
@@ -546,7 +553,7 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
matchLength = mlRep, offset = 0, start = ip;
}
{ size_t offset2=99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
+ size_t const ml2 = searchMax(ms, cParams, 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);
if ((ml2 >= 4) && (gain2 > gain1)) {
@@ -565,7 +572,7 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
matchLength = ml2, offset = 0, start = ip;
}
{ size_t offset2=99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
+ size_t const ml2 = searchMax(ms, cParams, 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);
if ((ml2 >= 4) && (gain2 > gain1)) {
@@ -590,7 +597,7 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
/* store sequence */
_storeSequence:
{ size_t const litLength = start - anchor;
- ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, litLength, anchor, (U32)offset, matchLength-MINMATCH);
anchor = ip = start + matchLength;
}
@@ -600,73 +607,80 @@ _storeSequence:
/* 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(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
ip += matchLength;
anchor = ip;
continue; /* faster when present ... (?) */
} }
/* Save reps for next block */
- seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
- seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
+ rep[0] = offset_1 ? offset_1 : savedOffset;
+ rep[1] = offset_2 ? offset_2 : savedOffset;
/* Return the last literals size */
return iend - anchor;
}
-size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_btlazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 1, 2);
}
-size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_lazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 2);
}
-size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_lazy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 1);
}
-size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_greedy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 0);
}
FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 searchMethod, const U32 depth)
+size_t ZSTD_compressBlock_lazy_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams,
+ const void* src, size_t srcSize,
+ const U32 searchMethod, const U32 depth)
{
- seqStore_t* seqStorePtr = &(ctx->seqStore);
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ctx->base;
- const U32 dictLimit = ctx->dictLimit;
- const U32 lowestIndex = ctx->lowLimit;
+ const BYTE* const base = ms->base;
+ const U32 dictLimit = ms->dictLimit;
+ const U32 lowestIndex = ms->lowLimit;
const BYTE* const prefixStart = base + dictLimit;
- const BYTE* const dictBase = ctx->dictBase;
+ const BYTE* const dictBase = ms->dictBase;
const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const dictStart = dictBase + ctx->lowLimit;
+ const BYTE* const dictStart = dictBase + ms->lowLimit;
- const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
- const U32 mls = ctx->appliedParams.cParams.searchLength;
-
- typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
- size_t* offsetPtr,
- U32 maxNbAttempts, U32 matchLengthSearch);
+ typedef size_t (*searchMax_f)(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
+ const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
- U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1];
+ U32 offset_1 = rep[0], offset_2 = rep[1];
/* init */
- ctx->nextToUpdate3 = ctx->nextToUpdate;
+ ms->nextToUpdate3 = ms->nextToUpdate;
ip += (ip == prefixStart);
/* Match Loop */
@@ -690,7 +704,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
/* first search (depth 0) */
{ size_t offsetFound = 99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
+ size_t const ml2 = searchMax(ms, cParams, ip, iend, &offsetFound);
if (ml2 > matchLength)
matchLength = ml2, start = ip, offset=offsetFound;
}
@@ -723,7 +737,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
/* search match, depth 1 */
{ size_t offset2=99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
+ size_t const ml2 = searchMax(ms, cParams, 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);
if ((ml2 >= 4) && (gain2 > gain1)) {
@@ -753,7 +767,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
/* search match, depth 2 */
{ size_t offset2=99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
+ size_t const ml2 = searchMax(ms, cParams, 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);
if ((ml2 >= 4) && (gain2 > gain1)) {
@@ -775,7 +789,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
/* store sequence */
_storeSequence:
{ size_t const litLength = start - anchor;
- ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, litLength, anchor, (U32)offset, matchLength-MINMATCH);
anchor = ip = start + matchLength;
}
@@ -790,7 +804,7 @@ _storeSequence:
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(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
ip += matchLength;
anchor = ip;
continue; /* faster when present ... (?) */
@@ -799,29 +813,41 @@ _storeSequence:
} }
/* Save reps for next block */
- seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
+ rep[0] = offset_1;
+ rep[1] = offset_2;
/* Return the last literals size */
return iend - anchor;
}
-size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_greedy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 0);
}
-size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_lazy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
+
{
- return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 1);
}
-size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_lazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
+
{
- return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 2);
}
-size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_btlazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
+
{
- return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, cParams, src, srcSize, 1, 2);
}
diff --git a/lib/compress/zstd_lazy.h b/lib/compress/zstd_lazy.h
index 5c02f1661..bda064f19 100644
--- a/lib/compress/zstd_lazy.h
+++ b/lib/compress/zstd_lazy.h
@@ -15,22 +15,39 @@
extern "C" {
#endif
-#include "mem.h" /* U32 */
-#include "zstd.h" /* ZSTD_CCtx, size_t */
+#include "zstd_compress_internal.h"
+
+U32 ZSTD_insertAndFindFirstIndex(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
+ const BYTE* ip);
-U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls); /* used in ZSTD_loadDictionaryContent() */
-void ZSTD_updateDUBT(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iend, U32 mls); /* used in ZSTD_loadDictionaryContent() */
void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK */
-size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
+size_t ZSTD_compressBlock_btlazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btlazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
#if defined (__cplusplus)
}
diff --git a/lib/compress/zstd_ldm.c b/lib/compress/zstd_ldm.c
index be50872cf..cc71de2e0 100644
--- a/lib/compress/zstd_ldm.c
+++ b/lib/compress/zstd_ldm.c
@@ -205,21 +205,22 @@ static size_t ZSTD_ldm_countBackwardsMatch(
*
* The tables for the other strategies are filled within their
* block compressors. */
-static size_t ZSTD_ldm_fillFastTables(ZSTD_CCtx* zc, const void* end)
+static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
+ ZSTD_compressionParameters const* cParams,
+ void const* end)
{
const BYTE* const iend = (const BYTE*)end;
- const U32 mls = zc->appliedParams.cParams.searchLength;
- switch(zc->appliedParams.cParams.strategy)
+ switch(cParams->strategy)
{
case ZSTD_fast:
- ZSTD_fillHashTable(zc, iend, mls);
- zc->nextToUpdate = (U32)(iend - zc->base);
+ ZSTD_fillHashTable(ms, cParams, iend);
+ ms->nextToUpdate = (U32)(iend - ms->base);
break;
case ZSTD_dfast:
- ZSTD_fillDoubleHashTable(zc, iend, mls);
- zc->nextToUpdate = (U32)(iend - zc->base);
+ ZSTD_fillDoubleHashTable(ms, cParams, iend);
+ ms->nextToUpdate = (U32)(iend - ms->base);
break;
case ZSTD_greedy:
@@ -268,51 +269,41 @@ static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
* Sets cctx->nextToUpdate to a position corresponding closer to anchor
* if it is far way
* (after a long match, only update tables a limited amount). */
-static void ZSTD_ldm_limitTableUpdate(ZSTD_CCtx* cctx, const BYTE* anchor)
+static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
{
- U32 const current = (U32)(anchor - cctx->base);
- if (current > cctx->nextToUpdate + 1024) {
- cctx->nextToUpdate =
- current - MIN(512, current - cctx->nextToUpdate - 1024);
+ U32 const current = (U32)(anchor - ms->base);
+ if (current > ms->nextToUpdate + 1024) {
+ ms->nextToUpdate =
+ current - MIN(512, current - ms->nextToUpdate - 1024);
}
}
-typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-/* defined in zstd_compress.c */
-ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict);
+size_t ZSTD_compressBlock_ldm(
+ ldmState_t* ldmState, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_CCtx_params const* params, void const* src, size_t srcSize)
-FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
- const void* src, size_t srcSize)
{
- ldmState_t* const ldmState = &(cctx->ldmState);
- const ldmParams_t ldmParams = cctx->appliedParams.ldmParams;
+ ZSTD_compressionParameters const* cParams = ¶ms->cParams;
+ const ldmParams_t ldmParams = params->ldmParams;
const U64 hashPower = ldmState->hashPower;
const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog);
const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1;
- seqStore_t* const seqStorePtr = &(cctx->seqStore);
- const BYTE* const base = cctx->base;
+ const BYTE* const base = ms->base;
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
- const U32 lowestIndex = cctx->dictLimit;
+ const U32 lowestIndex = ms->dictLimit;
const BYTE* const lowest = base + lowestIndex;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - MAX(ldmParams.minMatchLength, HASH_READ_SIZE);
const ZSTD_blockCompressor blockCompressor =
- ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0);
- U32* const repToConfirm = seqStorePtr->repToConfirm;
- U32 savedRep[ZSTD_REP_NUM];
+ ZSTD_selectBlockCompressor(cParams->strategy, 0);
U64 rollingHash = 0;
const BYTE* lastHashed = NULL;
size_t i, lastLiterals;
- /* Save seqStorePtr->rep and copy repToConfirm */
- for (i = 0; i < ZSTD_REP_NUM; i++)
- savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i];
-
/* Main Search Loop */
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
size_t mLength;
@@ -390,25 +381,21 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
const BYTE* const match = base + matchIndex - backwardMatchLength;
U32 const offset = (U32)(ip - match);
- /* Overwrite rep codes */
- for (i = 0; i < ZSTD_REP_NUM; i++)
- seqStorePtr->rep[i] = repToConfirm[i];
-
/* Fill tables for block compressor */
- ZSTD_ldm_limitTableUpdate(cctx, anchor);
- ZSTD_ldm_fillFastTables(cctx, anchor);
+ ZSTD_ldm_limitTableUpdate(ms, anchor);
+ ZSTD_ldm_fillFastTables(ms, cParams, anchor);
/* Call block compressor and get remaining literals */
- lastLiterals = blockCompressor(cctx, anchor, ip - anchor);
- cctx->nextToUpdate = (U32)(ip - base);
+ lastLiterals = blockCompressor(ms, seqStore, rep, cParams, anchor, ip - anchor);
+ ms->nextToUpdate = (U32)(ip - base);
/* Update repToConfirm with the new offset */
for (i = ZSTD_REP_NUM - 1; i > 0; i--)
- repToConfirm[i] = repToConfirm[i-1];
- repToConfirm[0] = offset;
+ rep[i] = rep[i-1];
+ rep[0] = offset;
/* Store the sequence with the leftover literals */
- ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals,
+ ZSTD_storeSeq(seqStore, lastLiterals, ip - lastLiterals,
offset + ZSTD_REP_MOVE, mLength - MINMATCH);
}
@@ -431,19 +418,19 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
anchor = ip;
/* Check immediate repcode */
while ( (ip < ilimit)
- && ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest))
- && (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) {
+ && ( (rep[1] > 0) && (rep[1] <= (U32)(ip-lowest))
+ && (MEM_read32(ip) == MEM_read32(ip - rep[1])) )) {
- size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1],
+ size_t const rLength = ZSTD_count(ip+4, ip+4-rep[1],
iend) + 4;
/* Swap repToConfirm[1] <=> repToConfirm[0] */
{
- U32 const tmpOff = repToConfirm[1];
- repToConfirm[1] = repToConfirm[0];
- repToConfirm[0] = tmpOff;
+ U32 const tmpOff = rep[1];
+ rep[1] = rep[0];
+ rep[0] = tmpOff;
}
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
/* Fill the hash table from lastHashed+1 to ip+rLength*/
if (ip + rLength < ilimit) {
@@ -457,67 +444,45 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
}
}
- /* Overwrite rep */
- for (i = 0; i < ZSTD_REP_NUM; i++)
- seqStorePtr->rep[i] = repToConfirm[i];
+ ZSTD_ldm_limitTableUpdate(ms, anchor);
+ ZSTD_ldm_fillFastTables(ms, cParams, anchor);
- ZSTD_ldm_limitTableUpdate(cctx, anchor);
- ZSTD_ldm_fillFastTables(cctx, anchor);
-
- lastLiterals = blockCompressor(cctx, anchor, iend - anchor);
- cctx->nextToUpdate = (U32)(iend - base);
-
- /* Restore seqStorePtr->rep */
- for (i = 0; i < ZSTD_REP_NUM; i++)
- seqStorePtr->rep[i] = savedRep[i];
+ lastLiterals = blockCompressor(ms, seqStore, rep, cParams, anchor, iend - anchor);
+ ms->nextToUpdate = (U32)(iend - base);
/* Return the last literals size */
return lastLiterals;
}
-size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_ldm_extDict(
+ ldmState_t* ldmState, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_CCtx_params const* params, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_ldm_generic(ctx, src, srcSize);
-}
-
-static size_t ZSTD_compressBlock_ldm_extDict_generic(
- ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
-{
- ldmState_t* const ldmState = &(ctx->ldmState);
- const ldmParams_t ldmParams = ctx->appliedParams.ldmParams;
+ const ldmParams_t ldmParams = params->ldmParams;
+ ZSTD_compressionParameters const* cParams = ¶ms->cParams;
const U64 hashPower = ldmState->hashPower;
const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog);
const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1;
- seqStore_t* const seqStorePtr = &(ctx->seqStore);
- const BYTE* const base = ctx->base;
- const BYTE* const dictBase = ctx->dictBase;
+ const BYTE* const base = ms->base;
+ const BYTE* const dictBase = ms->dictBase;
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
- const U32 lowestIndex = ctx->lowLimit;
+ const U32 lowestIndex = ms->lowLimit;
const BYTE* const dictStart = dictBase + lowestIndex;
- const U32 dictLimit = ctx->dictLimit;
+ const U32 dictLimit = ms->dictLimit;
const BYTE* const lowPrefixPtr = base + dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - MAX(ldmParams.minMatchLength, HASH_READ_SIZE);
const ZSTD_blockCompressor blockCompressor =
- ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1);
- U32* const repToConfirm = seqStorePtr->repToConfirm;
- U32 savedRep[ZSTD_REP_NUM];
+ ZSTD_selectBlockCompressor(cParams->strategy, 1);
U64 rollingHash = 0;
const BYTE* lastHashed = NULL;
size_t i, lastLiterals;
- /* Save seqStorePtr->rep and copy repToConfirm */
- for (i = 0; i < ZSTD_REP_NUM; i++) {
- savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i];
- }
-
/* Search Loop */
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
size_t mLength;
@@ -605,25 +570,21 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
U32 const matchIndex = bestEntry->offset;
U32 const offset = current - matchIndex;
- /* Overwrite rep codes */
- for (i = 0; i < ZSTD_REP_NUM; i++)
- seqStorePtr->rep[i] = repToConfirm[i];
-
/* Fill the hash table for the block compressor */
- ZSTD_ldm_limitTableUpdate(ctx, anchor);
- ZSTD_ldm_fillFastTables(ctx, anchor);
+ ZSTD_ldm_limitTableUpdate(ms, anchor);
+ ZSTD_ldm_fillFastTables(ms, cParams, anchor);
/* Call block compressor and get remaining literals */
- lastLiterals = blockCompressor(ctx, anchor, ip - anchor);
- ctx->nextToUpdate = (U32)(ip - base);
+ lastLiterals = blockCompressor(ms, seqStore, rep, cParams, anchor, ip - anchor);
+ ms->nextToUpdate = (U32)(ip - base);
/* Update repToConfirm with the new offset */
for (i = ZSTD_REP_NUM - 1; i > 0; i--)
- repToConfirm[i] = repToConfirm[i-1];
- repToConfirm[0] = offset;
+ rep[i] = rep[i-1];
+ rep[0] = offset;
/* Store the sequence with the leftover literals */
- ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals,
+ ZSTD_storeSeq(seqStore, lastLiterals, ip - lastLiterals,
offset + ZSTD_REP_MOVE, mLength - MINMATCH);
}
@@ -647,7 +608,7 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
/* check immediate repcode */
while (ip < ilimit) {
U32 const current2 = (U32)(ip-base);
- U32 const repIndex2 = current2 - repToConfirm[1];
+ U32 const repIndex2 = current2 - rep[1];
const BYTE* repMatch2 = repIndex2 < dictLimit ?
dictBase + repIndex2 : base + repIndex2;
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) &
@@ -659,11 +620,11 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
ZSTD_count_2segments(ip+4, repMatch2+4, iend,
repEnd2, lowPrefixPtr) + 4;
- U32 tmpOffset = repToConfirm[1];
- repToConfirm[1] = repToConfirm[0];
- repToConfirm[0] = tmpOffset;
+ U32 tmpOffset = rep[1];
+ rep[1] = rep[0];
+ rep[0] = tmpOffset;
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
/* Fill the hash table from lastHashed+1 to ip+repLength2*/
if (ip + repLength2 < ilimit) {
@@ -681,27 +642,13 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
}
}
- /* Overwrite rep */
- for (i = 0; i < ZSTD_REP_NUM; i++)
- seqStorePtr->rep[i] = repToConfirm[i];
-
- ZSTD_ldm_limitTableUpdate(ctx, anchor);
- ZSTD_ldm_fillFastTables(ctx, anchor);
+ ZSTD_ldm_limitTableUpdate(ms, anchor);
+ ZSTD_ldm_fillFastTables(ms, cParams, anchor);
/* Call the block compressor one last time on the last literals */
- lastLiterals = blockCompressor(ctx, anchor, iend - anchor);
- ctx->nextToUpdate = (U32)(iend - base);
-
- /* Restore seqStorePtr->rep */
- for (i = 0; i < ZSTD_REP_NUM; i++)
- seqStorePtr->rep[i] = savedRep[i];
+ lastLiterals = blockCompressor(ms, seqStore, rep, cParams, anchor, iend - anchor);
+ ms->nextToUpdate = (U32)(iend - base);
/* Return the last literals size */
return lastLiterals;
}
-
-size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
-{
- return ZSTD_compressBlock_ldm_extDict_generic(ctx, src, srcSize);
-}
diff --git a/lib/compress/zstd_ldm.h b/lib/compress/zstd_ldm.h
index 8f12c677a..7041c65a0 100644
--- a/lib/compress/zstd_ldm.h
+++ b/lib/compress/zstd_ldm.h
@@ -37,9 +37,13 @@ extern "C" {
* parameters), which stores the matched sequences. The "long distance"
* match is then stored with the remaining literals from the
* ZSTD_blockCompressor. */
-size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* cctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize);
+size_t ZSTD_compressBlock_ldm(
+ ldmState_t* ldms, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_CCtx_params const* params, void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_ldm_extDict(
+ ldmState_t* ldms, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_CCtx_params const* params, void const* src, size_t srcSize);
/** ZSTD_ldm_initializeParameters() :
* Initialize the long distance matching parameters to their default values. */
diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c
index 04824ccf2..1c56ff32d 100644
--- a/lib/compress/zstd_opt.c
+++ b/lib/compress/zstd_opt.c
@@ -243,13 +243,13 @@ 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_CCtx* const cctx, const BYTE* const ip)
+static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* const ip)
{
- U32* const hashTable3 = cctx->hashTable3;
- U32 const hashLog3 = cctx->hashLog3;
- const BYTE* const base = cctx->base;
- U32 idx = cctx->nextToUpdate3;
- U32 const target = cctx->nextToUpdate3 = (U32)(ip - base);
+ U32* const hashTable3 = ms->hashTable3;
+ U32 const hashLog3 = ms->hashLog3;
+ const BYTE* const base = ms->base;
+ U32 idx = ms->nextToUpdate3;
+ U32 const target = ms->nextToUpdate3 = (U32)(ip - base);
size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
while(idx < target) {
@@ -267,21 +267,22 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* const cctx, const BYTE*
/** ZSTD_insertBt1() : add one or multiple positions to tree.
* ip : assumed <= iend-8 .
* @return : nb of positions added */
-static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
+static U32 ZSTD_insertBt1(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* const ip, const BYTE* const iend,
- U32 nbCompares, U32 const mls, U32 const extDict)
+ U32 const mls, U32 const extDict)
{
- U32* const hashTable = zc->hashTable;
- U32 const hashLog = zc->appliedParams.cParams.hashLog;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
- U32* const bt = zc->chainTable;
- U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
U32 const btMask = (1 << btLog) - 1;
U32 matchIndex = hashTable[h];
size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const base = zc->base;
- const BYTE* const dictBase = zc->dictBase;
- const U32 dictLimit = zc->dictLimit;
+ const BYTE* const base = ms->base;
+ const BYTE* const dictBase = ms->dictBase;
+ const U32 dictLimit = ms->dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const prefixStart = base + dictLimit;
const BYTE* match;
@@ -290,9 +291,10 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
U32* smallerPtr = bt + 2*(current&btMask);
U32* largerPtr = smallerPtr + 1;
U32 dummy32; /* to be nullified at the end */
- U32 const windowLow = zc->lowLimit;
+ U32 const windowLow = ms->lowLimit;
U32 matchEndIdx = current+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);
@@ -375,66 +377,60 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
}
FORCE_INLINE_TEMPLATE
-void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
+void ZSTD_updateTree_internal(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* const ip, const BYTE* const iend,
- const U32 nbCompares, const U32 mls, const U32 extDict)
+ const U32 mls, const U32 extDict)
{
- const BYTE* const base = zc->base;
+ const BYTE* const base = ms->base;
U32 const target = (U32)(ip - base);
- U32 idx = zc->nextToUpdate;
+ U32 idx = ms->nextToUpdate;
DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (extDict:%u)",
idx, target, extDict);
while(idx < target)
- idx += ZSTD_insertBt1(zc, base+idx, iend, nbCompares, mls, extDict);
- zc->nextToUpdate = target;
+ idx += ZSTD_insertBt1(ms, cParams, base+idx, iend, mls, extDict);
+ ms->nextToUpdate = target;
}
-void ZSTD_updateTree(ZSTD_CCtx* zc,
- const BYTE* ip, const BYTE* iend,
- U32 nbCompares, U32 mls)
+void ZSTD_updateTree(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
+ const BYTE* ip, const BYTE* iend)
{
- ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
+ ZSTD_updateTree_internal(ms, cParams, ip, iend, cParams->searchLength, 0 /*extDict*/);
}
-static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- const U32 nbCompares, const U32 mls)
-{
- ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 1 /*extDict*/);
-}
-
-
FORCE_INLINE_TEMPLATE
U32 ZSTD_insertBtAndGetAllMatches (
- ZSTD_CCtx* zc,
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* const ip, const BYTE* const iLimit, int const extDict,
- U32 nbCompares, U32 const mls, U32 const sufficient_len,
U32 rep[ZSTD_REP_NUM], U32 const ll0,
- ZSTD_match_t* matches, const U32 lengthToBeat)
+ ZSTD_match_t* matches, const U32 lengthToBeat, U32 const mls /* template */)
{
- const BYTE* const base = zc->base;
+ U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+ const BYTE* const base = ms->base;
U32 const current = (U32)(ip-base);
- U32 const hashLog = zc->appliedParams.cParams.hashLog;
+ U32 const hashLog = cParams->hashLog;
U32 const minMatch = (mls==3) ? 3 : 4;
- U32* const hashTable = zc->hashTable;
+ U32* const hashTable = ms->hashTable;
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
U32 matchIndex = hashTable[h];
- U32* const bt = zc->chainTable;
- U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
U32 const btMask= (1U << btLog) - 1;
size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const dictBase = zc->dictBase;
- U32 const dictLimit = zc->dictLimit;
+ const BYTE* const dictBase = ms->dictBase;
+ U32 const dictLimit = ms->dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const prefixStart = base + dictLimit;
U32 const btLow = btMask >= current ? 0 : current - btMask;
- U32 const windowLow = zc->lowLimit;
+ U32 const windowLow = ms->lowLimit;
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 dummy32; /* to be nullified at the end */
U32 mnum = 0;
+ U32 nbCompares = 1U << cParams->searchLog;
size_t bestLength = lengthToBeat-1;
DEBUGLOG(7, "ZSTD_insertBtAndGetAllMatches");
@@ -475,7 +471,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
/* HC3 match finder */
if ((mls == 3) /*static*/ && (bestLength < mls)) {
- U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
+ U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip);
if ((matchIndex3 > windowLow)
& (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
size_t mlen;
@@ -499,7 +495,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
mnum = 1;
if ( (mlen > sufficient_len) |
(ip+mlen == iLimit) ) { /* best possible length */
- zc->nextToUpdate = current+1; /* skip insertion */
+ ms->nextToUpdate = current+1; /* skip insertion */
return 1;
} } } }
@@ -556,30 +552,29 @@ U32 ZSTD_insertBtAndGetAllMatches (
*smallerPtr = *largerPtr = 0;
assert(matchEndIdx > current+8);
- zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
+ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
return mnum;
}
FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
- ZSTD_CCtx* zc, /* Index table will be updated */
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
const BYTE* ip, const BYTE* const iHighLimit, int const extDict,
- U32 const maxNbAttempts, U32 const matchLengthSearch, U32 const sufficient_len,
U32 rep[ZSTD_REP_NUM], U32 const ll0,
ZSTD_match_t* matches, U32 const lengthToBeat)
{
+ U32 const matchLengthSearch = cParams->searchLength;
DEBUGLOG(7, "ZSTD_BtGetAllMatches");
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
- if (extDict) ZSTD_updateTree_extDict(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
- else ZSTD_updateTree(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
+ if (ip < ms->base + ms->nextToUpdate) return 0; /* skipped area */
+ ZSTD_updateTree_internal(ms, cParams, ip, iHighLimit, matchLengthSearch, extDict);
switch(matchLengthSearch)
{
- case 3 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 3, sufficient_len, rep, ll0, matches, lengthToBeat);
+ case 3 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 3);
default :
- case 4 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 4, sufficient_len, rep, ll0, matches, lengthToBeat);
- case 5 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 5, sufficient_len, rep, ll0, matches, lengthToBeat);
+ case 4 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 4);
+ case 5 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 5);
case 7 :
- case 6 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 6, sufficient_len, rep, ll0, matches, lengthToBeat);
+ case 6 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 6);
}
}
@@ -667,36 +662,33 @@ static int ZSTD_literalsContribution_cached(
}
FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
+size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams,
const void* src, size_t srcSize,
const int optLevel, const int extDict)
{
- seqStore_t* const seqStorePtr = &(ctx->seqStore);
- optState_t* const optStatePtr = &(ctx->optState);
+ optState_t* const optStatePtr = &ms->opt;
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ctx->base;
- const BYTE* const prefixStart = base + ctx->dictLimit;
+ const BYTE* const base = ms->base;
+ const BYTE* const prefixStart = base + ms->dictLimit;
- U32 const maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
- U32 const sufficient_len = MIN(ctx->appliedParams.cParams.targetLength, ZSTD_OPT_NUM -1);
- U32 const mls = ctx->appliedParams.cParams.searchLength;
- U32 const minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
+ U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+ U32 const minMatch = (cParams->searchLength == 3) ? 3 : 4;
ZSTD_optimal_t* const opt = optStatePtr->priceTable;
ZSTD_match_t* const matches = optStatePtr->matchTable;
cachedLiteralPrice_t cachedLitPrice;
- U32 rep[ZSTD_REP_NUM];
/* init */
DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
- ctx->nextToUpdate3 = ctx->nextToUpdate;
+ ms->nextToUpdate3 = ms->nextToUpdate;
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
ip += (ip==prefixStart);
- { int i; for (i=0; irep[i]; }
memset(&cachedLitPrice, 0, sizeof(cachedLitPrice));
/* Match Loop */
@@ -707,7 +699,7 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
/* find first match */
{ U32 const litlen = (U32)(ip - anchor);
U32 const ll0 = !litlen;
- U32 const nbMatches = ZSTD_BtGetAllMatches(ctx, ip, iend, extDict, maxSearches, mls, sufficient_len, rep, ll0, matches, minMatch);
+ U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, ip, iend, extDict, rep, ll0, matches, minMatch);
if (!nbMatches) { ip++; continue; }
/* initialize opt[0] */
@@ -793,7 +785,7 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
U32 const litlen = (opt[cur].mlen == 1) ? opt[cur].litlen : 0;
U32 const previousPrice = (cur > litlen) ? opt[cur-litlen].price : 0;
U32 const basePrice = previousPrice + ZSTD_fullLiteralsCost(inr-litlen, litlen, optStatePtr);
- U32 const nbMatches = ZSTD_BtGetAllMatches(ctx, inr, iend, extDict, maxSearches, mls, sufficient_len, opt[cur].rep, ll0, matches, minMatch);
+ U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, inr, iend, extDict, opt[cur].rep, ll0, matches, minMatch);
U32 matchNb;
if (!nbMatches) continue;
@@ -889,37 +881,42 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
}
ZSTD_updateStats(optStatePtr, llen, anchor, offset, mlen);
- ZSTD_storeSeq(seqStorePtr, llen, anchor, offset, mlen-MINMATCH);
+ ZSTD_storeSeq(seqStore, llen, anchor, offset, mlen-MINMATCH);
anchor = ip;
} }
ZSTD_setLog2Prices(optStatePtr);
} /* while (ip < ilimit) */
- /* Save reps for next block */
- { int i; for (i=0; irepToConfirm[i] = rep[i]; }
-
/* Return the last literals size */
return iend - anchor;
}
-size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_btopt(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
DEBUGLOG(5, "ZSTD_compressBlock_btopt");
- return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0 /*optLevel*/, 0 /*extDict*/);
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, 0 /*extDict*/);
}
-size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_btultra(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 2 /*optLevel*/, 0 /*extDict*/);
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, 0 /*extDict*/);
}
-size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_btopt_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0 /*optLevel*/, 1 /*extDict*/);
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, 1 /*extDict*/);
}
-size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock_btultra_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
{
- return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 2 /*optLevel*/, 1 /*extDict*/);
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, 1 /*extDict*/);
}
diff --git a/lib/compress/zstd_opt.h b/lib/compress/zstd_opt.h
index b803a0f2e..b8dc389f3 100644
--- a/lib/compress/zstd_opt.h
+++ b/lib/compress/zstd_opt.h
@@ -15,16 +15,25 @@
extern "C" {
#endif
-#include "mem.h" /* U32 */
-#include "zstd.h" /* ZSTD_CCtx, size_t */
+#include "zstd_compress_internal.h"
-void ZSTD_updateTree(ZSTD_CCtx* ctx, const BYTE* ip, const BYTE* iend, U32 nbCompares, U32 mls); /* used in ZSTD_loadDictionaryContent() */
+void ZSTD_updateTree(
+ ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
+ const BYTE* ip, const BYTE* iend); /* used in ZSTD_loadDictionaryContent() */
-size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
+size_t ZSTD_compressBlock_btopt(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
+size_t ZSTD_compressBlock_btopt_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
#if defined (__cplusplus)
}
From aae267a2e1687b6eaebb3ada9c08ddbc5d5d74dc Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Fri, 12 Jan 2018 12:06:10 -0800
Subject: [PATCH 049/255] Reorganize block state
---
lib/compress/zstd_compress.c | 107 +++++++++++++-------------
lib/compress/zstd_compress_internal.h | 26 ++++---
2 files changed, 69 insertions(+), 64 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index eba0baad0..49f73dc53 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -82,12 +82,12 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
/* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
- if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_blockState_t)) return NULL;
+ if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL;
assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
- cctx->prevBlock = (ZSTD_blockState_t*)cctx->workSpace;
- cctx->nextBlock = cctx->prevBlock + 1;
+ cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace;
+ cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1;
{
- void* const ptr = cctx->nextBlock + 1;
+ void* const ptr = cctx->blockState.nextCBlock + 1;
cctx->entropyWorkspace = (U32*)ptr;
}
return cctx;
@@ -665,7 +665,7 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
size_t const h3Size = ((size_t)1) << hashLog3;
size_t const entropySpace = HUF_WORKSPACE_SIZE;
- size_t const blockStateSpace = 2 * sizeof(ZSTD_blockState_t);
+ size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
size_t const optBudget =
@@ -799,7 +799,7 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
}
-static void ZSTD_resetBlockState(ZSTD_blockState_t* bs)
+static void ZSTD_resetBlockState(ZSTD_compressedBlockState_t* bs)
{
int i;
for (i = 0; i < ZSTD_REP_NUM; ++i)
@@ -845,8 +845,8 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
(U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
cctx->stage = ZSTDcs_init;
cctx->dictID = 0;
- ZSTD_invalidateMatchState(&cctx->matchState);
- ZSTD_resetBlockState(cctx->prevBlock);
+ ZSTD_invalidateMatchState(&cctx->blockState.matchState);
+ ZSTD_resetBlockState(cctx->blockState.prevCBlock);
XXH64_reset(&cctx->xxhState, 0);
return 0;
}
@@ -860,6 +860,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
ZSTD_compResetPolicy_e const crp,
ZSTD_buffered_policy_e const zbuff)
{
+ ZSTD_matchState_t* const ms = &zc->blockState.matchState;
DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
(U32)pledgedSrcSize, params.cParams.windowLog);
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
@@ -903,7 +904,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
/* Check if workSpace is large enough, alloc a new one if needed */
{ size_t const entropySpace = HUF_WORKSPACE_SIZE;
- size_t const blockStateSpace = 2 * sizeof(ZSTD_blockState_t);
+ size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<workSpace & 3) == 0); /* ensure correct alignment */
- assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_blockState_t));
- zc->prevBlock = (ZSTD_blockState_t*)zc->workSpace;
- zc->nextBlock = zc->prevBlock + 1;
- ptr = zc->nextBlock + 1;
+ assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t));
+ zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace;
+ zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1;
+ ptr = zc->blockState.nextCBlock + 1;
zc->entropyWorkspace = (U32*)ptr;
} }
@@ -957,19 +958,19 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->stage = ZSTDcs_init;
zc->dictID = 0;
- zc->matchState.nextSrc = NULL;
- zc->matchState.base = NULL;
- zc->matchState.dictBase = NULL;
- zc->matchState.hashLog3 = hashLog3;
- ZSTD_invalidateMatchState(&zc->matchState);
+ ms->nextSrc = NULL;
+ ms->base = NULL;
+ ms->dictBase = NULL;
+ ms->hashLog3 = hashLog3;
+ ZSTD_invalidateMatchState(ms);
- ZSTD_resetBlockState(zc->prevBlock);
+ ZSTD_resetBlockState(zc->blockState.prevCBlock);
ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
/* opt parser space */
if ((params.cParams.strategy == ZSTD_btopt) | (params.cParams.strategy == ZSTD_btultra)) {
- optState_t* opt = &zc->matchState.opt;
+ optState_t* opt = &zc->blockState.matchState.opt;
DEBUGLOG(4, "reserving optimal parser space");
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
opt->litFreq = (U32*)ptr;
@@ -997,10 +998,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
- zc->matchState.hashTable = (U32*)(ptr);
- zc->matchState.chainTable = zc->matchState.hashTable + hSize;
- zc->matchState.hashTable3 = zc->matchState.chainTable + chainSize;
- ptr = zc->matchState.hashTable3 + h3Size;
+ ms->hashTable = (U32*)(ptr);
+ ms->chainTable = ms->hashTable + hSize;
+ ms->hashTable3 = ms->chainTable + chainSize;
+ ptr = ms->hashTable3 + h3Size;
/* sequences storage */
zc->seqStore.sequencesStart = (seqDef*)ptr;
@@ -1037,8 +1038,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
* do not use with extDict variant ! */
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
int i;
- for (i=0; iprevBlock->rep[i] = 0;
- assert(/* !extDict */ cctx->matchState.lowLimit == cctx->matchState.dictLimit);
+ for (i=0; iblockState.prevCBlock->rep[i] = 0;
+ assert(/* !extDict */ cctx->blockState.matchState.lowLimit == cctx->blockState.matchState.dictLimit);
}
@@ -1072,17 +1073,17 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
/* copy tables */
{ size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
- size_t const h3Size = (size_t)1 << srcCCtx->matchState.hashLog3;
+ size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3;
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
- assert((U32*)dstCCtx->matchState.chainTable == (U32*)dstCCtx->matchState.hashTable + hSize); /* chainTable must follow hashTable */
- assert((U32*)dstCCtx->matchState.hashTable3 == (U32*)dstCCtx->matchState.chainTable + chainSize);
- memcpy(dstCCtx->matchState.hashTable, srcCCtx->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
+ assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
+ assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize);
+ memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */
}
/* copy dictionary offsets */
{
- ZSTD_matchState_t const* srcMatchState = &srcCCtx->matchState;
- ZSTD_matchState_t* dstMatchState = &dstCCtx->matchState;
+ ZSTD_matchState_t const* srcMatchState = &srcCCtx->blockState.matchState;
+ ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
dstMatchState->nextSrc = srcMatchState->nextSrc;
@@ -1095,7 +1096,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
dstCCtx->dictID = srcCCtx->dictID;
/* copy block state */
- memcpy(dstCCtx->prevBlock, srcCCtx->prevBlock, sizeof(*srcCCtx->prevBlock));
+ memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
return 0;
}
@@ -1162,7 +1163,7 @@ static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
* rescale all indexes to avoid future overflow (indexes are U32) */
static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
{
- ZSTD_matchState_t* const ms = &zc->matchState;
+ ZSTD_matchState_t* const ms = &zc->blockState.matchState;
{ U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
}
@@ -1721,23 +1722,23 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
const void* src, size_t srcSize)
{
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u) (dictLimit=%u, nextToUpdate=%u)",
- (U32)dstCapacity, zc->matchState.dictLimit, zc->matchState.nextToUpdate);
+ (U32)dstCapacity, zc->blockState.matchState.dictLimit, zc->blockState.matchState.nextToUpdate);
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1)
return 0; /* don't even attempt compression below a certain srcSize */
ZSTD_resetSeqStore(&(zc->seqStore));
/* limited update after a very long match */
- { const BYTE* const base = zc->matchState.base;
+ { const BYTE* const base = zc->blockState.matchState.base;
const BYTE* const istart = (const BYTE*)src;
const U32 current = (U32)(istart-base);
- if (current > zc->matchState.nextToUpdate + 384)
- zc->matchState.nextToUpdate = current - MIN(192, (U32)(current - zc->matchState.nextToUpdate - 384));
+ if (current > zc->blockState.matchState.nextToUpdate + 384)
+ zc->blockState.matchState.nextToUpdate = current - MIN(192, (U32)(current - zc->blockState.matchState.nextToUpdate - 384));
}
/* find and store sequences */
{
- U32 const extDict = zc->matchState.lowLimit < zc->matchState.dictLimit;
+ U32 const extDict = zc->blockState.matchState.lowLimit < zc->blockState.matchState.dictLimit;
size_t lastLLSize;
- { int i; for (i = 0; i < ZSTD_REP_NUM; ++i) zc->nextBlock->rep[i] = zc->prevBlock->rep[i]; }
+ { int i; for (i = 0; i < ZSTD_REP_NUM; ++i) zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; }
if (zc->appliedParams.ldmParams.enableLdm) {
typedef size_t (*ZSTD_ldmBlockCompressor)(
ldmState_t* ldms, ZSTD_matchState_t* ms, seqStore_t* seqStore,
@@ -1745,11 +1746,11 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
void const* src, size_t srcSize);
ZSTD_ldmBlockCompressor const ldmBlockCompressor = extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm;
- lastLLSize = ldmBlockCompressor(&zc->ldmState, &zc->matchState, &zc->seqStore, zc->nextBlock->rep, &zc->appliedParams, src, srcSize);
+ lastLLSize = ldmBlockCompressor(&zc->ldmState, &zc->blockState.matchState, &zc->seqStore, zc->blockState.nextCBlock->rep, &zc->appliedParams, src, srcSize);
} else {
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
- lastLLSize = blockCompressor(&zc->matchState, &zc->seqStore, zc->nextBlock->rep, &zc->appliedParams.cParams, src, srcSize);
+ lastLLSize = blockCompressor(&zc->blockState.matchState, &zc->seqStore, zc->blockState.nextCBlock->rep, &zc->appliedParams.cParams, src, srcSize);
}
{
const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
@@ -1758,14 +1759,14 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
}
/* encode */
{
- size_t const cSize = ZSTD_compressSequences(&zc->seqStore, &zc->prevBlock->entropy, &zc->nextBlock->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize, zc->entropyWorkspace);
+ size_t const cSize = ZSTD_compressSequences(&zc->seqStore, &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize, zc->entropyWorkspace);
if (ZSTD_isError(cSize) || cSize == 0)
return cSize;
/* confirm repcodes and entropy tables */
{
- ZSTD_blockState_t* const tmp = zc->prevBlock;
- zc->prevBlock = zc->nextBlock;
- zc->nextBlock = tmp;
+ ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
+ zc->blockState.prevCBlock = zc->blockState.nextCBlock;
+ zc->blockState.nextCBlock = tmp;
}
return cSize;
}
@@ -1797,7 +1798,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
XXH64_update(&cctx->xxhState, src, srcSize);
while (remaining) {
- ZSTD_matchState_t* const ms = &cctx->matchState;
+ ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
@@ -1823,7 +1824,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
*/
if (ms->lowLimit > (3U<<29)) {
U32 const cycleMask = ((U32)1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1;
- U32 const current = (U32)(ip - cctx->matchState.base);
+ U32 const current = (U32)(ip - cctx->blockState.matchState.base);
U32 const newCurrent = (current & cycleMask) + ((U32)1 << cctx->appliedParams.cParams.windowLog);
U32 const correction = current - newCurrent;
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
@@ -1975,7 +1976,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
- ZSTD_manageWindowContinuity(&cctx->matchState, src, srcSize);
+ ZSTD_manageWindowContinuity(&cctx->blockState.matchState, src, srcSize);
DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize);
{ size_t const cSize = frame ?
@@ -2085,7 +2086,7 @@ static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSym
* assumptions : magic number supposed already checked
* dictSize supposed > 8
*/
-static size_t ZSTD_loadZstdDictionary(ZSTD_blockState_t* bs, ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, void* workspace)
+static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, void* workspace)
{
const BYTE* dictPtr = (const BYTE*)dict;
const BYTE* const dictEnd = dictPtr + dictSize;
@@ -2181,12 +2182,12 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
/* dict restricted modes */
if (dictMode==ZSTD_dm_rawContent)
- return ZSTD_loadDictionaryContent(&cctx->matchState, &cctx->appliedParams, dict, dictSize);
+ return ZSTD_loadDictionaryContent(&cctx->blockState.matchState, &cctx->appliedParams, dict, dictSize);
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
if (dictMode == ZSTD_dm_auto) {
DEBUGLOG(4, "raw content dictionary detected");
- return ZSTD_loadDictionaryContent(&cctx->matchState, &cctx->appliedParams, dict, dictSize);
+ return ZSTD_loadDictionaryContent(&cctx->blockState.matchState, &cctx->appliedParams, dict, dictSize);
}
if (dictMode == ZSTD_dm_fullDict)
return ERROR(dictionary_wrong);
@@ -2195,7 +2196,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
/* dict as full zstd dictionary */
{
- size_t const dictID = ZSTD_loadZstdDictionary(cctx->prevBlock, &cctx->matchState, &cctx->appliedParams, dict, dictSize, cctx->entropyWorkspace);
+ size_t const dictID = ZSTD_loadZstdDictionary(cctx->blockState.prevCBlock, &cctx->blockState.matchState, &cctx->appliedParams, dict, dictSize, cctx->entropyWorkspace);
if (ZSTD_isError(dictID)) return dictID;
cctx->dictID = (U32)dictID;
}
diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h
index 7a7b1db1d..7be20d4c5 100644
--- a/lib/compress/zstd_compress_internal.h
+++ b/lib/compress/zstd_compress_internal.h
@@ -57,11 +57,6 @@ typedef struct {
FSE_repeat litlength_repeatMode;
} ZSTD_entropyCTables_t;
-typedef struct {
- ZSTD_entropyCTables_t entropy;
- U32 rep[ZSTD_REP_NUM];
-} ZSTD_blockState_t;
-
typedef struct {
U32 off;
U32 len;
@@ -98,7 +93,12 @@ typedef struct {
} optState_t;
typedef struct {
- BYTE const* nextSrc; /* next block here to continue on current prefix */ /* TODO: Does this belong here? */
+ ZSTD_entropyCTables_t entropy;
+ U32 rep[ZSTD_REP_NUM];
+} 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 */
@@ -106,13 +106,19 @@ typedef struct {
U32 nextToUpdate; /* index from which to continue table update */
U32 nextToUpdate3; /* index from which to continue table update */
U32 hashLog3; /* dispatch table : larger == faster, more memory */
- U32 loadedDictEnd; /* index of end of dictionary */ /* TODO: Does this belong here? */
+ U32 loadedDictEnd; /* index of end of dictionary */
U32* hashTable;
U32* hashTable3;
U32* chainTable;
optState_t opt; /* optimal parser state */
} ZSTD_matchState_t;
+typedef struct {
+ ZSTD_compressedBlockState_t* prevCBlock;
+ ZSTD_compressedBlockState_t* nextCBlock;
+ ZSTD_matchState_t matchState;
+} ZSTD_blockState_t;
+
typedef struct {
U32 offset;
U32 checksum;
@@ -171,9 +177,7 @@ struct ZSTD_CCtx_s {
seqStore_t seqStore; /* sequences storage ptrs */
ldmState_t ldmState; /* long distance matching state */
- ZSTD_matchState_t matchState;
- ZSTD_blockState_t* prevBlock;
- ZSTD_blockState_t* nextBlock;
+ ZSTD_blockState_t blockState;
U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
/* streaming */
@@ -202,7 +206,7 @@ struct ZSTD_CCtx_s {
typedef size_t (*ZSTD_blockCompressor) (
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict);
From 19cb37f837165fb3d8cbf6c4f890a67191ed96d3 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Tue, 16 Jan 2018 11:40:42 -0800
Subject: [PATCH 050/255] travis ci : added gcc-7 test
also added `-Werror` to sanitizer tests
---
.travis.yml | 1 +
Makefile | 19 +++++++++++--------
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 48d9ac3a6..bb6ca8474 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,7 @@ matrix:
# Ubuntu 14.04
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-test-zstd'
- env: Cmd='make gcc6install libc6install && CC=gcc-6 make clean uasan-test-zstd32'
+ - env: Cmd='make gcc7install && CC=gcc-7 make clean uasan-test-zstd'
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-test-zstd'
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-fuzztest'
diff --git a/Makefile b/Makefile
index c8f0ed4d4..8157bdd9d 100644
--- a/Makefile
+++ b/Makefile
@@ -231,31 +231,31 @@ msanregressiontest:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303
usan: clean
- $(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=undefined"
+ $(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=undefined -Werror"
asan: clean
- $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=address"
+ $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=address -Werror"
asan-%: clean
- LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=address" $(MAKE) -C $(TESTDIR) $*
+ LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=address -Werror" $(MAKE) -C $(TESTDIR) $*
msan: clean
- $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=memory -fno-omit-frame-pointer" HAVE_LZMA=0 # datagen.c fails this test for no obvious reason
+ $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=memory -fno-omit-frame-pointer -Werror" HAVE_LZMA=0 # datagen.c fails this test for no obvious reason
msan-%: clean
- LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) HAVE_LZMA=0 $*
+ LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer -Werror" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) HAVE_LZMA=0 $*
asan32: clean
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address"
uasan: clean
- $(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=address,undefined"
+ $(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=address,undefined -Werror"
uasan-%: clean
- LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=address,undefined" $(MAKE) -C $(TESTDIR) $*
+ LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=address,undefined -Werror" $(MAKE) -C $(TESTDIR) $*
tsan-%: clean
- LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=thread" $(MAKE) -C $(TESTDIR) $* FUZZER_FLAGS=--no-big-tests
+ LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=thread -Werror" $(MAKE) -C $(TESTDIR) $* FUZZER_FLAGS=--no-big-tests
apt-install:
sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install $(APT_PACKAGES)
@@ -279,6 +279,9 @@ libc6install:
gcc6install: apt-add-repo
APT_PACKAGES="libc6-dev-i386 gcc-multilib gcc-6 gcc-6-multilib" $(MAKE) apt-install
+gcc7install: apt-add-repo
+ APT_PACKAGES="libc6-dev-i386 gcc-multilib gcc-7 gcc-7-multilib" $(MAKE) apt-install
+
gpp6install: apt-add-repo
APT_PACKAGES="libc6-dev-i386 g++-multilib gcc-6 g++-6 g++-6-multilib" $(MAKE) apt-install
From f4e58455f67de7451b0316925e2944d7caa5f1fb Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Tue, 16 Jan 2018 11:50:16 -0800
Subject: [PATCH 051/255] ensure MOREFLAGS are not lost in root->tests Makefile
invocation
---
Makefile | 2 +-
tests/Makefile | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 8157bdd9d..d2c71ad39 100644
--- a/Makefile
+++ b/Makefile
@@ -77,7 +77,7 @@ check: shortest
.PHONY: test shortest
test shortest:
- $(MAKE) -C $(PRGDIR) allVariants MOREFLAGS="-g -DZSTD_DEBUG=1"
+ $(MAKE) -C $(PRGDIR) allVariants MOREFLAGS+="-g -DZSTD_DEBUG=1"
$(MAKE) -C $(TESTDIR) $@
.PHONY: examples
diff --git a/tests/Makefile b/tests/Makefile
index 95d0bf549..f3171efa5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -98,7 +98,7 @@ zstd-nolegacy:
$(MAKE) -C $(PRGDIR) $@ MOREFLAGS+="$(DEBUGFLAGS)"
gzstd:
- $(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 MOREFLAGS="$(DEBUGFLAGS)"
+ $(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 MOREFLAGS+="$(DEBUGFLAGS)"
.PHONY:
zstd-dll :
From 2e23333094e6df6f84b7e21b2dcf64deff88ec30 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Tue, 16 Jan 2018 15:28:43 -0800
Subject: [PATCH 052/255] ZSTDMT can now work in non-blocking mode with 1
thread
it still fallbacks to single-thread blocking invocation
when input is small (<1job)
or when invoking ZSTDMT_compress(), which is blocking.
Also : fixed a bug in new block-granular compression routine.
---
lib/compress/zstd_compress.c | 3 +-
lib/compress/zstdmt_compress.c | 71 ++++++++++++++++++--------------
lib/compress/zstdmt_compress.h | 2 +-
lib/decompress/zstd_decompress.c | 12 +++---
tests/zstreamtest.c | 7 ++++
5 files changed, 57 insertions(+), 38 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 49f73dc53..d2703f231 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -1962,7 +1962,8 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
{
size_t fhSize = 0;
- DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u", cctx->stage);
+ DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
+ cctx->stage, (U32)srcSize);
if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
if (frame && (cctx->stage==ZSTDcs_init)) {
diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
index 3a5b58a72..47b8923ac 100644
--- a/lib/compress/zstdmt_compress.c
+++ b/lib/compress/zstdmt_compress.c
@@ -365,11 +365,12 @@ void ZSTDMT_compressChunk(void* jobDescription)
if (!job->firstChunk) { /* flush and overwrite frame header when it's not first job */
size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0);
if (ZSTD_isError(hSize)) { job->cSize = hSize; /* save error code */ goto _endJob; }
+ DEBUGLOG(5, "ZSTDMT_compressChunk: flush and overwrite %u bytes of frame header (not first chunk)", (U32)hSize);
ZSTD_invalidateRepCodes(cctx);
}
/* compress */
-#if 1
+#if 0
job->cSize = (job->lastChunk) ?
ZSTD_compressEnd (cctx, dstBuff.start, dstBuff.size, src, job->srcSize) :
ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, job->srcSize);
@@ -382,26 +383,28 @@ void ZSTDMT_compressChunk(void* jobDescription)
BYTE* op = ostart;
BYTE* oend = op + dstBuff.size;
int blockNb;
+ DEBUGLOG(5, "ZSTDMT_compressChunk: compress %u bytes in %i blocks", (U32)job->srcSize, nbBlocks);
job->cSize = 0;
- for (blockNb = 0; blockNb < nbBlocks-1; blockNb++) {
+ for (blockNb = 1; blockNb < nbBlocks; blockNb++) {
size_t const cSize = ZSTD_compressContinue(cctx, op, oend-op, ip, ZSTD_BLOCKSIZE_MAX);
if (ZSTD_isError(cSize)) { job->cSize = cSize; goto _endJob; }
ip += ZSTD_BLOCKSIZE_MAX;
op += cSize; assert(op < oend);
/* stats */
job->cSize += cSize;
- job->readSize = ZSTD_BLOCKSIZE_MAX * (blockNb+1);
+ job->readSize = ZSTD_BLOCKSIZE_MAX * blockNb;
}
/* last block */
- { size_t const lastBlockSize1 = job->srcSize & (ZSTD_BLOCKSIZE_MAX-1);
- size_t const lastBlockSize = (lastBlockSize1==0) ? ZSTD_BLOCKSIZE_MAX : lastBlockSize1;
+ if ((nbBlocks > 0) | job->lastChunk /*need to output a "last block" flag*/ ) {
+ size_t const lastBlockSize1 = job->srcSize & (ZSTD_BLOCKSIZE_MAX-1);
+ size_t const lastBlockSize = ((lastBlockSize1==0) & (job->srcSize>=ZSTD_BLOCKSIZE_MAX)) ? ZSTD_BLOCKSIZE_MAX : lastBlockSize1;
size_t const cSize = (job->lastChunk) ?
ZSTD_compressEnd (cctx, op, oend-op, ip, lastBlockSize) :
ZSTD_compressContinue(cctx, op, oend-op, ip, lastBlockSize);
if (ZSTD_isError(cSize)) { job->cSize = cSize; goto _endJob; }
/* stats */
job->cSize += cSize;
- job->readSize = ZSTD_BLOCKSIZE_MAX * (blockNb+1);
+ job->readSize = job->srcSize;
}
}
#endif
@@ -443,7 +446,7 @@ struct ZSTDMT_CCtx_s {
size_t targetDictSize;
inBuff_t inBuff;
XXH64_state_t xxhState;
- unsigned singleThreaded;
+ unsigned singleBlockingThread;
unsigned jobIDMask;
unsigned doneJobID;
unsigned nextJobID;
@@ -457,7 +460,7 @@ struct ZSTDMT_CCtx_s {
/* Sets parameters relevant to the compression job, initializing others to
* default values. Notably, nbThreads should probably be zero. */
-static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
+static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(ZSTD_CCtx_params const params)
{
ZSTD_CCtx_params jobParams;
memset(&jobParams, 0, sizeof(jobParams));
@@ -646,17 +649,21 @@ size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter,
/* ===== Multi-threaded compression ===== */
/* ------------------------------------------ */
-static unsigned computeNbChunks(size_t srcSize, unsigned windowLog, unsigned nbThreads) {
- size_t const chunkSizeTarget = (size_t)1 << (windowLog + 2);
- size_t const chunkMaxSize = chunkSizeTarget << 2;
- size_t const passSizeMax = chunkMaxSize * nbThreads;
- unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1;
- unsigned const nbChunksLarge = multiplier * nbThreads;
- unsigned const nbChunksMax = (unsigned)(srcSize / chunkSizeTarget) + 1;
- unsigned const nbChunksSmall = MIN(nbChunksMax, nbThreads);
- return (multiplier>1) ? nbChunksLarge : nbChunksSmall;
-}
+static unsigned ZSTDMT_computeNbChunks(size_t srcSize, unsigned windowLog, unsigned nbThreads) {
+ assert(nbThreads>0);
+ { size_t const chunkSizeTarget = (size_t)1 << (windowLog + 2);
+ size_t const chunkMaxSize = chunkSizeTarget << 2;
+ size_t const passSizeMax = chunkMaxSize * nbThreads;
+ unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1;
+ unsigned const nbChunksLarge = multiplier * nbThreads;
+ unsigned const nbChunksMax = (unsigned)(srcSize / chunkSizeTarget) + 1;
+ unsigned const nbChunksSmall = MIN(nbChunksMax, nbThreads);
+ return (multiplier>1) ? nbChunksLarge : nbChunksSmall;
+} }
+/* 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,
@@ -664,10 +671,10 @@ static size_t ZSTDMT_compress_advanced_internal(
const ZSTD_CDict* cdict,
ZSTD_CCtx_params const params)
{
- ZSTD_CCtx_params const jobParams = ZSTDMT_makeJobCCtxParams(params);
+ ZSTD_CCtx_params const jobParams = ZSTDMT_initJobCCtxParams(params);
unsigned const overlapRLog = (params.overlapSizeLog>9) ? 0 : 9-params.overlapSizeLog;
size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog);
- unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads);
+ unsigned nbChunks = ZSTDMT_computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads);
size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks;
size_t const avgChunkSize = (((proposedChunkSize-1) & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */
const char* const srcStart = (const char*)src;
@@ -678,14 +685,16 @@ static size_t ZSTDMT_compress_advanced_internal(
assert(jobParams.nbThreads == 0);
assert(mtctx->cctxPool->totalCCtx == params.nbThreads);
- DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbChunks=%2u (rawSize=%u bytes; fixedSize=%u) ",
+ DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbChunks=%2u (rawSize=%u bytes; fixedSize=%u) ",
nbChunks, (U32)proposedChunkSize, (U32)avgChunkSize);
- if (nbChunks==1) { /* fallback to single-thread mode */
+
+ if ((nbChunks==1) | (params.nbThreads<=1)) { /* fallback to single-thread mode : this is a blocking invocation anyway */
ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
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(avgChunkSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), which is required for compressWithinDst */
+
+ assert(avgChunkSize >= 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(avgChunkSize) );
XXH64_reset(&xxh64, 0);
@@ -695,6 +704,7 @@ static size_t ZSTDMT_compress_advanced_internal(
mtctx->jobIDMask = 0;
mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, mtctx->cMem);
if (mtctx->jobs==NULL) return ERROR(memory_allocation);
+ assert((nbJobs != 0) && ((nbJobs & (nbJobs - 1)) == 0)); /* ensure nbJobs is a power of 2 */
mtctx->jobIDMask = nbJobs - 1;
}
@@ -827,10 +837,10 @@ size_t ZSTDMT_initCStream_internal(
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
assert(zcs->cctxPool->totalCCtx == params.nbThreads);
- zcs->singleThreaded = (params.nbThreads==1) | (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */
+ zcs->singleBlockingThread = pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN; /* do not trigger multi-threading when srcSize is too small */
- if (zcs->singleThreaded) {
- ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params);
+ if (zcs->singleBlockingThread) {
+ ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(params);
DEBUGLOG(4, "single thread mode");
assert(singleThreadParams.nbThreads == 0);
return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0],
@@ -921,10 +931,11 @@ size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize)
}
size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) {
- ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
+ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
ZSTD_CCtx_params cctxParams = zcs->params;
cctxParams.cParams = params.cParams;
cctxParams.fParams = params.fParams;
+ DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel);
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
}
@@ -1071,7 +1082,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
assert(output->pos <= output->size);
assert(input->pos <= input->size);
- if (mtctx->singleThreaded) { /* delegate to single-thread (synchronous) */
+ if (mtctx->singleBlockingThread) { /* delegate to single-thread (synchronous) */
return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
}
@@ -1166,7 +1177,7 @@ static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* ou
size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
{
DEBUGLOG(5, "ZSTDMT_flushStream");
- if (mtctx->singleThreaded)
+ if (mtctx->singleBlockingThread)
return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
return ZSTDMT_flushStream_internal(mtctx, output, 0 /* endFrame */);
}
@@ -1174,7 +1185,7 @@ size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
{
DEBUGLOG(4, "ZSTDMT_endStream");
- if (mtctx->singleThreaded)
+ if (mtctx->singleBlockingThread)
return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
return ZSTDMT_flushStream_internal(mtctx, output, 1 /* endFrame */);
}
diff --git a/lib/compress/zstdmt_compress.h b/lib/compress/zstdmt_compress.h
index d12f0adb8..b6e68684e 100644
--- a/lib/compress/zstdmt_compress.h
+++ b/lib/compress/zstdmt_compress.h
@@ -85,7 +85,7 @@ ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
* 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_overlapSectionLog /* Each job may reload a part of previous job to enhance compressionr ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window */
+ ZSTDMT_p_overlapSectionLog /* Each job may reload a part of previous job to enhance compressionr 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_parameter;
/* ZSTDMT_setMTCtxParameter() :
diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
index ab6c2edc5..a573cc19f 100644
--- a/lib/decompress/zstd_decompress.c
+++ b/lib/decompress/zstd_decompress.c
@@ -1759,7 +1759,7 @@ static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skip
* or an error code, which can be tested using ZSTD_isError() */
size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{
- DEBUGLOG(5, "ZSTD_decompressContinue");
+ DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (U32)srcSize);
/* Sanity check */
if (srcSize != dctx->expected) return ERROR(srcSize_wrong); /* not allowed */
if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
@@ -1820,12 +1820,12 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
case ZSTDds_decompressLastBlock:
case ZSTDds_decompressBlock:
- DEBUGLOG(5, "case ZSTDds_decompressBlock");
+ DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
{ size_t rSize;
switch(dctx->bType)
{
case bt_compressed:
- DEBUGLOG(5, "case bt_compressed");
+ DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
break;
case bt_raw :
@@ -1839,12 +1839,12 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
return ERROR(corruption_detected);
}
if (ZSTD_isError(rSize)) return rSize;
- DEBUGLOG(5, "decoded size from block : %u", (U32)rSize);
+ DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (U32)rSize);
dctx->decodedSize += rSize;
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
- DEBUGLOG(4, "decoded size from frame : %u", (U32)dctx->decodedSize);
+ DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (U32)dctx->decodedSize);
if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
if (dctx->decodedSize != dctx->fParams.frameContentSize) {
return ERROR(corruption_detected);
@@ -1868,7 +1868,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
assert(srcSize == 4); /* guaranteed by dctx->expected */
{ U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
U32 const check32 = MEM_readLE32(src);
- DEBUGLOG(4, "checksum : calculated %08X :: %08X read", h32, check32);
+ DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", h32, check32);
if (check32 != h32) return ERROR(checksum_wrong);
dctx->expected = 0;
dctx->stage = ZSTDds_getFrameHeaderSize;
diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
index 5590c9af1..5cd1ea0fb 100644
--- a/tests/zstreamtest.c
+++ b/tests/zstreamtest.c
@@ -1243,6 +1243,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
{ int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
+ DISPLAYLEVEL(5, "Init with compression level = %i \n", compressionLevel);
CHECK_Z( ZSTDMT_initCStream(zc, compressionLevel) );
}
} else {
@@ -1301,9 +1302,12 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
if ((FUZ_rand(&lseed) & 15) == 0) {
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
+ size_t const previousPos = outBuff.pos;
outBuff.size = outBuff.pos + adjustedDstSize;
DISPLAYLEVEL(5, "Flushing into dst buffer of size %u \n", (U32)adjustedDstSize);
CHECK_Z( ZSTDMT_flushStream(zc, &outBuff) );
+ assert(outBuff.pos >= previousPos);
+ DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_flushStream \n", (U32)(outBuff.pos-previousPos));
} }
/* final frame epilogue */
@@ -1311,10 +1315,13 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
while (remainingToFlush) {
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
+ size_t const previousPos = outBuff.pos;
outBuff.size = outBuff.pos + adjustedDstSize;
DISPLAYLEVEL(5, "Ending into dst buffer of size %u \n", (U32)adjustedDstSize);
remainingToFlush = ZSTDMT_endStream(zc, &outBuff);
CHECK (ZSTD_isError(remainingToFlush), "ZSTDMT_endStream error : %s", ZSTD_getErrorName(remainingToFlush));
+ assert(outBuff.pos >= previousPos);
+ DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_endStream \n", (U32)(outBuff.pos-previousPos));
DISPLAYLEVEL(5, "endStream : remainingToFlush : %u \n", (U32)remainingToFlush);
} }
crcOrig = XXH64_digest(&xxhState);
From 6025465e42dfce6d3312b14a80e7614bc52b362c Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Tue, 16 Jan 2018 15:34:41 -0800
Subject: [PATCH 053/255] ZSTDMT : minor CCtx memory optimization
can be useful when a compression job only has small amount of data to compress.
---
lib/compress/zstdmt_compress.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
index 47b8923ac..0dadda284 100644
--- a/lib/compress/zstdmt_compress.c
+++ b/lib/compress/zstdmt_compress.c
@@ -346,7 +346,7 @@ void ZSTDMT_compressChunk(void* jobDescription)
assert(job->firstChunk); /* only allowed for first job */
if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
} else { /* srcStart points at reloaded section */
- U64 const pledgedSrcSize = job->firstChunk ? job->fullFrameSize : ZSTD_CONTENTSIZE_UNKNOWN;
+ U64 const pledgedSrcSize = job->firstChunk ? job->fullFrameSize : job->srcSize;
ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */
{ size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
if (ZSTD_isError(forceWindowError)) {
@@ -355,7 +355,7 @@ void ZSTDMT_compressChunk(void* jobDescription)
} }
{ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
job->srcStart, job->prefixSize, ZSTD_dm_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
- NULL,
+ NULL, /*cdict*/
jobParams, pledgedSrcSize);
if (ZSTD_isError(initError)) {
job->cSize = initError;
@@ -404,8 +404,8 @@ void ZSTDMT_compressChunk(void* jobDescription)
if (ZSTD_isError(cSize)) { job->cSize = cSize; goto _endJob; }
/* stats */
job->cSize += cSize;
- job->readSize = job->srcSize;
}
+ job->readSize = job->srcSize;
}
#endif
From 1dba98d563d81fb42b4ac575e70eaf52654bbf8e Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Tue, 16 Jan 2018 16:15:47 -0800
Subject: [PATCH 054/255] introduced parameter ZSTD_p_nonBlockingMode
This new parameter makes it possible to call
streaming ZSTDMT with a single thread set
which is non blocking.
It makes it possible for the main thread to do other tasks in parallel
while the worker thread does compression.
Typically, for zstd cli, it means it can do I/O stuff.
Applied within fileio.c, this patch provides non-negligible gains during compression.
Tested on my laptop, with enwik9 (1000000000 bytes) : time zstd -f enwik9
With traditional single-thread blocking mode :
real 0m9.557s
user 0m8.861s
sys 0m0.538s
With new single-worker non blocking mode :
real 0m7.938s
user 0m8.049s
sys 0m0.514s
=> 20% faster
---
lib/compress/zstd_compress.c | 29 ++++++++++++++++++---------
lib/compress/zstd_compress_internal.h | 1 +
lib/compress/zstdmt_compress.c | 2 +-
lib/compress/zstdmt_compress.h | 2 +-
lib/zstd.h | 10 +++++++++
programs/fileio.c | 1 +
6 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index d2703f231..fbae3c3f2 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -281,9 +281,8 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
}
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+ case ZSTD_p_nonBlockingMode:
case ZSTD_p_jobSize:
- return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
-
case ZSTD_p_overlapSizeLog:
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
@@ -407,11 +406,18 @@ size_t ZSTD_CCtxParam_setParameter(
return ZSTDMT_CCtxParam_setNbThreads(CCtxParams, value);
#endif
+ case ZSTD_p_nonBlockingMode :
+#ifndef ZSTD_MULTITHREAD
+ return ERROR(parameter_unsupported);
+#else
+ CCtxParams->nonBlockingMode = (value>0);
+ return CCtxParams->nonBlockingMode;
+#endif
+
case ZSTD_p_jobSize :
#ifndef ZSTD_MULTITHREAD
return ERROR(parameter_unsupported);
#else
- if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported);
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value);
#endif
@@ -419,7 +425,6 @@ size_t ZSTD_CCtxParam_setParameter(
#ifndef ZSTD_MULTITHREAD
return ERROR(parameter_unsupported);
#else
- if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported);
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value);
#endif
@@ -3007,12 +3012,17 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
#ifdef ZSTD_MULTITHREAD
- if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN)
+ if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
params.nbThreads = 1; /* do not invoke multi-threading when src size is too small */
- if (params.nbThreads > 1) {
+ params.nonBlockingMode = 0;
+ }
+ if ((params.nbThreads > 1) | (params.nonBlockingMode == 1)) {
if (cctx->mtctx == NULL || (params.nbThreads != ZSTDMT_getNbThreads(cctx->mtctx))) {
- DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbThreads=%u (previous: %u)",
- params.nbThreads, (unsigned)ZSTDMT_getNbThreads(cctx->mtctx));
+ DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbThreads=%u",
+ params.nbThreads);
+ if (cctx->mtctx != NULL)
+ DEBUGLOG(4, "ZSTD_compress_generic: previous nbThreads was %u",
+ ZSTDMT_getNbThreads(cctx->mtctx));
ZSTDMT_freeCCtx(cctx->mtctx);
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
@@ -3024,6 +3034,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
cctx->streamStage = zcss_load;
cctx->appliedParams.nbThreads = params.nbThreads;
+ cctx->appliedParams.nonBlockingMode = params.nonBlockingMode;
} else
#endif
{ CHECK_F( ZSTD_resetCStream_internal(
@@ -3036,7 +3047,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
/* compression stage */
#ifdef ZSTD_MULTITHREAD
- if (cctx->appliedParams.nbThreads > 1) {
+ if ((cctx->appliedParams.nbThreads > 1) | (cctx->appliedParams.nonBlockingMode==1)) {
size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
if ( ZSTD_isError(flushMin)
|| (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h
index 7be20d4c5..eb18cbc5e 100644
--- a/lib/compress/zstd_compress_internal.h
+++ b/lib/compress/zstd_compress_internal.h
@@ -150,6 +150,7 @@ struct ZSTD_CCtx_params_s {
/* Multithreading: used to pass parameters to mtctx */
U32 nbThreads;
+ int nonBlockingMode; /* will trigger ZSTDMT even with nbThreads==1 */
unsigned jobSize;
unsigned overlapSizeLog;
diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
index 0dadda284..0c28eb787 100644
--- a/lib/compress/zstdmt_compress.c
+++ b/lib/compress/zstdmt_compress.c
@@ -497,7 +497,7 @@ size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThread
/* ZSTDMT_getNbThreads():
* @return nb threads currently active in mtctx.
* mtctx must be valid */
-size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx)
+unsigned ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx)
{
assert(mtctx != NULL);
return mtctx->params.nbThreads;
diff --git a/lib/compress/zstdmt_compress.h b/lib/compress/zstdmt_compress.h
index b6e68684e..7716ea68e 100644
--- a/lib/compress/zstdmt_compress.h
+++ b/lib/compress/zstdmt_compress.h
@@ -120,7 +120,7 @@ size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThread
/* ZSTDMT_getNbThreads():
* @return nb threads currently active in mtctx.
* mtctx must be valid */
-size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx);
+unsigned ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx);
/*! ZSTDMT_initCStream_internal() :
* Private use only. Init streaming operation.
diff --git a/lib/zstd.h b/lib/zstd.h
index a84490d99..6ac132a66 100644
--- a/lib/zstd.h
+++ b/lib/zstd.h
@@ -972,10 +972,20 @@ typedef enum {
ZSTD_p_dictIDFlag, /* 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 (ZSTD_MULTITHREAD).
+ * They return an error otherwise. */
ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1)
* More threads improve speed, but also increase memory usage.
* Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled.
* Special: value 0 means "do not change nbThreads" */
+ ZSTD_p_nonBlockingMode, /* Single thread mode is by default "blocking" :
+ * it finishes its job as much as possible, and only then gives back control to caller.
+ * In contrast, multi-thread is by default "non-blocking" :
+ * it takes some input, flush some output if available, and immediately gives back control to caller.
+ * Compression work is performed in parallel, within worker threads.
+ * (note : a strong exception to this rule is when first job is called with ZSTD_e_end : it becomes blocking)
+ * Setting this parameter to 1 will enforce non-blocking mode even when only 1 thread is selected.
+ * It allows the caller to do other tasks while the worker thread compresses in parallel. */
ZSTD_p_jobSize, /* Size of a compression job. This value is only enforced in streaming (non-blocking) mode.
* Each compression job is completed in parallel, so indirectly controls the nb of active threads.
* 0 means default, which is dynamically determined based on compression parameters.
diff --git a/programs/fileio.c b/programs/fileio.c
index 3ae2d4057..ea84853c7 100644
--- a/programs/fileio.c
+++ b/programs/fileio.c
@@ -457,6 +457,7 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
/* multi-threading */
DISPLAYLEVEL(5,"set nb threads = %u \n", g_nbThreads);
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) );
+ CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nonBlockingMode, 1) );
/* dictionary */
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) ); /* just for dictionary loading, for compression parameters adaptation */
CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) );
From 10c213761ac8714bfa9b9e6cf70648ec458308e8 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Tue, 16 Jan 2018 17:28:11 -0800
Subject: [PATCH 055/255] cli: fix for no-MT mode
when cli is compiled without MT support,
invoking ZSTD_p_nonBlockingMode result in an error code.
This patch only sets ZSTD_p_nonBlockingMode when ZSTD_MULTITHREAD is set, meaning there is MT support.
The error code could also be intentionnally ignored (there is no side effect).
---
programs/fileio.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/programs/fileio.c b/programs/fileio.c
index ea84853c7..58b77a813 100644
--- a/programs/fileio.c
+++ b/programs/fileio.c
@@ -457,7 +457,9 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
/* multi-threading */
DISPLAYLEVEL(5,"set nb threads = %u \n", g_nbThreads);
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) );
+#ifdef ZSTD_MULTITHREAD
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nonBlockingMode, 1) );
+#endif
/* dictionary */
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) ); /* just for dictionary loading, for compression parameters adaptation */
CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) );
From 3e1e57db2775c49595b483e22589eb2e20015b14 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Tue, 16 Jan 2018 17:35:00 -0800
Subject: [PATCH 056/255] fix fileio progression status update
The compression % is no longer correct,
since it's no longer possible to make direct correlation
between nb bytes read and nb bytes written
due to large internal buffer inside CCtx
(exacerbated with --long).
The current "fix" is to no longer display the %.
A more complex solution will have to count exactly how much data has been consumed and compressed internally, within CCtx buffers.
---
programs/fileio.c | 18 ++++--------------
1 file changed, 4 insertions(+), 14 deletions(-)
diff --git a/programs/fileio.c b/programs/fileio.c
index 58b77a813..326f0e673 100644
--- a/programs/fileio.c
+++ b/programs/fileio.c
@@ -809,21 +809,11 @@ static int FIO_compressFilename_internal(cRess_t ress,
compressedfilesize += outBuff.pos;
}
}
- if (g_nbThreads > 1) {
- if (fileSize == UTIL_FILESIZE_UNKNOWN)
- DISPLAYUPDATE(2, "\rRead : %u MB", (U32)(readsize>>20))
- else
- DISPLAYUPDATE(2, "\rRead : %u / %u MB",
- (U32)(readsize>>20), (U32)(fileSize>>20));
+ if (fileSize == UTIL_FILESIZE_UNKNOWN) {
+ DISPLAYUPDATE(2, "\rRead : %u MB", (U32)(readsize>>20));
} else {
- if (fileSize == UTIL_FILESIZE_UNKNOWN)
- DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%",
- (U32)(readsize>>20),
- (double)compressedfilesize/readsize*100)
- else
- DISPLAYUPDATE(2, "\rRead : %u / %u MB ==> %.2f%%",
- (U32)(readsize>>20), (U32)(fileSize>>20),
- (double)compressedfilesize/readsize*100);
+ DISPLAYUPDATE(2, "\rRead : %u / %u MB",
+ (U32)(readsize>>20), (U32)(fileSize>>20));
}
} while (directive != ZSTD_e_end);
From 22303da601ccf2e068113c51ce85cc192ec6cd07 Mon Sep 17 00:00:00 2001
From: Alexey Ivanov
Date: Wed, 17 Jan 2018 10:27:52 +0300
Subject: [PATCH 057/255] CMake: fixed multithreading build on Windows
`ZSTD_MULTITHREAD_SUPPORT` option fixed for Windows.
Signed-off-by: Alexey Ivanov
---
build/cmake/CMakeLists.txt | 42 +++++++++++++++++++++--------
build/cmake/lib/CMakeLists.txt | 13 ++++++++-
build/cmake/programs/CMakeLists.txt | 16 +++++------
3 files changed, 50 insertions(+), 21 deletions(-)
diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt
index 7361bc8a6..fd9bc2b1e 100644
--- a/build/cmake/CMakeLists.txt
+++ b/build/cmake/CMakeLists.txt
@@ -31,18 +31,9 @@ MESSAGE(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
#-----------------------------------------------------------------------------
# Options
#-----------------------------------------------------------------------------
+
+# Legacy support
OPTION(ZSTD_LEGACY_SUPPORT "LEGACY SUPPORT" OFF)
-IF (UNIX)
- OPTION(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" ON)
-ELSE (UNIX)
- OPTION(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" OFF)
-ENDIF (UNIX)
-OPTION(ZSTD_BUILD_PROGRAMS "BUILD PROGRAMS" ON)
-OPTION(ZSTD_BUILD_CONTRIB "BUILD CONTRIB" OFF)
-OPTION(ZSTD_BUILD_TESTS "BUILD TESTS" OFF)
-if (MSVC)
- OPTION(ZSTD_USE_STATIC_RUNTIME "LINK TO STATIC RUN-TIME LIBRARIES" OFF)
-endif ()
IF (ZSTD_LEGACY_SUPPORT)
MESSAGE(STATUS "ZSTD_LEGACY_SUPPORT defined!")
@@ -52,6 +43,35 @@ ELSE (ZSTD_LEGACY_SUPPORT)
ADD_DEFINITIONS(-DZSTD_LEGACY_SUPPORT=0)
ENDIF (ZSTD_LEGACY_SUPPORT)
+# Multi-threading support
+OPTION(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" ON)
+
+IF (ZSTD_MULTITHREAD_SUPPORT)
+ MESSAGE(STATUS "ZSTD_MULTITHREAD_SUPPORT is enabled")
+ELSE (ZSTD_MULTITHREAD_SUPPORT)
+ MESSAGE(STATUS "ZSTD_MULTITHREAD_SUPPORT is disabled")
+ENDIF (ZSTD_MULTITHREAD_SUPPORT)
+
+OPTION(ZSTD_BUILD_PROGRAMS "BUILD PROGRAMS" ON)
+OPTION(ZSTD_BUILD_CONTRIB "BUILD CONTRIB" OFF)
+OPTION(ZSTD_BUILD_TESTS "BUILD TESTS" OFF)
+if (MSVC)
+ OPTION(ZSTD_USE_STATIC_RUNTIME "LINK TO STATIC RUN-TIME LIBRARIES" OFF)
+endif ()
+
+#-----------------------------------------------------------------------------
+# External dependencies
+#-----------------------------------------------------------------------------
+IF (ZSTD_MULTITHREAD_SUPPORT AND UNIX)
+ SET(THREADS_PREFER_PTHREAD_FLAG ON)
+ FIND_PACKAGE(Threads REQUIRED)
+ IF(CMAKE_USE_PTHREADS_INIT)
+ SET(THREADS_LIBS "${CMAKE_THREAD_LIBS_INIT}")
+ ELSE()
+ MESSAGE(SEND_ERROR "ZSTD currently does not support thread libraries other than pthreads")
+ ENDIF()
+ENDIF (ZSTD_MULTITHREAD_SUPPORT AND UNIX)
+
#-----------------------------------------------------------------------------
# Add source directories
#-----------------------------------------------------------------------------
diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt
index 3435e1bb3..945fdb922 100644
--- a/build/cmake/lib/CMakeLists.txt
+++ b/build/cmake/lib/CMakeLists.txt
@@ -24,7 +24,7 @@ INCLUDE_DIRECTORIES(${LIBRARY_DIR} ${LIBRARY_DIR}/common)
# Parse version
INCLUDE(GetZstdLibraryVersion)
GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h LIBVER_MAJOR LIBVER_MINOR LIBVER_RELEASE)
-MESSAGE("ZSTD VERSION ${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE}")
+MESSAGE(STATUS "ZSTD VERSION ${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE}")
SET(Sources
${LIBRARY_DIR}/common/entropy_common.c
@@ -120,6 +120,17 @@ IF (MSVC)
ENDIF (ZSTD_BUILD_STATIC)
ENDIF (MSVC)
+# Add multi-threading support definitions
+
+IF (ZSTD_MULTITHREAD_SUPPORT)
+ SET_PROPERTY(TARGET libzstd_shared libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
+
+ IF (UNIX)
+ TARGET_LINK_LIBRARIES(libzstd_shared ${THREADS_LIBS})
+ TARGET_LINK_LIBRARIES(libzstd_static ${THREADS_LIBS})
+ ENDIF ()
+ENDIF (ZSTD_MULTITHREAD_SUPPORT)
+
# With MSVC static library needs to be renamed to avoid conflict with import library
IF (MSVC)
SET(STATIC_LIBRARY_BASE_NAME zstd_static)
diff --git a/build/cmake/programs/CMakeLists.txt b/build/cmake/programs/CMakeLists.txt
index 9251fd295..6c0ed05a1 100644
--- a/build/cmake/programs/CMakeLists.txt
+++ b/build/cmake/programs/CMakeLists.txt
@@ -54,19 +54,17 @@ IF (UNIX)
SET_PROPERTY(TARGET zstd-frugal APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_NOBENCH;ZSTD_NODICT")
ENDIF (UNIX)
+# Add multi-threading support definitions
+
IF (ZSTD_MULTITHREAD_SUPPORT)
SET_PROPERTY(TARGET zstd APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
- SET(THREADS_PREFER_PTHREAD_FLAG ON)
- FIND_PACKAGE(Threads REQUIRED)
- IF (CMAKE_USE_PTHREADS_INIT)
- TARGET_LINK_LIBRARIES(zstd ${CMAKE_THREAD_LIBS_INIT})
- ELSE()
- MESSAGE(SEND_ERROR "ZSTD currently does not support thread libraries other than pthreads")
- ENDIF()
+ IF (UNIX)
+ TARGET_LINK_LIBRARIES(zstd ${THREADS_LIBS})
- ADD_CUSTOM_TARGET(zstdmt ALL ${CMAKE_COMMAND} -E create_symlink zstd zstdmt DEPENDS zstd COMMENT "Creating zstdmt symlink")
- INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstdmt DESTINATION "bin")
+ ADD_CUSTOM_TARGET(zstdmt ALL ${CMAKE_COMMAND} -E create_symlink zstd zstdmt DEPENDS zstd COMMENT "Creating zstdmt symlink")
+ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstdmt DESTINATION "bin")
+ ENDIF (UNIX)
ENDIF (ZSTD_MULTITHREAD_SUPPORT)
OPTION(ZSTD_ZLIB_SUPPORT "ZLIB SUPPORT" OFF)
From cb57c107ff12b1f39adbb25ff14db56112a68cd1 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 17 Jan 2018 11:39:07 -0800
Subject: [PATCH 058/255] zstdmt: minor variable renaming, for clarity
---
lib/compress/zstd_compress.c | 1 +
lib/compress/zstdmt_compress.c | 58 +++++++++++++++++-----------------
2 files changed, 30 insertions(+), 29 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index fbae3c3f2..5cc02bcc3 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -2579,6 +2579,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
}
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) {
+ assert(cdict != NULL);
return cdict->refContext->appliedParams.cParams;
}
diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
index 0c28eb787..c65f3ea15 100644
--- a/lib/compress/zstdmt_compress.c
+++ b/lib/compress/zstdmt_compress.c
@@ -442,8 +442,8 @@ struct ZSTDMT_CCtx_s {
ZSTD_CCtx_params params;
size_t targetSectionSize;
size_t inBuffSize;
- size_t dictSize;
- size_t targetDictSize;
+ size_t prefixSize;
+ size_t targetPrefixSize;
inBuff_t inBuff;
XXH64_state_t xxhState;
unsigned singleBlockingThread;
@@ -841,13 +841,13 @@ size_t ZSTDMT_initCStream_internal(
if (zcs->singleBlockingThread) {
ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(params);
- DEBUGLOG(4, "single thread mode");
+ DEBUGLOG(4, "ZSTDMT_initCStream_internal: switch to single blocking thread mode");
assert(singleThreadParams.nbThreads == 0);
return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0],
dict, dictSize, cdict,
singleThreadParams, pledgedSrcSize);
}
- DEBUGLOG(4, "multi-threading mode (%u threads)", params.nbThreads);
+ DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u threads", params.nbThreads);
if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */
ZSTDMT_waitForAllJobsCompleted(zcs);
@@ -871,17 +871,17 @@ size_t ZSTDMT_initCStream_internal(
}
assert(params.overlapSizeLog <= 9);
- zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
- DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(zcs->targetDictSize>>10));
+ zcs->targetPrefixSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
+ DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(zcs->targetPrefixSize>>10));
zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2);
if (zcs->targetSectionSize < ZSTDMT_JOBSIZE_MIN) zcs->targetSectionSize = ZSTDMT_JOBSIZE_MIN;
- if (zcs->targetSectionSize < zcs->targetDictSize) zcs->targetSectionSize = zcs->targetDictSize; /* job size must be >= overlap size */
+ if (zcs->targetSectionSize < zcs->targetPrefixSize) zcs->targetSectionSize = zcs->targetPrefixSize; /* job size must be >= overlap size */
DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(zcs->targetSectionSize>>10), params.jobSize);
- zcs->inBuffSize = zcs->targetDictSize + zcs->targetSectionSize;
+ zcs->inBuffSize = zcs->targetPrefixSize + zcs->targetSectionSize;
DEBUGLOG(4, "inBuff Size : %u KB", (U32)(zcs->inBuffSize>>10));
ZSTDMT_setBufferSize(zcs->bufPool, MAX(zcs->inBuffSize, ZSTD_compressBound(zcs->targetSectionSize)) );
zcs->inBuff.buffer = g_nullBuffer;
- zcs->dictSize = 0;
+ zcs->prefixSize = 0;
zcs->doneJobID = 0;
zcs->nextJobID = 0;
zcs->frameEnded = 0;
@@ -895,8 +895,8 @@ size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
ZSTD_parameters params,
unsigned long long pledgedSrcSize)
{
- ZSTD_CCtx_params cctxParams = mtctx->params;
- DEBUGLOG(5, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)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_dm_auto, NULL,
@@ -909,9 +909,9 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
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;
- if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */
return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dm_auto, cdict,
cctxParams, pledgedSrcSize);
}
@@ -932,10 +932,10 @@ size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize)
size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) {
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
- ZSTD_CCtx_params cctxParams = zcs->params;
+ ZSTD_CCtx_params cctxParams = zcs->params; /* retrieve sticky params */
+ DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel);
cctxParams.cParams = params.cParams;
cctxParams.fParams = params.fParams;
- DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel);
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
}
@@ -945,13 +945,13 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
unsigned const jobID = zcs->nextJobID & zcs->jobIDMask;
DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ",
- zcs->nextJobID, (U32)srcSize, (U32)zcs->dictSize);
+ zcs->nextJobID, (U32)srcSize, (U32)zcs->prefixSize);
zcs->jobs[jobID].src = zcs->inBuff.buffer;
zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start;
zcs->jobs[jobID].srcSize = srcSize;
zcs->jobs[jobID].readSize = 0;
- zcs->jobs[jobID].prefixSize = zcs->dictSize;
- assert(zcs->inBuff.filled >= srcSize + zcs->dictSize);
+ zcs->jobs[jobID].prefixSize = zcs->prefixSize;
+ assert(zcs->inBuff.filled >= srcSize + zcs->prefixSize);
zcs->jobs[jobID].params = zcs->params;
/* do not calculate checksum within sections, but write it in header for first section */
if (zcs->nextJobID) zcs->jobs[jobID].params.fParams.checksumFlag = 0;
@@ -968,11 +968,11 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
zcs->jobs[jobID].jobCompleted_cond = &zcs->jobCompleted_cond;
if (zcs->params.fParams.checksumFlag)
- XXH64_update(&zcs->xxhState, (const char*)zcs->inBuff.buffer.start + zcs->dictSize, srcSize);
+ XXH64_update(&zcs->xxhState, (const char*)zcs->inBuff.buffer.start + zcs->prefixSize, srcSize);
/* get a new buffer for next input */
if (!endFrame) {
- size_t const newDictSize = MIN(srcSize + zcs->dictSize, zcs->targetDictSize);
+ size_t const newPrefixSize = MIN(srcSize + zcs->prefixSize, zcs->targetPrefixSize);
zcs->inBuff.buffer = ZSTDMT_getBuffer(zcs->bufPool);
if (zcs->inBuff.buffer.start == NULL) { /* not enough memory to allocate next input buffer */
zcs->jobs[jobID].jobCompleted = 1;
@@ -981,15 +981,15 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
ZSTDMT_releaseAllJobResources(zcs);
return ERROR(memory_allocation);
}
- zcs->inBuff.filled -= srcSize + zcs->dictSize - newDictSize;
+ zcs->inBuff.filled -= srcSize + zcs->prefixSize - newPrefixSize;
memmove(zcs->inBuff.buffer.start,
- (const char*)zcs->jobs[jobID].srcStart + zcs->dictSize + srcSize - newDictSize,
+ (const char*)zcs->jobs[jobID].srcStart + zcs->prefixSize + srcSize - newPrefixSize,
zcs->inBuff.filled);
- zcs->dictSize = newDictSize;
+ zcs->prefixSize = newPrefixSize;
} else { /* if (endFrame==1) */
zcs->inBuff.buffer = g_nullBuffer;
zcs->inBuff.filled = 0;
- zcs->dictSize = 0;
+ zcs->prefixSize = 0;
zcs->frameEnded = 1;
if (zcs->nextJobID == 0) {
/* single chunk exception : checksum is calculated directly within worker thread */
@@ -1028,17 +1028,17 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
{ ZSTDMT_jobDescription job = zcs->jobs[wJobID];
if (!job.jobScanned) {
if (ZSTD_isError(job.cSize)) {
- DEBUGLOG(5, "job %u : compression error detected : %s",
+ DEBUGLOG(5, "ZSTDMT_flushNextJob: job %u : compression error detected : %s",
zcs->doneJobID, ZSTD_getErrorName(job.cSize));
ZSTDMT_waitForAllJobsCompleted(zcs);
ZSTDMT_releaseAllJobResources(zcs);
return job.cSize;
}
- DEBUGLOG(5, "zcs->params.fParams.checksumFlag : %u ", zcs->params.fParams.checksumFlag);
+ DEBUGLOG(5, "ZSTDMT_flushNextJob: zcs->params.fParams.checksumFlag : %u ", zcs->params.fParams.checksumFlag);
if (zcs->params.fParams.checksumFlag) {
if (zcs->frameEnded && (zcs->doneJobID+1 == zcs->nextJobID)) { /* write checksum at end of last section */
U32 const checksum = (U32)XXH64_digest(&zcs->xxhState);
- DEBUGLOG(5, "writing checksum : %08X \n", checksum);
+ DEBUGLOG(5, "ZSTDMT_flushNextJob: writing checksum : %08X \n", checksum);
MEM_writeLE32((char*)job.dstBuff.start + job.cSize, checksum);
job.cSize += 4;
zcs->jobs[wJobID].cSize += 4;
@@ -1046,7 +1046,7 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
zcs->jobs[wJobID].jobScanned = 1;
}
{ size_t const toWrite = MIN(job.cSize - job.dstFlushed, output->size - output->pos);
- DEBUGLOG(5, "Flushing %u bytes from job %u ", (U32)toWrite, zcs->doneJobID);
+ DEBUGLOG(5, "ZSTDMT_flushNextJob: Flushing %u bytes from job %u ", (U32)toWrite, zcs->doneJobID);
memcpy((char*)output->dst + output->pos, (const char*)job.dstBuff.start + job.dstFlushed, toWrite);
output->pos += toWrite;
job.dstFlushed += toWrite;
@@ -1076,7 +1076,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
ZSTD_inBuffer* input,
ZSTD_EndDirective endOp)
{
- size_t const newJobThreshold = mtctx->dictSize + mtctx->targetSectionSize;
+ size_t const newJobThreshold = mtctx->prefixSize + mtctx->targetSectionSize;
unsigned forwardInputProgress = 0;
DEBUGLOG(5, "ZSTDMT_compressStream_generic ");
assert(output->pos <= output->size);
@@ -1160,7 +1160,7 @@ size_t ZSTDMT_compressStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, ZSTD_inBu
static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned endFrame)
{
- size_t const srcSize = mtctx->inBuff.filled - mtctx->dictSize;
+ size_t const srcSize = mtctx->inBuff.filled - mtctx->prefixSize;
DEBUGLOG(5, "ZSTDMT_flushStream_internal");
if ( ((srcSize > 0) || (endFrame && !mtctx->frameEnded))
From 16bd0fd4dfe72b0af6a1fa672c2ef90a6d0788d7 Mon Sep 17 00:00:00 2001
From: Nick Terrell
Date: Tue, 16 Jan 2018 15:23:39 -0800
Subject: [PATCH 059/255] Reduce size of ZSTD_CDict
Shaves 492,076 B off of the `ZSTD_CDict`.
The size of a `ZSTD_CDict` created from a 112,640 B dictionary is:
| Level | Before (B) | After (B) |
|-------|------------|-----------|
| 1 | 648,448 | 156,412 |
| 3 | 1,140,008 | 647,932 |
---
lib/compress/zstd_compress.c | 279 +++++++++++++++++++++++------------
1 file changed, 188 insertions(+), 91 deletions(-)
diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
index 49f73dc53..4ad5a6e61 100644
--- a/lib/compress/zstd_compress.c
+++ b/lib/compress/zstd_compress.c
@@ -49,7 +49,13 @@ struct ZSTD_CDict_s {
void* dictBuffer;
const void* dictContent;
size_t dictContentSize;
- ZSTD_CCtx* refContext;
+ void* workspace;
+ size_t workspaceSize;
+ ZSTD_matchState_t matchState;
+ ZSTD_compressedBlockState_t cBlockState;
+ ZSTD_compressionParameters cParams;
+ ZSTD_customMem customMem;
+ U32 dictID;
}; /* typedef'd to ZSTD_CDict within "zstd.h" */
ZSTD_CCtx* ZSTD_createCCtx(void)
@@ -799,7 +805,7 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
}
-static void ZSTD_resetBlockState(ZSTD_compressedBlockState_t* bs)
+static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
{
int i;
for (i = 0; i < ZSTD_REP_NUM; ++i)
@@ -846,13 +852,74 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
cctx->stage = ZSTDcs_init;
cctx->dictID = 0;
ZSTD_invalidateMatchState(&cctx->blockState.matchState);
- ZSTD_resetBlockState(cctx->blockState.prevCBlock);
+ ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock);
XXH64_reset(&cctx->xxhState, 0);
return 0;
}
typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
+static size_t ZSTD_sizeof_matchState(ZSTD_compressionParameters const* cParams, const U32 opt)
+{
+ size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ size_t const hSize = ((size_t)1) << cParams->hashLog;
+ U32 const hashLog3 = (cParams->searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog);
+ size_t const h3Size = ((size_t)1) << hashLog3;
+ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+ size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<strategy == ZSTD_btopt) ||
+ (cParams->strategy == ZSTD_btultra)))
+ ? optPotentialSpace
+ : 0;
+ DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
+ (U32)chainSize, (U32)hSize, (U32)h3Size);
+ return tableSpace + optSpace;
+}
+
+static void* ZSTD_reset_matchState(ZSTD_matchState_t* ms, void* ptr, ZSTD_compressionParameters const* cParams, ZSTD_compResetPolicy_e const crp, U32 const opt)
+{
+ size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ size_t const hSize = ((size_t)1) << cParams->hashLog;
+ U32 const hashLog3 = (cParams->searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog);
+ size_t const h3Size = ((size_t)1) << hashLog3;
+ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+
+ assert(((size_t)ptr & 3) == 0);
+
+ ms->nextSrc = NULL;
+ ms->base = NULL;
+ ms->dictBase = NULL;
+ ms->hashLog3 = hashLog3;
+ ZSTD_invalidateMatchState(ms);
+
+ /* opt parser space */
+ if (opt && ((cParams->strategy == ZSTD_btopt) | (cParams->strategy == ZSTD_btultra))) {
+ DEBUGLOG(4, "reserving optimal parser space");
+ ms->opt.litFreq = (U32*)ptr;
+ ms->opt.litLengthFreq = ms->opt.litFreq + (1<opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1);
+ ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1);
+ ptr = ms->opt.offCodeFreq + (MaxOff+1);
+ ms->opt.matchTable = (ZSTD_match_t*)ptr;
+ ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1;
+ ms->opt.priceTable = (ZSTD_optimal_t*)ptr;
+ ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1;
+ }
+
+ /* table Space */
+ DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
+ assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
+ if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
+ ms->hashTable = (U32*)(ptr);
+ ms->chainTable = ms->hashTable + hSize;
+ ms->hashTable3 = ms->chainTable + chainSize;
+ ptr = ms->hashTable3 + h3Size;
+
+ assert(((size_t)ptr & 3) == 0);
+ return ptr;
+}
+
/*! ZSTD_resetCCtx_internal() :
note : `params` are assumed fully validated at this stage */
static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
@@ -860,7 +927,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
ZSTD_compResetPolicy_e const crp,
ZSTD_buffered_policy_e const zbuff)
{
- ZSTD_matchState_t* const ms = &zc->blockState.matchState;
DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
(U32)pledgedSrcSize, params.cParams.windowLog);
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
@@ -891,35 +957,23 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
size_t const maxNbSeq = blockSize / divider;
size_t const tokenSpace = blockSize + 11*maxNbSeq;
- size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ?
- 0 : ((size_t)1 << params.cParams.chainLog);
- size_t const hSize = ((size_t)1) << params.cParams.hashLog;
- U32 const hashLog3 = (params.cParams.searchLength>3) ?
- 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
- size_t const h3Size = ((size_t)1) << hashLog3;
- size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
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, /* opt */ 1);
void* ptr;
/* Check if workSpace is large enough, alloc a new one if needed */
{ size_t const entropySpace = HUF_WORKSPACE_SIZE;
size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
- size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<>10), (U32)(tableSpace>>10), (U32)(bufferSpace>>10));
- DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u - windowSize: %u - blockSize: %u",
- (U32)chainSize, (U32)hSize, (U32)h3Size, (U32)windowSize, (U32)blockSize);
+ size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace +
+ matchStateSize + tokenSpace + bufferSpace;
+ DEBUGLOG(4, "Need %uKB workspace, including %uKB for match state, and %uKB for buffers",
+ (U32)(neededSpace>>10), (U32)(matchStateSize>>10), (U32)(bufferSpace>>10));
+ DEBUGLOG(4, "windowSize: %u - blockSize: %u", (U32)windowSize, (U32)blockSize);
if (zc->workSpaceSize < neededSpace) { /* too small : resize */
DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK",
@@ -958,32 +1012,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->stage = ZSTDcs_init;
zc->dictID = 0;
- ms->nextSrc = NULL;
- ms->base = NULL;
- ms->dictBase = NULL;
- ms->hashLog3 = hashLog3;
- ZSTD_invalidateMatchState(ms);
-
- ZSTD_resetBlockState(zc->blockState.prevCBlock);
+ ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
- /* opt parser space */
- if ((params.cParams.strategy == ZSTD_btopt) | (params.cParams.strategy == ZSTD_btultra)) {
- optState_t* opt = &zc->blockState.matchState.opt;
- DEBUGLOG(4, "reserving optimal parser space");
- assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
- opt->litFreq = (U32*)ptr;
- opt->litLengthFreq = opt->litFreq + (1<matchLengthFreq = opt->litLengthFreq + (MaxLL+1);
- opt->offCodeFreq = opt->matchLengthFreq + (MaxML+1);
- ptr = opt->offCodeFreq + (MaxOff+1);
- opt->matchTable = (ZSTD_match_t*)ptr;
- ptr = opt->matchTable + ZSTD_OPT_NUM+1;
- opt->priceTable = (ZSTD_optimal_t*)ptr;
- ptr = opt->priceTable + ZSTD_OPT_NUM+1;
- }
-
/* ldm hash table */
/* initialize bucketOffsets table later for pointer alignment */
if (params.ldmParams.enableLdm) {
@@ -994,14 +1026,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
ptr = zc->ldmState.hashTable + ldmHSize;
}
- /* table Space */
- DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
- if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
- assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
- ms->hashTable = (U32*)(ptr);
- ms->chainTable = ms->hashTable + hSize;
- ms->hashTable3 = ms->chainTable + chainSize;
- ptr = ms->hashTable3 + h3Size;
+ ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, ¶ms.cParams, crp, /* opt */ 1);
/* sequences storage */
zc->seqStore.sequencesStart = (seqDef*)ptr;
@@ -1042,6 +1067,54 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
assert(/* !extDict */ cctx->blockState.matchState.lowLimit == cctx->blockState.matchState.dictLimit);
}
+static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
+ const ZSTD_CDict* cdict,
+ unsigned windowLog,
+ ZSTD_frameParameters fParams,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ { ZSTD_CCtx_params params = cctx->requestedParams;
+ /* Copy only compression parameters related to tables. */
+ params.cParams = cdict->cParams;
+ if (windowLog) params.cParams.windowLog = windowLog;
+ params.fParams = fParams;
+ ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ ZSTDcrp_noMemset, zbuff);
+ }
+
+ /* copy tables */
+ { size_t const chainSize = (cctx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << cctx->appliedParams.cParams.chainLog);
+ size_t const hSize = (size_t)1 << cctx->appliedParams.cParams.hashLog;
+ size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3;
+ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+ assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
+ assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize);
+ assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */
+ assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize);
+ memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
+ }
+
+ /* copy dictionary offsets */
+ {
+ ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
+ ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
+ dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+ dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
+ dstMatchState->nextSrc = srcMatchState->nextSrc;
+ dstMatchState->base = srcMatchState->base;
+ dstMatchState->dictBase = srcMatchState->dictBase;
+ dstMatchState->dictLimit = srcMatchState->dictLimit;
+ dstMatchState->lowLimit = srcMatchState->lowLimit;
+ dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
+ }
+ cctx->dictID = cdict->dictID;
+
+ /* copy block state */
+ memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+
+ return 0;
+}
/*! ZSTD_copyCCtx_internal() :
* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
@@ -2172,22 +2245,26 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matc
}
/** ZSTD_compress_insertDictionary() :
-* @return : 0, or an error code */
-static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
+* @return : dictID, or an error code */
+static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms,
+ ZSTD_CCtx_params const* params,
const void* dict, size_t dictSize,
- ZSTD_dictMode_e dictMode)
+ ZSTD_dictMode_e dictMode,
+ void* workspace)
{
DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
if ((dict==NULL) || (dictSize<=8)) return 0;
+ ZSTD_reset_compressedBlockState(bs);
+
/* dict restricted modes */
if (dictMode==ZSTD_dm_rawContent)
- return ZSTD_loadDictionaryContent(&cctx->blockState.matchState, &cctx->appliedParams, dict, dictSize);
+ return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
if (dictMode == ZSTD_dm_auto) {
DEBUGLOG(4, "raw content dictionary detected");
- return ZSTD_loadDictionaryContent(&cctx->blockState.matchState, &cctx->appliedParams, dict, dictSize);
+ return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
}
if (dictMode == ZSTD_dm_fullDict)
return ERROR(dictionary_wrong);
@@ -2195,12 +2272,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
}
/* dict as full zstd dictionary */
- {
- size_t const dictID = ZSTD_loadZstdDictionary(cctx->blockState.prevCBlock, &cctx->blockState.matchState, &cctx->appliedParams, dict, dictSize, cctx->entropyWorkspace);
- if (ZSTD_isError(dictID)) return dictID;
- cctx->dictID = (U32)dictID;
- }
- return 0;
+ return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, workspace);
}
/*! ZSTD_compressBegin_internal() :
@@ -2219,14 +2291,21 @@ size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
if (cdict && cdict->dictContentSize>0) {
cctx->requestedParams = params;
- return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
- params.cParams.windowLog, params.fParams, pledgedSrcSize,
- zbuff);
+ return ZSTD_resetCCtx_usingCDict(cctx, cdict, params.cParams.windowLog,
+ params.fParams, pledgedSrcSize, zbuff);
}
CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
ZSTDcrp_continue, zbuff) );
- return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode);
+ {
+ size_t const dictID = ZSTD_compress_insertDictionary(
+ cctx->blockState.prevCBlock, &cctx->blockState.matchState,
+ ¶ms, dict, dictSize, dictMode, cctx->entropyWorkspace);
+ if (ZSTD_isError(dictID)) return dictID;
+ assert(dictID <= (size_t)(U32)-1);
+ cctx->dictID = (U32)dictID;
+ }
+ return 0;
}
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
@@ -2417,9 +2496,7 @@ size_t ZSTD_estimateCDictSize_advanced(
ZSTD_dictLoadMethod_e dictLoadMethod)
{
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
- DEBUGLOG(5, "CCtx estimate : %u",
- (U32)ZSTD_estimateCCtxSize_usingCParams(cParams));
- return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_usingCParams(cParams)
+ return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* opt */ 0)
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
}
@@ -2433,8 +2510,7 @@ size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
{
if (cdict==NULL) return 0; /* support sizeof on NULL */
DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict));
- DEBUGLOG(5, "ZSTD_sizeof_CCtx : %u", (U32)ZSTD_sizeof_CCtx(cdict->refContext));
- return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
+ return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
}
static size_t ZSTD_initCDict_internal(
@@ -2445,11 +2521,12 @@ static size_t ZSTD_initCDict_internal(
ZSTD_compressionParameters cParams)
{
DEBUGLOG(3, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
+ cdict->cParams = cParams;
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
cdict->dictBuffer = NULL;
cdict->dictContent = dictBuffer;
} else {
- void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
+ void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem);
cdict->dictBuffer = internalBuffer;
cdict->dictContent = internalBuffer;
if (!internalBuffer) return ERROR(memory_allocation);
@@ -2457,13 +2534,29 @@ static size_t ZSTD_initCDict_internal(
}
cdict->dictContentSize = dictSize;
- { ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams;
- cctxParams.cParams = cParams;
- CHECK_F( ZSTD_compressBegin_internal(cdict->refContext,
- cdict->dictContent, dictSize, dictMode,
- NULL,
- cctxParams, ZSTD_CONTENTSIZE_UNKNOWN,
- ZSTDb_not_buffered) );
+ {
+ void* const end = ZSTD_reset_matchState(
+ &cdict->matchState,
+ (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32,
+ &cParams, ZSTDcrp_continue, /* opt */ 0);
+ assert(end == (char*)cdict->workspace + cdict->workspaceSize);
+ (void)end;
+ }
+ {
+ ZSTD_CCtx_params params;
+ memset(¶ms, 0, sizeof(params));
+ params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
+ params.fParams.contentSizeFlag = 1;
+ params.cParams = cParams;
+ {
+ size_t const dictID = ZSTD_compress_insertDictionary(
+ &cdict->cBlockState, &cdict->matchState,¶ms,
+ cdict->dictContent, cdict->dictContentSize,
+ dictMode, cdict->workspace);
+ if (ZSTD_isError(dictID)) return dictID;
+ assert(dictID <= (size_t)(U32)-1);
+ cdict->dictID = (U32)dictID;
+ }
}
return 0;
@@ -2478,14 +2571,17 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
{ ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
- ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
+ size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* opt */ 0);
+ void* const workspace = ZSTD_malloc(workspaceSize, customMem);
- if (!cdict || !cctx) {
+ if (!cdict || !workspace) {
ZSTD_free(cdict, customMem);
- ZSTD_freeCCtx(cctx);
+ ZSTD_free(workspace, customMem);
return NULL;
}
- cdict->refContext = cctx;
+ cdict->customMem = customMem;
+ cdict->workspace = workspace;
+ cdict->workspaceSize = workspaceSize;
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
dictBuffer, dictSize,
dictLoadMethod, dictMode,
@@ -2517,8 +2613,8 @@ ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int
size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
{
if (cdict==NULL) return 0; /* support free on NULL */
- { ZSTD_customMem const cMem = cdict->refContext->customMem;
- ZSTD_freeCCtx(cdict->refContext);
+ { ZSTD_customMem const cMem = cdict->customMem;
+ ZSTD_free(cdict->workspace, cMem);
ZSTD_free(cdict->dictBuffer, cMem);
ZSTD_free(cdict, cMem);
return 0;
@@ -2544,9 +2640,9 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
ZSTD_dictMode_e dictMode,
ZSTD_compressionParameters cParams)
{
- size_t const cctxSize = ZSTD_estimateCCtxSize_usingCParams(cParams);
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* opt */ 0);
size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
- + cctxSize;
+ + HUF_WORKSPACE_SIZE + matchStateSize;
ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
void* ptr;
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
@@ -2561,7 +2657,8 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
} else {
ptr = cdict+1;
}
- cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize);
+ cdict->workspace = ptr;
+ cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize;
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
dict, dictSize,
@@ -2573,7 +2670,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
}
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) {
- return cdict->refContext->appliedParams.cParams;
+ return cdict->cParams;
}
/* ZSTD_compressBegin_usingCDict_advanced() :
From 58dd7de640e630f19d64a10fbecb52f2628e9750 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 17 Jan 2018 12:10:15 -0800
Subject: [PATCH 060/255] zstdmt: fixed an endless loop on allocation failure
this happened on 32-bits build when requiring a too large input buffer,
typically on wlog=29, creating jobs of 2 GB size.
also : zstd32 now compiles with multithread support enabled by default
(can be disabled with HAVE_THREAD=0)
---
lib/compress/zstdmt_compress.c | 21 +++++++++++++++------
programs/Makefile | 2 ++
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
index c65f3ea15..fe6ca52c2 100644
--- a/lib/compress/zstdmt_compress.c
+++ b/lib/compress/zstdmt_compress.c
@@ -150,7 +150,9 @@ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const
}
/** ZSTDMT_getBuffer() :
- * assumption : bufPool must be valid */
+ * assumption : bufPool must be valid
+ * @return : a buffer, with start pointer and size
+ * note: allocation may fail, in this case, start==NULL and size==0 */
static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
{
size_t const bSize = bufPool->bufferSize;
@@ -178,7 +180,11 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
void* const start = ZSTD_malloc(bSize, bufPool->cMem);
buffer.start = start; /* note : start can be NULL if malloc fails ! */
buffer.size = (start==NULL) ? 0 : bSize;
- DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
+ if (start==NULL) {
+ DEBUGLOG(5, "ZSTDMT_getBuffer: buffer allocation failure !!");
+ } else {
+ DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
+ }
return buffer;
}
}
@@ -1015,7 +1021,7 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned blockToFlush)
{
unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask;
- DEBUGLOG(5, "ZSTDMT_flushNextJob");
+ DEBUGLOG(5, "ZSTDMT_flushNextJob (blocking:%u)", blockToFlush);
if (zcs->doneJobID == zcs->nextJobID) return 0; /* all flushed ! */
ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
while (zcs->jobs[wJobID].jobCompleted==0) {
@@ -1112,10 +1118,13 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
/* fill input buffer */
if (input->size > input->pos) { /* support NULL input */
if (mtctx->inBuff.buffer.start == NULL) {
- mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); /* note : may fail, in which case, no forward input progress */
+ mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); /* note : allocation can fail, in which case, no forward input progress */
mtctx->inBuff.filled = 0;
- }
- if (mtctx->inBuff.buffer.start) {
+ if ( (mtctx->inBuff.buffer.start == NULL) /* allocation failure */
+ && (mtctx->doneJobID == mtctx->nextJobID) ) { /* and nothing to flush */
+ return ERROR(memory_allocation); /* no forward progress possible => output an error */
+ } }
+ if (mtctx->inBuff.buffer.start != NULL) {
size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled);
DEBUGLOG(5, "inBuff:%08X; inBuffSize=%u; ToCopy=%u", (U32)(size_t)mtctx->inBuff.buffer.start, (U32)mtctx->inBuffSize, (U32)toLoad);
memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, toLoad);
diff --git a/programs/Makefile b/programs/Makefile
index 51888d3ef..be666b4ef 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -157,6 +157,8 @@ endif
zstd-release: DEBUGFLAGS :=
zstd-release: zstd
+zstd32 : CPPFLAGS += $(THREAD_CPP)
+zstd32 : LDFLAGS += $(THREAD_LD)
zstd32 : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT)
zstd32 : $(ZSTDLIB_FILES) zstdcli.c fileio.c bench.c datagen.c dibio.c
ifneq (,$(filter Windows%,$(OS)))
From d14cc881b0f039d641cd3a7df33bad897320e654 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 17 Jan 2018 12:39:58 -0800
Subject: [PATCH 061/255] zstdmt : fixed very large window sizes
would create too large buffers,
since default job size == window size * 4.
This would crash on 32-bit systems.
Also : jobSize being a 32-bit unsigned, it cannot be >= 4 GB,
so the formula was failing for large window sizes >= 1 GB.
Fixed now : max job Size is 2 GB, whatever the window size.
---
lib/compress/zstdmt_compress.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
index fe6ca52c2..b3ccfe398 100644
--- a/lib/compress/zstdmt_compress.c
+++ b/lib/compress/zstdmt_compress.c
@@ -11,6 +11,7 @@
/* ====== Tuning parameters ====== */
#define ZSTDMT_NBTHREADS_MAX 200
+#define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (2 GB)) /* note : limited by `jobSize` type, which is `unsigned` */
#define ZSTDMT_OVERLAPLOG_DEFAULT 6
@@ -843,7 +844,14 @@ size_t ZSTDMT_initCStream_internal(
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
assert(zcs->cctxPool->totalCCtx == params.nbThreads);
- zcs->singleBlockingThread = pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN; /* do not trigger multi-threading when srcSize is too small */
+ zcs->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */
+ if (params.jobSize == 0) {
+ if (params.cParams.windowLog >= 29)
+ params.jobSize = ZSTDMT_JOBSIZE_MAX;
+ else
+ params.jobSize = 1 << (params.cParams.windowLog + 2);
+ }
+ if (params.jobSize > ZSTDMT_JOBSIZE_MAX) params.jobSize = ZSTDMT_JOBSIZE_MAX;
if (zcs->singleBlockingThread) {
ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(params);
@@ -879,7 +887,7 @@ size_t ZSTDMT_initCStream_internal(
assert(params.overlapSizeLog <= 9);
zcs->targetPrefixSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(zcs->targetPrefixSize>>10));
- zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2);
+ zcs->targetSectionSize = params.jobSize;
if (zcs->targetSectionSize < ZSTDMT_JOBSIZE_MIN) zcs->targetSectionSize = ZSTDMT_JOBSIZE_MIN;
if (zcs->targetSectionSize < zcs->targetPrefixSize) zcs->targetSectionSize = zcs->targetPrefixSize; /* job size must be >= overlap size */
DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(zcs->targetSectionSize>>10), params.jobSize);
From f3b8f90b6d7f6b2b00ab07577f77a4a4ec84dab7 Mon Sep 17 00:00:00 2001
From: Yann Collet
Date: Wed, 17 Jan 2018 14:08:48 -0800
Subject: [PATCH 062/255] changed initStatic?Dict() return type to const
ZSTD_?Dict*
ZSTD_create?Dict() is required to produce a ?Dict* return type
because `free()` does not accept a `const type*` argument.
If it wasn't for this restriction, I would have preferred to create a `const ?Dict*` object
to emphasize the fact that, once created, a dictionary never changes
(hence can be shared concurrently until the end of its lifetime).
There is no such limitation with initStatic?Dict() :
as stated in the doc, there is no corresponding free() function,
since `workspace` is provided, hence allocated, externally,
it can only be free() externally.
Which means, ZSTD_initStatic?Dict() can return a `const ZSTD_?Dict*` pointer.
Tested with `make all`, to catch initStatic's users,
which, incidentally, also updated zstd.h documentation.
---
doc/zstd_manual.html | 231 +++++++++++--------------------
lib/compress/zstd_compress.c | 3 +-
lib/decompress/zstd_decompress.c | 7 +-
lib/zstd.h | 18 +--
tests/fuzzer.c | 5 +-
5 files changed, 101 insertions(+), 163 deletions(-)
diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html
index da11ddb2a..a2e0966d7 100644
--- a/doc/zstd_manual.html
+++ b/doc/zstd_manual.html
@@ -11,7 +11,7 @@
Introduction
Version
Simple API
-Explicit memory management
+Explicit context
Simple dictionary API
Bulk processing dictionary API
Streaming
@@ -19,17 +19,16 @@
Streaming decompression - HowTo
START OF ADVANCED AND EXPERIMENTAL FUNCTIONS
Advanced types
-Custom memory allocation functions
-Frame size functions
-Context memory usage
-Advanced compression functions
-Advanced decompression functions
-Advanced streaming functions
-Buffer-less and synchronous inner streaming functions
-Buffer-less streaming compression (synchronous mode)
-Buffer-less streaming decompression (synchronous mode)
-New advanced API (experimental)
-Block level API
+Frame size functions
+Memory management
+Advanced compression functions
+Advanced decompression functions
+Advanced streaming functions
+Buffer-less and synchronous inner streaming functions
+Buffer-less streaming compression (synchronous mode)
+Buffer-less streaming decompression (synchronous mode)
+New advanced API (experimental)
+Block level API
Introduction
@@ -40,11 +39,11 @@
Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory.
Compression can be done in:
- a single step (described as Simple API)
- - a single step, reusing a context (described as Explicit memory management)
+ - a single step, reusing a context (described as Explicit context)
- unbounded multiple steps (described as Streaming compression)
The compression ratio achievable on small data can be highly improved using a dictionary in:
- a single step (described as Simple dictionary API)
- - a single step, reusing a dictionary (described as Fast dictionary API)
+ - a single step, reusing a dictionary (described as Bulk-processing dictionary API)
Advanced experimental functions can be accessed using #define ZSTD_STATIC_LINKING_ONLY before including zstd.h.
Advanced experimental APIs shall never be used with a dynamic library.
@@ -103,22 +102,20 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
- Both functions work the same way,
- but ZSTD_getDecompressedSize() blends
- "empty", "unknown" and "error" results in the same return value (0),
- while ZSTD_getFrameContentSize() distinguishes them.
-
- 'src' is the start of a zstd compressed frame.
- @return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise.
+ Both functions work the same way, but ZSTD_getDecompressedSize() blends
+ "empty", "unknown" and "error" results to the same return value (0),
+ while ZSTD_getFrameContentSize() gives them separate return values.
+ `src` is the start of a zstd compressed frame.
+ @return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise.
Helper functions
#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11)
/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */
-size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */
+size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */
unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */
int ZSTD_maxCLevel(void); /*!< maximum compression level available */
-Explicit memory management
+Explicit context
Compression context
When compressing many times,
it is recommended to allocate a context just once, and re-use it for each successive compression operation.
@@ -347,11 +344,18 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
ZSTD_frameParameters fParams;
} ZSTD_parameters;
-Custom memory allocation functions
-
-typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
+typedef enum {
+ ZSTD_dm_auto=0, /* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
+ ZSTD_dm_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
+ ZSTD_dm_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */
+} ZSTD_dictMode_e;
-Frame size functions
+typedef enum {
+ ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */
+ ZSTD_dlm_byRef, /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
+} ZSTD_dictLoadMethod_e;
+
+Frame size functions
size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
`src` should point to the start of a ZSTD encoded frame or skippable frame
@@ -390,7 +394,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
@return : size of the Frame Header
-Context memory usage
+Memory management
size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
@@ -399,7 +403,7 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);
size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
These functions give the current memory usage of selected object.
- Object memory usage can evolve when re-used multiple times.
+ Object memory usage can evolve when re-used.
size_t ZSTD_estimateCCtxSize(int compressionLevel);
@@ -413,7 +417,7 @@ size_t ZSTD_estimateDCtxSize(void);
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_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
- Note : CCtx estimation is only correct for single-threaded compression
+ Note : CCtx size estimation is only correct for single-threaded compression.
size_t ZSTD_estimateCStreamSize(int compressionLevel);
@@ -426,7 +430,7 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
- Note : CStream estimation is only correct for single-threaded compression.
+ Note : CStream size estimation is only correct for single-threaded compression.
ZSTD_DStream memory budget depends on window Size.
This information can be passed manually, using ZSTD_estimateDStreamSize,
or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
@@ -435,83 +439,59 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
In this case, get total size by adding ZSTD_estimate?DictSize
-typedef enum {
- ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */
- ZSTD_dlm_byRef, /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
-} ZSTD_dictLoadMethod_e;
-
size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
- ZSTD_estimateCStreamSize_advanced_usingCParams() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced().
- Note : dictionary created by reference using ZSTD_dlm_byRef are smaller
+ 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.
-Advanced compression functions
-
-ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
- Create a ZSTD compression context using external alloc and free functions
-
-
-ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
- workspace: The memory area to emplace the context into.
- Provided pointer must 8-bytes aligned.
- It must outlive context usage.
- workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize()
- to determine how large workspace must be to support scenario.
- @return : pointer to ZSTD_CCtx* (same address as workspace, but different type),
- or NULL if error (typically size too small)
- Note : zstd will never resize nor malloc() when using a static cctx.
- If it needs more memory than available, it will simply error out.
+
ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
+ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */
+ Initialize an object using a pre-allocated fixed-size buffer.
+ workspace: The memory area to emplace the object into.
+ Provided pointer *must be 8-bytes aligned*.
+ Buffer must outlive object.
+ workspaceSize: Use ZSTD_estimate*Size() to determine
+ how large workspace must be to support target scenario.
+ @return : pointer to object (same address as workspace, just different type),
+ or NULL if error (size too small, incorrect alignment, etc.)
+ Note : zstd will never resize nor malloc() when using a static buffer.
+ If the object requires more memory than available,
+ zstd will just error out (typically ZSTD_error_memory_allocation).
Note 2 : there is no corresponding "free" function.
- Since workspace was allocated externally, it must be freed externally too.
- Limitation 1 : currently not compatible with internal CDict creation, such as
- ZSTD_CCtx_loadDictionary() or ZSTD_initCStream_usingDict().
- Limitation 2 : currently not compatible with multi-threading
+ Since workspace is allocated externally, it must be freed externally too.
+ Note 3 : cParams : use ZSTD_getCParams() to convert a compression level
+ into its associated cParams.
+ Limitation 1 : currently not compatible with internal dictionary creation, triggered by
+ ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict().
+ Limitation 2 : static cctx currently not compatible with multi-threading.
+ Limitation 3 : static dctx is incompatible with legacy support.
+ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */
+
+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 */
+ These prototypes make it possible to pass your own allocation/free functions.
+ ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below.
+ All allocation/free operations will be completed using these custom variants instead of regular ones.
+
+
+
+Advanced compression functions
+
ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
Create a digested dictionary for compression
Dictionary content is simply referenced, and therefore stays in dictBuffer.
It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict
-typedef enum { ZSTD_dm_auto=0, /* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
- ZSTD_dm_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
- ZSTD_dm_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */
-} ZSTD_dictMode_e;
-
-ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictMode_e dictMode,
- ZSTD_compressionParameters cParams,
- ZSTD_customMem customMem);
- Create a ZSTD_CDict using external alloc and free, and customized compression parameters
-
-
-ZSTD_CDict* ZSTD_initStaticCDict(
- void* workspace, size_t workspaceSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode,
- ZSTD_compressionParameters cParams);
- Generate a digested dictionary in provided memory area.
- workspace: The memory area to emplace the dictionary into.
- Provided pointer must 8-bytes aligned.
- It must outlive dictionary usage.
- workspaceSize: Use ZSTD_estimateCDictSize()
- to determine how large workspace must be.
- cParams : use ZSTD_getCParams() to transform a compression level
- into its relevants cParams.
- @return : pointer to ZSTD_CDict* (same address as workspace, but different type),
- or NULL if error (typically, size too small).
- Note : there is no corresponding "free" function.
- Since workspace was allocated externally, it must be freed externally.
-
-
-
ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
@return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
`estimatedSrcSize` value is optional, select 0 if not known
@@ -546,7 +526,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters
-Advanced decompression functions
+Advanced decompression functions
unsigned ZSTD_isFrame(const void* buffer, size_t size);
Tells if the content of `buffer` starts with a valid Frame Identifier.
@@ -555,28 +535,6 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
Note 3 : Skippable Frame Identifiers are considered valid.
-ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
- Create a ZSTD decompression context using external alloc and free functions
-
-
-ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize);
- workspace: The memory area to emplace the context into.
- Provided pointer must 8-bytes aligned.
- It must outlive context usage.
- workspaceSize: Use ZSTD_estimateDCtxSize() or ZSTD_estimateDStreamSize()
- to determine how large workspace must be to support scenario.
- @return : pointer to ZSTD_DCtx* (same address as workspace, but different type),
- or NULL if error (typically size too small)
- Note : zstd will never resize nor malloc() when using a static dctx.
- If it needs more memory than available, it will simply error out.
- Note 2 : static dctx is incompatible with legacy support
- Note 3 : there is no corresponding "free" function.
- Since workspace was allocated externally, it must be freed externally.
- Limitation : currently not compatible with internal DDict creation,
- such as ZSTD_initDStream_usingDict().
-
-
-
ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
Create a digested dictionary, ready to start decompression operation without startup delay.
Dictionary content is referenced, and therefore stays in dictBuffer.
@@ -584,27 +542,6 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
it must remain read accessible throughout the lifetime of DDict
-ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_customMem customMem);
- Create a ZSTD_DDict using external alloc and free, optionally by reference
-
-
-ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod);
- Generate a digested dictionary in provided memory area.
- workspace: The memory area to emplace the dictionary into.
- Provided pointer must 8-bytes aligned.
- It must outlive dictionary usage.
- workspaceSize: Use ZSTD_estimateDDictSize()
- to determine how large workspace must be.
- @return : pointer to ZSTD_DDict*, or NULL if error (size too small)
- Note : there is no corresponding "free" function.
- Since workspace was allocated externally, it must be freed externally.
-
-
-
unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
Provides the dictID stored within dictionary.
if @return == 0, the dictionary is not conformant with Zstandard specification.
@@ -629,11 +566,9 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code.
-Advanced streaming functions
+Advanced streaming functions
-Advanced Streaming compression functions
ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
-ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize);
/**< same as ZSTD_initStaticCCtx() */
-size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< 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. */
+Advanced Streaming compression functions
size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize);
/**< 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. */
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */
@@ -651,22 +586,20 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict*
@return : 0, or an error code (which can be tested using ZSTD_isError())
-Advanced Streaming decompression functions
ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
-ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize);
/**< same as ZSTD_initStaticDCtx() */
-typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
+Advanced Streaming decompression functions
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); /* obsolete : this API will be removed in a future version */
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); /**< note : ddict is referenced, it must outlive decompression session */
size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */
-Buffer-less and synchronous inner streaming functions
+Buffer-less and synchronous inner streaming functions
This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
But it's also a complex one, with several restrictions, documented below.
Prefer normal streaming API for an easier experience.
-Buffer-less streaming compression (synchronous mode)
+Buffer-less streaming compression (synchronous mode)
A ZSTD_CCtx object is required to track streaming operations.
Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
ZSTD_CCtx object can be re-used multiple times within successive compression operations.
@@ -702,7 +635,7 @@ size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
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 */
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 */
-Buffer-less streaming decompression (synchronous mode)
+Buffer-less streaming decompression (synchronous mode)
A ZSTD_DCtx object is required to track streaming operations.
Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
A ZSTD_DCtx object can be re-used multiple times.
@@ -788,7 +721,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
-New advanced API (experimental)
+New advanced API (experimental)
typedef enum {
/* Question : should we have a format ZSTD_f_auto ?
@@ -1007,7 +940,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
-void ZSTD_CCtx_reset(ZSTD_CCtx* cctx); /* Not ready yet ! */
+void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);
Return a CCtx to clean state.
Useful after an error, or to interrupt an ongoing compression job and start a new one.
Any internal data not yet flushed is cancelled.
@@ -1178,7 +1111,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
-Block level API
+Block level API
Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
@@ -1206,7 +1139,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
Raw zstd block functions
size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize);
/**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression */
+size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */