Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
255597502c | ||
|
|
99e8063d40 | ||
|
|
268cc2a516 | ||
|
|
11a3e92883 | ||
|
|
eba13dba2e | ||
|
|
bffb4b46a1 | ||
|
|
2dc31dc842 | ||
|
|
343f60f2b2 | ||
|
|
0ef4d097db | ||
|
|
21eb26d664 | ||
|
|
2960f74c29 | ||
|
|
4d753b0ca8 | ||
|
|
a2d571de78 | ||
|
|
ad15c1b724 | ||
|
|
52ca7c6c56 | ||
|
|
6a8d69c427 | ||
|
|
f991897bb1 | ||
|
|
6356b007fb | ||
|
|
d9b2cbf650 | ||
|
|
956a3b7006 | ||
|
|
2489e71ff1 | ||
|
|
fa294b8590 | ||
|
|
308f405c73 | ||
|
|
b42ffb91f7 | ||
|
|
17e937bcd0 | ||
|
|
a59dac279a | ||
|
|
a75104d8f8 | ||
|
|
97bc1aec47 | ||
|
|
b94d08c566 | ||
|
|
b1f898ec82 | ||
|
|
929608146a | ||
|
|
1a83bcbd93 | ||
|
|
6bb6e6178a | ||
|
|
d6c6b62958 | ||
|
|
6aee5417a2 | ||
|
|
184e1c8b8c | ||
|
|
01082a39bd | ||
|
|
29b021f9a0 | ||
|
|
1340cafbeb | ||
|
|
f15e2fd55e | ||
|
|
ad344033df | ||
|
|
b7b80e1569 | ||
|
|
93b8262c02 | ||
|
|
153bc1c004 | ||
|
|
57e6b98eb1 | ||
|
|
1be8660eca | ||
|
|
a99c4a3621 | ||
|
|
87b0cf05bd | ||
|
|
1292a738d8 | ||
|
|
321de5682c | ||
|
|
0034c759b0 | ||
|
|
453d487807 | ||
|
|
d1bf609abf | ||
|
|
e0cb8d19c6 | ||
|
|
878728dc26 | ||
|
|
e1c52faace | ||
|
|
b18cb7e0b7 | ||
|
|
6cda8c932c | ||
|
|
2af41592ea | ||
|
|
0dadb6b70d | ||
|
|
569b8ba4d9 | ||
|
|
a3b76a77ef | ||
|
|
6873fec658 | ||
|
|
31b54b6eea | ||
|
|
136b9e2392 | ||
|
|
353117c5d7 | ||
|
|
451357f37f | ||
|
|
2ed5af0766 | ||
|
|
d19f803a3b | ||
|
|
24d9edbdd8 | ||
|
|
4b92574feb | ||
|
|
94c77710a9 | ||
|
|
9e6ba88363 | ||
|
|
5ad6cc4780 | ||
|
|
a7b532a347 | ||
|
|
b06db3b3c5 | ||
|
|
e5ddfaede8 | ||
|
|
aa4dbd09a1 | ||
|
|
c8b3d389fd | ||
|
|
6f4d0778a5 | ||
|
|
dc6a5471eb | ||
|
|
9f6b7b6ef4 | ||
|
|
2253d01b27 | ||
|
|
9618c0c804 | ||
|
|
f2562c02e4 | ||
|
|
d932fb621f | ||
|
|
90c598f089 | ||
|
|
7616200eaf | ||
|
|
ec0959e701 | ||
|
|
d796a78c92 | ||
|
|
4af1fafeb8 | ||
|
|
cbc71e40f6 | ||
|
|
5373e44ba7 | ||
|
|
97816400ca | ||
|
|
355cb645bf | ||
|
|
38cbcb5f1a | ||
|
|
f15a17e19f | ||
|
|
192542b63c | ||
|
|
55bb8bb85f | ||
|
|
a271399c97 | ||
|
|
1908c92c46 | ||
|
|
49ce7a0edf | ||
|
|
a909c293c6 | ||
|
|
a9a6dcba63 | ||
|
|
33fb966e56 | ||
|
|
4c5cbac179 | ||
|
|
50f763ec44 | ||
|
|
a95a88af57 | ||
|
|
bd7bb94361 | ||
|
|
430a2fec19 | ||
|
|
6e388eeac2 | ||
|
|
530eeb41a7 | ||
|
|
2f70fbf2a3 | ||
|
|
2291b85a1e | ||
|
|
a57d43d4d4 | ||
|
|
f24566b597 | ||
|
|
6a9b41b731 | ||
|
|
a146ee04ae | ||
|
|
facc09aa03 | ||
|
|
e0ba7ccdec | ||
|
|
c6351021e4 | ||
|
|
fe321f9e2a | ||
|
|
89a2ebb971 | ||
|
|
cdb1f1433e | ||
|
|
a166eae1ba | ||
|
|
17626ba56e | ||
|
|
8c6dbf490b | ||
|
|
5414b8ea01 | ||
|
|
e916b9090e | ||
|
|
51169575a8 | ||
|
|
0379d83951 | ||
|
|
7e103cdaf5 | ||
|
|
db147ea620 | ||
|
|
51262bd832 | ||
|
|
06ca9c7d7c | ||
|
|
9a91afe6ef | ||
|
|
7bd7a3ad43 | ||
|
|
c0393a538f | ||
|
|
a70f7e10fa | ||
|
|
03e7e14192 | ||
|
|
41bd10446e | ||
|
|
cb789d2df8 | ||
|
|
99afe72576 | ||
|
|
b91ddf0ae6 | ||
|
|
403741130d | ||
|
|
d02b44cf55 | ||
|
|
3ba307b240 | ||
|
|
45b09e7625 | ||
|
|
b01552a07a | ||
|
|
606374269c | ||
|
|
564cb1b640 | ||
|
|
ccb7184a76 | ||
|
|
0a0e64c641 | ||
|
|
2c4d3f339a | ||
|
|
33a3f18848 | ||
|
|
d18d43aaf9 | ||
|
|
89741653ab | ||
|
|
6cdf690441 | ||
|
|
6b88d592fd | ||
|
|
7e5e226cbf | ||
|
|
50bc2ce95e | ||
|
|
653383f74a | ||
|
|
7e2bf4ebad | ||
|
|
af866b3a58 | ||
|
|
4fb071ec3c | ||
|
|
0fd4df6ed3 | ||
|
|
4d6632c8f3 | ||
|
|
6e481504ee | ||
|
|
9c5a8040a9 | ||
|
|
364ce19463 | ||
|
|
993ffffba3 | ||
|
|
25d00d10fc | ||
|
|
010ba5f71f | ||
|
|
3538a535bf | ||
|
|
d3364aa39e | ||
|
|
6e128d3534 | ||
|
|
70163bf0d3 | ||
|
|
7117ea8bec | ||
|
|
b58f01537e | ||
|
|
4319132312 | ||
|
|
5ec97fff17 | ||
|
|
5cb1144872 | ||
|
|
9716250197 | ||
|
|
9b184359e2 | ||
|
|
2524cbd847 | ||
|
|
71c07966bb | ||
|
|
821efa466e | ||
|
|
5f7495371e | ||
|
|
992c2370f6 | ||
|
|
9945e60ac4 | ||
|
|
04a3f85ce7 | ||
|
|
4e3db17cab | ||
|
|
75689838e4 | ||
|
|
af48f0b62b | ||
|
|
426944c3e3 | ||
|
|
64ee732694 | ||
|
|
c72091556b | ||
|
|
4beaeaace5 | ||
|
|
6bfe50ad48 | ||
|
|
1850597eaa | ||
|
|
ab75df21ed | ||
|
|
421a2716d8 | ||
|
|
95424409ea | ||
|
|
cc61a3694a | ||
|
|
d6e841d609 | ||
|
|
de68c2ff10 | ||
|
|
0170cf9a7a | ||
|
|
94efb1749d | ||
|
|
5188749e1c | ||
|
|
4b525af53a | ||
|
|
90eca318a7 | ||
|
|
1291d9d7cf | ||
|
|
549d26ae71 | ||
|
|
6c492af284 | ||
|
|
209df52ba2 | ||
|
|
4b6a94f0cc | ||
|
|
60fa90b6c0 | ||
|
|
2bfc79ab8d | ||
|
|
f25351e23e | ||
|
|
48acaddff9 | ||
|
|
727bb7f090 | ||
|
|
9c8c69e41a | ||
|
|
ab3346af07 | ||
|
|
823a28a1f4 | ||
|
|
b173b8d8da | ||
|
|
a2ba629971 | ||
|
|
2cb0740b6b | ||
|
|
6b57387728 | ||
|
|
d13a75c969 | ||
|
|
9f8ed23b5b | ||
|
|
ba0cd8cf78 | ||
|
|
caf9e96dc3 | ||
|
|
9c40ae7ff1 | ||
|
|
77e36273de | ||
|
|
27c5853c42 | ||
|
|
0d426f6b83 | ||
|
|
79b6e28b0a | ||
|
|
d2b62b6fa5 | ||
|
|
fca13c6855 | ||
|
|
8e128eaf05 | ||
|
|
777d3c1559 | ||
|
|
a1d4041e69 | ||
|
|
1272d8e760 | ||
|
|
0fa96a6b78 | ||
|
|
50aea2f293 | ||
|
|
4f7c896113 | ||
|
|
5f349b129c | ||
|
|
c1cc57f270 | ||
|
|
de5e38a7a6 | ||
|
|
ebd955e26a | ||
|
|
2054eaf840 | ||
|
|
6711396d97 | ||
|
|
a7ef3a219c | ||
|
|
3ad7d4951c | ||
|
|
940634a610 | ||
|
|
dc69623453 | ||
|
|
cb5eba8e20 | ||
|
|
70f81d6030 | ||
|
|
d19dc1903c | ||
|
|
31f45c98f8 | ||
|
|
6f7280fb33 | ||
|
|
997e4d0ccd | ||
|
|
4f43ef731d | ||
|
|
ef97d5a287 | ||
|
|
b6ab232f2d | ||
|
|
6f3b54dc8b | ||
|
|
9d96761520 | ||
|
|
4d08ba8b77 | ||
|
|
c7190c69cc | ||
|
|
1b5d80d633 | ||
|
|
aa79c18e3f | ||
|
|
394eec697b | ||
|
|
592ce5a042 | ||
|
|
f3b8f90b6d | ||
|
|
5cde87ca4a | ||
|
|
b86865323a | ||
|
|
fbb703ea5e | ||
|
|
d14cc881b0 | ||
|
|
58dd7de640 | ||
|
|
16bd0fd4df | ||
|
|
cb57c107ff | ||
|
|
22303da601 | ||
|
|
3e1e57db27 | ||
|
|
10c213761a | ||
|
|
1dba98d563 | ||
|
|
6025465e42 | ||
|
|
2e23333094 | ||
|
|
8e83c5c910 | ||
|
|
f0d703243f | ||
|
|
0bc7a75468 | ||
|
|
f4e58455f6 | ||
|
|
19cb37f837 | ||
|
|
aae267a2e1 | ||
|
|
887cd4e35e | ||
|
|
a187486e3c | ||
|
|
403e2db139 | ||
|
|
815eddeda4 | ||
|
|
f6e17b8c7a | ||
|
|
4792ac6689 | ||
|
|
99a0a8bbd2 | ||
|
|
f8a05932b9 | ||
|
|
9477f6529d | ||
|
|
58ecf13e02 | ||
|
|
9a211d1f05 | ||
|
|
863b2f8db4 | ||
|
|
9d65a5c316 | ||
|
|
4b7c4e5f41 | ||
|
|
b610b777d3 | ||
|
|
cacf47cbee | ||
|
|
04c00f9388 | ||
|
|
b9a14900ff | ||
|
|
1d623e60a1 | ||
|
|
752bae4a48 | ||
|
|
e8093dde09 | ||
|
|
218e9fe0fc | ||
|
|
55cdbdb465 | ||
|
|
2103a62b3d | ||
|
|
ff795580f2 | ||
|
|
0e88f6e97b | ||
|
|
06995775b0 | ||
|
|
1edf33764e | ||
|
|
292eeb672f | ||
|
|
3ea156368c | ||
|
|
b17fb488b0 | ||
|
|
76321d6bbc | ||
|
|
658d6b8588 | ||
|
|
a927fae2a1 | ||
|
|
3d578eef0c | ||
|
|
752880ffed | ||
|
|
ed9611dc62 | ||
|
|
282ad05e0a | ||
|
|
fd63140e1c | ||
|
|
dce386f658 | ||
|
|
f51e861665 | ||
|
|
8adebbd0f8 | ||
|
|
e0596715dc | ||
|
|
2eff217136 | ||
|
|
b6887b6d43 | ||
|
|
00db4dbbb3 | ||
|
|
76e802cde6 | ||
|
|
f597f55675 | ||
|
|
a68b76afef | ||
|
|
706b5430bd | ||
|
|
eb52e2f45e | ||
|
|
ea41b580eb | ||
|
|
77fc611abe | ||
|
|
d228b6b0d0 | ||
|
|
02f64ef955 | ||
|
|
4c7f137bd2 | ||
|
|
64482c2c97 | ||
|
|
f36da5b4d9 | ||
|
|
ffc335bccf | ||
|
|
5235d8d6ba | ||
|
|
63aebdf9ea | ||
|
|
2126ca8a5f | ||
|
|
c707c6e9f2 | ||
|
|
6ff43c0051 | ||
|
|
d55aea3c3b | ||
|
|
b7d0d96ac6 | ||
|
|
914d983879 | ||
|
|
daffe435c0 |
@@ -6,14 +6,15 @@ dist: trusty
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# Ubuntu 14.04
|
# Ubuntu 14.04
|
||||||
- env: Cmd="make cxxtest && make clean && make gnu90build && make clean && make cmakebuild && make clean && make travis-install"
|
|
||||||
|
|
||||||
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-test'
|
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-test'
|
||||||
- env: Cmd='make gcc6install libc6install && CC=gcc-6 make clean uasan-test32'
|
- env: Cmd='make gcc6install libc6install && CC=gcc-6 make clean uasan-test32'
|
||||||
|
- env: Cmd='make gcc6install libc6install && CC=gcc-6 make clean uasan-test-zstd32'
|
||||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-test'
|
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-test'
|
||||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean tsan-test-zstream'
|
- env: Cmd='make clang38install && CC=clang-3.8 make clean tsan-test-zstream'
|
||||||
- env: Cmd='make valgrindinstall && make -C tests clean valgrindTest'
|
- env: Cmd='make valgrindinstall && make -C tests clean valgrindTest'
|
||||||
|
|
||||||
|
- env: Cmd="make cxxtest && make clean && make gnu90build && make clean && make cmakebuild && make clean && make travis-install"
|
||||||
|
|
||||||
- env: Cmd='make arminstall && make armtest'
|
- env: Cmd='make arminstall && make armtest'
|
||||||
- env: Cmd='make arminstall && make aarch64test'
|
- env: Cmd='make arminstall && make aarch64test'
|
||||||
- env: Cmd='make ppcinstall && make ppctest'
|
- env: Cmd='make ppcinstall && make ppctest'
|
||||||
@@ -38,6 +39,10 @@ before_install:
|
|||||||
install:
|
install:
|
||||||
- if [ `uname` = "Darwin" ]; then brew install xz; fi
|
- if [ `uname` = "Darwin" ]; then brew install xz; fi
|
||||||
|
|
||||||
|
# tag-specific test
|
||||||
|
- if: tag =~ ^v[0-9]\.[0-9]
|
||||||
|
env: Cmd='make -C tests checkTag && tests/checkTag $TRAVIS_BRANCH'
|
||||||
|
|
||||||
git:
|
git:
|
||||||
depth: 1
|
depth: 1
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ endif
|
|||||||
default: lib-release zstd-release
|
default: lib-release zstd-release
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: | allmost examples manual
|
all: | allmost examples manual contrib
|
||||||
|
|
||||||
.PHONY: allmost
|
.PHONY: allmost
|
||||||
allmost: allzstd
|
allmost: allzstd
|
||||||
@@ -72,14 +72,18 @@ zstdmt:
|
|||||||
zlibwrapper:
|
zlibwrapper:
|
||||||
$(MAKE) -C $(ZWRAPDIR) test
|
$(MAKE) -C $(ZWRAPDIR) test
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
$(MAKE) -C $(PRGDIR) allVariants MOREFLAGS+="-g -DZSTD_DEBUG=1"
|
||||||
|
$(MAKE) -C $(TESTDIR) $@
|
||||||
|
|
||||||
|
.PHONY: shortest
|
||||||
|
shortest:
|
||||||
|
$(MAKE) -C $(TESTDIR) $@
|
||||||
|
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: shortest
|
check: shortest
|
||||||
|
|
||||||
.PHONY: test shortest
|
|
||||||
test shortest:
|
|
||||||
$(MAKE) -C $(PRGDIR) allVariants MOREFLAGS="-g -DZSTD_DEBUG=1"
|
|
||||||
$(MAKE) -C $(TESTDIR) $@
|
|
||||||
|
|
||||||
.PHONY: examples
|
.PHONY: examples
|
||||||
examples:
|
examples:
|
||||||
CPPFLAGS=-I../lib LDFLAGS=-L../lib $(MAKE) -C examples/ all
|
CPPFLAGS=-I../lib LDFLAGS=-L../lib $(MAKE) -C examples/ all
|
||||||
@@ -88,6 +92,12 @@ examples:
|
|||||||
manual:
|
manual:
|
||||||
$(MAKE) -C contrib/gen_html $@
|
$(MAKE) -C contrib/gen_html $@
|
||||||
|
|
||||||
|
.PHONY: contrib
|
||||||
|
contrib: lib
|
||||||
|
$(MAKE) -C contrib/pzstd all
|
||||||
|
$(MAKE) -C contrib/seekable_format/examples all
|
||||||
|
$(MAKE) -C contrib/adaptive-compression all
|
||||||
|
|
||||||
.PHONY: cleanTabs
|
.PHONY: cleanTabs
|
||||||
cleanTabs:
|
cleanTabs:
|
||||||
cd contrib; ./cleanTabs
|
cd contrib; ./cleanTabs
|
||||||
@@ -100,6 +110,9 @@ clean:
|
|||||||
@$(MAKE) -C $(ZWRAPDIR) $@ > $(VOID)
|
@$(MAKE) -C $(ZWRAPDIR) $@ > $(VOID)
|
||||||
@$(MAKE) -C examples/ $@ > $(VOID)
|
@$(MAKE) -C examples/ $@ > $(VOID)
|
||||||
@$(MAKE) -C contrib/gen_html $@ > $(VOID)
|
@$(MAKE) -C contrib/gen_html $@ > $(VOID)
|
||||||
|
@$(MAKE) -C contrib/pzstd $@ > $(VOID)
|
||||||
|
@$(MAKE) -C contrib/seekable_format/examples $@ > $(VOID)
|
||||||
|
@$(MAKE) -C contrib/adaptive-compression $@ > $(VOID)
|
||||||
@$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
|
@$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
|
||||||
@$(RM) -r lz4
|
@$(RM) -r lz4
|
||||||
@echo Cleaning completed
|
@echo Cleaning completed
|
||||||
@@ -231,31 +244,31 @@ msanregressiontest:
|
|||||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303
|
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303
|
||||||
|
|
||||||
usan: clean
|
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
|
asan: clean
|
||||||
$(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=address"
|
$(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=address -Werror"
|
||||||
|
|
||||||
asan-%: clean
|
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
|
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
|
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
|
asan32: clean
|
||||||
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address"
|
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address"
|
||||||
|
|
||||||
uasan: clean
|
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
|
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
|
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:
|
apt-install:
|
||||||
sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install $(APT_PACKAGES)
|
sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install $(APT_PACKAGES)
|
||||||
@@ -279,6 +292,9 @@ libc6install:
|
|||||||
gcc6install: apt-add-repo
|
gcc6install: apt-add-repo
|
||||||
APT_PACKAGES="libc6-dev-i386 gcc-multilib gcc-6 gcc-6-multilib" $(MAKE) apt-install
|
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
|
gpp6install: apt-add-repo
|
||||||
APT_PACKAGES="libc6-dev-i386 g++-multilib gcc-6 g++-6 g++-6-multilib" $(MAKE) apt-install
|
APT_PACKAGES="libc6-dev-i386 g++-multilib gcc-6 g++-6 g++-6-multilib" $(MAKE) apt-install
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
|
v1.3.4
|
||||||
|
perf: faster speed (especially decoding speed) on recent cpus (haswell+)
|
||||||
|
perf: much better performance associating --long with multi-threading, by @terrelln
|
||||||
|
perf: better compression at levels 13-15
|
||||||
|
cli : asynchronous compression by default, for faster experience (use --single-thread for former behavior)
|
||||||
|
cli : smoother status report in multi-threading mode
|
||||||
|
cli : added command --fast=#, for faster compression modes
|
||||||
|
cli : fix crash when not overwriting existing files, by Pádraig Brady (@pixelb)
|
||||||
|
api : `nbThreads` becomes `nbWorkers` : 1 triggers asynchronous mode
|
||||||
|
api : compression levels can be negative, for even more speed
|
||||||
|
api : ZSTD_getFrameProgression() : get precise progress status of ZSTDMT anytime
|
||||||
|
api : ZSTDMT can accept new compression parameters during compression
|
||||||
|
api : implemented all advanced dictionary decompression prototypes
|
||||||
|
build: improved meson recipe, by Shawn Landden (@shawnl)
|
||||||
|
build: VS2017 scripts, by @HaydnTrigg
|
||||||
|
misc: all /contrib projects fixed
|
||||||
|
misc: added /contrib/docker script by @gyscos
|
||||||
|
|
||||||
v1.3.3
|
v1.3.3
|
||||||
perf: faster zstd_opt strategy (levels 17-19)
|
perf: faster zstd_opt strategy (levels 16-19)
|
||||||
fix : bug #944 : multithreading with shared ditionary and large data, reported by @gsliepen
|
fix : bug #944 : multithreading with shared ditionary and large data, reported by @gsliepen
|
||||||
cli : fix : content size written in header by default
|
cli : fix : content size written in header by default
|
||||||
cli : fix : improved LZ4 format support, by @felixhandte
|
cli : fix : improved LZ4 format support, by @felixhandte
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<p align="center"><img src="https://raw.githubusercontent.com/facebook/zstd/readme/doc/images/zstd_logo86.png" alt="Zstandard"></p>
|
<p align="center"><img src="https://raw.githubusercontent.com/facebook/zstd/dev/doc/images/zstd_logo86.png" alt="Zstandard"></p>
|
||||||
|
|
||||||
__Zstandard__, or `zstd` as short version, is a fast lossless compression algorithm,
|
__Zstandard__, or `zstd` as short version, is a fast lossless compression algorithm,
|
||||||
targeting real-time compression scenarios at zlib-level and better compression ratios.
|
targeting real-time compression scenarios at zlib-level and better compression ratios.
|
||||||
@@ -21,24 +21,25 @@ Development branch status : [![Build Status][travisDevBadge]][travisLink] [![B
|
|||||||
### Benchmarks
|
### Benchmarks
|
||||||
|
|
||||||
For reference, several fast compression algorithms were tested and compared
|
For reference, several fast compression algorithms were tested and compared
|
||||||
on a server running Linux Debian (`Linux version 4.8.0-1-amd64`),
|
on a server running Linux Debian (`Linux version 4.14.0-3-amd64`),
|
||||||
with a Core i7-6700K CPU @ 4.0GHz,
|
with a Core i7-6700K CPU @ 4.0GHz,
|
||||||
using [lzbench], an open-source in-memory benchmark by @inikep
|
using [lzbench], an open-source in-memory benchmark by @inikep
|
||||||
compiled with GCC 6.3.0,
|
compiled with [gcc] 7.3.0,
|
||||||
on the [Silesia compression corpus].
|
on the [Silesia compression corpus].
|
||||||
|
|
||||||
[lzbench]: https://github.com/inikep/lzbench
|
[lzbench]: https://github.com/inikep/lzbench
|
||||||
[Silesia compression corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
|
[Silesia compression corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
|
||||||
|
[gcc]: https://gcc.gnu.org/
|
||||||
|
|
||||||
| Compressor name | Ratio | Compression| Decompress.|
|
| Compressor name | Ratio | Compression| Decompress.|
|
||||||
| --------------- | ------| -----------| ---------- |
|
| --------------- | ------| -----------| ---------- |
|
||||||
| **zstd 1.1.3 -1** | 2.877 | 430 MB/s | 1110 MB/s |
|
| **zstd 1.3.4 -1** | 2.877 | 470 MB/s | 1380 MB/s |
|
||||||
| zlib 1.2.8 -1 | 2.743 | 110 MB/s | 400 MB/s |
|
| zlib 1.2.11 -1 | 2.743 | 110 MB/s | 400 MB/s |
|
||||||
| brotli 0.5.2 -0 | 2.708 | 400 MB/s | 430 MB/s |
|
| brotli 1.0.2 -0 | 2.701 | 410 MB/s | 430 MB/s |
|
||||||
| quicklz 1.5.0 -1 | 2.238 | 550 MB/s | 710 MB/s |
|
| quicklz 1.5.0 -1 | 2.238 | 550 MB/s | 710 MB/s |
|
||||||
| lzo1x 2.09 -1 | 2.108 | 650 MB/s | 830 MB/s |
|
| lzo1x 2.09 -1 | 2.108 | 650 MB/s | 830 MB/s |
|
||||||
| lz4 1.7.5 | 2.101 | 720 MB/s | 3600 MB/s |
|
| lz4 1.8.1 | 2.101 | 750 MB/s | 3700 MB/s |
|
||||||
| snappy 1.1.3 | 2.091 | 500 MB/s | 1650 MB/s |
|
| snappy 1.1.4 | 2.091 | 530 MB/s | 1800 MB/s |
|
||||||
| lzf 3.6 -1 | 2.077 | 400 MB/s | 860 MB/s |
|
| lzf 3.6 -1 | 2.077 | 400 MB/s | 860 MB/s |
|
||||||
|
|
||||||
[zlib]:http://www.zlib.net/
|
[zlib]:http://www.zlib.net/
|
||||||
@@ -50,15 +51,15 @@ Decompression speed is preserved and remains roughly the same at all settings,
|
|||||||
a property shared by most LZ compression algorithms, such as [zlib] or lzma.
|
a property shared by most LZ compression algorithms, such as [zlib] or lzma.
|
||||||
|
|
||||||
The following tests were run
|
The following tests were run
|
||||||
on a server running Linux Debian (`Linux version 4.8.0-1-amd64`)
|
on a server running Linux Debian (`Linux version 4.14.0-3-amd64`)
|
||||||
with a Core i7-6700K CPU @ 4.0GHz,
|
with a Core i7-6700K CPU @ 4.0GHz,
|
||||||
using [lzbench], an open-source in-memory benchmark by @inikep
|
using [lzbench], an open-source in-memory benchmark by @inikep
|
||||||
compiled with GCC 6.3.0,
|
compiled with [gcc] 7.3.0,
|
||||||
on the [Silesia compression corpus].
|
on the [Silesia compression corpus].
|
||||||
|
|
||||||
Compression Speed vs Ratio | Decompression Speed
|
Compression Speed vs Ratio | Decompression Speed
|
||||||
---------------------------|--------------------
|
---------------------------|--------------------
|
||||||
 | 
|
 | 
|
||||||
|
|
||||||
A few other algorithms can produce higher compression ratios at slower speeds, falling outside of the graph.
|
A few other algorithms can produce higher compression ratios at slower speeds, falling outside of the graph.
|
||||||
For a larger picture including slow modes, [click on this link](doc/images/DCspeed5.png).
|
For a larger picture including slow modes, [click on this link](doc/images/DCspeed5.png).
|
||||||
@@ -128,8 +129,8 @@ A Meson project is provided within `contrib/meson`.
|
|||||||
|
|
||||||
Going into `build` directory, you will find additional possibilities:
|
Going into `build` directory, you will find additional possibilities:
|
||||||
- Projects for Visual Studio 2005, 2008 and 2010.
|
- Projects for Visual Studio 2005, 2008 and 2010.
|
||||||
+ VS2010 project is compatible with VS2012, VS2013 and VS2015.
|
+ VS2010 project is compatible with VS2012, VS2013, VS2015 and VS2017.
|
||||||
- Automated build scripts for Visual compiler by @KrzysFR , in `build/VS_scripts`,
|
- Automated build scripts for Visual compiler by [@KrzysFR](https://github.com/KrzysFR), in `build/VS_scripts`,
|
||||||
which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution.
|
which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
version: 1.0.{build}
|
version: 1.0.{build}
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- dev
|
|
||||||
- master
|
- master
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- COMPILER: "gcc"
|
- COMPILER: "gcc"
|
||||||
HOST: "mingw"
|
HOST: "mingw"
|
||||||
PLATFORM: "x64"
|
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"
|
ARTIFACT: "true"
|
||||||
BUILD: "true"
|
BUILD: "true"
|
||||||
- COMPILER: "gcc"
|
- COMPILER: "gcc"
|
||||||
@@ -80,12 +79,22 @@
|
|||||||
SET "LDFLAGS=../../zlib/libz.a" &&
|
SET "LDFLAGS=../../zlib/libz.a" &&
|
||||||
sh -c "%SCRIPT%" &&
|
sh -c "%SCRIPT%" &&
|
||||||
( if [%COMPILER%]==[gcc] if [%ARTIFACT%]==[true]
|
( if [%COMPILER%]==[gcc] if [%ARTIFACT%]==[true]
|
||||||
|
ECHO Creating artifacts &&
|
||||||
|
ECHO %cd% &&
|
||||||
lib\dll\example\build_package.bat &&
|
lib\dll\example\build_package.bat &&
|
||||||
make -C programs DEBUGFLAGS= clean zstd &&
|
make -C programs DEBUGFLAGS= clean zstd &&
|
||||||
cd programs\ && 7z a -tzip -mx9 zstd-win-binary-%PLATFORM%.zip zstd.exe &&
|
cd programs\ && 7z a -tzip -mx9 zstd-win-binary-%PLATFORM%.zip zstd.exe &&
|
||||||
appveyor PushArtifact zstd-win-binary-%PLATFORM%.zip &&
|
appveyor PushArtifact zstd-win-binary-%PLATFORM%.zip &&
|
||||||
cp zstd.exe ..\bin\zstd.exe &&
|
cp zstd.exe ..\bin\zstd.exe &&
|
||||||
cd ..\bin\ && 7z a -tzip -mx9 zstd-win-release-%PLATFORM%.zip * &&
|
git clone --depth 1 --branch master https://github.com/facebook/zstd &&
|
||||||
|
cd zstd &&
|
||||||
|
git archive --format=tar master -o zstd-src.tar &&
|
||||||
|
..\zstd -19 zstd-src.tar &&
|
||||||
|
appveyor PushArtifact zstd-src.tar.zst &&
|
||||||
|
certUtil -hashfile zstd-src.tar.zst SHA256 > zstd-src.tar.zst.sha256.sig &&
|
||||||
|
appveyor PushArtifact zstd-src.tar.zst.sha256.sig &&
|
||||||
|
cd ..\..\bin\ &&
|
||||||
|
7z a -tzip -mx9 zstd-win-release-%PLATFORM%.zip * &&
|
||||||
appveyor PushArtifact zstd-win-release-%PLATFORM%.zip
|
appveyor PushArtifact zstd-win-release-%PLATFORM%.zip
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,48 +7,58 @@ Here are a few command lines for reference :
|
|||||||
|
|
||||||
Running the following command will build both the `Release Win32` and `Release x64` versions:
|
Running the following command will build both the `Release Win32` and `Release x64` versions:
|
||||||
```batch
|
```batch
|
||||||
build\build.VS2013.cmd
|
build.VS2013.cmd
|
||||||
```
|
```
|
||||||
The result of each build will be in the corresponding `build\bin\Release\{ARCH}\` folder.
|
The result of each build will be in the corresponding `bin\Release\{ARCH}\` folder.
|
||||||
|
|
||||||
If you want to only need one architecture:
|
If you want to only need one architecture:
|
||||||
- Win32: `build\build.generic.cmd VS2013 Win32 Release v120`
|
- Win32: `build.generic.cmd VS2013 Win32 Release v120`
|
||||||
- x64: `build\build.generic.cmd VS2013 x64 Release v120`
|
- x64: `build.generic.cmd VS2013 x64 Release v120`
|
||||||
|
|
||||||
If you want a Debug build:
|
If you want a Debug build:
|
||||||
- Win32: `build\build.generic.cmd VS2013 Win32 Debug v120`
|
- Win32: `build.generic.cmd VS2013 Win32 Debug v120`
|
||||||
- x64: `build\build.generic.cmd VS2013 x64 Debug v120`
|
- x64: `build.generic.cmd VS2013 x64 Debug v120`
|
||||||
|
|
||||||
### Build with Visual Studio 2015 for msvcr140.dll
|
### Build with Visual Studio 2015 for msvcr140.dll
|
||||||
|
|
||||||
Running the following command will build both the `Release Win32` and `Release x64` versions:
|
Running the following command will build both the `Release Win32` and `Release x64` versions:
|
||||||
```batch
|
```batch
|
||||||
build\build.VS2015.cmd
|
build.VS2015.cmd
|
||||||
```
|
```
|
||||||
The result of each build will be in the corresponding `build\bin\Release\{ARCH}\` folder.
|
The result of each build will be in the corresponding `bin\Release\{ARCH}\` folder.
|
||||||
|
|
||||||
If you want to only need one architecture:
|
If you want to only need one architecture:
|
||||||
- Win32: `build\build.generic.cmd VS2015 Win32 Release v140`
|
- Win32: `build.generic.cmd VS2015 Win32 Release v140`
|
||||||
- x64: `build\build.generic.cmd VS2015 x64 Release v140`
|
- x64: `build.generic.cmd VS2015 x64 Release v140`
|
||||||
|
|
||||||
If you want a Debug build:
|
If you want a Debug build:
|
||||||
- Win32: `build\build.generic.cmd VS2015 Win32 Debug v140`
|
- Win32: `build.generic.cmd VS2015 Win32 Debug v140`
|
||||||
- x64: `build\build.generic.cmd VS2015 x64 Debug v140`
|
- x64: `build.generic.cmd VS2015 x64 Debug v140`
|
||||||
|
|
||||||
### Build with Visual Studio 2015 for msvcr120.dll
|
### Build with Visual Studio 2015 for msvcr120.dll
|
||||||
|
|
||||||
You need to invoke `build\build.generic.cmd` with the proper arguments:
|
This capability is offered through `build.generic.cmd` using proper arguments:
|
||||||
|
|
||||||
**For Win32**
|
**For Win32**
|
||||||
```batch
|
```batch
|
||||||
build\build.generic.cmd VS2015 Win32 Release v120
|
build.generic.cmd VS2015 Win32 Release v120
|
||||||
```
|
```
|
||||||
The result of the build will be in the `build\bin\Release\Win32\` folder.
|
The result of the build will be in the `bin\Release\Win32\` folder.
|
||||||
|
|
||||||
**For x64**
|
**For x64**
|
||||||
```batch
|
```batch
|
||||||
build\build.generic.cmd VS2015 x64 Release v120
|
build.generic.cmd VS2015 x64 Release v120
|
||||||
```
|
```
|
||||||
The result of the build will be in the `build\bin\Release\x64\` folder.
|
The result of the build will be in the `bin\Release\x64\` folder.
|
||||||
|
|
||||||
If you want Debug builds, replace `Release` with `Debug`.
|
If you want Debug builds, replace `Release` with `Debug`.
|
||||||
|
|
||||||
|
### Build with Visual Studio 2017
|
||||||
|
|
||||||
|
`build.VS2017.cmd`, contributed by [@HaydnTrigg](https://github.com/HaydnTrigg),
|
||||||
|
will build both the `Release Win32` and `Release x64` versions
|
||||||
|
of the first VS2017 variant it finds, in this priority order :
|
||||||
|
Enterprise > Professional > Community
|
||||||
|
|
||||||
|
Alternatively, it's possible to target a specific version,
|
||||||
|
using appropriate script, such as `build.VS2017Enterprise.cmd` for example.
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
rem build 32-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017 Win32 Release v141
|
||||||
|
|
||||||
|
rem build 64-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017 x64 Release v141
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
rem build 32-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017Community Win32 Release v141
|
||||||
|
|
||||||
|
rem build 64-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017Community x64 Release v141
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
rem build 32-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017Enterprise Win32 Release v141
|
||||||
|
|
||||||
|
rem build 64-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017Enterprise x64 Release v141
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
rem build 32-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017Professional Win32 Release v141
|
||||||
|
|
||||||
|
rem build 64-bit
|
||||||
|
call "%~p0%build.generic.cmd" VS2017Professional x64 Release v141
|
||||||
@@ -19,19 +19,29 @@ GOTO build
|
|||||||
:display_help
|
:display_help
|
||||||
|
|
||||||
echo Syntax: build.generic.cmd msbuild_version msbuild_platform msbuild_configuration msbuild_toolset
|
echo Syntax: build.generic.cmd msbuild_version msbuild_platform msbuild_configuration msbuild_toolset
|
||||||
echo msbuild_version: VS installed version (VS2012, VS2013, VS2015, ...)
|
echo msbuild_version: VS installed version (VS2012, VS2013, VS2015, VS2017, ...)
|
||||||
echo msbuild_platform: Platform (x64 or Win32)
|
echo msbuild_platform: Platform (x64 or Win32)
|
||||||
echo msbuild_configuration: VS configuration (Release or Debug)
|
echo msbuild_configuration: VS configuration (Release or Debug)
|
||||||
echo msbuild_toolset: Platform Toolset (v100, v110, v120, v140)
|
echo msbuild_toolset: Platform Toolset (v100, v110, v120, v140, v141)
|
||||||
|
|
||||||
EXIT /B 1
|
EXIT /B 1
|
||||||
|
|
||||||
:build
|
:build
|
||||||
|
|
||||||
SET msbuild="%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"
|
SET msbuild="%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"
|
||||||
|
SET msbuild_vs2017community="%programfiles(x86)%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe"
|
||||||
|
SET msbuild_vs2017professional="%programfiles(x86)%\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\MSBuild.exe"
|
||||||
|
SET msbuild_vs2017enterprise="%programfiles(x86)%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe"
|
||||||
IF %msbuild_version% == VS2013 SET msbuild="%programfiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe"
|
IF %msbuild_version% == VS2013 SET msbuild="%programfiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe"
|
||||||
IF %msbuild_version% == VS2015 SET msbuild="%programfiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe"
|
IF %msbuild_version% == VS2015 SET msbuild="%programfiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe"
|
||||||
rem TODO: Visual Studio "15" (vNext) will use MSBuild 15.0 ?
|
IF %msbuild_version% == VS2017Community SET msbuild="%msbuild_vs2017community%
|
||||||
|
IF %msbuild_version% == VS2017Professional SET msbuild=%msbuild_vs2017professional%
|
||||||
|
IF %msbuild_version% == VS2017Enterprise SET msbuild=%msbuild_vs2017enterprise%
|
||||||
|
IF %msbuild_version% == VS2017 (
|
||||||
|
IF EXIST %msbuild_vs2017community% SET msbuild=%msbuild_vs2017community%
|
||||||
|
IF EXIST %msbuild_vs2017professional% SET msbuild=%msbuild_vs2017professional%
|
||||||
|
IF EXIST %msbuild_vs2017enterprise% SET msbuild=%msbuild_vs2017enterprise%
|
||||||
|
)
|
||||||
|
|
||||||
SET project="%~p0\..\VS2010\zstd.sln"
|
SET project="%~p0\..\VS2010\zstd.sln"
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ PROJECT(zstd)
|
|||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
|
||||||
SET(ZSTD_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
SET(ZSTD_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
||||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||||
|
INCLUDE(GNUInstallDirs)
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# Add extra compilation flags
|
# Add extra compilation flags
|
||||||
@@ -21,21 +22,18 @@ ADD_ZSTD_COMPILATION_FLAGS()
|
|||||||
# Always hide XXHash symbols
|
# Always hide XXHash symbols
|
||||||
ADD_DEFINITIONS(-DXXH_NAMESPACE=ZSTD_)
|
ADD_DEFINITIONS(-DXXH_NAMESPACE=ZSTD_)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Installation variables
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
MESSAGE(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
|
||||||
|
MESSAGE(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# Options
|
# Options
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Legacy support
|
||||||
OPTION(ZSTD_LEGACY_SUPPORT "LEGACY SUPPORT" OFF)
|
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)
|
IF (ZSTD_LEGACY_SUPPORT)
|
||||||
MESSAGE(STATUS "ZSTD_LEGACY_SUPPORT defined!")
|
MESSAGE(STATUS "ZSTD_LEGACY_SUPPORT defined!")
|
||||||
@@ -45,6 +43,35 @@ ELSE (ZSTD_LEGACY_SUPPORT)
|
|||||||
ADD_DEFINITIONS(-DZSTD_LEGACY_SUPPORT=0)
|
ADD_DEFINITIONS(-DZSTD_LEGACY_SUPPORT=0)
|
||||||
ENDIF (ZSTD_LEGACY_SUPPORT)
|
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
|
# Add source directories
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -27,4 +27,4 @@ ADD_CUSTOM_TARGET(zstd_manual.html ALL
|
|||||||
${GENHTML_BINARY} "${LIBVERSION}" "${LIBRARY_DIR}/zstd.h" "${PROJECT_BINARY_DIR}/zstd_manual.html"
|
${GENHTML_BINARY} "${LIBVERSION}" "${LIBRARY_DIR}/zstd.h" "${PROJECT_BINARY_DIR}/zstd_manual.html"
|
||||||
DEPENDS gen_html COMMENT "Update zstd manual")
|
DEPENDS gen_html COMMENT "Update zstd manual")
|
||||||
|
|
||||||
INSTALL(FILES "${PROJECT_BINARY_DIR}/zstd_manual.html" DESTINATION "share/doc")
|
INSTALL(FILES "${PROJECT_BINARY_DIR}/zstd_manual.html" DESTINATION "${CMAKE_INSTALL_PREFIX}/${DOC_INSTALL_DIR}")
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ INCLUDE_DIRECTORIES(${LIBRARY_DIR} ${LIBRARY_DIR}/common)
|
|||||||
# Parse version
|
# Parse version
|
||||||
INCLUDE(GetZstdLibraryVersion)
|
INCLUDE(GetZstdLibraryVersion)
|
||||||
GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h LIBVER_MAJOR LIBVER_MINOR LIBVER_RELEASE)
|
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
|
SET(Sources
|
||||||
${LIBRARY_DIR}/common/entropy_common.c
|
${LIBRARY_DIR}/common/entropy_common.c
|
||||||
@@ -120,6 +120,17 @@ IF (MSVC)
|
|||||||
ENDIF (ZSTD_BUILD_STATIC)
|
ENDIF (ZSTD_BUILD_STATIC)
|
||||||
ENDIF (MSVC)
|
ENDIF (MSVC)
|
||||||
|
|
||||||
|
# Add multi-threading support definitions
|
||||||
|
|
||||||
|
IF (ZSTD_MULTITHREAD_SUPPORT AND ZSTD_BUILD_SHARED AND ZSTD_BUILD_STATIC)
|
||||||
|
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 AND ZSTD_BUILD_SHARED AND ZSTD_BUILD_STATIC)
|
||||||
|
|
||||||
# With MSVC static library needs to be renamed to avoid conflict with import library
|
# With MSVC static library needs to be renamed to avoid conflict with import library
|
||||||
IF (MSVC)
|
IF (MSVC)
|
||||||
SET(STATIC_LIBRARY_BASE_NAME zstd_static)
|
SET(STATIC_LIBRARY_BASE_NAME zstd_static)
|
||||||
@@ -146,7 +157,7 @@ ENDIF (ZSTD_BUILD_STATIC)
|
|||||||
IF (UNIX)
|
IF (UNIX)
|
||||||
# pkg-config
|
# pkg-config
|
||||||
SET(PREFIX "${CMAKE_INSTALL_PREFIX}")
|
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(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include")
|
||||||
SET(VERSION "${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE}")
|
SET(VERSION "${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE}")
|
||||||
ADD_CUSTOM_TARGET(libzstd.pc ALL
|
ADD_CUSTOM_TARGET(libzstd.pc ALL
|
||||||
@@ -155,7 +166,7 @@ IF (UNIX)
|
|||||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/pkgconfig.cmake"
|
-P "${CMAKE_CURRENT_SOURCE_DIR}/pkgconfig.cmake"
|
||||||
COMMENT "Creating pkg-config file")
|
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)
|
ENDIF (UNIX)
|
||||||
|
|
||||||
# install target
|
# install target
|
||||||
@@ -167,10 +178,12 @@ INSTALL(FILES
|
|||||||
DESTINATION "include")
|
DESTINATION "include")
|
||||||
|
|
||||||
IF (ZSTD_BUILD_SHARED)
|
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()
|
ENDIF()
|
||||||
IF (ZSTD_BUILD_STATIC)
|
IF (ZSTD_BUILD_STATIC)
|
||||||
INSTALL(TARGETS libzstd_static ARCHIVE DESTINATION "lib")
|
INSTALL(TARGETS libzstd_static ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||||
ENDIF (ZSTD_BUILD_STATIC)
|
ENDIF (ZSTD_BUILD_STATIC)
|
||||||
|
|
||||||
# uninstall target
|
# uninstall target
|
||||||
|
|||||||
@@ -45,28 +45,33 @@ IF (UNIX)
|
|||||||
COMMENT "Copying manpage zstd.1")
|
COMMENT "Copying manpage zstd.1")
|
||||||
ADD_CUSTOM_TARGET(zstdcat.1 ALL ${CMAKE_COMMAND} -E create_symlink zstd.1 zstdcat.1 DEPENDS zstd.1 COMMENT "Creating zstdcat.1 symlink")
|
ADD_CUSTOM_TARGET(zstdcat.1 ALL ${CMAKE_COMMAND} -E create_symlink zstd.1 zstdcat.1 DEPENDS zstd.1 COMMENT "Creating zstdcat.1 symlink")
|
||||||
ADD_CUSTOM_TARGET(unzstd.1 ALL ${CMAKE_COMMAND} -E create_symlink zstd.1 unzstd.1 DEPENDS zstd.1 COMMENT "Creating unzstd.1 symlink")
|
ADD_CUSTOM_TARGET(unzstd.1 ALL ${CMAKE_COMMAND} -E create_symlink zstd.1 unzstd.1 DEPENDS zstd.1 COMMENT "Creating unzstd.1 symlink")
|
||||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstd.1 DESTINATION "share/man/man1")
|
|
||||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstdcat.1 DESTINATION "share/man/man1")
|
# Define MAN_INSTALL_DIR if necessary
|
||||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/unzstd.1 DESTINATION "share/man/man1")
|
IF (MAN_INSTALL_DIR)
|
||||||
|
ELSE (MAN_INSTALL_DIR)
|
||||||
|
SET(MAN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/share/man/man1)
|
||||||
|
ENDIF (MAN_INSTALL_DIR)
|
||||||
|
|
||||||
|
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstd.1 DESTINATION "${MAN_INSTALL_DIR}")
|
||||||
|
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstdcat.1 DESTINATION "${MAN_INSTALL_DIR}")
|
||||||
|
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/unzstd.1 DESTINATION "${MAN_INSTALL_DIR}")
|
||||||
|
|
||||||
ADD_EXECUTABLE(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c)
|
ADD_EXECUTABLE(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c)
|
||||||
TARGET_LINK_LIBRARIES(zstd-frugal libzstd_static)
|
TARGET_LINK_LIBRARIES(zstd-frugal libzstd_static)
|
||||||
SET_PROPERTY(TARGET zstd-frugal APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_NOBENCH;ZSTD_NODICT")
|
SET_PROPERTY(TARGET zstd-frugal APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_NOBENCH;ZSTD_NODICT")
|
||||||
ENDIF (UNIX)
|
ENDIF (UNIX)
|
||||||
|
|
||||||
|
# Add multi-threading support definitions
|
||||||
|
|
||||||
IF (ZSTD_MULTITHREAD_SUPPORT)
|
IF (ZSTD_MULTITHREAD_SUPPORT)
|
||||||
SET_PROPERTY(TARGET zstd APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
|
SET_PROPERTY(TARGET zstd APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
|
||||||
|
|
||||||
SET(THREADS_PREFER_PTHREAD_FLAG ON)
|
IF (UNIX)
|
||||||
FIND_PACKAGE(Threads REQUIRED)
|
TARGET_LINK_LIBRARIES(zstd ${THREADS_LIBS})
|
||||||
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()
|
|
||||||
|
|
||||||
ADD_CUSTOM_TARGET(zstdmt ALL ${CMAKE_COMMAND} -E create_symlink zstd zstdmt DEPENDS zstd COMMENT "Creating zstdmt symlink")
|
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")
|
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstdmt DESTINATION "bin")
|
||||||
|
ENDIF (UNIX)
|
||||||
ENDIF (ZSTD_MULTITHREAD_SUPPORT)
|
ENDIF (ZSTD_MULTITHREAD_SUPPORT)
|
||||||
|
|
||||||
OPTION(ZSTD_ZLIB_SUPPORT "ZLIB SUPPORT" OFF)
|
OPTION(ZSTD_ZLIB_SUPPORT "ZLIB SUPPORT" OFF)
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# binaries generated
|
||||||
|
adapt
|
||||||
|
datagen
|
||||||
@@ -40,7 +40,6 @@ static unsigned g_compressionLevel = DEFAULT_COMPRESSION_LEVEL;
|
|||||||
static UTIL_time_t g_startTime;
|
static UTIL_time_t g_startTime;
|
||||||
static size_t g_streamedSize = 0;
|
static size_t g_streamedSize = 0;
|
||||||
static unsigned g_useProgressBar = 1;
|
static unsigned g_useProgressBar = 1;
|
||||||
static UTIL_freq_t g_ticksPerSecond;
|
|
||||||
static unsigned g_forceCompressionLevel = 0;
|
static unsigned g_forceCompressionLevel = 0;
|
||||||
static unsigned g_minCLevel = 1;
|
static unsigned g_minCLevel = 1;
|
||||||
static unsigned g_maxCLevel;
|
static unsigned g_maxCLevel;
|
||||||
@@ -576,13 +575,12 @@ static void* compressionThread(void* arg)
|
|||||||
/* begin compression */
|
/* begin compression */
|
||||||
{
|
{
|
||||||
size_t const useDictSize = MIN(getUseableDictSize(cLevel), job->dictSize);
|
size_t const useDictSize = MIN(getUseableDictSize(cLevel), job->dictSize);
|
||||||
size_t const dictModeError = ZSTD_setCCtxParameter(ctx->cctx, ZSTD_p_forceRawDict, 1);
|
|
||||||
ZSTD_parameters params = ZSTD_getParams(cLevel, 0, useDictSize);
|
ZSTD_parameters params = ZSTD_getParams(cLevel, 0, useDictSize);
|
||||||
params.cParams.windowLog = 23;
|
params.cParams.windowLog = 23;
|
||||||
{
|
{
|
||||||
size_t const initError = ZSTD_compressBegin_advanced(ctx->cctx, job->src.start + job->dictSize - useDictSize, useDictSize, params, 0);
|
size_t const initError = ZSTD_compressBegin_advanced(ctx->cctx, job->src.start + job->dictSize - useDictSize, useDictSize, params, 0);
|
||||||
size_t const windowSizeError = ZSTD_setCCtxParameter(ctx->cctx, ZSTD_p_forceWindow, 1);
|
size_t const windowSizeError = ZSTD_CCtx_setParameter(ctx->cctx, ZSTD_p_forceMaxWindow, 1);
|
||||||
if (ZSTD_isError(dictModeError) || ZSTD_isError(initError) || ZSTD_isError(windowSizeError)) {
|
if (ZSTD_isError(initError) || ZSTD_isError(windowSizeError)) {
|
||||||
DISPLAY("Error: something went wrong while starting compression\n");
|
DISPLAY("Error: something went wrong while starting compression\n");
|
||||||
signalErrorToThreads(ctx);
|
signalErrorToThreads(ctx);
|
||||||
return arg;
|
return arg;
|
||||||
@@ -644,21 +642,17 @@ static void* compressionThread(void* arg)
|
|||||||
|
|
||||||
static void displayProgress(unsigned cLevel, unsigned last)
|
static void displayProgress(unsigned cLevel, unsigned last)
|
||||||
{
|
{
|
||||||
UTIL_time_t currTime;
|
UTIL_time_t currTime = UTIL_getTime();
|
||||||
UTIL_getTime(&currTime);
|
|
||||||
if (!g_useProgressBar) return;
|
if (!g_useProgressBar) return;
|
||||||
{
|
{ double const timeElapsed = (double)(UTIL_getSpanTimeMicro(g_startTime, currTime) / 1000.0);
|
||||||
double const timeElapsed = (double)(UTIL_getSpanTimeMicro(g_ticksPerSecond, g_startTime, currTime) / 1000.0);
|
|
||||||
double const sizeMB = (double)g_streamedSize / (1 << 20);
|
double const sizeMB = (double)g_streamedSize / (1 << 20);
|
||||||
double const avgCompRate = sizeMB * 1000 / timeElapsed;
|
double const avgCompRate = sizeMB * 1000 / timeElapsed;
|
||||||
fprintf(stderr, "\r| Comp. Level: %2u | Time Elapsed: %7.2f s | Data Size: %7.1f MB | Avg Comp. Rate: %6.2f MB/s |", cLevel, timeElapsed/1000.0, sizeMB, avgCompRate);
|
fprintf(stderr, "\r| Comp. Level: %2u | Time Elapsed: %7.2f s | Data Size: %7.1f MB | Avg Comp. Rate: %6.2f MB/s |", cLevel, timeElapsed/1000.0, sizeMB, avgCompRate);
|
||||||
if (last) {
|
if (last) {
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
}
|
} }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* outputThread(void* arg)
|
static void* outputThread(void* arg)
|
||||||
@@ -971,7 +965,6 @@ static int compressFilename(const char* const srcFilename, const char* const dst
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
fcResources fcr = createFileCompressionResources(srcFilename, dstFilenameOrNull);
|
fcResources fcr = createFileCompressionResources(srcFilename, dstFilenameOrNull);
|
||||||
UTIL_getTime(&g_startTime);
|
|
||||||
g_streamedSize = 0;
|
g_streamedSize = 0;
|
||||||
ret |= performCompression(fcr.ctx, fcr.srcFile, fcr.otArg);
|
ret |= performCompression(fcr.ctx, fcr.srcFile, fcr.otArg);
|
||||||
ret |= freeFileCompressionResources(&fcr);
|
ret |= freeFileCompressionResources(&fcr);
|
||||||
@@ -1044,8 +1037,6 @@ int main(int argCount, const char* argv[])
|
|||||||
filenameTable[0] = stdinmark;
|
filenameTable[0] = stdinmark;
|
||||||
g_maxCLevel = ZSTD_maxCLevel();
|
g_maxCLevel = ZSTD_maxCLevel();
|
||||||
|
|
||||||
UTIL_initTimer(&g_ticksPerSecond);
|
|
||||||
|
|
||||||
if (filenameTable == NULL) {
|
if (filenameTable == NULL) {
|
||||||
DISPLAY("Error: could not allocate sapce for filename table.\n");
|
DISPLAY("Error: could not allocate sapce for filename table.\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Dockerfile
|
||||||
|
# First image to build the binary
|
||||||
|
FROM alpine as builder
|
||||||
|
|
||||||
|
RUN apk --no-cache add make gcc libc-dev
|
||||||
|
COPY . /src
|
||||||
|
RUN mkdir /pkg && cd /src && make && make DESTDIR=/pkg install
|
||||||
|
|
||||||
|
# Second minimal image to only keep the built binary
|
||||||
|
FROM alpine
|
||||||
|
|
||||||
|
# Copy the built files
|
||||||
|
COPY --from=builder /pkg /
|
||||||
|
|
||||||
|
# Copy the license as well
|
||||||
|
RUN mkdir -p /usr/local/share/licenses/zstd
|
||||||
|
COPY --from=builder /src/LICENSE /usr/local/share/licences/zstd/
|
||||||
|
|
||||||
|
# Just run `zstd` if no other command is given
|
||||||
|
CMD ["/usr/local/bin/zstd"]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
## Requirement
|
||||||
|
|
||||||
|
The `Dockerfile` script requires a version of `docker` >= 17.05
|
||||||
|
|
||||||
|
## Installing docker
|
||||||
|
|
||||||
|
The officiel docker install docs use a ppa with a modern version available:
|
||||||
|
https://docs.docker.com/install/linux/docker-ce/ubuntu/
|
||||||
|
|
||||||
|
## How to run
|
||||||
|
|
||||||
|
`docker build -t zstd .`
|
||||||
|
|
||||||
|
## test
|
||||||
|
|
||||||
|
```
|
||||||
|
echo foo | docker run -i --rm zstd | docker run -i --rm zstd zstdcat
|
||||||
|
foo
|
||||||
|
```
|
||||||
@@ -7,10 +7,10 @@
|
|||||||
# in the COPYING file in the root directory of this source tree).
|
# in the COPYING file in the root directory of this source tree).
|
||||||
# ################################################################
|
# ################################################################
|
||||||
|
|
||||||
CFLAGS ?= -O3
|
CXXFLAGS ?= -O3
|
||||||
CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wno-comment
|
CXXFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wno-comment
|
||||||
CFLAGS += $(MOREFLAGS)
|
CXXFLAGS += $(MOREFLAGS)
|
||||||
FLAGS = $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) $(LDFLAGS)
|
FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(CXXFLAGS) $(LDFLAGS)
|
||||||
|
|
||||||
ZSTDAPI = ../../lib/zstd.h
|
ZSTDAPI = ../../lib/zstd.h
|
||||||
ZSTDMANUAL = ../../doc/zstd_manual.html
|
ZSTDMANUAL = ../../doc/zstd_manual.html
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
# ################################################################
|
|
||||||
# Copyright (c) 2017-present, 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).
|
|
||||||
# ################################################################
|
|
||||||
|
|
||||||
# This Makefile presumes libzstd is installed, using `sudo make install`
|
|
||||||
|
|
||||||
CPPFLAGS+= -I../../lib/common
|
|
||||||
CFLAGS ?= -O3
|
|
||||||
DEBUGFLAGS = -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
|
|
||||||
-Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
|
|
||||||
-Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \
|
|
||||||
-Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
|
|
||||||
-Wredundant-decls
|
|
||||||
CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
|
|
||||||
FLAGS = $(CPPFLAGS) $(CFLAGS)
|
|
||||||
|
|
||||||
LDFLAGS += -lzstd
|
|
||||||
|
|
||||||
.PHONY: default all clean
|
|
||||||
|
|
||||||
default: all
|
|
||||||
|
|
||||||
all: ldm
|
|
||||||
|
|
||||||
ldm: ldm_common.c ldm.c main.c
|
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@rm -f core *.o tmp* result* *.ldm *.ldm.dec \
|
|
||||||
ldm
|
|
||||||
@echo Cleaning completed
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
This is a compression algorithm focused on finding long distance matches.
|
|
||||||
|
|
||||||
It is based upon lz4 and uses nearly the same block format (github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md). The number of bytes to encode the offset is four instead of two in lz4 to reflect the longer distance matching. The block format is described in `ldm.h`.
|
|
||||||
|
|
||||||
### Build
|
|
||||||
|
|
||||||
Run `make`.
|
|
||||||
|
|
||||||
### Compressing a file
|
|
||||||
|
|
||||||
`ldm <filename>`
|
|
||||||
|
|
||||||
Decompression and verification can be enabled by defining `DECOMPRESS_AND_VERIFY` in `main.c`.
|
|
||||||
The output file names are as follows:
|
|
||||||
- `<filename>.ldm` : compressed file
|
|
||||||
- `<filename>.ldm.dec` : decompressed file
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
|
|
||||||
There are various parameters that can be tuned. These parameters can be tuned in `ldm.h` or, alternatively if `ldm_params.h` is included, in `ldm_params.h` (for easier configuration).
|
|
||||||
|
|
||||||
The parameters are as follows and must all be defined:
|
|
||||||
- `LDM_MEMORY_USAGE` : the memory usage of the underlying hash table in bytes.
|
|
||||||
- `HASH_BUCKET_SIZE_LOG` : the log size of each bucket in the hash table (used in collision resolution).
|
|
||||||
- `LDM_LAG` : the lag (in bytes) in inserting entries into the hash table.
|
|
||||||
- `LDM_WINDOW_SIZE_LOG` : the log maximum window size when searching for matches.
|
|
||||||
- `LDM_MIN_MATCH_LENGTH` : the minimum match length.
|
|
||||||
- `INSERT_BY_TAG` : insert entries into the hash table as a function of the hash. This increases speed by reducing the number of hash table lookups and match comparisons. Certain hashes will never be inserted.
|
|
||||||
- `USE_CHECKSUM` : store a checksum with the hash table entries for faster comparison. This halves the number of entries the hash table can contain.
|
|
||||||
|
|
||||||
The optional parameter `HASH_ONLY_EVERY_LOG` is the log inverse frequency of insertion into the hash table. That is, an entry is inserted approximately every `1 << HASH_ONLY_EVERY_LOG` times. If this parameter is not defined, the value is computed as a function of the window size and memory usage to approximate an even coverage of the window.
|
|
||||||
|
|
||||||
|
|
||||||
### Benchmark
|
|
||||||
|
|
||||||
Below is a comparison of various compression methods on a tar of four versions of llvm (versions `3.9.0`, `3.9.1`, `4.0.0`, `4.0.1`) with a total size of `727900160` B.
|
|
||||||
|
|
||||||
| Method | Size | Ratio |
|
|
||||||
|:---|---:|---:|
|
|
||||||
|lrzip -p 32 -n -w 1 | `369968714` | `1.97`|
|
|
||||||
|ldm | `209391361` | `3.48`|
|
|
||||||
|lz4 | `189954338` | `3.83`|
|
|
||||||
|lrzip -p 32 -l -w 1 | `163940343` | `4.44`|
|
|
||||||
|zstd -1 | `126080293` | `5.77`|
|
|
||||||
|lrzip -p 32 -n | `124821009` | `5.83`|
|
|
||||||
|lrzip -p 32 -n -w 1 & zstd -1 | `120317909` | `6.05`|
|
|
||||||
|zstd -3 -o | `115290952` | `6.31`|
|
|
||||||
|lrzip -p 32 -g -L 9 -w 1 | `107168979` | `6.79`|
|
|
||||||
|zstd -6 -o | `102772098` | `7.08`|
|
|
||||||
|zstd -T16 -9 | `98040470` | `7.42`|
|
|
||||||
|lrzip -p 32 -n -w 1 & zstd -T32 -19 | `88050289` | `8.27`|
|
|
||||||
|zstd -T32 -19 | `83626098` | `8.70`|
|
|
||||||
|lrzip -p 32 -n & zstd -1 | `36335117` | `20.03`|
|
|
||||||
|ldm & zstd -6 | `32856232` | `22.15`|
|
|
||||||
|lrzip -p 32 -g -L 9 | `32243594` | `22.58`|
|
|
||||||
|lrzip -p 32 -n & zstd -6 | `30954572` | `23.52`|
|
|
||||||
|lrzip -p 32 -n & zstd -T32 -19 | `26472064` | `27.50`|
|
|
||||||
|
|
||||||
The method marked `ldm` was run with the following parameters:
|
|
||||||
|
|
||||||
| Parameter | Value |
|
|
||||||
|:---|---:|
|
|
||||||
| `LDM_MEMORY_USAGE` | `23`|
|
|
||||||
|`HASH_BUCKET_SIZE_LOG` | `3`|
|
|
||||||
|`LDM_LAG` | `0`|
|
|
||||||
|`LDM_WINDOW_SIZE_LOG` | `28`|
|
|
||||||
|`LDM_MIN_MATCH_LENGTH`| `64`|
|
|
||||||
|`INSERT_BY_TAG` | `1`|
|
|
||||||
|`USE_CHECKSUM` | `1`|
|
|
||||||
|
|
||||||
The compression speed was `220.5 MB/s`.
|
|
||||||
|
|
||||||
### Parameter selection
|
|
||||||
|
|
||||||
Below is a brief discussion of the effects of the parameters on the speed and compression ratio.
|
|
||||||
|
|
||||||
#### Speed
|
|
||||||
|
|
||||||
A large bottleneck in terms of speed is finding the matches and comparing to see if they are greater than the minimum match length. Generally:
|
|
||||||
- The fewer matches found (or the lower the percentage of the literals matched), the slower the algorithm will behave.
|
|
||||||
- Increasing `HASH_ONLY_EVERY_LOG` results in fewer inserts and, if `INSERT_BY_TAG` is set, fewer lookups in the table. This has a large effect on speed, as well as compression ratio.
|
|
||||||
- If `HASH_ONLY_EVERY_LOG` is not set, its value is calculated based on `LDM_WINDOW_SIZE_LOG` and `LDM_MEMORY_USAGE`. Increasing `LDM_WINDOW_SIZE_LOG` has the effect of increasing `HASH_ONLY_EVERY_LOG` and increasing `LDM_MEMORY_USAGE` decreases `HASH_ONLY_EVERY_LOG`.
|
|
||||||
- `USE_CHECKSUM` generally improves speed with hash table lookups.
|
|
||||||
|
|
||||||
#### Compression ratio
|
|
||||||
|
|
||||||
The compression ratio is highly correlated with the coverage of matches. As a long distance matcher, the algorithm was designed to "optimize" for long distance matches outside the zstd compression window. The compression ratio after recompressing the output of the long-distance matcher with zstd was a more important signal in development than the raw compression ratio itself.
|
|
||||||
|
|
||||||
Generally, increasing `LDM_MEMORY_USAGE` will improve the compression ratio. However when using the default computed value of `HASH_ONLY_EVERY_LOG`, this increases the frequency of insertion and lookup in the table and thus may result in a decrease in speed.
|
|
||||||
|
|
||||||
Below is a table showing the speed and compression ratio when compressing the llvm tar (as described above) using different settings for `LDM_MEMORY_USAGE`. The other parameters were the same as used in the benchmark above.
|
|
||||||
|
|
||||||
| `LDM_MEMORY_USAGE` | Ratio | Speed (MB/s) | Ratio after zstd -6 |
|
|
||||||
|---:| ---: | ---: | ---: |
|
|
||||||
| `18` | `1.85` | `232.4` | `10.92` |
|
|
||||||
| `21` | `2.79` | `233.9` | `15.92` |
|
|
||||||
| `23` | `3.48` | `220.5` | `18.29` |
|
|
||||||
| `25` | `4.56` | `140.8` | `19.21` |
|
|
||||||
|
|
||||||
### Compression statistics
|
|
||||||
|
|
||||||
Compression statistics (and the configuration) can be enabled/disabled via `COMPUTE_STATS` and `OUTPUT_CONFIGURATION` in `ldm.h`.
|
|
||||||
@@ -1,856 +0,0 @@
|
|||||||
#include <limits.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "ldm.h"
|
|
||||||
|
|
||||||
#define LDM_HASHTABLESIZE (1 << (LDM_MEMORY_USAGE))
|
|
||||||
#define LDM_HASHTABLESIZE_U32 ((LDM_HASHTABLESIZE) >> 2)
|
|
||||||
#define LDM_HASHTABLESIZE_U64 ((LDM_HASHTABLESIZE) >> 3)
|
|
||||||
|
|
||||||
#if USE_CHECKSUM
|
|
||||||
#define LDM_HASH_ENTRY_SIZE_LOG 3
|
|
||||||
#else
|
|
||||||
#define LDM_HASH_ENTRY_SIZE_LOG 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Entries are inserted into the table HASH_ONLY_EVERY + 1 times "on average".
|
|
||||||
#ifndef HASH_ONLY_EVERY_LOG
|
|
||||||
#define HASH_ONLY_EVERY_LOG (LDM_WINDOW_SIZE_LOG-((LDM_MEMORY_USAGE)-(LDM_HASH_ENTRY_SIZE_LOG)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define HASH_ONLY_EVERY ((1 << (HASH_ONLY_EVERY_LOG)) - 1)
|
|
||||||
|
|
||||||
#define HASH_BUCKET_SIZE (1 << (HASH_BUCKET_SIZE_LOG))
|
|
||||||
#define NUM_HASH_BUCKETS_LOG ((LDM_MEMORY_USAGE)-(LDM_HASH_ENTRY_SIZE_LOG)-(HASH_BUCKET_SIZE_LOG))
|
|
||||||
|
|
||||||
#define HASH_CHAR_OFFSET 10
|
|
||||||
|
|
||||||
// Take the first match in the hash bucket only.
|
|
||||||
//#define ZSTD_SKIP
|
|
||||||
|
|
||||||
static const U64 prime8bytes = 11400714785074694791ULL;
|
|
||||||
|
|
||||||
// Type of the small hash used to index into the hash table.
|
|
||||||
typedef U32 hash_t;
|
|
||||||
|
|
||||||
#if USE_CHECKSUM
|
|
||||||
typedef struct LDM_hashEntry {
|
|
||||||
U32 offset;
|
|
||||||
U32 checksum;
|
|
||||||
} LDM_hashEntry;
|
|
||||||
#else
|
|
||||||
typedef struct LDM_hashEntry {
|
|
||||||
U32 offset;
|
|
||||||
} LDM_hashEntry;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct LDM_compressStats {
|
|
||||||
U32 windowSizeLog, hashTableSizeLog;
|
|
||||||
U32 numMatches;
|
|
||||||
U64 totalMatchLength;
|
|
||||||
U64 totalLiteralLength;
|
|
||||||
U64 totalOffset;
|
|
||||||
|
|
||||||
U32 matchLengthHistogram[32];
|
|
||||||
|
|
||||||
U32 minOffset, maxOffset;
|
|
||||||
U32 offsetHistogram[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct LDM_hashTable LDM_hashTable;
|
|
||||||
|
|
||||||
struct LDM_CCtx {
|
|
||||||
size_t isize; /* Input size */
|
|
||||||
size_t maxOSize; /* Maximum output size */
|
|
||||||
|
|
||||||
const BYTE *ibase; /* Base of input */
|
|
||||||
const BYTE *ip; /* Current input position */
|
|
||||||
const BYTE *iend; /* End of input */
|
|
||||||
|
|
||||||
// Maximum input position such that hashing at the position does not exceed
|
|
||||||
// end of input.
|
|
||||||
const BYTE *ihashLimit;
|
|
||||||
|
|
||||||
// Maximum input position such that finding a match of at least the minimum
|
|
||||||
// match length does not exceed end of input.
|
|
||||||
const BYTE *imatchLimit;
|
|
||||||
|
|
||||||
const BYTE *obase; /* Base of output */
|
|
||||||
BYTE *op; /* Output */
|
|
||||||
|
|
||||||
const BYTE *anchor; /* Anchor to start of current (match) block */
|
|
||||||
|
|
||||||
LDM_compressStats stats; /* Compression statistics */
|
|
||||||
|
|
||||||
LDM_hashTable *hashTable;
|
|
||||||
|
|
||||||
const BYTE *lastPosHashed; /* Last position hashed */
|
|
||||||
U64 lastHash;
|
|
||||||
|
|
||||||
const BYTE *nextIp; // TODO: this is redundant (ip + step)
|
|
||||||
const BYTE *nextPosHashed;
|
|
||||||
U64 nextHash;
|
|
||||||
|
|
||||||
unsigned step; // ip step, should be 1.
|
|
||||||
|
|
||||||
const BYTE *lagIp;
|
|
||||||
U64 lagHash;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LDM_hashTable {
|
|
||||||
U32 numBuckets; // The number of buckets.
|
|
||||||
U32 numEntries; // numBuckets * HASH_BUCKET_SIZE.
|
|
||||||
|
|
||||||
LDM_hashEntry *entries;
|
|
||||||
BYTE *bucketOffsets; // A pointer (per bucket) to the next insert position.
|
|
||||||
};
|
|
||||||
|
|
||||||
static void HASH_destroyTable(LDM_hashTable *table) {
|
|
||||||
free(table->entries);
|
|
||||||
free(table->bucketOffsets);
|
|
||||||
free(table);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a hash table that can contain size elements.
|
|
||||||
* The number of buckets is determined by size >> HASH_BUCKET_SIZE_LOG.
|
|
||||||
*
|
|
||||||
* Returns NULL if table creation failed.
|
|
||||||
*/
|
|
||||||
static LDM_hashTable *HASH_createTable(U32 size) {
|
|
||||||
LDM_hashTable *table = malloc(sizeof(LDM_hashTable));
|
|
||||||
if (!table) return NULL;
|
|
||||||
|
|
||||||
table->numBuckets = size >> HASH_BUCKET_SIZE_LOG;
|
|
||||||
table->numEntries = size;
|
|
||||||
table->entries = calloc(size, sizeof(LDM_hashEntry));
|
|
||||||
table->bucketOffsets = calloc(size >> HASH_BUCKET_SIZE_LOG, sizeof(BYTE));
|
|
||||||
|
|
||||||
if (!table->entries || !table->bucketOffsets) {
|
|
||||||
HASH_destroyTable(table);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
||||||
static LDM_hashEntry *getBucket(const LDM_hashTable *table, const hash_t hash) {
|
|
||||||
return table->entries + (hash << HASH_BUCKET_SIZE_LOG);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned ZSTD_NbCommonBytes (size_t val) {
|
|
||||||
if (MEM_isLittleEndian()) {
|
|
||||||
if (MEM_64bits()) {
|
|
||||||
# if defined(_MSC_VER) && defined(_WIN64)
|
|
||||||
unsigned long r = 0;
|
|
||||||
_BitScanForward64( &r, (U64)val );
|
|
||||||
return (unsigned)(r>>3);
|
|
||||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
|
||||||
return (__builtin_ctzll((U64)val) >> 3);
|
|
||||||
# else
|
|
||||||
static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
|
|
||||||
0, 3, 1, 3, 1, 4, 2, 7,
|
|
||||||
0, 2, 3, 6, 1, 5, 3, 5,
|
|
||||||
1, 3, 4, 4, 2, 5, 6, 7,
|
|
||||||
7, 0, 1, 2, 3, 3, 4, 6,
|
|
||||||
2, 6, 5, 5, 3, 4, 5, 6,
|
|
||||||
7, 1, 2, 4, 6, 4, 4, 5,
|
|
||||||
7, 2, 6, 5, 7, 6, 7, 7 };
|
|
||||||
return DeBruijnBytePos[
|
|
||||||
((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
|
|
||||||
# endif
|
|
||||||
} else { /* 32 bits */
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
unsigned long r=0;
|
|
||||||
_BitScanForward( &r, (U32)val );
|
|
||||||
return (unsigned)(r>>3);
|
|
||||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
|
||||||
return (__builtin_ctz((U32)val) >> 3);
|
|
||||||
# else
|
|
||||||
static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
|
|
||||||
3, 2, 2, 1, 3, 2, 0, 1,
|
|
||||||
3, 3, 1, 2, 2, 2, 2, 0,
|
|
||||||
3, 1, 2, 0, 1, 0, 1, 1 };
|
|
||||||
return DeBruijnBytePos[
|
|
||||||
((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
} else { /* Big Endian CPU */
|
|
||||||
if (MEM_64bits()) {
|
|
||||||
# if defined(_MSC_VER) && defined(_WIN64)
|
|
||||||
unsigned long r = 0;
|
|
||||||
_BitScanReverse64( &r, val );
|
|
||||||
return (unsigned)(r>>3);
|
|
||||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
|
||||||
return (__builtin_clzll(val) >> 3);
|
|
||||||
# else
|
|
||||||
unsigned r;
|
|
||||||
/* calculate this way due to compiler complaining in 32-bits mode */
|
|
||||||
const unsigned n32 = sizeof(size_t)*4;
|
|
||||||
if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
|
|
||||||
if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
|
|
||||||
r += (!val);
|
|
||||||
return r;
|
|
||||||
# endif
|
|
||||||
} else { /* 32 bits */
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
unsigned long r = 0;
|
|
||||||
_BitScanReverse( &r, (unsigned long)val );
|
|
||||||
return (unsigned)(r>>3);
|
|
||||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
|
||||||
return (__builtin_clz((U32)val) >> 3);
|
|
||||||
# else
|
|
||||||
unsigned r;
|
|
||||||
if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
|
|
||||||
r += (!val);
|
|
||||||
return r;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// From lib/compress/zstd_compress.c
|
|
||||||
static size_t ZSTD_count(const BYTE *pIn, const BYTE *pMatch,
|
|
||||||
const BYTE *const pInLimit) {
|
|
||||||
const BYTE * const pStart = pIn;
|
|
||||||
const BYTE * const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
|
|
||||||
|
|
||||||
while (pIn < pInLoopLimit) {
|
|
||||||
size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
|
|
||||||
if (!diff) {
|
|
||||||
pIn += sizeof(size_t);
|
|
||||||
pMatch += sizeof(size_t);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pIn += ZSTD_NbCommonBytes(diff);
|
|
||||||
return (size_t)(pIn - pStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MEM_64bits()) {
|
|
||||||
if ((pIn < (pInLimit - 3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) {
|
|
||||||
pIn += 4;
|
|
||||||
pMatch += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((pIn < (pInLimit - 1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) {
|
|
||||||
pIn += 2;
|
|
||||||
pMatch += 2;
|
|
||||||
}
|
|
||||||
if ((pIn < pInLimit) && (*pMatch == *pIn)) {
|
|
||||||
pIn++;
|
|
||||||
}
|
|
||||||
return (size_t)(pIn - pStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count number of bytes that match backwards before pIn and pMatch.
|
|
||||||
*
|
|
||||||
* We count only bytes where pMatch > pBase and pIn > pAnchor.
|
|
||||||
*/
|
|
||||||
static size_t countBackwardsMatch(const BYTE *pIn, const BYTE *pAnchor,
|
|
||||||
const BYTE *pMatch, const BYTE *pBase) {
|
|
||||||
size_t matchLength = 0;
|
|
||||||
while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
|
|
||||||
pIn--;
|
|
||||||
pMatch--;
|
|
||||||
matchLength++;
|
|
||||||
}
|
|
||||||
return matchLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a pointer to the entry in the hash table matching the hash and
|
|
||||||
* checksum with the "longest match length" as defined below. The forward and
|
|
||||||
* backward match lengths are written to *pForwardMatchLength and
|
|
||||||
* *pBackwardMatchLength.
|
|
||||||
*
|
|
||||||
* The match length is defined based on cctx->ip and the entry's offset.
|
|
||||||
* The forward match is computed from cctx->ip and entry->offset + cctx->ibase.
|
|
||||||
* The backward match is computed backwards from cctx->ip and
|
|
||||||
* cctx->ibase only if the forward match is longer than LDM_MIN_MATCH_LENGTH.
|
|
||||||
*/
|
|
||||||
static LDM_hashEntry *HASH_getBestEntry(const LDM_CCtx *cctx,
|
|
||||||
const hash_t hash,
|
|
||||||
const U32 checksum,
|
|
||||||
U64 *pForwardMatchLength,
|
|
||||||
U64 *pBackwardMatchLength) {
|
|
||||||
LDM_hashTable *table = cctx->hashTable;
|
|
||||||
LDM_hashEntry *bucket = getBucket(table, hash);
|
|
||||||
LDM_hashEntry *cur;
|
|
||||||
LDM_hashEntry *bestEntry = NULL;
|
|
||||||
U64 bestMatchLength = 0;
|
|
||||||
#if !(USE_CHECKSUM)
|
|
||||||
(void)checksum;
|
|
||||||
#endif
|
|
||||||
for (cur = bucket; cur < bucket + HASH_BUCKET_SIZE; ++cur) {
|
|
||||||
const BYTE *pMatch = cur->offset + cctx->ibase;
|
|
||||||
|
|
||||||
// Check checksum for faster check.
|
|
||||||
#if USE_CHECKSUM
|
|
||||||
if (cur->checksum == checksum &&
|
|
||||||
cctx->ip - pMatch <= LDM_WINDOW_SIZE) {
|
|
||||||
#else
|
|
||||||
if (cctx->ip - pMatch <= LDM_WINDOW_SIZE) {
|
|
||||||
#endif
|
|
||||||
U64 forwardMatchLength = ZSTD_count(cctx->ip, pMatch, cctx->iend);
|
|
||||||
U64 backwardMatchLength, totalMatchLength;
|
|
||||||
|
|
||||||
// Only take matches where the forward match length is large enough
|
|
||||||
// for speed.
|
|
||||||
if (forwardMatchLength < LDM_MIN_MATCH_LENGTH) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
backwardMatchLength =
|
|
||||||
countBackwardsMatch(cctx->ip, cctx->anchor,
|
|
||||||
cur->offset + cctx->ibase,
|
|
||||||
cctx->ibase);
|
|
||||||
|
|
||||||
totalMatchLength = forwardMatchLength + backwardMatchLength;
|
|
||||||
|
|
||||||
if (totalMatchLength >= bestMatchLength) {
|
|
||||||
bestMatchLength = totalMatchLength;
|
|
||||||
*pForwardMatchLength = forwardMatchLength;
|
|
||||||
*pBackwardMatchLength = backwardMatchLength;
|
|
||||||
|
|
||||||
bestEntry = cur;
|
|
||||||
#ifdef ZSTD_SKIP
|
|
||||||
return cur;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (bestEntry != NULL) {
|
|
||||||
return bestEntry;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert an entry into the hash table. The table uses a "circular buffer",
|
|
||||||
* with the oldest entry overwritten.
|
|
||||||
*/
|
|
||||||
static void HASH_insert(LDM_hashTable *table,
|
|
||||||
const hash_t hash, const LDM_hashEntry entry) {
|
|
||||||
*(getBucket(table, hash) + table->bucketOffsets[hash]) = entry;
|
|
||||||
table->bucketOffsets[hash]++;
|
|
||||||
table->bucketOffsets[hash] &= HASH_BUCKET_SIZE - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HASH_outputTableOccupancy(const LDM_hashTable *table) {
|
|
||||||
U32 ctr = 0;
|
|
||||||
LDM_hashEntry *cur = table->entries;
|
|
||||||
LDM_hashEntry *end = table->entries + (table->numBuckets * HASH_BUCKET_SIZE);
|
|
||||||
for (; cur < end; ++cur) {
|
|
||||||
if (cur->offset == 0) {
|
|
||||||
ctr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The number of buckets is repeated as a check for now.
|
|
||||||
printf("Num buckets, bucket size: %d (2^%d), %d\n",
|
|
||||||
table->numBuckets, NUM_HASH_BUCKETS_LOG, HASH_BUCKET_SIZE);
|
|
||||||
printf("Hash table size, empty slots, %% empty: %u, %u, %.3f\n",
|
|
||||||
table->numEntries, ctr,
|
|
||||||
100.0 * (double)(ctr) / table->numEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This can be done more efficiently, for example by using builtin
|
|
||||||
// functions (but it is not that important as it is only used for computing
|
|
||||||
// stats).
|
|
||||||
static int intLog2(U64 x) {
|
|
||||||
int ret = 0;
|
|
||||||
while (x >>= 1) {
|
|
||||||
ret++;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LDM_printCompressStats(const LDM_compressStats *stats) {
|
|
||||||
printf("=====================\n");
|
|
||||||
printf("Compression statistics\n");
|
|
||||||
printf("Window size, hash table size (bytes): 2^%u, 2^%u\n",
|
|
||||||
stats->windowSizeLog, stats->hashTableSizeLog);
|
|
||||||
printf("num matches, total match length, %% matched: %u, %llu, %.3f\n",
|
|
||||||
stats->numMatches,
|
|
||||||
stats->totalMatchLength,
|
|
||||||
100.0 * (double)stats->totalMatchLength /
|
|
||||||
(double)(stats->totalMatchLength + stats->totalLiteralLength));
|
|
||||||
printf("avg match length: %.1f\n", ((double)stats->totalMatchLength) /
|
|
||||||
(double)stats->numMatches);
|
|
||||||
printf("avg literal length, total literalLength: %.1f, %llu\n",
|
|
||||||
((double)stats->totalLiteralLength) / (double)stats->numMatches,
|
|
||||||
stats->totalLiteralLength);
|
|
||||||
printf("avg offset length: %.1f\n",
|
|
||||||
((double)stats->totalOffset) / (double)stats->numMatches);
|
|
||||||
printf("min offset, max offset: %u, %u\n",
|
|
||||||
stats->minOffset, stats->maxOffset);
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
printf("offset histogram | match length histogram\n");
|
|
||||||
printf("offset/ML, num matches, %% of matches | num matches, %% of matches\n");
|
|
||||||
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int logMaxOffset = intLog2(stats->maxOffset);
|
|
||||||
for (i = 0; i <= logMaxOffset; i++) {
|
|
||||||
printf("2^%*d: %10u %6.3f%% |2^%*d: %10u %6.3f \n",
|
|
||||||
2, i,
|
|
||||||
stats->offsetHistogram[i],
|
|
||||||
100.0 * (double) stats->offsetHistogram[i] /
|
|
||||||
(double) stats->numMatches,
|
|
||||||
2, i,
|
|
||||||
stats->matchLengthHistogram[i],
|
|
||||||
100.0 * (double) stats->matchLengthHistogram[i] /
|
|
||||||
(double) stats->numMatches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
printf("=====================\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the upper (most significant) NUM_HASH_BUCKETS_LOG bits.
|
|
||||||
*/
|
|
||||||
static hash_t getSmallHash(U64 hash) {
|
|
||||||
return hash >> (64 - NUM_HASH_BUCKETS_LOG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the 32 bits after the upper NUM_HASH_BUCKETS_LOG bits.
|
|
||||||
*/
|
|
||||||
static U32 getChecksum(U64 hash) {
|
|
||||||
return (hash >> (64 - 32 - NUM_HASH_BUCKETS_LOG)) & 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if INSERT_BY_TAG
|
|
||||||
static U32 lowerBitsFromHfHash(U64 hash) {
|
|
||||||
// The number of bits used so far is NUM_HASH_BUCKETS_LOG + 32.
|
|
||||||
// So there are 32 - NUM_HASH_BUCKETS_LOG bits left.
|
|
||||||
// Occasional hashing requires HASH_ONLY_EVERY_LOG bits.
|
|
||||||
// So if 32 - LDMHASHLOG < HASH_ONLY_EVERY_LOG, just return lower bits
|
|
||||||
// allowing for reuse of bits.
|
|
||||||
if (32 - NUM_HASH_BUCKETS_LOG < HASH_ONLY_EVERY_LOG) {
|
|
||||||
return hash & HASH_ONLY_EVERY;
|
|
||||||
} else {
|
|
||||||
// Otherwise shift by
|
|
||||||
// (32 - NUM_HASH_BUCKETS_LOG - HASH_ONLY_EVERY_LOG) bits first.
|
|
||||||
return (hash >> (32 - NUM_HASH_BUCKETS_LOG - HASH_ONLY_EVERY_LOG)) &
|
|
||||||
HASH_ONLY_EVERY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a 64-bit hash using the first len bytes from buf.
|
|
||||||
*
|
|
||||||
* Giving bytes s = s_1, s_2, ... s_k, the hash is defined to be
|
|
||||||
* H(s) = s_1*(a^(k-1)) + s_2*(a^(k-2)) + ... + s_k*(a^0)
|
|
||||||
*
|
|
||||||
* where the constant a is defined to be prime8bytes.
|
|
||||||
*
|
|
||||||
* The implementation adds an offset to each byte, so
|
|
||||||
* H(s) = (s_1 + HASH_CHAR_OFFSET)*(a^(k-1)) + ...
|
|
||||||
*/
|
|
||||||
static U64 getHash(const BYTE *buf, U32 len) {
|
|
||||||
U64 ret = 0;
|
|
||||||
U32 i;
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
ret *= prime8bytes;
|
|
||||||
ret += buf[i] + HASH_CHAR_OFFSET;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static U64 ipow(U64 base, U64 exp) {
|
|
||||||
U64 ret = 1;
|
|
||||||
while (exp) {
|
|
||||||
if (exp & 1) {
|
|
||||||
ret *= base;
|
|
||||||
}
|
|
||||||
exp >>= 1;
|
|
||||||
base *= base;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static U64 updateHash(U64 hash, U32 len,
|
|
||||||
BYTE toRemove, BYTE toAdd) {
|
|
||||||
// TODO: this relies on compiler optimization.
|
|
||||||
// The exponential can be calculated explicitly as len is constant.
|
|
||||||
hash -= ((toRemove + HASH_CHAR_OFFSET) *
|
|
||||||
ipow(prime8bytes, len - 1));
|
|
||||||
hash *= prime8bytes;
|
|
||||||
hash += toAdd + HASH_CHAR_OFFSET;
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update cctx->nextHash and cctx->nextPosHashed
|
|
||||||
* based on cctx->lastHash and cctx->lastPosHashed.
|
|
||||||
*
|
|
||||||
* This uses a rolling hash and requires that the last position hashed
|
|
||||||
* corresponds to cctx->nextIp - step.
|
|
||||||
*/
|
|
||||||
static void setNextHash(LDM_CCtx *cctx) {
|
|
||||||
cctx->nextHash = updateHash(
|
|
||||||
cctx->lastHash, LDM_HASH_LENGTH,
|
|
||||||
cctx->lastPosHashed[0],
|
|
||||||
cctx->lastPosHashed[LDM_HASH_LENGTH]);
|
|
||||||
cctx->nextPosHashed = cctx->nextIp;
|
|
||||||
|
|
||||||
#if LDM_LAG
|
|
||||||
if (cctx->ip - cctx->ibase > LDM_LAG) {
|
|
||||||
cctx->lagHash = updateHash(
|
|
||||||
cctx->lagHash, LDM_HASH_LENGTH,
|
|
||||||
cctx->lagIp[0], cctx->lagIp[LDM_HASH_LENGTH]);
|
|
||||||
cctx->lagIp++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void putHashOfCurrentPositionFromHash(LDM_CCtx *cctx, U64 hash) {
|
|
||||||
// Hash only every HASH_ONLY_EVERY times, based on cctx->ip.
|
|
||||||
// Note: this works only when cctx->step is 1.
|
|
||||||
#if LDM_LAG
|
|
||||||
if (cctx -> lagIp - cctx->ibase > 0) {
|
|
||||||
#if INSERT_BY_TAG
|
|
||||||
U32 hashEveryMask = lowerBitsFromHfHash(cctx->lagHash);
|
|
||||||
if (hashEveryMask == HASH_ONLY_EVERY) {
|
|
||||||
#else
|
|
||||||
if (((cctx->ip - cctx->ibase) & HASH_ONLY_EVERY) == HASH_ONLY_EVERY) {
|
|
||||||
#endif
|
|
||||||
U32 smallHash = getSmallHash(cctx->lagHash);
|
|
||||||
|
|
||||||
# if USE_CHECKSUM
|
|
||||||
U32 checksum = getChecksum(cctx->lagHash);
|
|
||||||
const LDM_hashEntry entry = { cctx->lagIp - cctx->ibase, checksum };
|
|
||||||
# else
|
|
||||||
const LDM_hashEntry entry = { cctx->lagIp - cctx->ibase };
|
|
||||||
# endif
|
|
||||||
|
|
||||||
HASH_insert(cctx->hashTable, smallHash, entry);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#endif // LDM_LAG
|
|
||||||
#if INSERT_BY_TAG
|
|
||||||
U32 hashEveryMask = lowerBitsFromHfHash(hash);
|
|
||||||
if (hashEveryMask == HASH_ONLY_EVERY) {
|
|
||||||
#else
|
|
||||||
if (((cctx->ip - cctx->ibase) & HASH_ONLY_EVERY) == HASH_ONLY_EVERY) {
|
|
||||||
#endif
|
|
||||||
U32 smallHash = getSmallHash(hash);
|
|
||||||
|
|
||||||
#if USE_CHECKSUM
|
|
||||||
U32 checksum = getChecksum(hash);
|
|
||||||
const LDM_hashEntry entry = { cctx->ip - cctx->ibase, checksum };
|
|
||||||
#else
|
|
||||||
const LDM_hashEntry entry = { cctx->ip - cctx->ibase };
|
|
||||||
#endif
|
|
||||||
HASH_insert(cctx->hashTable, smallHash, entry);
|
|
||||||
}
|
|
||||||
#if LDM_LAG
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cctx->lastPosHashed = cctx->ip;
|
|
||||||
cctx->lastHash = hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy over the cctx->lastHash, and cctx->lastPosHashed
|
|
||||||
* fields from the "next" fields.
|
|
||||||
*
|
|
||||||
* This requires that cctx->ip == cctx->nextPosHashed.
|
|
||||||
*/
|
|
||||||
static void LDM_updateLastHashFromNextHash(LDM_CCtx *cctx) {
|
|
||||||
putHashOfCurrentPositionFromHash(cctx, cctx->nextHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert hash of the current position into the hash table.
|
|
||||||
*/
|
|
||||||
static void LDM_putHashOfCurrentPosition(LDM_CCtx *cctx) {
|
|
||||||
U64 hash = getHash(cctx->ip, LDM_HASH_LENGTH);
|
|
||||||
|
|
||||||
putHashOfCurrentPositionFromHash(cctx, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t LDM_initializeCCtx(LDM_CCtx *cctx,
|
|
||||||
const void *src, size_t srcSize,
|
|
||||||
void *dst, size_t maxDstSize) {
|
|
||||||
cctx->isize = srcSize;
|
|
||||||
cctx->maxOSize = maxDstSize;
|
|
||||||
|
|
||||||
cctx->ibase = (const BYTE *)src;
|
|
||||||
cctx->ip = cctx->ibase;
|
|
||||||
cctx->iend = cctx->ibase + srcSize;
|
|
||||||
|
|
||||||
cctx->ihashLimit = cctx->iend - LDM_HASH_LENGTH;
|
|
||||||
cctx->imatchLimit = cctx->iend - LDM_MIN_MATCH_LENGTH;
|
|
||||||
|
|
||||||
cctx->obase = (BYTE *)dst;
|
|
||||||
cctx->op = (BYTE *)dst;
|
|
||||||
|
|
||||||
cctx->anchor = cctx->ibase;
|
|
||||||
|
|
||||||
memset(&(cctx->stats), 0, sizeof(cctx->stats));
|
|
||||||
#if USE_CHECKSUM
|
|
||||||
cctx->hashTable = HASH_createTable(LDM_HASHTABLESIZE_U64);
|
|
||||||
#else
|
|
||||||
cctx->hashTable = HASH_createTable(LDM_HASHTABLESIZE_U32);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!cctx->hashTable) return 1;
|
|
||||||
|
|
||||||
cctx->stats.minOffset = UINT_MAX;
|
|
||||||
cctx->stats.windowSizeLog = LDM_WINDOW_SIZE_LOG;
|
|
||||||
cctx->stats.hashTableSizeLog = LDM_MEMORY_USAGE;
|
|
||||||
|
|
||||||
cctx->lastPosHashed = NULL;
|
|
||||||
|
|
||||||
cctx->step = 1; // Fixed to be 1 for now. Changing may break things.
|
|
||||||
cctx->nextIp = cctx->ip + cctx->step;
|
|
||||||
cctx->nextPosHashed = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LDM_destroyCCtx(LDM_CCtx *cctx) {
|
|
||||||
HASH_destroyTable(cctx->hashTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the "best" match.
|
|
||||||
*
|
|
||||||
* Returns 0 if successful and 1 otherwise (i.e. no match can be found
|
|
||||||
* in the remaining input that is long enough).
|
|
||||||
*
|
|
||||||
* forwardMatchLength contains the forward length of the match.
|
|
||||||
*/
|
|
||||||
static int LDM_findBestMatch(LDM_CCtx *cctx, const BYTE **match,
|
|
||||||
U64 *forwardMatchLength, U64 *backwardMatchLength) {
|
|
||||||
|
|
||||||
LDM_hashEntry *entry = NULL;
|
|
||||||
cctx->nextIp = cctx->ip + cctx->step;
|
|
||||||
|
|
||||||
while (entry == NULL) {
|
|
||||||
U64 hash;
|
|
||||||
hash_t smallHash;
|
|
||||||
U32 checksum;
|
|
||||||
#if INSERT_BY_TAG
|
|
||||||
U32 hashEveryMask;
|
|
||||||
#endif
|
|
||||||
setNextHash(cctx);
|
|
||||||
|
|
||||||
hash = cctx->nextHash;
|
|
||||||
smallHash = getSmallHash(hash);
|
|
||||||
checksum = getChecksum(hash);
|
|
||||||
#if INSERT_BY_TAG
|
|
||||||
hashEveryMask = lowerBitsFromHfHash(hash);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cctx->ip = cctx->nextIp;
|
|
||||||
cctx->nextIp += cctx->step;
|
|
||||||
|
|
||||||
if (cctx->ip > cctx->imatchLimit) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if INSERT_BY_TAG
|
|
||||||
if (hashEveryMask == HASH_ONLY_EVERY) {
|
|
||||||
|
|
||||||
entry = HASH_getBestEntry(cctx, smallHash, checksum,
|
|
||||||
forwardMatchLength, backwardMatchLength);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
entry = HASH_getBestEntry(cctx, smallHash, checksum,
|
|
||||||
forwardMatchLength, backwardMatchLength);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (entry != NULL) {
|
|
||||||
*match = entry->offset + cctx->ibase;
|
|
||||||
}
|
|
||||||
|
|
||||||
putHashOfCurrentPositionFromHash(cctx, hash);
|
|
||||||
|
|
||||||
}
|
|
||||||
setNextHash(cctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LDM_encodeLiteralLengthAndLiterals(
|
|
||||||
LDM_CCtx *cctx, BYTE *pToken, const U64 literalLength) {
|
|
||||||
/* Encode the literal length. */
|
|
||||||
if (literalLength >= RUN_MASK) {
|
|
||||||
U64 len = (U64)literalLength - RUN_MASK;
|
|
||||||
*pToken = (RUN_MASK << ML_BITS);
|
|
||||||
for (; len >= 255; len -= 255) {
|
|
||||||
*(cctx->op)++ = 255;
|
|
||||||
}
|
|
||||||
*(cctx->op)++ = (BYTE)len;
|
|
||||||
} else {
|
|
||||||
*pToken = (BYTE)(literalLength << ML_BITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Encode the literals. */
|
|
||||||
memcpy(cctx->op, cctx->anchor, literalLength);
|
|
||||||
cctx->op += literalLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LDM_outputBlock(LDM_CCtx *cctx,
|
|
||||||
const U64 literalLength,
|
|
||||||
const U32 offset,
|
|
||||||
const U64 matchLength) {
|
|
||||||
BYTE *pToken = cctx->op++;
|
|
||||||
|
|
||||||
/* Encode the literal length and literals. */
|
|
||||||
LDM_encodeLiteralLengthAndLiterals(cctx, pToken, literalLength);
|
|
||||||
|
|
||||||
/* Encode the offset. */
|
|
||||||
MEM_write32(cctx->op, offset);
|
|
||||||
cctx->op += LDM_OFFSET_SIZE;
|
|
||||||
|
|
||||||
/* Encode the match length. */
|
|
||||||
if (matchLength >= ML_MASK) {
|
|
||||||
U64 matchLengthRemaining = matchLength;
|
|
||||||
*pToken += ML_MASK;
|
|
||||||
matchLengthRemaining -= ML_MASK;
|
|
||||||
MEM_write32(cctx->op, 0xFFFFFFFF);
|
|
||||||
while (matchLengthRemaining >= 4*0xFF) {
|
|
||||||
cctx->op += 4;
|
|
||||||
MEM_write32(cctx->op, 0xffffffff);
|
|
||||||
matchLengthRemaining -= 4*0xFF;
|
|
||||||
}
|
|
||||||
cctx->op += matchLengthRemaining / 255;
|
|
||||||
*(cctx->op)++ = (BYTE)(matchLengthRemaining % 255);
|
|
||||||
} else {
|
|
||||||
*pToken += (BYTE)(matchLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: maxDstSize is unused. This function may seg fault when writing
|
|
||||||
// beyond the size of dst, as it does not check maxDstSize. Writing to
|
|
||||||
// a buffer and performing checks is a possible solution.
|
|
||||||
//
|
|
||||||
// This is based upon lz4.
|
|
||||||
size_t LDM_compress(const void *src, size_t srcSize,
|
|
||||||
void *dst, size_t maxDstSize) {
|
|
||||||
LDM_CCtx cctx;
|
|
||||||
const BYTE *match = NULL;
|
|
||||||
U64 forwardMatchLength = 0;
|
|
||||||
U64 backwardsMatchLength = 0;
|
|
||||||
|
|
||||||
if (LDM_initializeCCtx(&cctx, src, srcSize, dst, maxDstSize)) {
|
|
||||||
// Initialization failed.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef OUTPUT_CONFIGURATION
|
|
||||||
LDM_outputConfiguration();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Hash the first position and put it into the hash table. */
|
|
||||||
LDM_putHashOfCurrentPosition(&cctx);
|
|
||||||
|
|
||||||
cctx.lagIp = cctx.ip;
|
|
||||||
cctx.lagHash = cctx.lastHash;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a match.
|
|
||||||
* If no more matches can be found (i.e. the length of the remaining input
|
|
||||||
* is less than the minimum match length), then stop searching for matches
|
|
||||||
* and encode the final literals.
|
|
||||||
*/
|
|
||||||
while (!LDM_findBestMatch(&cctx, &match, &forwardMatchLength,
|
|
||||||
&backwardsMatchLength)) {
|
|
||||||
|
|
||||||
#ifdef COMPUTE_STATS
|
|
||||||
cctx.stats.numMatches++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cctx.ip -= backwardsMatchLength;
|
|
||||||
match -= backwardsMatchLength;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write current block (literals, literal length, match offset, match
|
|
||||||
* length) and update pointers and hashes.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
const U64 literalLength = cctx.ip - cctx.anchor;
|
|
||||||
const U32 offset = cctx.ip - match;
|
|
||||||
const U64 matchLength = forwardMatchLength +
|
|
||||||
backwardsMatchLength -
|
|
||||||
LDM_MIN_MATCH_LENGTH;
|
|
||||||
|
|
||||||
LDM_outputBlock(&cctx, literalLength, offset, matchLength);
|
|
||||||
|
|
||||||
#ifdef COMPUTE_STATS
|
|
||||||
cctx.stats.totalLiteralLength += literalLength;
|
|
||||||
cctx.stats.totalOffset += offset;
|
|
||||||
cctx.stats.totalMatchLength += matchLength + LDM_MIN_MATCH_LENGTH;
|
|
||||||
cctx.stats.minOffset =
|
|
||||||
offset < cctx.stats.minOffset ? offset : cctx.stats.minOffset;
|
|
||||||
cctx.stats.maxOffset =
|
|
||||||
offset > cctx.stats.maxOffset ? offset : cctx.stats.maxOffset;
|
|
||||||
cctx.stats.offsetHistogram[(U32)intLog2(offset)]++;
|
|
||||||
cctx.stats.matchLengthHistogram[
|
|
||||||
(U32)intLog2(matchLength + LDM_MIN_MATCH_LENGTH)]++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Move ip to end of block, inserting hashes at each position.
|
|
||||||
cctx.nextIp = cctx.ip + cctx.step;
|
|
||||||
while (cctx.ip < cctx.anchor + LDM_MIN_MATCH_LENGTH +
|
|
||||||
matchLength + literalLength) {
|
|
||||||
if (cctx.ip > cctx.lastPosHashed) {
|
|
||||||
// TODO: Simplify.
|
|
||||||
LDM_updateLastHashFromNextHash(&cctx);
|
|
||||||
setNextHash(&cctx);
|
|
||||||
}
|
|
||||||
cctx.ip++;
|
|
||||||
cctx.nextIp++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set start of next block to current input pointer.
|
|
||||||
cctx.anchor = cctx.ip;
|
|
||||||
LDM_updateLastHashFromNextHash(&cctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Encode the last literals (no more matches). */
|
|
||||||
{
|
|
||||||
const U64 lastRun = cctx.iend - cctx.anchor;
|
|
||||||
BYTE *pToken = cctx.op++;
|
|
||||||
LDM_encodeLiteralLengthAndLiterals(&cctx, pToken, lastRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef COMPUTE_STATS
|
|
||||||
LDM_printCompressStats(&cctx.stats);
|
|
||||||
HASH_outputTableOccupancy(cctx.hashTable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
|
||||||
const size_t ret = cctx.op - cctx.obase;
|
|
||||||
LDM_destroyCCtx(&cctx);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LDM_outputConfiguration(void) {
|
|
||||||
printf("=====================\n");
|
|
||||||
printf("Configuration\n");
|
|
||||||
printf("LDM_WINDOW_SIZE_LOG: %d\n", LDM_WINDOW_SIZE_LOG);
|
|
||||||
printf("LDM_MIN_MATCH_LENGTH, LDM_HASH_LENGTH: %d, %d\n",
|
|
||||||
LDM_MIN_MATCH_LENGTH, LDM_HASH_LENGTH);
|
|
||||||
printf("LDM_MEMORY_USAGE: %d\n", LDM_MEMORY_USAGE);
|
|
||||||
printf("HASH_ONLY_EVERY_LOG: %d\n", HASH_ONLY_EVERY_LOG);
|
|
||||||
printf("HASH_BUCKET_SIZE_LOG: %d\n", HASH_BUCKET_SIZE_LOG);
|
|
||||||
printf("LDM_LAG: %d\n", LDM_LAG);
|
|
||||||
printf("USE_CHECKSUM: %d\n", USE_CHECKSUM);
|
|
||||||
printf("INSERT_BY_TAG: %d\n", INSERT_BY_TAG);
|
|
||||||
printf("HASH_CHAR_OFFSET: %d\n", HASH_CHAR_OFFSET);
|
|
||||||
printf("=====================\n");
|
|
||||||
}
|
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
#ifndef LDM_H
|
|
||||||
#define LDM_H
|
|
||||||
|
|
||||||
#include "mem.h" // from /lib/common/mem.h
|
|
||||||
|
|
||||||
//#include "ldm_params.h"
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Modify the parameters in ldm_params.h if "ldm_params.h" is included.
|
|
||||||
// Otherwise, modify the parameters here.
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
#ifndef LDM_PARAMS_H
|
|
||||||
// Defines the size of the hash table.
|
|
||||||
// Note that this is not the number of buckets.
|
|
||||||
// Currently this should be less than WINDOW_SIZE_LOG + 4.
|
|
||||||
#define LDM_MEMORY_USAGE 23
|
|
||||||
|
|
||||||
// The number of entries in a hash bucket.
|
|
||||||
#define HASH_BUCKET_SIZE_LOG 3 // The maximum is 4 for now.
|
|
||||||
|
|
||||||
// Defines the lag in inserting elements into the hash table.
|
|
||||||
#define LDM_LAG 0
|
|
||||||
|
|
||||||
// The maximum window size when searching for matches.
|
|
||||||
// The maximum value is 30
|
|
||||||
#define LDM_WINDOW_SIZE_LOG 28
|
|
||||||
|
|
||||||
// The minimum match length.
|
|
||||||
// This should be a multiple of four.
|
|
||||||
#define LDM_MIN_MATCH_LENGTH 64
|
|
||||||
|
|
||||||
// If INSERT_BY_TAG, insert entries into the hash table as a function of the
|
|
||||||
// hash. Certain hashes will not be inserted.
|
|
||||||
//
|
|
||||||
// Otherwise, insert as a function of the position.
|
|
||||||
#define INSERT_BY_TAG 1
|
|
||||||
|
|
||||||
// Store a checksum with the hash table entries for faster comparison.
|
|
||||||
// This halves the number of entries the hash table can contain.
|
|
||||||
#define USE_CHECKSUM 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Output compression statistics.
|
|
||||||
#define COMPUTE_STATS
|
|
||||||
|
|
||||||
// Output the configuration.
|
|
||||||
#define OUTPUT_CONFIGURATION
|
|
||||||
|
|
||||||
// If defined, forces the probability of insertion to be approximately
|
|
||||||
// one per (1 << HASH_ONLY_EVERY_LOG). If not defined, the probability will be
|
|
||||||
// calculated based on the memory usage and window size for "even" insertion
|
|
||||||
// throughout the window.
|
|
||||||
|
|
||||||
// #define HASH_ONLY_EVERY_LOG 8
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// The number of bytes storing the compressed and decompressed size
|
|
||||||
// in the header.
|
|
||||||
#define LDM_COMPRESSED_SIZE 8
|
|
||||||
#define LDM_DECOMPRESSED_SIZE 8
|
|
||||||
#define LDM_HEADER_SIZE ((LDM_COMPRESSED_SIZE)+(LDM_DECOMPRESSED_SIZE))
|
|
||||||
|
|
||||||
#define ML_BITS 4
|
|
||||||
#define ML_MASK ((1U<<ML_BITS)-1)
|
|
||||||
#define RUN_BITS (8-ML_BITS)
|
|
||||||
#define RUN_MASK ((1U<<RUN_BITS)-1)
|
|
||||||
|
|
||||||
// The number of bytes storing the offset.
|
|
||||||
#define LDM_OFFSET_SIZE 4
|
|
||||||
|
|
||||||
#define LDM_WINDOW_SIZE (1 << (LDM_WINDOW_SIZE_LOG))
|
|
||||||
|
|
||||||
// TODO: Match lengths that are too small do not use the hash table efficiently.
|
|
||||||
// There should be a minimum hash length given the hash table size.
|
|
||||||
#define LDM_HASH_LENGTH LDM_MIN_MATCH_LENGTH
|
|
||||||
|
|
||||||
typedef struct LDM_compressStats LDM_compressStats;
|
|
||||||
typedef struct LDM_CCtx LDM_CCtx;
|
|
||||||
typedef struct LDM_DCtx LDM_DCtx;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compresses src into dst.
|
|
||||||
* Returns the compressed size if successful, 0 otherwise.
|
|
||||||
*
|
|
||||||
* NB: This currently ignores maxDstSize and assumes enough space is available.
|
|
||||||
*
|
|
||||||
* Block format (see lz4 documentation for more information):
|
|
||||||
* github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md
|
|
||||||
*
|
|
||||||
* A block is composed of sequences. Each sequence begins with a token, which
|
|
||||||
* is a one-byte value separated into two 4-bit fields.
|
|
||||||
*
|
|
||||||
* The first field uses the four high bits of the token and encodes the literal
|
|
||||||
* length. If the field value is 0, there is no literal. If it is 15,
|
|
||||||
* additional bytes are added (each ranging from 0 to 255) to the previous
|
|
||||||
* value to produce a total length.
|
|
||||||
*
|
|
||||||
* Following the token and optional length bytes are the literals.
|
|
||||||
*
|
|
||||||
* Next are the 4 bytes representing the offset of the match (2 in lz4),
|
|
||||||
* representing the position to copy the literals.
|
|
||||||
*
|
|
||||||
* The lower four bits of the token encode the match length. With additional
|
|
||||||
* bytes added similarly to the additional literal length bytes after the offset.
|
|
||||||
*
|
|
||||||
* The last sequence is incomplete and stops right after the literals.
|
|
||||||
*/
|
|
||||||
size_t LDM_compress(const void *src, size_t srcSize,
|
|
||||||
void *dst, size_t maxDstSize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the compression context.
|
|
||||||
*
|
|
||||||
* Allocates memory for the hash table.
|
|
||||||
*
|
|
||||||
* Returns 0 if successful, 1 otherwise.
|
|
||||||
*/
|
|
||||||
size_t LDM_initializeCCtx(LDM_CCtx *cctx,
|
|
||||||
const void *src, size_t srcSize,
|
|
||||||
void *dst, size_t maxDstSize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees up memory allocated in LDM_initializeCCtx().
|
|
||||||
*/
|
|
||||||
void LDM_destroyCCtx(LDM_CCtx *cctx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the distribution of offsets in the hash table.
|
|
||||||
*
|
|
||||||
* The offsets are defined as the distance of the hash table entry from the
|
|
||||||
* current input position of the cctx.
|
|
||||||
*/
|
|
||||||
void LDM_outputHashTableOffsetHistogram(const LDM_CCtx *cctx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs compression statistics to stdout.
|
|
||||||
*/
|
|
||||||
void LDM_printCompressStats(const LDM_compressStats *stats);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode the literal length followed by the literals.
|
|
||||||
*
|
|
||||||
* The literal length is written to the upper four bits of pToken, with
|
|
||||||
* additional bytes written to the output as needed (see lz4).
|
|
||||||
*
|
|
||||||
* This is followed by literalLength bytes corresponding to the literals.
|
|
||||||
*/
|
|
||||||
void LDM_encodeLiteralLengthAndLiterals(LDM_CCtx *cctx, BYTE *pToken,
|
|
||||||
const U64 literalLength);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write current block (literals, literal length, match offset,
|
|
||||||
* match length).
|
|
||||||
*/
|
|
||||||
void LDM_outputBlock(LDM_CCtx *cctx,
|
|
||||||
const U64 literalLength,
|
|
||||||
const U32 offset,
|
|
||||||
const U64 matchLength);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decompresses src into dst.
|
|
||||||
*
|
|
||||||
* Note: assumes src does not have a header.
|
|
||||||
*/
|
|
||||||
size_t LDM_decompress(const void *src, size_t srcSize,
|
|
||||||
void *dst, size_t maxDstSize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the decompression context.
|
|
||||||
*/
|
|
||||||
void LDM_initializeDCtx(LDM_DCtx *dctx,
|
|
||||||
const void *src, size_t compressedSize,
|
|
||||||
void *dst, size_t maxDecompressedSize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the header from src and writes the compressed size and
|
|
||||||
* decompressed size into compressedSize and decompressedSize respectively.
|
|
||||||
*
|
|
||||||
* NB: LDM_compress and LDM_decompress currently do not add/read headers.
|
|
||||||
*/
|
|
||||||
void LDM_readHeader(const void *src, U64 *compressedSize,
|
|
||||||
U64 *decompressedSize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the compressed and decompressed size.
|
|
||||||
*/
|
|
||||||
void LDM_writeHeader(void *memPtr, U64 compressedSize,
|
|
||||||
U64 decompressedSize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output the configuration used.
|
|
||||||
*/
|
|
||||||
void LDM_outputConfiguration(void);
|
|
||||||
|
|
||||||
#endif /* LDM_H */
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "ldm.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function reads the header at the beginning of src and writes
|
|
||||||
* the compressed and decompressed size to compressedSize and
|
|
||||||
* decompressedSize.
|
|
||||||
*
|
|
||||||
* The header consists of 16 bytes: 8 bytes each in little-endian format
|
|
||||||
* of the compressed size and the decompressed size.
|
|
||||||
*/
|
|
||||||
void LDM_readHeader(const void *src, U64 *compressedSize,
|
|
||||||
U64 *decompressedSize) {
|
|
||||||
const BYTE *ip = (const BYTE *)src;
|
|
||||||
*compressedSize = MEM_readLE64(ip);
|
|
||||||
*decompressedSize = MEM_readLE64(ip + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the 16-byte header (8-bytes each of the compressedSize and
|
|
||||||
* decompressedSize in little-endian format) to memPtr.
|
|
||||||
*/
|
|
||||||
void LDM_writeHeader(void *memPtr, U64 compressedSize,
|
|
||||||
U64 decompressedSize) {
|
|
||||||
MEM_writeLE64(memPtr, compressedSize);
|
|
||||||
MEM_writeLE64((BYTE *)memPtr + 8, decompressedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LDM_DCtx {
|
|
||||||
size_t compressedSize;
|
|
||||||
size_t maxDecompressedSize;
|
|
||||||
|
|
||||||
const BYTE *ibase; /* Base of input */
|
|
||||||
const BYTE *ip; /* Current input position */
|
|
||||||
const BYTE *iend; /* End of source */
|
|
||||||
|
|
||||||
const BYTE *obase; /* Base of output */
|
|
||||||
BYTE *op; /* Current output position */
|
|
||||||
const BYTE *oend; /* End of output */
|
|
||||||
};
|
|
||||||
|
|
||||||
void LDM_initializeDCtx(LDM_DCtx *dctx,
|
|
||||||
const void *src, size_t compressedSize,
|
|
||||||
void *dst, size_t maxDecompressedSize) {
|
|
||||||
dctx->compressedSize = compressedSize;
|
|
||||||
dctx->maxDecompressedSize = maxDecompressedSize;
|
|
||||||
|
|
||||||
dctx->ibase = src;
|
|
||||||
dctx->ip = (const BYTE *)src;
|
|
||||||
dctx->iend = dctx->ip + dctx->compressedSize;
|
|
||||||
dctx->op = dst;
|
|
||||||
dctx->oend = dctx->op + dctx->maxDecompressedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t LDM_decompress(const void *src, size_t compressedSize,
|
|
||||||
void *dst, size_t maxDecompressedSize) {
|
|
||||||
|
|
||||||
LDM_DCtx dctx;
|
|
||||||
LDM_initializeDCtx(&dctx, src, compressedSize, dst, maxDecompressedSize);
|
|
||||||
|
|
||||||
while (dctx.ip < dctx.iend) {
|
|
||||||
BYTE *cpy;
|
|
||||||
const BYTE *match;
|
|
||||||
size_t length, offset;
|
|
||||||
|
|
||||||
/* Get the literal length. */
|
|
||||||
const unsigned token = *(dctx.ip)++;
|
|
||||||
if ((length = (token >> ML_BITS)) == RUN_MASK) {
|
|
||||||
unsigned s;
|
|
||||||
do {
|
|
||||||
s = *(dctx.ip)++;
|
|
||||||
length += s;
|
|
||||||
} while (s == 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the literals. */
|
|
||||||
cpy = dctx.op + length;
|
|
||||||
memcpy(dctx.op, dctx.ip, length);
|
|
||||||
dctx.ip += length;
|
|
||||||
dctx.op = cpy;
|
|
||||||
|
|
||||||
//TODO: dynamic offset size?
|
|
||||||
/* Encode the offset. */
|
|
||||||
offset = MEM_read32(dctx.ip);
|
|
||||||
dctx.ip += LDM_OFFSET_SIZE;
|
|
||||||
match = dctx.op - offset;
|
|
||||||
|
|
||||||
/* Get the match length. */
|
|
||||||
length = token & ML_MASK;
|
|
||||||
if (length == ML_MASK) {
|
|
||||||
unsigned s;
|
|
||||||
do {
|
|
||||||
s = *(dctx.ip)++;
|
|
||||||
length += s;
|
|
||||||
} while (s == 255);
|
|
||||||
}
|
|
||||||
length += LDM_MIN_MATCH_LENGTH;
|
|
||||||
|
|
||||||
/* Copy match. */
|
|
||||||
cpy = dctx.op + length;
|
|
||||||
|
|
||||||
// TODO: this can be made more efficient.
|
|
||||||
while (match < cpy - offset && dctx.op < dctx.oend) {
|
|
||||||
*(dctx.op)++ = *match++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dctx.op - (BYTE *)dst;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef LDM_PARAMS_H
|
|
||||||
#define LDM_PARAMS_H
|
|
||||||
|
|
||||||
#define LDM_MEMORY_USAGE 23
|
|
||||||
#define HASH_BUCKET_SIZE_LOG 3
|
|
||||||
#define LDM_LAG 0
|
|
||||||
#define LDM_WINDOW_SIZE_LOG 28
|
|
||||||
#define LDM_MIN_MATCH_LENGTH 64
|
|
||||||
#define INSERT_BY_TAG 1
|
|
||||||
#define USE_CHECKSUM 1
|
|
||||||
|
|
||||||
#endif // LDM_PARAMS_H
|
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <zstd.h>
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include "ldm.h"
|
|
||||||
#include "zstd.h"
|
|
||||||
|
|
||||||
// #define DECOMPRESS_AND_VERIFY
|
|
||||||
|
|
||||||
/* Compress file given by fname and output to oname.
|
|
||||||
* Returns 0 if successful, error code otherwise.
|
|
||||||
*
|
|
||||||
* This adds a header from LDM_writeHeader to the beginning of the output.
|
|
||||||
*
|
|
||||||
* This might seg fault if the compressed size is > the decompress
|
|
||||||
* size due to the mmapping and output file size allocated to be the input size
|
|
||||||
* The compress function should check before writing or buffer writes.
|
|
||||||
*/
|
|
||||||
static int compress(const char *fname, const char *oname) {
|
|
||||||
int fdin, fdout;
|
|
||||||
struct stat statbuf;
|
|
||||||
char *src, *dst;
|
|
||||||
size_t maxCompressedSize, compressedSize;
|
|
||||||
|
|
||||||
struct timeval tv1, tv2;
|
|
||||||
double timeTaken;
|
|
||||||
|
|
||||||
|
|
||||||
/* Open the input file. */
|
|
||||||
if ((fdin = open(fname, O_RDONLY)) < 0) {
|
|
||||||
perror("Error in file opening");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the output file. */
|
|
||||||
if ((fdout = open(oname, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600)) < 0) {
|
|
||||||
perror("Can't create output file");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the size of the input file. */
|
|
||||||
if (fstat (fdin, &statbuf) < 0) {
|
|
||||||
perror("Fstat error");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
maxCompressedSize = (statbuf.st_size + LDM_HEADER_SIZE);
|
|
||||||
|
|
||||||
// Handle case where compressed size is > decompressed size.
|
|
||||||
// TODO: The compress function should check before writing or buffer writes.
|
|
||||||
maxCompressedSize += statbuf.st_size / 255;
|
|
||||||
|
|
||||||
ftruncate(fdout, maxCompressedSize);
|
|
||||||
|
|
||||||
/* mmap the input file. */
|
|
||||||
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0))
|
|
||||||
== (caddr_t) - 1) {
|
|
||||||
perror("mmap error for input");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mmap the output file. */
|
|
||||||
if ((dst = mmap(0, maxCompressedSize, PROT_READ | PROT_WRITE,
|
|
||||||
MAP_SHARED, fdout, 0)) == (caddr_t) - 1) {
|
|
||||||
perror("mmap error for output");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday(&tv1, NULL);
|
|
||||||
|
|
||||||
compressedSize = LDM_HEADER_SIZE +
|
|
||||||
LDM_compress(src, statbuf.st_size,
|
|
||||||
dst + LDM_HEADER_SIZE, maxCompressedSize);
|
|
||||||
|
|
||||||
gettimeofday(&tv2, NULL);
|
|
||||||
|
|
||||||
// Write the header.
|
|
||||||
LDM_writeHeader(dst, compressedSize, statbuf.st_size);
|
|
||||||
|
|
||||||
// Truncate file to compressedSize.
|
|
||||||
ftruncate(fdout, compressedSize);
|
|
||||||
|
|
||||||
printf("%25s : %10lu -> %10lu - %s \n", fname,
|
|
||||||
(size_t)statbuf.st_size, (size_t)compressedSize, oname);
|
|
||||||
printf("Compression ratio: %.2fx --- %.1f%%\n",
|
|
||||||
(double)statbuf.st_size / (double)compressedSize,
|
|
||||||
(double)compressedSize / (double)(statbuf.st_size) * 100.0);
|
|
||||||
|
|
||||||
timeTaken = (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
|
|
||||||
(double) (tv2.tv_sec - tv1.tv_sec),
|
|
||||||
|
|
||||||
printf("Total compress time = %.3f seconds, Average scanning speed: %.3f MB/s\n",
|
|
||||||
timeTaken,
|
|
||||||
((double)statbuf.st_size / (double) (1 << 20)) / timeTaken);
|
|
||||||
|
|
||||||
// Close files.
|
|
||||||
close(fdin);
|
|
||||||
close(fdout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DECOMPRESS_AND_VERIFY
|
|
||||||
/* Decompress file compressed using LDM_compress.
|
|
||||||
* The input file should have the LDM_HEADER followed by payload.
|
|
||||||
* Returns 0 if succesful, and an error code otherwise.
|
|
||||||
*/
|
|
||||||
static int decompress(const char *fname, const char *oname) {
|
|
||||||
int fdin, fdout;
|
|
||||||
struct stat statbuf;
|
|
||||||
char *src, *dst;
|
|
||||||
U64 compressedSize, decompressedSize;
|
|
||||||
size_t outSize;
|
|
||||||
|
|
||||||
/* Open the input file. */
|
|
||||||
if ((fdin = open(fname, O_RDONLY)) < 0) {
|
|
||||||
perror("Error in file opening");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the output file. */
|
|
||||||
if ((fdout = open(oname, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600)) < 0) {
|
|
||||||
perror("Can't create output file");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the size of the input file. */
|
|
||||||
if (fstat (fdin, &statbuf) < 0) {
|
|
||||||
perror("Fstat error");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mmap the input file. */
|
|
||||||
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0))
|
|
||||||
== (caddr_t) - 1) {
|
|
||||||
perror("mmap error for input");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the header. */
|
|
||||||
LDM_readHeader(src, &compressedSize, &decompressedSize);
|
|
||||||
|
|
||||||
ftruncate(fdout, decompressedSize);
|
|
||||||
|
|
||||||
/* mmap the output file */
|
|
||||||
if ((dst = mmap(0, decompressedSize, PROT_READ | PROT_WRITE,
|
|
||||||
MAP_SHARED, fdout, 0)) == (caddr_t) - 1) {
|
|
||||||
perror("mmap error for output");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
outSize = LDM_decompress(
|
|
||||||
src + LDM_HEADER_SIZE, statbuf.st_size - LDM_HEADER_SIZE,
|
|
||||||
dst, decompressedSize);
|
|
||||||
printf("Ret size out: %zu\n", outSize);
|
|
||||||
|
|
||||||
close(fdin);
|
|
||||||
close(fdout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compare two files.
|
|
||||||
* Returns 0 iff they are the same.
|
|
||||||
*/
|
|
||||||
static int compare(FILE *fp0, FILE *fp1) {
|
|
||||||
int result = 0;
|
|
||||||
while (result == 0) {
|
|
||||||
char b0[1024];
|
|
||||||
char b1[1024];
|
|
||||||
const size_t r0 = fread(b0, 1, sizeof(b0), fp0);
|
|
||||||
const size_t r1 = fread(b1, 1, sizeof(b1), fp1);
|
|
||||||
|
|
||||||
result = (int)r0 - (int)r1;
|
|
||||||
|
|
||||||
if (0 == r0 || 0 == r1) break;
|
|
||||||
|
|
||||||
if (0 == result) result = memcmp(b0, b1, r0);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify the input file is the same as the decompressed file. */
|
|
||||||
static int verify(const char *inpFilename, const char *decFilename) {
|
|
||||||
FILE *inpFp, *decFp;
|
|
||||||
|
|
||||||
if ((inpFp = fopen(inpFilename, "rb")) == NULL) {
|
|
||||||
perror("Could not open input file\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((decFp = fopen(decFilename, "rb")) == NULL) {
|
|
||||||
perror("Could not open decompressed file\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("verify : %s <-> %s\n", inpFilename, decFilename);
|
|
||||||
{
|
|
||||||
const int cmp = compare(inpFp, decFp);
|
|
||||||
if(0 == cmp) {
|
|
||||||
printf("verify : OK\n");
|
|
||||||
} else {
|
|
||||||
printf("verify : NG\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(decFp);
|
|
||||||
fclose(inpFp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
|
||||||
const char * const exeName = argv[0];
|
|
||||||
char inpFilename[256] = { 0 };
|
|
||||||
char ldmFilename[256] = { 0 };
|
|
||||||
char decFilename[256] = { 0 };
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
printf("Wrong arguments\n");
|
|
||||||
printf("Usage:\n");
|
|
||||||
printf("%s FILE\n", exeName);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(inpFilename, 256, "%s", argv[1]);
|
|
||||||
snprintf(ldmFilename, 256, "%s.ldm", argv[1]);
|
|
||||||
snprintf(decFilename, 256, "%s.ldm.dec", argv[1]);
|
|
||||||
|
|
||||||
printf("inp = [%s]\n", inpFilename);
|
|
||||||
printf("ldm = [%s]\n", ldmFilename);
|
|
||||||
printf("dec = [%s]\n", decFilename);
|
|
||||||
|
|
||||||
/* Compress */
|
|
||||||
{
|
|
||||||
if (compress(inpFilename, ldmFilename)) {
|
|
||||||
printf("Compress error\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DECOMPRESS_AND_VERIFY
|
|
||||||
/* Decompress */
|
|
||||||
{
|
|
||||||
struct timeval tv1, tv2;
|
|
||||||
gettimeofday(&tv1, NULL);
|
|
||||||
if (decompress(ldmFilename, decFilename)) {
|
|
||||||
printf("Decompress error\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
gettimeofday(&tv2, NULL);
|
|
||||||
printf("Total decompress time = %f seconds\n",
|
|
||||||
(double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
|
|
||||||
(double) (tv2.tv_sec - tv1.tv_sec));
|
|
||||||
}
|
|
||||||
/* verify */
|
|
||||||
if (verify(inpFilename, decFilename)) {
|
|
||||||
printf("Verification error\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -38,21 +38,45 @@ libzstd_srcs = [
|
|||||||
|
|
||||||
libzstd_includes = [include_directories(common_dir, dictbuilder_dir, compress_dir, lib_dir)]
|
libzstd_includes = [include_directories(common_dir, dictbuilder_dir, compress_dir, lib_dir)]
|
||||||
|
|
||||||
if get_option('legacy_support')
|
legacy = get_option('legacy_support')
|
||||||
message('Enabling legacy support')
|
if legacy == '0'
|
||||||
libzstd_cflags = ['-DZSTD_LEGACY_SUPPORT=4']
|
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')
|
legacy_dir = join_paths(lib_dir, 'legacy')
|
||||||
libzstd_includes += [include_directories(legacy_dir)]
|
libzstd_includes += [include_directories(legacy_dir)]
|
||||||
libzstd_srcs += [
|
if legacy_int <= 1
|
||||||
join_paths(legacy_dir, 'zstd_v01.c'),
|
libzstd_srcs += join_paths(legacy_dir, 'zstd_v01.c')
|
||||||
join_paths(legacy_dir, 'zstd_v02.c'),
|
endif
|
||||||
join_paths(legacy_dir, 'zstd_v03.c'),
|
if legacy_int <= 2
|
||||||
join_paths(legacy_dir, 'zstd_v04.c'),
|
libzstd_srcs += join_paths(legacy_dir, 'zstd_v02.c')
|
||||||
join_paths(legacy_dir, 'zstd_v05.c'),
|
endif
|
||||||
join_paths(legacy_dir, 'zstd_v06.c'),
|
if legacy_int <= 3
|
||||||
join_paths(legacy_dir, 'zstd_v07.c')
|
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
|
else
|
||||||
libzstd_cflags = []
|
libzstd_cflags = []
|
||||||
endif
|
endif
|
||||||
@@ -70,7 +94,9 @@ libzstd = library('zstd',
|
|||||||
include_directories: libzstd_includes,
|
include_directories: libzstd_includes,
|
||||||
c_args: libzstd_cflags,
|
c_args: libzstd_cflags,
|
||||||
dependencies: libzstd_deps,
|
dependencies: libzstd_deps,
|
||||||
install: true)
|
install: true,
|
||||||
|
soversion: '1',
|
||||||
|
)
|
||||||
|
|
||||||
programs_dir = join_paths('..', '..', 'programs')
|
programs_dir = join_paths('..', '..', 'programs')
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
option('multithread', type: 'boolean', value: false)
|
option('multithread', type: 'boolean', value: false)
|
||||||
option('legacy_support', type: 'boolean', value: false)
|
option('legacy_support', type: 'string', value: '4',
|
||||||
|
description: 'True or false, or 7 to 1 for v0.7+ to v0.1+.')
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ size_t ZSTD_seekable_initCStream(ZSTD_seekable_CStream* zcs,
|
|||||||
|
|
||||||
/* make sure maxFrameSize has a reasonable value */
|
/* make sure maxFrameSize has a reasonable value */
|
||||||
if (maxFrameSize > ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE) {
|
if (maxFrameSize > ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE) {
|
||||||
return ERROR(compressionParameter_unsupported);
|
return ERROR(frameParameter_unsupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
zcs->maxFrameSize = maxFrameSize
|
zcs->maxFrameSize = maxFrameSize
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ static int ZSTD_seekable_seek_buff(void* opaque, S64 offset, int origin)
|
|||||||
newOffset = (unsigned long long)buff->size - offset;
|
newOffset = (unsigned long long)buff->size - offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (newOffset < 0 || newOffset > buff->size) {
|
if (newOffset > buff->size) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buff->pos = newOffset;
|
buff->pos = newOffset;
|
||||||
@@ -145,7 +145,7 @@ typedef struct {
|
|||||||
int checksumFlag;
|
int checksumFlag;
|
||||||
} seekTable_t;
|
} seekTable_t;
|
||||||
|
|
||||||
#define SEEKABLE_BUFF_SIZE ZSTD_BLOCKSIZE_ABSOLUTEMAX
|
#define SEEKABLE_BUFF_SIZE ZSTD_BLOCKSIZE_MAX
|
||||||
|
|
||||||
struct ZSTD_seekable_s {
|
struct ZSTD_seekable_s {
|
||||||
ZSTD_DStream* dstream;
|
ZSTD_DStream* dstream;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
name: zstd
|
||||||
|
version: git
|
||||||
|
summary: Zstandard - Fast real-time compression algorithm
|
||||||
|
description: |
|
||||||
|
Zstandard, or zstd as short version, is a fast lossless compression
|
||||||
|
algorithm, targeting real-time compression scenarios at zlib-level and better
|
||||||
|
compression ratios. It's backed by a very fast entropy stage, provided by
|
||||||
|
Huff0 and FSE library
|
||||||
|
|
||||||
|
grade: devel # must be 'stable' to release into candidate/stable channels
|
||||||
|
confinement: devmode # use 'strict' once you have the right plugs and slots
|
||||||
|
|
||||||
|
apps:
|
||||||
|
zstd:
|
||||||
|
command: usr/local/bin/zstd
|
||||||
|
plugs: [home, removable-media]
|
||||||
|
zstdgrep:
|
||||||
|
command: usr/local/bin/zstdgrep
|
||||||
|
plugs: [home, removable-media]
|
||||||
|
zstdless:
|
||||||
|
command: usr/local/bin/zstdless
|
||||||
|
plugs: [home, removable-media]
|
||||||
|
|
||||||
|
parts:
|
||||||
|
zstd:
|
||||||
|
source: .
|
||||||
|
plugin: make
|
||||||
|
build-packages: [g++]
|
||||||
@@ -2,19 +2,24 @@ Zstandard Documentation
|
|||||||
=======================
|
=======================
|
||||||
|
|
||||||
This directory contains material defining the Zstandard format,
|
This directory contains material defining the Zstandard format,
|
||||||
as well as for help using the `zstd` library.
|
as well as detailed instructions to use `zstd` library.
|
||||||
|
|
||||||
|
__`zstd_manual.html`__ : Documentation of `zstd.h` API, in html format.
|
||||||
|
Click on this link: [http://zstd.net/zstd_manual.html](http://zstd.net/zstd_manual.html)
|
||||||
|
to display documentation of latest release in readable format within a browser.
|
||||||
|
|
||||||
__`zstd_compression_format.md`__ : This document defines the Zstandard compression format.
|
__`zstd_compression_format.md`__ : This document defines the Zstandard compression format.
|
||||||
Compliant decoders must adhere to this document,
|
Compliant decoders must adhere to this document,
|
||||||
and compliant encoders must generate data that follows it.
|
and compliant encoders must generate data that follows it.
|
||||||
|
|
||||||
|
Should you look for ressources to develop your own port of Zstandard algorithm,
|
||||||
|
you may find the following ressources useful :
|
||||||
|
|
||||||
__`educational_decoder`__ : This directory contains an implementation of a Zstandard decoder,
|
__`educational_decoder`__ : This directory contains an implementation of a Zstandard decoder,
|
||||||
compliant with the Zstandard compression format.
|
compliant with the Zstandard compression format.
|
||||||
It can be used, for example, to better understand the format,
|
It can be used, for example, to better understand the format,
|
||||||
or as the basis for a separate implementation a Zstandard decoder/encoder.
|
or as the basis for a separate implementation of Zstandard decoder.
|
||||||
|
|
||||||
__`zstd_manual.html`__ : Documentation on the functions found in `zstd.h`.
|
|
||||||
See [http://zstd.net/zstd_manual.html](http://zstd.net/zstd_manual.html) for
|
|
||||||
the manual released with the latest official `zstd` release.
|
|
||||||
|
|
||||||
|
|
||||||
|
[__`decode_corpus`__](https://github.com/facebook/zstd/tree/dev/tests#decodecorpus---tool-to-generate-zstandard-frames-for-decoder-testing) :
|
||||||
|
This tool, stored in `/tests` directory, is able to generate random valid frames,
|
||||||
|
which is useful if you wish to test your decoder and verify it fully supports the specification.
|
||||||
|
|||||||
|
After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 114 KiB |
@@ -257,7 +257,7 @@ a decoder is allowed to reject a compressed frame
|
|||||||
which requests a memory size beyond decoder's authorized range.
|
which requests a memory size beyond decoder's authorized range.
|
||||||
|
|
||||||
For improved interoperability,
|
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.
|
and encoders are recommended to not request more than 8 MB.
|
||||||
It's merely a recommendation though,
|
It's merely a recommendation though,
|
||||||
decoders are free to support larger or lower limits,
|
decoders are free to support larger or lower limits,
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||||
<title>zstd 1.3.3 Manual</title>
|
<title>zstd 1.3.4 Manual</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>zstd 1.3.3 Manual</h1>
|
<h1>zstd 1.3.4 Manual</h1>
|
||||||
<hr>
|
<hr>
|
||||||
<a name="Contents"></a><h2>Contents</h2>
|
<a name="Contents"></a><h2>Contents</h2>
|
||||||
<ol>
|
<ol>
|
||||||
<li><a href="#Chapter1">Introduction</a></li>
|
<li><a href="#Chapter1">Introduction</a></li>
|
||||||
<li><a href="#Chapter2">Version</a></li>
|
<li><a href="#Chapter2">Version</a></li>
|
||||||
<li><a href="#Chapter3">Simple API</a></li>
|
<li><a href="#Chapter3">Simple API</a></li>
|
||||||
<li><a href="#Chapter4">Explicit memory management</a></li>
|
<li><a href="#Chapter4">Explicit context</a></li>
|
||||||
<li><a href="#Chapter5">Simple dictionary API</a></li>
|
<li><a href="#Chapter5">Simple dictionary API</a></li>
|
||||||
<li><a href="#Chapter6">Bulk processing dictionary API</a></li>
|
<li><a href="#Chapter6">Bulk processing dictionary API</a></li>
|
||||||
<li><a href="#Chapter7">Streaming</a></li>
|
<li><a href="#Chapter7">Streaming</a></li>
|
||||||
@@ -19,17 +19,16 @@
|
|||||||
<li><a href="#Chapter9">Streaming decompression - HowTo</a></li>
|
<li><a href="#Chapter9">Streaming decompression - HowTo</a></li>
|
||||||
<li><a href="#Chapter10">START OF ADVANCED AND EXPERIMENTAL FUNCTIONS</a></li>
|
<li><a href="#Chapter10">START OF ADVANCED AND EXPERIMENTAL FUNCTIONS</a></li>
|
||||||
<li><a href="#Chapter11">Advanced types</a></li>
|
<li><a href="#Chapter11">Advanced types</a></li>
|
||||||
<li><a href="#Chapter12">Custom memory allocation functions</a></li>
|
<li><a href="#Chapter12">Frame size functions</a></li>
|
||||||
<li><a href="#Chapter13">Frame size functions</a></li>
|
<li><a href="#Chapter13">Memory management</a></li>
|
||||||
<li><a href="#Chapter14">Context memory usage</a></li>
|
<li><a href="#Chapter14">Advanced compression functions</a></li>
|
||||||
<li><a href="#Chapter15">Advanced compression functions</a></li>
|
<li><a href="#Chapter15">Advanced decompression functions</a></li>
|
||||||
<li><a href="#Chapter16">Advanced decompression functions</a></li>
|
<li><a href="#Chapter16">Advanced streaming functions</a></li>
|
||||||
<li><a href="#Chapter17">Advanced streaming functions</a></li>
|
<li><a href="#Chapter17">Buffer-less and synchronous inner streaming functions</a></li>
|
||||||
<li><a href="#Chapter18">Buffer-less and synchronous inner streaming functions</a></li>
|
<li><a href="#Chapter18">Buffer-less streaming compression (synchronous mode)</a></li>
|
||||||
<li><a href="#Chapter19">Buffer-less streaming compression (synchronous mode)</a></li>
|
<li><a href="#Chapter19">Buffer-less streaming decompression (synchronous mode)</a></li>
|
||||||
<li><a href="#Chapter20">Buffer-less streaming decompression (synchronous mode)</a></li>
|
<li><a href="#Chapter20">New advanced API (experimental)</a></li>
|
||||||
<li><a href="#Chapter21">New advanced API (experimental)</a></li>
|
<li><a href="#Chapter21">Block level API</a></li>
|
||||||
<li><a href="#Chapter22">Block level API</a></li>
|
|
||||||
</ol>
|
</ol>
|
||||||
<hr>
|
<hr>
|
||||||
<a name="Chapter1"></a><h2>Introduction</h2><pre>
|
<a name="Chapter1"></a><h2>Introduction</h2><pre>
|
||||||
@@ -40,11 +39,11 @@
|
|||||||
Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory.
|
Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory.
|
||||||
Compression can be done in:
|
Compression can be done in:
|
||||||
- a single step (described as Simple API)
|
- 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)
|
- unbounded multiple steps (described as Streaming compression)
|
||||||
The compression ratio achievable on small data can be highly improved using a dictionary in:
|
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 (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 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.
|
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);
|
|||||||
|
|
||||||
<pre><b>unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
|
<pre><b>unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
|
||||||
</b><p> NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
|
</b><p> NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
|
||||||
Both functions work the same way,
|
Both functions work the same way, but ZSTD_getDecompressedSize() blends
|
||||||
but ZSTD_getDecompressedSize() blends
|
"empty", "unknown" and "error" results to the same return value (0),
|
||||||
"empty", "unknown" and "error" results in the same return value (0),
|
while ZSTD_getFrameContentSize() gives them separate return values.
|
||||||
while ZSTD_getFrameContentSize() distinguishes them.
|
`src` is the start of a zstd compressed frame.
|
||||||
|
|
||||||
'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.
|
@return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise.
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<h3>Helper functions</h3><pre></pre><b><pre>#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) </b>/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */<b>
|
<h3>Helper functions</h3><pre></pre><b><pre>#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) </b>/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */<b>
|
||||||
size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case scenario */<b>
|
size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case single-pass scenario */<b>
|
||||||
unsigned ZSTD_isError(size_t code); </b>/*!< tells if a `size_t` function result is an error code */<b>
|
unsigned ZSTD_isError(size_t code); </b>/*!< tells if a `size_t` function result is an error code */<b>
|
||||||
const char* ZSTD_getErrorName(size_t code); </b>/*!< provides readable string from an error code */<b>
|
const char* ZSTD_getErrorName(size_t code); </b>/*!< provides readable string from an error code */<b>
|
||||||
int ZSTD_maxCLevel(void); </b>/*!< maximum compression level available */<b>
|
int ZSTD_maxCLevel(void); </b>/*!< maximum compression level available */<b>
|
||||||
</pre></b><BR>
|
</pre></b><BR>
|
||||||
<a name="Chapter4"></a><h2>Explicit memory management</h2><pre></pre>
|
<a name="Chapter4"></a><h2>Explicit context</h2><pre></pre>
|
||||||
|
|
||||||
<h3>Compression context</h3><pre> When compressing many times,
|
<h3>Compression context</h3><pre> When compressing many times,
|
||||||
it is recommended to allocate a context just once, and re-use it for each successive compression operation.
|
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_frameParameters fParams;
|
||||||
} ZSTD_parameters;
|
} ZSTD_parameters;
|
||||||
</b></pre><BR>
|
</b></pre><BR>
|
||||||
<a name="Chapter12"></a><h2>Custom memory allocation functions</h2><pre></pre>
|
<pre><b>typedef enum {
|
||||||
|
ZSTD_dct_auto=0, </b>/* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */<b>
|
||||||
<pre><b>typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
|
ZSTD_dct_rawContent, </b>/* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */<b>
|
||||||
|
ZSTD_dct_fullDict </b>/* refuses to load a dictionary if it does not respect Zstandard's specification */<b>
|
||||||
|
} ZSTD_dictContentType_e;
|
||||||
</b></pre><BR>
|
</b></pre><BR>
|
||||||
<a name="Chapter13"></a><h2>Frame size functions</h2><pre></pre>
|
<pre><b>typedef enum {
|
||||||
|
ZSTD_dlm_byCopy = 0, </b>/**< Copy dictionary content internally */<b>
|
||||||
|
ZSTD_dlm_byRef, </b>/**< Reference dictionary content -- the dictionary buffer must outlive its users. */<b>
|
||||||
|
} ZSTD_dictLoadMethod_e;
|
||||||
|
</b></pre><BR>
|
||||||
|
<a name="Chapter12"></a><h2>Frame size functions</h2><pre></pre>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
|
<pre><b>size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
|
||||||
</b><p> `src` should point to the start of a ZSTD encoded frame or skippable frame
|
</b><p> `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
|
@return : size of the Frame Header
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<a name="Chapter14"></a><h2>Context memory usage</h2><pre></pre>
|
<a name="Chapter13"></a><h2>Memory management</h2><pre></pre>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
|
<pre><b>size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
|
||||||
size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
|
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_CDict(const ZSTD_CDict* cdict);
|
||||||
size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
||||||
</b><p> These functions give the current memory usage of selected object.
|
</b><p> 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.
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_estimateCCtxSize(int compressionLevel);
|
<pre><b>size_t ZSTD_estimateCCtxSize(int compressionLevel);
|
||||||
@@ -412,8 +416,8 @@ size_t ZSTD_estimateDCtxSize(void);
|
|||||||
It will also consider src size to be arbitrarily "large", which is worst case.
|
It will also consider src size to be arbitrarily "large", which is worst case.
|
||||||
If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
|
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_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.
|
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_nbWorkers is >= 1.
|
||||||
Note : CCtx estimation is only correct for single-threaded compression
|
Note : CCtx size estimation is only correct for single-threaded compression.
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_estimateCStreamSize(int compressionLevel);
|
<pre><b>size_t ZSTD_estimateCStreamSize(int compressionLevel);
|
||||||
@@ -425,8 +429,8 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
|||||||
It will also consider src size to be arbitrarily "large", which is worst case.
|
It will also consider src size to be arbitrarily "large", which is worst case.
|
||||||
If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
||||||
ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||||
ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_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.
|
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_nbWorkers is >= 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.
|
ZSTD_DStream memory budget depends on window Size.
|
||||||
This information can be passed manually, using ZSTD_estimateDStreamSize,
|
This information can be passed manually, using ZSTD_estimateDStreamSize,
|
||||||
or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
|
or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
|
||||||
@@ -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
|
In this case, get total size by adding ZSTD_estimate?DictSize
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>typedef enum {
|
|
||||||
ZSTD_dlm_byCopy = 0, </b>/**< Copy dictionary content internally */<b>
|
|
||||||
ZSTD_dlm_byRef, </b>/**< Reference dictionary content -- the dictionary buffer must outlive its users. */<b>
|
|
||||||
} ZSTD_dictLoadMethod_e;
|
|
||||||
</b></pre><BR>
|
|
||||||
<pre><b>size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
|
<pre><b>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_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||||
size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
|
size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||||
</b><p> ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
|
</b><p> 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().
|
ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced().
|
||||||
Note : dictionary created by reference using ZSTD_dlm_byRef are smaller
|
Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller.
|
||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<a name="Chapter15"></a><h2>Advanced compression functions</h2><pre></pre>
|
|
||||||
|
|
||||||
<pre><b>ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
|
|
||||||
</b><p> Create a ZSTD compression context using external alloc and free functions
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
|
<pre><b>ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
|
||||||
</b><p> workspace: The memory area to emplace the context into.
|
ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticCCtx() */<b>
|
||||||
Provided pointer must 8-bytes aligned.
|
</b><p> Initialize an object using a pre-allocated fixed-size buffer.
|
||||||
It must outlive context usage.
|
workspace: The memory area to emplace the object into.
|
||||||
workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize()
|
Provided pointer *must be 8-bytes aligned*.
|
||||||
to determine how large workspace must be to support scenario.
|
Buffer must outlive object.
|
||||||
@return : pointer to ZSTD_CCtx* (same address as workspace, but different type),
|
workspaceSize: Use ZSTD_estimate*Size() to determine
|
||||||
or NULL if error (typically size too small)
|
how large workspace must be to support target scenario.
|
||||||
Note : zstd will never resize nor malloc() when using a static cctx.
|
@return : pointer to object (same address as workspace, just different type),
|
||||||
If it needs more memory than available, it will simply error out.
|
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.
|
Note 2 : there is no corresponding "free" function.
|
||||||
Since workspace was allocated externally, it must be freed externally too.
|
Since workspace is allocated externally, it must be freed externally too.
|
||||||
Limitation 1 : currently not compatible with internal CDict creation, such as
|
Note 3 : cParams : use ZSTD_getCParams() to convert a compression level
|
||||||
ZSTD_CCtx_loadDictionary() or ZSTD_initCStream_usingDict().
|
into its associated cParams.
|
||||||
Limitation 2 : currently not compatible with multi-threading
|
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.
|
||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
|
<pre><b>ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticDCtx() */<b>
|
||||||
|
</b></pre><BR>
|
||||||
|
<pre><b>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 }; </b>/**< this constant defers to stdlib's functions */<b>
|
||||||
|
</b><p> 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 <stdlib.h> ones.
|
||||||
|
|
||||||
|
</p></pre><BR>
|
||||||
|
|
||||||
|
<a name="Chapter14"></a><h2>Advanced compression functions</h2><pre></pre>
|
||||||
|
|
||||||
<pre><b>ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
|
<pre><b>ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
|
||||||
</b><p> Create a digested dictionary for compression
|
</b><p> Create a digested dictionary for compression
|
||||||
Dictionary content is simply referenced, and therefore stays in dictBuffer.
|
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
|
It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>typedef enum { ZSTD_dm_auto=0, </b>/* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */<b>
|
|
||||||
ZSTD_dm_rawContent, </b>/* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */<b>
|
|
||||||
ZSTD_dm_fullDict </b>/* refuses to load a dictionary if it does not respect Zstandard's specification */<b>
|
|
||||||
} ZSTD_dictMode_e;
|
|
||||||
</b></pre><BR>
|
|
||||||
<pre><b>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);
|
|
||||||
</b><p> Create a ZSTD_CDict using external alloc and free, and customized compression parameters
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>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);
|
|
||||||
</b><p> 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.
|
|
||||||
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
|
<pre><b>ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
|
||||||
</b><p> @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
|
</b><p> @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
|
||||||
`estimatedSrcSize` value is optional, select 0 if not known
|
`estimatedSrcSize` value is optional, select 0 if not known
|
||||||
@@ -546,7 +526,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
|
|||||||
</b><p> Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters
|
</b><p> Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<a name="Chapter16"></a><h2>Advanced decompression functions</h2><pre></pre>
|
<a name="Chapter15"></a><h2>Advanced decompression functions</h2><pre></pre>
|
||||||
|
|
||||||
<pre><b>unsigned ZSTD_isFrame(const void* buffer, size_t size);
|
<pre><b>unsigned ZSTD_isFrame(const void* buffer, size_t size);
|
||||||
</b><p> Tells if the content of `buffer` starts with a valid Frame Identifier.
|
</b><p> 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.
|
Note 3 : Skippable Frame Identifiers are considered valid.
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
|
|
||||||
</b><p> Create a ZSTD decompression context using external alloc and free functions
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize);
|
|
||||||
</b><p> 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().
|
|
||||||
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
|
<pre><b>ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
|
||||||
</b><p> Create a digested dictionary, ready to start decompression operation without startup delay.
|
</b><p> Create a digested dictionary, ready to start decompression operation without startup delay.
|
||||||
Dictionary content is referenced, and therefore stays in dictBuffer.
|
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
|
it must remain read accessible throughout the lifetime of DDict
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
|
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
|
||||||
ZSTD_customMem customMem);
|
|
||||||
</b><p> Create a ZSTD_DDict using external alloc and free, optionally by reference
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
|
|
||||||
const void* dict, size_t dictSize,
|
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod);
|
|
||||||
</b><p> 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.
|
|
||||||
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
|
<pre><b>unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
|
||||||
</b><p> Provides the dictID stored within dictionary.
|
</b><p> Provides the dictID stored within dictionary.
|
||||||
if @return == 0, the dictionary is not conformant with Zstandard specification.
|
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.
|
When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code.
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<a name="Chapter17"></a><h2>Advanced streaming functions</h2><pre></pre>
|
<a name="Chapter16"></a><h2>Advanced streaming functions</h2><pre></pre>
|
||||||
|
|
||||||
<h3>Advanced Streaming compression functions</h3><pre></pre><b><pre>ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
|
<h3>Advanced Streaming compression functions</h3><pre></pre><b><pre>size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); </b>/**< 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. */<b>
|
||||||
ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticCCtx() */<b>
|
|
||||||
size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); </b>/**< 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. */<b>
|
|
||||||
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); </b>/**< 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.*/<b>
|
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); </b>/**< 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.*/<b>
|
||||||
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
|
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
|
||||||
ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< 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. */<b>
|
ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< 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. */<b>
|
||||||
@@ -647,26 +582,30 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict*
|
|||||||
If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
|
If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
|
||||||
If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
|
If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
|
||||||
For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
|
For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
|
||||||
but it may change to mean "empty" in some future version, so prefer using macro ZSTD_CONTENTSIZE_UNKNOWN.
|
but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
|
||||||
@return : 0, or an error code (which can be tested using ZSTD_isError())
|
@return : 0, or an error code (which can be tested using ZSTD_isError())
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<h3>Advanced Streaming decompression functions</h3><pre></pre><b><pre>ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
|
<pre><b>typedef struct {
|
||||||
ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticDCtx() */<b>
|
unsigned long long ingested;
|
||||||
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
|
unsigned long long consumed;
|
||||||
|
unsigned long long produced;
|
||||||
|
} ZSTD_frameProgression;
|
||||||
|
</b></pre><BR>
|
||||||
|
<h3>Advanced Streaming decompression functions</h3><pre></pre><b><pre>typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
|
||||||
size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); </b>/* obsolete : this API will be removed in a future version */<b>
|
size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); </b>/* obsolete : this API will be removed in a future version */<b>
|
||||||
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); </b>/**< note: no dictionary will be used if dict == NULL or dictSize < 8 */<b>
|
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); </b>/**< note: no dictionary will be used if dict == NULL or dictSize < 8 */<b>
|
||||||
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); </b>/**< note : ddict is referenced, it must outlive decompression session */<b>
|
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); </b>/**< note : ddict is referenced, it must outlive decompression session */<b>
|
||||||
size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression parameters from previous init; saves dictionary loading */<b>
|
size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression parameters from previous init; saves dictionary loading */<b>
|
||||||
</pre></b><BR>
|
</pre></b><BR>
|
||||||
<a name="Chapter18"></a><h2>Buffer-less and synchronous inner streaming functions</h2><pre>
|
<a name="Chapter17"></a><h2>Buffer-less and synchronous inner streaming functions</h2><pre>
|
||||||
This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
|
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.
|
But it's also a complex one, with several restrictions, documented below.
|
||||||
Prefer normal streaming API for an easier experience.
|
Prefer normal streaming API for an easier experience.
|
||||||
|
|
||||||
<BR></pre>
|
<BR></pre>
|
||||||
|
|
||||||
<a name="Chapter19"></a><h2>Buffer-less streaming compression (synchronous mode)</h2><pre>
|
<a name="Chapter18"></a><h2>Buffer-less streaming compression (synchronous mode)</h2><pre>
|
||||||
A ZSTD_CCtx object is required to track streaming operations.
|
A ZSTD_CCtx object is required to track streaming operations.
|
||||||
Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
|
Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
|
||||||
ZSTD_CCtx object can be re-used multiple times within successive compression operations.
|
ZSTD_CCtx object can be re-used multiple times within successive compression operations.
|
||||||
@@ -702,7 +641,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); </b>/* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */<b>
|
size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); </b>/* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */<b>
|
||||||
size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); </b>/**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */<b>
|
size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); </b>/**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */<b>
|
||||||
</pre></b><BR>
|
</pre></b><BR>
|
||||||
<a name="Chapter20"></a><h2>Buffer-less streaming decompression (synchronous mode)</h2><pre>
|
<a name="Chapter19"></a><h2>Buffer-less streaming decompression (synchronous mode)</h2><pre>
|
||||||
A ZSTD_DCtx object is required to track streaming operations.
|
A ZSTD_DCtx object is required to track streaming operations.
|
||||||
Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
|
Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
|
||||||
A ZSTD_DCtx object can be re-used multiple times.
|
A ZSTD_DCtx object can be re-used multiple times.
|
||||||
@@ -788,15 +727,15 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
|||||||
</pre></b><BR>
|
</pre></b><BR>
|
||||||
<pre><b>typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
|
<pre><b>typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
|
||||||
</b></pre><BR>
|
</b></pre><BR>
|
||||||
<a name="Chapter21"></a><h2>New advanced API (experimental)</h2><pre></pre>
|
<a name="Chapter20"></a><h2>New advanced API (experimental)</h2><pre></pre>
|
||||||
|
|
||||||
<pre><b>typedef enum {
|
<pre><b>typedef enum {
|
||||||
</b>/* Question : should we have a format ZSTD_f_auto ?<b>
|
</b>/* Opened question : should we have a format ZSTD_f_auto ?<b>
|
||||||
* For the time being, it would mean exactly the same as ZSTD_f_zstd1.
|
* Today, it would mean exactly the same as ZSTD_f_zstd1.
|
||||||
* But, in the future, should several formats be supported,
|
* But, in the future, should several formats become supported,
|
||||||
* on the compression side, it would mean "default format".
|
* on the compression side, it would mean "default format".
|
||||||
* On the decompression side, it would mean "multi format",
|
* On the decompression side, it would mean "automatic format detection",
|
||||||
* and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames".
|
* so that ZSTD_f_zstd1 would mean "accept *only* zstd frames".
|
||||||
* Since meaning is a little different, another option could be to define different enums for compression and decompression.
|
* Since meaning is a little different, another option could be to define different enums for compression and decompression.
|
||||||
* This question could be kept for later, when there are actually multiple formats to support,
|
* This question could be kept for later, when there are actually multiple formats to support,
|
||||||
* but there is also the question of pinning enum values, and pinning value `0` is especially important */
|
* but there is also the question of pinning enum values, and pinning value `0` is especially important */
|
||||||
@@ -814,42 +753,76 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
|||||||
</b>/* compression parameters */<b>
|
</b>/* compression parameters */<b>
|
||||||
ZSTD_p_compressionLevel=100, </b>/* Update all compression parameters according to pre-defined cLevel table<b>
|
ZSTD_p_compressionLevel=100, </b>/* Update all compression parameters according to pre-defined cLevel table<b>
|
||||||
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
||||||
* Special: value 0 means "do not change cLevel". */
|
* Special: value 0 means "do not change cLevel".
|
||||||
|
* Note 1 : it's possible to pass a negative compression level by casting it to unsigned type.
|
||||||
|
* Note 2 : setting a level sets all default values of other compression parameters.
|
||||||
|
* Note 3 : setting compressionLevel automatically updates ZSTD_p_compressLiterals. */
|
||||||
ZSTD_p_windowLog, </b>/* Maximum allowed back-reference distance, expressed as power of 2.<b>
|
ZSTD_p_windowLog, </b>/* Maximum allowed back-reference distance, expressed as power of 2.<b>
|
||||||
* Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
|
* Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
|
||||||
* Special: value 0 means "do not change windowLog".
|
* Special: value 0 means "use default windowLog".
|
||||||
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
||||||
* requires setting the maximum window size at least as large during decompression. */
|
* requires explicitly allowing such window size during decompression stage. */
|
||||||
ZSTD_p_hashLog, </b>/* Size of the probe table, as a power of 2.<b>
|
ZSTD_p_hashLog, </b>/* Size of the probe table, as a power of 2.<b>
|
||||||
* Resulting table size is (1 << (hashLog+2)).
|
* Resulting table size is (1 << (hashLog+2)).
|
||||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
||||||
* Larger tables improve compression ratio of strategies <= dFast,
|
* Larger tables improve compression ratio of strategies <= dFast,
|
||||||
* and improve speed of strategies > dFast.
|
* and improve speed of strategies > dFast.
|
||||||
* Special: value 0 means "do not change hashLog". */
|
* Special: value 0 means "use default hashLog". */
|
||||||
ZSTD_p_chainLog, </b>/* Size of the full-search table, as a power of 2.<b>
|
ZSTD_p_chainLog, </b>/* Size of the full-search table, as a power of 2.<b>
|
||||||
* Resulting table size is (1 << (chainLog+2)).
|
* Resulting table size is (1 << (chainLog+2)).
|
||||||
* Larger tables result in better and slower compression.
|
* Larger tables result in better and slower compression.
|
||||||
* This parameter is useless when using "fast" strategy.
|
* This parameter is useless when using "fast" strategy.
|
||||||
* Special: value 0 means "do not change chainLog". */
|
* Special: value 0 means "use default chainLog". */
|
||||||
ZSTD_p_searchLog, </b>/* Number of search attempts, as a power of 2.<b>
|
ZSTD_p_searchLog, </b>/* Number of search attempts, as a power of 2.<b>
|
||||||
* More attempts result in better and slower compression.
|
* More attempts result in better and slower compression.
|
||||||
* This parameter is useless when using "fast" and "dFast" strategies.
|
* This parameter is useless when using "fast" and "dFast" strategies.
|
||||||
* Special: value 0 means "do not change searchLog". */
|
* Special: value 0 means "use default searchLog". */
|
||||||
ZSTD_p_minMatch, </b>/* Minimum size of searched matches (note : repCode matches can be smaller).<b>
|
ZSTD_p_minMatch, </b>/* Minimum size of searched matches (note : repCode matches can be smaller).<b>
|
||||||
* Larger values make faster compression and decompression, but decrease ratio.
|
* Larger values make faster compression and decompression, but decrease ratio.
|
||||||
* Must be clamped between ZSTD_SEARCHLENGTH_MIN and ZSTD_SEARCHLENGTH_MAX.
|
* Must be clamped between ZSTD_SEARCHLENGTH_MIN and ZSTD_SEARCHLENGTH_MAX.
|
||||||
* Note that currently, for all strategies < btopt, effective minimum is 4.
|
* Note that currently, for all strategies < btopt, effective minimum is 4.
|
||||||
* Note that currently, for all strategies > fast, effective maximum is 6.
|
* , for all strategies > fast, effective maximum is 6.
|
||||||
* Special: value 0 means "do not change minMatchLength". */
|
* Special: value 0 means "use default minMatchLength". */
|
||||||
ZSTD_p_targetLength, </b>/* Only useful for strategies >= btopt.<b>
|
ZSTD_p_targetLength, </b>/* Impact of this field depends on strategy.<b>
|
||||||
|
* For strategies btopt & btultra:
|
||||||
* Length of Match considered "good enough" to stop search.
|
* Length of Match considered "good enough" to stop search.
|
||||||
* Larger values make compression stronger and slower.
|
* Larger values make compression stronger, and slower.
|
||||||
* Special: value 0 means "do not change targetLength". */
|
* For strategy fast:
|
||||||
|
* Distance between match sampling.
|
||||||
|
* Larger values make compression faster, and weaker.
|
||||||
|
* Special: value 0 means "use default targetLength". */
|
||||||
ZSTD_p_compressionStrategy, </b>/* See ZSTD_strategy enum definition.<b>
|
ZSTD_p_compressionStrategy, </b>/* See ZSTD_strategy enum definition.<b>
|
||||||
* Cast selected strategy as unsigned for ZSTD_CCtx_setParameter() compatibility.
|
* Cast selected strategy as unsigned for ZSTD_CCtx_setParameter() compatibility.
|
||||||
* The higher the value of selected strategy, the more complex it is,
|
* The higher the value of selected strategy, the more complex it is,
|
||||||
* resulting in stronger and slower compression.
|
* resulting in stronger and slower compression.
|
||||||
* Special: value 0 means "do not change strategy". */
|
* Special: value 0 means "use default strategy". */
|
||||||
|
|
||||||
|
ZSTD_p_enableLongDistanceMatching=160, </b>/* Enable long distance matching.<b>
|
||||||
|
* This parameter is designed to improve compression ratio
|
||||||
|
* for large inputs, by finding large matches at long distance.
|
||||||
|
* It increases memory usage and window size.
|
||||||
|
* Note: enabling this parameter increases ZSTD_p_windowLog to 128 MB
|
||||||
|
* except when expressly set to a different value. */
|
||||||
|
ZSTD_p_ldmHashLog, </b>/* Size of the table for long distance matching, as a power of 2.<b>
|
||||||
|
* Larger values increase memory usage and compression ratio,
|
||||||
|
* but decrease compression speed.
|
||||||
|
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
|
||||||
|
* default: windowlog - 7.
|
||||||
|
* Special: value 0 means "automatically determine hashlog". */
|
||||||
|
ZSTD_p_ldmMinMatch, </b>/* Minimum match size for long distance matcher.<b>
|
||||||
|
* Larger/too small values usually decrease compression ratio.
|
||||||
|
* Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX.
|
||||||
|
* Special: value 0 means "use default value" (default: 64). */
|
||||||
|
ZSTD_p_ldmBucketSizeLog, </b>/* Log size of each bucket in the LDM hash table for collision resolution.<b>
|
||||||
|
* Larger values improve collision resolution but decrease compression speed.
|
||||||
|
* The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX .
|
||||||
|
* Special: value 0 means "use default value" (default: 3). */
|
||||||
|
ZSTD_p_ldmHashEveryLog, </b>/* Frequency of inserting/looking up entries in the LDM hash table.<b>
|
||||||
|
* Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN).
|
||||||
|
* Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage.
|
||||||
|
* Larger values improve compression speed.
|
||||||
|
* Deviating far from default value will likely result in a compression ratio decrease.
|
||||||
|
* Special: value 0 means "automatically determine hashEveryLog". */
|
||||||
|
|
||||||
</b>/* frame parameters */<b>
|
</b>/* frame parameters */<b>
|
||||||
ZSTD_p_contentSizeFlag=200, </b>/* Content size will be written into frame header _whenever known_ (default:1)<b>
|
ZSTD_p_contentSizeFlag=200, </b>/* Content size will be written into frame header _whenever known_ (default:1)<b>
|
||||||
@@ -859,57 +832,44 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
|||||||
ZSTD_p_dictIDFlag, </b>/* When applicable, dictionary's ID is written into frame header (default:1) */<b>
|
ZSTD_p_dictIDFlag, </b>/* When applicable, dictionary's ID is written into frame header (default:1) */<b>
|
||||||
|
|
||||||
</b>/* multi-threading parameters */<b>
|
</b>/* multi-threading parameters */<b>
|
||||||
ZSTD_p_nbThreads=400, </b>/* Select how many threads a compression job can spawn (default:1)<b>
|
</b>/* These parameters are only useful if multi-threading is enabled (ZSTD_MULTITHREAD).<b>
|
||||||
* More threads improve speed, but also increase memory usage.
|
* They return an error otherwise. */
|
||||||
* Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled.
|
ZSTD_p_nbWorkers=400, </b>/* Select how many threads will be spawned to compress in parallel.<b>
|
||||||
* Special: value 0 means "do not change nbThreads" */
|
* When nbWorkers >= 1, triggers asynchronous mode :
|
||||||
ZSTD_p_jobSize, </b>/* Size of a compression job. This value is only enforced in streaming (non-blocking) mode.<b>
|
* ZSTD_compress_generic() consumes some input, flush some output if possible, and immediately gives back control to caller,
|
||||||
* Each compression job is completed in parallel, so indirectly controls the nb of active threads.
|
* while compression work is performed in parallel, within worker threads.
|
||||||
|
* (note : a strong exception to this rule is when first invocation sets ZSTD_e_end : it becomes a blocking call).
|
||||||
|
* More workers improve speed, but also increase memory usage.
|
||||||
|
* Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */
|
||||||
|
ZSTD_p_jobSize, </b>/* Size of a compression job. This value is enforced only in non-blocking mode.<b>
|
||||||
|
* Each compression job is completed in parallel, so this value indirectly controls the nb of active threads.
|
||||||
* 0 means default, which is dynamically determined based on compression parameters.
|
* 0 means default, which is dynamically determined based on compression parameters.
|
||||||
* Job size must be a minimum of overlapSize, or 1 KB, whichever is largest
|
* Job size must be a minimum of overlapSize, or 1 MB, whichever is largest.
|
||||||
* The minimum size is automatically and transparently enforced */
|
* The minimum size is automatically and transparently enforced */
|
||||||
ZSTD_p_overlapSizeLog, </b>/* Size of previous input reloaded at the beginning of each job.<b>
|
ZSTD_p_overlapSizeLog, </b>/* Size of previous input reloaded at the beginning of each job.<b>
|
||||||
* 0 => no overlap, 6(default) => use 1/8th of windowSize, >=9 => use full windowSize */
|
* 0 => no overlap, 6(default) => use 1/8th of windowSize, >=9 => use full windowSize */
|
||||||
|
|
||||||
</b>/* advanced parameters - may not remain available after API update */<b>
|
</b>/* =================================================================== */<b>
|
||||||
|
</b>/* experimental parameters - no stability guaranteed */<b>
|
||||||
|
</b>/* =================================================================== */<b>
|
||||||
|
|
||||||
|
ZSTD_p_compressLiterals=1000, </b>/* control huffman compression of literals (enabled) by default.<b>
|
||||||
|
* disabling it improves speed and decreases compression ratio by a large amount.
|
||||||
|
* note : this setting is automatically updated when changing compression level.
|
||||||
|
* positive compression levels set ZSTD_p_compressLiterals to 1.
|
||||||
|
* negative compression levels set ZSTD_p_compressLiterals to 0. */
|
||||||
|
|
||||||
ZSTD_p_forceMaxWindow=1100, </b>/* Force back-reference distances to remain < windowSize,<b>
|
ZSTD_p_forceMaxWindow=1100, </b>/* Force back-reference distances to remain < windowSize,<b>
|
||||||
* even when referencing into Dictionary content (default:0) */
|
* even when referencing into Dictionary content (default:0) */
|
||||||
ZSTD_p_enableLongDistanceMatching=1200, </b>/* Enable long distance matching.<b>
|
|
||||||
* This parameter is designed to improve the compression
|
|
||||||
* ratio for large inputs with long distance matches.
|
|
||||||
* This increases the memory usage as well as window size.
|
|
||||||
* Note: setting this parameter sets all the LDM parameters
|
|
||||||
* as well as ZSTD_p_windowLog. It should be set after
|
|
||||||
* ZSTD_p_compressionLevel and before ZSTD_p_windowLog and
|
|
||||||
* other LDM parameters. Setting the compression level
|
|
||||||
* after this parameter overrides the window log, though LDM
|
|
||||||
* will remain enabled until explicitly disabled. */
|
|
||||||
ZSTD_p_ldmHashLog, </b>/* Size of the table for long distance matching, as a power of 2.<b>
|
|
||||||
* Larger values increase memory usage and compression ratio, but decrease
|
|
||||||
* compression speed.
|
|
||||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
|
|
||||||
* (default: windowlog - 7). */
|
|
||||||
ZSTD_p_ldmMinMatch, </b>/* Minimum size of searched matches for long distance matcher.<b>
|
|
||||||
* Larger/too small values usually decrease compression ratio.
|
|
||||||
* Must be clamped between ZSTD_LDM_MINMATCH_MIN
|
|
||||||
* and ZSTD_LDM_MINMATCH_MAX (default: 64). */
|
|
||||||
ZSTD_p_ldmBucketSizeLog, </b>/* Log size of each bucket in the LDM hash table for collision resolution.<b>
|
|
||||||
* Larger values usually improve collision resolution but may decrease
|
|
||||||
* compression speed.
|
|
||||||
* The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX (default: 3). */
|
|
||||||
ZSTD_p_ldmHashEveryLog, </b>/* Frequency of inserting/looking up entries in the LDM hash table.<b>
|
|
||||||
* The default is MAX(0, (windowLog - ldmHashLog)) to
|
|
||||||
* optimize hash table usage.
|
|
||||||
* Larger values improve compression speed. Deviating far from the
|
|
||||||
* default value will likely result in a decrease in compression ratio.
|
|
||||||
* Must be clamped between 0 and ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
|
|
||||||
|
|
||||||
} ZSTD_cParameter;
|
} ZSTD_cParameter;
|
||||||
</b></pre><BR>
|
</b></pre><BR>
|
||||||
<pre><b>size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value);
|
<pre><b>size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value);
|
||||||
</b><p> Set one compression parameter, selected by enum ZSTD_cParameter.
|
</b><p> Set one compression parameter, selected by enum ZSTD_cParameter.
|
||||||
|
Setting a parameter is generally only possible during frame initialization (before starting compression),
|
||||||
|
except for a few exceptions which can be updated during compression: compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy.
|
||||||
Note : when `value` is an enum, cast it to unsigned for proper type checking.
|
Note : when `value` is an enum, cast it to unsigned for proper type checking.
|
||||||
@result : informational value (typically, the one being set, possibly corrected),
|
@result : informational value (typically, value being set clamped correctly),
|
||||||
or an error code (which can be tested with ZSTD_isError()).
|
or an error code (which can be tested with ZSTD_isError()).
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
@@ -926,24 +886,22 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
|||||||
|
|
||||||
<pre><b>size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
<pre><b>size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||||
size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||||
size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
|
size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
|
||||||
</b><p> Create an internal CDict from dict buffer.
|
</b><p> Create an internal CDict from `dict` buffer.
|
||||||
Decompression will have to use same buffer.
|
Decompression will have to use same dictionary.
|
||||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||||
Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
|
Special: Adding a NULL (or 0-size) dictionary invalidates previous dictionary,
|
||||||
meaning "return to no-dictionary mode".
|
meaning "return to no-dictionary mode".
|
||||||
Note 1 : `dict` content will be copied internally. Use
|
Note 1 : Dictionary will be used for all future compression jobs.
|
||||||
ZSTD_CCtx_loadDictionary_byReference() to reference dictionary
|
To return to "no-dictionary" situation, load a NULL dictionary
|
||||||
content instead. The dictionary buffer must then outlive its
|
|
||||||
users.
|
|
||||||
Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters.
|
Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters.
|
||||||
For this reason, compression parameters cannot be changed anymore after loading a dictionary.
|
For this reason, compression parameters cannot be changed anymore after loading a dictionary.
|
||||||
It's also a CPU-heavy operation, with non-negligible impact on latency.
|
It's also a CPU consuming operation, with non-negligible impact on latency.
|
||||||
Note 3 : Dictionary will be used for all future compression jobs.
|
Note 3 :`dict` content will be copied internally.
|
||||||
To return to "no-dictionary" situation, load a NULL dictionary
|
Use ZSTD_CCtx_loadDictionary_byReference() to reference dictionary content instead.
|
||||||
Note 5 : Use ZSTD_CCtx_loadDictionary_advanced() to select how dictionary
|
In such a case, dictionary buffer must outlive its users.
|
||||||
content will be interpreted.
|
Note 4 : Use ZSTD_CCtx_loadDictionary_advanced()
|
||||||
|
to precisely select how dictionary content must be interpreted.
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
<pre><b>size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
||||||
@@ -956,11 +914,10 @@ size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size
|
|||||||
Note 1 : Currently, only one dictionary can be managed.
|
Note 1 : Currently, only one dictionary can be managed.
|
||||||
Adding a new dictionary effectively "discards" any previous one.
|
Adding a new dictionary effectively "discards" any previous one.
|
||||||
Note 2 : CDict is just referenced, its lifetime must outlive CCtx.
|
Note 2 : CDict is just referenced, its lifetime must outlive CCtx.
|
||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize);
|
<pre><b>size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize);
|
||||||
size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
|
size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
|
||||||
</b><p> Reference a prefix (single-usage dictionary) for next compression job.
|
</b><p> Reference a prefix (single-usage dictionary) for next compression job.
|
||||||
Decompression need same prefix to properly regenerate data.
|
Decompression need same prefix to properly regenerate data.
|
||||||
Prefix is **only used once**. Tables are discarded at end of compression job.
|
Prefix is **only used once**. Tables are discarded at end of compression job.
|
||||||
@@ -970,14 +927,23 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
|||||||
Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary
|
Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary
|
||||||
Note 1 : Prefix buffer is referenced. It must outlive compression job.
|
Note 1 : Prefix buffer is referenced. It must outlive compression job.
|
||||||
Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
||||||
It's a CPU-heavy operation, with non-negligible impact on latency.
|
It's a CPU consuming operation, with non-negligible impact on latency.
|
||||||
Note 3 : By default, the prefix is treated as raw content
|
Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||||
(ZSTD_dm_rawContent). Use ZSTD_CCtx_refPrefix_advanced() to alter
|
Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
||||||
dictMode.
|
</p></pre><BR>
|
||||||
|
|
||||||
|
<pre><b>void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);
|
||||||
|
</b><p> 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.
|
||||||
|
Dictionary (if any) is dropped.
|
||||||
|
All parameters are back to default values.
|
||||||
|
It's possible to modify compression parameters after a reset.
|
||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>typedef enum {
|
<pre><b>typedef enum {
|
||||||
ZSTD_e_continue=0, </b>/* collect more data, encoder transparently decides when to output result, for optimal conditions */<b>
|
ZSTD_e_continue=0, </b>/* collect more data, encoder decides when to output compressed result, for optimal conditions */<b>
|
||||||
ZSTD_e_flush, </b>/* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */<b>
|
ZSTD_e_flush, </b>/* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */<b>
|
||||||
ZSTD_e_end </b>/* flush any remaining data and close current frame. Any additional data starts a new frame. */<b>
|
ZSTD_e_end </b>/* flush any remaining data and close current frame. Any additional data starts a new frame. */<b>
|
||||||
} ZSTD_EndDirective;
|
} ZSTD_EndDirective;
|
||||||
@@ -996,10 +962,11 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
|||||||
and then immediately returns, just indicating that there is some data remaining to be flushed.
|
and then immediately returns, just indicating that there is some data remaining to be flushed.
|
||||||
The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
|
The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
|
||||||
- Exception : in multi-threading mode, if the first call requests a ZSTD_e_end directive, it is blocking : it will complete compression before giving back control to caller.
|
- Exception : in multi-threading mode, if the first call requests a ZSTD_e_end directive, it is blocking : it will complete compression before giving back control to caller.
|
||||||
- @return provides the minimum amount of data remaining to be flushed from internal buffers
|
- @return provides a minimum amount of data remaining to be flushed from internal buffers
|
||||||
or an error code, which can be tested using ZSTD_isError().
|
or an error code, which can be tested using ZSTD_isError().
|
||||||
if @return != 0, flush is not fully completed, there is still some data left within internal buffers.
|
if @return != 0, flush is not fully completed, there is still some data left within internal buffers.
|
||||||
This is useful to determine if a ZSTD_e_flush or ZSTD_e_end directive is completed.
|
This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers.
|
||||||
|
For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed.
|
||||||
- after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
|
- after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
|
||||||
only ZSTD_e_end or ZSTD_e_flush operations are allowed.
|
only ZSTD_e_end or ZSTD_e_flush operations are allowed.
|
||||||
Before starting a new compression job, or changing compression parameters,
|
Before starting a new compression job, or changing compression parameters,
|
||||||
@@ -1007,16 +974,6 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
|||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>void ZSTD_CCtx_reset(ZSTD_CCtx* cctx); </b>/* Not ready yet ! */<b>
|
|
||||||
</b><p> 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.
|
|
||||||
Dictionary (if any) is dropped.
|
|
||||||
All parameters are back to default values.
|
|
||||||
It's possible to modify compression parameters after a reset.
|
|
||||||
|
|
||||||
</p></pre><BR>
|
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_compress_generic_simpleArgs (
|
<pre><b>size_t ZSTD_compress_generic_simpleArgs (
|
||||||
ZSTD_CCtx* cctx,
|
ZSTD_CCtx* cctx,
|
||||||
void* dst, size_t dstCapacity, size_t* dstPos,
|
void* dst, size_t dstCapacity, size_t* dstPos,
|
||||||
@@ -1031,6 +988,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
|||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
|
<pre><b>ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
|
||||||
|
size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
|
||||||
</b><p> Quick howto :
|
</b><p> Quick howto :
|
||||||
- ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
|
- ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
|
||||||
- ZSTD_CCtxParam_setParameter() : Push parameters one by one into
|
- ZSTD_CCtxParam_setParameter() : Push parameters one by one into
|
||||||
@@ -1049,18 +1007,18 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
|||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
|
<pre><b>size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params);
|
||||||
</b><p> Reset params to default, with the default compression level.
|
</b><p> Reset params to default values.
|
||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel);
|
<pre><b>size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel);
|
||||||
</b><p> Initializes the compression parameters of cctxParams according to
|
</b><p> Initializes the compression parameters of cctxParams according to
|
||||||
compression level. All other parameters are reset to their default values.
|
compression level. All other parameters are reset to their default values.
|
||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
|
<pre><b>size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
|
||||||
</b><p> Initializes the compression and frame parameters of cctxParams according to
|
</b><p> Initializes the compression and frame parameters of cctxParams according to
|
||||||
params. All other parameters are reset to their default values.
|
params. All other parameters are reset to their default values.
|
||||||
|
|
||||||
@@ -1078,16 +1036,17 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
|||||||
<pre><b>size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
<pre><b>size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
||||||
</b><p> Apply a set of ZSTD_CCtx_params to the compression context.
|
</b><p> Apply a set of ZSTD_CCtx_params to the compression context.
|
||||||
This must be done before the dictionary is loaded.
|
This can be done even after compression is started,
|
||||||
The pledgedSrcSize is treated as unknown.
|
if nbWorkers==0, this will have no impact until a new compression is started.
|
||||||
Multithreading parameters are applied only if nbThreads > 1.
|
if nbWorkers>=1, new parameters will be picked up at next job,
|
||||||
|
with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated).
|
||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<h3>Advanced parameters for decompression API</h3><pre></pre><b><pre></pre></b><BR>
|
<h3>Advanced parameters for decompression API</h3><pre></pre><b><pre></pre></b><BR>
|
||||||
<pre><b>size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); </b>/* not implemented */<b>
|
<pre><b>size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
|
||||||
size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); </b>/* not implemented */<b>
|
size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
|
||||||
size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode); </b>/* not implemented */<b>
|
size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
|
||||||
</b><p> Create an internal DDict from dict buffer,
|
</b><p> Create an internal DDict from dict buffer,
|
||||||
to be used to decompress next frames.
|
to be used to decompress next frames.
|
||||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||||
@@ -1104,7 +1063,7 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size
|
|||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); </b>/* not implemented */<b>
|
<pre><b>size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
|
||||||
</b><p> Reference a prepared dictionary, to be used to decompress next frames.
|
</b><p> Reference a prepared dictionary, to be used to decompress next frames.
|
||||||
The dictionary remains active for decompression of future frames using same DCtx.
|
The dictionary remains active for decompression of future frames using same DCtx.
|
||||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||||
@@ -1115,8 +1074,8 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size
|
|||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<pre><b>size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize); </b>/* not implemented */<b>
|
<pre><b>size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);
|
||||||
size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode); </b>/* not implemented */<b>
|
size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
|
||||||
</b><p> Reference a prefix (single-usage dictionary) for next compression job.
|
</b><p> Reference a prefix (single-usage dictionary) for next compression job.
|
||||||
Prefix is **only used once**. It must be explicitly referenced before each frame.
|
Prefix is **only used once**. It must be explicitly referenced before each frame.
|
||||||
If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead.
|
If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead.
|
||||||
@@ -1178,7 +1137,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
|
|||||||
|
|
||||||
</p></pre><BR>
|
</p></pre><BR>
|
||||||
|
|
||||||
<a name="Chapter22"></a><h2>Block level API</h2><pre></pre>
|
<a name="Chapter21"></a><h2>Block level API</h2><pre></pre>
|
||||||
|
|
||||||
<pre><b></b><p> Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
<pre><b></b><p> 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.
|
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
|
||||||
@@ -1206,7 +1165,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
|
|||||||
<h3>Raw zstd block functions</h3><pre></pre><b><pre>size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
|
<h3>Raw zstd block functions</h3><pre></pre><b><pre>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_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_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); </b>/**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression */<b>
|
size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); </b>/**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */<b>
|
||||||
</pre></b><BR>
|
</pre></b><BR>
|
||||||
</html>
|
</html>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
# This Makefile presumes libzstd is installed, using `sudo make install`
|
# This Makefile presumes libzstd is installed, using `sudo make install`
|
||||||
|
|
||||||
|
CPPFLAGS += -I../lib
|
||||||
LIB = ../lib/libzstd.a
|
LIB = ../lib/libzstd.a
|
||||||
|
|
||||||
.PHONY: default all clean test
|
.PHONY: default all clean test
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ static unsigned readU32FromChar(const char** stringPtr)
|
|||||||
|
|
||||||
int main(int argc, char const *argv[]) {
|
int main(int argc, char const *argv[]) {
|
||||||
|
|
||||||
printf("\n Zstandard (v%u) memory usage for streaming contexts : \n\n", ZSTD_versionNumber());
|
printf("\n Zstandard (v%s) memory usage for streaming : \n\n", ZSTD_versionString());
|
||||||
|
|
||||||
unsigned wLog = 0;
|
unsigned wLog = 0;
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
@@ -69,11 +69,13 @@ int main(int argc, char const *argv[]) {
|
|||||||
|
|
||||||
/* forces compressor to use maximum memory size for given compression level,
|
/* forces compressor to use maximum memory size for given compression level,
|
||||||
* by not providing any information on input size */
|
* by not providing any information on input size */
|
||||||
ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, 0);
|
ZSTD_parameters params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
|
||||||
if (wLog) { /* special mode : specific wLog */
|
if (wLog) { /* special mode : specific wLog */
|
||||||
printf("Using custom compression parameter : level 1 + wLog=%u \n", wLog);
|
printf("Using custom compression parameter : level 1 + wLog=%u \n", wLog);
|
||||||
params = ZSTD_getParams(1, 1 << wLog, 0);
|
params = ZSTD_getParams(1 /*compressionLevel*/,
|
||||||
size_t const error = ZSTD_initCStream_advanced(cstream, NULL, 0, params, 0);
|
1 << wLog /*estimatedSrcSize*/,
|
||||||
|
0 /*no dictionary*/);
|
||||||
|
size_t const error = ZSTD_initCStream_advanced(cstream, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN);
|
||||||
if (ZSTD_isError(error)) {
|
if (ZSTD_isError(error)) {
|
||||||
printf("ZSTD_initCStream_advanced error : %s \n", ZSTD_getErrorName(error));
|
printf("ZSTD_initCStream_advanced error : %s \n", ZSTD_getErrorName(error));
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ cxx_library(
|
|||||||
name='decompress',
|
name='decompress',
|
||||||
header_namespace='',
|
header_namespace='',
|
||||||
visibility=['PUBLIC'],
|
visibility=['PUBLIC'],
|
||||||
|
headers=subdir_glob([
|
||||||
|
('decompress', '*_impl.h'),
|
||||||
|
]),
|
||||||
srcs=glob(['decompress/zstd*.c']),
|
srcs=glob(['decompress/zstd*.c']),
|
||||||
deps=[
|
deps=[
|
||||||
':common',
|
':common',
|
||||||
@@ -80,6 +83,15 @@ cxx_library(
|
|||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cxx_library(
|
||||||
|
name='cpu',
|
||||||
|
header_namespace='',
|
||||||
|
visibility=['PUBLIC'],
|
||||||
|
exported_headers=subdir_glob([
|
||||||
|
('common', 'cpu.h'),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
cxx_library(
|
cxx_library(
|
||||||
name='bitstream',
|
name='bitstream',
|
||||||
header_namespace='',
|
header_namespace='',
|
||||||
@@ -196,6 +208,7 @@ cxx_library(
|
|||||||
deps=[
|
deps=[
|
||||||
':bitstream',
|
':bitstream',
|
||||||
':compiler',
|
':compiler',
|
||||||
|
':cpu',
|
||||||
':entropy',
|
':entropy',
|
||||||
':errors',
|
':errors',
|
||||||
':mem',
|
':mem',
|
||||||
|
|||||||
@@ -2,16 +2,19 @@ Zstandard library files
|
|||||||
================================
|
================================
|
||||||
|
|
||||||
The __lib__ directory is split into several sub-directories,
|
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
|
#### Building
|
||||||
|
|
||||||
`Makefile` script is provided, supporting the standard set of commands,
|
`Makefile` script is provided, supporting all standard [Makefile conventions](https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html#Makefile-Conventions),
|
||||||
directories, and variables (see https://www.gnu.org/prep/standards/html_node/Command-Variables.html).
|
including commands variables, staged install, directory variables and standard targets.
|
||||||
- `make` : generates both static and dynamic libraries
|
- `make` : generates both static and dynamic libraries
|
||||||
- `make install` : install libraries in default system directories
|
- `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
|
#### API
|
||||||
|
|
||||||
@@ -27,13 +30,15 @@ Optional advanced features are exposed via :
|
|||||||
- `ZSTD_STATIC_LINKING_ONLY` : if this macro is defined _before_ including `zstd.h`,
|
- `ZSTD_STATIC_LINKING_ONLY` : if this macro is defined _before_ including `zstd.h`,
|
||||||
it unlocks access to advanced experimental API,
|
it unlocks access to advanced experimental API,
|
||||||
exposed in second part of `zstd.h`.
|
exposed in second part of `zstd.h`.
|
||||||
These APIs shall ___never be used with dynamic library___ !
|
These APIs are not "stable", their definition may change in the future.
|
||||||
They are not "stable", their definition may change in the future.
|
As a consequence, it shall ___never be used with dynamic library___ !
|
||||||
Only static linking is allowed.
|
Only static linking is allowed.
|
||||||
|
|
||||||
|
|
||||||
#### Modular build
|
#### Modular build
|
||||||
|
|
||||||
|
It's possible to compile only a limited set of features.
|
||||||
|
|
||||||
- Directory `lib/common` is always required, for all variants.
|
- Directory `lib/common` is always required, for all variants.
|
||||||
- Compression source code lies in `lib/compress`
|
- Compression source code lies in `lib/compress`
|
||||||
- Decompression source code lies in `lib/decompress`
|
- Decompression source code lies in `lib/decompress`
|
||||||
@@ -41,15 +46,21 @@ Optional advanced features are exposed via :
|
|||||||
- `lib/dictBuilder` : makes it possible to generate dictionaries from a set of samples.
|
- `lib/dictBuilder` : makes it possible to generate dictionaries from a set of samples.
|
||||||
The API is exposed in `lib/dictBuilder/zdict.h`.
|
The API is exposed in `lib/dictBuilder/zdict.h`.
|
||||||
This module depends on both `lib/common` and `lib/compress` .
|
This module depends on both `lib/common` and `lib/compress` .
|
||||||
- `lib/legacy` : source code to decompress older zstd formats, starting from `v0.1`.
|
- `lib/legacy` : source code to decompress legacy zstd formats, starting from `v0.1.0`.
|
||||||
This module depends on `lib/common` and `lib/decompress`.
|
This module depends on `lib/common` and `lib/decompress`.
|
||||||
To enable this feature, it's necessary to define `ZSTD_LEGACY_SUPPORT = 1` during compilation.
|
To enable this feature, it's required to define `ZSTD_LEGACY_SUPPORT` during compilation.
|
||||||
Typically, with `gcc`, add argument `-DZSTD_LEGACY_SUPPORT=1`.
|
Typically, with `gcc`, add argument `-DZSTD_LEGACY_SUPPORT=1`.
|
||||||
Using higher number limits the number of version supported.
|
Using higher number limits versions supported.
|
||||||
For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats starting from v0.2+".
|
For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats >= v0.2.0".
|
||||||
The API is exposed in `lib/legacy/zstd_legacy.h`.
|
`ZSTD_LEGACY_SUPPORT=3` means : "support legacy formats >= v0.3.0", and so on.
|
||||||
Each version also provides a (dedicated) set of advanced API.
|
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` .
|
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
|
#### Multithreading support
|
||||||
@@ -57,19 +68,16 @@ Optional advanced features are exposed via :
|
|||||||
Multithreading is disabled by default when building with `make`.
|
Multithreading is disabled by default when building with `make`.
|
||||||
Enabling multithreading requires 2 conditions :
|
Enabling multithreading requires 2 conditions :
|
||||||
- set macro `ZSTD_MULTITHREAD`
|
- 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.
|
Both conditions are automatically triggered by invoking `make lib-mt` target.
|
||||||
Note that, when linking a POSIX program with a multithreaded version of `libzstd`,
|
Note that, when linking a POSIX program with a multithreaded version of `libzstd`,
|
||||||
it's necessary to trigger `-pthread` flag during link stage.
|
it's necessary to trigger `-pthread` flag during link stage.
|
||||||
|
|
||||||
Multithreading capabilities are exposed via :
|
Multithreading capabilities are exposed
|
||||||
- private API `lib/compress/zstdmt_compress.h`.
|
via [advanced API `ZSTD_compress_generic()` defined in `lib/zstd.h`](https://github.com/facebook/zstd/blob/dev/lib/zstd.h#L919).
|
||||||
Symbols defined in this header are currently exposed in `libzstd`, hence usable.
|
This API is still considered experimental,
|
||||||
Note however that this API is planned to be locked and remain strictly internal in the future.
|
but is expected to become "stable" at some point 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.
|
|
||||||
|
|
||||||
|
|
||||||
#### Windows : using MinGW+MSYS to create DLL
|
#### 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`.
|
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`.
|
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.
|
These prototypes will be removed in some future version.
|
||||||
Consider migrating code towards supported streaming API exposed in `zstd.h`.
|
Consider migrating code towards supported streaming API exposed in `zstd.h`.
|
||||||
|
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits)
|
|||||||
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
||||||
* This function is safe, it guarantees it will not read beyond src buffer.
|
* This function is safe, it guarantees it will not read beyond src buffer.
|
||||||
* @return : status of `BIT_DStream_t` internal register.
|
* @return : status of `BIT_DStream_t` internal register.
|
||||||
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
|
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
|
||||||
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
||||||
{
|
{
|
||||||
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
|
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
|
||||||
|
|||||||
@@ -63,6 +63,31 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* target attribute */
|
||||||
|
#ifndef __has_attribute
|
||||||
|
#define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
|
||||||
|
#else
|
||||||
|
# define TARGET_ATTRIBUTE(target)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Enable runtime BMI2 dispatch based on the CPU.
|
||||||
|
* Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
|
||||||
|
*/
|
||||||
|
#ifndef DYNAMIC_BMI2
|
||||||
|
#if (defined(__clang__) && __has_attribute(__target__)) \
|
||||||
|
|| (defined(__GNUC__) \
|
||||||
|
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \
|
||||||
|
&& (defined(__x86_64__) || defined(_M_X86)) \
|
||||||
|
&& !defined(__BMI2__)
|
||||||
|
# define DYNAMIC_BMI2 1
|
||||||
|
#else
|
||||||
|
# define DYNAMIC_BMI2 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* prefetch */
|
/* prefetch */
|
||||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */
|
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */
|
||||||
# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
|
# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
|
||||||
|
|||||||
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_COMMON_CPU_H
|
||||||
|
#define ZSTD_COMMON_CPU_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation taken from folly/CpuId.h
|
||||||
|
* https://github.com/facebook/folly/blob/master/folly/CpuId.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mem.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 f1c;
|
||||||
|
U32 f1d;
|
||||||
|
U32 f7b;
|
||||||
|
U32 f7c;
|
||||||
|
} ZSTD_cpuid_t;
|
||||||
|
|
||||||
|
MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
|
||||||
|
U32 f1c = 0;
|
||||||
|
U32 f1d = 0;
|
||||||
|
U32 f7b = 0;
|
||||||
|
U32 f7c = 0;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
int reg[4];
|
||||||
|
__cpuid((int*)reg, 0);
|
||||||
|
{
|
||||||
|
int const n = reg[0];
|
||||||
|
if (n >= 1) {
|
||||||
|
__cpuid((int*)reg, 1);
|
||||||
|
f1c = (U32)reg[2];
|
||||||
|
f1d = (U32)reg[3];
|
||||||
|
}
|
||||||
|
if (n >= 7) {
|
||||||
|
__cpuidex((int*)reg, 7, 0);
|
||||||
|
f7b = (U32)reg[1];
|
||||||
|
f7c = (U32)reg[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
|
||||||
|
/* The following block like the normal cpuid branch below, but gcc
|
||||||
|
* reserves ebx for use of its pic register so we must specially
|
||||||
|
* handle the save and restore to avoid clobbering the register
|
||||||
|
*/
|
||||||
|
U32 n;
|
||||||
|
__asm__(
|
||||||
|
"pushl %%ebx\n\t"
|
||||||
|
"cpuid\n\t"
|
||||||
|
"popl %%ebx\n\t"
|
||||||
|
: "=a"(n)
|
||||||
|
: "a"(0)
|
||||||
|
: "ecx", "edx");
|
||||||
|
if (n >= 1) {
|
||||||
|
U32 f1a;
|
||||||
|
__asm__(
|
||||||
|
"pushl %%ebx\n\t"
|
||||||
|
"cpuid\n\t"
|
||||||
|
"popl %%ebx\n\t"
|
||||||
|
: "=a"(f1a), "=c"(f1c), "=d"(f1d)
|
||||||
|
: "a"(1)
|
||||||
|
:);
|
||||||
|
}
|
||||||
|
if (n >= 7) {
|
||||||
|
__asm__(
|
||||||
|
"pushl %%ebx\n\t"
|
||||||
|
"cpuid\n\t"
|
||||||
|
"movl %%ebx, %%eax\n\r"
|
||||||
|
"popl %%ebx"
|
||||||
|
: "=a"(f7b), "=c"(f7c)
|
||||||
|
: "a"(7), "c"(0)
|
||||||
|
: "edx");
|
||||||
|
}
|
||||||
|
#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
|
||||||
|
U32 n;
|
||||||
|
__asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
|
||||||
|
if (n >= 1) {
|
||||||
|
U32 f1a;
|
||||||
|
__asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
|
||||||
|
}
|
||||||
|
if (n >= 7) {
|
||||||
|
U32 f7a;
|
||||||
|
__asm__("cpuid"
|
||||||
|
: "=a"(f7a), "=b"(f7b), "=c"(f7c)
|
||||||
|
: "a"(7), "c"(0)
|
||||||
|
: "edx");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ZSTD_cpuid_t cpuid;
|
||||||
|
cpuid.f1c = f1c;
|
||||||
|
cpuid.f1d = f1d;
|
||||||
|
cpuid.f7b = f7b;
|
||||||
|
cpuid.f7c = f7c;
|
||||||
|
return cpuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(name, r, bit) \
|
||||||
|
MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \
|
||||||
|
return ((cpuid.r) & (1U << bit)) != 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cpuid(1): Processor Info and Feature Bits. */
|
||||||
|
#define C(name, bit) X(name, f1c, bit)
|
||||||
|
C(sse3, 0)
|
||||||
|
C(pclmuldq, 1)
|
||||||
|
C(dtes64, 2)
|
||||||
|
C(monitor, 3)
|
||||||
|
C(dscpl, 4)
|
||||||
|
C(vmx, 5)
|
||||||
|
C(smx, 6)
|
||||||
|
C(eist, 7)
|
||||||
|
C(tm2, 8)
|
||||||
|
C(ssse3, 9)
|
||||||
|
C(cnxtid, 10)
|
||||||
|
C(fma, 12)
|
||||||
|
C(cx16, 13)
|
||||||
|
C(xtpr, 14)
|
||||||
|
C(pdcm, 15)
|
||||||
|
C(pcid, 17)
|
||||||
|
C(dca, 18)
|
||||||
|
C(sse41, 19)
|
||||||
|
C(sse42, 20)
|
||||||
|
C(x2apic, 21)
|
||||||
|
C(movbe, 22)
|
||||||
|
C(popcnt, 23)
|
||||||
|
C(tscdeadline, 24)
|
||||||
|
C(aes, 25)
|
||||||
|
C(xsave, 26)
|
||||||
|
C(osxsave, 27)
|
||||||
|
C(avx, 28)
|
||||||
|
C(f16c, 29)
|
||||||
|
C(rdrand, 30)
|
||||||
|
#undef C
|
||||||
|
#define D(name, bit) X(name, f1d, bit)
|
||||||
|
D(fpu, 0)
|
||||||
|
D(vme, 1)
|
||||||
|
D(de, 2)
|
||||||
|
D(pse, 3)
|
||||||
|
D(tsc, 4)
|
||||||
|
D(msr, 5)
|
||||||
|
D(pae, 6)
|
||||||
|
D(mce, 7)
|
||||||
|
D(cx8, 8)
|
||||||
|
D(apic, 9)
|
||||||
|
D(sep, 11)
|
||||||
|
D(mtrr, 12)
|
||||||
|
D(pge, 13)
|
||||||
|
D(mca, 14)
|
||||||
|
D(cmov, 15)
|
||||||
|
D(pat, 16)
|
||||||
|
D(pse36, 17)
|
||||||
|
D(psn, 18)
|
||||||
|
D(clfsh, 19)
|
||||||
|
D(ds, 21)
|
||||||
|
D(acpi, 22)
|
||||||
|
D(mmx, 23)
|
||||||
|
D(fxsr, 24)
|
||||||
|
D(sse, 25)
|
||||||
|
D(sse2, 26)
|
||||||
|
D(ss, 27)
|
||||||
|
D(htt, 28)
|
||||||
|
D(tm, 29)
|
||||||
|
D(pbe, 31)
|
||||||
|
#undef D
|
||||||
|
|
||||||
|
/* cpuid(7): Extended Features. */
|
||||||
|
#define B(name, bit) X(name, f7b, bit)
|
||||||
|
B(bmi1, 3)
|
||||||
|
B(hle, 4)
|
||||||
|
B(avx2, 5)
|
||||||
|
B(smep, 7)
|
||||||
|
B(bmi2, 8)
|
||||||
|
B(erms, 9)
|
||||||
|
B(invpcid, 10)
|
||||||
|
B(rtm, 11)
|
||||||
|
B(mpx, 14)
|
||||||
|
B(avx512f, 16)
|
||||||
|
B(avx512dq, 17)
|
||||||
|
B(rdseed, 18)
|
||||||
|
B(adx, 19)
|
||||||
|
B(smap, 20)
|
||||||
|
B(avx512ifma, 21)
|
||||||
|
B(pcommit, 22)
|
||||||
|
B(clflushopt, 23)
|
||||||
|
B(clwb, 24)
|
||||||
|
B(avx512pf, 26)
|
||||||
|
B(avx512er, 27)
|
||||||
|
B(avx512cd, 28)
|
||||||
|
B(sha, 29)
|
||||||
|
B(avx512bw, 30)
|
||||||
|
B(avx512vl, 31)
|
||||||
|
#undef B
|
||||||
|
#define C(name, bit) X(name, f7c, bit)
|
||||||
|
C(prefetchwt1, 0)
|
||||||
|
C(avx512vbmi, 1)
|
||||||
|
#undef C
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
#endif /* ZSTD_COMMON_CPU_H */
|
||||||
@@ -29,6 +29,7 @@ const char* ERR_getErrorString(ERR_enum code)
|
|||||||
case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
|
case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
|
||||||
case PREFIX(init_missing): return "Context should be init first";
|
case PREFIX(init_missing): return "Context should be init first";
|
||||||
case PREFIX(memory_allocation): return "Allocation error : not enough memory";
|
case PREFIX(memory_allocation): return "Allocation error : not enough memory";
|
||||||
|
case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough";
|
||||||
case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
|
case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
|
||||||
case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
|
case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
|
||||||
case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
|
case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const void* s
|
|||||||
*/
|
*/
|
||||||
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* workSpace);
|
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* workSpace);
|
||||||
|
|
||||||
/*! FSE_count_simple
|
/*! FSE_count_simple() :
|
||||||
* Same as FSE_countFast(), but does not use any additional memory (not even on stack).
|
* Same as FSE_countFast(), but does not use any additional memory (not even on stack).
|
||||||
* This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
|
* This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -139,8 +139,8 @@ size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned
|
|||||||
{ U32 u;
|
{ U32 u;
|
||||||
for (u=0; u<tableSize; u++) {
|
for (u=0; u<tableSize; u++) {
|
||||||
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
|
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
|
||||||
U16 nextState = symbolNext[symbol]++;
|
U32 const nextState = symbolNext[symbol]++;
|
||||||
tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32 ((U32)nextState) );
|
tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
|
||||||
tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
|
tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|||||||
@@ -58,31 +58,31 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================== */
|
||||||
/* *** simple functions *** */
|
/* *** simple functions *** */
|
||||||
/**
|
/* ========================== */
|
||||||
HUF_compress() :
|
|
||||||
Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
|
/** HUF_compress() :
|
||||||
'dst' buffer must be already allocated.
|
* Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
|
||||||
Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
|
* 'dst' buffer must be already allocated.
|
||||||
`srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
|
* Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
|
||||||
@return : size of compressed data (<= `dstCapacity`).
|
* `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
|
||||||
Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
|
* @return : size of compressed data (<= `dstCapacity`).
|
||||||
if return == 1, srcData is a single repeated byte symbol (RLE compression).
|
* Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
|
||||||
if HUF_isError(return), compression failed (more details using HUF_getErrorName())
|
* if HUF_isError(return), compression failed (more details using HUF_getErrorName())
|
||||||
*/
|
*/
|
||||||
HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
|
HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize);
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
/**
|
/** HUF_decompress() :
|
||||||
HUF_decompress() :
|
* Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
|
||||||
Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
|
* into already allocated buffer 'dst', of minimum size 'dstSize'.
|
||||||
into already allocated buffer 'dst', of minimum size 'dstSize'.
|
* `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
|
||||||
`originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
|
* Note : in contrast with FSE, HUF_decompress can regenerate
|
||||||
Note : in contrast with FSE, HUF_decompress can regenerate
|
* RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
|
||||||
RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
|
* because it knows size to regenerate (originalSize).
|
||||||
because it knows size to regenerate.
|
* @return : size of regenerated data (== originalSize),
|
||||||
@return : size of regenerated data (== originalSize),
|
* or an error code, which can be tested using HUF_isError()
|
||||||
or an error code, which can be tested using HUF_isError()
|
|
||||||
*/
|
*/
|
||||||
HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
|
HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
|
||||||
const void* cSrc, size_t cSrcSize);
|
const void* cSrc, size_t cSrcSize);
|
||||||
@@ -100,39 +100,32 @@ HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error c
|
|||||||
/* *** Advanced function *** */
|
/* *** Advanced function *** */
|
||||||
|
|
||||||
/** HUF_compress2() :
|
/** HUF_compress2() :
|
||||||
* Same as HUF_compress(), but offers direct control over `maxSymbolValue` and `tableLog`.
|
* Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
|
||||||
|
* `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
|
||||||
* `tableLog` must be `<= HUF_TABLELOG_MAX` . */
|
* `tableLog` must be `<= HUF_TABLELOG_MAX` . */
|
||||||
HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
|
HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
/** HUF_compress4X_wksp() :
|
/** HUF_compress4X_wksp() :
|
||||||
* Same as HUF_compress2(), but uses externally allocated `workSpace`.
|
* Same as HUF_compress2(), but uses externally allocated `workSpace`.
|
||||||
* `workspace` must have minimum alignment of 4, and be at least as large as following macro */
|
* `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */
|
||||||
#define HUF_WORKSPACE_SIZE (6 << 10)
|
#define HUF_WORKSPACE_SIZE (6 << 10)
|
||||||
#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
|
#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
|
||||||
HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
/**
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
* The minimum workspace size for the `workSpace` used in
|
void* workSpace, size_t wkspSize);
|
||||||
* HUF_readDTableX2_wksp() and HUF_readDTableX4_wksp().
|
|
||||||
*
|
|
||||||
* The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
|
|
||||||
* HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
|
|
||||||
* Buffer overflow errors may potentially occur if code modifications result in
|
|
||||||
* a required workspace size greater than that specified in the following
|
|
||||||
* macro.
|
|
||||||
*/
|
|
||||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
|
|
||||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
|
||||||
|
|
||||||
#endif /* HUF_H_298734234 */
|
#endif /* HUF_H_298734234 */
|
||||||
|
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* WARNING !!
|
* WARNING !!
|
||||||
* The following section contains advanced and experimental definitions
|
* The following section contains advanced and experimental definitions
|
||||||
* which shall never be used in the context of dll
|
* which shall never be used in the context of a dynamic library,
|
||||||
* because they are not guaranteed to remain stable in the future.
|
* because they are not guaranteed to remain stable in the future.
|
||||||
* Only consider them in association with static linking.
|
* Only consider them in association with static linking.
|
||||||
*******************************************************************/
|
* *****************************************************************/
|
||||||
#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
|
#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
|
||||||
#define HUF_H_HUF_STATIC_LINKING_ONLY
|
#define HUF_H_HUF_STATIC_LINKING_ONLY
|
||||||
|
|
||||||
@@ -141,8 +134,8 @@ HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, const
|
|||||||
|
|
||||||
|
|
||||||
/* *** Constants *** */
|
/* *** Constants *** */
|
||||||
#define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
|
#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
|
||||||
#define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
|
#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */
|
||||||
#define HUF_SYMBOLVALUE_MAX 255
|
#define HUF_SYMBOLVALUE_MAX 255
|
||||||
|
|
||||||
#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
|
#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
|
||||||
@@ -193,23 +186,22 @@ size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
|||||||
|
|
||||||
/* ****************************************
|
/* ****************************************
|
||||||
* HUF detailed API
|
* HUF detailed API
|
||||||
******************************************/
|
* ****************************************/
|
||||||
/*!
|
|
||||||
HUF_compress() does the following:
|
|
||||||
1. count symbol occurrence from source[] into table count[] using FSE_count()
|
|
||||||
2. (optional) refine tableLog using HUF_optimalTableLog()
|
|
||||||
3. build Huffman table from count using HUF_buildCTable()
|
|
||||||
4. save Huffman table to memory buffer using HUF_writeCTable()
|
|
||||||
5. encode the data stream using HUF_compress4X_usingCTable()
|
|
||||||
|
|
||||||
The following API allows targeting specific sub-functions for advanced tasks.
|
/*! HUF_compress() does the following:
|
||||||
For example, it's possible to compress several blocks using the same 'CTable',
|
* 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
|
||||||
or to save and regenerate 'CTable' using external methods.
|
* 2. (optional) refine tableLog using HUF_optimalTableLog()
|
||||||
|
* 3. build Huffman table from count using HUF_buildCTable()
|
||||||
|
* 4. save Huffman table to memory buffer using HUF_writeCTable()
|
||||||
|
* 5. encode the data stream using HUF_compress4X_usingCTable()
|
||||||
|
*
|
||||||
|
* 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" */
|
|
||||||
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
||||||
typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
|
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_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);
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
||||||
|
|
||||||
@@ -223,21 +215,27 @@ typedef enum {
|
|||||||
* If it uses hufTable it does not modify hufTable or repeat.
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
* If preferRepeat then the old table will always be used if valid. */
|
* If preferRepeat then the old table will always be used if valid. */
|
||||||
size_t HUF_compress4X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
|
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
|
||||||
|
|
||||||
/** HUF_buildCTable_wksp() :
|
/** HUF_buildCTable_wksp() :
|
||||||
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
|
* `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
|
||||||
*/
|
*/
|
||||||
|
#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
|
||||||
|
#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
|
||||||
size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize);
|
size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
/*! HUF_readStats() :
|
/*! HUF_readStats() :
|
||||||
Read compact Huffman tree, saved by HUF_writeCTable().
|
* Read compact Huffman tree, saved by HUF_writeCTable().
|
||||||
`huffWeight` is destination buffer.
|
* `huffWeight` is destination buffer.
|
||||||
@return : size read from `src` , or an error Code .
|
* @return : size read from `src` , or an error Code .
|
||||||
Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
|
* Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
|
||||||
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
|
||||||
U32* nbSymbolsPtr, U32* tableLogPtr,
|
U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
const void* src, size_t srcSize);
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
/** HUF_readCTable() :
|
/** HUF_readCTable() :
|
||||||
@@ -246,19 +244,32 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HUF_decompress() does the following:
|
* HUF_decompress() does the following:
|
||||||
1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
|
* 1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
|
||||||
2. build Huffman table from save, using HUF_readDTableXn()
|
* 2. build Huffman table from save, using HUF_readDTableX?()
|
||||||
3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable
|
* 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** HUF_selectDecoder() :
|
/** HUF_selectDecoder() :
|
||||||
* Tells which decoder is likely to decode faster,
|
* Tells which decoder is likely to decode faster,
|
||||||
* based on a set of pre-determined metrics.
|
* based on a set of pre-computed metrics.
|
||||||
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
||||||
* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
|
* Assumption : 0 < dstSize <= 128 KB */
|
||||||
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
|
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum workspace size for the `workSpace` used in
|
||||||
|
* HUF_readDTableX2_wksp() and HUF_readDTableX4_wksp().
|
||||||
|
*
|
||||||
|
* The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
|
||||||
|
* HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
|
||||||
|
* Buffer overflow errors may potentially occur if code modifications result in
|
||||||
|
* a required workspace size greater than that specified in the following
|
||||||
|
* macro.
|
||||||
|
*/
|
||||||
|
#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
|
||||||
|
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
||||||
|
|
||||||
size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||||
size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
||||||
size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||||
@@ -269,7 +280,9 @@ size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* c
|
|||||||
size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
|
||||||
|
|
||||||
|
/* ====================== */
|
||||||
/* single stream variants */
|
/* single stream variants */
|
||||||
|
/* ====================== */
|
||||||
|
|
||||||
size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
|
size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
|
||||||
size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
||||||
@@ -279,7 +292,11 @@ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, si
|
|||||||
* If it uses hufTable it does not modify hufTable or repeat.
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
* If preferRepeat then the old table will always be used if valid. */
|
* If preferRepeat then the old table will always be used if valid. */
|
||||||
size_t HUF_compress1X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
|
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
|
||||||
|
|
||||||
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
|
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
|
||||||
size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
|
size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
|
||||||
@@ -295,6 +312,14 @@ size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cS
|
|||||||
size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
|
||||||
|
/* BMI2 variants.
|
||||||
|
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
|
||||||
|
*/
|
||||||
|
size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
|
||||||
|
size_t HUF_decompress1X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
|
size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
|
||||||
|
size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
|
|
||||||
#endif /* HUF_STATIC_LINKING_ONLY */
|
#endif /* HUF_STATIC_LINKING_ONLY */
|
||||||
|
|
||||||
#if defined (__cplusplus)
|
#if defined (__cplusplus)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
/* ====== Dependencies ======= */
|
/* ====== Dependencies ======= */
|
||||||
#include <stddef.h> /* size_t */
|
#include <stddef.h> /* size_t */
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
|
#include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */
|
||||||
|
|
||||||
/* ====== Compiler specifics ====== */
|
/* ====== Compiler specifics ====== */
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
@@ -193,32 +194,54 @@ static int isQueueFull(POOL_ctx const* ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void POOL_add(void* ctxVoid, POOL_function function, void *opaque) {
|
|
||||||
POOL_ctx* const ctx = (POOL_ctx*)ctxVoid;
|
|
||||||
if (!ctx) { return; }
|
|
||||||
|
|
||||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
|
||||||
{ POOL_job const job = {function, opaque};
|
{
|
||||||
|
POOL_job const job = {function, opaque};
|
||||||
|
assert(ctx != NULL);
|
||||||
|
if (ctx->shutdown) return;
|
||||||
|
|
||||||
/* Wait until there is space in the queue for the new job */
|
|
||||||
while (isQueueFull(ctx) && !ctx->shutdown) {
|
|
||||||
ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
|
|
||||||
}
|
|
||||||
/* The queue is still going => there is space */
|
|
||||||
if (!ctx->shutdown) {
|
|
||||||
ctx->queueEmpty = 0;
|
ctx->queueEmpty = 0;
|
||||||
ctx->queue[ctx->queueTail] = job;
|
ctx->queue[ctx->queueTail] = job;
|
||||||
ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
|
ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
|
||||||
}
|
|
||||||
}
|
|
||||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
|
||||||
ZSTD_pthread_cond_signal(&ctx->queuePopCond);
|
ZSTD_pthread_cond_signal(&ctx->queuePopCond);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* ZSTD_MULTITHREAD not defined */
|
void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
|
||||||
/* No multi-threading support */
|
{
|
||||||
|
assert(ctx != NULL);
|
||||||
|
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||||
|
/* Wait until there is space in the queue for the new job */
|
||||||
|
while (isQueueFull(ctx) && (!ctx->shutdown)) {
|
||||||
|
ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
|
||||||
|
}
|
||||||
|
POOL_add_internal(ctx, function, opaque);
|
||||||
|
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||||
|
}
|
||||||
|
|
||||||
/* We don't need any data, but if it is empty malloc() might return NULL. */
|
|
||||||
|
int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
|
||||||
|
{
|
||||||
|
assert(ctx != NULL);
|
||||||
|
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||||
|
if (isQueueFull(ctx)) {
|
||||||
|
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
POOL_add_internal(ctx, function, opaque);
|
||||||
|
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else /* ZSTD_MULTITHREAD not defined */
|
||||||
|
|
||||||
|
/* ========================== */
|
||||||
|
/* No multi-threading support */
|
||||||
|
/* ========================== */
|
||||||
|
|
||||||
|
|
||||||
|
/* We don't need any data, but if it is empty, malloc() might return NULL. */
|
||||||
struct POOL_ctx_s {
|
struct POOL_ctx_s {
|
||||||
int dummy;
|
int dummy;
|
||||||
};
|
};
|
||||||
@@ -240,11 +263,17 @@ void POOL_free(POOL_ctx* ctx) {
|
|||||||
(void)ctx;
|
(void)ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void POOL_add(void* ctx, POOL_function function, void* opaque) {
|
void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
function(opaque);
|
function(opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
|
||||||
|
(void)ctx;
|
||||||
|
function(opaque);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t POOL_sizeof(POOL_ctx* ctx) {
|
size_t POOL_sizeof(POOL_ctx* ctx) {
|
||||||
if (ctx==NULL) return 0; /* supports sizeof NULL */
|
if (ctx==NULL) return 0; /* supports sizeof NULL */
|
||||||
assert(ctx == &g_ctx);
|
assert(ctx == &g_ctx);
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
#include <stddef.h> /* size_t */
|
#include <stddef.h> /* size_t */
|
||||||
#include "zstd_internal.h" /* ZSTD_customMem */
|
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */
|
||||||
|
#include "zstd.h"
|
||||||
|
|
||||||
typedef struct POOL_ctx_s POOL_ctx;
|
typedef struct POOL_ctx_s POOL_ctx;
|
||||||
|
|
||||||
@@ -51,11 +52,19 @@ typedef void (*POOL_function)(void *);
|
|||||||
typedef void (*POOL_add_function)(void*, POOL_function, void*);
|
typedef void (*POOL_add_function)(void*, POOL_function, void*);
|
||||||
|
|
||||||
/*! POOL_add() :
|
/*! POOL_add() :
|
||||||
Add the job `function(opaque)` to the thread pool.
|
Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
|
||||||
Possibly blocks until there is room in the queue.
|
Possibly blocks until there is room in the queue.
|
||||||
Note : The function may be executed asynchronously, so `opaque` must live until the function has been completed.
|
Note : The function may be executed asynchronously, so `opaque` must live until the function has been completed.
|
||||||
*/
|
*/
|
||||||
void POOL_add(void *ctx, POOL_function function, void *opaque);
|
void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque);
|
||||||
|
|
||||||
|
|
||||||
|
/*! POOL_tryAdd() :
|
||||||
|
Add the job `function(opaque)` to the thread pool if a worker is available.
|
||||||
|
return immediately otherwise.
|
||||||
|
@return : 1 if successful, 0 if not.
|
||||||
|
*/
|
||||||
|
int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
|
||||||
|
|
||||||
|
|
||||||
#if defined (__cplusplus)
|
#if defined (__cplusplus)
|
||||||
|
|||||||
@@ -45,15 +45,15 @@ extern "C" {
|
|||||||
|
|
||||||
/* mutex */
|
/* mutex */
|
||||||
#define ZSTD_pthread_mutex_t CRITICAL_SECTION
|
#define ZSTD_pthread_mutex_t CRITICAL_SECTION
|
||||||
#define ZSTD_pthread_mutex_init(a, b) (InitializeCriticalSection((a)), 0)
|
#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0)
|
||||||
#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a))
|
#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a))
|
||||||
#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a))
|
#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a))
|
||||||
#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a))
|
#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a))
|
||||||
|
|
||||||
/* condition variable */
|
/* condition variable */
|
||||||
#define ZSTD_pthread_cond_t CONDITION_VARIABLE
|
#define ZSTD_pthread_cond_t CONDITION_VARIABLE
|
||||||
#define ZSTD_pthread_cond_init(a, b) (InitializeConditionVariable((a)), 0)
|
#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0)
|
||||||
#define ZSTD_pthread_cond_destroy(a) /* No delete */
|
#define ZSTD_pthread_cond_destroy(a) ((void)(a))
|
||||||
#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE)
|
#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE)
|
||||||
#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a))
|
#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a))
|
||||||
#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a))
|
#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a))
|
||||||
@@ -100,17 +100,17 @@ int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr);
|
|||||||
/* No multithreading support */
|
/* No multithreading support */
|
||||||
|
|
||||||
typedef int ZSTD_pthread_mutex_t;
|
typedef int ZSTD_pthread_mutex_t;
|
||||||
#define ZSTD_pthread_mutex_init(a, b) ((void)a, 0)
|
#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0)
|
||||||
#define ZSTD_pthread_mutex_destroy(a)
|
#define ZSTD_pthread_mutex_destroy(a) ((void)(a))
|
||||||
#define ZSTD_pthread_mutex_lock(a)
|
#define ZSTD_pthread_mutex_lock(a) ((void)(a))
|
||||||
#define ZSTD_pthread_mutex_unlock(a)
|
#define ZSTD_pthread_mutex_unlock(a) ((void)(a))
|
||||||
|
|
||||||
typedef int ZSTD_pthread_cond_t;
|
typedef int ZSTD_pthread_cond_t;
|
||||||
#define ZSTD_pthread_cond_init(a, b) ((void)a, 0)
|
#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0)
|
||||||
#define ZSTD_pthread_cond_destroy(a)
|
#define ZSTD_pthread_cond_destroy(a) ((void)(a))
|
||||||
#define ZSTD_pthread_cond_wait(a, b)
|
#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b))
|
||||||
#define ZSTD_pthread_cond_signal(a)
|
#define ZSTD_pthread_cond_signal(a) ((void)(a))
|
||||||
#define ZSTD_pthread_cond_broadcast(a)
|
#define ZSTD_pthread_cond_broadcast(a) ((void)(a))
|
||||||
|
|
||||||
/* do not use ZSTD_pthread_t */
|
/* do not use ZSTD_pthread_t */
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,20 @@ extern "C" {
|
|||||||
# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY
|
# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-****************************************
|
/*-*********************************************
|
||||||
* error codes list
|
* Error codes list
|
||||||
* note : this API is still considered unstable
|
*-*********************************************
|
||||||
* and shall not be used with a dynamic library.
|
* Error codes _values_ are pinned down since v1.3.1 only.
|
||||||
* only static linking is allowed
|
* Therefore, don't rely on values if you may link to any version < v1.3.1.
|
||||||
******************************************/
|
*
|
||||||
|
* Only values < 100 are considered stable.
|
||||||
|
*
|
||||||
|
* note 1 : this API shall be used with static linking only.
|
||||||
|
* dynamic linking is not yet officially supported.
|
||||||
|
* note 2 : Prefer relying on the enum than on its value whenever possible
|
||||||
|
* This is the only supported way to use the error list < v1.3.1
|
||||||
|
* note 3 : ZSTD_isError() is always correct, whatever the library version.
|
||||||
|
**********************************************/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ZSTD_error_no_error = 0,
|
ZSTD_error_no_error = 0,
|
||||||
ZSTD_error_GENERIC = 1,
|
ZSTD_error_GENERIC = 1,
|
||||||
@@ -61,9 +69,10 @@ typedef enum {
|
|||||||
ZSTD_error_stage_wrong = 60,
|
ZSTD_error_stage_wrong = 60,
|
||||||
ZSTD_error_init_missing = 62,
|
ZSTD_error_init_missing = 62,
|
||||||
ZSTD_error_memory_allocation = 64,
|
ZSTD_error_memory_allocation = 64,
|
||||||
|
ZSTD_error_workSpace_tooSmall= 66,
|
||||||
ZSTD_error_dstSize_tooSmall = 70,
|
ZSTD_error_dstSize_tooSmall = 70,
|
||||||
ZSTD_error_srcSize_wrong = 72,
|
ZSTD_error_srcSize_wrong = 72,
|
||||||
/* following error codes are not stable and may be removed or changed in a future version */
|
/* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
|
||||||
ZSTD_error_frameIndex_tooLarge = 100,
|
ZSTD_error_frameIndex_tooLarge = 100,
|
||||||
ZSTD_error_seekableIO = 102,
|
ZSTD_error_seekableIO = 102,
|
||||||
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy
|
|||||||
#define MLFSELog 9
|
#define MLFSELog 9
|
||||||
#define LLFSELog 9
|
#define LLFSELog 9
|
||||||
#define OffFSELog 8
|
#define OffFSELog 8
|
||||||
|
#define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
|
||||||
|
|
||||||
static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
@@ -228,8 +229,6 @@ typedef struct {
|
|||||||
BYTE* ofCode;
|
BYTE* ofCode;
|
||||||
U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
|
U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
|
||||||
U32 longLengthPos;
|
U32 longLengthPos;
|
||||||
U32 rep[ZSTD_REP_NUM];
|
|
||||||
U32 repToConfirm[ZSTD_REP_NUM];
|
|
||||||
} seqStore_t;
|
} seqStore_t;
|
||||||
|
|
||||||
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
|
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
|||||||
bitCount -= (count<max);
|
bitCount -= (count<max);
|
||||||
previous0 = (count==1);
|
previous0 = (count==1);
|
||||||
if (remaining<1) return ERROR(GENERIC);
|
if (remaining<1) return ERROR(GENERIC);
|
||||||
while (remaining<threshold) nbBits--, threshold>>=1;
|
while (remaining<threshold) { nbBits--; threshold>>=1; }
|
||||||
}
|
}
|
||||||
if (bitCount>16) {
|
if (bitCount>16) {
|
||||||
if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
|
if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
|
||||||
@@ -292,7 +292,7 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalized
|
|||||||
It doesn't use any additional memory.
|
It doesn't use any additional memory.
|
||||||
But this function is unsafe : it doesn't check that all values within `src` can fit into `count`.
|
But this function is unsafe : it doesn't check that all values within `src` can fit into `count`.
|
||||||
For this reason, prefer using a table `count` with 256 elements.
|
For this reason, prefer using a table `count` with 256 elements.
|
||||||
@return : count of most numerous element
|
@return : count of most numerous element.
|
||||||
*/
|
*/
|
||||||
size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
const void* src, size_t srcSize)
|
const void* src, size_t srcSize)
|
||||||
@@ -305,7 +305,10 @@ size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
|||||||
memset(count, 0, (maxSymbolValue+1)*sizeof(*count));
|
memset(count, 0, (maxSymbolValue+1)*sizeof(*count));
|
||||||
if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
|
if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
|
||||||
|
|
||||||
while (ip<end) count[*ip++]++;
|
while (ip<end) {
|
||||||
|
assert(*ip <= maxSymbolValue);
|
||||||
|
count[*ip++]++;
|
||||||
|
}
|
||||||
|
|
||||||
while (!count[maxSymbolValue]) maxSymbolValue--;
|
while (!count[maxSymbolValue]) maxSymbolValue--;
|
||||||
*maxSymbolValuePtr = maxSymbolValue;
|
*maxSymbolValuePtr = maxSymbolValue;
|
||||||
@@ -318,7 +321,8 @@ size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
|||||||
|
|
||||||
/* FSE_count_parallel_wksp() :
|
/* FSE_count_parallel_wksp() :
|
||||||
* Same as FSE_count_parallel(), but using an externally provided scratch buffer.
|
* Same as FSE_count_parallel(), but using an externally provided scratch buffer.
|
||||||
* `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`` */
|
* `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`.
|
||||||
|
* @return : largest histogram frequency, or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */
|
||||||
static size_t FSE_count_parallel_wksp(
|
static size_t FSE_count_parallel_wksp(
|
||||||
unsigned* count, unsigned* maxSymbolValuePtr,
|
unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
const void* source, size_t sourceSize,
|
const void* source, size_t sourceSize,
|
||||||
@@ -333,7 +337,7 @@ static size_t FSE_count_parallel_wksp(
|
|||||||
U32* const Counting3 = Counting2 + 256;
|
U32* const Counting3 = Counting2 + 256;
|
||||||
U32* const Counting4 = Counting3 + 256;
|
U32* const Counting4 = Counting3 + 256;
|
||||||
|
|
||||||
memset(Counting1, 0, 4*256*sizeof(unsigned));
|
memset(workSpace, 0, 4*256*sizeof(unsigned));
|
||||||
|
|
||||||
/* safety checks */
|
/* safety checks */
|
||||||
if (!sourceSize) {
|
if (!sourceSize) {
|
||||||
@@ -379,7 +383,9 @@ static size_t FSE_count_parallel_wksp(
|
|||||||
if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
|
if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
|
||||||
} }
|
} }
|
||||||
|
|
||||||
{ U32 s; for (s=0; s<=maxSymbolValue; s++) {
|
{ U32 s;
|
||||||
|
if (maxSymbolValue > 255) maxSymbolValue = 255;
|
||||||
|
for (s=0; s<=maxSymbolValue; s++) {
|
||||||
count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
|
count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
|
||||||
if (count[s] > max) max = count[s];
|
if (count[s] > max) max = count[s];
|
||||||
} }
|
} }
|
||||||
@@ -393,9 +399,11 @@ static size_t FSE_count_parallel_wksp(
|
|||||||
* Same as FSE_countFast(), but using an externally provided scratch buffer.
|
* Same as FSE_countFast(), but using an externally provided scratch buffer.
|
||||||
* `workSpace` size must be table of >= `1024` unsigned */
|
* `workSpace` size must be table of >= `1024` unsigned */
|
||||||
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
const void* source, size_t sourceSize, unsigned* workSpace)
|
const void* source, size_t sourceSize,
|
||||||
|
unsigned* workSpace)
|
||||||
{
|
{
|
||||||
if (sourceSize < 1500) return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
|
if (sourceSize < 1500) /* heuristic threshold */
|
||||||
|
return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
|
||||||
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
|
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +548,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
|
|||||||
find max, then give all remaining points to max */
|
find max, then give all remaining points to max */
|
||||||
U32 maxV = 0, maxC = 0;
|
U32 maxV = 0, maxC = 0;
|
||||||
for (s=0; s<=maxSymbolValue; s++)
|
for (s=0; s<=maxSymbolValue; s++)
|
||||||
if (count[s] > maxC) maxV=s, maxC=count[s];
|
if (count[s] > maxC) { maxV=s; maxC=count[s]; }
|
||||||
norm[maxV] += (short)ToDistribute;
|
norm[maxV] += (short)ToDistribute;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -548,7 +556,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
|
|||||||
if (total == 0) {
|
if (total == 0) {
|
||||||
/* all of the symbols were low enough for the lowOne or lowThreshold */
|
/* all of the symbols were low enough for the lowOne or lowThreshold */
|
||||||
for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
|
for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
|
||||||
if (norm[s] > 0) ToDistribute--, norm[s]++;
|
if (norm[s] > 0) { ToDistribute--; norm[s]++; }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,7 +612,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
|
|||||||
U64 restToBeat = vStep * rtbTable[proba];
|
U64 restToBeat = vStep * rtbTable[proba];
|
||||||
proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
|
proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
|
||||||
}
|
}
|
||||||
if (proba > largestP) largestP=proba, largest=s;
|
if (proba > largestP) { largestP=proba; largest=s; }
|
||||||
normalizedCounter[s] = proba;
|
normalizedCounter[s] = proba;
|
||||||
stillToDistribute -= proba;
|
stillToDistribute -= proba;
|
||||||
} }
|
} }
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
#include <string.h> /* memcpy, memset */
|
#include <string.h> /* memcpy, memset */
|
||||||
#include <stdio.h> /* printf (debug) */
|
#include <stdio.h> /* printf (debug) */
|
||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
|
#include "compiler.h"
|
||||||
#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
|
#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
|
||||||
#include "fse.h" /* header compression */
|
#include "fse.h" /* header compression */
|
||||||
#define HUF_STATIC_LINKING_ONLY
|
#define HUF_STATIC_LINKING_ONLY
|
||||||
@@ -322,7 +323,10 @@ static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue)
|
|||||||
U32 const c = count[n];
|
U32 const c = count[n];
|
||||||
U32 const r = BIT_highbit32(c+1) + 1;
|
U32 const r = BIT_highbit32(c+1) + 1;
|
||||||
U32 pos = rank[r].current++;
|
U32 pos = rank[r].current++;
|
||||||
while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) huffNode[pos]=huffNode[pos-1], pos--;
|
while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) {
|
||||||
|
huffNode[pos] = huffNode[pos-1];
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
huffNode[pos].count = c;
|
huffNode[pos].count = c;
|
||||||
huffNode[pos].byte = (BYTE)n;
|
huffNode[pos].byte = (BYTE)n;
|
||||||
}
|
}
|
||||||
@@ -331,10 +335,10 @@ static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue)
|
|||||||
|
|
||||||
/** HUF_buildCTable_wksp() :
|
/** HUF_buildCTable_wksp() :
|
||||||
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
|
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of HUF_CTABLE_WORKSPACE_SIZE_U32 unsigned.
|
||||||
*/
|
*/
|
||||||
#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
|
#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
|
||||||
typedef nodeElt huffNodeTable[2*HUF_SYMBOLVALUE_MAX+1 +1];
|
typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32];
|
||||||
size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
|
size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
|
||||||
{
|
{
|
||||||
nodeElt* const huffNode0 = (nodeElt*)workSpace;
|
nodeElt* const huffNode0 = (nodeElt*)workSpace;
|
||||||
@@ -345,9 +349,10 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValu
|
|||||||
U32 nodeRoot;
|
U32 nodeRoot;
|
||||||
|
|
||||||
/* safety checks */
|
/* safety checks */
|
||||||
if (wkspSize < sizeof(huffNodeTable)) return ERROR(GENERIC); /* workSpace is not large enough */
|
if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
|
||||||
|
if (wkspSize < sizeof(huffNodeTable)) return ERROR(workSpace_tooSmall);
|
||||||
if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
|
if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
|
||||||
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(GENERIC);
|
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
||||||
memset(huffNode0, 0, sizeof(huffNodeTable));
|
memset(huffNode0, 0, sizeof(huffNodeTable));
|
||||||
|
|
||||||
/* sort, decreasing order */
|
/* sort, decreasing order */
|
||||||
@@ -405,6 +410,7 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** HUF_buildCTable() :
|
/** HUF_buildCTable() :
|
||||||
|
* @return : maxNbBits
|
||||||
* Note : count is used before tree is written, so they can safely overlap
|
* 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)
|
size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits)
|
||||||
@@ -432,13 +438,14 @@ static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, uns
|
|||||||
return !bad;
|
return !bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
|
size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE void
|
||||||
|
HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
|
||||||
{
|
{
|
||||||
BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
|
BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
|
|
||||||
|
|
||||||
#define HUF_FLUSHBITS(s) BIT_flushBits(s)
|
#define HUF_FLUSHBITS(s) BIT_flushBits(s)
|
||||||
|
|
||||||
#define HUF_FLUSHBITS_1(stream) \
|
#define HUF_FLUSHBITS_1(stream) \
|
||||||
@@ -447,7 +454,10 @@ size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
|
|||||||
#define HUF_FLUSHBITS_2(stream) \
|
#define HUF_FLUSHBITS_2(stream) \
|
||||||
if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
|
if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
|
||||||
|
|
||||||
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const HUF_CElt* CTable)
|
||||||
{
|
{
|
||||||
const BYTE* ip = (const BYTE*) src;
|
const BYTE* ip = (const BYTE*) src;
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
@@ -491,8 +501,58 @@ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, si
|
|||||||
return BIT_closeCStream(&bitC);
|
return BIT_closeCStream(&bitC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
|
||||||
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
static TARGET_ATTRIBUTE("bmi2") size_t
|
||||||
|
HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const HUF_CElt* CTable, const int bmi2)
|
||||||
|
{
|
||||||
|
if (bmi2) {
|
||||||
|
return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable);
|
||||||
|
}
|
||||||
|
return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const HUF_CElt* CTable, const int bmi2)
|
||||||
|
{
|
||||||
|
(void)bmi2;
|
||||||
|
return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const HUF_CElt* CTable, int bmi2)
|
||||||
{
|
{
|
||||||
size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
|
size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
|
||||||
const BYTE* ip = (const BYTE*) src;
|
const BYTE* ip = (const BYTE*) src;
|
||||||
@@ -505,28 +565,31 @@ size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, si
|
|||||||
if (srcSize < 12) return 0; /* no saving possible : too small input */
|
if (srcSize < 12) return 0; /* no saving possible : too small input */
|
||||||
op += 6; /* jumpTable */
|
op += 6; /* jumpTable */
|
||||||
|
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
|
||||||
if (cSize==0) return 0;
|
if (cSize==0) return 0;
|
||||||
|
assert(cSize <= 65535);
|
||||||
MEM_writeLE16(ostart, (U16)cSize);
|
MEM_writeLE16(ostart, (U16)cSize);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip += segmentSize;
|
ip += segmentSize;
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
|
||||||
if (cSize==0) return 0;
|
if (cSize==0) return 0;
|
||||||
|
assert(cSize <= 65535);
|
||||||
MEM_writeLE16(ostart+2, (U16)cSize);
|
MEM_writeLE16(ostart+2, (U16)cSize);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip += segmentSize;
|
ip += segmentSize;
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
|
||||||
if (cSize==0) return 0;
|
if (cSize==0) return 0;
|
||||||
|
assert(cSize <= 65535);
|
||||||
MEM_writeLE16(ostart+4, (U16)cSize);
|
MEM_writeLE16(ostart+4, (U16)cSize);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip += segmentSize;
|
ip += segmentSize;
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, iend-ip, CTable) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, iend-ip, CTable, bmi2) );
|
||||||
if (cSize==0) return 0;
|
if (cSize==0) return 0;
|
||||||
op += cSize;
|
op += cSize;
|
||||||
}
|
}
|
||||||
@@ -534,15 +597,20 @@ size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, si
|
|||||||
return op-ostart;
|
return op-ostart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t HUF_compressCTable_internal(
|
static size_t HUF_compressCTable_internal(
|
||||||
BYTE* const ostart, BYTE* op, BYTE* const oend,
|
BYTE* const ostart, BYTE* op, BYTE* const oend,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned singleStream, const HUF_CElt* CTable)
|
unsigned singleStream, const HUF_CElt* CTable, const int bmi2)
|
||||||
{
|
{
|
||||||
size_t const cSize = singleStream ?
|
size_t const cSize = singleStream ?
|
||||||
HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable) :
|
HUF_compress1X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2) :
|
||||||
HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable);
|
HUF_compress4X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2);
|
||||||
if (HUF_isError(cSize)) { return cSize; }
|
if (HUF_isError(cSize)) { return cSize; }
|
||||||
if (cSize==0) { return 0; } /* uncompressible */
|
if (cSize==0) { return 0; } /* uncompressible */
|
||||||
op += cSize;
|
op += cSize;
|
||||||
@@ -551,86 +619,98 @@ static size_t HUF_compressCTable_internal(
|
|||||||
return op-ostart;
|
return op-ostart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 count[HUF_SYMBOLVALUE_MAX + 1];
|
||||||
|
HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
|
||||||
|
huffNodeTable nodeTable;
|
||||||
|
} HUF_compress_tables_t;
|
||||||
|
|
||||||
/* `workSpace` must a table of at least 1024 unsigned */
|
/* HUF_compress_internal() :
|
||||||
|
* `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
||||||
static size_t HUF_compress_internal (
|
static size_t HUF_compress_internal (
|
||||||
void* dst, size_t dstSize,
|
void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
unsigned singleStream,
|
unsigned singleStream,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat)
|
HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
|
||||||
|
const int bmi2)
|
||||||
{
|
{
|
||||||
|
HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace;
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
BYTE* const oend = ostart + dstSize;
|
BYTE* const oend = ostart + dstSize;
|
||||||
BYTE* op = ostart;
|
BYTE* op = ostart;
|
||||||
|
|
||||||
U32* count;
|
|
||||||
size_t const countSize = sizeof(U32) * (HUF_SYMBOLVALUE_MAX + 1);
|
|
||||||
HUF_CElt* CTable;
|
|
||||||
size_t const CTableSize = sizeof(HUF_CElt) * (HUF_SYMBOLVALUE_MAX + 1);
|
|
||||||
|
|
||||||
/* checks & inits */
|
/* checks & inits */
|
||||||
if (wkspSize < sizeof(huffNodeTable) + countSize + CTableSize) return ERROR(GENERIC);
|
if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
|
||||||
if (!srcSize) return 0; /* Uncompressed (note : 1 means rle, so first byte must be correct) */
|
if (wkspSize < sizeof(*table)) return ERROR(workSpace_tooSmall);
|
||||||
if (!dstSize) return 0; /* cannot fit within dst budget */
|
if (!srcSize) return 0; /* Uncompressed */
|
||||||
|
if (!dstSize) return 0; /* cannot fit anything within dst budget */
|
||||||
if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
|
if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
|
||||||
if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||||
|
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
||||||
if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
|
if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
|
||||||
if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
|
if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
|
||||||
|
|
||||||
count = (U32*)workSpace;
|
/* Heuristic : If old table is valid, use it for small inputs */
|
||||||
workSpace = (BYTE*)workSpace + countSize;
|
|
||||||
wkspSize -= countSize;
|
|
||||||
CTable = (HUF_CElt*)workSpace;
|
|
||||||
workSpace = (BYTE*)workSpace + CTableSize;
|
|
||||||
wkspSize -= CTableSize;
|
|
||||||
|
|
||||||
/* Heuristic : If we don't need to check the validity of the old table use the old table for small inputs */
|
|
||||||
if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
|
if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
|
||||||
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
|
src, srcSize,
|
||||||
|
singleStream, oldHufTable, bmi2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan input and build symbol stats */
|
/* Scan input and build symbol stats */
|
||||||
{ CHECK_V_F(largest, FSE_count_wksp (count, &maxSymbolValue, (const BYTE*)src, srcSize, (U32*)workSpace) );
|
{ CHECK_V_F(largest, FSE_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, table->count) );
|
||||||
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
|
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
|
||||||
if (largest <= (srcSize >> 7)+1) return 0; /* Fast heuristic : not compressible enough */
|
if (largest <= (srcSize >> 7)+1) return 0; /* heuristic : probably not compressible enough */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check validity of previous table */
|
/* Check validity of previous table */
|
||||||
if (repeat && *repeat == HUF_repeat_check && !HUF_validateCTable(oldHufTable, count, maxSymbolValue)) {
|
if ( repeat
|
||||||
|
&& *repeat == HUF_repeat_check
|
||||||
|
&& !HUF_validateCTable(oldHufTable, table->count, maxSymbolValue)) {
|
||||||
*repeat = HUF_repeat_none;
|
*repeat = HUF_repeat_none;
|
||||||
}
|
}
|
||||||
/* Heuristic : use existing table for small inputs */
|
/* Heuristic : use existing table for small inputs */
|
||||||
if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
|
if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
|
||||||
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
|
src, srcSize,
|
||||||
|
singleStream, oldHufTable, bmi2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build Huffman Tree */
|
/* Build Huffman Tree */
|
||||||
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
||||||
{ CHECK_V_F(maxBits, HUF_buildCTable_wksp (CTable, count, maxSymbolValue, huffLog, workSpace, wkspSize) );
|
{ CHECK_V_F(maxBits, HUF_buildCTable_wksp(table->CTable, table->count,
|
||||||
|
maxSymbolValue, huffLog,
|
||||||
|
table->nodeTable, sizeof(table->nodeTable)) );
|
||||||
huffLog = (U32)maxBits;
|
huffLog = (U32)maxBits;
|
||||||
/* Zero the unused symbols so we can check it for validity */
|
/* Zero unused symbols in CTable, so we can check it for validity */
|
||||||
memset(CTable + maxSymbolValue + 1, 0, CTableSize - (maxSymbolValue + 1) * sizeof(HUF_CElt));
|
memset(table->CTable + (maxSymbolValue + 1), 0,
|
||||||
|
sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write table description header */
|
/* Write table description header */
|
||||||
{ CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, CTable, maxSymbolValue, huffLog) );
|
{ CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
|
||||||
/* Check if using the previous table will be beneficial */
|
/* Check if using previous huffman table is beneficial */
|
||||||
if (repeat && *repeat != HUF_repeat_none) {
|
if (repeat && *repeat != HUF_repeat_none) {
|
||||||
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, count, maxSymbolValue);
|
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
|
||||||
size_t const newSize = HUF_estimateCompressedSize(CTable, count, maxSymbolValue);
|
size_t const newSize = HUF_estimateCompressedSize(table->CTable, table->count, maxSymbolValue);
|
||||||
if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
|
if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
|
||||||
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
}
|
src, srcSize,
|
||||||
}
|
singleStream, oldHufTable, bmi2);
|
||||||
/* Use the new table */
|
} }
|
||||||
|
|
||||||
|
/* Use the new huffman table */
|
||||||
if (hSize + 12ul >= srcSize) { return 0; }
|
if (hSize + 12ul >= srcSize) { return 0; }
|
||||||
op += hSize;
|
op += hSize;
|
||||||
if (repeat) { *repeat = HUF_repeat_none; }
|
if (repeat) { *repeat = HUF_repeat_none; }
|
||||||
if (oldHufTable) { memcpy(oldHufTable, CTable, CTableSize); } /* Save the new table */
|
if (oldHufTable)
|
||||||
|
memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */
|
||||||
}
|
}
|
||||||
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, CTable);
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
|
src, srcSize,
|
||||||
|
singleStream, table->CTable, bmi2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -639,52 +719,70 @@ size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
|
|||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize)
|
void* workSpace, size_t wkspSize)
|
||||||
{
|
{
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, NULL, NULL, 0);
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
|
maxSymbolValue, huffLog, 1 /*single stream*/,
|
||||||
|
workSpace, wkspSize,
|
||||||
|
NULL, NULL, 0, 0 /*bmi2*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat)
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
|
||||||
{
|
{
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, hufTable, repeat, preferRepeat);
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
|
maxSymbolValue, huffLog, 1 /*single stream*/,
|
||||||
|
workSpace, wkspSize, hufTable,
|
||||||
|
repeat, preferRepeat, bmi2);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compress1X (void* dst, size_t dstSize,
|
size_t HUF_compress1X (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog)
|
unsigned maxSymbolValue, unsigned huffLog)
|
||||||
{
|
{
|
||||||
unsigned workSpace[1024];
|
unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
|
||||||
return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
|
return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* HUF_compress4X_repeat():
|
||||||
|
* compress input using 4 streams.
|
||||||
|
* provide workspace to generate compression tables */
|
||||||
size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
|
size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize)
|
void* workSpace, size_t wkspSize)
|
||||||
{
|
{
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, NULL, NULL, 0);
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
|
maxSymbolValue, huffLog, 0 /*4 streams*/,
|
||||||
|
workSpace, wkspSize,
|
||||||
|
NULL, NULL, 0, 0 /*bmi2*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* HUF_compress4X_repeat():
|
||||||
|
* compress input using 4 streams.
|
||||||
|
* re-use an existing huffman compression table */
|
||||||
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat)
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
|
||||||
{
|
{
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, hufTable, repeat, preferRepeat);
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
|
maxSymbolValue, huffLog, 0 /* 4 streams */,
|
||||||
|
workSpace, wkspSize,
|
||||||
|
hufTable, repeat, preferRepeat, bmi2);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compress2 (void* dst, size_t dstSize,
|
size_t HUF_compress2 (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog)
|
unsigned maxSymbolValue, unsigned huffLog)
|
||||||
{
|
{
|
||||||
unsigned workSpace[1024];
|
unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
|
||||||
return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
|
return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return HUF_compress2(dst, maxDstSize, src, (U32)srcSize, 255, HUF_TABLELOG_DEFAULT);
|
return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
* Dependencies
|
* Dependencies
|
||||||
***************************************/
|
***************************************/
|
||||||
#include <string.h> /* memset */
|
#include <string.h> /* memset */
|
||||||
|
#include "cpu.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
|
#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
|
||||||
#include "fse.h"
|
#include "fse.h"
|
||||||
@@ -49,7 +50,13 @@ struct ZSTD_CDict_s {
|
|||||||
void* dictBuffer;
|
void* dictBuffer;
|
||||||
const void* dictContent;
|
const void* dictContent;
|
||||||
size_t dictContentSize;
|
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" */
|
}; /* typedef'd to ZSTD_CDict within "zstd.h" */
|
||||||
|
|
||||||
ZSTD_CCtx* ZSTD_createCCtx(void)
|
ZSTD_CCtx* ZSTD_createCCtx(void)
|
||||||
@@ -59,19 +66,18 @@ ZSTD_CCtx* ZSTD_createCCtx(void)
|
|||||||
|
|
||||||
ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
|
ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
|
||||||
{
|
{
|
||||||
ZSTD_CCtx* cctx;
|
ZSTD_STATIC_ASSERT(zcss_init==0);
|
||||||
|
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
|
||||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||||
|
{ ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
|
||||||
cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
|
|
||||||
if (!cctx) return NULL;
|
if (!cctx) return NULL;
|
||||||
cctx->customMem = customMem;
|
cctx->customMem = customMem;
|
||||||
cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
||||||
cctx->requestedParams.fParams.contentSizeFlag = 1;
|
cctx->requestedParams.fParams.contentSizeFlag = 1;
|
||||||
ZSTD_STATIC_ASSERT(zcss_init==0);
|
cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
|
|
||||||
return cctx;
|
return cctx;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
|
ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
|
||||||
{
|
{
|
||||||
@@ -83,11 +89,16 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
|
|||||||
cctx->workSpace = (void*)(cctx+1);
|
cctx->workSpace = (void*)(cctx+1);
|
||||||
cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
|
cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
|
||||||
|
|
||||||
/* entropy space (never moves) */
|
/* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
|
||||||
if (cctx->workSpaceSize < sizeof(ZSTD_entropyCTables_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 */
|
assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
|
||||||
cctx->entropy = (ZSTD_entropyCTables_t*)cctx->workSpace;
|
cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace;
|
||||||
|
cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1;
|
||||||
|
{
|
||||||
|
void* const ptr = cctx->blockState.nextCBlock + 1;
|
||||||
|
cctx->entropyWorkspace = (U32*)ptr;
|
||||||
|
}
|
||||||
|
cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||||
return cctx;
|
return cctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,13 +106,10 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
|
|||||||
{
|
{
|
||||||
if (cctx==NULL) return 0; /* support free on NULL */
|
if (cctx==NULL) return 0; /* support free on NULL */
|
||||||
if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
|
if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
|
||||||
ZSTD_free(cctx->workSpace, cctx->customMem);
|
ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL;
|
||||||
cctx->workSpace = NULL;
|
ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL;
|
||||||
ZSTD_freeCDict(cctx->cdictLocal);
|
|
||||||
cctx->cdictLocal = NULL;
|
|
||||||
#ifdef ZSTD_MULTITHREAD
|
#ifdef ZSTD_MULTITHREAD
|
||||||
ZSTDMT_freeCCtx(cctx->mtctx);
|
ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
|
||||||
cctx->mtctx = NULL;
|
|
||||||
#endif
|
#endif
|
||||||
ZSTD_free(cctx, cctx->customMem);
|
ZSTD_free(cctx, cctx->customMem);
|
||||||
return 0; /* reserved as a potential error code in the future */
|
return 0; /* reserved as a potential error code in the future */
|
||||||
@@ -122,10 +130,6 @@ static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
|
|||||||
size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
|
size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
|
||||||
{
|
{
|
||||||
if (cctx==NULL) return 0; /* support sizeof on NULL */
|
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
|
return sizeof(*cctx) + cctx->workSpaceSize
|
||||||
+ ZSTD_sizeof_CDict(cctx->cdictLocal)
|
+ ZSTD_sizeof_CDict(cctx->cdictLocal)
|
||||||
+ ZSTD_sizeof_mtctx(cctx);
|
+ ZSTD_sizeof_mtctx(cctx);
|
||||||
@@ -139,37 +143,19 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
|
|||||||
/* private API call, for dictBuilder only */
|
/* private API call, for dictBuilder only */
|
||||||
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
|
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
|
||||||
|
|
||||||
#define ZSTD_CLEVEL_CUSTOM 999
|
ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
||||||
|
const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
|
||||||
static ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
|
||||||
ZSTD_CCtx_params CCtxParams, U64 srcSizeHint, size_t dictSize)
|
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_getCParamsFromCCtxParams: srcSize = %u, dictSize = %u",
|
ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize);
|
||||||
(U32)srcSizeHint, (U32)dictSize);
|
if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
|
||||||
return (CCtxParams.compressionLevel == ZSTD_CLEVEL_CUSTOM) ?
|
if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
|
||||||
CCtxParams.cParams :
|
if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
|
||||||
ZSTD_getCParams(CCtxParams.compressionLevel, srcSizeHint, dictSize);
|
if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
|
||||||
}
|
if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
|
||||||
|
if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength;
|
||||||
static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* CCtxParams, U64 srcSize)
|
if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
|
||||||
{
|
if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
|
||||||
DEBUGLOG(4, "ZSTD_cLevelToCCtxParams_srcSize: srcSize = %u",
|
return cParams;
|
||||||
(U32)srcSize);
|
|
||||||
CCtxParams->cParams = ZSTD_getCParamsFromCCtxParams(*CCtxParams, srcSize, 0);
|
|
||||||
CCtxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
|
|
||||||
{
|
|
||||||
DEBUGLOG(4, "ZSTD_cLevelToCParams: level=%i", cctx->requestedParams.compressionLevel);
|
|
||||||
ZSTD_cLevelToCCtxParams_srcSize(
|
|
||||||
&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* CCtxParams)
|
|
||||||
{
|
|
||||||
DEBUGLOG(4, "ZSTD_cLevelToCCtxParams");
|
|
||||||
ZSTD_cLevelToCCtxParams_srcSize(CCtxParams, ZSTD_CONTENTSIZE_UNKNOWN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
||||||
@@ -178,7 +164,9 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
|||||||
ZSTD_CCtx_params cctxParams;
|
ZSTD_CCtx_params cctxParams;
|
||||||
memset(&cctxParams, 0, sizeof(cctxParams));
|
memset(&cctxParams, 0, sizeof(cctxParams));
|
||||||
cctxParams.cParams = cParams;
|
cctxParams.cParams = cParams;
|
||||||
cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
|
||||||
|
assert(!ZSTD_checkCParams(cParams));
|
||||||
|
cctxParams.fParams.contentSizeFlag = 1;
|
||||||
return cctxParams;
|
return cctxParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,6 +180,7 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
|
|||||||
if (!params) { return NULL; }
|
if (!params) { return NULL; }
|
||||||
params->customMem = customMem;
|
params->customMem = customMem;
|
||||||
params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
||||||
|
params->fParams.contentSizeFlag = 1;
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,36 +196,41 @@ size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params)
|
size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
|
||||||
{
|
{
|
||||||
return ZSTD_initCCtxParams(params, ZSTD_CLEVEL_DEFAULT);
|
return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
|
size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
|
||||||
if (!cctxParams) { return ERROR(GENERIC); }
|
if (!cctxParams) { return ERROR(GENERIC); }
|
||||||
memset(cctxParams, 0, sizeof(*cctxParams));
|
memset(cctxParams, 0, sizeof(*cctxParams));
|
||||||
cctxParams->compressionLevel = compressionLevel;
|
cctxParams->compressionLevel = compressionLevel;
|
||||||
|
cctxParams->fParams.contentSizeFlag = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
|
size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
|
||||||
{
|
{
|
||||||
if (!cctxParams) { return ERROR(GENERIC); }
|
if (!cctxParams) { return ERROR(GENERIC); }
|
||||||
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
||||||
memset(cctxParams, 0, sizeof(*cctxParams));
|
memset(cctxParams, 0, sizeof(*cctxParams));
|
||||||
cctxParams->cParams = params.cParams;
|
cctxParams->cParams = params.cParams;
|
||||||
cctxParams->fParams = params.fParams;
|
cctxParams->fParams = params.fParams;
|
||||||
cctxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
|
||||||
|
assert(!ZSTD_checkCParams(params.cParams));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ZSTD_assignParamsToCCtxParams() :
|
||||||
|
* params is presumed valid at this stage */
|
||||||
static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
|
static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
|
||||||
ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
|
ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
|
||||||
{
|
{
|
||||||
ZSTD_CCtx_params ret = cctxParams;
|
ZSTD_CCtx_params ret = cctxParams;
|
||||||
ret.cParams = params.cParams;
|
ret.cParams = params.cParams;
|
||||||
ret.fParams = params.fParams;
|
ret.fParams = params.fParams;
|
||||||
ret.compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
|
||||||
|
assert(!ZSTD_checkCParams(params.cParams));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,10 +239,49 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
|
|||||||
return ERROR(parameter_outOfBound); \
|
return ERROR(parameter_outOfBound); \
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
|
||||||
|
{
|
||||||
|
switch(param)
|
||||||
|
{
|
||||||
|
case ZSTD_p_compressionLevel:
|
||||||
|
case ZSTD_p_hashLog:
|
||||||
|
case ZSTD_p_chainLog:
|
||||||
|
case ZSTD_p_searchLog:
|
||||||
|
case ZSTD_p_minMatch:
|
||||||
|
case ZSTD_p_targetLength:
|
||||||
|
case ZSTD_p_compressionStrategy:
|
||||||
|
case ZSTD_p_compressLiterals:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case ZSTD_p_format:
|
||||||
|
case ZSTD_p_windowLog:
|
||||||
|
case ZSTD_p_contentSizeFlag:
|
||||||
|
case ZSTD_p_checksumFlag:
|
||||||
|
case ZSTD_p_dictIDFlag:
|
||||||
|
case ZSTD_p_forceMaxWindow :
|
||||||
|
case ZSTD_p_nbWorkers:
|
||||||
|
case ZSTD_p_jobSize:
|
||||||
|
case ZSTD_p_overlapSizeLog:
|
||||||
|
case ZSTD_p_enableLongDistanceMatching:
|
||||||
|
case ZSTD_p_ldmHashLog:
|
||||||
|
case ZSTD_p_ldmMinMatch:
|
||||||
|
case ZSTD_p_ldmBucketSizeLog:
|
||||||
|
case ZSTD_p_ldmHashEveryLog:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
|
size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_CCtx_setParameter (%u, %u)", (U32)param, value);
|
DEBUGLOG(4, "ZSTD_CCtx_setParameter (%u, %u)", (U32)param, value);
|
||||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
if (cctx->streamStage != zcss_init) {
|
||||||
|
if (ZSTD_isUpdateAuthorized(param)) {
|
||||||
|
cctx->cParamsChanged = 1;
|
||||||
|
} else {
|
||||||
|
return ERROR(stage_wrong);
|
||||||
|
} }
|
||||||
|
|
||||||
switch(param)
|
switch(param)
|
||||||
{
|
{
|
||||||
@@ -267,9 +300,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
|
|||||||
case ZSTD_p_targetLength:
|
case ZSTD_p_targetLength:
|
||||||
case ZSTD_p_compressionStrategy:
|
case ZSTD_p_compressionStrategy:
|
||||||
if (cctx->cdict) return ERROR(stage_wrong);
|
if (cctx->cdict) return ERROR(stage_wrong);
|
||||||
if (value>0) ZSTD_cLevelToCParams(cctx); /* Can optimize if srcSize is known */
|
|
||||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||||
|
|
||||||
|
case ZSTD_p_compressLiterals:
|
||||||
case ZSTD_p_contentSizeFlag:
|
case ZSTD_p_contentSizeFlag:
|
||||||
case ZSTD_p_checksumFlag:
|
case ZSTD_p_checksumFlag:
|
||||||
case ZSTD_p_dictIDFlag:
|
case ZSTD_p_dictIDFlag:
|
||||||
@@ -280,23 +313,17 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
|
|||||||
* default : 0 when using a CDict, 1 when using a Prefix */
|
* default : 0 when using a CDict, 1 when using a Prefix */
|
||||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||||
|
|
||||||
case ZSTD_p_nbThreads:
|
case ZSTD_p_nbWorkers:
|
||||||
if ((value > 1) && cctx->staticSize) {
|
if ((value>0) && cctx->staticSize) {
|
||||||
return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
|
return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
|
||||||
}
|
}
|
||||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||||
|
|
||||||
case ZSTD_p_jobSize:
|
case ZSTD_p_jobSize:
|
||||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
|
||||||
|
|
||||||
case ZSTD_p_overlapSizeLog:
|
case ZSTD_p_overlapSizeLog:
|
||||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||||
|
|
||||||
case ZSTD_p_enableLongDistanceMatching:
|
case ZSTD_p_enableLongDistanceMatching:
|
||||||
if (cctx->cdict) return ERROR(stage_wrong);
|
|
||||||
if (value>0) ZSTD_cLevelToCParams(cctx);
|
|
||||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
|
||||||
|
|
||||||
case ZSTD_p_ldmHashLog:
|
case ZSTD_p_ldmHashLog:
|
||||||
case ZSTD_p_ldmMinMatch:
|
case ZSTD_p_ldmMinMatch:
|
||||||
case ZSTD_p_ldmBucketSizeLog:
|
case ZSTD_p_ldmBucketSizeLog:
|
||||||
@@ -320,69 +347,62 @@ size_t ZSTD_CCtxParam_setParameter(
|
|||||||
CCtxParams->format = (ZSTD_format_e)value;
|
CCtxParams->format = (ZSTD_format_e)value;
|
||||||
return (size_t)CCtxParams->format;
|
return (size_t)CCtxParams->format;
|
||||||
|
|
||||||
case ZSTD_p_compressionLevel :
|
case ZSTD_p_compressionLevel : {
|
||||||
if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
|
int cLevel = (int)value; /* cast expected to restore negative sign */
|
||||||
if (value) /* 0 : does not change current level */
|
if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
|
||||||
CCtxParams->compressionLevel = value;
|
if (cLevel) { /* 0 : does not change current level */
|
||||||
return CCtxParams->compressionLevel;
|
CCtxParams->disableLiteralCompression = (cLevel<0); /* negative levels disable huffman */
|
||||||
|
CCtxParams->compressionLevel = cLevel;
|
||||||
|
}
|
||||||
|
if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel;
|
||||||
|
return 0; /* return type (size_t) cannot represent negative values */
|
||||||
|
}
|
||||||
|
|
||||||
case ZSTD_p_windowLog :
|
case ZSTD_p_windowLog :
|
||||||
DEBUGLOG(4, "ZSTD_CCtxParam_setParameter: set windowLog=%u", value);
|
if (value>0) /* 0 => use default */
|
||||||
if (value) { /* 0 : does not change current windowLog */
|
|
||||||
CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
|
CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
|
||||||
CCtxParams->cParams.windowLog = value;
|
CCtxParams->cParams.windowLog = value;
|
||||||
}
|
|
||||||
return CCtxParams->cParams.windowLog;
|
return CCtxParams->cParams.windowLog;
|
||||||
|
|
||||||
case ZSTD_p_hashLog :
|
case ZSTD_p_hashLog :
|
||||||
if (value) { /* 0 : does not change current hashLog */
|
if (value>0) /* 0 => use default */
|
||||||
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
|
||||||
CCtxParams->cParams.hashLog = value;
|
CCtxParams->cParams.hashLog = value;
|
||||||
}
|
|
||||||
return CCtxParams->cParams.hashLog;
|
return CCtxParams->cParams.hashLog;
|
||||||
|
|
||||||
case ZSTD_p_chainLog :
|
case ZSTD_p_chainLog :
|
||||||
if (value) { /* 0 : does not change current chainLog */
|
if (value>0) /* 0 => use default */
|
||||||
CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
|
CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
|
||||||
CCtxParams->cParams.chainLog = value;
|
CCtxParams->cParams.chainLog = value;
|
||||||
}
|
|
||||||
return CCtxParams->cParams.chainLog;
|
return CCtxParams->cParams.chainLog;
|
||||||
|
|
||||||
case ZSTD_p_searchLog :
|
case ZSTD_p_searchLog :
|
||||||
if (value) { /* 0 : does not change current searchLog */
|
if (value>0) /* 0 => use default */
|
||||||
CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
|
||||||
CCtxParams->cParams.searchLog = value;
|
CCtxParams->cParams.searchLog = value;
|
||||||
}
|
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
case ZSTD_p_minMatch :
|
case ZSTD_p_minMatch :
|
||||||
if (value) { /* 0 : does not change current minMatch length */
|
if (value>0) /* 0 => use default */
|
||||||
CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
|
||||||
CCtxParams->cParams.searchLength = value;
|
CCtxParams->cParams.searchLength = value;
|
||||||
}
|
|
||||||
return CCtxParams->cParams.searchLength;
|
return CCtxParams->cParams.searchLength;
|
||||||
|
|
||||||
case ZSTD_p_targetLength :
|
case ZSTD_p_targetLength :
|
||||||
if (value) { /* 0 : does not change current sufficient_len */
|
/* all values are valid. 0 => use default */
|
||||||
CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
|
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
|
||||||
CCtxParams->cParams.targetLength = value;
|
CCtxParams->cParams.targetLength = value;
|
||||||
}
|
|
||||||
return CCtxParams->cParams.targetLength;
|
return CCtxParams->cParams.targetLength;
|
||||||
|
|
||||||
case ZSTD_p_compressionStrategy :
|
case ZSTD_p_compressionStrategy :
|
||||||
if (value) { /* 0 : does not change currentstrategy */
|
if (value>0) /* 0 => use default */
|
||||||
CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
|
CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
|
||||||
CCtxParams->cParams.strategy = (ZSTD_strategy)value;
|
CCtxParams->cParams.strategy = (ZSTD_strategy)value;
|
||||||
}
|
|
||||||
return (size_t)CCtxParams->cParams.strategy;
|
return (size_t)CCtxParams->cParams.strategy;
|
||||||
|
|
||||||
|
case ZSTD_p_compressLiterals:
|
||||||
|
CCtxParams->disableLiteralCompression = !value;
|
||||||
|
return !CCtxParams->disableLiteralCompression;
|
||||||
|
|
||||||
case ZSTD_p_contentSizeFlag :
|
case ZSTD_p_contentSizeFlag :
|
||||||
/* Content size written in frame header _when known_ (default:1) */
|
/* Content size written in frame header _when known_ (default:1) */
|
||||||
DEBUGLOG(4, "set content size flag = %u", (value>0));
|
DEBUGLOG(4, "set content size flag = %u", (value>0));
|
||||||
@@ -396,27 +416,25 @@ size_t ZSTD_CCtxParam_setParameter(
|
|||||||
|
|
||||||
case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
|
case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
|
||||||
DEBUGLOG(4, "set dictIDFlag = %u", (value>0));
|
DEBUGLOG(4, "set dictIDFlag = %u", (value>0));
|
||||||
CCtxParams->fParams.noDictIDFlag = (value == 0);
|
CCtxParams->fParams.noDictIDFlag = !value;
|
||||||
return !CCtxParams->fParams.noDictIDFlag;
|
return !CCtxParams->fParams.noDictIDFlag;
|
||||||
|
|
||||||
case ZSTD_p_forceMaxWindow :
|
case ZSTD_p_forceMaxWindow :
|
||||||
CCtxParams->forceWindow = (value > 0);
|
CCtxParams->forceWindow = (value > 0);
|
||||||
return CCtxParams->forceWindow;
|
return CCtxParams->forceWindow;
|
||||||
|
|
||||||
case ZSTD_p_nbThreads :
|
case ZSTD_p_nbWorkers :
|
||||||
if (value == 0) return CCtxParams->nbThreads;
|
|
||||||
#ifndef ZSTD_MULTITHREAD
|
#ifndef ZSTD_MULTITHREAD
|
||||||
if (value > 1) return ERROR(parameter_unsupported);
|
if (value>0) return ERROR(parameter_unsupported);
|
||||||
return 1;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return ZSTDMT_CCtxParam_setNbThreads(CCtxParams, value);
|
return ZSTDMT_CCtxParam_setNbWorkers(CCtxParams, value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case ZSTD_p_jobSize :
|
case ZSTD_p_jobSize :
|
||||||
#ifndef ZSTD_MULTITHREAD
|
#ifndef ZSTD_MULTITHREAD
|
||||||
return ERROR(parameter_unsupported);
|
return ERROR(parameter_unsupported);
|
||||||
#else
|
#else
|
||||||
if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported);
|
|
||||||
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value);
|
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -424,44 +442,36 @@ size_t ZSTD_CCtxParam_setParameter(
|
|||||||
#ifndef ZSTD_MULTITHREAD
|
#ifndef ZSTD_MULTITHREAD
|
||||||
return ERROR(parameter_unsupported);
|
return ERROR(parameter_unsupported);
|
||||||
#else
|
#else
|
||||||
if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported);
|
|
||||||
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value);
|
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case ZSTD_p_enableLongDistanceMatching :
|
case ZSTD_p_enableLongDistanceMatching :
|
||||||
if (value) {
|
CCtxParams->ldmParams.enableLdm = (value>0);
|
||||||
ZSTD_cLevelToCCtxParams(CCtxParams);
|
return CCtxParams->ldmParams.enableLdm;
|
||||||
CCtxParams->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
|
|
||||||
}
|
|
||||||
return ZSTD_ldm_initializeParameters(&CCtxParams->ldmParams, value);
|
|
||||||
|
|
||||||
case ZSTD_p_ldmHashLog :
|
case ZSTD_p_ldmHashLog :
|
||||||
if (value) { /* 0 : does not change current ldmHashLog */
|
if (value>0) /* 0 ==> auto */
|
||||||
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||||
CCtxParams->ldmParams.hashLog = value;
|
CCtxParams->ldmParams.hashLog = value;
|
||||||
}
|
|
||||||
return CCtxParams->ldmParams.hashLog;
|
return CCtxParams->ldmParams.hashLog;
|
||||||
|
|
||||||
case ZSTD_p_ldmMinMatch :
|
case ZSTD_p_ldmMinMatch :
|
||||||
if (value) { /* 0 : does not change current ldmMinMatch */
|
if (value>0) /* 0 ==> default */
|
||||||
CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
|
CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
|
||||||
CCtxParams->ldmParams.minMatchLength = value;
|
CCtxParams->ldmParams.minMatchLength = value;
|
||||||
}
|
|
||||||
return CCtxParams->ldmParams.minMatchLength;
|
return CCtxParams->ldmParams.minMatchLength;
|
||||||
|
|
||||||
case ZSTD_p_ldmBucketSizeLog :
|
case ZSTD_p_ldmBucketSizeLog :
|
||||||
if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) {
|
if (value > ZSTD_LDM_BUCKETSIZELOG_MAX)
|
||||||
return ERROR(parameter_outOfBound);
|
return ERROR(parameter_outOfBound);
|
||||||
}
|
|
||||||
CCtxParams->ldmParams.bucketSizeLog = value;
|
CCtxParams->ldmParams.bucketSizeLog = value;
|
||||||
return value;
|
return CCtxParams->ldmParams.bucketSizeLog;
|
||||||
|
|
||||||
case ZSTD_p_ldmHashEveryLog :
|
case ZSTD_p_ldmHashEveryLog :
|
||||||
if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) {
|
if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN)
|
||||||
return ERROR(parameter_outOfBound);
|
return ERROR(parameter_outOfBound);
|
||||||
}
|
|
||||||
CCtxParams->ldmParams.hashEveryLog = value;
|
CCtxParams->ldmParams.hashEveryLog = value;
|
||||||
return value;
|
return CCtxParams->ldmParams.hashEveryLog;
|
||||||
|
|
||||||
default: return ERROR(parameter_unsupported);
|
default: return ERROR(parameter_unsupported);
|
||||||
}
|
}
|
||||||
@@ -470,6 +480,9 @@ size_t ZSTD_CCtxParam_setParameter(
|
|||||||
/** ZSTD_CCtx_setParametersUsingCCtxParams() :
|
/** ZSTD_CCtx_setParametersUsingCCtxParams() :
|
||||||
* just applies `params` into `cctx`
|
* just applies `params` into `cctx`
|
||||||
* no action is performed, parameters are merely stored.
|
* no action is performed, parameters are merely stored.
|
||||||
|
* If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
|
||||||
|
* This is possible even if a compression is ongoing.
|
||||||
|
* In which case, new parameters will be applied on the fly, starting with next compression job.
|
||||||
*/
|
*/
|
||||||
size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
|
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
|
||||||
@@ -478,7 +491,6 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
|||||||
if (cctx->cdict) return ERROR(stage_wrong);
|
if (cctx->cdict) return ERROR(stage_wrong);
|
||||||
|
|
||||||
cctx->requestedParams = *params;
|
cctx->requestedParams = *params;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +504,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
|
|||||||
|
|
||||||
size_t ZSTD_CCtx_loadDictionary_advanced(
|
size_t ZSTD_CCtx_loadDictionary_advanced(
|
||||||
ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
|
ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode)
|
ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
|
||||||
{
|
{
|
||||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||||
if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
|
if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
|
||||||
@@ -503,10 +515,10 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
|
|||||||
cctx->cdict = NULL;
|
cctx->cdict = NULL;
|
||||||
} else {
|
} else {
|
||||||
ZSTD_compressionParameters const cParams =
|
ZSTD_compressionParameters const cParams =
|
||||||
ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize);
|
ZSTD_getCParamsFromCCtxParams(&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize);
|
||||||
cctx->cdictLocal = ZSTD_createCDict_advanced(
|
cctx->cdictLocal = ZSTD_createCDict_advanced(
|
||||||
dict, dictSize,
|
dict, dictSize,
|
||||||
dictLoadMethod, dictMode,
|
dictLoadMethod, dictContentType,
|
||||||
cParams, cctx->customMem);
|
cParams, cctx->customMem);
|
||||||
cctx->cdict = cctx->cdictLocal;
|
cctx->cdict = cctx->cdictLocal;
|
||||||
if (cctx->cdictLocal == NULL)
|
if (cctx->cdictLocal == NULL)
|
||||||
@@ -519,13 +531,13 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
|
|||||||
ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
||||||
{
|
{
|
||||||
return ZSTD_CCtx_loadDictionary_advanced(
|
return ZSTD_CCtx_loadDictionary_advanced(
|
||||||
cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dm_auto);
|
cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
||||||
{
|
{
|
||||||
return ZSTD_CCtx_loadDictionary_advanced(
|
return ZSTD_CCtx_loadDictionary_advanced(
|
||||||
cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dm_auto);
|
cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -539,17 +551,17 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
|
|||||||
|
|
||||||
size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
|
size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
|
||||||
{
|
{
|
||||||
return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dm_rawContent);
|
return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_CCtx_refPrefix_advanced(
|
size_t ZSTD_CCtx_refPrefix_advanced(
|
||||||
ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode)
|
ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
|
||||||
{
|
{
|
||||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||||
cctx->cdict = NULL; /* prefix discards any prior cdict */
|
cctx->cdict = NULL; /* prefix discards any prior cdict */
|
||||||
cctx->prefixDict.dict = prefix;
|
cctx->prefixDict.dict = prefix;
|
||||||
cctx->prefixDict.dictSize = prefixSize;
|
cctx->prefixDict.dictSize = prefixSize;
|
||||||
cctx->prefixDict.dictMode = dictMode;
|
cctx->prefixDict.dictContentType = dictContentType;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,7 +589,8 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
|
|||||||
CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||||
CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
||||||
CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
||||||
CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
|
if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN)
|
||||||
|
return ERROR(parameter_unsupported);
|
||||||
if ((U32)(cParams.strategy) > (U32)ZSTD_btultra)
|
if ((U32)(cParams.strategy) > (U32)ZSTD_btultra)
|
||||||
return ERROR(parameter_unsupported);
|
return ERROR(parameter_unsupported);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -597,7 +610,7 @@ static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters c
|
|||||||
CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||||
CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
||||||
CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
||||||
CLAMP(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
|
if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN) cParams.targetLength = ZSTD_TARGETLENGTH_MIN;
|
||||||
if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra;
|
if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra;
|
||||||
return cParams;
|
return cParams;
|
||||||
}
|
}
|
||||||
@@ -653,36 +666,43 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u
|
|||||||
return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
|
return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t ZSTD_sizeof_matchState(ZSTD_compressionParameters const* cParams, const U32 forCCtx)
|
||||||
|
{
|
||||||
|
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 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
|
||||||
|
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<<Litbits)) * sizeof(U32)
|
||||||
|
+ (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
|
||||||
|
size_t const optSpace = (forCCtx && ((cParams->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;
|
||||||
|
}
|
||||||
|
|
||||||
size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||||
{
|
{
|
||||||
/* Estimate CCtx size is supported for single-threaded compression only. */
|
/* Estimate CCtx size is supported for single-threaded compression only. */
|
||||||
if (params->nbThreads > 1) { return ERROR(GENERIC); }
|
if (params->nbWorkers > 0) { return ERROR(GENERIC); }
|
||||||
{ ZSTD_compressionParameters const cParams =
|
{ ZSTD_compressionParameters const cParams =
|
||||||
ZSTD_getCParamsFromCCtxParams(*params, 0, 0);
|
ZSTD_getCParamsFromCCtxParams(params, 0, 0);
|
||||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
||||||
U32 const divider = (cParams.searchLength==3) ? 3 : 4;
|
U32 const divider = (cParams.searchLength==3) ? 3 : 4;
|
||||||
size_t const maxNbSeq = blockSize / divider;
|
size_t const maxNbSeq = blockSize / divider;
|
||||||
size_t const tokenSpace = blockSize + 11*maxNbSeq;
|
size_t const tokenSpace = blockSize + 11*maxNbSeq;
|
||||||
size_t const chainSize =
|
size_t const entropySpace = HUF_WORKSPACE_SIZE;
|
||||||
(cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams.chainLog);
|
size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
|
||||||
size_t const hSize = ((size_t)1) << cParams.hashLog;
|
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
|
||||||
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 tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
|
||||||
|
|
||||||
size_t const optBudget =
|
size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
|
||||||
((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
|
size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq);
|
||||||
+ (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
|
|
||||||
size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
|
|
||||||
|
|
||||||
size_t const ldmSpace = params->ldmParams.enableLdm ?
|
size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace +
|
||||||
ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
|
matchStateSize + ldmSpace + ldmSeqSpace;
|
||||||
params->ldmParams.bucketSizeLog) : 0;
|
|
||||||
|
|
||||||
size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
|
|
||||||
optSpace + ldmSpace;
|
|
||||||
|
|
||||||
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
|
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
|
||||||
DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
|
DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
|
||||||
@@ -696,15 +716,26 @@ size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
|
|||||||
return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms);
|
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);
|
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
|
||||||
return ZSTD_estimateCCtxSize_usingCParams(cParams);
|
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)
|
size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||||
{
|
{
|
||||||
if (params->nbThreads > 1) { return ERROR(GENERIC); }
|
if (params->nbWorkers > 0) { return ERROR(GENERIC); }
|
||||||
{ size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
|
{ size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
|
||||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
|
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
|
||||||
size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
|
size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
|
||||||
@@ -721,11 +752,44 @@ size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
|
|||||||
return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
|
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);
|
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
|
||||||
return ZSTD_estimateCStreamSize_usingCParams(cParams);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTD_getFrameProgression():
|
||||||
|
* tells how much data has been consumed (input) and produced (output) for current frame.
|
||||||
|
* able to count progression inside worker threads (non-blocking mode).
|
||||||
|
*/
|
||||||
|
ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
|
||||||
|
{
|
||||||
|
#ifdef ZSTD_MULTITHREAD
|
||||||
|
if (cctx->appliedParams.nbWorkers > 0) {
|
||||||
|
return ZSTDMT_getFrameProgression(cctx->mtctx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
{ ZSTD_frameProgression fp;
|
||||||
|
size_t const buffered = (cctx->inBuff == NULL) ? 0 :
|
||||||
|
cctx->inBuffPos - cctx->inToCompress;
|
||||||
|
if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
|
||||||
|
assert(buffered <= ZSTD_BLOCKSIZE_MAX);
|
||||||
|
fp.ingested = cctx->consumedSrcSize + buffered;
|
||||||
|
fp.consumed = cctx->consumedSrcSize;
|
||||||
|
fp.produced = cctx->producedCSize;
|
||||||
|
return fp;
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
|
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
|
||||||
ZSTD_compressionParameters cParams2)
|
ZSTD_compressionParameters cParams2)
|
||||||
{
|
{
|
||||||
@@ -761,9 +825,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 windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize));
|
||||||
size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
|
size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
|
||||||
size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0;
|
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);
|
(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);
|
(U32)blockSize2, (U32)blockSize1);
|
||||||
return (blockSize2 <= blockSize1) /* seqStore space depends on blockSize */
|
return (blockSize2 <= blockSize1) /* seqStore space depends on blockSize */
|
||||||
& (neededBufferSize2 <= bufferSize1);
|
& (neededBufferSize2 <= bufferSize1);
|
||||||
@@ -782,37 +846,101 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
|
|||||||
ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
|
ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_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)
|
||||||
|
{
|
||||||
|
ZSTD_window_clear(&ms->window);
|
||||||
|
|
||||||
|
ms->nextToUpdate = ms->window.dictLimit + 1;
|
||||||
|
ms->loadedDictEnd = 0;
|
||||||
|
ms->opt.litLengthSum = 0; /* force reset of btopt stats */
|
||||||
|
}
|
||||||
|
|
||||||
/*! ZSTD_continueCCtx() :
|
/*! ZSTD_continueCCtx() :
|
||||||
* reuse CCtx without reset (note : requires no dictionary) */
|
* reuse CCtx without reset (note : requires no dictionary) */
|
||||||
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
|
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 windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
|
size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
|
||||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
||||||
DEBUGLOG(4, "ZSTD_continueCCtx");
|
DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
|
||||||
|
|
||||||
cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
|
cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
|
||||||
cctx->appliedParams = params;
|
cctx->appliedParams = params;
|
||||||
cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
||||||
cctx->consumedSrcSize = 0;
|
cctx->consumedSrcSize = 0;
|
||||||
|
cctx->producedCSize = 0;
|
||||||
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
|
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
|
||||||
cctx->appliedParams.fParams.contentSizeFlag = 0;
|
cctx->appliedParams.fParams.contentSizeFlag = 0;
|
||||||
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
||||||
(U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
|
(U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
|
||||||
cctx->lowLimit = end;
|
|
||||||
cctx->dictLimit = end;
|
|
||||||
cctx->nextToUpdate = end+1;
|
|
||||||
cctx->stage = ZSTDcs_init;
|
cctx->stage = ZSTDcs_init;
|
||||||
cctx->dictID = 0;
|
cctx->dictID = 0;
|
||||||
cctx->loadedDictEnd = 0;
|
if (params.ldmParams.enableLdm)
|
||||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = repStartValue[i]; }
|
ZSTD_window_clear(&cctx->ldmState.window);
|
||||||
cctx->optState.litLengthSum = 0; /* force reset of btopt stats */
|
ZSTD_referenceExternalSequences(cctx, NULL, 0);
|
||||||
|
ZSTD_invalidateMatchState(&cctx->blockState.matchState);
|
||||||
|
ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock);
|
||||||
XXH64_reset(&cctx->xxhState, 0);
|
XXH64_reset(&cctx->xxhState, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
|
typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
|
||||||
|
|
||||||
|
static void* ZSTD_reset_matchState(ZSTD_matchState_t* ms, void* ptr, ZSTD_compressionParameters const* cParams, ZSTD_compResetPolicy_e const crp, U32 const forCCtx)
|
||||||
|
{
|
||||||
|
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 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
|
||||||
|
size_t const h3Size = ((size_t)1) << hashLog3;
|
||||||
|
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
||||||
|
|
||||||
|
assert(((size_t)ptr & 3) == 0);
|
||||||
|
|
||||||
|
ms->hashLog3 = hashLog3;
|
||||||
|
memset(&ms->window, 0, sizeof(ms->window));
|
||||||
|
ZSTD_invalidateMatchState(ms);
|
||||||
|
|
||||||
|
/* opt parser space */
|
||||||
|
if (forCCtx && ((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<<Litbits);
|
||||||
|
ms->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() :
|
/*! ZSTD_resetCCtx_internal() :
|
||||||
note : `params` are assumed fully validated at this stage */
|
note : `params` are assumed fully validated at this stage */
|
||||||
static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||||
@@ -830,19 +958,14 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
zbuff, pledgedSrcSize)) {
|
zbuff, pledgedSrcSize)) {
|
||||||
DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%u)",
|
DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%u)",
|
||||||
zc->appliedParams.cParams.windowLog, (U32)zc->blockSize);
|
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);
|
return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
|
||||||
} }
|
} }
|
||||||
DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
|
DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
|
||||||
|
|
||||||
if (params.ldmParams.enableLdm) {
|
if (params.ldmParams.enableLdm) {
|
||||||
/* Adjust long distance matching parameters */
|
/* Adjust long distance matching parameters */
|
||||||
ZSTD_ldm_adjustParameters(¶ms.ldmParams, params.cParams.windowLog);
|
params.ldmParams.windowLog = params.cParams.windowLog;
|
||||||
|
ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams);
|
||||||
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
||||||
assert(params.ldmParams.hashEveryLog < 32);
|
assert(params.ldmParams.hashEveryLog < 32);
|
||||||
zc->ldmState.hashPower =
|
zc->ldmState.hashPower =
|
||||||
@@ -854,34 +977,25 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
|
U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
|
||||||
size_t const maxNbSeq = blockSize / divider;
|
size_t const maxNbSeq = blockSize / divider;
|
||||||
size_t const tokenSpace = blockSize + 11*maxNbSeq;
|
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 buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
|
||||||
size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
|
size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
|
||||||
|
size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1);
|
||||||
|
size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
|
||||||
void* ptr;
|
void* ptr;
|
||||||
|
|
||||||
/* Check if workSpace is large enough, alloc a new one if needed */
|
/* 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 optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
|
size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
|
||||||
+ (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
|
|
||||||
size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
|
|
||||||
|| (params.cParams.strategy == ZSTD_btultra)) ?
|
|
||||||
optPotentialSpace : 0;
|
|
||||||
size_t const bufferSpace = buffInSize + buffOutSize;
|
size_t const bufferSpace = buffInSize + buffOutSize;
|
||||||
size_t const ldmSpace = params.ldmParams.enableLdm
|
size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
|
||||||
? ZSTD_ldm_getTableSize(params.ldmParams.hashLog, params.ldmParams.bucketSizeLog)
|
size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq);
|
||||||
: 0;
|
|
||||||
size_t const neededSpace = entropySpace + optSpace + ldmSpace +
|
size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace +
|
||||||
tableSpace + tokenSpace + bufferSpace;
|
ldmSeqSpace + matchStateSize + tokenSpace +
|
||||||
DEBUGLOG(4, "Need %uKB workspace, including %uKB for tables, and %uKB for buffers",
|
bufferSpace;
|
||||||
(U32)(neededSpace>>10), (U32)(tableSpace>>10), (U32)(bufferSpace>>10));
|
DEBUGLOG(4, "Need %uKB workspace, including %uKB for match state, and %uKB for buffers",
|
||||||
DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u - windowSize: %u - blockSize: %u",
|
(U32)(neededSpace>>10), (U32)(matchStateSize>>10), (U32)(bufferSpace>>10));
|
||||||
(U32)chainSize, (U32)hSize, (U32)h3Size, (U32)windowSize, (U32)blockSize);
|
DEBUGLOG(4, "windowSize: %u - blockSize: %u", (U32)windowSize, (U32)blockSize);
|
||||||
|
|
||||||
if (zc->workSpaceSize < neededSpace) { /* too small : resize */
|
if (zc->workSpaceSize < neededSpace) { /* too small : resize */
|
||||||
DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK",
|
DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK",
|
||||||
@@ -897,16 +1011,20 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
zc->workSpaceSize = neededSpace;
|
zc->workSpaceSize = neededSpace;
|
||||||
ptr = zc->workSpace;
|
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(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
|
||||||
assert(zc->workSpaceSize >= sizeof(ZSTD_entropyCTables_t));
|
assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t));
|
||||||
zc->entropy = (ZSTD_entropyCTables_t*)zc->workSpace;
|
zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace;
|
||||||
|
zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1;
|
||||||
|
ptr = zc->blockState.nextCBlock + 1;
|
||||||
|
zc->entropyWorkspace = (U32*)ptr;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
/* init params */
|
/* init params */
|
||||||
zc->appliedParams = params;
|
zc->appliedParams = params;
|
||||||
zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
||||||
zc->consumedSrcSize = 0;
|
zc->consumedSrcSize = 0;
|
||||||
|
zc->producedCSize = 0;
|
||||||
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
|
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
|
||||||
zc->appliedParams.fParams.contentSizeFlag = 0;
|
zc->appliedParams.fParams.contentSizeFlag = 0;
|
||||||
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
||||||
@@ -916,37 +1034,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
XXH64_reset(&zc->xxhState, 0);
|
XXH64_reset(&zc->xxhState, 0);
|
||||||
zc->stage = ZSTDcs_init;
|
zc->stage = ZSTDcs_init;
|
||||||
zc->dictID = 0;
|
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->nextToUpdate = 1;
|
|
||||||
zc->nextSrc = NULL;
|
|
||||||
zc->base = NULL;
|
|
||||||
zc->dictBase = NULL;
|
|
||||||
zc->dictLimit = 0;
|
|
||||||
zc->lowLimit = 0;
|
|
||||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->seqStore.rep[i] = repStartValue[i]; }
|
|
||||||
zc->hashLog3 = hashLog3;
|
|
||||||
zc->optState.litLengthSum = 0;
|
|
||||||
|
|
||||||
ptr = zc->entropy + 1;
|
ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
|
||||||
|
|
||||||
/* opt parser space */
|
ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
|
||||||
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;
|
|
||||||
zc->optState.litLengthFreq = zc->optState.litFreq + (1<<Litbits);
|
|
||||||
zc->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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ldm hash table */
|
/* ldm hash table */
|
||||||
/* initialize bucketOffsets table later for pointer alignment */
|
/* initialize bucketOffsets table later for pointer alignment */
|
||||||
@@ -956,16 +1047,15 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
|
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
|
||||||
zc->ldmState.hashTable = (ldmEntry_t*)ptr;
|
zc->ldmState.hashTable = (ldmEntry_t*)ptr;
|
||||||
ptr = zc->ldmState.hashTable + ldmHSize;
|
ptr = zc->ldmState.hashTable + ldmHSize;
|
||||||
}
|
zc->ldmSequences = (rawSeq*)ptr;
|
||||||
|
ptr = zc->ldmSequences + maxNbLdmSeq;
|
||||||
|
zc->maxNbLdmSequences = maxNbLdmSeq;
|
||||||
|
|
||||||
/* table Space */
|
memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window));
|
||||||
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 */
|
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
|
||||||
zc->hashTable = (U32*)(ptr);
|
|
||||||
zc->chainTable = zc->hashTable + hSize;
|
ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, ¶ms.cParams, crp, /* forCCtx */ 1);
|
||||||
zc->hashTable3 = zc->chainTable + chainSize;
|
|
||||||
ptr = zc->hashTable3 + h3Size;
|
|
||||||
|
|
||||||
/* sequences storage */
|
/* sequences storage */
|
||||||
zc->seqStore.sequencesStart = (seqDef*)ptr;
|
zc->seqStore.sequencesStart = (seqDef*)ptr;
|
||||||
@@ -984,7 +1074,9 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
memset(ptr, 0, ldmBucketSize);
|
memset(ptr, 0, ldmBucketSize);
|
||||||
zc->ldmState.bucketOffsets = (BYTE*)ptr;
|
zc->ldmState.bucketOffsets = (BYTE*)ptr;
|
||||||
ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
|
ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
|
||||||
|
ZSTD_window_clear(&zc->ldmState.window);
|
||||||
}
|
}
|
||||||
|
ZSTD_referenceExternalSequences(zc, NULL, 0);
|
||||||
|
|
||||||
/* buffers */
|
/* buffers */
|
||||||
zc->inBuffSize = buffInSize;
|
zc->inBuffSize = buffInSize;
|
||||||
@@ -1002,9 +1094,61 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
* do not use with extDict variant ! */
|
* do not use with extDict variant ! */
|
||||||
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
|
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = 0;
|
for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
|
||||||
|
assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
assert(cctx->appliedParams.cParams.strategy == cdict->cParams.strategy);
|
||||||
|
assert(cctx->appliedParams.cParams.hashLog == cdict->cParams.hashLog);
|
||||||
|
assert(cctx->appliedParams.cParams.chainLog == cdict->cParams.chainLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy tables */
|
||||||
|
{ size_t const chainSize = (cdict->cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict->cParams.chainLog);
|
||||||
|
size_t const hSize = (size_t)1 << cdict->cParams.hashLog;
|
||||||
|
size_t const tableSpace = (chainSize + hSize) * 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 */
|
||||||
|
}
|
||||||
|
/* Zero the hashTable3, since the cdict never fills it */
|
||||||
|
{ size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3;
|
||||||
|
assert(cdict->matchState.hashLog3 == 0);
|
||||||
|
memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy dictionary offsets */
|
||||||
|
{
|
||||||
|
ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
|
||||||
|
ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
|
||||||
|
dstMatchState->window = srcMatchState->window;
|
||||||
|
dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
|
||||||
|
dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
|
||||||
|
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() :
|
/*! ZSTD_copyCCtx_internal() :
|
||||||
* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
|
* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
|
||||||
@@ -1015,7 +1159,6 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
|
|||||||
* @return : 0, or an error code */
|
* @return : 0, or an error code */
|
||||||
static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
||||||
const ZSTD_CCtx* srcCCtx,
|
const ZSTD_CCtx* srcCCtx,
|
||||||
unsigned windowLog,
|
|
||||||
ZSTD_frameParameters fParams,
|
ZSTD_frameParameters fParams,
|
||||||
U64 pledgedSrcSize,
|
U64 pledgedSrcSize,
|
||||||
ZSTD_buffered_policy_e zbuff)
|
ZSTD_buffered_policy_e zbuff)
|
||||||
@@ -1027,41 +1170,39 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
|||||||
{ ZSTD_CCtx_params params = dstCCtx->requestedParams;
|
{ ZSTD_CCtx_params params = dstCCtx->requestedParams;
|
||||||
/* Copy only compression parameters related to tables. */
|
/* Copy only compression parameters related to tables. */
|
||||||
params.cParams = srcCCtx->appliedParams.cParams;
|
params.cParams = srcCCtx->appliedParams.cParams;
|
||||||
if (windowLog) params.cParams.windowLog = windowLog;
|
|
||||||
params.fParams = fParams;
|
params.fParams = fParams;
|
||||||
ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
|
ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
|
||||||
ZSTDcrp_noMemset, zbuff);
|
ZSTDcrp_noMemset, zbuff);
|
||||||
|
assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
|
||||||
|
assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
|
||||||
|
assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
|
||||||
|
assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
|
||||||
|
assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy tables */
|
/* copy tables */
|
||||||
{ size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
|
{ 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 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->blockState.matchState.hashLog3;
|
||||||
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
||||||
assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
|
assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
|
||||||
assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
|
assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize);
|
||||||
memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
|
memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy dictionary offsets */
|
/* copy dictionary offsets */
|
||||||
dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
|
{
|
||||||
dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
|
ZSTD_matchState_t const* srcMatchState = &srcCCtx->blockState.matchState;
|
||||||
dstCCtx->nextSrc = srcCCtx->nextSrc;
|
ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
|
||||||
dstCCtx->base = srcCCtx->base;
|
dstMatchState->window = srcMatchState->window;
|
||||||
dstCCtx->dictBase = srcCCtx->dictBase;
|
dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
|
||||||
dstCCtx->dictLimit = srcCCtx->dictLimit;
|
dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
|
||||||
dstCCtx->lowLimit = srcCCtx->lowLimit;
|
dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
|
||||||
dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
|
}
|
||||||
dstCCtx->dictID = srcCCtx->dictID;
|
dstCCtx->dictID = srcCCtx->dictID;
|
||||||
|
|
||||||
/* copy entropy tables */
|
/* copy block state */
|
||||||
memcpy(dstCCtx->entropy, srcCCtx->entropy, sizeof(ZSTD_entropyCTables_t));
|
memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
|
||||||
/* copy repcodes */
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ZSTD_REP_NUM; ++i)
|
|
||||||
dstCCtx->seqStore.rep[i] = srcCCtx->seqStore.rep[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1080,51 +1221,69 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long
|
|||||||
fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
|
fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
|
||||||
|
|
||||||
return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
|
return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
|
||||||
0 /*windowLog from srcCCtx*/, fParams, pledgedSrcSize,
|
fParams, pledgedSrcSize,
|
||||||
zbuff);
|
zbuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ZSTD_ROWSIZE 16
|
||||||
/*! ZSTD_reduceTable() :
|
/*! ZSTD_reduceTable() :
|
||||||
* reduce table indexes by `reducerValue` */
|
* reduce table indexes by `reducerValue`, or squash to zero.
|
||||||
static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
|
* PreserveMark preserves "unsorted mark" for btlazy2 strategy.
|
||||||
|
* It must be set to a clear 0/1 value, to remove branch during inlining.
|
||||||
|
* Presume table size is a multiple of ZSTD_ROWSIZE
|
||||||
|
* to help auto-vectorization */
|
||||||
|
FORCE_INLINE_TEMPLATE void
|
||||||
|
ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
|
||||||
{
|
{
|
||||||
U32 u;
|
int const nbRows = (int)size / ZSTD_ROWSIZE;
|
||||||
for (u=0 ; u < size ; u++) {
|
int cellNb = 0;
|
||||||
if (table[u] < reducerValue) table[u] = 0;
|
int rowNb;
|
||||||
else table[u] -= reducerValue;
|
assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
|
||||||
|
assert(size < (1U<<31)); /* can be casted to int */
|
||||||
|
for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
|
||||||
|
int column;
|
||||||
|
for (column=0; column<ZSTD_ROWSIZE; column++) {
|
||||||
|
if (preserveMark) {
|
||||||
|
U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
|
||||||
|
table[cellNb] += adder;
|
||||||
}
|
}
|
||||||
|
if (table[cellNb] < reducerValue) table[cellNb] = 0;
|
||||||
|
else table[cellNb] -= reducerValue;
|
||||||
|
cellNb++;
|
||||||
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ZSTD_ldm_reduceTable() :
|
static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
|
||||||
* reduce table indexes by `reducerValue` */
|
|
||||||
static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
|
|
||||||
U32 const reducerValue)
|
|
||||||
{
|
{
|
||||||
U32 u;
|
ZSTD_reduceTable_internal(table, size, reducerValue, 0);
|
||||||
for (u = 0; u < size; u++) {
|
|
||||||
if (table[u].offset < reducerValue) table[u].offset = 0;
|
|
||||||
else table[u].offset -= reducerValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
|
||||||
|
{
|
||||||
|
ZSTD_reduceTable_internal(table, size, reducerValue, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ZSTD_reduceIndex() :
|
/*! ZSTD_reduceIndex() :
|
||||||
* rescale all indexes to avoid future overflow (indexes are U32) */
|
* rescale all indexes to avoid future overflow (indexes are U32) */
|
||||||
static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
|
static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
|
||||||
{
|
{
|
||||||
|
ZSTD_matchState_t* const ms = &zc->blockState.matchState;
|
||||||
{ U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
|
{ U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
|
||||||
ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
|
ZSTD_reduceTable(ms->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); }
|
|
||||||
|
|
||||||
{ U32 const h3Size = (zc->hashLog3) ? (U32)1 << zc->hashLog3 : 0;
|
|
||||||
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.cParams.strategy != ZSTD_fast) {
|
||||||
|
U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
|
||||||
|
if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
|
||||||
|
ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
|
||||||
|
else
|
||||||
|
ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms->hashLog3) {
|
||||||
|
U32 const h3Size = (U32)1 << ms->hashLog3;
|
||||||
|
ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1199,10 +1358,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_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_strategy strategy,
|
ZSTD_entropyCTables_t* nextEntropy,
|
||||||
|
ZSTD_strategy strategy, int disableLiteralCompression,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize)
|
const void* src, size_t srcSize,
|
||||||
|
U32* workspace, const int bmi2)
|
||||||
{
|
{
|
||||||
size_t const minGain = ZSTD_minGain(srcSize);
|
size_t const minGain = ZSTD_minGain(srcSize);
|
||||||
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
||||||
@@ -1211,34 +1372,51 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
|
|||||||
symbolEncodingType_e hType = set_compressed;
|
symbolEncodingType_e hType = set_compressed;
|
||||||
size_t cLitSize;
|
size_t cLitSize;
|
||||||
|
|
||||||
|
DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)",
|
||||||
|
disableLiteralCompression);
|
||||||
|
|
||||||
|
/* Prepare nextEntropy assuming reusing the existing table */
|
||||||
|
nextEntropy->hufCTable_repeatMode = prevEntropy->hufCTable_repeatMode;
|
||||||
|
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable,
|
||||||
|
sizeof(prevEntropy->hufCTable));
|
||||||
|
|
||||||
|
if (disableLiteralCompression)
|
||||||
|
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
|
|
||||||
/* small ? don't even attempt compression (speed opt) */
|
/* small ? don't even attempt compression (speed opt) */
|
||||||
# define LITERAL_NOENTROPY 63
|
# define COMPRESS_LITERALS_SIZE_MIN 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 : COMPRESS_LITERALS_SIZE_MIN;
|
||||||
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
|
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;
|
int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
|
||||||
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
||||||
cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
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, bmi2)
|
||||||
: HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
: HUF_compress4X_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, bmi2);
|
||||||
if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
|
if (repeat != HUF_repeat_none) {
|
||||||
else { entropy->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
|
/* reused the existing table */
|
||||||
|
hType = set_repeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
|
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);
|
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
}
|
}
|
||||||
if (cLitSize==1) {
|
if (cLitSize==1) {
|
||||||
entropy->hufCTable_repeatMode = HUF_repeat_none;
|
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
|
||||||
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hType == set_compressed) {
|
||||||
|
/* using a newly constructed table */
|
||||||
|
nextEntropy->hufCTable_repeatMode = HUF_repeat_check;
|
||||||
|
}
|
||||||
|
|
||||||
/* Build header */
|
/* Build header */
|
||||||
switch(lhSize)
|
switch(lhSize)
|
||||||
{
|
{
|
||||||
@@ -1332,10 +1510,11 @@ symbolEncodingType_e ZSTD_selectEncodingType(
|
|||||||
|
|
||||||
MEM_STATIC
|
MEM_STATIC
|
||||||
size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
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,
|
U32* count, U32 max,
|
||||||
BYTE const* codeTable, size_t nbSeq,
|
BYTE const* codeTable, size_t nbSeq,
|
||||||
S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||||
|
FSE_CTable const* prevCTable, size_t prevCTableSize,
|
||||||
void* workspace, size_t workspaceSize)
|
void* workspace, size_t workspaceSize)
|
||||||
{
|
{
|
||||||
BYTE* op = (BYTE*)dst;
|
BYTE* op = (BYTE*)dst;
|
||||||
@@ -1344,12 +1523,13 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case set_rle:
|
case set_rle:
|
||||||
*op = codeTable[0];
|
*op = codeTable[0];
|
||||||
CHECK_F(FSE_buildCTable_rle(CTable, (BYTE)max));
|
CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max));
|
||||||
return 1;
|
return 1;
|
||||||
case set_repeat:
|
case set_repeat:
|
||||||
|
memcpy(nextCTable, prevCTable, prevCTableSize);
|
||||||
return 0;
|
return 0;
|
||||||
case set_basic:
|
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;
|
return 0;
|
||||||
case set_compressed: {
|
case set_compressed: {
|
||||||
S16 norm[MaxSeq + 1];
|
S16 norm[MaxSeq + 1];
|
||||||
@@ -1363,7 +1543,7 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
|||||||
CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
|
CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
|
||||||
{ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
|
{ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
|
||||||
if (FSE_isError(NCountSize)) return NCountSize;
|
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;
|
return NCountSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1371,8 +1551,8 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
size_t ZSTD_encodeSequences(
|
ZSTD_encodeSequences_body(
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
@@ -1419,7 +1599,8 @@ size_t ZSTD_encodeSequences(
|
|||||||
DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
|
DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
|
||||||
sequences[n].litLength,
|
sequences[n].litLength,
|
||||||
sequences[n].matchLength + MINMATCH,
|
sequences[n].matchLength + MINMATCH,
|
||||||
sequences[n].offset); /* 32b*/ /* 64b*/
|
sequences[n].offset);
|
||||||
|
/* 32b*/ /* 64b*/
|
||||||
/* (7)*/ /* (7)*/
|
/* (7)*/ /* (7)*/
|
||||||
FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
|
FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
|
||||||
FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
|
FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
|
||||||
@@ -1445,8 +1626,11 @@ size_t ZSTD_encodeSequences(
|
|||||||
BIT_flushBits(&blockStream); /* (7)*/
|
BIT_flushBits(&blockStream); /* (7)*/
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
|
||||||
FSE_flushCState(&blockStream, &stateMatchLength);
|
FSE_flushCState(&blockStream, &stateMatchLength);
|
||||||
|
DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
|
||||||
FSE_flushCState(&blockStream, &stateOffsetBits);
|
FSE_flushCState(&blockStream, &stateOffsetBits);
|
||||||
|
DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
|
||||||
FSE_flushCState(&blockStream, &stateLitLength);
|
FSE_flushCState(&blockStream, &stateLitLength);
|
||||||
|
|
||||||
{ size_t const streamSize = BIT_closeCStream(&blockStream);
|
{ size_t const streamSize = BIT_closeCStream(&blockStream);
|
||||||
@@ -1455,16 +1639,77 @@ size_t ZSTD_encodeSequences(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
static size_t
|
||||||
ZSTD_entropyCTables_t* entropy,
|
ZSTD_encodeSequences_default(
|
||||||
ZSTD_compressionParameters const* cParams,
|
void* dst, size_t dstCapacity,
|
||||||
void* dst, size_t dstCapacity)
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
{
|
{
|
||||||
const int longOffsets = cParams->windowLog > STREAM_ACCUMULATOR_MIN;
|
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
|
||||||
|
static TARGET_ATTRIBUTE("bmi2") size_t
|
||||||
|
ZSTD_encodeSequences_bmi2(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
|
{
|
||||||
|
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t ZSTD_encodeSequences(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
|
||||||
|
{
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
if (bmi2) {
|
||||||
|
return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)bmi2;
|
||||||
|
return ZSTD_encodeSequences_default(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
|
ZSTD_entropyCTables_t const* prevEntropy,
|
||||||
|
ZSTD_entropyCTables_t* nextEntropy,
|
||||||
|
ZSTD_CCtx_params const* cctxParams,
|
||||||
|
void* dst, size_t dstCapacity, U32* workspace,
|
||||||
|
const int bmi2)
|
||||||
|
{
|
||||||
|
const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
|
||||||
U32 count[MaxSeq+1];
|
U32 count[MaxSeq+1];
|
||||||
FSE_CTable* CTable_LitLength = entropy->litlengthCTable;
|
FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
|
||||||
FSE_CTable* CTable_OffsetBits = entropy->offcodeCTable;
|
FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
|
||||||
FSE_CTable* CTable_MatchLength = entropy->matchlengthCTable;
|
FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
|
||||||
U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
|
U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
|
||||||
const seqDef* const sequences = seqStorePtr->sequencesStart;
|
const seqDef* const sequences = seqStorePtr->sequencesStart;
|
||||||
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
|
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
|
||||||
@@ -1476,13 +1721,17 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
|||||||
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
||||||
BYTE* seqHead;
|
BYTE* seqHead;
|
||||||
|
|
||||||
ZSTD_STATIC_ASSERT(sizeof(entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
|
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||||
|
|
||||||
/* Compress literals */
|
/* Compress literals */
|
||||||
{ const BYTE* const literals = seqStorePtr->litStart;
|
{ const BYTE* const literals = seqStorePtr->litStart;
|
||||||
size_t const litSize = seqStorePtr->lit - literals;
|
size_t const litSize = seqStorePtr->lit - literals;
|
||||||
size_t const cSize = ZSTD_compressLiterals(
|
size_t const cSize = ZSTD_compressLiterals(
|
||||||
entropy, cParams->strategy, op, dstCapacity, literals, litSize);
|
prevEntropy, nextEntropy,
|
||||||
|
cctxParams->cParams.strategy, cctxParams->disableLiteralCompression,
|
||||||
|
op, dstCapacity,
|
||||||
|
literals, litSize,
|
||||||
|
workspace, bmi2);
|
||||||
if (ZSTD_isError(cSize))
|
if (ZSTD_isError(cSize))
|
||||||
return cSize;
|
return cSize;
|
||||||
assert(cSize <= dstCapacity);
|
assert(cSize <= dstCapacity);
|
||||||
@@ -1497,7 +1746,15 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
|||||||
op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
|
op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
|
||||||
else
|
else
|
||||||
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
||||||
if (nbSeq==0) 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 : flags for FSE encoding type */
|
||||||
seqHead = op++;
|
seqHead = op++;
|
||||||
@@ -1506,36 +1763,42 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
|||||||
ZSTD_seqToCodes(seqStorePtr);
|
ZSTD_seqToCodes(seqStorePtr);
|
||||||
/* build CTable for Literal Lengths */
|
/* build CTable for Literal Lengths */
|
||||||
{ U32 max = MaxLL;
|
{ 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");
|
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,
|
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
|
||||||
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
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;
|
if (ZSTD_isError(countSize)) return countSize;
|
||||||
op += countSize;
|
op += countSize;
|
||||||
} }
|
} }
|
||||||
/* build CTable for Offsets */
|
/* build CTable for Offsets */
|
||||||
{ U32 max = MaxOff;
|
{ 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 */
|
/* 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;
|
ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
|
||||||
DEBUGLOG(5, "Building OF table");
|
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,
|
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
|
||||||
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
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;
|
if (ZSTD_isError(countSize)) return countSize;
|
||||||
op += countSize;
|
op += countSize;
|
||||||
} }
|
} }
|
||||||
/* build CTable for MatchLengths */
|
/* build CTable for MatchLengths */
|
||||||
{ U32 max = MaxML;
|
{ 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");
|
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,
|
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
|
||||||
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
|
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;
|
if (ZSTD_isError(countSize)) return countSize;
|
||||||
op += countSize;
|
op += countSize;
|
||||||
} }
|
} }
|
||||||
@@ -1548,7 +1811,7 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
|||||||
CTable_OffsetBits, ofCodeTable,
|
CTable_OffsetBits, ofCodeTable,
|
||||||
CTable_LitLength, llCodeTable,
|
CTable_LitLength, llCodeTable,
|
||||||
sequences, nbSeq,
|
sequences, nbSeq,
|
||||||
longOffsets);
|
longOffsets, bmi2);
|
||||||
if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
|
if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
|
||||||
op += bitstreamSize;
|
op += bitstreamSize;
|
||||||
}
|
}
|
||||||
@@ -1557,48 +1820,40 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||||
ZSTD_entropyCTables_t* entropy,
|
ZSTD_entropyCTables_t const* prevEntropy,
|
||||||
ZSTD_compressionParameters const* cParams,
|
ZSTD_entropyCTables_t* nextEntropy,
|
||||||
|
ZSTD_CCtx_params const* cctxParams,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
size_t srcSize)
|
size_t srcSize, U32* workspace, int bmi2)
|
||||||
{
|
{
|
||||||
size_t const cSize = ZSTD_compressSequences_internal(seqStorePtr, entropy, cParams,
|
size_t const cSize = ZSTD_compressSequences_internal(
|
||||||
dst, dstCapacity);
|
seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity,
|
||||||
/* If the srcSize <= dstCapacity, then there is enough space to write a
|
workspace, bmi2);
|
||||||
* raw uncompressed block. Since we ran out of space, the block must not
|
/* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
|
||||||
* be compressible, so fall back to a raw uncompressed block.
|
* Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
|
||||||
*/
|
*/
|
||||||
int const uncompressibleError = (cSize == ERROR(dstSize_tooSmall)) && (srcSize <= dstCapacity);
|
if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
|
||||||
if (ZSTD_isError(cSize) && !uncompressibleError)
|
return 0; /* block not compressed */
|
||||||
return cSize;
|
if (ZSTD_isError(cSize)) return cSize;
|
||||||
|
|
||||||
|
/* Check compressibility */
|
||||||
|
{ size_t const maxCSize = srcSize - ZSTD_minGain(srcSize); /* note : fixed formula, maybe should depend on compression level, or strategy */
|
||||||
|
if (cSize >= maxCSize) return 0; /* block not compressed */
|
||||||
|
}
|
||||||
|
|
||||||
/* We check that dictionaries have offset codes available for the first
|
/* We check that dictionaries have offset codes available for the first
|
||||||
* block. After the first block, the offcode table might not have large
|
* block. After the first block, the offcode table might not have large
|
||||||
* enough codes to represent the offsets in the data.
|
* enough codes to represent the offsets in the data.
|
||||||
*/
|
*/
|
||||||
if (entropy->offcode_repeatMode == FSE_repeat_valid)
|
if (nextEntropy->offcode_repeatMode == FSE_repeat_valid)
|
||||||
entropy->offcode_repeatMode = FSE_repeat_check;
|
nextEntropy->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; i<ZSTD_REP_NUM; i++) seqStorePtr->rep[i] = seqStorePtr->repToConfirm[i]; }
|
|
||||||
return cSize;
|
return cSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_selectBlockCompressor() :
|
/* ZSTD_selectBlockCompressor() :
|
||||||
* Not static, but internal use only (used by long distance matcher)
|
* Not static, but internal use only (used by long distance matcher)
|
||||||
* assumption : strat is a valid strategy */
|
* 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)
|
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
|
||||||
{
|
{
|
||||||
static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
|
static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
|
||||||
@@ -1632,32 +1887,83 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
|
|||||||
ssPtr->longLengthID = 0;
|
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);
|
ZSTD_matchState_t* const ms = &zc->blockState.matchState;
|
||||||
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1)
|
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
|
||||||
|
(U32)dstCapacity, ms->window.dictLimit, ms->nextToUpdate);
|
||||||
|
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
|
||||||
|
ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.searchLength);
|
||||||
return 0; /* don't even attempt compression below a certain srcSize */
|
return 0; /* don't even attempt compression below a certain srcSize */
|
||||||
|
}
|
||||||
ZSTD_resetSeqStore(&(zc->seqStore));
|
ZSTD_resetSeqStore(&(zc->seqStore));
|
||||||
|
|
||||||
/* limited update after a very long match */
|
/* limited update after a very long match */
|
||||||
{ const BYTE* const base = zc->base;
|
{ const BYTE* const base = ms->window.base;
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const U32 current = (U32)(istart-base);
|
const U32 current = (U32)(istart-base);
|
||||||
if (current > zc->nextToUpdate + 384)
|
if (current > ms->nextToUpdate + 384)
|
||||||
zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384));
|
ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
|
||||||
}
|
}
|
||||||
/* find and store sequences */
|
|
||||||
{ U32 const extDict = zc->lowLimit < zc->dictLimit;
|
/* select and store sequences */
|
||||||
const ZSTD_blockCompressor blockCompressor =
|
{ U32 const extDict = ZSTD_window_hasExtDict(ms->window);
|
||||||
zc->appliedParams.ldmParams.enableLdm
|
size_t lastLLSize;
|
||||||
? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
|
{ int i;
|
||||||
: ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
|
for (i = 0; i < ZSTD_REP_NUM; ++i)
|
||||||
size_t const lastLLSize = blockCompressor(zc, src, srcSize);
|
zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
|
||||||
const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
|
}
|
||||||
ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
|
if (zc->externSeqStore.pos < zc->externSeqStore.size) {
|
||||||
|
assert(!zc->appliedParams.ldmParams.enableLdm);
|
||||||
|
/* Updates ldmSeqStore.pos */
|
||||||
|
lastLLSize =
|
||||||
|
ZSTD_ldm_blockCompress(&zc->externSeqStore,
|
||||||
|
ms, &zc->seqStore,
|
||||||
|
zc->blockState.nextCBlock->rep,
|
||||||
|
&zc->appliedParams.cParams,
|
||||||
|
src, srcSize, extDict);
|
||||||
|
assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
|
||||||
|
} else if (zc->appliedParams.ldmParams.enableLdm) {
|
||||||
|
rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
|
||||||
|
|
||||||
|
ldmSeqStore.seq = zc->ldmSequences;
|
||||||
|
ldmSeqStore.capacity = zc->maxNbLdmSequences;
|
||||||
|
/* Updates ldmSeqStore.size */
|
||||||
|
CHECK_F(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
|
||||||
|
&zc->appliedParams.ldmParams,
|
||||||
|
src, srcSize));
|
||||||
|
/* Updates ldmSeqStore.pos */
|
||||||
|
lastLLSize =
|
||||||
|
ZSTD_ldm_blockCompress(&ldmSeqStore,
|
||||||
|
ms, &zc->seqStore,
|
||||||
|
zc->blockState.nextCBlock->rep,
|
||||||
|
&zc->appliedParams.cParams,
|
||||||
|
src, srcSize, extDict);
|
||||||
|
assert(ldmSeqStore.pos == ldmSeqStore.size);
|
||||||
|
} else { /* not long range mode */
|
||||||
|
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
|
||||||
|
lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, &zc->appliedParams.cParams, src, srcSize);
|
||||||
|
}
|
||||||
|
{ const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
|
||||||
|
ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* encode sequences and literals */
|
||||||
|
{ size_t const cSize = ZSTD_compressSequences(&zc->seqStore,
|
||||||
|
&zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
|
||||||
|
&zc->appliedParams,
|
||||||
|
dst, dstCapacity,
|
||||||
|
srcSize, zc->entropyWorkspace, zc->bmi2);
|
||||||
|
if (ZSTD_isError(cSize) || cSize == 0) return cSize;
|
||||||
|
/* confirm repcodes and entropy tables */
|
||||||
|
{ ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
|
||||||
|
zc->blockState.prevCBlock = zc->blockState.nextCBlock;
|
||||||
|
zc->blockState.nextCBlock = tmp;
|
||||||
|
}
|
||||||
|
return cSize;
|
||||||
}
|
}
|
||||||
/* encode */
|
|
||||||
return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1686,54 +1992,27 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
|||||||
XXH64_update(&cctx->xxhState, src, srcSize);
|
XXH64_update(&cctx->xxhState, src, srcSize);
|
||||||
|
|
||||||
while (remaining) {
|
while (remaining) {
|
||||||
|
ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
|
||||||
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
|
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
|
||||||
|
|
||||||
if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
|
if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
|
||||||
return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
|
return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
|
||||||
if (remaining < blockSize) blockSize = remaining;
|
if (remaining < blockSize) blockSize = remaining;
|
||||||
|
|
||||||
/* preemptive overflow correction:
|
if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) {
|
||||||
* 1. correction is large enough:
|
U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy);
|
||||||
* lowLimit > (3<<29) ==> current > 3<<29 + 1<<windowLog - blockSize
|
U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
|
||||||
* 1<<windowLog <= newCurrent < 1<<chainLog + 1<<windowLog
|
|
||||||
*
|
|
||||||
* current - newCurrent
|
|
||||||
* > (3<<29 + 1<<windowLog - blockSize) - (1<<windowLog + 1<<chainLog)
|
|
||||||
* > (3<<29 - blockSize) - (1<<chainLog)
|
|
||||||
* > (3<<29 - blockSize) - (1<<30) (NOTE: chainLog <= 30)
|
|
||||||
* > 1<<29 - 1<<17
|
|
||||||
*
|
|
||||||
* 2. (ip+blockSize - cctx->base) doesn't overflow:
|
|
||||||
* In 32 bit mode we limit windowLog to 30 so we don't get
|
|
||||||
* differences larger than 1<<31-1.
|
|
||||||
* 3. cctx->lowLimit < 1<<32:
|
|
||||||
* windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
|
|
||||||
*/
|
|
||||||
if (cctx->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 newCurrent = (current & cycleMask) + ((U32)1 << cctx->appliedParams.cParams.windowLog);
|
|
||||||
U32 const correction = current - newCurrent;
|
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
|
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
|
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
|
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
|
||||||
assert(current > newCurrent);
|
|
||||||
assert(correction > 1<<28); /* Loose bound, should be about 1<<29 */
|
|
||||||
ZSTD_reduceIndex(cctx, correction);
|
ZSTD_reduceIndex(cctx, correction);
|
||||||
cctx->base += correction;
|
if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
|
||||||
cctx->dictBase += correction;
|
else ms->nextToUpdate -= correction;
|
||||||
cctx->lowLimit -= correction;
|
ms->loadedDictEnd = 0;
|
||||||
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);
|
|
||||||
}
|
|
||||||
/* 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) cctx->dictLimit = cctx->lowLimit;
|
|
||||||
}
|
}
|
||||||
|
ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd);
|
||||||
|
if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
|
||||||
|
|
||||||
{ size_t cSize = ZSTD_compressBlock_internal(cctx,
|
{ size_t cSize = ZSTD_compressBlock_internal(cctx,
|
||||||
op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
|
op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
|
||||||
@@ -1810,16 +2089,44 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ZSTD_writeLastEmptyBlock() :
|
||||||
|
* output an empty Block with end-of-frame mark to complete a frame
|
||||||
|
* @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
|
||||||
|
* or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize)
|
||||||
|
*/
|
||||||
|
size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
|
||||||
|
{
|
||||||
|
if (dstCapacity < ZSTD_blockHeaderSize) return ERROR(dstSize_tooSmall);
|
||||||
|
{ U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */
|
||||||
|
MEM_writeLE24(dst, cBlockHeader24);
|
||||||
|
return ZSTD_blockHeaderSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
|
||||||
|
{
|
||||||
|
if (cctx->stage != ZSTDcs_init)
|
||||||
|
return ERROR(stage_wrong);
|
||||||
|
if (cctx->appliedParams.ldmParams.enableLdm)
|
||||||
|
return ERROR(parameter_unsupported);
|
||||||
|
cctx->externSeqStore.seq = seq;
|
||||||
|
cctx->externSeqStore.size = nbSeq;
|
||||||
|
cctx->externSeqStore.capacity = nbSeq;
|
||||||
|
cctx->externSeqStore.pos = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
U32 frame, U32 lastFrameChunk)
|
U32 frame, U32 lastFrameChunk)
|
||||||
{
|
{
|
||||||
const BYTE* const ip = (const BYTE*) src;
|
ZSTD_matchState_t* ms = &cctx->blockState.matchState;
|
||||||
size_t fhSize = 0;
|
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 (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
|
||||||
|
|
||||||
if (frame && (cctx->stage==ZSTDcs_init)) {
|
if (frame && (cctx->stage==ZSTDcs_init)) {
|
||||||
@@ -1833,26 +2140,11 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
|||||||
|
|
||||||
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
|
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
|
||||||
|
|
||||||
/* Check if blocks follow each other */
|
if (!ZSTD_window_update(&ms->window, src, srcSize)) {
|
||||||
if (src != cctx->nextSrc) {
|
ms->nextToUpdate = ms->window.dictLimit;
|
||||||
/* not contiguous */
|
|
||||||
size_t const distanceFromBase = (size_t)(cctx->nextSrc - cctx->base);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
if (cctx->appliedParams.ldmParams.enableLdm)
|
||||||
|
ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize);
|
DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize);
|
||||||
{ size_t const cSize = frame ?
|
{ size_t const cSize = frame ?
|
||||||
@@ -1860,6 +2152,14 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
|||||||
ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
|
ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
|
||||||
if (ZSTD_isError(cSize)) return cSize;
|
if (ZSTD_isError(cSize)) return cSize;
|
||||||
cctx->consumedSrcSize += srcSize;
|
cctx->consumedSrcSize += srcSize;
|
||||||
|
cctx->producedCSize += (cSize + fhSize);
|
||||||
|
if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
|
||||||
|
if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) {
|
||||||
|
DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u",
|
||||||
|
(U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
|
||||||
|
return ERROR(srcSize_wrong);
|
||||||
|
}
|
||||||
|
}
|
||||||
return cSize + fhSize;
|
return cSize + fhSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1868,14 +2168,15 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
|
|||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize)
|
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 */);
|
return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
|
size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
|
||||||
{
|
{
|
||||||
ZSTD_compressionParameters const cParams =
|
ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
|
||||||
ZSTD_getCParamsFromCCtxParams(cctx->appliedParams, 0, 0);
|
assert(!ZSTD_checkCParams(cParams));
|
||||||
return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
|
return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1889,50 +2190,45 @@ size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const
|
|||||||
/*! ZSTD_loadDictionaryContent() :
|
/*! ZSTD_loadDictionaryContent() :
|
||||||
* @return : 0, or an error code
|
* @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 ip = (const BYTE*) src;
|
||||||
const BYTE* const iend = ip + srcSize;
|
const BYTE* const iend = ip + srcSize;
|
||||||
|
ZSTD_compressionParameters const* cParams = ¶ms->cParams;
|
||||||
|
|
||||||
/* input becomes current prefix */
|
ZSTD_window_update(&ms->window, src, srcSize);
|
||||||
zc->lowLimit = zc->dictLimit;
|
ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
|
||||||
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);
|
|
||||||
|
|
||||||
zc->nextSrc = iend;
|
|
||||||
if (srcSize <= HASH_READ_SIZE) return 0;
|
if (srcSize <= HASH_READ_SIZE) return 0;
|
||||||
|
|
||||||
switch(zc->appliedParams.cParams.strategy)
|
switch(params->cParams.strategy)
|
||||||
{
|
{
|
||||||
case ZSTD_fast:
|
case ZSTD_fast:
|
||||||
ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
|
ZSTD_fillHashTable(ms, cParams, iend);
|
||||||
break;
|
break;
|
||||||
case ZSTD_dfast:
|
case ZSTD_dfast:
|
||||||
ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
|
ZSTD_fillDoubleHashTable(ms, cParams, iend);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSTD_greedy:
|
case ZSTD_greedy:
|
||||||
case ZSTD_lazy:
|
case ZSTD_lazy:
|
||||||
case ZSTD_lazy2:
|
case ZSTD_lazy2:
|
||||||
if (srcSize >= HASH_READ_SIZE)
|
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;
|
break;
|
||||||
|
|
||||||
case ZSTD_btlazy2:
|
case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
|
||||||
case ZSTD_btopt:
|
case ZSTD_btopt:
|
||||||
case ZSTD_btultra:
|
case ZSTD_btultra:
|
||||||
if (srcSize >= HASH_READ_SIZE)
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0); /* not possible : not a valid strategy id */
|
assert(0); /* not possible : not a valid strategy id */
|
||||||
}
|
}
|
||||||
|
|
||||||
zc->nextToUpdate = (U32)(iend - zc->base);
|
ms->nextToUpdate = (U32)(iend - ms->window.base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1956,25 +2252,26 @@ static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSym
|
|||||||
* https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
|
* https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
|
||||||
*/
|
*/
|
||||||
/*! ZSTD_loadZstdDictionary() :
|
/*! ZSTD_loadZstdDictionary() :
|
||||||
* @return : 0, or an error code
|
* @return : dictID, or an error code
|
||||||
* assumptions : magic number supposed already checked
|
* assumptions : magic number supposed already checked
|
||||||
* dictSize supposed > 8
|
* dictSize supposed > 8
|
||||||
*/
|
*/
|
||||||
static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
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* dictPtr = (const BYTE*)dict;
|
||||||
const BYTE* const dictEnd = dictPtr + dictSize;
|
const BYTE* const dictEnd = dictPtr + dictSize;
|
||||||
short offcodeNCount[MaxOff+1];
|
short offcodeNCount[MaxOff+1];
|
||||||
unsigned offcodeMaxValue = MaxOff;
|
unsigned offcodeMaxValue = MaxOff;
|
||||||
|
size_t dictID;
|
||||||
|
|
||||||
ZSTD_STATIC_ASSERT(sizeof(cctx->entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
|
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||||
|
|
||||||
dictPtr += 4; /* skip magic number */
|
dictPtr += 4; /* skip magic number */
|
||||||
cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
|
dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
|
||||||
dictPtr += 4;
|
dictPtr += 4;
|
||||||
|
|
||||||
{ unsigned maxSymbolValue = 255;
|
{ 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 (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
|
||||||
if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
|
if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
|
||||||
dictPtr += hufHeaderSize;
|
dictPtr += hufHeaderSize;
|
||||||
@@ -1985,7 +2282,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
|||||||
if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
|
if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
|
||||||
if (offcodeLog > OffFSELog) 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 */
|
/* 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);
|
dictionary_corrupted);
|
||||||
dictPtr += offcodeHeaderSize;
|
dictPtr += offcodeHeaderSize;
|
||||||
}
|
}
|
||||||
@@ -1997,7 +2294,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
|||||||
if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
|
if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
|
||||||
/* Every match length code must have non-zero probability */
|
/* Every match length code must have non-zero probability */
|
||||||
CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
|
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);
|
dictionary_corrupted);
|
||||||
dictPtr += matchlengthHeaderSize;
|
dictPtr += matchlengthHeaderSize;
|
||||||
}
|
}
|
||||||
@@ -2009,15 +2306,15 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
|||||||
if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
|
if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
|
||||||
/* Every literal length code must have non-zero probability */
|
/* Every literal length code must have non-zero probability */
|
||||||
CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
|
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);
|
dictionary_corrupted);
|
||||||
dictPtr += litlengthHeaderSize;
|
dictPtr += litlengthHeaderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
|
if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
|
||||||
cctx->seqStore.rep[0] = MEM_readLE32(dictPtr+0);
|
bs->rep[0] = MEM_readLE32(dictPtr+0);
|
||||||
cctx->seqStore.rep[1] = MEM_readLE32(dictPtr+4);
|
bs->rep[1] = MEM_readLE32(dictPtr+4);
|
||||||
cctx->seqStore.rep[2] = MEM_readLE32(dictPtr+8);
|
bs->rep[2] = MEM_readLE32(dictPtr+8);
|
||||||
dictPtr += 12;
|
dictPtr += 12;
|
||||||
|
|
||||||
{ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
|
{ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
|
||||||
@@ -2031,50 +2328,55 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
|||||||
/* All repCodes must be <= dictContentSize and != 0*/
|
/* All repCodes must be <= dictContentSize and != 0*/
|
||||||
{ U32 u;
|
{ U32 u;
|
||||||
for (u=0; u<3; u++) {
|
for (u=0; u<3; u++) {
|
||||||
if (cctx->seqStore.rep[u] == 0) return ERROR(dictionary_corrupted);
|
if (bs->rep[u] == 0) return ERROR(dictionary_corrupted);
|
||||||
if (cctx->seqStore.rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
|
if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
|
||||||
} }
|
} }
|
||||||
|
|
||||||
cctx->entropy->hufCTable_repeatMode = HUF_repeat_valid;
|
bs->entropy.hufCTable_repeatMode = HUF_repeat_valid;
|
||||||
cctx->entropy->offcode_repeatMode = FSE_repeat_valid;
|
bs->entropy.offcode_repeatMode = FSE_repeat_valid;
|
||||||
cctx->entropy->matchlength_repeatMode = FSE_repeat_valid;
|
bs->entropy.matchlength_repeatMode = FSE_repeat_valid;
|
||||||
cctx->entropy->litlength_repeatMode = FSE_repeat_valid;
|
bs->entropy.litlength_repeatMode = FSE_repeat_valid;
|
||||||
return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
|
CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize));
|
||||||
|
return dictID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ZSTD_compress_insertDictionary() :
|
/** ZSTD_compress_insertDictionary() :
|
||||||
* @return : 0, or an error code */
|
* @return : dictID, or an error code */
|
||||||
static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
|
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,
|
const void* dict, size_t dictSize,
|
||||||
ZSTD_dictMode_e dictMode)
|
ZSTD_dictContentType_e dictContentType,
|
||||||
|
void* workspace)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
|
DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
|
||||||
if ((dict==NULL) || (dictSize<=8)) return 0;
|
if ((dict==NULL) || (dictSize<=8)) return 0;
|
||||||
|
|
||||||
|
ZSTD_reset_compressedBlockState(bs);
|
||||||
|
|
||||||
/* dict restricted modes */
|
/* dict restricted modes */
|
||||||
if (dictMode==ZSTD_dm_rawContent)
|
if (dictContentType == ZSTD_dct_rawContent)
|
||||||
return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
|
return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
|
||||||
|
|
||||||
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
|
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
|
||||||
if (dictMode == ZSTD_dm_auto) {
|
if (dictContentType == ZSTD_dct_auto) {
|
||||||
DEBUGLOG(4, "raw content dictionary detected");
|
DEBUGLOG(4, "raw content dictionary detected");
|
||||||
return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
|
return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
|
||||||
}
|
}
|
||||||
if (dictMode == ZSTD_dm_fullDict)
|
if (dictContentType == ZSTD_dct_fullDict)
|
||||||
return ERROR(dictionary_wrong);
|
return ERROR(dictionary_wrong);
|
||||||
assert(0); /* impossible */
|
assert(0); /* impossible */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dict as full zstd dictionary */
|
/* dict as full zstd dictionary */
|
||||||
return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
|
return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ZSTD_compressBegin_internal() :
|
/*! ZSTD_compressBegin_internal() :
|
||||||
* @return : 0, or an error code */
|
* @return : 0, or an error code */
|
||||||
size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||||
const void* dict, size_t dictSize,
|
const void* dict, size_t dictSize,
|
||||||
ZSTD_dictMode_e dictMode,
|
ZSTD_dictContentType_e dictContentType,
|
||||||
const ZSTD_CDict* cdict,
|
const ZSTD_CDict* cdict,
|
||||||
ZSTD_CCtx_params params, U64 pledgedSrcSize,
|
ZSTD_CCtx_params params, U64 pledgedSrcSize,
|
||||||
ZSTD_buffered_policy_e zbuff)
|
ZSTD_buffered_policy_e zbuff)
|
||||||
@@ -2086,19 +2388,26 @@ size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
|||||||
|
|
||||||
if (cdict && cdict->dictContentSize>0) {
|
if (cdict && cdict->dictContentSize>0) {
|
||||||
cctx->requestedParams = params;
|
cctx->requestedParams = params;
|
||||||
return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
|
return ZSTD_resetCCtx_usingCDict(cctx, cdict, params.cParams.windowLog,
|
||||||
params.cParams.windowLog, params.fParams, pledgedSrcSize,
|
params.fParams, pledgedSrcSize, zbuff);
|
||||||
zbuff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
|
CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
|
||||||
ZSTDcrp_continue, zbuff) );
|
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, dictContentType, 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,
|
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
||||||
const void* dict, size_t dictSize,
|
const void* dict, size_t dictSize,
|
||||||
ZSTD_dictMode_e dictMode,
|
ZSTD_dictContentType_e dictContentType,
|
||||||
const ZSTD_CDict* cdict,
|
const ZSTD_CDict* cdict,
|
||||||
ZSTD_CCtx_params params,
|
ZSTD_CCtx_params params,
|
||||||
unsigned long long pledgedSrcSize)
|
unsigned long long pledgedSrcSize)
|
||||||
@@ -2107,7 +2416,7 @@ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
|||||||
/* compression parameters verification and optimization */
|
/* compression parameters verification and optimization */
|
||||||
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
||||||
return ZSTD_compressBegin_internal(cctx,
|
return ZSTD_compressBegin_internal(cctx,
|
||||||
dict, dictSize, dictMode,
|
dict, dictSize, dictContentType,
|
||||||
cdict,
|
cdict,
|
||||||
params, pledgedSrcSize,
|
params, pledgedSrcSize,
|
||||||
ZSTDb_not_buffered);
|
ZSTDb_not_buffered);
|
||||||
@@ -2122,18 +2431,18 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
|
|||||||
ZSTD_CCtx_params const cctxParams =
|
ZSTD_CCtx_params const cctxParams =
|
||||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||||
return ZSTD_compressBegin_advanced_internal(cctx,
|
return ZSTD_compressBegin_advanced_internal(cctx,
|
||||||
dict, dictSize, ZSTD_dm_auto,
|
dict, dictSize, ZSTD_dct_auto,
|
||||||
NULL /*cdict*/,
|
NULL /*cdict*/,
|
||||||
cctxParams, pledgedSrcSize);
|
cctxParams, pledgedSrcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
|
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
|
||||||
{
|
{
|
||||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
|
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
|
||||||
ZSTD_CCtx_params const cctxParams =
|
ZSTD_CCtx_params const cctxParams =
|
||||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
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,
|
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL,
|
||||||
cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
|
cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2152,7 +2461,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
|
|||||||
BYTE* op = ostart;
|
BYTE* op = ostart;
|
||||||
size_t fhSize = 0;
|
size_t fhSize = 0;
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_writeEpilogue");
|
DEBUGLOG(4, "ZSTD_writeEpilogue");
|
||||||
if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
|
if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
|
||||||
|
|
||||||
/* special case : empty frame */
|
/* special case : empty frame */
|
||||||
@@ -2176,6 +2485,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
|
|||||||
if (cctx->appliedParams.fParams.checksumFlag) {
|
if (cctx->appliedParams.fParams.checksumFlag) {
|
||||||
U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
|
U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
|
||||||
if (dstCapacity<4) return ERROR(dstSize_tooSmall);
|
if (dstCapacity<4) return ERROR(dstSize_tooSmall);
|
||||||
|
DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", checksum);
|
||||||
MEM_writeLE32(op, checksum);
|
MEM_writeLE32(op, checksum);
|
||||||
op += 4;
|
op += 4;
|
||||||
}
|
}
|
||||||
@@ -2184,7 +2494,6 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
|
|||||||
return op-ostart;
|
return op-ostart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
|
size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize)
|
const void* src, size_t srcSize)
|
||||||
@@ -2242,25 +2551,27 @@ size_t ZSTD_compress_advanced_internal(
|
|||||||
const void* dict,size_t dictSize,
|
const void* dict,size_t dictSize,
|
||||||
ZSTD_CCtx_params params)
|
ZSTD_CCtx_params params)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_compress_advanced_internal");
|
DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)",
|
||||||
CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
|
(U32)srcSize);
|
||||||
|
CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL,
|
||||||
params, srcSize, ZSTDb_not_buffered) );
|
params, srcSize, ZSTDb_not_buffered) );
|
||||||
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
|
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
|
size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
|
||||||
const void* dict, size_t dictSize, int compressionLevel)
|
const void* dict, size_t dictSize, int compressionLevel)
|
||||||
{
|
{
|
||||||
ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize ? srcSize : 1, dict ? dictSize : 0);
|
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize ? srcSize : 1, dict ? dictSize : 0);
|
||||||
params.fParams.contentSizeFlag = 1;
|
ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||||
DEBUGLOG(4, "ZSTD_compress_usingDict (level=%i, srcSize=%u, dictSize=%u)",
|
assert(params.fParams.contentSizeFlag == 1);
|
||||||
compressionLevel, (U32)srcSize, (U32)dictSize);
|
ZSTD_CCtxParam_setParameter(&cctxParams, ZSTD_p_compressLiterals, compressionLevel>=0);
|
||||||
return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
|
return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
|
size_t ZSTD_compressCCtx (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
|
||||||
{
|
{
|
||||||
return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
|
DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (U32)srcSize);
|
||||||
|
return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
|
size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
|
||||||
@@ -2284,9 +2595,7 @@ size_t ZSTD_estimateCDictSize_advanced(
|
|||||||
ZSTD_dictLoadMethod_e dictLoadMethod)
|
ZSTD_dictLoadMethod_e dictLoadMethod)
|
||||||
{
|
{
|
||||||
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
|
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
|
||||||
DEBUGLOG(5, "CCtx estimate : %u",
|
return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
|
||||||
(U32)ZSTD_estimateCCtxSize_usingCParams(cParams));
|
|
||||||
return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_usingCParams(cParams)
|
|
||||||
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2300,23 +2609,24 @@ size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
|
|||||||
{
|
{
|
||||||
if (cdict==NULL) return 0; /* support sizeof on NULL */
|
if (cdict==NULL) return 0; /* support sizeof on NULL */
|
||||||
DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict));
|
DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict));
|
||||||
DEBUGLOG(5, "ZSTD_sizeof_CCtx : %u", (U32)ZSTD_sizeof_CCtx(cdict->refContext));
|
return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
|
||||||
return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_initCDict_internal(
|
static size_t ZSTD_initCDict_internal(
|
||||||
ZSTD_CDict* cdict,
|
ZSTD_CDict* cdict,
|
||||||
const void* dictBuffer, size_t dictSize,
|
const void* dictBuffer, size_t dictSize,
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
ZSTD_dictMode_e dictMode,
|
ZSTD_dictContentType_e dictContentType,
|
||||||
ZSTD_compressionParameters cParams)
|
ZSTD_compressionParameters cParams)
|
||||||
{
|
{
|
||||||
DEBUGLOG(3, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
|
DEBUGLOG(3, "ZSTD_initCDict_internal, dictContentType %u", (U32)dictContentType);
|
||||||
|
assert(!ZSTD_checkCParams(cParams));
|
||||||
|
cdict->cParams = cParams;
|
||||||
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
|
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
|
||||||
cdict->dictBuffer = NULL;
|
cdict->dictBuffer = NULL;
|
||||||
cdict->dictContent = dictBuffer;
|
cdict->dictContent = dictBuffer;
|
||||||
} else {
|
} else {
|
||||||
void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
|
void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem);
|
||||||
cdict->dictBuffer = internalBuffer;
|
cdict->dictBuffer = internalBuffer;
|
||||||
cdict->dictContent = internalBuffer;
|
cdict->dictContent = internalBuffer;
|
||||||
if (!internalBuffer) return ERROR(memory_allocation);
|
if (!internalBuffer) return ERROR(memory_allocation);
|
||||||
@@ -2324,13 +2634,31 @@ static size_t ZSTD_initCDict_internal(
|
|||||||
}
|
}
|
||||||
cdict->dictContentSize = dictSize;
|
cdict->dictContentSize = dictSize;
|
||||||
|
|
||||||
{ ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams;
|
/* Reset the state to no dictionary */
|
||||||
cctxParams.cParams = cParams;
|
ZSTD_reset_compressedBlockState(&cdict->cBlockState);
|
||||||
CHECK_F( ZSTD_compressBegin_internal(cdict->refContext,
|
{ void* const end = ZSTD_reset_matchState(
|
||||||
cdict->dictContent, dictSize, dictMode,
|
&cdict->matchState,
|
||||||
NULL,
|
(U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32,
|
||||||
cctxParams, ZSTD_CONTENTSIZE_UNKNOWN,
|
&cParams, ZSTDcrp_continue, /* forCCtx */ 0);
|
||||||
ZSTDb_not_buffered) );
|
assert(end == (char*)cdict->workspace + cdict->workspaceSize);
|
||||||
|
(void)end;
|
||||||
|
}
|
||||||
|
/* (Maybe) load the dictionary
|
||||||
|
* Skips loading the dictionary if it is <= 8 bytes.
|
||||||
|
*/
|
||||||
|
{ ZSTD_CCtx_params params;
|
||||||
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
||||||
|
params.fParams.contentSizeFlag = 1;
|
||||||
|
params.cParams = cParams;
|
||||||
|
{ size_t const dictID = ZSTD_compress_insertDictionary(
|
||||||
|
&cdict->cBlockState, &cdict->matchState, ¶ms,
|
||||||
|
cdict->dictContent, cdict->dictContentSize,
|
||||||
|
dictContentType, cdict->workspace);
|
||||||
|
if (ZSTD_isError(dictID)) return dictID;
|
||||||
|
assert(dictID <= (size_t)(U32)-1);
|
||||||
|
cdict->dictID = (U32)dictID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2338,24 +2666,27 @@ static size_t ZSTD_initCDict_internal(
|
|||||||
|
|
||||||
ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
|
ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
ZSTD_dictMode_e dictMode,
|
ZSTD_dictContentType_e dictContentType,
|
||||||
ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
|
ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
|
||||||
{
|
{
|
||||||
DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode);
|
DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (U32)dictContentType);
|
||||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||||
|
|
||||||
{ ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
|
{ 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, /* forCCtx */ 0);
|
||||||
|
void* const workspace = ZSTD_malloc(workspaceSize, customMem);
|
||||||
|
|
||||||
if (!cdict || !cctx) {
|
if (!cdict || !workspace) {
|
||||||
ZSTD_free(cdict, customMem);
|
ZSTD_free(cdict, customMem);
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_free(workspace, customMem);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cdict->refContext = cctx;
|
cdict->customMem = customMem;
|
||||||
|
cdict->workspace = workspace;
|
||||||
|
cdict->workspaceSize = workspaceSize;
|
||||||
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
||||||
dictBuffer, dictSize,
|
dictBuffer, dictSize,
|
||||||
dictLoadMethod, dictMode,
|
dictLoadMethod, dictContentType,
|
||||||
cParams) )) {
|
cParams) )) {
|
||||||
ZSTD_freeCDict(cdict);
|
ZSTD_freeCDict(cdict);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -2369,7 +2700,7 @@ ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionL
|
|||||||
{
|
{
|
||||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
|
ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
|
||||||
return ZSTD_createCDict_advanced(dict, dictSize,
|
return ZSTD_createCDict_advanced(dict, dictSize,
|
||||||
ZSTD_dlm_byCopy, ZSTD_dm_auto,
|
ZSTD_dlm_byCopy, ZSTD_dct_auto,
|
||||||
cParams, ZSTD_defaultCMem);
|
cParams, ZSTD_defaultCMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2377,15 +2708,15 @@ ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int
|
|||||||
{
|
{
|
||||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
|
ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
|
||||||
return ZSTD_createCDict_advanced(dict, dictSize,
|
return ZSTD_createCDict_advanced(dict, dictSize,
|
||||||
ZSTD_dlm_byRef, ZSTD_dm_auto,
|
ZSTD_dlm_byRef, ZSTD_dct_auto,
|
||||||
cParams, ZSTD_defaultCMem);
|
cParams, ZSTD_defaultCMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
|
size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
|
||||||
{
|
{
|
||||||
if (cdict==NULL) return 0; /* support free on NULL */
|
if (cdict==NULL) return 0; /* support free on NULL */
|
||||||
{ ZSTD_customMem const cMem = cdict->refContext->customMem;
|
{ ZSTD_customMem const cMem = cdict->customMem;
|
||||||
ZSTD_freeCCtx(cdict->refContext);
|
ZSTD_free(cdict->workspace, cMem);
|
||||||
ZSTD_free(cdict->dictBuffer, cMem);
|
ZSTD_free(cdict->dictBuffer, cMem);
|
||||||
ZSTD_free(cdict, cMem);
|
ZSTD_free(cdict, cMem);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2405,18 +2736,18 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
|
|||||||
* Note : there is no corresponding "free" function.
|
* Note : there is no corresponding "free" function.
|
||||||
* Since workspace was allocated externally, it must be freed externally.
|
* Since workspace was allocated externally, it must be freed externally.
|
||||||
*/
|
*/
|
||||||
ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
|
const ZSTD_CDict* ZSTD_initStaticCDict(
|
||||||
|
void* workspace, size_t workspaceSize,
|
||||||
const void* dict, size_t dictSize,
|
const void* dict, size_t dictSize,
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
ZSTD_dictMode_e dictMode,
|
ZSTD_dictContentType_e dictContentType,
|
||||||
ZSTD_compressionParameters cParams)
|
ZSTD_compressionParameters cParams)
|
||||||
{
|
{
|
||||||
size_t const cctxSize = ZSTD_estimateCCtxSize_usingCParams(cParams);
|
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
|
||||||
size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
|
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;
|
ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
|
||||||
void* ptr;
|
void* ptr;
|
||||||
DEBUGLOG(4, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
|
|
||||||
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
|
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
|
||||||
DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
|
DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
|
||||||
(U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
|
(U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
|
||||||
@@ -2429,19 +2760,22 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
|
|||||||
} else {
|
} else {
|
||||||
ptr = cdict+1;
|
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,
|
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
||||||
dict, dictSize,
|
dict, dictSize,
|
||||||
ZSTD_dlm_byRef, dictMode,
|
ZSTD_dlm_byRef, dictContentType,
|
||||||
cParams) ))
|
cParams) ))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return cdict;
|
return cdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) {
|
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
|
||||||
return cdict->refContext->appliedParams.cParams;
|
{
|
||||||
|
assert(cdict != NULL);
|
||||||
|
return cdict->cParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_compressBegin_usingCDict_advanced() :
|
/* ZSTD_compressBegin_usingCDict_advanced() :
|
||||||
@@ -2454,9 +2788,18 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
|
|||||||
if (cdict==NULL) return ERROR(dictionary_wrong);
|
if (cdict==NULL) return ERROR(dictionary_wrong);
|
||||||
{ ZSTD_CCtx_params params = cctx->requestedParams;
|
{ ZSTD_CCtx_params params = cctx->requestedParams;
|
||||||
params.cParams = ZSTD_getCParamsFromCDict(cdict);
|
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;
|
params.fParams = fParams;
|
||||||
return ZSTD_compressBegin_internal(cctx,
|
return ZSTD_compressBegin_internal(cctx,
|
||||||
NULL, 0, ZSTD_dm_auto,
|
NULL, 0, ZSTD_dct_auto,
|
||||||
cdict,
|
cdict,
|
||||||
params, pledgedSrcSize,
|
params, pledgedSrcSize,
|
||||||
ZSTDb_not_buffered);
|
ZSTDb_not_buffered);
|
||||||
@@ -2534,29 +2877,30 @@ size_t ZSTD_CStreamOutSize(void)
|
|||||||
return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
|
return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
|
static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
|
||||||
const void* const dict, size_t const dictSize, ZSTD_dictMode_e const dictMode,
|
const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
|
||||||
const ZSTD_CDict* const cdict,
|
const ZSTD_CDict* const cdict,
|
||||||
ZSTD_CCtx_params const params, unsigned long long const pledgedSrcSize)
|
ZSTD_CCtx_params const params, unsigned long long const pledgedSrcSize)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_resetCStream_internal");
|
DEBUGLOG(4, "ZSTD_resetCStream_internal (disableLiteralCompression=%i)",
|
||||||
|
params.disableLiteralCompression);
|
||||||
/* params are supposed to be fully validated at this point */
|
/* params are supposed to be fully validated at this point */
|
||||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||||
|
|
||||||
CHECK_F( ZSTD_compressBegin_internal(zcs,
|
CHECK_F( ZSTD_compressBegin_internal(cctx,
|
||||||
dict, dictSize, dictMode,
|
dict, dictSize, dictContentType,
|
||||||
cdict,
|
cdict,
|
||||||
params, pledgedSrcSize,
|
params, pledgedSrcSize,
|
||||||
ZSTDb_buffered) );
|
ZSTDb_buffered) );
|
||||||
|
|
||||||
zcs->inToCompress = 0;
|
cctx->inToCompress = 0;
|
||||||
zcs->inBuffPos = 0;
|
cctx->inBuffPos = 0;
|
||||||
zcs->inBuffTarget = zcs->blockSize
|
cctx->inBuffTarget = cctx->blockSize
|
||||||
+ (zcs->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
|
+ (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
|
||||||
zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
|
cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
|
||||||
zcs->streamStage = zcss_load;
|
cctx->streamStage = zcss_load;
|
||||||
zcs->frameEnded = 0;
|
cctx->frameEnded = 0;
|
||||||
return 0; /* ready to go */
|
return 0; /* ready to go */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2568,8 +2912,8 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
|
|||||||
DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (U32)pledgedSrcSize);
|
DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (U32)pledgedSrcSize);
|
||||||
if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
|
if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
|
||||||
params.fParams.contentSizeFlag = 1;
|
params.fParams.contentSizeFlag = 1;
|
||||||
params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0);
|
params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, 0);
|
||||||
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
|
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ZSTD_initCStream_internal() :
|
/*! ZSTD_initCStream_internal() :
|
||||||
@@ -2592,7 +2936,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
|
|||||||
}
|
}
|
||||||
ZSTD_freeCDict(zcs->cdictLocal);
|
ZSTD_freeCDict(zcs->cdictLocal);
|
||||||
zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
|
zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
|
||||||
ZSTD_dlm_byCopy, ZSTD_dm_auto,
|
ZSTD_dlm_byCopy, ZSTD_dct_auto,
|
||||||
params.cParams, zcs->customMem);
|
params.cParams, zcs->customMem);
|
||||||
zcs->cdict = zcs->cdictLocal;
|
zcs->cdict = zcs->cdictLocal;
|
||||||
if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
|
if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
|
||||||
@@ -2605,10 +2949,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
|
|||||||
zcs->cdict = cdict;
|
zcs->cdict = cdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
params.compressionLevel = ZSTD_CLEVEL_CUSTOM; /* enforce usage of cParams, instead of a dynamic derivation from cLevel (but does that happen ?) */
|
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
|
||||||
zcs->requestedParams = params;
|
|
||||||
|
|
||||||
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_initCStream_usingCDict_advanced() :
|
/* ZSTD_initCStream_usingCDict_advanced() :
|
||||||
@@ -2637,21 +2978,23 @@ size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
|
|||||||
return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); /* note : will check that cdict != NULL */
|
return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); /* note : will check that cdict != NULL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ZSTD_initCStream_advanced() :
|
/* ZSTD_initCStream_advanced() :
|
||||||
* pledgedSrcSize must be correct.
|
* pledgedSrcSize must be exact.
|
||||||
* if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
|
* if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
|
||||||
* dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */
|
* dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */
|
||||||
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
|
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
|
||||||
const void* dict, size_t dictSize,
|
const void* dict, size_t dictSize,
|
||||||
ZSTD_parameters params, unsigned long long pledgedSrcSize)
|
ZSTD_parameters params, unsigned long long pledgedSrcSize)
|
||||||
{
|
{
|
||||||
ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
|
|
||||||
DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u",
|
DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u",
|
||||||
(U32)pledgedSrcSize, params.fParams.contentSizeFlag);
|
(U32)pledgedSrcSize, params.fParams.contentSizeFlag);
|
||||||
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
||||||
if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */
|
if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */
|
||||||
|
{ ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
|
||||||
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, cctxParams, pledgedSrcSize);
|
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, cctxParams, pledgedSrcSize);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
|
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
|
||||||
{
|
{
|
||||||
@@ -2687,7 +3030,7 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
|
|||||||
|
|
||||||
/** ZSTD_compressStream_generic():
|
/** ZSTD_compressStream_generic():
|
||||||
* internal function for all *compressStream*() variants and *compress_generic()
|
* internal function for all *compressStream*() variants and *compress_generic()
|
||||||
* non-static, because can be called from zstdmt.c
|
* non-static, because can be called from zstdmt_compress.c
|
||||||
* @return : hint size for next input */
|
* @return : hint size for next input */
|
||||||
size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
||||||
ZSTD_outBuffer* output,
|
ZSTD_outBuffer* output,
|
||||||
@@ -2862,46 +3205,56 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
|||||||
DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage");
|
DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage");
|
||||||
if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
|
if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
|
||||||
params.cParams = ZSTD_getCParamsFromCCtxParams(
|
params.cParams = ZSTD_getCParamsFromCCtxParams(
|
||||||
cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
|
&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
|
||||||
|
|
||||||
#ifdef ZSTD_MULTITHREAD
|
#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 */
|
params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
|
||||||
if (params.nbThreads > 1) {
|
}
|
||||||
if (cctx->mtctx == NULL || (params.nbThreads != ZSTDMT_getNbThreads(cctx->mtctx))) {
|
if (params.nbWorkers > 0) {
|
||||||
DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbThreads=%u (previous: %u)",
|
/* mt context creation */
|
||||||
params.nbThreads, ZSTDMT_getNbThreads(cctx->mtctx));
|
if (cctx->mtctx == NULL || (params.nbWorkers != ZSTDMT_getNbWorkers(cctx->mtctx))) {
|
||||||
|
DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbWorkers=%u",
|
||||||
|
params.nbWorkers);
|
||||||
|
if (cctx->mtctx != NULL)
|
||||||
|
DEBUGLOG(4, "ZSTD_compress_generic: previous nbWorkers was %u",
|
||||||
|
ZSTDMT_getNbWorkers(cctx->mtctx));
|
||||||
ZSTDMT_freeCCtx(cctx->mtctx);
|
ZSTDMT_freeCCtx(cctx->mtctx);
|
||||||
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
|
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem);
|
||||||
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
|
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
|
||||||
}
|
}
|
||||||
DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads);
|
/* mt compression */
|
||||||
|
DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
|
||||||
CHECK_F( ZSTDMT_initCStream_internal(
|
CHECK_F( ZSTDMT_initCStream_internal(
|
||||||
cctx->mtctx,
|
cctx->mtctx,
|
||||||
prefixDict.dict, prefixDict.dictSize, ZSTD_dm_rawContent,
|
prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent,
|
||||||
cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
|
cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
|
||||||
cctx->streamStage = zcss_load;
|
cctx->streamStage = zcss_load;
|
||||||
cctx->appliedParams.nbThreads = params.nbThreads;
|
cctx->appliedParams.nbWorkers = params.nbWorkers;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{ CHECK_F( ZSTD_resetCStream_internal(
|
{ CHECK_F( ZSTD_resetCStream_internal(cctx,
|
||||||
cctx, prefixDict.dict, prefixDict.dictSize,
|
prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
|
||||||
prefixDict.dictMode, cctx->cdict, params,
|
cctx->cdict,
|
||||||
cctx->pledgedSrcSizePlusOne-1) );
|
params, cctx->pledgedSrcSizePlusOne-1) );
|
||||||
assert(cctx->streamStage == zcss_load);
|
assert(cctx->streamStage == zcss_load);
|
||||||
assert(cctx->appliedParams.nbThreads <= 1);
|
assert(cctx->appliedParams.nbWorkers == 0);
|
||||||
} }
|
} }
|
||||||
|
|
||||||
/* compression stage */
|
/* compression stage */
|
||||||
#ifdef ZSTD_MULTITHREAD
|
#ifdef ZSTD_MULTITHREAD
|
||||||
if (cctx->appliedParams.nbThreads > 1) {
|
if (cctx->appliedParams.nbWorkers > 0) {
|
||||||
size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
|
if (cctx->cParamsChanged) {
|
||||||
|
ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
|
||||||
|
cctx->cParamsChanged = 0;
|
||||||
|
}
|
||||||
|
{ size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
|
||||||
if ( ZSTD_isError(flushMin)
|
if ( ZSTD_isError(flushMin)
|
||||||
|| (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
|
|| (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
|
||||||
ZSTD_startNewCompression(cctx);
|
ZSTD_startNewCompression(cctx);
|
||||||
}
|
}
|
||||||
return flushMin;
|
return flushMin;
|
||||||
}
|
} }
|
||||||
#endif
|
#endif
|
||||||
CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
|
CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
|
||||||
DEBUGLOG(5, "completed ZSTD_compress_generic");
|
DEBUGLOG(5, "completed ZSTD_compress_generic");
|
||||||
@@ -2959,11 +3312,11 @@ int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
|
|||||||
static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
|
static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
|
||||||
{ /* "default" - guarantees a monotonically increasing memory budget */
|
{ /* "default" - guarantees a monotonically increasing memory budget */
|
||||||
/* W, C, H, S, L, TL, strat */
|
/* W, C, H, S, L, TL, strat */
|
||||||
{ 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
|
{ 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */
|
||||||
{ 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
|
{ 19, 13, 14, 1, 7, 1, ZSTD_fast }, /* level 1 */
|
||||||
{ 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
|
{ 19, 15, 16, 1, 6, 1, ZSTD_fast }, /* level 2 */
|
||||||
{ 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3 */
|
{ 20, 16, 17, 1, 5, 8, ZSTD_dfast }, /* level 3 */
|
||||||
{ 20, 17, 18, 1, 5, 16, ZSTD_dfast }, /* level 4 */
|
{ 20, 17, 18, 1, 5, 8, ZSTD_dfast }, /* level 4 */
|
||||||
{ 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */
|
{ 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */
|
||||||
{ 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
|
{ 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
|
||||||
{ 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */
|
{ 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */
|
||||||
@@ -2972,9 +3325,9 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
|
|||||||
{ 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
|
{ 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
|
||||||
{ 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
|
{ 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
|
||||||
{ 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
|
{ 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
|
||||||
{ 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
|
{ 22, 21, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */
|
||||||
{ 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
|
{ 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */
|
||||||
{ 22, 21, 22, 4, 5, 16, ZSTD_btlazy2 }, /* level 15 */
|
{ 22, 22, 22, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */
|
||||||
{ 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */
|
{ 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */
|
||||||
{ 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */
|
{ 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */
|
||||||
{ 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */
|
{ 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */
|
||||||
@@ -2985,8 +3338,8 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
|
|||||||
},
|
},
|
||||||
{ /* for srcSize <= 256 KB */
|
{ /* for srcSize <= 256 KB */
|
||||||
/* W, C, H, S, L, T, strat */
|
/* W, C, H, S, L, T, strat */
|
||||||
{ 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
|
{ 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
|
||||||
{ 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
|
{ 18, 13, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */
|
||||||
{ 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
|
{ 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
|
||||||
{ 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
|
{ 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
|
||||||
{ 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
|
{ 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
|
||||||
@@ -2997,8 +3350,8 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
|
|||||||
{ 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
|
{ 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
|
||||||
{ 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
|
{ 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
|
||||||
{ 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
|
{ 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
|
||||||
{ 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
|
{ 18, 18, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 12.*/
|
||||||
{ 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
|
{ 18, 19, 17, 7, 4, 8, ZSTD_btlazy2 }, /* level 13 */
|
||||||
{ 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
|
{ 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
|
||||||
{ 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
|
{ 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
|
||||||
{ 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
|
{ 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
|
||||||
@@ -3011,9 +3364,9 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
|
|||||||
},
|
},
|
||||||
{ /* for srcSize <= 128 KB */
|
{ /* for srcSize <= 128 KB */
|
||||||
/* W, C, H, S, L, T, strat */
|
/* W, C, H, S, L, T, strat */
|
||||||
{ 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
|
{ 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* level 0 - not used */
|
||||||
{ 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
|
{ 17, 12, 13, 1, 6, 1, ZSTD_fast }, /* level 1 */
|
||||||
{ 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
|
{ 17, 13, 16, 1, 5, 1, ZSTD_fast }, /* level 2 */
|
||||||
{ 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
|
{ 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
|
||||||
{ 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
|
{ 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
|
||||||
{ 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
|
{ 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
|
||||||
@@ -3037,9 +3390,9 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
|
|||||||
},
|
},
|
||||||
{ /* for srcSize <= 16 KB */
|
{ /* for srcSize <= 16 KB */
|
||||||
/* W, C, H, S, L, T, strat */
|
/* W, C, H, S, L, T, strat */
|
||||||
{ 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
|
{ 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
|
||||||
{ 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
|
{ 14, 14, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */
|
||||||
{ 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
|
{ 14, 14, 14, 1, 4, 1, ZSTD_fast }, /* level 2 */
|
||||||
{ 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
|
{ 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
|
||||||
{ 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
|
{ 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
|
||||||
{ 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
|
{ 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
|
||||||
@@ -3063,46 +3416,21 @@ 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<ZSTD_maxCLevel(); level++) {
|
|
||||||
ZSTD_compressionParameters const c1 = ZSTD_defaultCParameters[0][level];
|
|
||||||
ZSTD_compressionParameters const c2 = ZSTD_defaultCParameters[0][level+1];
|
|
||||||
assert(c1.windowLog <= c2.windowLog);
|
|
||||||
# define ZSTD_TABLECOST(h,c) ((1<<(h)) + (1<<(c)))
|
|
||||||
assert(ZSTD_TABLECOST(c1.hashLog, c1.chainLog) <= ZSTD_TABLECOST(c2.hashLog, c2.chainLog));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*! ZSTD_getCParams() :
|
/*! ZSTD_getCParams() :
|
||||||
* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
|
* @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
|
||||||
* Size values are optional, provide 0 if not known or unused */
|
* Size values are optional, provide 0 if not known or unused */
|
||||||
ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
|
ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
|
||||||
{
|
{
|
||||||
size_t const addedSize = srcSizeHint ? 0 : 500;
|
size_t const addedSize = srcSizeHint ? 0 : 500;
|
||||||
U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
|
U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
|
||||||
U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
|
U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
|
||||||
|
int row = compressionLevel;
|
||||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
|
DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel);
|
||||||
static int g_monotonicTest = 1;
|
if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
|
||||||
if (g_monotonicTest) {
|
if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
|
||||||
ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget();
|
if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
|
||||||
g_monotonicTest=0;
|
{ ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
|
||||||
}
|
if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
|
||||||
#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 */
|
|
||||||
if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
|
|
||||||
{ ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel];
|
|
||||||
return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); }
|
return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3113,6 +3441,7 @@ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long l
|
|||||||
ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
|
ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
|
||||||
ZSTD_parameters params;
|
ZSTD_parameters params;
|
||||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
|
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
|
||||||
|
DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
params.cParams = cParams;
|
params.cParams = cParams;
|
||||||
params.fParams.contentSizeFlag = 1;
|
params.fParams.contentSizeFlag = 1;
|
||||||
|
|||||||
@@ -30,8 +30,14 @@ extern "C" {
|
|||||||
/*-*************************************
|
/*-*************************************
|
||||||
* Constants
|
* Constants
|
||||||
***************************************/
|
***************************************/
|
||||||
static const U32 g_searchStrength = 8;
|
#define kSearchStrength 8
|
||||||
#define HASH_READ_SIZE 8
|
#define HASH_READ_SIZE 8
|
||||||
|
#define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index 1 now means "unsorted".
|
||||||
|
It could be confused for a real successor at index "1", if sorted as larger than its predecessor.
|
||||||
|
It's not a big deal though : candidate will just be sorted again.
|
||||||
|
Additionnally, candidate position 1 will be lost.
|
||||||
|
But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
|
||||||
|
The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy */
|
||||||
|
|
||||||
|
|
||||||
/*-*************************************
|
/*-*************************************
|
||||||
@@ -43,7 +49,7 @@ typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
|
|||||||
typedef struct ZSTD_prefixDict_s {
|
typedef struct ZSTD_prefixDict_s {
|
||||||
const void* dict;
|
const void* dict;
|
||||||
size_t dictSize;
|
size_t dictSize;
|
||||||
ZSTD_dictMode_e dictMode;
|
ZSTD_dictContentType_e dictContentType;
|
||||||
} ZSTD_prefixDict;
|
} ZSTD_prefixDict;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -51,7 +57,6 @@ typedef struct {
|
|||||||
FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
|
FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
|
||||||
FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
|
FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
|
||||||
FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
|
FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
|
||||||
U32 workspace[HUF_WORKSPACE_SIZE_U32];
|
|
||||||
HUF_repeat hufCTable_repeatMode;
|
HUF_repeat hufCTable_repeatMode;
|
||||||
FSE_repeat offcode_repeatMode;
|
FSE_repeat offcode_repeatMode;
|
||||||
FSE_repeat matchlength_repeatMode;
|
FSE_repeat matchlength_repeatMode;
|
||||||
@@ -93,12 +98,44 @@ typedef struct {
|
|||||||
U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */
|
U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */
|
||||||
} optState_t;
|
} optState_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
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 */
|
||||||
|
U32 lowLimit; /* below that point, no more data */
|
||||||
|
} ZSTD_window_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ZSTD_window_t window; /* State for window round buffer management */
|
||||||
|
U32 loadedDictEnd; /* index of end of dictionary */
|
||||||
|
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* 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 {
|
typedef struct {
|
||||||
U32 offset;
|
U32 offset;
|
||||||
U32 checksum;
|
U32 checksum;
|
||||||
} ldmEntry_t;
|
} ldmEntry_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
ZSTD_window_t window; /* State for the window round buffer management */
|
||||||
ldmEntry_t* hashTable;
|
ldmEntry_t* hashTable;
|
||||||
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
|
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
|
||||||
U64 hashPower; /* Used to compute the rolling hash.
|
U64 hashPower; /* Used to compute the rolling hash.
|
||||||
@@ -111,60 +148,68 @@ typedef struct {
|
|||||||
U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
|
U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
|
||||||
U32 minMatchLength; /* Minimum match length */
|
U32 minMatchLength; /* Minimum match length */
|
||||||
U32 hashEveryLog; /* Log number of entries to skip */
|
U32 hashEveryLog; /* Log number of entries to skip */
|
||||||
|
U32 windowLog; /* Window log for the LDM */
|
||||||
} ldmParams_t;
|
} ldmParams_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 offset;
|
||||||
|
U32 litLength;
|
||||||
|
U32 matchLength;
|
||||||
|
} rawSeq;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rawSeq* seq; /* The start of the sequences */
|
||||||
|
size_t pos; /* The position where reading stopped. <= size. */
|
||||||
|
size_t size; /* The number of sequences. <= capacity. */
|
||||||
|
size_t capacity; /* The capacity of the `seq` pointer */
|
||||||
|
} rawSeqStore_t;
|
||||||
|
|
||||||
struct ZSTD_CCtx_params_s {
|
struct ZSTD_CCtx_params_s {
|
||||||
ZSTD_format_e format;
|
ZSTD_format_e format;
|
||||||
ZSTD_compressionParameters cParams;
|
ZSTD_compressionParameters cParams;
|
||||||
ZSTD_frameParameters fParams;
|
ZSTD_frameParameters fParams;
|
||||||
|
|
||||||
int compressionLevel;
|
int compressionLevel;
|
||||||
U32 forceWindow; /* force back-references to respect limit of
|
int disableLiteralCompression;
|
||||||
|
int forceWindow; /* force back-references to respect limit of
|
||||||
* 1<<wLog, even for dictionary */
|
* 1<<wLog, even for dictionary */
|
||||||
|
|
||||||
/* Multithreading: used to pass parameters to mtctx */
|
/* Multithreading: used to pass parameters to mtctx */
|
||||||
U32 nbThreads;
|
unsigned nbWorkers;
|
||||||
unsigned jobSize;
|
unsigned jobSize;
|
||||||
unsigned overlapSizeLog;
|
unsigned overlapSizeLog;
|
||||||
|
|
||||||
/* Long distance matching parameters */
|
/* Long distance matching parameters */
|
||||||
ldmParams_t ldmParams;
|
ldmParams_t ldmParams;
|
||||||
|
|
||||||
/* For use with createCCtxParams() and freeCCtxParams() only */
|
/* Internal use, for createCCtxParams() and freeCCtxParams() only */
|
||||||
ZSTD_customMem customMem;
|
ZSTD_customMem customMem;
|
||||||
|
|
||||||
}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
|
}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
|
||||||
|
|
||||||
struct ZSTD_CCtx_s {
|
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;
|
ZSTD_compressionStage_e stage;
|
||||||
U32 dictID;
|
int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
|
||||||
|
int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
|
||||||
ZSTD_CCtx_params requestedParams;
|
ZSTD_CCtx_params requestedParams;
|
||||||
ZSTD_CCtx_params appliedParams;
|
ZSTD_CCtx_params appliedParams;
|
||||||
|
U32 dictID;
|
||||||
void* workSpace;
|
void* workSpace;
|
||||||
size_t workSpaceSize;
|
size_t workSpaceSize;
|
||||||
size_t blockSize;
|
size_t blockSize;
|
||||||
U64 pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
|
unsigned long long pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
|
||||||
U64 consumedSrcSize;
|
unsigned long long consumedSrcSize;
|
||||||
|
unsigned long long producedCSize;
|
||||||
XXH64_state_t xxhState;
|
XXH64_state_t xxhState;
|
||||||
ZSTD_customMem customMem;
|
ZSTD_customMem customMem;
|
||||||
size_t staticSize;
|
size_t staticSize;
|
||||||
|
|
||||||
seqStore_t seqStore; /* sequences storage ptrs */
|
seqStore_t seqStore; /* sequences storage ptrs */
|
||||||
optState_t optState;
|
|
||||||
ldmState_t ldmState; /* long distance matching state */
|
ldmState_t ldmState; /* long distance matching state */
|
||||||
U32* hashTable;
|
rawSeq* ldmSequences; /* Storage for the ldm output sequences */
|
||||||
U32* hashTable3;
|
size_t maxNbLdmSequences;
|
||||||
U32* chainTable;
|
rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */
|
||||||
ZSTD_entropyCTables_t* entropy;
|
ZSTD_blockState_t blockState;
|
||||||
|
U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
|
||||||
|
|
||||||
/* streaming */
|
/* streaming */
|
||||||
char* inBuff;
|
char* inBuff;
|
||||||
@@ -191,6 +236,12 @@ struct ZSTD_CCtx_s {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef size_t (*ZSTD_blockCompressor) (
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
|
MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
|
||||||
{
|
{
|
||||||
static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
@@ -362,7 +413,9 @@ MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* co
|
|||||||
* can count match length with `ip` & `match` in 2 different segments.
|
* can count match length with `ip` & `match` in 2 different segments.
|
||||||
* convention : on reaching mEnd, match count continue starting from iStart
|
* convention : on reaching mEnd, match count continue starting from iStart
|
||||||
*/
|
*/
|
||||||
MEM_STATIC size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
|
MEM_STATIC size_t
|
||||||
|
ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
|
||||||
|
const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
|
||||||
{
|
{
|
||||||
const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
|
const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
|
||||||
size_t const matchLength = ZSTD_count(ip, match, vEnd);
|
size_t const matchLength = ZSTD_count(ip, match, vEnd);
|
||||||
@@ -411,6 +464,171 @@ MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Round buffer management
|
||||||
|
***************************************/
|
||||||
|
/* Max current allowed */
|
||||||
|
#define ZSTD_CURRENT_MAX ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX))
|
||||||
|
/* Maximum chunk size before overflow correction needs to be called again */
|
||||||
|
#define ZSTD_CHUNKSIZE_MAX \
|
||||||
|
( ((U32)-1) /* Maximum ending current index */ \
|
||||||
|
- ZSTD_CURRENT_MAX) /* Maximum beginning lowLimit */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_window_clear():
|
||||||
|
* Clears the window containing the history by simply setting it to empty.
|
||||||
|
*/
|
||||||
|
MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
|
||||||
|
{
|
||||||
|
size_t const endT = (size_t)(window->nextSrc - window->base);
|
||||||
|
U32 const end = (U32)endT;
|
||||||
|
|
||||||
|
window->lowLimit = end;
|
||||||
|
window->dictLimit = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_window_hasExtDict():
|
||||||
|
* Returns non-zero if the window has a non-empty extDict.
|
||||||
|
*/
|
||||||
|
MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
|
||||||
|
{
|
||||||
|
return window.lowLimit < window.dictLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_window_needOverflowCorrection():
|
||||||
|
* Returns non-zero if the indices are getting too large and need overflow
|
||||||
|
* protection.
|
||||||
|
*/
|
||||||
|
MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
|
||||||
|
void const* srcEnd)
|
||||||
|
{
|
||||||
|
U32 const current = (U32)((BYTE const*)srcEnd - window.base);
|
||||||
|
return current > ZSTD_CURRENT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_window_correctOverflow():
|
||||||
|
* Reduces the indices to protect from index overflow.
|
||||||
|
* Returns the correction made to the indices, which must be applied to every
|
||||||
|
* stored index.
|
||||||
|
*
|
||||||
|
* The least significant cycleLog bits of the indices must remain the same,
|
||||||
|
* which may be 0. Every index up to maxDist in the past must be valid.
|
||||||
|
* NOTE: (maxDist & cycleMask) must be zero.
|
||||||
|
*/
|
||||||
|
MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
|
||||||
|
U32 maxDist, void const* src)
|
||||||
|
{
|
||||||
|
/* preemptive overflow correction:
|
||||||
|
* 1. correction is large enough:
|
||||||
|
* lowLimit > (3<<29) ==> current > 3<<29 + 1<<windowLog
|
||||||
|
* 1<<windowLog <= newCurrent < 1<<chainLog + 1<<windowLog
|
||||||
|
*
|
||||||
|
* current - newCurrent
|
||||||
|
* > (3<<29 + 1<<windowLog) - (1<<windowLog + 1<<chainLog)
|
||||||
|
* > (3<<29) - (1<<chainLog)
|
||||||
|
* > (3<<29) - (1<<30) (NOTE: chainLog <= 30)
|
||||||
|
* > 1<<29
|
||||||
|
*
|
||||||
|
* 2. (ip+ZSTD_CHUNKSIZE_MAX - cctx->base) doesn't overflow:
|
||||||
|
* After correction, current is less than (1<<chainLog + 1<<windowLog).
|
||||||
|
* In 64-bit mode we are safe, because we have 64-bit ptrdiff_t.
|
||||||
|
* In 32-bit mode we are safe, because (chainLog <= 29), so
|
||||||
|
* ip+ZSTD_CHUNKSIZE_MAX - cctx->base < 1<<32.
|
||||||
|
* 3. (cctx->lowLimit + 1<<windowLog) < 1<<32:
|
||||||
|
* windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
|
||||||
|
*/
|
||||||
|
U32 const cycleMask = (1U << cycleLog) - 1;
|
||||||
|
U32 const current = (U32)((BYTE const*)src - window->base);
|
||||||
|
U32 const newCurrent = (current & cycleMask) + maxDist;
|
||||||
|
U32 const correction = current - newCurrent;
|
||||||
|
assert((maxDist & cycleMask) == 0);
|
||||||
|
assert(current > newCurrent);
|
||||||
|
/* Loose bound, should be around 1<<29 (see above) */
|
||||||
|
assert(correction > 1<<28);
|
||||||
|
|
||||||
|
window->base += correction;
|
||||||
|
window->dictBase += correction;
|
||||||
|
window->lowLimit -= correction;
|
||||||
|
window->dictLimit -= correction;
|
||||||
|
|
||||||
|
DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction,
|
||||||
|
window->lowLimit);
|
||||||
|
return correction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_window_enforceMaxDist():
|
||||||
|
* Updates lowLimit so that:
|
||||||
|
* (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
|
||||||
|
* This allows a simple check that index >= lowLimit to see if index is valid.
|
||||||
|
* This must be called before a block compression call, with srcEnd as the block
|
||||||
|
* source end.
|
||||||
|
* If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit.
|
||||||
|
* This is because dictionaries are allowed to be referenced as long as the last
|
||||||
|
* byte of the dictionary is in the window, but once they are out of range,
|
||||||
|
* they cannot be referenced. If loadedDictEndPtr is NULL, we use
|
||||||
|
* loadedDictEnd == 0.
|
||||||
|
*/
|
||||||
|
MEM_STATIC void ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
|
||||||
|
void const* srcEnd, U32 maxDist,
|
||||||
|
U32* loadedDictEndPtr)
|
||||||
|
{
|
||||||
|
U32 const current = (U32)((BYTE const*)srcEnd - window->base);
|
||||||
|
U32 loadedDictEnd = loadedDictEndPtr != NULL ? *loadedDictEndPtr : 0;
|
||||||
|
if (current > maxDist + loadedDictEnd) {
|
||||||
|
U32 const newLowLimit = current - maxDist;
|
||||||
|
if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
|
||||||
|
if (window->dictLimit < window->lowLimit) {
|
||||||
|
DEBUGLOG(5, "Update dictLimit from %u to %u", window->dictLimit,
|
||||||
|
window->lowLimit);
|
||||||
|
window->dictLimit = window->lowLimit;
|
||||||
|
}
|
||||||
|
if (loadedDictEndPtr)
|
||||||
|
*loadedDictEndPtr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_window_update():
|
||||||
|
* Updates the window by appending [src, src + srcSize) to the window.
|
||||||
|
* If it is not contiguous, the current prefix becomes the extDict, and we
|
||||||
|
* forget about the extDict. Handles overlap of the prefix and extDict.
|
||||||
|
* Returns non-zero if the segment is contiguous.
|
||||||
|
*/
|
||||||
|
MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||||
|
void const* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
BYTE const* const ip = (BYTE const*)src;
|
||||||
|
U32 contiguous = 1;
|
||||||
|
/* Check if blocks follow each other */
|
||||||
|
if (src != window->nextSrc) {
|
||||||
|
/* not contiguous */
|
||||||
|
size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
|
||||||
|
DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u",
|
||||||
|
window->dictLimit);
|
||||||
|
window->lowLimit = window->dictLimit;
|
||||||
|
assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
|
||||||
|
window->dictLimit = (U32)distanceFromBase;
|
||||||
|
window->dictBase = window->base;
|
||||||
|
window->base = ip - distanceFromBase;
|
||||||
|
// ms->nextToUpdate = window->dictLimit;
|
||||||
|
if (window->dictLimit - window->lowLimit < HASH_READ_SIZE) window->lowLimit = window->dictLimit; /* too small extDict */
|
||||||
|
contiguous = 0;
|
||||||
|
}
|
||||||
|
window->nextSrc = ip + srcSize;
|
||||||
|
/* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
|
||||||
|
if ( (ip+srcSize > window->dictBase + window->lowLimit)
|
||||||
|
& (ip < window->dictBase + window->dictLimit)) {
|
||||||
|
ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
|
||||||
|
U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
|
||||||
|
window->lowLimit = lowLimitMax;
|
||||||
|
}
|
||||||
|
return contiguous;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined (__cplusplus)
|
#if defined (__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -421,6 +639,13 @@ MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
|
|||||||
* These prototypes shall only be called from within lib/compress
|
* These prototypes shall only be called from within lib/compress
|
||||||
* ============================================================== */
|
* ============================================================== */
|
||||||
|
|
||||||
|
/* ZSTD_getCParamsFromCCtxParams() :
|
||||||
|
* cParams are built depending on compressionLevel, src size hints,
|
||||||
|
* LDM and manually set compression parameters.
|
||||||
|
*/
|
||||||
|
ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
||||||
|
const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize);
|
||||||
|
|
||||||
/*! ZSTD_initCStream_internal() :
|
/*! ZSTD_initCStream_internal() :
|
||||||
* Private use only. Init streaming operation.
|
* Private use only. Init streaming operation.
|
||||||
* expects params to be valid.
|
* expects params to be valid.
|
||||||
@@ -446,7 +671,7 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
|
|||||||
* Private use only. To be called from zstdmt_compress.c. */
|
* Private use only. To be called from zstdmt_compress.c. */
|
||||||
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
||||||
const void* dict, size_t dictSize,
|
const void* dict, size_t dictSize,
|
||||||
ZSTD_dictMode_e dictMode,
|
ZSTD_dictContentType_e dictContentType,
|
||||||
const ZSTD_CDict* cdict,
|
const ZSTD_CDict* cdict,
|
||||||
ZSTD_CCtx_params params,
|
ZSTD_CCtx_params params,
|
||||||
unsigned long long pledgedSrcSize);
|
unsigned long long pledgedSrcSize);
|
||||||
@@ -459,4 +684,26 @@ size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
|
|||||||
const void* dict,size_t dictSize,
|
const void* dict,size_t dictSize,
|
||||||
ZSTD_CCtx_params params);
|
ZSTD_CCtx_params params);
|
||||||
|
|
||||||
|
|
||||||
|
/* ZSTD_writeLastEmptyBlock() :
|
||||||
|
* output an empty Block with end-of-frame mark to complete a frame
|
||||||
|
* @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
|
||||||
|
* or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize)
|
||||||
|
*/
|
||||||
|
size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity);
|
||||||
|
|
||||||
|
|
||||||
|
/* ZSTD_referenceExternalSequences() :
|
||||||
|
* Must be called before starting a compression operation.
|
||||||
|
* seqs must parse a prefix of the source.
|
||||||
|
* This cannot be used when long range matching is enabled.
|
||||||
|
* Zstd will use these sequences, and pass the literals to a secondary block
|
||||||
|
* compressor.
|
||||||
|
* @return : An error code on failure.
|
||||||
|
* NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory
|
||||||
|
* access and data corruption.
|
||||||
|
*/
|
||||||
|
size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq);
|
||||||
|
|
||||||
|
|
||||||
#endif /* ZSTD_COMPRESS_H */
|
#endif /* ZSTD_COMPRESS_H */
|
||||||
|
|||||||
@@ -12,44 +12,58 @@
|
|||||||
#include "zstd_double_fast.h"
|
#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 hashLarge = ms->hashTable;
|
||||||
U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
|
U32 const hBitsL = cParams->hashLog;
|
||||||
U32* const hashSmall = cctx->chainTable;
|
U32 const mls = cParams->searchLength;
|
||||||
U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
|
U32* const hashSmall = ms->chainTable;
|
||||||
const BYTE* const base = cctx->base;
|
U32 const hBitsS = cParams->chainLog;
|
||||||
const BYTE* ip = base + cctx->nextToUpdate;
|
const BYTE* const base = ms->window.base;
|
||||||
|
const BYTE* ip = base + ms->nextToUpdate;
|
||||||
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
||||||
const size_t fastHashFillStep = 3;
|
const U32 fastHashFillStep = 3;
|
||||||
|
|
||||||
while(ip <= iend) {
|
/* Always insert every fastHashFillStep position into the hash tables.
|
||||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
|
* Insert the other positions into the large hash table if their entry
|
||||||
hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
|
* is empty.
|
||||||
ip += fastHashFillStep;
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
|
size_t ZSTD_compressBlock_doubleFast_generic(
|
||||||
const void* src, size_t srcSize,
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
const U32 mls)
|
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
|
||||||
|
U32 const mls /* template */)
|
||||||
{
|
{
|
||||||
U32* const hashLong = cctx->hashTable;
|
U32* const hashLong = ms->hashTable;
|
||||||
const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
|
const U32 hBitsL = cParams->hashLog;
|
||||||
U32* const hashSmall = cctx->chainTable;
|
U32* const hashSmall = ms->chainTable;
|
||||||
const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
|
const U32 hBitsS = cParams->chainLog;
|
||||||
seqStore_t* seqStorePtr = &(cctx->seqStore);
|
const BYTE* const base = ms->window.base;
|
||||||
const BYTE* const base = cctx->base;
|
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const U32 lowestIndex = cctx->dictLimit;
|
const U32 lowestIndex = ms->window.dictLimit;
|
||||||
const BYTE* const lowest = base + lowestIndex;
|
const BYTE* const lowest = base + lowestIndex;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
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;
|
U32 offsetSaved = 0;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
@@ -76,7 +90,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
|
|||||||
/* favor repcode */
|
/* favor repcode */
|
||||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||||
} else {
|
} else {
|
||||||
U32 offset;
|
U32 offset;
|
||||||
if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
|
if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
|
||||||
@@ -99,14 +113,14 @@ size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
|
|||||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
ip += ((ip-anchor) >> kSearchStrength) + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
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 */
|
/* match found */
|
||||||
@@ -129,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 */
|
{ 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);
|
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
|
||||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (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;
|
ip += rLength;
|
||||||
anchor = ip;
|
anchor = ip;
|
||||||
continue; /* faster when present ... (?) */
|
continue; /* faster when present ... (?) */
|
||||||
} } }
|
} } }
|
||||||
|
|
||||||
/* save reps for next block */
|
/* save reps for next block */
|
||||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
|
rep[0] = offset_1 ? offset_1 : offsetSaved;
|
||||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
|
rep[1] = offset_2 ? offset_2 : offsetSaved;
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return iend - anchor;
|
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)
|
switch(mls)
|
||||||
{
|
{
|
||||||
default: /* includes case 3 */
|
default: /* includes case 3 */
|
||||||
case 4 :
|
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 :
|
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 :
|
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 :
|
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,
|
static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||||
const void* src, size_t srcSize,
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
const U32 mls)
|
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
|
||||||
|
U32 const mls /* template */)
|
||||||
{
|
{
|
||||||
U32* const hashLong = ctx->hashTable;
|
U32* const hashLong = ms->hashTable;
|
||||||
U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
|
U32 const hBitsL = cParams->hashLog;
|
||||||
U32* const hashSmall = ctx->chainTable;
|
U32* const hashSmall = ms->chainTable;
|
||||||
U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
|
U32 const hBitsS = cParams->chainLog;
|
||||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
const BYTE* const base = ms->window.base;
|
||||||
const BYTE* const base = ctx->base;
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
const BYTE* const dictBase = ctx->dictBase;
|
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const U32 lowestIndex = ctx->lowLimit;
|
const U32 lowestIndex = ms->window.lowLimit;
|
||||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||||
const U32 dictLimit = ctx->dictLimit;
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - 8;
|
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 */
|
/* Search Loop */
|
||||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||||
@@ -209,7 +225,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||||
} else {
|
} else {
|
||||||
if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
||||||
const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
|
const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
|
||||||
@@ -220,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 */
|
while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
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))) {
|
} else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
|
||||||
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||||
@@ -245,10 +261,10 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
}
|
}
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
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 {
|
} else {
|
||||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
ip += ((ip-anchor) >> kSearchStrength) + 1;
|
||||||
continue;
|
continue;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
@@ -272,7 +288,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
||||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
|
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 */
|
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;
|
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
||||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
||||||
ip += repLength2;
|
ip += repLength2;
|
||||||
@@ -283,27 +299,29 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
} } }
|
} } }
|
||||||
|
|
||||||
/* save reps for next block */
|
/* 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 the last literals size */
|
||||||
return iend - anchor;
|
return iend - anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
|
size_t ZSTD_compressBlock_doubleFast_extDict(
|
||||||
const void* src, size_t srcSize)
|
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)
|
switch(mls)
|
||||||
{
|
{
|
||||||
default: /* includes case 3 */
|
default: /* includes case 3 */
|
||||||
case 4 :
|
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 :
|
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 :
|
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 :
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,18 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mem.h" /* U32 */
|
#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)
|
#if defined (__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,39 +12,48 @@
|
|||||||
#include "zstd_fast.h"
|
#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 hashTable = ms->hashTable;
|
||||||
U32 const hBits = zc->appliedParams.cParams.hashLog;
|
U32 const hBits = cParams->hashLog;
|
||||||
const BYTE* const base = zc->base;
|
U32 const mls = cParams->searchLength;
|
||||||
const BYTE* ip = base + zc->nextToUpdate;
|
const BYTE* const base = ms->window.base;
|
||||||
|
const BYTE* ip = base + ms->nextToUpdate;
|
||||||
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
||||||
const size_t fastHashFillStep = 3;
|
const U32 fastHashFillStep = 3;
|
||||||
|
|
||||||
while(ip <= iend) {
|
/* Always insert every fastHashFillStep position into the hash table.
|
||||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
|
* Insert the other positions if their hash entry is empty.
|
||||||
ip += fastHashFillStep;
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
|
size_t ZSTD_compressBlock_fast_generic(
|
||||||
const void* src, size_t srcSize,
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
const U32 mls)
|
void const* src, size_t srcSize,
|
||||||
|
U32 const hlog, U32 const stepSize, U32 const mls)
|
||||||
{
|
{
|
||||||
U32* const hashTable = cctx->hashTable;
|
U32* const hashTable = ms->hashTable;
|
||||||
U32 const hBits = cctx->appliedParams.cParams.hashLog;
|
const BYTE* const base = ms->window.base;
|
||||||
seqStore_t* seqStorePtr = &(cctx->seqStore);
|
|
||||||
const BYTE* const base = cctx->base;
|
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const U32 lowestIndex = cctx->dictLimit;
|
const U32 lowestIndex = ms->window.dictLimit;
|
||||||
const BYTE* const lowest = base + lowestIndex;
|
const BYTE* const lowest = base + lowestIndex;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
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;
|
U32 offsetSaved = 0;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
@@ -57,7 +66,7 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
|
|||||||
/* Main Search Loop */
|
/* Main Search Loop */
|
||||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||||
size_t mLength;
|
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 current = (U32)(ip-base);
|
||||||
U32 const matchIndex = hashTable[h];
|
U32 const matchIndex = hashTable[h];
|
||||||
const BYTE* match = base + matchIndex;
|
const BYTE* match = base + matchIndex;
|
||||||
@@ -66,21 +75,21 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
|
|||||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
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;
|
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||||
} else {
|
} else {
|
||||||
U32 offset;
|
if ( (matchIndex <= lowestIndex)
|
||||||
if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
|
|| (MEM_read32(match) != MEM_read32(ip)) ) {
|
||||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
assert(stepSize >= 1);
|
||||||
|
ip += ((ip-anchor) >> kSearchStrength) + stepSize;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||||
offset = (U32)(ip-match);
|
{ U32 const offset = (U32)(ip-match);
|
||||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
offset_1 = offset;
|
||||||
|
ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
} }
|
||||||
}
|
|
||||||
|
|
||||||
/* match found */
|
/* match found */
|
||||||
ip += mLength;
|
ip += mLength;
|
||||||
@@ -88,8 +97,8 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
|
|||||||
|
|
||||||
if (ip <= ilimit) {
|
if (ip <= ilimit) {
|
||||||
/* Fill Table */
|
/* Fill Table */
|
||||||
hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
|
hashTable[ZSTD_hashPtr(base+current+2, hlog, 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(ip-2, hlog, mls)] = (U32)(ip-2-base);
|
||||||
/* check immediate repcode */
|
/* check immediate repcode */
|
||||||
while ( (ip <= ilimit)
|
while ( (ip <= ilimit)
|
||||||
&& ( (offset_2>0)
|
&& ( (offset_2>0)
|
||||||
@@ -97,65 +106,67 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
|
|||||||
/* store sequence */
|
/* store sequence */
|
||||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
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 */
|
{ 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);
|
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
|
||||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
|
ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
|
||||||
ip += rLength;
|
ip += rLength;
|
||||||
anchor = ip;
|
anchor = ip;
|
||||||
continue; /* faster when present ... (?) */
|
continue; /* faster when present ... (?) */
|
||||||
} } }
|
} } }
|
||||||
|
|
||||||
/* save reps for next block */
|
/* save reps for next block */
|
||||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
|
rep[0] = offset_1 ? offset_1 : offsetSaved;
|
||||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
|
rep[1] = offset_2 ? offset_2 : offsetSaved;
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return iend - anchor;
|
return iend - anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
|
size_t ZSTD_compressBlock_fast(
|
||||||
const void* src, size_t srcSize)
|
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;
|
||||||
|
U32 const stepSize = cParams->targetLength;
|
||||||
switch(mls)
|
switch(mls)
|
||||||
{
|
{
|
||||||
default: /* includes case 3 */
|
default: /* includes case 3 */
|
||||||
case 4 :
|
case 4 :
|
||||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4);
|
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4);
|
||||||
case 5 :
|
case 5 :
|
||||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5);
|
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5);
|
||||||
case 6 :
|
case 6 :
|
||||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6);
|
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6);
|
||||||
case 7 :
|
case 7 :
|
||||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7);
|
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||||
const void* src, size_t srcSize,
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
const U32 mls)
|
void const* src, size_t srcSize,
|
||||||
|
U32 const hlog, U32 const stepSize, U32 const mls)
|
||||||
{
|
{
|
||||||
U32* hashTable = ctx->hashTable;
|
U32* hashTable = ms->hashTable;
|
||||||
const U32 hBits = ctx->appliedParams.cParams.hashLog;
|
const BYTE* const base = ms->window.base;
|
||||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
const BYTE* const base = ctx->base;
|
|
||||||
const BYTE* const dictBase = ctx->dictBase;
|
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const U32 lowestIndex = ctx->lowLimit;
|
const U32 lowestIndex = ms->window.lowLimit;
|
||||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||||
const U32 dictLimit = ctx->dictLimit;
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - 8;
|
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 */
|
/* Search Loop */
|
||||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
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 U32 matchIndex = hashTable[h];
|
||||||
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
||||||
const BYTE* match = matchBase + matchIndex;
|
const BYTE* match = matchBase + matchIndex;
|
||||||
@@ -171,11 +182,12 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||||
} else {
|
} else {
|
||||||
if ( (matchIndex < lowestIndex) ||
|
if ( (matchIndex < lowestIndex) ||
|
||||||
(MEM_read32(match) != MEM_read32(ip)) ) {
|
(MEM_read32(match) != MEM_read32(ip)) ) {
|
||||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
assert(stepSize >= 1);
|
||||||
|
ip += ((ip-anchor) >> kSearchStrength) + stepSize;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
{ const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
{ const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
||||||
@@ -186,7 +198,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
offset = current - matchIndex;
|
offset = current - matchIndex;
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
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 */
|
/* found a match : store it */
|
||||||
@@ -195,8 +207,8 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
|
|
||||||
if (ip <= ilimit) {
|
if (ip <= ilimit) {
|
||||||
/* Fill Table */
|
/* Fill Table */
|
||||||
hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
|
hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
|
||||||
hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
|
hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
|
||||||
/* check immediate repcode */
|
/* check immediate repcode */
|
||||||
while (ip <= ilimit) {
|
while (ip <= ilimit) {
|
||||||
U32 const current2 = (U32)(ip-base);
|
U32 const current2 = (U32)(ip-base);
|
||||||
@@ -207,8 +219,8 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
||||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
|
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 */
|
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);
|
||||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
|
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
|
||||||
ip += repLength2;
|
ip += repLength2;
|
||||||
anchor = ip;
|
anchor = ip;
|
||||||
continue;
|
continue;
|
||||||
@@ -217,27 +229,31 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
} } }
|
} } }
|
||||||
|
|
||||||
/* save reps for next block */
|
/* 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 the last literals size */
|
||||||
return iend - anchor;
|
return iend - anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
|
size_t ZSTD_compressBlock_fast_extDict(
|
||||||
const void* src, size_t srcSize)
|
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;
|
||||||
|
U32 const stepSize = cParams->targetLength;
|
||||||
switch(mls)
|
switch(mls)
|
||||||
{
|
{
|
||||||
default: /* includes case 3 */
|
default: /* includes case 3 */
|
||||||
case 4 :
|
case 4 :
|
||||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4);
|
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4);
|
||||||
case 5 :
|
case 5 :
|
||||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5);
|
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5);
|
||||||
case 6 :
|
case 6 :
|
||||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6);
|
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6);
|
||||||
case 7 :
|
case 7 :
|
||||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7);
|
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,17 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mem.h" /* U32 */
|
#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);
|
void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
|
||||||
size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
|
ZSTD_compressionParameters const* cParams,
|
||||||
const void* src, size_t srcSize);
|
void const* end);
|
||||||
size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
|
size_t ZSTD_compressBlock_fast(
|
||||||
const void* src, size_t srcSize);
|
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)
|
#if defined (__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,76 +15,90 @@
|
|||||||
/*-*************************************
|
/*-*************************************
|
||||||
* Binary Tree search
|
* Binary Tree search
|
||||||
***************************************/
|
***************************************/
|
||||||
/** ZSTD_insertBt1() : add one or multiple positions to tree.
|
|
||||||
* ip : assumed <= iend-8 .
|
void ZSTD_updateDUBT(
|
||||||
* @return : nb of positions added */
|
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
|
const BYTE* ip, const BYTE* iend,
|
||||||
const BYTE* const ip, const BYTE* const iend,
|
U32 mls)
|
||||||
U32 nbCompares, U32 const mls, U32 const extDict)
|
|
||||||
{
|
{
|
||||||
U32* const hashTable = zc->hashTable;
|
U32* const hashTable = ms->hashTable;
|
||||||
U32 const hashLog = zc->appliedParams.cParams.hashLog;
|
U32 const hashLog = cParams->hashLog;
|
||||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
|
||||||
U32* const bt = zc->chainTable;
|
U32* const bt = ms->chainTable;
|
||||||
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
|
U32 const btLog = cParams->chainLog - 1;
|
||||||
|
U32 const btMask = (1 << btLog) - 1;
|
||||||
|
|
||||||
|
const BYTE* const base = ms->window.base;
|
||||||
|
U32 const target = (U32)(ip - base);
|
||||||
|
U32 idx = ms->nextToUpdate;
|
||||||
|
|
||||||
|
if (idx != target)
|
||||||
|
DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
|
||||||
|
idx, target, ms->window.dictLimit);
|
||||||
|
assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
|
||||||
|
(void)iend;
|
||||||
|
|
||||||
|
assert(idx >= ms->window.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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
ms->nextToUpdate = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** ZSTD_insertDUBT1() :
|
||||||
|
* sort one already inserted but unsorted position
|
||||||
|
* assumption : current >= btlow == (current - btmask)
|
||||||
|
* doesn't fail */
|
||||||
|
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 = ms->chainTable;
|
||||||
|
U32 const btLog = cParams->chainLog - 1;
|
||||||
U32 const btMask = (1 << btLog) - 1;
|
U32 const btMask = (1 << btLog) - 1;
|
||||||
U32 matchIndex = hashTable[h];
|
|
||||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||||
const BYTE* const base = zc->base;
|
const BYTE* const base = ms->window.base;
|
||||||
const BYTE* const dictBase = zc->dictBase;
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
const U32 dictLimit = zc->dictLimit;
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
|
const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
|
||||||
|
const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const BYTE* const prefixStart = base + dictLimit;
|
const BYTE* const prefixStart = base + dictLimit;
|
||||||
const BYTE* match;
|
const BYTE* match;
|
||||||
const U32 current = (U32)(ip-base);
|
|
||||||
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
|
||||||
U32* smallerPtr = bt + 2*(current&btMask);
|
U32* smallerPtr = bt + 2*(current&btMask);
|
||||||
U32* largerPtr = smallerPtr + 1;
|
U32* largerPtr = smallerPtr + 1;
|
||||||
|
U32 matchIndex = *smallerPtr;
|
||||||
U32 dummy32; /* to be nullified at the end */
|
U32 dummy32; /* to be nullified at the end */
|
||||||
U32 const windowLow = zc->lowLimit;
|
U32 const windowLow = ms->window.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) (dictLimit=%u, lowLimit=%u)",
|
||||||
|
current, dictLimit, windowLow);
|
||||||
assert(ip <= iend-8); /* required for h calculation */
|
assert(current >= btLow);
|
||||||
hashTable[h] = current; /* Update Hash Table */
|
assert(ip < iend); /* condition for ZSTD_count */
|
||||||
|
|
||||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||||
assert(matchIndex < current);
|
assert(matchIndex < current);
|
||||||
|
|
||||||
#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
|
if ( (!extDict)
|
||||||
const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
|
|| (matchIndex+matchLength >= dictLimit) /* both in current segment*/
|
||||||
if (matchIndex == predictedSmall) {
|
|| (current < dictLimit) /* both in extDict */) {
|
||||||
/* no need to check length, result known */
|
const BYTE* const mBase = !extDict || ((matchIndex+matchLength) >= dictLimit) ? base : dictBase;
|
||||||
*smallerPtr = matchIndex;
|
assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */
|
||||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
|| (current < dictLimit) );
|
||||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
match = mBase + matchIndex;
|
||||||
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);
|
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
|
||||||
} else {
|
} else {
|
||||||
match = dictBase + matchIndex;
|
match = dictBase + matchIndex;
|
||||||
@@ -93,11 +107,8 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
|
|||||||
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchLength > bestLength) {
|
DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ",
|
||||||
bestLength = matchLength;
|
current, matchIndex, (U32)matchLength);
|
||||||
if (matchLength > matchEndIdx - matchIndex)
|
|
||||||
matchEndIdx = matchIndex + (U32)matchLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
|
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 */
|
break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
|
||||||
@@ -108,6 +119,8 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
|
|||||||
*smallerPtr = matchIndex; /* update smaller idx */
|
*smallerPtr = matchIndex; /* update smaller idx */
|
||||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
||||||
|
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 */
|
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 */
|
matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
|
||||||
} else {
|
} else {
|
||||||
@@ -115,77 +128,92 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
|
|||||||
*largerPtr = matchIndex;
|
*largerPtr = matchIndex;
|
||||||
commonLengthLarger = matchLength;
|
commonLengthLarger = matchLength;
|
||||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
||||||
|
DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is larger => %u",
|
||||||
|
matchIndex, btLow, nextPtr[0]);
|
||||||
largerPtr = nextPtr;
|
largerPtr = nextPtr;
|
||||||
matchIndex = nextPtr[0];
|
matchIndex = nextPtr[0];
|
||||||
} }
|
} }
|
||||||
|
|
||||||
*smallerPtr = *largerPtr = 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 (
|
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,
|
const BYTE* const ip, const BYTE* const iend,
|
||||||
size_t* offsetPtr,
|
size_t* offsetPtr,
|
||||||
U32 nbCompares, const U32 mls,
|
U32 const mls,
|
||||||
U32 extDict)
|
U32 const extDict)
|
||||||
{
|
{
|
||||||
U32* const hashTable = zc->hashTable;
|
U32* const hashTable = ms->hashTable;
|
||||||
U32 const hashLog = zc->appliedParams.cParams.hashLog;
|
U32 const hashLog = cParams->hashLog;
|
||||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
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];
|
U32 matchIndex = hashTable[h];
|
||||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
|
||||||
const BYTE* const base = zc->base;
|
const BYTE* const base = ms->window.base;
|
||||||
const BYTE* const dictBase = zc->dictBase;
|
U32 const current = (U32)(ip-base);
|
||||||
const U32 dictLimit = zc->dictLimit;
|
U32 const windowLow = ms->window.lowLimit;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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_DUBT_findBestMatch: candidate %u is unsorted",
|
||||||
|
matchIndex);
|
||||||
|
*unsortedMark = previousCandidate;
|
||||||
|
previousCandidate = matchIndex;
|
||||||
|
matchIndex = *nextCandidate;
|
||||||
|
nextCandidate = bt + 2*(matchIndex&btMask);
|
||||||
|
unsortedMark = bt + 2*(matchIndex&btMask) + 1;
|
||||||
|
nbCandidates --;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (matchIndex > unsortLimit)
|
||||||
|
&& (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
|
||||||
|
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) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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(ms, cParams, matchIndex, iend,
|
||||||
|
nbCandidates, unsortLimit, extDict);
|
||||||
|
matchIndex = nextCandidateIdx;
|
||||||
|
nbCandidates++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find longest match */
|
||||||
|
{ size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||||
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const BYTE* const prefixStart = base + 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* smallerPtr = bt + 2*(current&btMask);
|
||||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||||
U32 matchEndIdx = current+8+1;
|
U32 matchEndIdx = current+8+1;
|
||||||
U32 dummy32; /* to be nullified at the end */
|
U32 dummy32; /* to be nullified at the end */
|
||||||
size_t bestLength = 0;
|
size_t bestLength = 0;
|
||||||
|
|
||||||
assert(ip <= iend-8); /* required for h calculation */
|
matchIndex = hashTable[h];
|
||||||
hashTable[h] = current; /* Update Hash Table */
|
hashTable[h] = current; /* Update Hash Table */
|
||||||
|
|
||||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||||
@@ -231,68 +259,74 @@ static size_t ZSTD_insertBtAndFindBestMatch (
|
|||||||
|
|
||||||
*smallerPtr = *largerPtr = 0;
|
*smallerPtr = *largerPtr = 0;
|
||||||
|
|
||||||
assert(matchEndIdx > current+8);
|
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)",
|
||||||
|
current, (U32)bestLength, (U32)*offsetPtr, mIndex);
|
||||||
|
}
|
||||||
return bestLength;
|
return bestLength;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
|
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
|
||||||
static size_t ZSTD_BtFindBestMatch (
|
static size_t ZSTD_BtFindBestMatch (
|
||||||
ZSTD_CCtx* zc,
|
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
const BYTE* const ip, const BYTE* const iLimit,
|
const BYTE* const ip, const BYTE* const iLimit,
|
||||||
size_t* offsetPtr,
|
size_t* offsetPtr,
|
||||||
const U32 maxNbAttempts, const U32 mls)
|
const U32 mls /* template */)
|
||||||
{
|
{
|
||||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
DEBUGLOG(7, "ZSTD_BtFindBestMatch");
|
||||||
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
|
if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
|
||||||
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
|
ZSTD_updateDUBT(ms, cParams, ip, iLimit, mls);
|
||||||
|
return ZSTD_DUBT_findBestMatch(ms, cParams, ip, iLimit, offsetPtr, mls, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTD_BtFindBestMatch_selectMLS (
|
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,
|
const BYTE* ip, const BYTE* const iLimit,
|
||||||
size_t* offsetPtr,
|
size_t* offsetPtr)
|
||||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
|
||||||
{
|
{
|
||||||
switch(matchLengthSearch)
|
switch(cParams->searchLength)
|
||||||
{
|
{
|
||||||
default : /* includes case 3 */
|
default : /* includes case 3 */
|
||||||
case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
|
case 4 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 4);
|
||||||
case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
|
case 5 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 5);
|
||||||
case 7 :
|
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 */
|
/** Tree updater, providing best match */
|
||||||
static size_t ZSTD_BtFindBestMatch_extDict (
|
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,
|
const BYTE* const ip, const BYTE* const iLimit,
|
||||||
size_t* offsetPtr,
|
size_t* offsetPtr,
|
||||||
const U32 maxNbAttempts, const U32 mls)
|
const U32 mls)
|
||||||
{
|
{
|
||||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
DEBUGLOG(7, "ZSTD_BtFindBestMatch_extDict");
|
||||||
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
|
if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
|
||||||
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
|
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 (
|
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,
|
const BYTE* ip, const BYTE* const iLimit,
|
||||||
size_t* offsetPtr,
|
size_t* offsetPtr)
|
||||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
|
||||||
{
|
{
|
||||||
switch(matchLengthSearch)
|
switch(cParams->searchLength)
|
||||||
{
|
{
|
||||||
default : /* includes case 3 */
|
default : /* includes case 3 */
|
||||||
case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
|
case 4 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 4);
|
||||||
case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
|
case 5 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 5);
|
||||||
case 7 :
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,15 +339,17 @@ static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
|
|||||||
|
|
||||||
/* Update chains up to ip (excluded)
|
/* Update chains up to ip (excluded)
|
||||||
Assumption : always within prefix (i.e. not within extDict) */
|
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;
|
U32* const hashTable = ms->hashTable;
|
||||||
const U32 hashLog = zc->appliedParams.cParams.hashLog;
|
const U32 hashLog = cParams->hashLog;
|
||||||
U32* const chainTable = zc->chainTable;
|
U32* const chainTable = ms->chainTable;
|
||||||
const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
|
const U32 chainMask = (1 << cParams->chainLog) - 1;
|
||||||
const BYTE* const base = zc->base;
|
const BYTE* const base = ms->window.base;
|
||||||
const U32 target = (U32)(ip - base);
|
const U32 target = (U32)(ip - base);
|
||||||
U32 idx = zc->nextToUpdate;
|
U32 idx = ms->nextToUpdate;
|
||||||
|
|
||||||
while(idx < target) { /* catch up */
|
while(idx < target) { /* catch up */
|
||||||
size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
|
size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
|
||||||
@@ -322,35 +358,42 @@ U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
|
|||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
zc->nextToUpdate = target;
|
ms->nextToUpdate = target;
|
||||||
return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
|
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) */
|
/* inlining is important to hardwire a hot branch (template emulation) */
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
size_t ZSTD_HcFindBestMatch_generic (
|
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,
|
const BYTE* const ip, const BYTE* const iLimit,
|
||||||
size_t* offsetPtr,
|
size_t* offsetPtr,
|
||||||
const U32 maxNbAttempts, const U32 mls, const U32 extDict)
|
const U32 mls, const U32 extDict)
|
||||||
{
|
{
|
||||||
U32* const chainTable = zc->chainTable;
|
U32* const chainTable = ms->chainTable;
|
||||||
const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
|
const U32 chainSize = (1 << cParams->chainLog);
|
||||||
const U32 chainMask = chainSize-1;
|
const U32 chainMask = chainSize-1;
|
||||||
const BYTE* const base = zc->base;
|
const BYTE* const base = ms->window.base;
|
||||||
const BYTE* const dictBase = zc->dictBase;
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
const U32 dictLimit = zc->dictLimit;
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
const BYTE* const prefixStart = base + dictLimit;
|
const BYTE* const prefixStart = base + dictLimit;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const U32 lowLimit = zc->lowLimit;
|
const U32 lowLimit = ms->window.lowLimit;
|
||||||
const U32 current = (U32)(ip-base);
|
const U32 current = (U32)(ip-base);
|
||||||
const U32 minChain = current > chainSize ? current - chainSize : 0;
|
const U32 minChain = current > chainSize ? current - chainSize : 0;
|
||||||
int nbAttempts=maxNbAttempts;
|
U32 nbAttempts = 1U << cParams->searchLog;
|
||||||
size_t ml=4-1;
|
size_t ml=4-1;
|
||||||
|
|
||||||
/* HC4 match finder */
|
/* 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--) {
|
for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
|
||||||
size_t currentMl=0;
|
size_t currentMl=0;
|
||||||
@@ -381,35 +424,33 @@ size_t ZSTD_HcFindBestMatch_generic (
|
|||||||
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
|
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,
|
const BYTE* ip, const BYTE* const iLimit,
|
||||||
size_t* offsetPtr,
|
size_t* offsetPtr)
|
||||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
|
||||||
{
|
{
|
||||||
switch(matchLengthSearch)
|
switch(cParams->searchLength)
|
||||||
{
|
{
|
||||||
default : /* includes case 3 */
|
default : /* includes case 3 */
|
||||||
case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
|
case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, 0);
|
||||||
case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
|
case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, 0);
|
||||||
case 7 :
|
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 (
|
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,
|
const BYTE* ip, const BYTE* const iLimit,
|
||||||
size_t* const offsetPtr,
|
size_t* const offsetPtr)
|
||||||
U32 const maxNbAttempts, U32 const matchLengthSearch)
|
|
||||||
{
|
{
|
||||||
switch(matchLengthSearch)
|
switch(cParams->searchLength)
|
||||||
{
|
{
|
||||||
default : /* includes case 3 */
|
default : /* includes case 3 */
|
||||||
case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
|
case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, 1);
|
||||||
case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
|
case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, 1);
|
||||||
case 7 :
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,30 +459,29 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
|
|||||||
* Common parser - lazy strategy
|
* Common parser - lazy strategy
|
||||||
*********************************/
|
*********************************/
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
|
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 void* src, size_t srcSize,
|
||||||
const U32 searchMethod, const U32 depth)
|
const U32 searchMethod, const U32 depth)
|
||||||
{
|
{
|
||||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - 8;
|
const BYTE* const ilimit = iend - 8;
|
||||||
const BYTE* const base = ctx->base + ctx->dictLimit;
|
const BYTE* const base = ms->window.base + ms->window.dictLimit;
|
||||||
|
|
||||||
U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
|
typedef size_t (*searchMax_f)(
|
||||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
|
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
||||||
typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
|
|
||||||
size_t* offsetPtr,
|
|
||||||
U32 maxNbAttempts, U32 matchLengthSearch);
|
|
||||||
searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
|
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 */
|
/* init */
|
||||||
ip += (ip==base);
|
ip += (ip==base);
|
||||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
ms->nextToUpdate3 = ms->nextToUpdate;
|
||||||
{ U32 const maxRep = (U32)(ip-base);
|
{ U32 const maxRep = (U32)(ip-base);
|
||||||
if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
|
if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
|
||||||
if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
|
if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
|
||||||
@@ -462,13 +502,13 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
|
|||||||
|
|
||||||
/* first search (depth 0) */
|
/* first search (depth 0) */
|
||||||
{ size_t offsetFound = 99999999;
|
{ 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)
|
if (ml2 > matchLength)
|
||||||
matchLength = ml2, start = ip, offset=offsetFound;
|
matchLength = ml2, start = ip, offset=offsetFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchLength < 4) {
|
if (matchLength < 4) {
|
||||||
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
|
ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,7 +524,7 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
|
|||||||
matchLength = mlRep, offset = 0, start = ip;
|
matchLength = mlRep, offset = 0, start = ip;
|
||||||
}
|
}
|
||||||
{ size_t offset2=99999999;
|
{ 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 gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
||||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||||
@@ -503,7 +543,7 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
|
|||||||
matchLength = ml2, offset = 0, start = ip;
|
matchLength = ml2, offset = 0, start = ip;
|
||||||
}
|
}
|
||||||
{ size_t offset2=99999999;
|
{ 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 gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
||||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||||
@@ -528,7 +568,7 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
|
|||||||
/* store sequence */
|
/* store sequence */
|
||||||
_storeSequence:
|
_storeSequence:
|
||||||
{ size_t const litLength = start - anchor;
|
{ 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;
|
anchor = ip = start + matchLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,73 +578,80 @@ _storeSequence:
|
|||||||
/* store sequence */
|
/* store sequence */
|
||||||
matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
|
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;
|
ip += matchLength;
|
||||||
anchor = ip;
|
anchor = ip;
|
||||||
continue; /* faster when present ... (?) */
|
continue; /* faster when present ... (?) */
|
||||||
} }
|
} }
|
||||||
|
|
||||||
/* Save reps for next block */
|
/* Save reps for next block */
|
||||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
|
rep[0] = offset_1 ? offset_1 : savedOffset;
|
||||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
|
rep[1] = offset_2 ? offset_2 : savedOffset;
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return iend - anchor;
|
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
|
FORCE_INLINE_TEMPLATE
|
||||||
size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
|
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 void* src, size_t srcSize,
|
||||||
const U32 searchMethod, const U32 depth)
|
const U32 searchMethod, const U32 depth)
|
||||||
{
|
{
|
||||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - 8;
|
const BYTE* const ilimit = iend - 8;
|
||||||
const BYTE* const base = ctx->base;
|
const BYTE* const base = ms->window.base;
|
||||||
const U32 dictLimit = ctx->dictLimit;
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
const U32 lowestIndex = ctx->lowLimit;
|
const U32 lowestIndex = ms->window.lowLimit;
|
||||||
const BYTE* const prefixStart = base + dictLimit;
|
const BYTE* const prefixStart = base + dictLimit;
|
||||||
const BYTE* const dictBase = ctx->dictBase;
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const BYTE* const dictStart = dictBase + ctx->lowLimit;
|
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||||
|
|
||||||
const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
|
typedef size_t (*searchMax_f)(
|
||||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
|
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
||||||
typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
|
|
||||||
size_t* offsetPtr,
|
|
||||||
U32 maxNbAttempts, U32 matchLengthSearch);
|
|
||||||
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
|
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 */
|
/* init */
|
||||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
ms->nextToUpdate3 = ms->nextToUpdate;
|
||||||
ip += (ip == prefixStart);
|
ip += (ip == prefixStart);
|
||||||
|
|
||||||
/* Match Loop */
|
/* Match Loop */
|
||||||
@@ -628,13 +675,13 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
|
|
||||||
/* first search (depth 0) */
|
/* first search (depth 0) */
|
||||||
{ size_t offsetFound = 99999999;
|
{ 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)
|
if (ml2 > matchLength)
|
||||||
matchLength = ml2, start = ip, offset=offsetFound;
|
matchLength = ml2, start = ip, offset=offsetFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchLength < 4) {
|
if (matchLength < 4) {
|
||||||
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
|
ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,7 +708,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
|
|
||||||
/* search match, depth 1 */
|
/* search match, depth 1 */
|
||||||
{ size_t offset2=99999999;
|
{ 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 gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
||||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||||
@@ -691,7 +738,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
|
|
||||||
/* search match, depth 2 */
|
/* search match, depth 2 */
|
||||||
{ size_t offset2=99999999;
|
{ 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 gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
||||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||||
@@ -713,7 +760,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
|
|||||||
/* store sequence */
|
/* store sequence */
|
||||||
_storeSequence:
|
_storeSequence:
|
||||||
{ size_t const litLength = start - anchor;
|
{ 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;
|
anchor = ip = start + matchLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,7 +775,7 @@ _storeSequence:
|
|||||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||||
matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
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 */
|
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;
|
ip += matchLength;
|
||||||
anchor = ip;
|
anchor = ip;
|
||||||
continue; /* faster when present ... (?) */
|
continue; /* faster when present ... (?) */
|
||||||
@@ -737,29 +784,41 @@ _storeSequence:
|
|||||||
} }
|
} }
|
||||||
|
|
||||||
/* Save reps for next block */
|
/* 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 the last literals size */
|
||||||
return iend - anchor;
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,22 +15,39 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mem.h" /* U32 */
|
#include "zstd_compress_internal.h"
|
||||||
#include "zstd.h" /* ZSTD_CCtx, size_t */
|
|
||||||
|
|
||||||
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls);
|
U32 ZSTD_insertAndFindFirstIndex(
|
||||||
void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
|
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
|
const BYTE* ip);
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
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_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_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
size_t ZSTD_compressBlock_btlazy2(
|
||||||
size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_btlazy2_extDict(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);
|
||||||
|
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_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)
|
#if defined (__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,36 +17,45 @@
|
|||||||
#define LDM_HASH_RLOG 7
|
#define LDM_HASH_RLOG 7
|
||||||
#define LDM_HASH_CHAR_OFFSET 10
|
#define LDM_HASH_CHAR_OFFSET 10
|
||||||
|
|
||||||
size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm)
|
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
||||||
|
ZSTD_compressionParameters const* cParams)
|
||||||
{
|
{
|
||||||
|
U32 const windowLog = cParams->windowLog;
|
||||||
ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
|
ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
|
||||||
params->enableLdm = enableLdm>0;
|
DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
|
||||||
params->hashLog = 0;
|
if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
|
||||||
params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
|
if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
|
||||||
params->minMatchLength = LDM_MIN_MATCH_LENGTH;
|
if (cParams->strategy >= ZSTD_btopt) {
|
||||||
params->hashEveryLog = ZSTD_LDM_HASHEVERYLOG_NOTSET;
|
/* Get out of the way of the optimal parser */
|
||||||
return 0;
|
U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength);
|
||||||
|
assert(minMatch >= ZSTD_LDM_MINMATCH_MIN);
|
||||||
|
assert(minMatch <= ZSTD_LDM_MINMATCH_MAX);
|
||||||
|
params->minMatchLength = minMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog)
|
|
||||||
{
|
|
||||||
if (params->hashLog == 0) {
|
if (params->hashLog == 0) {
|
||||||
params->hashLog = MAX(ZSTD_HASHLOG_MIN, windowLog - LDM_HASH_RLOG);
|
params->hashLog = MAX(ZSTD_HASHLOG_MIN, windowLog - LDM_HASH_RLOG);
|
||||||
assert(params->hashLog <= ZSTD_HASHLOG_MAX);
|
assert(params->hashLog <= ZSTD_HASHLOG_MAX);
|
||||||
}
|
}
|
||||||
if (params->hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET) {
|
if (params->hashEveryLog == 0) {
|
||||||
params->hashEveryLog =
|
params->hashEveryLog =
|
||||||
windowLog < params->hashLog ? 0 : windowLog - params->hashLog;
|
windowLog < params->hashLog ? 0 : windowLog - params->hashLog;
|
||||||
}
|
}
|
||||||
params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
|
params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog) {
|
size_t ZSTD_ldm_getTableSize(ldmParams_t params)
|
||||||
size_t const ldmHSize = ((size_t)1) << hashLog;
|
{
|
||||||
size_t const ldmBucketSizeLog = MIN(bucketSizeLog, hashLog);
|
size_t const ldmHSize = ((size_t)1) << params.hashLog;
|
||||||
|
size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
|
||||||
size_t const ldmBucketSize =
|
size_t const ldmBucketSize =
|
||||||
((size_t)1) << (hashLog - ldmBucketSizeLog);
|
((size_t)1) << (params.hashLog - ldmBucketSizeLog);
|
||||||
return ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t)));
|
size_t const totalSize = ldmBucketSize + ldmHSize * sizeof(ldmEntry_t);
|
||||||
|
return params.enableLdm ? totalSize : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
|
||||||
|
{
|
||||||
|
return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ZSTD_ldm_getSmallHash() :
|
/** ZSTD_ldm_getSmallHash() :
|
||||||
@@ -167,6 +176,7 @@ static U64 ZSTD_ldm_ipow(U64 base, U64 exp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
U64 ZSTD_ldm_getHashPower(U32 minMatchLength) {
|
U64 ZSTD_ldm_getHashPower(U32 minMatchLength) {
|
||||||
|
DEBUGLOG(4, "ZSTD_ldm_getHashPower: mml=%u", minMatchLength);
|
||||||
assert(minMatchLength >= ZSTD_LDM_MINMATCH_MIN);
|
assert(minMatchLength >= ZSTD_LDM_MINMATCH_MIN);
|
||||||
return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1);
|
return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1);
|
||||||
}
|
}
|
||||||
@@ -205,21 +215,22 @@ static size_t ZSTD_ldm_countBackwardsMatch(
|
|||||||
*
|
*
|
||||||
* The tables for the other strategies are filled within their
|
* The tables for the other strategies are filled within their
|
||||||
* block compressors. */
|
* 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 BYTE* const iend = (const BYTE*)end;
|
||||||
const U32 mls = zc->appliedParams.cParams.searchLength;
|
|
||||||
|
|
||||||
switch(zc->appliedParams.cParams.strategy)
|
switch(cParams->strategy)
|
||||||
{
|
{
|
||||||
case ZSTD_fast:
|
case ZSTD_fast:
|
||||||
ZSTD_fillHashTable(zc, iend, mls);
|
ZSTD_fillHashTable(ms, cParams, iend);
|
||||||
zc->nextToUpdate = (U32)(iend - zc->base);
|
ms->nextToUpdate = (U32)(iend - ms->window.base);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSTD_dfast:
|
case ZSTD_dfast:
|
||||||
ZSTD_fillDoubleHashTable(zc, iend, mls);
|
ZSTD_fillDoubleHashTable(ms, cParams, iend);
|
||||||
zc->nextToUpdate = (U32)(iend - zc->base);
|
ms->nextToUpdate = (U32)(iend - ms->window.base);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSTD_greedy:
|
case ZSTD_greedy:
|
||||||
@@ -268,69 +279,62 @@ static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
|
|||||||
* Sets cctx->nextToUpdate to a position corresponding closer to anchor
|
* Sets cctx->nextToUpdate to a position corresponding closer to anchor
|
||||||
* if it is far way
|
* if it is far way
|
||||||
* (after a long match, only update tables a limited amount). */
|
* (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);
|
U32 const current = (U32)(anchor - ms->window.base);
|
||||||
if (current > cctx->nextToUpdate + 1024) {
|
if (current > ms->nextToUpdate + 1024) {
|
||||||
cctx->nextToUpdate =
|
ms->nextToUpdate =
|
||||||
current - MIN(512, current - cctx->nextToUpdate - 1024);
|
current - MIN(512, current - ms->nextToUpdate - 1024);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
static size_t ZSTD_ldm_generateSequences_internal(
|
||||||
/* defined in zstd_compress.c */
|
ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
|
||||||
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict);
|
ldmParams_t 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);
|
/* LDM parameters */
|
||||||
const ldmParams_t ldmParams = cctx->appliedParams.ldmParams;
|
int const extDict = ZSTD_window_hasExtDict(ldmState->window);
|
||||||
const U64 hashPower = ldmState->hashPower;
|
U32 const minMatchLength = params->minMatchLength;
|
||||||
const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
|
U64 const hashPower = ldmState->hashPower;
|
||||||
const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog);
|
U32 const hBits = params->hashLog - params->bucketSizeLog;
|
||||||
const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1;
|
U32 const ldmBucketSize = 1U << params->bucketSizeLog;
|
||||||
seqStore_t* const seqStorePtr = &(cctx->seqStore);
|
U32 const hashEveryLog = params->hashEveryLog;
|
||||||
const BYTE* const base = cctx->base;
|
U32 const ldmTagMask = (1U << params->hashEveryLog) - 1;
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
/* Prefix and extDict parameters */
|
||||||
const BYTE* ip = istart;
|
U32 const dictLimit = ldmState->window.dictLimit;
|
||||||
const BYTE* anchor = istart;
|
U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
|
||||||
const U32 lowestIndex = cctx->dictLimit;
|
BYTE const* const base = ldmState->window.base;
|
||||||
const BYTE* const lowest = base + lowestIndex;
|
BYTE const* const dictBase = extDict ? ldmState->window.dictBase : NULL;
|
||||||
const BYTE* const iend = istart + srcSize;
|
BYTE const* const dictStart = extDict ? dictBase + lowestIndex : NULL;
|
||||||
const BYTE* const ilimit = iend - MAX(ldmParams.minMatchLength, HASH_READ_SIZE);
|
BYTE const* const dictEnd = extDict ? dictBase + dictLimit : NULL;
|
||||||
|
BYTE const* const lowPrefixPtr = base + dictLimit;
|
||||||
const ZSTD_blockCompressor blockCompressor =
|
/* Input bounds */
|
||||||
ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0);
|
BYTE const* const istart = (BYTE const*)src;
|
||||||
U32* const repToConfirm = seqStorePtr->repToConfirm;
|
BYTE const* const iend = istart + srcSize;
|
||||||
U32 savedRep[ZSTD_REP_NUM];
|
BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
|
||||||
|
/* Input positions */
|
||||||
|
BYTE const* anchor = istart;
|
||||||
|
BYTE const* ip = istart;
|
||||||
|
/* Rolling hash */
|
||||||
|
BYTE const* lastHashed = NULL;
|
||||||
U64 rollingHash = 0;
|
U64 rollingHash = 0;
|
||||||
const BYTE* lastHashed = NULL;
|
|
||||||
size_t i, lastLiterals;
|
|
||||||
|
|
||||||
/* Save seqStorePtr->rep and copy repToConfirm */
|
while (ip <= ilimit) {
|
||||||
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;
|
size_t mLength;
|
||||||
U32 const current = (U32)(ip - base);
|
U32 const current = (U32)(ip - base);
|
||||||
size_t forwardMatchLength = 0, backwardMatchLength = 0;
|
size_t forwardMatchLength = 0, backwardMatchLength = 0;
|
||||||
ldmEntry_t* bestEntry = NULL;
|
ldmEntry_t* bestEntry = NULL;
|
||||||
if (ip != istart) {
|
if (ip != istart) {
|
||||||
rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0],
|
rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0],
|
||||||
lastHashed[ldmParams.minMatchLength],
|
lastHashed[minMatchLength],
|
||||||
hashPower);
|
hashPower);
|
||||||
} else {
|
} else {
|
||||||
rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength);
|
rollingHash = ZSTD_ldm_getRollingHash(ip, minMatchLength);
|
||||||
}
|
}
|
||||||
lastHashed = ip;
|
lastHashed = ip;
|
||||||
|
|
||||||
/* Do not insert and do not look for a match */
|
/* Do not insert and do not look for a match */
|
||||||
if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) !=
|
if (ZSTD_ldm_getTag(rollingHash, hBits, hashEveryLog) != ldmTagMask) {
|
||||||
ldmTagMask) {
|
|
||||||
ip++;
|
ip++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -340,27 +344,49 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
|
|||||||
ldmEntry_t* const bucket =
|
ldmEntry_t* const bucket =
|
||||||
ZSTD_ldm_getBucket(ldmState,
|
ZSTD_ldm_getBucket(ldmState,
|
||||||
ZSTD_ldm_getSmallHash(rollingHash, hBits),
|
ZSTD_ldm_getSmallHash(rollingHash, hBits),
|
||||||
ldmParams);
|
*params);
|
||||||
ldmEntry_t* cur;
|
ldmEntry_t* cur;
|
||||||
size_t bestMatchLength = 0;
|
size_t bestMatchLength = 0;
|
||||||
U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
||||||
|
|
||||||
for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
|
for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
|
||||||
const BYTE* const pMatch = cur->offset + base;
|
|
||||||
size_t curForwardMatchLength, curBackwardMatchLength,
|
size_t curForwardMatchLength, curBackwardMatchLength,
|
||||||
curTotalMatchLength;
|
curTotalMatchLength;
|
||||||
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
|
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (extDict) {
|
||||||
|
BYTE const* const curMatchBase =
|
||||||
|
cur->offset < dictLimit ? dictBase : base;
|
||||||
|
BYTE const* const pMatch = curMatchBase + cur->offset;
|
||||||
|
BYTE const* const matchEnd =
|
||||||
|
cur->offset < dictLimit ? dictEnd : iend;
|
||||||
|
BYTE const* const lowMatchPtr =
|
||||||
|
cur->offset < dictLimit ? dictStart : lowPrefixPtr;
|
||||||
|
|
||||||
curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
|
curForwardMatchLength = ZSTD_count_2segments(
|
||||||
if (curForwardMatchLength < ldmParams.minMatchLength) {
|
ip, pMatch, iend,
|
||||||
|
matchEnd, lowPrefixPtr);
|
||||||
|
if (curForwardMatchLength < minMatchLength) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch(
|
curBackwardMatchLength =
|
||||||
ip, anchor, pMatch, lowest);
|
ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
|
||||||
|
lowMatchPtr);
|
||||||
curTotalMatchLength = curForwardMatchLength +
|
curTotalMatchLength = curForwardMatchLength +
|
||||||
curBackwardMatchLength;
|
curBackwardMatchLength;
|
||||||
|
} else { /* !extDict */
|
||||||
|
BYTE const* const pMatch = base + cur->offset;
|
||||||
|
curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
|
||||||
|
if (curForwardMatchLength < minMatchLength) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
curBackwardMatchLength =
|
||||||
|
ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
|
||||||
|
lowPrefixPtr);
|
||||||
|
curTotalMatchLength = curForwardMatchLength +
|
||||||
|
curBackwardMatchLength;
|
||||||
|
}
|
||||||
|
|
||||||
if (curTotalMatchLength > bestMatchLength) {
|
if (curTotalMatchLength > bestMatchLength) {
|
||||||
bestMatchLength = curTotalMatchLength;
|
bestMatchLength = curTotalMatchLength;
|
||||||
@@ -375,7 +401,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
|
|||||||
if (bestEntry == NULL) {
|
if (bestEntry == NULL) {
|
||||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
|
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
|
||||||
hBits, current,
|
hBits, current,
|
||||||
ldmParams);
|
*params);
|
||||||
ip++;
|
ip++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -384,324 +410,244 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
|
|||||||
mLength = forwardMatchLength + backwardMatchLength;
|
mLength = forwardMatchLength + backwardMatchLength;
|
||||||
ip -= backwardMatchLength;
|
ip -= backwardMatchLength;
|
||||||
|
|
||||||
/* Call the block compressor on the remaining literals */
|
|
||||||
{
|
{
|
||||||
|
/* Store the sequence:
|
||||||
|
* ip = current - backwardMatchLength
|
||||||
|
* The match is at (bestEntry->offset - backwardMatchLength)
|
||||||
|
*/
|
||||||
U32 const matchIndex = bestEntry->offset;
|
U32 const matchIndex = bestEntry->offset;
|
||||||
const BYTE* const match = base + matchIndex - backwardMatchLength;
|
U32 const offset = current - matchIndex;
|
||||||
U32 const offset = (U32)(ip - match);
|
rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
|
||||||
|
|
||||||
/* Overwrite rep codes */
|
/* Out of sequence storage */
|
||||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
if (rawSeqStore->size == rawSeqStore->capacity)
|
||||||
seqStorePtr->rep[i] = repToConfirm[i];
|
return ERROR(dstSize_tooSmall);
|
||||||
|
seq->litLength = (U32)(ip - anchor);
|
||||||
/* Fill tables for block compressor */
|
seq->matchLength = (U32)mLength;
|
||||||
ZSTD_ldm_limitTableUpdate(cctx, anchor);
|
seq->offset = offset;
|
||||||
ZSTD_ldm_fillFastTables(cctx, anchor);
|
rawSeqStore->size++;
|
||||||
|
|
||||||
/* Call block compressor and get remaining literals */
|
|
||||||
lastLiterals = blockCompressor(cctx, anchor, ip - anchor);
|
|
||||||
cctx->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;
|
|
||||||
|
|
||||||
/* Store the sequence with the leftover literals */
|
|
||||||
ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals,
|
|
||||||
offset + ZSTD_REP_MOVE, mLength - MINMATCH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the current entry into the hash table */
|
/* Insert the current entry into the hash table */
|
||||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
|
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
|
||||||
(U32)(lastHashed - base),
|
(U32)(lastHashed - base),
|
||||||
ldmParams);
|
*params);
|
||||||
|
|
||||||
assert(ip + backwardMatchLength == lastHashed);
|
assert(ip + backwardMatchLength == lastHashed);
|
||||||
|
|
||||||
/* Fill the hash table from lastHashed+1 to ip+mLength*/
|
/* Fill the hash table from lastHashed+1 to ip+mLength*/
|
||||||
/* Heuristic: don't need to fill the entire table at end of block */
|
/* Heuristic: don't need to fill the entire table at end of block */
|
||||||
if (ip + mLength < ilimit) {
|
if (ip + mLength <= ilimit) {
|
||||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
||||||
ldmState, rollingHash, lastHashed,
|
ldmState, rollingHash, lastHashed,
|
||||||
ip + mLength, base, hBits, ldmParams);
|
ip + mLength, base, hBits, *params);
|
||||||
lastHashed = ip + mLength - 1;
|
lastHashed = ip + mLength - 1;
|
||||||
}
|
}
|
||||||
ip += mLength;
|
ip += mLength;
|
||||||
anchor = ip;
|
anchor = ip;
|
||||||
/* Check immediate repcode */
|
}
|
||||||
while ( (ip < ilimit)
|
return iend - anchor;
|
||||||
&& ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest))
|
}
|
||||||
&& (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) {
|
|
||||||
|
|
||||||
size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1],
|
/*! ZSTD_ldm_reduceTable() :
|
||||||
iend) + 4;
|
* reduce table indexes by `reducerValue` */
|
||||||
/* Swap repToConfirm[1] <=> repToConfirm[0] */
|
static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
|
||||||
|
U32 const reducerValue)
|
||||||
{
|
{
|
||||||
U32 const tmpOff = repToConfirm[1];
|
U32 u;
|
||||||
repToConfirm[1] = repToConfirm[0];
|
for (u = 0; u < size; u++) {
|
||||||
repToConfirm[0] = tmpOff;
|
if (table[u].offset < reducerValue) table[u].offset = 0;
|
||||||
}
|
else table[u].offset -= reducerValue;
|
||||||
|
|
||||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
|
|
||||||
|
|
||||||
/* Fill the hash table from lastHashed+1 to ip+rLength*/
|
|
||||||
if (ip + rLength < ilimit) {
|
|
||||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
|
||||||
ldmState, rollingHash, lastHashed,
|
|
||||||
ip + rLength, base, hBits, ldmParams);
|
|
||||||
lastHashed = ip + rLength - 1;
|
|
||||||
}
|
|
||||||
ip += rLength;
|
|
||||||
anchor = ip;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overwrite rep */
|
size_t ZSTD_ldm_generateSequences(
|
||||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
ldmState_t* ldmState, rawSeqStore_t* sequences,
|
||||||
seqStorePtr->rep[i] = repToConfirm[i];
|
ldmParams_t const* params, void const* src, size_t srcSize)
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
/* Return the last literals size */
|
|
||||||
return lastLiterals;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* ctx,
|
|
||||||
const void* src, size_t srcSize)
|
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_ldm_generic(ctx, src, srcSize);
|
U32 const maxDist = 1U << params->windowLog;
|
||||||
|
BYTE const* const istart = (BYTE const*)src;
|
||||||
|
BYTE const* const iend = istart + srcSize;
|
||||||
|
size_t const kMaxChunkSize = 1 << 20;
|
||||||
|
size_t const nbChunks = (srcSize / kMaxChunkSize) + ((srcSize % kMaxChunkSize) != 0);
|
||||||
|
size_t chunk;
|
||||||
|
size_t leftoverSize = 0;
|
||||||
|
|
||||||
|
assert(ZSTD_CHUNKSIZE_MAX >= kMaxChunkSize);
|
||||||
|
/* Check that ZSTD_window_update() has been called for this chunk prior
|
||||||
|
* to passing it to this function.
|
||||||
|
*/
|
||||||
|
assert(ldmState->window.nextSrc >= (BYTE const*)src + srcSize);
|
||||||
|
/* The input could be very large (in zstdmt), so it must be broken up into
|
||||||
|
* chunks to enforce the maximmum distance and handle overflow correction.
|
||||||
|
*/
|
||||||
|
assert(sequences->pos <= sequences->size);
|
||||||
|
assert(sequences->size <= sequences->capacity);
|
||||||
|
for (chunk = 0; chunk < nbChunks && sequences->size < sequences->capacity; ++chunk) {
|
||||||
|
BYTE const* const chunkStart = istart + chunk * kMaxChunkSize;
|
||||||
|
size_t const remaining = (size_t)(iend - chunkStart);
|
||||||
|
BYTE const *const chunkEnd =
|
||||||
|
(remaining < kMaxChunkSize) ? iend : chunkStart + kMaxChunkSize;
|
||||||
|
size_t const chunkSize = chunkEnd - chunkStart;
|
||||||
|
size_t newLeftoverSize;
|
||||||
|
size_t const prevSize = sequences->size;
|
||||||
|
|
||||||
|
assert(chunkStart < iend);
|
||||||
|
/* 1. Perform overflow correction if necessary. */
|
||||||
|
if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
|
||||||
|
U32 const ldmHSize = 1U << params->hashLog;
|
||||||
|
U32 const correction = ZSTD_window_correctOverflow(
|
||||||
|
&ldmState->window, /* cycleLog */ 0, maxDist, src);
|
||||||
|
ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction);
|
||||||
}
|
}
|
||||||
|
/* 2. We enforce the maximum offset allowed.
|
||||||
static size_t ZSTD_compressBlock_ldm_extDict_generic(
|
*
|
||||||
ZSTD_CCtx* ctx,
|
* kMaxChunkSize should be small enough that we don't lose too much of
|
||||||
const void* src, size_t srcSize)
|
* the window through early invalidation.
|
||||||
{
|
* TODO: * Test the chunk size.
|
||||||
ldmState_t* const ldmState = &(ctx->ldmState);
|
* * Try invalidation after the sequence generation and test the
|
||||||
const ldmParams_t ldmParams = ctx->appliedParams.ldmParams;
|
* the offset against maxDist directly.
|
||||||
const U64 hashPower = ldmState->hashPower;
|
*/
|
||||||
const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
|
ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL);
|
||||||
const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog);
|
/* 3. Generate the sequences for the chunk, and get newLeftoverSize. */
|
||||||
const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1;
|
newLeftoverSize = ZSTD_ldm_generateSequences_internal(
|
||||||
seqStore_t* const seqStorePtr = &(ctx->seqStore);
|
ldmState, sequences, params, chunkStart, chunkSize);
|
||||||
const BYTE* const base = ctx->base;
|
if (ZSTD_isError(newLeftoverSize))
|
||||||
const BYTE* const dictBase = ctx->dictBase;
|
return newLeftoverSize;
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
/* 4. We add the leftover literals from previous iterations to the first
|
||||||
const BYTE* ip = istart;
|
* newly generated sequence, or add the `newLeftoverSize` if none are
|
||||||
const BYTE* anchor = istart;
|
* generated.
|
||||||
const U32 lowestIndex = ctx->lowLimit;
|
*/
|
||||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
/* Prepend the leftover literals from the last call */
|
||||||
const U32 dictLimit = ctx->dictLimit;
|
if (prevSize < sequences->size) {
|
||||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
sequences->seq[prevSize].litLength += (U32)leftoverSize;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
leftoverSize = newLeftoverSize;
|
||||||
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];
|
|
||||||
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;
|
|
||||||
const U32 current = (U32)(ip-base);
|
|
||||||
size_t forwardMatchLength = 0, backwardMatchLength = 0;
|
|
||||||
ldmEntry_t* bestEntry = NULL;
|
|
||||||
if (ip != istart) {
|
|
||||||
rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0],
|
|
||||||
lastHashed[ldmParams.minMatchLength],
|
|
||||||
hashPower);
|
|
||||||
} else {
|
} else {
|
||||||
rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength);
|
assert(newLeftoverSize == chunkSize);
|
||||||
|
leftoverSize += chunkSize;
|
||||||
}
|
}
|
||||||
lastHashed = ip;
|
}
|
||||||
|
return 0;
|
||||||
if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) !=
|
|
||||||
ldmTagMask) {
|
|
||||||
/* Don't insert and don't look for a match */
|
|
||||||
ip++;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the best entry and compute the match lengths */
|
void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) {
|
||||||
|
while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
|
||||||
|
rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
|
||||||
|
if (srcSize <= seq->litLength) {
|
||||||
|
/* Skip past srcSize literals */
|
||||||
|
seq->litLength -= (U32)srcSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
srcSize -= seq->litLength;
|
||||||
|
seq->litLength = 0;
|
||||||
|
if (srcSize < seq->matchLength) {
|
||||||
|
/* Skip past the first srcSize of the match */
|
||||||
|
seq->matchLength -= (U32)srcSize;
|
||||||
|
if (seq->matchLength < minMatch) {
|
||||||
|
/* The match is too short, omit it */
|
||||||
|
if (rawSeqStore->pos + 1 < rawSeqStore->size) {
|
||||||
|
seq[1].litLength += seq[0].matchLength;
|
||||||
|
}
|
||||||
|
rawSeqStore->pos++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
srcSize -= seq->matchLength;
|
||||||
|
seq->matchLength = 0;
|
||||||
|
rawSeqStore->pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the sequence length is longer than remaining then the sequence is split
|
||||||
|
* between this block and the next.
|
||||||
|
*
|
||||||
|
* Returns the current sequence to handle, or if the rest of the block should
|
||||||
|
* be literals, it returns a sequence with offset == 0.
|
||||||
|
*/
|
||||||
|
static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
|
||||||
|
U32 const remaining, U32 const minMatch)
|
||||||
{
|
{
|
||||||
ldmEntry_t* const bucket =
|
rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
|
||||||
ZSTD_ldm_getBucket(ldmState,
|
assert(sequence.offset > 0);
|
||||||
ZSTD_ldm_getSmallHash(rollingHash, hBits),
|
/* Likely: No partial sequence */
|
||||||
ldmParams);
|
if (remaining >= sequence.litLength + sequence.matchLength) {
|
||||||
ldmEntry_t* cur;
|
rawSeqStore->pos++;
|
||||||
size_t bestMatchLength = 0;
|
return sequence;
|
||||||
U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
|
||||||
|
|
||||||
for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
|
|
||||||
const BYTE* const curMatchBase =
|
|
||||||
cur->offset < dictLimit ? dictBase : base;
|
|
||||||
const BYTE* const pMatch = curMatchBase + cur->offset;
|
|
||||||
const BYTE* const matchEnd =
|
|
||||||
cur->offset < dictLimit ? dictEnd : iend;
|
|
||||||
const BYTE* const lowMatchPtr =
|
|
||||||
cur->offset < dictLimit ? dictStart : lowPrefixPtr;
|
|
||||||
size_t curForwardMatchLength, curBackwardMatchLength,
|
|
||||||
curTotalMatchLength;
|
|
||||||
|
|
||||||
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
/* Cut the sequence short (offset == 0 ==> rest is literals). */
|
||||||
curForwardMatchLength = ZSTD_count_2segments(
|
if (remaining <= sequence.litLength) {
|
||||||
ip, pMatch, iend,
|
sequence.offset = 0;
|
||||||
matchEnd, lowPrefixPtr);
|
} else if (remaining < sequence.litLength + sequence.matchLength) {
|
||||||
if (curForwardMatchLength < ldmParams.minMatchLength) {
|
sequence.matchLength = remaining - sequence.litLength;
|
||||||
continue;
|
if (sequence.matchLength < minMatch) {
|
||||||
}
|
sequence.offset = 0;
|
||||||
curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch(
|
|
||||||
ip, anchor, pMatch, lowMatchPtr);
|
|
||||||
curTotalMatchLength = curForwardMatchLength +
|
|
||||||
curBackwardMatchLength;
|
|
||||||
|
|
||||||
if (curTotalMatchLength > bestMatchLength) {
|
|
||||||
bestMatchLength = curTotalMatchLength;
|
|
||||||
forwardMatchLength = curForwardMatchLength;
|
|
||||||
backwardMatchLength = curBackwardMatchLength;
|
|
||||||
bestEntry = cur;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Skip past `remaining` bytes for the future sequences. */
|
||||||
|
ZSTD_ldm_skipSequences(rawSeqStore, remaining, minMatch);
|
||||||
|
return sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No match found -- continue searching */
|
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||||
if (bestEntry == NULL) {
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
|
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
|
||||||
(U32)(lastHashed - base),
|
int const extDict)
|
||||||
ldmParams);
|
|
||||||
ip++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Match found */
|
|
||||||
mLength = forwardMatchLength + backwardMatchLength;
|
|
||||||
ip -= backwardMatchLength;
|
|
||||||
|
|
||||||
/* Call the block compressor on the remaining literals */
|
|
||||||
{
|
{
|
||||||
/* ip = current - backwardMatchLength
|
unsigned const minMatch = cParams->searchLength;
|
||||||
* The match is at (bestEntry->offset - backwardMatchLength) */
|
ZSTD_blockCompressor const blockCompressor =
|
||||||
U32 const matchIndex = bestEntry->offset;
|
ZSTD_selectBlockCompressor(cParams->strategy, extDict);
|
||||||
U32 const offset = current - matchIndex;
|
BYTE const* const base = ms->window.base;
|
||||||
|
/* Input bounds */
|
||||||
|
BYTE const* const istart = (BYTE const*)src;
|
||||||
|
BYTE const* const iend = istart + srcSize;
|
||||||
|
/* Input positions */
|
||||||
|
BYTE const* ip = istart;
|
||||||
|
|
||||||
/* Overwrite rep codes */
|
assert(rawSeqStore->pos <= rawSeqStore->size);
|
||||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
assert(rawSeqStore->size <= rawSeqStore->capacity);
|
||||||
seqStorePtr->rep[i] = repToConfirm[i];
|
/* Loop through each sequence and apply the block compressor to the lits */
|
||||||
|
while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
|
||||||
/* Fill the hash table for the block compressor */
|
/* maybeSplitSequence updates rawSeqStore->pos */
|
||||||
ZSTD_ldm_limitTableUpdate(ctx, anchor);
|
rawSeq const sequence = maybeSplitSequence(rawSeqStore,
|
||||||
ZSTD_ldm_fillFastTables(ctx, anchor);
|
(U32)(iend - ip), minMatch);
|
||||||
|
int i;
|
||||||
/* Call block compressor and get remaining literals */
|
/* End signal */
|
||||||
lastLiterals = blockCompressor(ctx, anchor, ip - anchor);
|
if (sequence.offset == 0)
|
||||||
ctx->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;
|
|
||||||
|
|
||||||
/* Store the sequence with the leftover literals */
|
|
||||||
ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals,
|
|
||||||
offset + ZSTD_REP_MOVE, mLength - MINMATCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert the current entry into the hash table */
|
|
||||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
|
|
||||||
(U32)(lastHashed - base),
|
|
||||||
ldmParams);
|
|
||||||
|
|
||||||
/* Fill the hash table from lastHashed+1 to ip+mLength */
|
|
||||||
assert(ip + backwardMatchLength == lastHashed);
|
|
||||||
if (ip + mLength < ilimit) {
|
|
||||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
|
||||||
ldmState, rollingHash, lastHashed,
|
|
||||||
ip + mLength, base, hBits,
|
|
||||||
ldmParams);
|
|
||||||
lastHashed = ip + mLength - 1;
|
|
||||||
}
|
|
||||||
ip += mLength;
|
|
||||||
anchor = ip;
|
|
||||||
|
|
||||||
/* check immediate repcode */
|
|
||||||
while (ip < ilimit) {
|
|
||||||
U32 const current2 = (U32)(ip-base);
|
|
||||||
U32 const repIndex2 = current2 - repToConfirm[1];
|
|
||||||
const BYTE* repMatch2 = repIndex2 < dictLimit ?
|
|
||||||
dictBase + repIndex2 : base + repIndex2;
|
|
||||||
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) &
|
|
||||||
(repIndex2 > lowestIndex)) /* intentional overflow */
|
|
||||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
|
||||||
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 = repToConfirm[1];
|
|
||||||
repToConfirm[1] = repToConfirm[0];
|
|
||||||
repToConfirm[0] = tmpOffset;
|
|
||||||
|
|
||||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
|
|
||||||
|
|
||||||
/* Fill the hash table from lastHashed+1 to ip+repLength2*/
|
|
||||||
if (ip + repLength2 < ilimit) {
|
|
||||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
|
||||||
ldmState, rollingHash, lastHashed,
|
|
||||||
ip + repLength2, base, hBits,
|
|
||||||
ldmParams);
|
|
||||||
lastHashed = ip + repLength2 - 1;
|
|
||||||
}
|
|
||||||
ip += repLength2;
|
|
||||||
anchor = ip;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
assert(sequence.offset <= (1U << cParams->windowLog));
|
||||||
|
assert(ip + sequence.litLength + sequence.matchLength <= iend);
|
||||||
|
|
||||||
|
/* Fill tables for block compressor */
|
||||||
|
ZSTD_ldm_limitTableUpdate(ms, ip);
|
||||||
|
ZSTD_ldm_fillFastTables(ms, cParams, ip);
|
||||||
|
/* Run the block compressor */
|
||||||
|
{
|
||||||
|
size_t const newLitLength =
|
||||||
|
blockCompressor(ms, seqStore, rep, cParams, ip,
|
||||||
|
sequence.litLength);
|
||||||
|
ip += sequence.litLength;
|
||||||
|
ms->nextToUpdate = (U32)(ip - base);
|
||||||
|
/* Update the repcodes */
|
||||||
|
for (i = ZSTD_REP_NUM - 1; i > 0; i--)
|
||||||
|
rep[i] = rep[i-1];
|
||||||
|
rep[0] = sequence.offset;
|
||||||
|
/* Store the sequence */
|
||||||
|
ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength,
|
||||||
|
sequence.offset + ZSTD_REP_MOVE,
|
||||||
|
sequence.matchLength - MINMATCH);
|
||||||
|
ip += sequence.matchLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Fill the tables for the block compressor */
|
||||||
/* Overwrite rep */
|
ZSTD_ldm_limitTableUpdate(ms, ip);
|
||||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
ZSTD_ldm_fillFastTables(ms, cParams, ip);
|
||||||
seqStorePtr->rep[i] = repToConfirm[i];
|
/* Compress the last literals */
|
||||||
|
{
|
||||||
ZSTD_ldm_limitTableUpdate(ctx, anchor);
|
size_t const lastLiterals = blockCompressor(ms, seqStore, rep, cParams,
|
||||||
ZSTD_ldm_fillFastTables(ctx, anchor);
|
ip, iend - ip);
|
||||||
|
ms->nextToUpdate = (U32)(iend - base);
|
||||||
/* 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];
|
|
||||||
|
|
||||||
/* Return the last literals size */
|
|
||||||
return lastLiterals;
|
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,32 +22,71 @@ extern "C" {
|
|||||||
***************************************/
|
***************************************/
|
||||||
|
|
||||||
#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_DEFAULTMAX
|
#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_DEFAULTMAX
|
||||||
#define ZSTD_LDM_HASHEVERYLOG_NOTSET 9999
|
|
||||||
|
|
||||||
/** ZSTD_compressBlock_ldm_generic() :
|
/**
|
||||||
|
* ZSTD_ldm_generateSequences():
|
||||||
*
|
*
|
||||||
* This is a block compressor intended for long distance matching.
|
* Generates the sequences using the long distance match finder.
|
||||||
|
* Generates long range matching sequences in `sequences`, which parse a prefix
|
||||||
|
* of the source. `sequences` must be large enough to store every sequence,
|
||||||
|
* which can be checked with `ZSTD_ldm_getMaxNbSeq()`.
|
||||||
|
* @returns 0 or an error code.
|
||||||
*
|
*
|
||||||
* The function searches for matches of length at least
|
* NOTE: The user must have called ZSTD_window_update() for all of the input
|
||||||
* ldmParams.minMatchLength using a hash table in cctx->ldmState.
|
* they have, even if they pass it to ZSTD_ldm_generateSequences() in chunks.
|
||||||
* Matches can be at a distance of up to cParams.windowLog.
|
* NOTE: This function returns an error if it runs out of space to store
|
||||||
|
* sequences.
|
||||||
|
*/
|
||||||
|
size_t ZSTD_ldm_generateSequences(
|
||||||
|
ldmState_t* ldms, rawSeqStore_t* sequences,
|
||||||
|
ldmParams_t const* params, void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_ldm_blockCompress():
|
||||||
*
|
*
|
||||||
* Upon finding a match, the unmatched literals are compressed using a
|
* Compresses a block using the predefined sequences, along with a secondary
|
||||||
* ZSTD_blockCompressor (depending on the strategy in the compression
|
* block compressor. The literals section of every sequence is passed to the
|
||||||
* parameters), which stores the matched sequences. The "long distance"
|
* secondary block compressor, and those sequences are interspersed with the
|
||||||
* match is then stored with the remaining literals from the
|
* predefined sequences. Returns the length of the last literals.
|
||||||
* ZSTD_blockCompressor. */
|
* Updates `rawSeqStore.pos` to indicate how many sequences have been consumed.
|
||||||
size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* cctx, const void* src, size_t srcSize);
|
* `rawSeqStore.seq` may also be updated to split the last sequence between two
|
||||||
size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx,
|
* blocks.
|
||||||
const void* src, size_t srcSize);
|
* @return The length of the last literals.
|
||||||
|
*
|
||||||
|
* NOTE: The source must be at most the maximum block size, but the predefined
|
||||||
|
* sequences can be any size, and may be longer than the block. In the case that
|
||||||
|
* they are longer than the block, the last sequences may need to be split into
|
||||||
|
* two. We handle that case correctly, and update `rawSeqStore` appropriately.
|
||||||
|
* NOTE: This function does not return any errors.
|
||||||
|
*/
|
||||||
|
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||||
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
ZSTD_compressionParameters const* cParams,
|
||||||
|
void const* src, size_t srcSize,
|
||||||
|
int const extDict);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZSTD_ldm_skipSequences():
|
||||||
|
*
|
||||||
|
* Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
|
||||||
|
* Avoids emitting matches less than `minMatch` bytes.
|
||||||
|
* Must be called for data with is not passed to ZSTD_ldm_blockCompress().
|
||||||
|
*/
|
||||||
|
void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
|
||||||
|
U32 const minMatch);
|
||||||
|
|
||||||
/** ZSTD_ldm_initializeParameters() :
|
|
||||||
* Initialize the long distance matching parameters to their default values. */
|
|
||||||
size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm);
|
|
||||||
|
|
||||||
/** ZSTD_ldm_getTableSize() :
|
/** ZSTD_ldm_getTableSize() :
|
||||||
* Estimate the space needed for long distance matching tables. */
|
* Estimate the space needed for long distance matching tables or 0 if LDM is
|
||||||
size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog);
|
* disabled.
|
||||||
|
*/
|
||||||
|
size_t ZSTD_ldm_getTableSize(ldmParams_t params);
|
||||||
|
|
||||||
|
/** ZSTD_ldm_getSeqSpace() :
|
||||||
|
* Return an upper bound on the number of sequences that can be produced by
|
||||||
|
* the long distance matcher, or 0 if LDM is disabled.
|
||||||
|
*/
|
||||||
|
size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize);
|
||||||
|
|
||||||
/** ZSTD_ldm_getTableSize() :
|
/** ZSTD_ldm_getTableSize() :
|
||||||
* Return prime8bytes^(minMatchLength-1) */
|
* Return prime8bytes^(minMatchLength-1) */
|
||||||
@@ -58,8 +97,12 @@ U64 ZSTD_ldm_getHashPower(U32 minMatchLength);
|
|||||||
* windowLog and params->hashLog.
|
* windowLog and params->hashLog.
|
||||||
*
|
*
|
||||||
* Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
|
* Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
|
||||||
* params->hashLog if it is not). */
|
* params->hashLog if it is not).
|
||||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog);
|
*
|
||||||
|
* Ensures that the minMatchLength >= targetLength during optimal parsing.
|
||||||
|
*/
|
||||||
|
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
||||||
|
ZSTD_compressionParameters const* cParams);
|
||||||
|
|
||||||
#if defined (__cplusplus)
|
#if defined (__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "zstd_compress_internal.h"
|
#include "zstd_compress_internal.h"
|
||||||
#include "zstd_opt.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 (?) */
|
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats. Also used for matchSum (?) */
|
||||||
@@ -244,14 +243,15 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
|
|||||||
|
|
||||||
/* Update hashTable3 up to ip (excluded)
|
/* Update hashTable3 up to ip (excluded)
|
||||||
Assumption : always within prefix (i.e. not within extDict) */
|
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 hashTable3 = ms->hashTable3;
|
||||||
U32 const hashLog3 = cctx->hashLog3;
|
U32 const hashLog3 = ms->hashLog3;
|
||||||
const BYTE* const base = cctx->base;
|
const BYTE* const base = ms->window.base;
|
||||||
U32 idx = cctx->nextToUpdate3;
|
U32 idx = ms->nextToUpdate3;
|
||||||
U32 const target = cctx->nextToUpdate3 = (U32)(ip - base);
|
U32 const target = ms->nextToUpdate3 = (U32)(ip - base);
|
||||||
size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
|
size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
|
||||||
|
assert(hashLog3 > 0);
|
||||||
|
|
||||||
while(idx < target) {
|
while(idx < target) {
|
||||||
hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
|
hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
|
||||||
@@ -265,36 +265,173 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* const cctx, const BYTE*
|
|||||||
/*-*************************************
|
/*-*************************************
|
||||||
* Binary Tree search
|
* 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_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
|
const BYTE* const ip, const BYTE* const iend,
|
||||||
|
U32 const mls, U32 const extDict)
|
||||||
|
{
|
||||||
|
U32* const hashTable = ms->hashTable;
|
||||||
|
U32 const hashLog = cParams->hashLog;
|
||||||
|
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||||
|
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 = ms->window.base;
|
||||||
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
|
const U32 dictLimit = ms->window.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 = ms->window.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);
|
||||||
|
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_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
|
const BYTE* const ip, const BYTE* const iend,
|
||||||
|
const U32 mls, const U32 extDict)
|
||||||
|
{
|
||||||
|
const BYTE* const base = ms->window.base;
|
||||||
|
U32 const target = (U32)(ip - base);
|
||||||
|
U32 idx = ms->nextToUpdate;
|
||||||
|
DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (extDict:%u)",
|
||||||
|
idx, target, extDict);
|
||||||
|
|
||||||
|
while(idx < target)
|
||||||
|
idx += ZSTD_insertBt1(ms, cParams, base+idx, iend, mls, extDict);
|
||||||
|
ms->nextToUpdate = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSTD_updateTree(
|
||||||
|
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
|
const BYTE* ip, const BYTE* iend)
|
||||||
|
{
|
||||||
|
ZSTD_updateTree_internal(ms, cParams, ip, iend, cParams->searchLength, 0 /*extDict*/);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
U32 ZSTD_insertBtAndGetAllMatches (
|
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,
|
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,
|
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->window.base;
|
||||||
U32 const current = (U32)(ip-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 minMatch = (mls==3) ? 3 : 4;
|
||||||
U32* const hashTable = zc->hashTable;
|
U32* const hashTable = ms->hashTable;
|
||||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||||
U32 matchIndex = hashTable[h];
|
U32 matchIndex = hashTable[h];
|
||||||
U32* const bt = zc->chainTable;
|
U32* const bt = ms->chainTable;
|
||||||
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
|
U32 const btLog = cParams->chainLog - 1;
|
||||||
U32 const btMask= (1U << btLog) - 1;
|
U32 const btMask= (1U << btLog) - 1;
|
||||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||||
const BYTE* const dictBase = zc->dictBase;
|
const BYTE* const dictBase = ms->window.dictBase;
|
||||||
U32 const dictLimit = zc->dictLimit;
|
U32 const dictLimit = ms->window.dictLimit;
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const BYTE* const prefixStart = base + dictLimit;
|
const BYTE* const prefixStart = base + dictLimit;
|
||||||
U32 const btLow = btMask >= current ? 0 : current - btMask;
|
U32 const btLow = btMask >= current ? 0 : current - btMask;
|
||||||
U32 const windowLow = zc->lowLimit;
|
U32 const windowLow = ms->window.lowLimit;
|
||||||
U32* smallerPtr = bt + 2*(current&btMask);
|
U32* smallerPtr = bt + 2*(current&btMask);
|
||||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||||
U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */
|
U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */
|
||||||
U32 dummy32; /* to be nullified at the end */
|
U32 dummy32; /* to be nullified at the end */
|
||||||
U32 mnum = 0;
|
U32 mnum = 0;
|
||||||
|
U32 nbCompares = 1U << cParams->searchLog;
|
||||||
|
|
||||||
size_t bestLength = lengthToBeat-1;
|
size_t bestLength = lengthToBeat-1;
|
||||||
DEBUGLOG(7, "ZSTD_insertBtAndGetAllMatches");
|
DEBUGLOG(7, "ZSTD_insertBtAndGetAllMatches");
|
||||||
@@ -335,7 +472,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|||||||
|
|
||||||
/* HC3 match finder */
|
/* HC3 match finder */
|
||||||
if ((mls == 3) /*static*/ && (bestLength < mls)) {
|
if ((mls == 3) /*static*/ && (bestLength < mls)) {
|
||||||
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
|
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip);
|
||||||
if ((matchIndex3 > windowLow)
|
if ((matchIndex3 > windowLow)
|
||||||
& (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
|
& (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
|
||||||
size_t mlen;
|
size_t mlen;
|
||||||
@@ -359,7 +496,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|||||||
mnum = 1;
|
mnum = 1;
|
||||||
if ( (mlen > sufficient_len) |
|
if ( (mlen > sufficient_len) |
|
||||||
(ip+mlen == iLimit) ) { /* best possible length */
|
(ip+mlen == iLimit) ) { /* best possible length */
|
||||||
zc->nextToUpdate = current+1; /* skip insertion */
|
ms->nextToUpdate = current+1; /* skip insertion */
|
||||||
return 1;
|
return 1;
|
||||||
} } } }
|
} } } }
|
||||||
|
|
||||||
@@ -416,30 +553,29 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|||||||
*smallerPtr = *largerPtr = 0;
|
*smallerPtr = *largerPtr = 0;
|
||||||
|
|
||||||
assert(matchEndIdx > current+8);
|
assert(matchEndIdx > current+8);
|
||||||
zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
|
ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
|
||||||
return mnum;
|
return mnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
|
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,
|
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,
|
U32 rep[ZSTD_REP_NUM], U32 const ll0,
|
||||||
ZSTD_match_t* matches, U32 const lengthToBeat)
|
ZSTD_match_t* matches, U32 const lengthToBeat)
|
||||||
{
|
{
|
||||||
|
U32 const matchLengthSearch = cParams->searchLength;
|
||||||
DEBUGLOG(7, "ZSTD_BtGetAllMatches");
|
DEBUGLOG(7, "ZSTD_BtGetAllMatches");
|
||||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
|
||||||
if (extDict) ZSTD_updateTree_extDict(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
|
ZSTD_updateTree_internal(ms, cParams, ip, iHighLimit, matchLengthSearch, extDict);
|
||||||
else ZSTD_updateTree(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
|
|
||||||
switch(matchLengthSearch)
|
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 :
|
default :
|
||||||
case 4 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 4, 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(zc, ip, iHighLimit, extDict, maxNbAttempts, 5, sufficient_len, rep, ll0, matches, lengthToBeat);
|
case 5 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 5);
|
||||||
case 7 :
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,36 +663,33 @@ static int ZSTD_literalsContribution_cached(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE
|
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 void* src, size_t srcSize,
|
||||||
const int optLevel, const int extDict)
|
const int optLevel, const int extDict)
|
||||||
{
|
{
|
||||||
seqStore_t* const seqStorePtr = &(ctx->seqStore);
|
optState_t* const optStatePtr = &ms->opt;
|
||||||
optState_t* const optStatePtr = &(ctx->optState);
|
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - 8;
|
const BYTE* const ilimit = iend - 8;
|
||||||
const BYTE* const base = ctx->base;
|
const BYTE* const base = ms->window.base;
|
||||||
const BYTE* const prefixStart = base + ctx->dictLimit;
|
const BYTE* const prefixStart = base + ms->window.dictLimit;
|
||||||
|
|
||||||
U32 const maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
|
U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
|
||||||
U32 const sufficient_len = MIN(ctx->appliedParams.cParams.targetLength, ZSTD_OPT_NUM -1);
|
U32 const minMatch = (cParams->searchLength == 3) ? 3 : 4;
|
||||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
|
||||||
U32 const minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
|
|
||||||
|
|
||||||
ZSTD_optimal_t* const opt = optStatePtr->priceTable;
|
ZSTD_optimal_t* const opt = optStatePtr->priceTable;
|
||||||
ZSTD_match_t* const matches = optStatePtr->matchTable;
|
ZSTD_match_t* const matches = optStatePtr->matchTable;
|
||||||
cachedLiteralPrice_t cachedLitPrice;
|
cachedLiteralPrice_t cachedLitPrice;
|
||||||
U32 rep[ZSTD_REP_NUM];
|
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
|
DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
|
||||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
ms->nextToUpdate3 = ms->nextToUpdate;
|
||||||
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
|
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
|
||||||
ip += (ip==prefixStart);
|
ip += (ip==prefixStart);
|
||||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
|
|
||||||
memset(&cachedLitPrice, 0, sizeof(cachedLitPrice));
|
memset(&cachedLitPrice, 0, sizeof(cachedLitPrice));
|
||||||
|
|
||||||
/* Match Loop */
|
/* Match Loop */
|
||||||
@@ -567,7 +700,7 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
|||||||
/* find first match */
|
/* find first match */
|
||||||
{ U32 const litlen = (U32)(ip - anchor);
|
{ U32 const litlen = (U32)(ip - anchor);
|
||||||
U32 const ll0 = !litlen;
|
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; }
|
if (!nbMatches) { ip++; continue; }
|
||||||
|
|
||||||
/* initialize opt[0] */
|
/* initialize opt[0] */
|
||||||
@@ -653,7 +786,7 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
|||||||
U32 const litlen = (opt[cur].mlen == 1) ? opt[cur].litlen : 0;
|
U32 const litlen = (opt[cur].mlen == 1) ? opt[cur].litlen : 0;
|
||||||
U32 const previousPrice = (cur > litlen) ? opt[cur-litlen].price : 0;
|
U32 const previousPrice = (cur > litlen) ? opt[cur-litlen].price : 0;
|
||||||
U32 const basePrice = previousPrice + ZSTD_fullLiteralsCost(inr-litlen, litlen, optStatePtr);
|
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;
|
U32 matchNb;
|
||||||
if (!nbMatches) continue;
|
if (!nbMatches) continue;
|
||||||
|
|
||||||
@@ -749,37 +882,42 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_updateStats(optStatePtr, llen, anchor, offset, mlen);
|
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;
|
anchor = ip;
|
||||||
} }
|
} }
|
||||||
ZSTD_setLog2Prices(optStatePtr);
|
ZSTD_setLog2Prices(optStatePtr);
|
||||||
} /* while (ip < ilimit) */
|
} /* while (ip < ilimit) */
|
||||||
|
|
||||||
/* Save reps for next block */
|
|
||||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
|
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return iend - anchor;
|
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");
|
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*/);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,25 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "zstd.h" /* ZSTD_CCtx, size_t */
|
#include "zstd_compress_internal.h"
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
void ZSTD_updateTree(
|
||||||
size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||||
|
const BYTE* ip, const BYTE* iend); /* used in ZSTD_loadDictionaryContent() */
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
size_t ZSTD_compressBlock_btopt(
|
||||||
size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
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_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)
|
#if defined (__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
|
|
||||||
|
|
||||||
/* ====== Tuning parameters ====== */
|
/* ====== Tuning parameters ====== */
|
||||||
#define ZSTDMT_NBTHREADS_MAX 200
|
#define ZSTDMT_NBWORKERS_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
|
#define ZSTDMT_OVERLAPLOG_DEFAULT 6
|
||||||
|
|
||||||
|
|
||||||
@@ -22,11 +23,18 @@
|
|||||||
|
|
||||||
/* ====== Dependencies ====== */
|
/* ====== Dependencies ====== */
|
||||||
#include <string.h> /* memcpy, memset */
|
#include <string.h> /* memcpy, memset */
|
||||||
|
#include <limits.h> /* INT_MAX */
|
||||||
#include "pool.h" /* threadpool */
|
#include "pool.h" /* threadpool */
|
||||||
#include "threading.h" /* mutex */
|
#include "threading.h" /* mutex */
|
||||||
#include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
|
#include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
|
||||||
|
#include "zstd_ldm.h"
|
||||||
#include "zstdmt_compress.h"
|
#include "zstdmt_compress.h"
|
||||||
|
|
||||||
|
/* Guards code to support resizing the SeqPool.
|
||||||
|
* We will want to resize the SeqPool to save memory in the future.
|
||||||
|
* Until then, comment the code out since it is unused.
|
||||||
|
*/
|
||||||
|
#define ZSTD_RESIZE_SEQPOOL 0
|
||||||
|
|
||||||
/* ====== Debug ====== */
|
/* ====== Debug ====== */
|
||||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
|
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
|
||||||
@@ -81,7 +89,7 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
|||||||
|
|
||||||
typedef struct buffer_s {
|
typedef struct buffer_s {
|
||||||
void* start;
|
void* start;
|
||||||
size_t size;
|
size_t capacity;
|
||||||
} buffer_t;
|
} buffer_t;
|
||||||
|
|
||||||
static const buffer_t g_nullBuffer = { NULL, 0 };
|
static const buffer_t g_nullBuffer = { NULL, 0 };
|
||||||
@@ -95,9 +103,9 @@ typedef struct ZSTDMT_bufferPool_s {
|
|||||||
buffer_t bTable[1]; /* variable size */
|
buffer_t bTable[1]; /* variable size */
|
||||||
} ZSTDMT_bufferPool;
|
} ZSTDMT_bufferPool;
|
||||||
|
|
||||||
static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_customMem cMem)
|
static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbWorkers, ZSTD_customMem cMem)
|
||||||
{
|
{
|
||||||
unsigned const maxNbBuffers = 2*nbThreads + 3;
|
unsigned const maxNbBuffers = 2*nbWorkers + 3;
|
||||||
ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc(
|
ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc(
|
||||||
sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
|
sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
|
||||||
if (bufPool==NULL) return NULL;
|
if (bufPool==NULL) return NULL;
|
||||||
@@ -134,12 +142,16 @@ static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
|
|||||||
size_t totalBufferSize = 0;
|
size_t totalBufferSize = 0;
|
||||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||||
for (u=0; u<bufPool->totalBuffers; u++)
|
for (u=0; u<bufPool->totalBuffers; u++)
|
||||||
totalBufferSize += bufPool->bTable[u].size;
|
totalBufferSize += bufPool->bTable[u].capacity;
|
||||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||||
|
|
||||||
return poolSize + totalBufferSize;
|
return poolSize + totalBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ZSTDMT_setBufferSize() :
|
||||||
|
* all future buffers provided by this buffer pool will have _at least_ this size
|
||||||
|
* note : it's better for all buffers to have same size,
|
||||||
|
* as they become freely interchangeable, reducing malloc/free usages and memory fragmentation */
|
||||||
static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize)
|
static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize)
|
||||||
{
|
{
|
||||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||||
@@ -149,7 +161,9 @@ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** ZSTDMT_getBuffer() :
|
/** 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)
|
static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
|
||||||
{
|
{
|
||||||
size_t const bSize = bufPool->bufferSize;
|
size_t const bSize = bufPool->bufferSize;
|
||||||
@@ -157,12 +171,12 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
|
|||||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||||
if (bufPool->nbBuffers) { /* try to use an existing buffer */
|
if (bufPool->nbBuffers) { /* try to use an existing buffer */
|
||||||
buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
|
buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
|
||||||
size_t const availBufferSize = buf.size;
|
size_t const availBufferSize = buf.capacity;
|
||||||
bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
|
bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
|
||||||
if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) {
|
if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) {
|
||||||
/* large enough, but not too much */
|
/* large enough, but not too much */
|
||||||
DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u",
|
DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u",
|
||||||
bufPool->nbBuffers, (U32)buf.size);
|
bufPool->nbBuffers, (U32)buf.capacity);
|
||||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@@ -176,12 +190,42 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
|
|||||||
{ buffer_t buffer;
|
{ buffer_t buffer;
|
||||||
void* const start = ZSTD_malloc(bSize, bufPool->cMem);
|
void* const start = ZSTD_malloc(bSize, bufPool->cMem);
|
||||||
buffer.start = start; /* note : start can be NULL if malloc fails ! */
|
buffer.start = start; /* note : start can be NULL if malloc fails ! */
|
||||||
buffer.size = (start==NULL) ? 0 : bSize;
|
buffer.capacity = (start==NULL) ? 0 : bSize;
|
||||||
|
if (start==NULL) {
|
||||||
|
DEBUGLOG(5, "ZSTDMT_getBuffer: buffer allocation failure !!");
|
||||||
|
} else {
|
||||||
DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
|
DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
|
||||||
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ZSTD_RESIZE_SEQPOOL
|
||||||
|
/** ZSTDMT_resizeBuffer() :
|
||||||
|
* assumption : bufPool must be valid
|
||||||
|
* @return : a buffer that is at least the buffer pool buffer size.
|
||||||
|
* If a reallocation happens, the data in the input buffer is copied.
|
||||||
|
*/
|
||||||
|
static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer)
|
||||||
|
{
|
||||||
|
size_t const bSize = bufPool->bufferSize;
|
||||||
|
if (buffer.capacity < bSize) {
|
||||||
|
void* const start = ZSTD_malloc(bSize, bufPool->cMem);
|
||||||
|
buffer_t newBuffer;
|
||||||
|
newBuffer.start = start;
|
||||||
|
newBuffer.capacity = start == NULL ? 0 : bSize;
|
||||||
|
if (start != NULL) {
|
||||||
|
assert(newBuffer.capacity >= buffer.capacity);
|
||||||
|
memcpy(newBuffer.start, buffer.start, buffer.capacity);
|
||||||
|
DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize);
|
||||||
|
return newBuffer;
|
||||||
|
}
|
||||||
|
DEBUGLOG(5, "ZSTDMT_resizeBuffer: buffer allocation failure !!");
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* store buffer for later re-use, up to pool capacity */
|
/* store buffer for later re-use, up to pool capacity */
|
||||||
static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
|
static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
|
||||||
{
|
{
|
||||||
@@ -191,7 +235,7 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
|
|||||||
if (bufPool->nbBuffers < bufPool->totalBuffers) {
|
if (bufPool->nbBuffers < bufPool->totalBuffers) {
|
||||||
bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */
|
bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */
|
||||||
DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u",
|
DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u",
|
||||||
(U32)buf.size, (U32)(bufPool->nbBuffers-1));
|
(U32)buf.capacity, (U32)(bufPool->nbBuffers-1));
|
||||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -201,21 +245,73 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
|
|||||||
ZSTD_free(buf.start, bufPool->cMem);
|
ZSTD_free(buf.start, bufPool->cMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets parameters relevant to the compression job, initializing others to
|
|
||||||
* default values. Notably, nbThreads should probably be zero. */
|
/* ===== Seq Pool Wrapper ====== */
|
||||||
static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
|
|
||||||
|
static rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0};
|
||||||
|
|
||||||
|
typedef ZSTDMT_bufferPool ZSTDMT_seqPool;
|
||||||
|
|
||||||
|
static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool)
|
||||||
{
|
{
|
||||||
ZSTD_CCtx_params jobParams;
|
return ZSTDMT_sizeof_bufferPool(seqPool);
|
||||||
memset(&jobParams, 0, sizeof(jobParams));
|
|
||||||
|
|
||||||
jobParams.cParams = params.cParams;
|
|
||||||
jobParams.fParams = params.fParams;
|
|
||||||
jobParams.compressionLevel = params.compressionLevel;
|
|
||||||
|
|
||||||
jobParams.ldmParams = params.ldmParams;
|
|
||||||
return jobParams;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rawSeqStore_t bufferToSeq(buffer_t buffer)
|
||||||
|
{
|
||||||
|
rawSeqStore_t seq = {NULL, 0, 0, 0};
|
||||||
|
seq.seq = (rawSeq*)buffer.start;
|
||||||
|
seq.capacity = buffer.capacity / sizeof(rawSeq);
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static buffer_t seqToBuffer(rawSeqStore_t seq)
|
||||||
|
{
|
||||||
|
buffer_t buffer;
|
||||||
|
buffer.start = seq.seq;
|
||||||
|
buffer.capacity = seq.capacity * sizeof(rawSeq);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rawSeqStore_t ZSTDMT_getSeq(ZSTDMT_seqPool* seqPool)
|
||||||
|
{
|
||||||
|
if (seqPool->bufferSize == 0) {
|
||||||
|
return kNullRawSeqStore;
|
||||||
|
}
|
||||||
|
return bufferToSeq(ZSTDMT_getBuffer(seqPool));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ZSTD_RESIZE_SEQPOOL
|
||||||
|
static rawSeqStore_t ZSTDMT_resizeSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq)
|
||||||
|
{
|
||||||
|
return bufferToSeq(ZSTDMT_resizeBuffer(seqPool, seqToBuffer(seq)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void ZSTDMT_releaseSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq)
|
||||||
|
{
|
||||||
|
ZSTDMT_releaseBuffer(seqPool, seqToBuffer(seq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTDMT_setNbSeq(ZSTDMT_seqPool* const seqPool, size_t const nbSeq)
|
||||||
|
{
|
||||||
|
ZSTDMT_setBufferSize(seqPool, nbSeq * sizeof(rawSeq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZSTDMT_seqPool* ZSTDMT_createSeqPool(unsigned nbWorkers, ZSTD_customMem cMem)
|
||||||
|
{
|
||||||
|
ZSTDMT_seqPool* seqPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
|
||||||
|
ZSTDMT_setNbSeq(seqPool, 0);
|
||||||
|
return seqPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool)
|
||||||
|
{
|
||||||
|
ZSTDMT_freeBufferPool(seqPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ===== CCtx Pool ===== */
|
/* ===== CCtx Pool ===== */
|
||||||
/* a single CCtx Pool can be invoked from multiple threads in parallel */
|
/* a single CCtx Pool can be invoked from multiple threads in parallel */
|
||||||
|
|
||||||
@@ -238,23 +334,24 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTDMT_createCCtxPool() :
|
/* ZSTDMT_createCCtxPool() :
|
||||||
* implies nbThreads >= 1 , checked by caller ZSTDMT_createCCtx() */
|
* implies nbWorkers >= 1 , checked by caller ZSTDMT_createCCtx() */
|
||||||
static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads,
|
static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbWorkers,
|
||||||
ZSTD_customMem cMem)
|
ZSTD_customMem cMem)
|
||||||
{
|
{
|
||||||
ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc(
|
ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc(
|
||||||
sizeof(ZSTDMT_CCtxPool) + (nbThreads-1)*sizeof(ZSTD_CCtx*), cMem);
|
sizeof(ZSTDMT_CCtxPool) + (nbWorkers-1)*sizeof(ZSTD_CCtx*), cMem);
|
||||||
|
assert(nbWorkers > 0);
|
||||||
if (!cctxPool) return NULL;
|
if (!cctxPool) return NULL;
|
||||||
if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
|
if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
|
||||||
ZSTD_free(cctxPool, cMem);
|
ZSTD_free(cctxPool, cMem);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cctxPool->cMem = cMem;
|
cctxPool->cMem = cMem;
|
||||||
cctxPool->totalCCtx = nbThreads;
|
cctxPool->totalCCtx = nbWorkers;
|
||||||
cctxPool->availCCtx = 1; /* at least one cctx for single-thread mode */
|
cctxPool->availCCtx = 1; /* at least one cctx for single-thread mode */
|
||||||
cctxPool->cctx[0] = ZSTD_createCCtx_advanced(cMem);
|
cctxPool->cctx[0] = ZSTD_createCCtx_advanced(cMem);
|
||||||
if (!cctxPool->cctx[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; }
|
if (!cctxPool->cctx[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; }
|
||||||
DEBUGLOG(3, "cctxPool created, with %u threads", nbThreads);
|
DEBUGLOG(3, "cctxPool created, with %u workers", nbWorkers);
|
||||||
return cctxPool;
|
return cctxPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,15 +359,16 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads,
|
|||||||
static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
|
static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
|
||||||
{
|
{
|
||||||
ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
|
ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
|
||||||
{ unsigned const nbThreads = cctxPool->totalCCtx;
|
{ unsigned const nbWorkers = cctxPool->totalCCtx;
|
||||||
size_t const poolSize = sizeof(*cctxPool)
|
size_t const poolSize = sizeof(*cctxPool)
|
||||||
+ (nbThreads-1)*sizeof(ZSTD_CCtx*);
|
+ (nbWorkers-1) * sizeof(ZSTD_CCtx*);
|
||||||
unsigned u;
|
unsigned u;
|
||||||
size_t totalCCtxSize = 0;
|
size_t totalCCtxSize = 0;
|
||||||
for (u=0; u<nbThreads; u++) {
|
for (u=0; u<nbWorkers; u++) {
|
||||||
totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctx[u]);
|
totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctx[u]);
|
||||||
}
|
}
|
||||||
ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
|
ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||||
|
assert(nbWorkers > 0);
|
||||||
return poolSize + totalCCtxSize;
|
return poolSize + totalCCtxSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,111 +395,318 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
|
|||||||
if (pool->availCCtx < pool->totalCCtx)
|
if (pool->availCCtx < pool->totalCCtx)
|
||||||
pool->cctx[pool->availCCtx++] = cctx;
|
pool->cctx[pool->availCCtx++] = cctx;
|
||||||
else {
|
else {
|
||||||
/* pool overflow : should not happen, since totalCCtx==nbThreads */
|
/* pool overflow : should not happen, since totalCCtx==nbWorkers */
|
||||||
DEBUGLOG(5, "CCtx pool overflow : free cctx");
|
DEBUGLOG(4, "CCtx pool overflow : free cctx");
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
}
|
}
|
||||||
ZSTD_pthread_mutex_unlock(&pool->poolMutex);
|
ZSTD_pthread_mutex_unlock(&pool->poolMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==== Serial State ==== */
|
||||||
/* ===== Thread worker ===== */
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
buffer_t src;
|
void const* start;
|
||||||
const void* srcStart;
|
size_t size;
|
||||||
size_t prefixSize;
|
} range_t;
|
||||||
size_t srcSize;
|
|
||||||
buffer_t dstBuff;
|
typedef struct {
|
||||||
size_t cSize;
|
/* All variables in the struct are protected by mutex. */
|
||||||
size_t dstFlushed;
|
ZSTD_pthread_mutex_t mutex;
|
||||||
unsigned firstChunk;
|
ZSTD_pthread_cond_t cond;
|
||||||
unsigned lastChunk;
|
|
||||||
unsigned jobCompleted;
|
|
||||||
unsigned jobScanned;
|
|
||||||
ZSTD_pthread_mutex_t* jobCompleted_mutex;
|
|
||||||
ZSTD_pthread_cond_t* jobCompleted_cond;
|
|
||||||
ZSTD_CCtx_params params;
|
ZSTD_CCtx_params params;
|
||||||
const ZSTD_CDict* cdict;
|
ldmState_t ldmState;
|
||||||
ZSTDMT_CCtxPool* cctxPool;
|
XXH64_state_t xxhState;
|
||||||
ZSTDMT_bufferPool* bufPool;
|
unsigned nextJobID;
|
||||||
unsigned long long fullFrameSize;
|
/* Protects ldmWindow.
|
||||||
|
* Must be acquired after the main mutex when acquiring both.
|
||||||
|
*/
|
||||||
|
ZSTD_pthread_mutex_t ldmWindowMutex;
|
||||||
|
ZSTD_pthread_cond_t ldmWindowCond; /* Signaled when ldmWindow is udpated */
|
||||||
|
ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */
|
||||||
|
} serialState_t;
|
||||||
|
|
||||||
|
static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* seqPool, ZSTD_CCtx_params params)
|
||||||
|
{
|
||||||
|
/* Adjust parameters */
|
||||||
|
if (params.ldmParams.enableLdm) {
|
||||||
|
DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10);
|
||||||
|
params.ldmParams.windowLog = params.cParams.windowLog;
|
||||||
|
ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams);
|
||||||
|
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
||||||
|
assert(params.ldmParams.hashEveryLog < 32);
|
||||||
|
serialState->ldmState.hashPower =
|
||||||
|
ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
|
||||||
|
} else {
|
||||||
|
memset(¶ms.ldmParams, 0, sizeof(params.ldmParams));
|
||||||
|
}
|
||||||
|
serialState->nextJobID = 0;
|
||||||
|
if (params.fParams.checksumFlag)
|
||||||
|
XXH64_reset(&serialState->xxhState, 0);
|
||||||
|
if (params.ldmParams.enableLdm) {
|
||||||
|
ZSTD_customMem cMem = params.customMem;
|
||||||
|
unsigned const hashLog = params.ldmParams.hashLog;
|
||||||
|
size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t);
|
||||||
|
unsigned const bucketLog =
|
||||||
|
params.ldmParams.hashLog - params.ldmParams.bucketSizeLog;
|
||||||
|
size_t const bucketSize = (size_t)1 << bucketLog;
|
||||||
|
unsigned const prevBucketLog =
|
||||||
|
serialState->params.ldmParams.hashLog -
|
||||||
|
serialState->params.ldmParams.bucketSizeLog;
|
||||||
|
/* Size the seq pool tables */
|
||||||
|
ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, params.jobSize));
|
||||||
|
/* Reset the window */
|
||||||
|
ZSTD_window_clear(&serialState->ldmState.window);
|
||||||
|
serialState->ldmWindow = serialState->ldmState.window;
|
||||||
|
/* Resize tables and output space if necessary. */
|
||||||
|
if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) {
|
||||||
|
ZSTD_free(serialState->ldmState.hashTable, cMem);
|
||||||
|
serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_malloc(hashSize, cMem);
|
||||||
|
}
|
||||||
|
if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) {
|
||||||
|
ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
|
||||||
|
serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_malloc(bucketSize, cMem);
|
||||||
|
}
|
||||||
|
if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets)
|
||||||
|
return 1;
|
||||||
|
/* Zero the tables */
|
||||||
|
memset(serialState->ldmState.hashTable, 0, hashSize);
|
||||||
|
memset(serialState->ldmState.bucketOffsets, 0, bucketSize);
|
||||||
|
}
|
||||||
|
serialState->params = params;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ZSTDMT_serialState_init(serialState_t* serialState)
|
||||||
|
{
|
||||||
|
int initError = 0;
|
||||||
|
memset(serialState, 0, sizeof(*serialState));
|
||||||
|
initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL);
|
||||||
|
initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL);
|
||||||
|
initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL);
|
||||||
|
initError |= ZSTD_pthread_cond_init(&serialState->ldmWindowCond, NULL);
|
||||||
|
return initError;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTDMT_serialState_free(serialState_t* serialState)
|
||||||
|
{
|
||||||
|
ZSTD_customMem cMem = serialState->params.customMem;
|
||||||
|
ZSTD_pthread_mutex_destroy(&serialState->mutex);
|
||||||
|
ZSTD_pthread_cond_destroy(&serialState->cond);
|
||||||
|
ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex);
|
||||||
|
ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond);
|
||||||
|
ZSTD_free(serialState->ldmState.hashTable, cMem);
|
||||||
|
ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTDMT_serialState_update(serialState_t* serialState,
|
||||||
|
ZSTD_CCtx* jobCCtx, rawSeqStore_t seqStore,
|
||||||
|
range_t src, unsigned jobID)
|
||||||
|
{
|
||||||
|
/* Wait for our turn */
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
|
||||||
|
while (serialState->nextJobID < jobID) {
|
||||||
|
ZSTD_pthread_cond_wait(&serialState->cond, &serialState->mutex);
|
||||||
|
}
|
||||||
|
/* A future job may error and skip our job */
|
||||||
|
if (serialState->nextJobID == jobID) {
|
||||||
|
/* It is now our turn, do any processing necessary */
|
||||||
|
if (serialState->params.ldmParams.enableLdm) {
|
||||||
|
size_t error;
|
||||||
|
assert(seqStore.seq != NULL && seqStore.pos == 0 &&
|
||||||
|
seqStore.size == 0 && seqStore.capacity > 0);
|
||||||
|
ZSTD_window_update(&serialState->ldmState.window, src.start, src.size);
|
||||||
|
error = ZSTD_ldm_generateSequences(
|
||||||
|
&serialState->ldmState, &seqStore,
|
||||||
|
&serialState->params.ldmParams, src.start, src.size);
|
||||||
|
/* We provide a large enough buffer to never fail. */
|
||||||
|
assert(!ZSTD_isError(error)); (void)error;
|
||||||
|
/* Update ldmWindow to match the ldmState.window and signal the main
|
||||||
|
* thread if it is waiting for a buffer.
|
||||||
|
*/
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex);
|
||||||
|
serialState->ldmWindow = serialState->ldmState.window;
|
||||||
|
ZSTD_pthread_cond_signal(&serialState->ldmWindowCond);
|
||||||
|
ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex);
|
||||||
|
}
|
||||||
|
if (serialState->params.fParams.checksumFlag && src.size > 0)
|
||||||
|
XXH64_update(&serialState->xxhState, src.start, src.size);
|
||||||
|
}
|
||||||
|
/* Now it is the next jobs turn */
|
||||||
|
serialState->nextJobID++;
|
||||||
|
ZSTD_pthread_cond_broadcast(&serialState->cond);
|
||||||
|
ZSTD_pthread_mutex_unlock(&serialState->mutex);
|
||||||
|
|
||||||
|
if (seqStore.size > 0) {
|
||||||
|
size_t const err = ZSTD_referenceExternalSequences(
|
||||||
|
jobCCtx, seqStore.seq, seqStore.size);
|
||||||
|
assert(serialState->params.ldmParams.enableLdm);
|
||||||
|
assert(!ZSTD_isError(err));
|
||||||
|
(void)err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTDMT_serialState_ensureFinished(serialState_t* serialState,
|
||||||
|
unsigned jobID, size_t cSize)
|
||||||
|
{
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
|
||||||
|
if (serialState->nextJobID <= jobID) {
|
||||||
|
assert(ZSTD_isError(cSize)); (void)cSize;
|
||||||
|
DEBUGLOG(5, "Skipping past job %u because of error", jobID);
|
||||||
|
serialState->nextJobID = jobID + 1;
|
||||||
|
ZSTD_pthread_cond_broadcast(&serialState->cond);
|
||||||
|
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex);
|
||||||
|
ZSTD_window_clear(&serialState->ldmWindow);
|
||||||
|
ZSTD_pthread_cond_signal(&serialState->ldmWindowCond);
|
||||||
|
ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex);
|
||||||
|
}
|
||||||
|
ZSTD_pthread_mutex_unlock(&serialState->mutex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
/* ===== Worker thread ===== */
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
|
||||||
|
static const range_t kNullRange = { NULL, 0 };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t consumed; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx */
|
||||||
|
size_t cSize; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx, then set0 by mtctx */
|
||||||
|
ZSTD_pthread_mutex_t job_mutex; /* Thread-safe - used by mtctx and worker */
|
||||||
|
ZSTD_pthread_cond_t job_cond; /* Thread-safe - used by mtctx and worker */
|
||||||
|
ZSTDMT_CCtxPool* cctxPool; /* Thread-safe - used by mtctx and (all) workers */
|
||||||
|
ZSTDMT_bufferPool* bufPool; /* Thread-safe - used by mtctx and (all) workers */
|
||||||
|
ZSTDMT_seqPool* seqPool; /* Thread-safe - used by mtctx and (all) workers */
|
||||||
|
serialState_t* serial; /* Thread-safe - used by mtctx and (all) workers */
|
||||||
|
buffer_t dstBuff; /* set by worker (or mtctx), then read by worker & mtctx, then modified by mtctx => no barrier */
|
||||||
|
range_t prefix; /* set by mtctx, then read by worker & mtctx => no barrier */
|
||||||
|
range_t src; /* set by mtctx, then read by worker & mtctx => no barrier */
|
||||||
|
unsigned jobID; /* set by mtctx, then read by worker => no barrier */
|
||||||
|
unsigned firstJob; /* set by mtctx, then read by worker => no barrier */
|
||||||
|
unsigned lastJob; /* set by mtctx, then read by worker => no barrier */
|
||||||
|
ZSTD_CCtx_params params; /* set by mtctx, then read by worker => no barrier */
|
||||||
|
const ZSTD_CDict* cdict; /* set by mtctx, then read by worker => no barrier */
|
||||||
|
unsigned long long fullFrameSize; /* set by mtctx, then read by worker => no barrier */
|
||||||
|
size_t dstFlushed; /* used only by mtctx */
|
||||||
|
unsigned frameChecksumNeeded; /* used only by mtctx */
|
||||||
} ZSTDMT_jobDescription;
|
} ZSTDMT_jobDescription;
|
||||||
|
|
||||||
/* ZSTDMT_compressChunk() : POOL_function type */
|
/* ZSTDMT_compressionJob() is a POOL_function type */
|
||||||
void ZSTDMT_compressChunk(void* jobDescription)
|
void ZSTDMT_compressionJob(void* jobDescription)
|
||||||
{
|
{
|
||||||
ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
|
ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
|
||||||
|
ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */
|
||||||
ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool);
|
ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool);
|
||||||
const void* const src = (const char*)job->srcStart + job->prefixSize;
|
rawSeqStore_t rawSeqStore = ZSTDMT_getSeq(job->seqPool);
|
||||||
buffer_t dstBuff = job->dstBuff;
|
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);
|
|
||||||
|
|
||||||
|
/* Don't compute the checksum for chunks, since we compute it externally,
|
||||||
|
* but write it in the header.
|
||||||
|
*/
|
||||||
|
if (job->jobID != 0) jobParams.fParams.checksumFlag = 0;
|
||||||
|
/* Don't run LDM for the chunks, since we handle it externally */
|
||||||
|
jobParams.ldmParams.enableLdm = 0;
|
||||||
|
|
||||||
|
/* ressources */
|
||||||
if (cctx==NULL) {
|
if (cctx==NULL) {
|
||||||
job->cSize = ERROR(memory_allocation);
|
job->cSize = ERROR(memory_allocation);
|
||||||
goto _endJob;
|
goto _endJob;
|
||||||
}
|
}
|
||||||
|
if (dstBuff.start == NULL) { /* streaming job : doesn't provide a dstBuffer */
|
||||||
if (dstBuff.start == NULL) {
|
|
||||||
dstBuff = ZSTDMT_getBuffer(job->bufPool);
|
dstBuff = ZSTDMT_getBuffer(job->bufPool);
|
||||||
if (dstBuff.start==NULL) {
|
if (dstBuff.start==NULL) {
|
||||||
job->cSize = ERROR(memory_allocation);
|
job->cSize = ERROR(memory_allocation);
|
||||||
goto _endJob;
|
goto _endJob;
|
||||||
}
|
}
|
||||||
job->dstBuff = dstBuff;
|
job->dstBuff = dstBuff; /* this value can be read in ZSTDMT_flush, when it copies the whole job */
|
||||||
DEBUGLOG(5, "ZSTDMT_compressChunk: received dstBuff of size %u", (U32)dstBuff.size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* init */
|
||||||
if (job->cdict) {
|
if (job->cdict) {
|
||||||
size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dm_auto, job->cdict, job->params, job->fullFrameSize);
|
size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dct_auto, job->cdict, jobParams, job->fullFrameSize);
|
||||||
DEBUGLOG(4, "ZSTDMT_compressChunk: init using CDict (windowLog=%u)", job->params.cParams.windowLog);
|
assert(job->firstJob); /* only allowed for first job */
|
||||||
assert(job->firstChunk); /* only allowed for first job */
|
|
||||||
if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
|
if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
|
||||||
} else { /* srcStart points at reloaded section */
|
} else { /* srcStart points at reloaded section */
|
||||||
U64 const pledgedSrcSize = job->firstChunk ? job->fullFrameSize : ZSTD_CONTENTSIZE_UNKNOWN;
|
U64 const pledgedSrcSize = job->firstJob ? job->fullFrameSize : job->src.size;
|
||||||
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->firstJob);
|
||||||
size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
|
|
||||||
if (ZSTD_isError(forceWindowError)) {
|
if (ZSTD_isError(forceWindowError)) {
|
||||||
DEBUGLOG(5, "ZSTD_CCtxParam_setParameter error : %s ", ZSTD_getErrorName(forceWindowError));
|
|
||||||
job->cSize = forceWindowError;
|
job->cSize = forceWindowError;
|
||||||
goto _endJob;
|
goto _endJob;
|
||||||
}
|
} }
|
||||||
DEBUGLOG(5, "ZSTDMT_compressChunk: invoking ZSTD_compressBegin_advanced_internal with windowLog = %u ", jobParams.cParams.windowLog);
|
|
||||||
{ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
|
{ 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) */
|
job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
|
||||||
NULL,
|
NULL, /*cdict*/
|
||||||
jobParams, pledgedSrcSize);
|
jobParams, pledgedSrcSize);
|
||||||
if (ZSTD_isError(initError)) {
|
if (ZSTD_isError(initError)) {
|
||||||
DEBUGLOG(5, "ZSTD_compressBegin_advanced_internal error : %s ", ZSTD_getErrorName(initError));
|
|
||||||
job->cSize = initError;
|
job->cSize = initError;
|
||||||
goto _endJob;
|
goto _endJob;
|
||||||
} }
|
} } }
|
||||||
}
|
|
||||||
if (!job->firstChunk) { /* flush and overwrite frame header when it's not first job */
|
/* Perform serial step as early as possible, but after CCtx initialization */
|
||||||
size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0);
|
ZSTDMT_serialState_update(job->serial, cctx, rawSeqStore, job->src, job->jobID);
|
||||||
|
|
||||||
|
if (!job->firstJob) { /* flush and overwrite frame header when it's not first job */
|
||||||
|
size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0);
|
||||||
if (ZSTD_isError(hSize)) { job->cSize = hSize; /* save error code */ goto _endJob; }
|
if (ZSTD_isError(hSize)) { job->cSize = hSize; /* save error code */ goto _endJob; }
|
||||||
|
DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize);
|
||||||
ZSTD_invalidateRepCodes(cctx);
|
ZSTD_invalidateRepCodes(cctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGLOG(5, "Compressing into dstBuff of size %u", (U32)dstBuff.size);
|
/* compress */
|
||||||
DEBUG_PRINTHEX(6, job->srcStart, 12);
|
{ size_t const chunkSize = 4*ZSTD_BLOCKSIZE_MAX;
|
||||||
job->cSize = (job->lastChunk) ?
|
int const nbChunks = (int)((job->src.size + (chunkSize-1)) / chunkSize);
|
||||||
ZSTD_compressEnd (cctx, dstBuff.start, dstBuff.size, src, job->srcSize) :
|
const BYTE* ip = (const BYTE*) job->src.start;
|
||||||
ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, job->srcSize);
|
BYTE* const ostart = (BYTE*)dstBuff.start;
|
||||||
DEBUGLOG(5, "compressed %u bytes into %u bytes (first:%u) (last:%u) ",
|
BYTE* op = ostart;
|
||||||
(unsigned)job->srcSize, (unsigned)job->cSize, job->firstChunk, job->lastChunk);
|
BYTE* oend = op + dstBuff.capacity;
|
||||||
DEBUGLOG(5, "dstBuff.size : %u ; => %s ", (U32)dstBuff.size, ZSTD_getErrorName(job->cSize));
|
int chunkNb;
|
||||||
|
if (sizeof(size_t) > sizeof(int)) assert(job->src.size < ((size_t)INT_MAX) * chunkSize); /* check overflow */
|
||||||
|
DEBUGLOG(5, "ZSTDMT_compressionJob: compress %u bytes in %i blocks", (U32)job->src.size, nbChunks);
|
||||||
|
assert(job->cSize == 0);
|
||||||
|
for (chunkNb = 1; chunkNb < nbChunks; chunkNb++) {
|
||||||
|
size_t const cSize = ZSTD_compressContinue(cctx, op, oend-op, ip, chunkSize);
|
||||||
|
if (ZSTD_isError(cSize)) { job->cSize = cSize; goto _endJob; }
|
||||||
|
ip += chunkSize;
|
||||||
|
op += cSize; assert(op < oend);
|
||||||
|
/* stats */
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
|
||||||
|
job->cSize += cSize;
|
||||||
|
job->consumed = chunkSize * chunkNb;
|
||||||
|
DEBUGLOG(5, "ZSTDMT_compressionJob: compress new block : cSize==%u bytes (total: %u)",
|
||||||
|
(U32)cSize, (U32)job->cSize);
|
||||||
|
ZSTD_pthread_cond_signal(&job->job_cond); /* warns some more data is ready to be flushed */
|
||||||
|
ZSTD_pthread_mutex_unlock(&job->job_mutex);
|
||||||
|
}
|
||||||
|
/* last block */
|
||||||
|
assert(chunkSize > 0); assert((chunkSize & (chunkSize - 1)) == 0); /* chunkSize must be power of 2 for mask==(chunkSize-1) to work */
|
||||||
|
if ((nbChunks > 0) | job->lastJob /*must output a "last block" flag*/ ) {
|
||||||
|
size_t const lastBlockSize1 = job->src.size & (chunkSize-1);
|
||||||
|
size_t const lastBlockSize = ((lastBlockSize1==0) & (job->src.size>=chunkSize)) ? chunkSize : lastBlockSize1;
|
||||||
|
size_t const cSize = (job->lastJob) ?
|
||||||
|
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 */
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
|
||||||
|
job->cSize += cSize;
|
||||||
|
ZSTD_pthread_mutex_unlock(&job->job_mutex);
|
||||||
|
} }
|
||||||
|
|
||||||
_endJob:
|
_endJob:
|
||||||
|
ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize);
|
||||||
|
if (job->prefix.size > 0)
|
||||||
|
DEBUGLOG(5, "Finished with prefix: %zx", (size_t)job->prefix.start);
|
||||||
|
DEBUGLOG(5, "Finished with source: %zx", (size_t)job->src.start);
|
||||||
|
/* release resources */
|
||||||
|
ZSTDMT_releaseSeq(job->seqPool, rawSeqStore);
|
||||||
ZSTDMT_releaseCCtx(job->cctxPool, cctx);
|
ZSTDMT_releaseCCtx(job->cctxPool, cctx);
|
||||||
ZSTDMT_releaseBuffer(job->bufPool, job->src);
|
/* report */
|
||||||
job->src = g_nullBuffer; job->srcStart = NULL;
|
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
|
||||||
ZSTD_PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex);
|
job->consumed = job->src.size;
|
||||||
job->jobCompleted = 1;
|
ZSTD_pthread_cond_signal(&job->job_cond);
|
||||||
job->jobScanned = 0;
|
ZSTD_pthread_mutex_unlock(&job->job_mutex);
|
||||||
ZSTD_pthread_cond_signal(job->jobCompleted_cond);
|
|
||||||
ZSTD_pthread_mutex_unlock(job->jobCompleted_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -410,109 +715,141 @@ _endJob:
|
|||||||
/* ------------------------------------------ */
|
/* ------------------------------------------ */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
range_t prefix; /* read-only non-owned prefix buffer */
|
||||||
buffer_t buffer;
|
buffer_t buffer;
|
||||||
size_t filled;
|
size_t filled;
|
||||||
} inBuff_t;
|
} inBuff_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE* buffer; /* The round input buffer. All jobs get references
|
||||||
|
* to pieces of the buffer. ZSTDMT_tryGetInputRange()
|
||||||
|
* handles handing out job input buffers, and makes
|
||||||
|
* sure it doesn't overlap with any pieces still in use.
|
||||||
|
*/
|
||||||
|
size_t capacity; /* The capacity of buffer. */
|
||||||
|
size_t pos; /* The position of the current inBuff in the round
|
||||||
|
* buffer. Updated past the end if the inBuff once
|
||||||
|
* the inBuff is sent to the worker thread.
|
||||||
|
* pos <= capacity.
|
||||||
|
*/
|
||||||
|
} roundBuff_t;
|
||||||
|
|
||||||
|
static const roundBuff_t kNullRoundBuff = {NULL, 0, 0};
|
||||||
|
|
||||||
struct ZSTDMT_CCtx_s {
|
struct ZSTDMT_CCtx_s {
|
||||||
POOL_ctx* factory;
|
POOL_ctx* factory;
|
||||||
ZSTDMT_jobDescription* jobs;
|
ZSTDMT_jobDescription* jobs;
|
||||||
ZSTDMT_bufferPool* bufPool;
|
ZSTDMT_bufferPool* bufPool;
|
||||||
ZSTDMT_CCtxPool* cctxPool;
|
ZSTDMT_CCtxPool* cctxPool;
|
||||||
ZSTD_pthread_mutex_t jobCompleted_mutex;
|
ZSTDMT_seqPool* seqPool;
|
||||||
ZSTD_pthread_cond_t jobCompleted_cond;
|
|
||||||
ZSTD_CCtx_params params;
|
ZSTD_CCtx_params params;
|
||||||
size_t targetSectionSize;
|
size_t targetSectionSize;
|
||||||
size_t inBuffSize;
|
size_t targetPrefixSize;
|
||||||
size_t dictSize;
|
roundBuff_t roundBuff;
|
||||||
size_t targetDictSize;
|
|
||||||
inBuff_t inBuff;
|
inBuff_t inBuff;
|
||||||
XXH64_state_t xxhState;
|
int jobReady; /* 1 => one job is already prepared, but pool has shortage of workers. Don't create another one. */
|
||||||
unsigned singleThreaded;
|
serialState_t serial;
|
||||||
|
unsigned singleBlockingThread;
|
||||||
unsigned jobIDMask;
|
unsigned jobIDMask;
|
||||||
unsigned doneJobID;
|
unsigned doneJobID;
|
||||||
unsigned nextJobID;
|
unsigned nextJobID;
|
||||||
unsigned frameEnded;
|
unsigned frameEnded;
|
||||||
unsigned allJobsCompleted;
|
unsigned allJobsCompleted;
|
||||||
unsigned long long frameContentSize;
|
unsigned long long frameContentSize;
|
||||||
|
unsigned long long consumed;
|
||||||
|
unsigned long long produced;
|
||||||
ZSTD_customMem cMem;
|
ZSTD_customMem cMem;
|
||||||
ZSTD_CDict* cdictLocal;
|
ZSTD_CDict* cdictLocal;
|
||||||
const ZSTD_CDict* cdict;
|
const ZSTD_CDict* cdict;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customMem cMem)
|
static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZSTD_customMem cMem)
|
||||||
|
{
|
||||||
|
U32 jobNb;
|
||||||
|
if (jobTable == NULL) return;
|
||||||
|
for (jobNb=0; jobNb<nbJobs; jobNb++) {
|
||||||
|
ZSTD_pthread_mutex_destroy(&jobTable[jobNb].job_mutex);
|
||||||
|
ZSTD_pthread_cond_destroy(&jobTable[jobNb].job_cond);
|
||||||
|
}
|
||||||
|
ZSTD_free(jobTable, cMem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTDMT_allocJobsTable()
|
||||||
|
* allocate and init a job table.
|
||||||
|
* update *nbJobsPtr to next power of 2 value, as size of table */
|
||||||
|
static ZSTDMT_jobDescription* ZSTDMT_createJobsTable(U32* nbJobsPtr, ZSTD_customMem cMem)
|
||||||
{
|
{
|
||||||
U32 const nbJobsLog2 = ZSTD_highbit32(*nbJobsPtr) + 1;
|
U32 const nbJobsLog2 = ZSTD_highbit32(*nbJobsPtr) + 1;
|
||||||
U32 const nbJobs = 1 << nbJobsLog2;
|
U32 const nbJobs = 1 << nbJobsLog2;
|
||||||
|
U32 jobNb;
|
||||||
|
ZSTDMT_jobDescription* const jobTable = (ZSTDMT_jobDescription*)
|
||||||
|
ZSTD_calloc(nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
|
||||||
|
int initError = 0;
|
||||||
|
if (jobTable==NULL) return NULL;
|
||||||
*nbJobsPtr = nbJobs;
|
*nbJobsPtr = nbJobs;
|
||||||
return (ZSTDMT_jobDescription*) ZSTD_calloc(
|
for (jobNb=0; jobNb<nbJobs; jobNb++) {
|
||||||
nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
|
initError |= ZSTD_pthread_mutex_init(&jobTable[jobNb].job_mutex, NULL);
|
||||||
|
initError |= ZSTD_pthread_cond_init(&jobTable[jobNb].job_cond, NULL);
|
||||||
|
}
|
||||||
|
if (initError != 0) {
|
||||||
|
ZSTDMT_freeJobsTable(jobTable, nbJobs, cMem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return jobTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTDMT_CCtxParam_setNbThreads():
|
/* ZSTDMT_CCtxParam_setNbWorkers():
|
||||||
* Internal use only */
|
* Internal use only */
|
||||||
size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads)
|
size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers)
|
||||||
{
|
{
|
||||||
if (nbThreads > ZSTDMT_NBTHREADS_MAX) nbThreads = ZSTDMT_NBTHREADS_MAX;
|
if (nbWorkers > ZSTDMT_NBWORKERS_MAX) nbWorkers = ZSTDMT_NBWORKERS_MAX;
|
||||||
if (nbThreads < 1) nbThreads = 1;
|
params->nbWorkers = nbWorkers;
|
||||||
params->nbThreads = nbThreads;
|
|
||||||
params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT;
|
params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT;
|
||||||
params->jobSize = 0;
|
params->jobSize = 0;
|
||||||
return nbThreads;
|
return nbWorkers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTDMT_getNbThreads():
|
ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem)
|
||||||
* @return nb threads currently active in mtctx.
|
|
||||||
* mtctx must be valid */
|
|
||||||
size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx)
|
|
||||||
{
|
|
||||||
assert(mtctx != NULL);
|
|
||||||
return mtctx->params.nbThreads;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
|
|
||||||
{
|
{
|
||||||
ZSTDMT_CCtx* mtctx;
|
ZSTDMT_CCtx* mtctx;
|
||||||
U32 nbJobs = nbThreads + 2;
|
U32 nbJobs = nbWorkers + 2;
|
||||||
DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbThreads = %u)", nbThreads);
|
int initError;
|
||||||
|
DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbWorkers = %u)", nbWorkers);
|
||||||
|
|
||||||
if (nbThreads < 1) return NULL;
|
if (nbWorkers < 1) return NULL;
|
||||||
nbThreads = MIN(nbThreads , ZSTDMT_NBTHREADS_MAX);
|
nbWorkers = MIN(nbWorkers , ZSTDMT_NBWORKERS_MAX);
|
||||||
if ((cMem.customAlloc!=NULL) ^ (cMem.customFree!=NULL))
|
if ((cMem.customAlloc!=NULL) ^ (cMem.customFree!=NULL))
|
||||||
/* invalid custom allocator */
|
/* invalid custom allocator */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
|
mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
|
||||||
if (!mtctx) return NULL;
|
if (!mtctx) return NULL;
|
||||||
ZSTDMT_CCtxParam_setNbThreads(&mtctx->params, nbThreads);
|
ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers);
|
||||||
mtctx->cMem = cMem;
|
mtctx->cMem = cMem;
|
||||||
mtctx->allJobsCompleted = 1;
|
mtctx->allJobsCompleted = 1;
|
||||||
mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem);
|
mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem);
|
||||||
mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, cMem);
|
mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem);
|
||||||
|
assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0); /* ensure nbJobs is a power of 2 */
|
||||||
mtctx->jobIDMask = nbJobs - 1;
|
mtctx->jobIDMask = nbJobs - 1;
|
||||||
mtctx->bufPool = ZSTDMT_createBufferPool(nbThreads, cMem);
|
mtctx->bufPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
|
||||||
mtctx->cctxPool = ZSTDMT_createCCtxPool(nbThreads, cMem);
|
mtctx->cctxPool = ZSTDMT_createCCtxPool(nbWorkers, cMem);
|
||||||
if (!mtctx->factory | !mtctx->jobs | !mtctx->bufPool | !mtctx->cctxPool) {
|
mtctx->seqPool = ZSTDMT_createSeqPool(nbWorkers, cMem);
|
||||||
|
initError = ZSTDMT_serialState_init(&mtctx->serial);
|
||||||
|
mtctx->roundBuff = kNullRoundBuff;
|
||||||
|
if (!mtctx->factory | !mtctx->jobs | !mtctx->bufPool | !mtctx->cctxPool | !mtctx->seqPool | initError) {
|
||||||
ZSTDMT_freeCCtx(mtctx);
|
ZSTDMT_freeCCtx(mtctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (ZSTD_pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL)) {
|
DEBUGLOG(3, "mt_cctx created, for %u threads", nbWorkers);
|
||||||
ZSTDMT_freeCCtx(mtctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (ZSTD_pthread_cond_init(&mtctx->jobCompleted_cond, NULL)) {
|
|
||||||
ZSTDMT_freeCCtx(mtctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
DEBUGLOG(3, "mt_cctx created, for %u threads", nbThreads);
|
|
||||||
return mtctx;
|
return mtctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbThreads)
|
ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers)
|
||||||
{
|
{
|
||||||
return ZSTDMT_createCCtx_advanced(nbThreads, ZSTD_defaultCMem);
|
return ZSTDMT_createCCtx_advanced(nbWorkers, ZSTD_defaultCMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ZSTDMT_releaseAllJobResources() :
|
/* ZSTDMT_releaseAllJobResources() :
|
||||||
* note : ensure all workers are killed first ! */
|
* note : ensure all workers are killed first ! */
|
||||||
static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
|
static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
|
||||||
@@ -523,29 +860,26 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
|
|||||||
DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start);
|
DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start);
|
||||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
|
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
|
||||||
mtctx->jobs[jobID].dstBuff = g_nullBuffer;
|
mtctx->jobs[jobID].dstBuff = g_nullBuffer;
|
||||||
DEBUGLOG(4, "job%02u: release src address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].src.start);
|
mtctx->jobs[jobID].cSize = 0;
|
||||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].src);
|
|
||||||
mtctx->jobs[jobID].src = g_nullBuffer;
|
|
||||||
}
|
}
|
||||||
memset(mtctx->jobs, 0, (mtctx->jobIDMask+1)*sizeof(ZSTDMT_jobDescription));
|
memset(mtctx->jobs, 0, (mtctx->jobIDMask+1)*sizeof(ZSTDMT_jobDescription));
|
||||||
DEBUGLOG(4, "input: release address %08X", (U32)(size_t)mtctx->inBuff.buffer.start);
|
|
||||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->inBuff.buffer);
|
|
||||||
mtctx->inBuff.buffer = g_nullBuffer;
|
mtctx->inBuff.buffer = g_nullBuffer;
|
||||||
|
mtctx->inBuff.filled = 0;
|
||||||
mtctx->allJobsCompleted = 1;
|
mtctx->allJobsCompleted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs)
|
static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted");
|
DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted");
|
||||||
while (zcs->doneJobID < zcs->nextJobID) {
|
while (mtctx->doneJobID < mtctx->nextJobID) {
|
||||||
unsigned const jobID = zcs->doneJobID & zcs->jobIDMask;
|
unsigned const jobID = mtctx->doneJobID & mtctx->jobIDMask;
|
||||||
ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
|
ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex);
|
||||||
while (zcs->jobs[jobID].jobCompleted==0) {
|
while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) {
|
||||||
DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */
|
DEBUGLOG(5, "waiting for jobCompleted signal from job %u", mtctx->doneJobID); /* we want to block when waiting for data to flush */
|
||||||
ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex);
|
ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex);
|
||||||
}
|
}
|
||||||
ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex);
|
ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex);
|
||||||
zcs->doneJobID++;
|
mtctx->doneJobID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,12 +888,14 @@ size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx)
|
|||||||
if (mtctx==NULL) return 0; /* compatible with free on NULL */
|
if (mtctx==NULL) return 0; /* compatible with free on NULL */
|
||||||
POOL_free(mtctx->factory); /* stop and free worker threads */
|
POOL_free(mtctx->factory); /* stop and free worker threads */
|
||||||
ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */
|
ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */
|
||||||
ZSTD_free(mtctx->jobs, mtctx->cMem);
|
ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
|
||||||
ZSTDMT_freeBufferPool(mtctx->bufPool);
|
ZSTDMT_freeBufferPool(mtctx->bufPool);
|
||||||
ZSTDMT_freeCCtxPool(mtctx->cctxPool);
|
ZSTDMT_freeCCtxPool(mtctx->cctxPool);
|
||||||
|
ZSTDMT_freeSeqPool(mtctx->seqPool);
|
||||||
|
ZSTDMT_serialState_free(&mtctx->serial);
|
||||||
ZSTD_freeCDict(mtctx->cdictLocal);
|
ZSTD_freeCDict(mtctx->cdictLocal);
|
||||||
ZSTD_pthread_mutex_destroy(&mtctx->jobCompleted_mutex);
|
if (mtctx->roundBuff.buffer)
|
||||||
ZSTD_pthread_cond_destroy(&mtctx->jobCompleted_cond);
|
ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
|
||||||
ZSTD_free(mtctx, mtctx->cMem);
|
ZSTD_free(mtctx, mtctx->cMem);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -572,7 +908,9 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx)
|
|||||||
+ ZSTDMT_sizeof_bufferPool(mtctx->bufPool)
|
+ ZSTDMT_sizeof_bufferPool(mtctx->bufPool)
|
||||||
+ (mtctx->jobIDMask+1) * sizeof(ZSTDMT_jobDescription)
|
+ (mtctx->jobIDMask+1) * sizeof(ZSTDMT_jobDescription)
|
||||||
+ ZSTDMT_sizeof_CCtxPool(mtctx->cctxPool)
|
+ ZSTDMT_sizeof_CCtxPool(mtctx->cctxPool)
|
||||||
+ ZSTD_sizeof_CDict(mtctx->cdictLocal);
|
+ ZSTDMT_sizeof_seqPool(mtctx->seqPool)
|
||||||
|
+ ZSTD_sizeof_CDict(mtctx->cdictLocal)
|
||||||
|
+ mtctx->roundBuff.capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Internal only */
|
/* Internal only */
|
||||||
@@ -612,133 +950,224 @@ size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sets parameters relevant to the compression job,
|
||||||
|
* initializing others to default values. */
|
||||||
|
static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(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.disableLiteralCompression = params.disableLiteralCompression;
|
||||||
|
|
||||||
|
return jobParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! ZSTDMT_updateCParams_whileCompressing() :
|
||||||
|
* Updates only a selected set of compression parameters, to remain compatible with current frame.
|
||||||
|
* New parameters will be applied to next compression job. */
|
||||||
|
void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams)
|
||||||
|
{
|
||||||
|
U32 const saved_wlog = mtctx->params.cParams.windowLog; /* Do not modify windowLog while compressing */
|
||||||
|
int const compressionLevel = cctxParams->compressionLevel;
|
||||||
|
DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)",
|
||||||
|
compressionLevel);
|
||||||
|
mtctx->params.compressionLevel = compressionLevel;
|
||||||
|
{ ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, 0, 0);
|
||||||
|
cParams.windowLog = saved_wlog;
|
||||||
|
mtctx->params.cParams = cParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTDMT_getNbWorkers():
|
||||||
|
* @return nb threads currently active in mtctx.
|
||||||
|
* mtctx must be valid */
|
||||||
|
unsigned ZSTDMT_getNbWorkers(const ZSTDMT_CCtx* mtctx)
|
||||||
|
{
|
||||||
|
assert(mtctx != NULL);
|
||||||
|
return mtctx->params.nbWorkers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTDMT_getFrameProgression():
|
||||||
|
* tells how much data has been consumed (input) and produced (output) for current frame.
|
||||||
|
* able to count progression inside worker threads.
|
||||||
|
* Note : mutex will be acquired during statistics collection. */
|
||||||
|
ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
|
||||||
|
{
|
||||||
|
ZSTD_frameProgression fps;
|
||||||
|
DEBUGLOG(6, "ZSTDMT_getFrameProgression");
|
||||||
|
fps.consumed = mtctx->consumed;
|
||||||
|
fps.produced = mtctx->produced;
|
||||||
|
fps.ingested = mtctx->consumed + mtctx->inBuff.filled;
|
||||||
|
{ unsigned jobNb;
|
||||||
|
unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1);
|
||||||
|
DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)",
|
||||||
|
mtctx->doneJobID, lastJobNb, mtctx->jobReady)
|
||||||
|
for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) {
|
||||||
|
unsigned const wJobID = jobNb & mtctx->jobIDMask;
|
||||||
|
ZSTD_pthread_mutex_lock(&mtctx->jobs[wJobID].job_mutex);
|
||||||
|
{ size_t const cResult = mtctx->jobs[wJobID].cSize;
|
||||||
|
size_t const produced = ZSTD_isError(cResult) ? 0 : cResult;
|
||||||
|
fps.consumed += mtctx->jobs[wJobID].consumed;
|
||||||
|
fps.ingested += mtctx->jobs[wJobID].src.size;
|
||||||
|
fps.produced += produced;
|
||||||
|
}
|
||||||
|
ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------ */
|
/* ------------------------------------------ */
|
||||||
/* ===== Multi-threaded compression ===== */
|
/* ===== Multi-threaded compression ===== */
|
||||||
/* ------------------------------------------ */
|
/* ------------------------------------------ */
|
||||||
|
|
||||||
static unsigned computeNbChunks(size_t srcSize, unsigned windowLog, unsigned nbThreads) {
|
static size_t ZSTDMT_computeTargetJobLog(ZSTD_CCtx_params const params)
|
||||||
size_t const chunkSizeTarget = (size_t)1 << (windowLog + 2);
|
{
|
||||||
size_t const chunkMaxSize = chunkSizeTarget << 2;
|
if (params.ldmParams.enableLdm)
|
||||||
size_t const passSizeMax = chunkMaxSize * nbThreads;
|
return MAX(21, params.cParams.chainLog + 4);
|
||||||
unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1;
|
return MAX(20, params.cParams.windowLog + 2);
|
||||||
unsigned const nbChunksLarge = multiplier * nbThreads;
|
|
||||||
unsigned const nbChunksMax = (unsigned)(srcSize / chunkSizeTarget) + 1;
|
|
||||||
unsigned const nbChunksSmall = MIN(nbChunksMax, nbThreads);
|
|
||||||
return (multiplier>1) ? nbChunksLarge : nbChunksSmall;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t ZSTDMT_computeOverlapLog(ZSTD_CCtx_params const params)
|
||||||
|
{
|
||||||
|
unsigned const overlapRLog = (params.overlapSizeLog>9) ? 0 : 9-params.overlapSizeLog;
|
||||||
|
if (params.ldmParams.enableLdm)
|
||||||
|
return (MIN(params.cParams.windowLog, ZSTDMT_computeTargetJobLog(params) - 2) - overlapRLog);
|
||||||
|
return overlapRLog >= 9 ? 0 : (params.cParams.windowLog - overlapRLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned ZSTDMT_computeNbJobs(ZSTD_CCtx_params params, size_t srcSize, unsigned nbWorkers) {
|
||||||
|
assert(nbWorkers>0);
|
||||||
|
{ size_t const jobSizeTarget = (size_t)1 << ZSTDMT_computeTargetJobLog(params);
|
||||||
|
size_t const jobMaxSize = jobSizeTarget << 2;
|
||||||
|
size_t const passSizeMax = jobMaxSize * nbWorkers;
|
||||||
|
unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1;
|
||||||
|
unsigned const nbJobsLarge = multiplier * nbWorkers;
|
||||||
|
unsigned const nbJobsMax = (unsigned)(srcSize / jobSizeTarget) + 1;
|
||||||
|
unsigned const nbJobsSmall = MIN(nbJobsMax, nbWorkers);
|
||||||
|
return (multiplier>1) ? nbJobsLarge : nbJobsSmall;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* ZSTDMT_compress_advanced_internal() :
|
||||||
|
* This is a blocking function : it will only give back control to caller after finishing its compression job.
|
||||||
|
*/
|
||||||
static size_t ZSTDMT_compress_advanced_internal(
|
static size_t ZSTDMT_compress_advanced_internal(
|
||||||
ZSTDMT_CCtx* mtctx,
|
ZSTDMT_CCtx* mtctx,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const ZSTD_CDict* cdict,
|
const ZSTD_CDict* cdict,
|
||||||
ZSTD_CCtx_params const params)
|
ZSTD_CCtx_params 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 = (size_t)1 << ZSTDMT_computeOverlapLog(params);
|
||||||
size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog);
|
unsigned const nbJobs = ZSTDMT_computeNbJobs(params, srcSize, params.nbWorkers);
|
||||||
unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads);
|
size_t const proposedJobSize = (srcSize + (nbJobs-1)) / nbJobs;
|
||||||
size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks;
|
size_t const avgJobSize = (((proposedJobSize-1) & 0x1FFFF) < 0x7FFF) ? proposedJobSize + 0xFFFF : proposedJobSize; /* avoid too small last block */
|
||||||
size_t const avgChunkSize = (((proposedChunkSize-1) & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */
|
|
||||||
const char* const srcStart = (const char*)src;
|
const char* const srcStart = (const char*)src;
|
||||||
size_t remainingSrcSize = srcSize;
|
size_t remainingSrcSize = srcSize;
|
||||||
unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */
|
unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbJobs : (unsigned)(dstCapacity / ZSTD_compressBound(avgJobSize)); /* presumes avgJobSize >= 256 KB, which should be the case */
|
||||||
size_t frameStartPos = 0, dstBufferPos = 0;
|
size_t frameStartPos = 0, dstBufferPos = 0;
|
||||||
XXH64_state_t xxh64;
|
assert(jobParams.nbWorkers == 0);
|
||||||
assert(jobParams.nbThreads == 0);
|
assert(mtctx->cctxPool->totalCCtx == params.nbWorkers);
|
||||||
assert(mtctx->cctxPool->totalCCtx == params.nbThreads);
|
|
||||||
|
|
||||||
DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbChunks=%2u (rawSize=%u bytes; fixedSize=%u) ",
|
params.jobSize = (U32)avgJobSize;
|
||||||
nbChunks, (U32)proposedChunkSize, (U32)avgChunkSize);
|
DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbJobs=%2u (rawSize=%u bytes; fixedSize=%u) ",
|
||||||
if (nbChunks==1) { /* fallback to single-thread mode */
|
nbJobs, (U32)proposedJobSize, (U32)avgJobSize);
|
||||||
|
|
||||||
|
if ((nbJobs==1) | (params.nbWorkers<=1)) { /* fallback to single-thread mode : this is a blocking invocation anyway */
|
||||||
ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
|
ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
|
||||||
|
DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: fallback to single-thread mode");
|
||||||
if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams);
|
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);
|
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 */
|
|
||||||
ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgChunkSize) );
|
|
||||||
XXH64_reset(&xxh64, 0);
|
|
||||||
|
|
||||||
if (nbChunks > mtctx->jobIDMask+1) { /* enlarge job table */
|
assert(avgJobSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), required to compress directly into Dst (no additional buffer) */
|
||||||
U32 nbJobs = nbChunks;
|
ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgJobSize) );
|
||||||
ZSTD_free(mtctx->jobs, mtctx->cMem);
|
if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params))
|
||||||
|
return ERROR(memory_allocation);
|
||||||
|
|
||||||
|
if (nbJobs > mtctx->jobIDMask+1) { /* enlarge job table */
|
||||||
|
U32 jobsTableSize = nbJobs;
|
||||||
|
ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
|
||||||
mtctx->jobIDMask = 0;
|
mtctx->jobIDMask = 0;
|
||||||
mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, mtctx->cMem);
|
mtctx->jobs = ZSTDMT_createJobsTable(&jobsTableSize, mtctx->cMem);
|
||||||
if (mtctx->jobs==NULL) return ERROR(memory_allocation);
|
if (mtctx->jobs==NULL) return ERROR(memory_allocation);
|
||||||
mtctx->jobIDMask = nbJobs - 1;
|
assert((jobsTableSize != 0) && ((jobsTableSize & (jobsTableSize - 1)) == 0)); /* ensure jobsTableSize is a power of 2 */
|
||||||
|
mtctx->jobIDMask = jobsTableSize - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ unsigned u;
|
{ unsigned u;
|
||||||
for (u=0; u<nbChunks; u++) {
|
for (u=0; u<nbJobs; u++) {
|
||||||
size_t const chunkSize = MIN(remainingSrcSize, avgChunkSize);
|
size_t const jobSize = MIN(remainingSrcSize, avgJobSize);
|
||||||
size_t const dstBufferCapacity = ZSTD_compressBound(chunkSize);
|
size_t const dstBufferCapacity = ZSTD_compressBound(jobSize);
|
||||||
buffer_t const dstAsBuffer = { (char*)dst + dstBufferPos, dstBufferCapacity };
|
buffer_t const dstAsBuffer = { (char*)dst + dstBufferPos, dstBufferCapacity };
|
||||||
buffer_t const dstBuffer = u < compressWithinDst ? dstAsBuffer : g_nullBuffer;
|
buffer_t const dstBuffer = u < compressWithinDst ? dstAsBuffer : g_nullBuffer;
|
||||||
size_t dictSize = u ? overlapSize : 0;
|
size_t dictSize = u ? overlapSize : 0;
|
||||||
|
|
||||||
mtctx->jobs[u].src = g_nullBuffer;
|
mtctx->jobs[u].prefix.start = srcStart + frameStartPos - dictSize;
|
||||||
mtctx->jobs[u].srcStart = srcStart + frameStartPos - dictSize;
|
mtctx->jobs[u].prefix.size = dictSize;
|
||||||
mtctx->jobs[u].prefixSize = dictSize;
|
mtctx->jobs[u].src.start = srcStart + frameStartPos;
|
||||||
mtctx->jobs[u].srcSize = chunkSize;
|
mtctx->jobs[u].src.size = jobSize; assert(jobSize > 0); /* avoid job.src.size == 0 */
|
||||||
|
mtctx->jobs[u].consumed = 0;
|
||||||
|
mtctx->jobs[u].cSize = 0;
|
||||||
mtctx->jobs[u].cdict = (u==0) ? cdict : NULL;
|
mtctx->jobs[u].cdict = (u==0) ? cdict : NULL;
|
||||||
mtctx->jobs[u].fullFrameSize = srcSize;
|
mtctx->jobs[u].fullFrameSize = srcSize;
|
||||||
mtctx->jobs[u].params = jobParams;
|
mtctx->jobs[u].params = jobParams;
|
||||||
/* do not calculate checksum within sections, but write it in header for first section */
|
/* do not calculate checksum within sections, but write it in header for first section */
|
||||||
if (u!=0) mtctx->jobs[u].params.fParams.checksumFlag = 0;
|
|
||||||
mtctx->jobs[u].dstBuff = dstBuffer;
|
mtctx->jobs[u].dstBuff = dstBuffer;
|
||||||
mtctx->jobs[u].cctxPool = mtctx->cctxPool;
|
mtctx->jobs[u].cctxPool = mtctx->cctxPool;
|
||||||
mtctx->jobs[u].bufPool = mtctx->bufPool;
|
mtctx->jobs[u].bufPool = mtctx->bufPool;
|
||||||
mtctx->jobs[u].firstChunk = (u==0);
|
mtctx->jobs[u].seqPool = mtctx->seqPool;
|
||||||
mtctx->jobs[u].lastChunk = (u==nbChunks-1);
|
mtctx->jobs[u].serial = &mtctx->serial;
|
||||||
mtctx->jobs[u].jobCompleted = 0;
|
mtctx->jobs[u].jobID = u;
|
||||||
mtctx->jobs[u].jobCompleted_mutex = &mtctx->jobCompleted_mutex;
|
mtctx->jobs[u].firstJob = (u==0);
|
||||||
mtctx->jobs[u].jobCompleted_cond = &mtctx->jobCompleted_cond;
|
mtctx->jobs[u].lastJob = (u==nbJobs-1);
|
||||||
|
|
||||||
if (params.fParams.checksumFlag) {
|
DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u (%u bytes)", u, (U32)jobSize);
|
||||||
XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize);
|
DEBUG_PRINTHEX(6, mtctx->jobs[u].prefix.start, 12);
|
||||||
}
|
POOL_add(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[u]);
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u (%u bytes)", u, (U32)chunkSize);
|
frameStartPos += jobSize;
|
||||||
DEBUG_PRINTHEX(6, mtctx->jobs[u].srcStart, 12);
|
|
||||||
POOL_add(mtctx->factory, ZSTDMT_compressChunk, &mtctx->jobs[u]);
|
|
||||||
|
|
||||||
frameStartPos += chunkSize;
|
|
||||||
dstBufferPos += dstBufferCapacity;
|
dstBufferPos += dstBufferCapacity;
|
||||||
remainingSrcSize -= chunkSize;
|
remainingSrcSize -= jobSize;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
/* collect result */
|
/* collect result */
|
||||||
{ size_t error = 0, dstPos = 0;
|
{ size_t error = 0, dstPos = 0;
|
||||||
unsigned chunkID;
|
unsigned jobID;
|
||||||
for (chunkID=0; chunkID<nbChunks; chunkID++) {
|
for (jobID=0; jobID<nbJobs; jobID++) {
|
||||||
DEBUGLOG(5, "waiting for chunk %u ", chunkID);
|
DEBUGLOG(5, "waiting for job %u ", jobID);
|
||||||
ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobCompleted_mutex);
|
ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex);
|
||||||
while (mtctx->jobs[chunkID].jobCompleted==0) {
|
while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) {
|
||||||
DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", chunkID);
|
DEBUGLOG(5, "waiting for jobCompleted signal from job %u", jobID);
|
||||||
ZSTD_pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex);
|
ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex);
|
||||||
}
|
}
|
||||||
ZSTD_pthread_mutex_unlock(&mtctx->jobCompleted_mutex);
|
ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex);
|
||||||
DEBUGLOG(5, "ready to write chunk %u ", chunkID);
|
DEBUGLOG(5, "ready to write job %u ", jobID);
|
||||||
|
|
||||||
mtctx->jobs[chunkID].srcStart = NULL;
|
{ size_t const cSize = mtctx->jobs[jobID].cSize;
|
||||||
{ size_t const cSize = mtctx->jobs[chunkID].cSize;
|
|
||||||
if (ZSTD_isError(cSize)) error = cSize;
|
if (ZSTD_isError(cSize)) error = cSize;
|
||||||
if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall);
|
if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall);
|
||||||
if (chunkID) { /* note : chunk 0 is written directly at dst, which is correct position */
|
if (jobID) { /* note : job 0 is written directly at dst, which is correct position */
|
||||||
if (!error)
|
if (!error)
|
||||||
memmove((char*)dst + dstPos, mtctx->jobs[chunkID].dstBuff.start, cSize); /* may overlap when chunk compressed within dst */
|
memmove((char*)dst + dstPos, mtctx->jobs[jobID].dstBuff.start, cSize); /* may overlap when job compressed within dst */
|
||||||
if (chunkID >= compressWithinDst) { /* chunk compressed into its own buffer, which must be released */
|
if (jobID >= compressWithinDst) { /* job compressed into its own buffer, which must be released */
|
||||||
DEBUGLOG(5, "releasing buffer %u>=%u", chunkID, compressWithinDst);
|
DEBUGLOG(5, "releasing buffer %u>=%u", jobID, compressWithinDst);
|
||||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[chunkID].dstBuff);
|
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
|
||||||
} }
|
} }
|
||||||
mtctx->jobs[chunkID].dstBuff = g_nullBuffer;
|
mtctx->jobs[jobID].dstBuff = g_nullBuffer;
|
||||||
|
mtctx->jobs[jobID].cSize = 0;
|
||||||
dstPos += cSize ;
|
dstPos += cSize ;
|
||||||
}
|
}
|
||||||
} /* for (chunkID=0; chunkID<nbChunks; chunkID++) */
|
} /* for (jobID=0; jobID<nbJobs; jobID++) */
|
||||||
|
|
||||||
DEBUGLOG(4, "checksumFlag : %u ", params.fParams.checksumFlag);
|
DEBUGLOG(4, "checksumFlag : %u ", params.fParams.checksumFlag);
|
||||||
if (params.fParams.checksumFlag) {
|
if (params.fParams.checksumFlag) {
|
||||||
U32 const checksum = (U32)XXH64_digest(&xxh64);
|
U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
|
||||||
if (dstPos + 4 > dstCapacity) {
|
if (dstPos + 4 > dstCapacity) {
|
||||||
error = ERROR(dstSize_tooSmall);
|
error = ERROR(dstSize_tooSmall);
|
||||||
} else {
|
} else {
|
||||||
@@ -756,7 +1185,7 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
|
|||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const ZSTD_CDict* cdict,
|
const ZSTD_CDict* cdict,
|
||||||
ZSTD_parameters const params,
|
ZSTD_parameters params,
|
||||||
unsigned overlapLog)
|
unsigned overlapLog)
|
||||||
{
|
{
|
||||||
ZSTD_CCtx_params cctxParams = mtctx->params;
|
ZSTD_CCtx_params cctxParams = mtctx->params;
|
||||||
@@ -787,66 +1216,104 @@ size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
|
|||||||
/* ====================================== */
|
/* ====================================== */
|
||||||
|
|
||||||
size_t ZSTDMT_initCStream_internal(
|
size_t ZSTDMT_initCStream_internal(
|
||||||
ZSTDMT_CCtx* zcs,
|
ZSTDMT_CCtx* mtctx,
|
||||||
const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
|
const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
|
||||||
const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
|
const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
|
||||||
unsigned long long pledgedSrcSize)
|
unsigned long long pledgedSrcSize)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
|
DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u, nbWorkers=%u, cctxPool=%u, disableLiteralCompression=%i)",
|
||||||
|
(U32)pledgedSrcSize, params.nbWorkers, mtctx->cctxPool->totalCCtx, params.disableLiteralCompression);
|
||||||
/* params are supposed to be fully validated at this point */
|
/* params are supposed to be fully validated at this point */
|
||||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||||
assert(zcs->cctxPool->totalCCtx == params.nbThreads);
|
assert(mtctx->cctxPool->totalCCtx == params.nbWorkers);
|
||||||
zcs->singleThreaded = (params.nbThreads==1) | (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */
|
|
||||||
|
|
||||||
if (zcs->singleThreaded) {
|
/* init */
|
||||||
ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params);
|
if (params.jobSize == 0) {
|
||||||
DEBUGLOG(4, "single thread mode");
|
params.jobSize = 1U << ZSTDMT_computeTargetJobLog(params);
|
||||||
assert(singleThreadParams.nbThreads == 0);
|
}
|
||||||
return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0],
|
if (params.jobSize > ZSTDMT_JOBSIZE_MAX) params.jobSize = ZSTDMT_JOBSIZE_MAX;
|
||||||
|
|
||||||
|
mtctx->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */
|
||||||
|
if (mtctx->singleBlockingThread) {
|
||||||
|
ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(params);
|
||||||
|
DEBUGLOG(5, "ZSTDMT_initCStream_internal: switch to single blocking thread mode");
|
||||||
|
assert(singleThreadParams.nbWorkers == 0);
|
||||||
|
return ZSTD_initCStream_internal(mtctx->cctxPool->cctx[0],
|
||||||
dict, dictSize, cdict,
|
dict, dictSize, cdict,
|
||||||
singleThreadParams, pledgedSrcSize);
|
singleThreadParams, pledgedSrcSize);
|
||||||
}
|
}
|
||||||
DEBUGLOG(4, "multi-threading mode (%u threads)", params.nbThreads);
|
|
||||||
|
|
||||||
if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */
|
DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers);
|
||||||
ZSTDMT_waitForAllJobsCompleted(zcs);
|
|
||||||
ZSTDMT_releaseAllJobResources(zcs);
|
if (mtctx->allJobsCompleted == 0) { /* previous compression not correctly finished */
|
||||||
zcs->allJobsCompleted = 1;
|
ZSTDMT_waitForAllJobsCompleted(mtctx);
|
||||||
|
ZSTDMT_releaseAllJobResources(mtctx);
|
||||||
|
mtctx->allJobsCompleted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
zcs->params = params;
|
mtctx->params = params;
|
||||||
zcs->frameContentSize = pledgedSrcSize;
|
mtctx->frameContentSize = pledgedSrcSize;
|
||||||
if (dict) {
|
if (dict) {
|
||||||
ZSTD_freeCDict(zcs->cdictLocal);
|
ZSTD_freeCDict(mtctx->cdictLocal);
|
||||||
zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
|
mtctx->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
|
||||||
ZSTD_dlm_byCopy, dictMode, /* note : a loadPrefix becomes an internal CDict */
|
ZSTD_dlm_byCopy, dictContentType, /* note : a loadPrefix becomes an internal CDict */
|
||||||
params.cParams, zcs->cMem);
|
params.cParams, mtctx->cMem);
|
||||||
zcs->cdict = zcs->cdictLocal;
|
mtctx->cdict = mtctx->cdictLocal;
|
||||||
if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
|
if (mtctx->cdictLocal == NULL) return ERROR(memory_allocation);
|
||||||
} else {
|
} else {
|
||||||
ZSTD_freeCDict(zcs->cdictLocal);
|
ZSTD_freeCDict(mtctx->cdictLocal);
|
||||||
zcs->cdictLocal = NULL;
|
mtctx->cdictLocal = NULL;
|
||||||
zcs->cdict = cdict;
|
mtctx->cdict = cdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(params.overlapSizeLog <= 9);
|
mtctx->targetPrefixSize = (size_t)1 << ZSTDMT_computeOverlapLog(params);
|
||||||
zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
|
DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(mtctx->targetPrefixSize>>10));
|
||||||
DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(zcs->targetDictSize>>10));
|
mtctx->targetSectionSize = params.jobSize;
|
||||||
zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2);
|
if (mtctx->targetSectionSize < ZSTDMT_JOBSIZE_MIN) mtctx->targetSectionSize = ZSTDMT_JOBSIZE_MIN;
|
||||||
if (zcs->targetSectionSize < ZSTDMT_JOBSIZE_MIN) zcs->targetSectionSize = ZSTDMT_JOBSIZE_MIN;
|
if (mtctx->targetSectionSize < mtctx->targetPrefixSize) mtctx->targetSectionSize = mtctx->targetPrefixSize; /* job size must be >= overlap size */
|
||||||
if (zcs->targetSectionSize < zcs->targetDictSize) zcs->targetSectionSize = zcs->targetDictSize; /* job size must be >= overlap size */
|
DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(mtctx->targetSectionSize>>10), params.jobSize);
|
||||||
DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(zcs->targetSectionSize>>10), params.jobSize);
|
DEBUGLOG(4, "inBuff Size : %u KB", (U32)(mtctx->targetSectionSize>>10));
|
||||||
zcs->inBuffSize = zcs->targetDictSize + zcs->targetSectionSize;
|
ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize));
|
||||||
DEBUGLOG(4, "inBuff Size : %u KB", (U32)(zcs->inBuffSize>>10));
|
{
|
||||||
ZSTDMT_setBufferSize(zcs->bufPool, MAX(zcs->inBuffSize, ZSTD_compressBound(zcs->targetSectionSize)) );
|
/* If ldm is enabled we need windowSize space. */
|
||||||
zcs->inBuff.buffer = g_nullBuffer;
|
size_t const windowSize = mtctx->params.ldmParams.enableLdm ? (1U << mtctx->params.cParams.windowLog) : 0;
|
||||||
zcs->dictSize = 0;
|
/* Two buffers of slack, plus extra space for the overlap
|
||||||
zcs->doneJobID = 0;
|
* This is the minimum slack that LDM works with. One extra because
|
||||||
zcs->nextJobID = 0;
|
* flush might waste up to targetSectionSize-1 bytes. Another extra
|
||||||
zcs->frameEnded = 0;
|
* for the overlap (if > 0), then one to fill which doesn't overlap
|
||||||
zcs->allJobsCompleted = 0;
|
* with the LDM window.
|
||||||
if (params.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0);
|
*/
|
||||||
|
size_t const nbSlackBuffers = 2 + (mtctx->targetPrefixSize > 0);
|
||||||
|
size_t const slackSize = mtctx->targetSectionSize * nbSlackBuffers;
|
||||||
|
/* Compute the total size, and always have enough slack */
|
||||||
|
size_t const nbWorkers = MAX(mtctx->params.nbWorkers, 1);
|
||||||
|
size_t const sectionsSize = mtctx->targetSectionSize * nbWorkers;
|
||||||
|
size_t const capacity = MAX(windowSize, sectionsSize) + slackSize;
|
||||||
|
if (mtctx->roundBuff.capacity < capacity) {
|
||||||
|
if (mtctx->roundBuff.buffer)
|
||||||
|
ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
|
||||||
|
mtctx->roundBuff.buffer = (BYTE*)ZSTD_malloc(capacity, mtctx->cMem);
|
||||||
|
if (mtctx->roundBuff.buffer == NULL) {
|
||||||
|
mtctx->roundBuff.capacity = 0;
|
||||||
|
return ERROR(memory_allocation);
|
||||||
|
}
|
||||||
|
mtctx->roundBuff.capacity = capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUGLOG(4, "roundBuff capacity : %u KB", (U32)(mtctx->roundBuff.capacity>>10));
|
||||||
|
mtctx->roundBuff.pos = 0;
|
||||||
|
mtctx->inBuff.buffer = g_nullBuffer;
|
||||||
|
mtctx->inBuff.filled = 0;
|
||||||
|
mtctx->inBuff.prefix = kNullRange;
|
||||||
|
mtctx->doneJobID = 0;
|
||||||
|
mtctx->nextJobID = 0;
|
||||||
|
mtctx->frameEnded = 0;
|
||||||
|
mtctx->allJobsCompleted = 0;
|
||||||
|
mtctx->consumed = 0;
|
||||||
|
mtctx->produced = 0;
|
||||||
|
if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params))
|
||||||
|
return ERROR(memory_allocation);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,11 +1322,11 @@ size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
|
|||||||
ZSTD_parameters params,
|
ZSTD_parameters params,
|
||||||
unsigned long long pledgedSrcSize)
|
unsigned long long pledgedSrcSize)
|
||||||
{
|
{
|
||||||
ZSTD_CCtx_params cctxParams = mtctx->params;
|
ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */
|
||||||
DEBUGLOG(5, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
|
DEBUGLOG(4, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
|
||||||
cctxParams.cParams = params.cParams;
|
cctxParams.cParams = params.cParams;
|
||||||
cctxParams.fParams = params.fParams;
|
cctxParams.fParams = params.fParams;
|
||||||
return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dm_auto, NULL,
|
return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dct_auto, NULL,
|
||||||
cctxParams, pledgedSrcSize);
|
cctxParams, pledgedSrcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,10 +1336,10 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
|
|||||||
unsigned long long pledgedSrcSize)
|
unsigned long long pledgedSrcSize)
|
||||||
{
|
{
|
||||||
ZSTD_CCtx_params cctxParams = mtctx->params;
|
ZSTD_CCtx_params cctxParams = mtctx->params;
|
||||||
|
if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */
|
||||||
cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict);
|
cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict);
|
||||||
cctxParams.fParams = fParams;
|
cctxParams.fParams = fParams;
|
||||||
if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */
|
return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dct_auto, cdict,
|
||||||
return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dm_auto, cdict,
|
|
||||||
cctxParams, pledgedSrcSize);
|
cctxParams, pledgedSrcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,149 +1348,359 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
|
|||||||
* pledgedSrcSize can be zero == unknown (for the time being)
|
* pledgedSrcSize can be zero == unknown (for the time being)
|
||||||
* prefer using ZSTD_CONTENTSIZE_UNKNOWN,
|
* prefer using ZSTD_CONTENTSIZE_UNKNOWN,
|
||||||
* as `0` might mean "empty" in the future */
|
* as `0` might mean "empty" in the future */
|
||||||
size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize)
|
size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize)
|
||||||
{
|
{
|
||||||
if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
|
if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
|
||||||
if (zcs->params.nbThreads==1)
|
return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, 0, mtctx->params,
|
||||||
return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize);
|
|
||||||
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, 0, zcs->params,
|
|
||||||
pledgedSrcSize);
|
pledgedSrcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) {
|
size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, 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;
|
ZSTD_CCtx_params cctxParams = mtctx->params; /* retrieve sticky params */
|
||||||
|
DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel);
|
||||||
cctxParams.cParams = params.cParams;
|
cctxParams.cParams = params.cParams;
|
||||||
cctxParams.fParams = params.fParams;
|
cctxParams.fParams = params.fParams;
|
||||||
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
|
return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsigned endFrame)
|
/* ZSTDMT_writeLastEmptyBlock()
|
||||||
|
* Write a single empty block with an end-of-frame to finish a frame.
|
||||||
|
* Job must be created from streaming variant.
|
||||||
|
* This function is always successfull if expected conditions are fulfilled.
|
||||||
|
*/
|
||||||
|
static void ZSTDMT_writeLastEmptyBlock(ZSTDMT_jobDescription* job)
|
||||||
{
|
{
|
||||||
unsigned const jobID = zcs->nextJobID & zcs->jobIDMask;
|
assert(job->lastJob == 1);
|
||||||
|
assert(job->src.size == 0); /* last job is empty -> will be simplified into a last empty block */
|
||||||
DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ",
|
assert(job->firstJob == 0); /* cannot be first job, as it also needs to create frame header */
|
||||||
zcs->nextJobID, (U32)srcSize, (U32)zcs->dictSize);
|
assert(job->dstBuff.start == NULL); /* invoked from streaming variant only (otherwise, dstBuff might be user's output) */
|
||||||
zcs->jobs[jobID].src = zcs->inBuff.buffer;
|
job->dstBuff = ZSTDMT_getBuffer(job->bufPool);
|
||||||
zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start;
|
if (job->dstBuff.start == NULL) {
|
||||||
zcs->jobs[jobID].srcSize = srcSize;
|
job->cSize = ERROR(memory_allocation);
|
||||||
zcs->jobs[jobID].prefixSize = zcs->dictSize;
|
return;
|
||||||
assert(zcs->inBuff.filled >= srcSize + zcs->dictSize);
|
|
||||||
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;
|
|
||||||
zcs->jobs[jobID].cdict = zcs->nextJobID==0 ? zcs->cdict : NULL;
|
|
||||||
zcs->jobs[jobID].fullFrameSize = zcs->frameContentSize;
|
|
||||||
zcs->jobs[jobID].dstBuff = g_nullBuffer;
|
|
||||||
zcs->jobs[jobID].cctxPool = zcs->cctxPool;
|
|
||||||
zcs->jobs[jobID].bufPool = zcs->bufPool;
|
|
||||||
zcs->jobs[jobID].firstChunk = (zcs->nextJobID==0);
|
|
||||||
zcs->jobs[jobID].lastChunk = endFrame;
|
|
||||||
zcs->jobs[jobID].jobCompleted = 0;
|
|
||||||
zcs->jobs[jobID].dstFlushed = 0;
|
|
||||||
zcs->jobs[jobID].jobCompleted_mutex = &zcs->jobCompleted_mutex;
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* get a new buffer for next input */
|
|
||||||
if (!endFrame) {
|
|
||||||
size_t const newDictSize = MIN(srcSize + zcs->dictSize, zcs->targetDictSize);
|
|
||||||
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;
|
|
||||||
zcs->nextJobID++;
|
|
||||||
ZSTDMT_waitForAllJobsCompleted(zcs);
|
|
||||||
ZSTDMT_releaseAllJobResources(zcs);
|
|
||||||
return ERROR(memory_allocation);
|
|
||||||
}
|
}
|
||||||
zcs->inBuff.filled -= srcSize + zcs->dictSize - newDictSize;
|
assert(job->dstBuff.capacity >= ZSTD_blockHeaderSize); /* no buffer should ever be that small */
|
||||||
memmove(zcs->inBuff.buffer.start,
|
job->src = kNullRange;
|
||||||
(const char*)zcs->jobs[jobID].srcStart + zcs->dictSize + srcSize - newDictSize,
|
job->cSize = ZSTD_writeLastEmptyBlock(job->dstBuff.start, job->dstBuff.capacity);
|
||||||
zcs->inBuff.filled);
|
assert(!ZSTD_isError(job->cSize));
|
||||||
zcs->dictSize = newDictSize;
|
assert(job->consumed == 0);
|
||||||
} else { /* if (endFrame==1) */
|
}
|
||||||
zcs->inBuff.buffer = g_nullBuffer;
|
|
||||||
zcs->inBuff.filled = 0;
|
static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* mtctx, size_t srcSize, ZSTD_EndDirective endOp)
|
||||||
zcs->dictSize = 0;
|
{
|
||||||
zcs->frameEnded = 1;
|
unsigned const jobID = mtctx->nextJobID & mtctx->jobIDMask;
|
||||||
if (zcs->nextJobID == 0) {
|
int const endFrame = (endOp == ZSTD_e_end);
|
||||||
/* single chunk exception : checksum is calculated directly within worker thread */
|
|
||||||
zcs->params.fParams.checksumFlag = 0;
|
if (mtctx->nextJobID > mtctx->doneJobID + mtctx->jobIDMask) {
|
||||||
|
DEBUGLOG(5, "ZSTDMT_createCompressionJob: will not create new job : table is full");
|
||||||
|
assert((mtctx->nextJobID & mtctx->jobIDMask) == (mtctx->doneJobID & mtctx->jobIDMask));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mtctx->jobReady) {
|
||||||
|
BYTE const* src = (BYTE const*)mtctx->inBuff.buffer.start;
|
||||||
|
DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ",
|
||||||
|
mtctx->nextJobID, (U32)srcSize, (U32)mtctx->inBuff.prefix.size);
|
||||||
|
mtctx->jobs[jobID].src.start = src;
|
||||||
|
mtctx->jobs[jobID].src.size = srcSize;
|
||||||
|
assert(mtctx->inBuff.filled >= srcSize);
|
||||||
|
mtctx->jobs[jobID].prefix = mtctx->inBuff.prefix;
|
||||||
|
mtctx->jobs[jobID].consumed = 0;
|
||||||
|
mtctx->jobs[jobID].cSize = 0;
|
||||||
|
mtctx->jobs[jobID].params = mtctx->params;
|
||||||
|
mtctx->jobs[jobID].cdict = mtctx->nextJobID==0 ? mtctx->cdict : NULL;
|
||||||
|
mtctx->jobs[jobID].fullFrameSize = mtctx->frameContentSize;
|
||||||
|
mtctx->jobs[jobID].dstBuff = g_nullBuffer;
|
||||||
|
mtctx->jobs[jobID].cctxPool = mtctx->cctxPool;
|
||||||
|
mtctx->jobs[jobID].bufPool = mtctx->bufPool;
|
||||||
|
mtctx->jobs[jobID].seqPool = mtctx->seqPool;
|
||||||
|
mtctx->jobs[jobID].serial = &mtctx->serial;
|
||||||
|
mtctx->jobs[jobID].jobID = mtctx->nextJobID;
|
||||||
|
mtctx->jobs[jobID].firstJob = (mtctx->nextJobID==0);
|
||||||
|
mtctx->jobs[jobID].lastJob = endFrame;
|
||||||
|
mtctx->jobs[jobID].frameChecksumNeeded = endFrame && (mtctx->nextJobID>0) && mtctx->params.fParams.checksumFlag;
|
||||||
|
mtctx->jobs[jobID].dstFlushed = 0;
|
||||||
|
|
||||||
|
/* Update the round buffer pos and clear the input buffer to be reset */
|
||||||
|
mtctx->roundBuff.pos += srcSize;
|
||||||
|
mtctx->inBuff.buffer = g_nullBuffer;
|
||||||
|
mtctx->inBuff.filled = 0;
|
||||||
|
/* Set the prefix */
|
||||||
|
if (!endFrame) {
|
||||||
|
size_t const newPrefixSize = MIN(srcSize, mtctx->targetPrefixSize);
|
||||||
|
mtctx->inBuff.prefix.start = src + srcSize - newPrefixSize;
|
||||||
|
mtctx->inBuff.prefix.size = newPrefixSize;
|
||||||
|
} else { /* endFrame==1 => no need for another input buffer */
|
||||||
|
mtctx->inBuff.prefix = kNullRange;
|
||||||
|
mtctx->frameEnded = endFrame;
|
||||||
|
if (mtctx->nextJobID == 0) {
|
||||||
|
/* single job exception : checksum is already calculated directly within worker thread */
|
||||||
|
mtctx->params.fParams.checksumFlag = 0;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes (end:%u) (note : doneJob = %u=>%u)",
|
if ( (srcSize == 0)
|
||||||
zcs->nextJobID,
|
&& (mtctx->nextJobID>0)/*single job must also write frame header*/ ) {
|
||||||
(U32)zcs->jobs[jobID].srcSize,
|
DEBUGLOG(5, "ZSTDMT_createCompressionJob: creating a last empty block to end frame");
|
||||||
zcs->jobs[jobID].lastChunk,
|
assert(endOp == ZSTD_e_end); /* only possible case : need to end the frame with an empty last block */
|
||||||
zcs->doneJobID,
|
ZSTDMT_writeLastEmptyBlock(mtctx->jobs + jobID);
|
||||||
zcs->doneJobID & zcs->jobIDMask);
|
mtctx->nextJobID++;
|
||||||
POOL_add(zcs->factory, ZSTDMT_compressChunk, &zcs->jobs[jobID]); /* this call is blocking when thread worker pool is exhausted */
|
return 0;
|
||||||
zcs->nextJobID++;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes (end:%u, jobNb == %u (mod:%u))",
|
||||||
|
mtctx->nextJobID,
|
||||||
|
(U32)mtctx->jobs[jobID].src.size,
|
||||||
|
mtctx->jobs[jobID].lastJob,
|
||||||
|
mtctx->nextJobID,
|
||||||
|
jobID);
|
||||||
|
if (POOL_tryAdd(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[jobID])) {
|
||||||
|
mtctx->nextJobID++;
|
||||||
|
mtctx->jobReady = 0;
|
||||||
|
} else {
|
||||||
|
DEBUGLOG(5, "ZSTDMT_createCompressionJob: no worker available for job %u", mtctx->nextJobID);
|
||||||
|
mtctx->jobReady = 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ZSTDMT_flushNextJob() :
|
/*! ZSTDMT_flushProduced() :
|
||||||
* output : will be updated with amount of data flushed .
|
* `output` : `pos` will be updated with amount of data flushed .
|
||||||
* blockToFlush : if >0, the function will block and wait if there is no data available to flush .
|
* `blockToFlush` : if >0, the function will block and wait if there is no data available to flush .
|
||||||
* @return : amount of data remaining within internal buffer, 1 if unknown but > 0, 0 if no more, or an error code */
|
* @return : amount of data remaining within internal buffer, 0 if no more, 1 if unknown but > 0, or an error code */
|
||||||
static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned blockToFlush)
|
static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned blockToFlush, ZSTD_EndDirective end)
|
||||||
{
|
{
|
||||||
unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask;
|
unsigned const wJobID = mtctx->doneJobID & mtctx->jobIDMask;
|
||||||
DEBUGLOG(5, "ZSTDMT_flushNextJob");
|
DEBUGLOG(5, "ZSTDMT_flushProduced (blocking:%u , job %u <= %u)",
|
||||||
if (zcs->doneJobID == zcs->nextJobID) return 0; /* all flushed ! */
|
blockToFlush, mtctx->doneJobID, mtctx->nextJobID);
|
||||||
ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
|
assert(output->size >= output->pos);
|
||||||
while (zcs->jobs[wJobID].jobCompleted==0) {
|
|
||||||
DEBUGLOG(5, "waiting for jobCompleted signal from job %u", zcs->doneJobID);
|
ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex);
|
||||||
if (!blockToFlush) { ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex); return 0; } /* nothing ready to be flushed => skip */
|
if ( blockToFlush
|
||||||
ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); /* block when nothing available to flush */
|
&& (mtctx->doneJobID < mtctx->nextJobID) ) {
|
||||||
|
assert(mtctx->jobs[wJobID].dstFlushed <= mtctx->jobs[wJobID].cSize);
|
||||||
|
while (mtctx->jobs[wJobID].dstFlushed == mtctx->jobs[wJobID].cSize) { /* nothing to flush */
|
||||||
|
if (mtctx->jobs[wJobID].consumed == mtctx->jobs[wJobID].src.size) {
|
||||||
|
DEBUGLOG(5, "job %u is completely consumed (%u == %u) => don't wait for cond, there will be none",
|
||||||
|
mtctx->doneJobID, (U32)mtctx->jobs[wJobID].consumed, (U32)mtctx->jobs[wJobID].src.size);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex);
|
DEBUGLOG(5, "waiting for something to flush from job %u (currently flushed: %u bytes)",
|
||||||
/* compression job completed : output can be flushed */
|
mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed);
|
||||||
{ ZSTDMT_jobDescription job = zcs->jobs[wJobID];
|
ZSTD_pthread_cond_wait(&mtctx->jobs[wJobID].job_cond, &mtctx->jobs[wJobID].job_mutex); /* block when nothing to flush but some to come */
|
||||||
if (!job.jobScanned) {
|
|
||||||
if (ZSTD_isError(job.cSize)) {
|
|
||||||
DEBUGLOG(5, "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);
|
|
||||||
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);
|
|
||||||
MEM_writeLE32((char*)job.dstBuff.start + job.cSize, checksum);
|
|
||||||
job.cSize += 4;
|
|
||||||
zcs->jobs[wJobID].cSize += 4;
|
|
||||||
} }
|
} }
|
||||||
zcs->jobs[wJobID].jobScanned = 1;
|
|
||||||
|
/* try to flush something */
|
||||||
|
{ size_t cSize = mtctx->jobs[wJobID].cSize; /* shared */
|
||||||
|
size_t const srcConsumed = mtctx->jobs[wJobID].consumed; /* shared */
|
||||||
|
size_t const srcSize = mtctx->jobs[wJobID].src.size; /* read-only, could be done after mutex lock, but no-declaration-after-statement */
|
||||||
|
ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
|
||||||
|
if (ZSTD_isError(cSize)) {
|
||||||
|
DEBUGLOG(5, "ZSTDMT_flushProduced: job %u : compression error detected : %s",
|
||||||
|
mtctx->doneJobID, ZSTD_getErrorName(cSize));
|
||||||
|
ZSTDMT_waitForAllJobsCompleted(mtctx);
|
||||||
|
ZSTDMT_releaseAllJobResources(mtctx);
|
||||||
|
return cSize;
|
||||||
}
|
}
|
||||||
{ size_t const toWrite = MIN(job.cSize - job.dstFlushed, output->size - output->pos);
|
/* add frame checksum if necessary (can only happen once) */
|
||||||
DEBUGLOG(5, "Flushing %u bytes from job %u ", (U32)toWrite, zcs->doneJobID);
|
assert(srcConsumed <= srcSize);
|
||||||
memcpy((char*)output->dst + output->pos, (const char*)job.dstBuff.start + job.dstFlushed, toWrite);
|
if ( (srcConsumed == srcSize) /* job completed -> worker no longer active */
|
||||||
output->pos += toWrite;
|
&& mtctx->jobs[wJobID].frameChecksumNeeded ) {
|
||||||
job.dstFlushed += toWrite;
|
U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
|
||||||
|
DEBUGLOG(4, "ZSTDMT_flushProduced: writing checksum : %08X \n", checksum);
|
||||||
|
MEM_writeLE32((char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].cSize, checksum);
|
||||||
|
cSize += 4;
|
||||||
|
mtctx->jobs[wJobID].cSize += 4; /* can write this shared value, as worker is no longer active */
|
||||||
|
mtctx->jobs[wJobID].frameChecksumNeeded = 0;
|
||||||
}
|
}
|
||||||
if (job.dstFlushed == job.cSize) { /* output buffer fully flushed => move to next one */
|
if (cSize > 0) { /* compression is ongoing or completed */
|
||||||
ZSTDMT_releaseBuffer(zcs->bufPool, job.dstBuff);
|
size_t const toFlush = MIN(cSize - mtctx->jobs[wJobID].dstFlushed, output->size - output->pos);
|
||||||
zcs->jobs[wJobID].dstBuff = g_nullBuffer;
|
DEBUGLOG(5, "ZSTDMT_flushProduced: Flushing %u bytes from job %u (completion:%u/%u, generated:%u)",
|
||||||
zcs->jobs[wJobID].jobCompleted = 0;
|
(U32)toFlush, mtctx->doneJobID, (U32)srcConsumed, (U32)srcSize, (U32)cSize);
|
||||||
zcs->doneJobID++;
|
assert(mtctx->doneJobID < mtctx->nextJobID);
|
||||||
} else {
|
assert(cSize >= mtctx->jobs[wJobID].dstFlushed);
|
||||||
zcs->jobs[wJobID].dstFlushed = job.dstFlushed;
|
assert(mtctx->jobs[wJobID].dstBuff.start != NULL);
|
||||||
}
|
memcpy((char*)output->dst + output->pos,
|
||||||
/* return value : how many bytes left in buffer ; fake it to 1 if unknown but >0 */
|
(const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
|
||||||
if (job.cSize > job.dstFlushed) return (job.cSize - job.dstFlushed);
|
toFlush);
|
||||||
if (zcs->doneJobID < zcs->nextJobID) return 1; /* still some buffer to flush */
|
output->pos += toFlush;
|
||||||
zcs->allJobsCompleted = zcs->frameEnded; /* frame completed and entirely flushed */
|
mtctx->jobs[wJobID].dstFlushed += toFlush; /* can write : this value is only used by mtctx */
|
||||||
return 0; /* everything flushed */
|
|
||||||
|
if ( (srcConsumed == srcSize) /* job completed */
|
||||||
|
&& (mtctx->jobs[wJobID].dstFlushed == cSize) ) { /* output buffer fully flushed => free this job position */
|
||||||
|
DEBUGLOG(5, "Job %u completed (%u bytes), moving to next one",
|
||||||
|
mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed);
|
||||||
|
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[wJobID].dstBuff);
|
||||||
|
mtctx->jobs[wJobID].dstBuff = g_nullBuffer;
|
||||||
|
mtctx->jobs[wJobID].cSize = 0; /* ensure this job slot is considered "not started" in future check */
|
||||||
|
mtctx->consumed += srcSize;
|
||||||
|
mtctx->produced += cSize;
|
||||||
|
mtctx->doneJobID++;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
/* return value : how many bytes left in buffer ; fake it to 1 when unknown but >0 */
|
||||||
|
if (cSize > mtctx->jobs[wJobID].dstFlushed) return (cSize - mtctx->jobs[wJobID].dstFlushed);
|
||||||
|
if (srcSize > srcConsumed) return 1; /* current job not completely compressed */
|
||||||
|
}
|
||||||
|
if (mtctx->doneJobID < mtctx->nextJobID) return 1; /* some more jobs ongoing */
|
||||||
|
if (mtctx->jobReady) return 1; /* one job is ready to push, just not yet in the list */
|
||||||
|
if (mtctx->inBuff.filled > 0) return 1; /* input is not empty, and still needs to be converted into a job */
|
||||||
|
mtctx->allJobsCompleted = mtctx->frameEnded; /* all jobs are entirely flushed => if this one is last one, frame is completed */
|
||||||
|
if (end == ZSTD_e_end) return !mtctx->frameEnded; /* for ZSTD_e_end, question becomes : is frame completed ? instead of : are internal buffers fully flushed ? */
|
||||||
|
return 0; /* internal buffers fully flushed */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the range of data used by the earliest job that is not yet complete.
|
||||||
|
* If the data of the first job is broken up into two segments, we cover both
|
||||||
|
* sections.
|
||||||
|
*/
|
||||||
|
static range_t ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx)
|
||||||
|
{
|
||||||
|
unsigned const firstJobID = mtctx->doneJobID;
|
||||||
|
unsigned const lastJobID = mtctx->nextJobID;
|
||||||
|
unsigned jobID;
|
||||||
|
|
||||||
|
for (jobID = firstJobID; jobID < lastJobID; ++jobID) {
|
||||||
|
unsigned const wJobID = jobID & mtctx->jobIDMask;
|
||||||
|
size_t consumed;
|
||||||
|
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex);
|
||||||
|
consumed = mtctx->jobs[wJobID].consumed;
|
||||||
|
ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
|
||||||
|
|
||||||
|
if (consumed < mtctx->jobs[wJobID].src.size) {
|
||||||
|
range_t range = mtctx->jobs[wJobID].prefix;
|
||||||
|
if (range.size == 0) {
|
||||||
|
/* Empty prefix */
|
||||||
|
range = mtctx->jobs[wJobID].src;
|
||||||
|
}
|
||||||
|
/* Job source in multiple segments not supported yet */
|
||||||
|
assert(range.start <= mtctx->jobs[wJobID].src.start);
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kNullRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns non-zero iff buffer and range overlap.
|
||||||
|
*/
|
||||||
|
static int ZSTDMT_isOverlapped(buffer_t buffer, range_t range)
|
||||||
|
{
|
||||||
|
BYTE const* const bufferStart = (BYTE const*)buffer.start;
|
||||||
|
BYTE const* const bufferEnd = bufferStart + buffer.capacity;
|
||||||
|
BYTE const* const rangeStart = (BYTE const*)range.start;
|
||||||
|
BYTE const* const rangeEnd = rangeStart + range.size;
|
||||||
|
|
||||||
|
if (rangeStart == NULL || bufferStart == NULL)
|
||||||
|
return 0;
|
||||||
|
/* Empty ranges cannot overlap */
|
||||||
|
if (bufferStart == bufferEnd || rangeStart == rangeEnd)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return bufferStart < rangeEnd && rangeStart < bufferEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window)
|
||||||
|
{
|
||||||
|
range_t extDict;
|
||||||
|
range_t prefix;
|
||||||
|
|
||||||
|
extDict.start = window.dictBase + window.lowLimit;
|
||||||
|
extDict.size = window.dictLimit - window.lowLimit;
|
||||||
|
|
||||||
|
prefix.start = window.base + window.dictLimit;
|
||||||
|
prefix.size = window.nextSrc - (window.base + window.dictLimit);
|
||||||
|
DEBUGLOG(5, "extDict [0x%zx, 0x%zx)",
|
||||||
|
(size_t)extDict.start,
|
||||||
|
(size_t)extDict.start + extDict.size);
|
||||||
|
DEBUGLOG(5, "prefix [0x%zx, 0x%zx)",
|
||||||
|
(size_t)prefix.start,
|
||||||
|
(size_t)prefix.start + prefix.size);
|
||||||
|
|
||||||
|
return ZSTDMT_isOverlapped(buffer, extDict)
|
||||||
|
|| ZSTDMT_isOverlapped(buffer, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, buffer_t buffer)
|
||||||
|
{
|
||||||
|
if (mtctx->params.ldmParams.enableLdm) {
|
||||||
|
ZSTD_pthread_mutex_t* mutex = &mtctx->serial.ldmWindowMutex;
|
||||||
|
DEBUGLOG(5, "source [0x%zx, 0x%zx)",
|
||||||
|
(size_t)buffer.start,
|
||||||
|
(size_t)buffer.start + buffer.capacity);
|
||||||
|
ZSTD_PTHREAD_MUTEX_LOCK(mutex);
|
||||||
|
while (ZSTDMT_doesOverlapWindow(buffer, mtctx->serial.ldmWindow)) {
|
||||||
|
DEBUGLOG(6, "Waiting for LDM to finish...");
|
||||||
|
ZSTD_pthread_cond_wait(&mtctx->serial.ldmWindowCond, mutex);
|
||||||
|
}
|
||||||
|
DEBUGLOG(6, "Done waiting for LDM to finish");
|
||||||
|
ZSTD_pthread_mutex_unlock(mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to set the inBuff to the next section to fill.
|
||||||
|
* If any part of the new section is still in use we give up.
|
||||||
|
* Returns non-zero if the buffer is filled.
|
||||||
|
*/
|
||||||
|
static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx)
|
||||||
|
{
|
||||||
|
range_t const inUse = ZSTDMT_getInputDataInUse(mtctx);
|
||||||
|
size_t const spaceLeft = mtctx->roundBuff.capacity - mtctx->roundBuff.pos;
|
||||||
|
size_t const target = mtctx->targetSectionSize;
|
||||||
|
buffer_t buffer;
|
||||||
|
|
||||||
|
assert(mtctx->inBuff.buffer.start == NULL);
|
||||||
|
assert(mtctx->roundBuff.capacity >= target);
|
||||||
|
|
||||||
|
if (spaceLeft < target) {
|
||||||
|
/* ZSTD_invalidateRepCodes() doesn't work for extDict variants.
|
||||||
|
* Simply copy the prefix to the beginning in that case.
|
||||||
|
*/
|
||||||
|
BYTE* const start = (BYTE*)mtctx->roundBuff.buffer;
|
||||||
|
size_t const prefixSize = mtctx->inBuff.prefix.size;
|
||||||
|
|
||||||
|
buffer.start = start;
|
||||||
|
buffer.capacity = prefixSize;
|
||||||
|
if (ZSTDMT_isOverlapped(buffer, inUse)) {
|
||||||
|
DEBUGLOG(6, "Waiting for buffer...");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ZSTDMT_waitForLdmComplete(mtctx, buffer);
|
||||||
|
memmove(start, mtctx->inBuff.prefix.start, prefixSize);
|
||||||
|
mtctx->inBuff.prefix.start = start;
|
||||||
|
mtctx->roundBuff.pos = prefixSize;
|
||||||
|
}
|
||||||
|
buffer.start = mtctx->roundBuff.buffer + mtctx->roundBuff.pos;
|
||||||
|
buffer.capacity = target;
|
||||||
|
|
||||||
|
if (ZSTDMT_isOverlapped(buffer, inUse)) {
|
||||||
|
DEBUGLOG(6, "Waiting for buffer...");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert(!ZSTDMT_isOverlapped(buffer, mtctx->inBuff.prefix));
|
||||||
|
|
||||||
|
ZSTDMT_waitForLdmComplete(mtctx, buffer);
|
||||||
|
|
||||||
|
DEBUGLOG(5, "Using prefix range [%zx, %zx)",
|
||||||
|
(size_t)mtctx->inBuff.prefix.start,
|
||||||
|
(size_t)mtctx->inBuff.prefix.start + mtctx->inBuff.prefix.size);
|
||||||
|
DEBUGLOG(5, "Using source range [%zx, %zx)",
|
||||||
|
(size_t)buffer.start,
|
||||||
|
(size_t)buffer.start + buffer.capacity);
|
||||||
|
|
||||||
|
|
||||||
|
mtctx->inBuff.buffer = buffer;
|
||||||
|
mtctx->inBuff.filled = 0;
|
||||||
|
assert(mtctx->roundBuff.pos + buffer.capacity <= mtctx->roundBuff.capacity);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** ZSTDMT_compressStream_generic() :
|
/** ZSTDMT_compressStream_generic() :
|
||||||
* internal use only - exposed to be invoked from zstd_compress.c
|
* internal use only - exposed to be invoked from zstd_compress.c
|
||||||
@@ -1034,13 +1711,13 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
|||||||
ZSTD_inBuffer* input,
|
ZSTD_inBuffer* input,
|
||||||
ZSTD_EndDirective endOp)
|
ZSTD_EndDirective endOp)
|
||||||
{
|
{
|
||||||
size_t const newJobThreshold = mtctx->dictSize + mtctx->targetSectionSize;
|
|
||||||
unsigned forwardInputProgress = 0;
|
unsigned forwardInputProgress = 0;
|
||||||
DEBUGLOG(5, "ZSTDMT_compressStream_generic ");
|
DEBUGLOG(5, "ZSTDMT_compressStream_generic (endOp=%u, srcSize=%u)",
|
||||||
|
(U32)endOp, (U32)(input->size - input->pos));
|
||||||
assert(output->pos <= output->size);
|
assert(output->pos <= output->size);
|
||||||
assert(input->pos <= input->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);
|
return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1052,8 +1729,9 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
|||||||
/* single-pass shortcut (note : synchronous-mode) */
|
/* single-pass shortcut (note : synchronous-mode) */
|
||||||
if ( (mtctx->nextJobID == 0) /* just started */
|
if ( (mtctx->nextJobID == 0) /* just started */
|
||||||
&& (mtctx->inBuff.filled == 0) /* nothing buffered */
|
&& (mtctx->inBuff.filled == 0) /* nothing buffered */
|
||||||
|
&& (!mtctx->jobReady) /* no job already created */
|
||||||
&& (endOp == ZSTD_e_end) /* end order */
|
&& (endOp == ZSTD_e_end) /* end order */
|
||||||
&& (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough room */
|
&& (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough space in dst */
|
||||||
size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx,
|
size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx,
|
||||||
(char*)output->dst + output->pos, output->size - output->pos,
|
(char*)output->dst + output->pos, output->size - output->pos,
|
||||||
(const char*)input->src + input->pos, input->size - input->pos,
|
(const char*)input->src + input->pos, input->size - input->pos,
|
||||||
@@ -1061,89 +1739,93 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
|||||||
if (ZSTD_isError(cSize)) return cSize;
|
if (ZSTD_isError(cSize)) return cSize;
|
||||||
input->pos = input->size;
|
input->pos = input->size;
|
||||||
output->pos += cSize;
|
output->pos += cSize;
|
||||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->inBuff.buffer); /* was allocated in initStream */
|
|
||||||
mtctx->allJobsCompleted = 1;
|
mtctx->allJobsCompleted = 1;
|
||||||
mtctx->frameEnded = 1;
|
mtctx->frameEnded = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill input buffer */
|
/* fill input buffer */
|
||||||
if (input->size > input->pos) { /* support NULL input */
|
if ( (!mtctx->jobReady)
|
||||||
|
&& (input->size > input->pos) ) { /* support NULL input */
|
||||||
if (mtctx->inBuff.buffer.start == NULL) {
|
if (mtctx->inBuff.buffer.start == NULL) {
|
||||||
mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); /* note : may fail, in which case, no forward input progress */
|
assert(mtctx->inBuff.filled == 0); /* Can't fill an empty buffer */
|
||||||
mtctx->inBuff.filled = 0;
|
if (!ZSTDMT_tryGetInputRange(mtctx)) {
|
||||||
|
/* It is only possible for this operation to fail if there are
|
||||||
|
* still compression jobs ongoing.
|
||||||
|
*/
|
||||||
|
assert(mtctx->doneJobID != mtctx->nextJobID);
|
||||||
}
|
}
|
||||||
if (mtctx->inBuff.buffer.start) {
|
}
|
||||||
size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled);
|
if (mtctx->inBuff.buffer.start != NULL) {
|
||||||
DEBUGLOG(5, "inBuff:%08X; inBuffSize=%u; ToCopy=%u", (U32)(size_t)mtctx->inBuff.buffer.start, (U32)mtctx->inBuffSize, (U32)toLoad);
|
size_t const toLoad = MIN(input->size - input->pos, mtctx->targetSectionSize - mtctx->inBuff.filled);
|
||||||
|
assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize);
|
||||||
|
DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u",
|
||||||
|
(U32)toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize);
|
||||||
memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, toLoad);
|
memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, toLoad);
|
||||||
input->pos += toLoad;
|
input->pos += toLoad;
|
||||||
mtctx->inBuff.filled += toLoad;
|
mtctx->inBuff.filled += toLoad;
|
||||||
forwardInputProgress = toLoad>0;
|
forwardInputProgress = toLoad>0;
|
||||||
} }
|
}
|
||||||
|
if ((input->pos < input->size) && (endOp == ZSTD_e_end))
|
||||||
|
endOp = ZSTD_e_flush; /* can't end now : not all input consumed */
|
||||||
|
}
|
||||||
|
|
||||||
if ( (mtctx->inBuff.filled >= newJobThreshold) /* filled enough : let's compress */
|
if ( (mtctx->jobReady)
|
||||||
&& (mtctx->nextJobID <= mtctx->doneJobID + mtctx->jobIDMask) ) { /* avoid overwriting job round buffer */
|
|| (mtctx->inBuff.filled >= mtctx->targetSectionSize) /* filled enough : let's compress */
|
||||||
CHECK_F( ZSTDMT_createCompressionJob(mtctx, mtctx->targetSectionSize, 0 /* endFrame */) );
|
|| ((endOp != ZSTD_e_continue) && (mtctx->inBuff.filled > 0)) /* something to flush : let's go */
|
||||||
|
|| ((endOp == ZSTD_e_end) && (!mtctx->frameEnded)) ) { /* must finish the frame with a zero-size block */
|
||||||
|
size_t const jobSize = mtctx->inBuff.filled;
|
||||||
|
assert(mtctx->inBuff.filled <= mtctx->targetSectionSize);
|
||||||
|
CHECK_F( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for potential compressed data ready to be flushed */
|
/* check for potential compressed data ready to be flushed */
|
||||||
CHECK_F( ZSTDMT_flushNextJob(mtctx, output, !forwardInputProgress /* blockToFlush */) ); /* block if there was no forward input progress */
|
{ size_t const remainingToFlush = ZSTDMT_flushProduced(mtctx, output, !forwardInputProgress, endOp); /* block if there was no forward input progress */
|
||||||
|
if (input->pos < input->size) return MAX(remainingToFlush, 1); /* input not consumed : do not end flush yet */
|
||||||
if (input->pos < input->size) /* input not consumed : do not flush yet */
|
return remainingToFlush;
|
||||||
endOp = ZSTD_e_continue;
|
|
||||||
|
|
||||||
switch(endOp)
|
|
||||||
{
|
|
||||||
case ZSTD_e_flush:
|
|
||||||
return ZSTDMT_flushStream(mtctx, output);
|
|
||||||
case ZSTD_e_end:
|
|
||||||
return ZSTDMT_endStream(mtctx, output);
|
|
||||||
case ZSTD_e_continue:
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
return ERROR(GENERIC); /* invalid endDirective */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTDMT_compressStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
|
size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
|
||||||
{
|
{
|
||||||
CHECK_F( ZSTDMT_compressStream_generic(zcs, output, input, ZSTD_e_continue) );
|
CHECK_F( ZSTDMT_compressStream_generic(mtctx, output, input, ZSTD_e_continue) );
|
||||||
|
|
||||||
/* recommended next input size : fill current input buffer */
|
/* recommended next input size : fill current input buffer */
|
||||||
return zcs->inBuffSize - zcs->inBuff.filled; /* note : could be zero when input buffer is fully filled and no more availability to create new job */
|
return mtctx->targetSectionSize - mtctx->inBuff.filled; /* note : could be zero when input buffer is fully filled and no more availability to create new job */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned endFrame)
|
static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_EndDirective endFrame)
|
||||||
{
|
{
|
||||||
size_t const srcSize = mtctx->inBuff.filled - mtctx->dictSize;
|
size_t const srcSize = mtctx->inBuff.filled;
|
||||||
DEBUGLOG(5, "ZSTDMT_flushStream_internal");
|
DEBUGLOG(5, "ZSTDMT_flushStream_internal");
|
||||||
|
|
||||||
if ( ((srcSize > 0) || (endFrame && !mtctx->frameEnded))
|
if ( mtctx->jobReady /* one job ready for a worker to pick up */
|
||||||
&& (mtctx->nextJobID <= mtctx->doneJobID + mtctx->jobIDMask) ) {
|
|| (srcSize > 0) /* still some data within input buffer */
|
||||||
DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job");
|
|| ((endFrame==ZSTD_e_end) && !mtctx->frameEnded)) { /* need a last 0-size block to end frame */
|
||||||
|
DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job (%u bytes, end:%u)",
|
||||||
|
(U32)srcSize, (U32)endFrame);
|
||||||
CHECK_F( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) );
|
CHECK_F( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if there is any data available to flush */
|
/* check if there is any data available to flush */
|
||||||
return ZSTDMT_flushNextJob(mtctx, output, 1 /* blockToFlush */);
|
return ZSTDMT_flushProduced(mtctx, output, 1 /* blockToFlush */, endFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
|
size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
|
||||||
{
|
{
|
||||||
DEBUGLOG(5, "ZSTDMT_flushStream");
|
DEBUGLOG(5, "ZSTDMT_flushStream");
|
||||||
if (mtctx->singleThreaded)
|
if (mtctx->singleBlockingThread)
|
||||||
return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
|
return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
|
||||||
return ZSTDMT_flushStream_internal(mtctx, output, 0 /* endFrame */);
|
return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
|
size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTDMT_endStream");
|
DEBUGLOG(4, "ZSTDMT_endStream");
|
||||||
if (mtctx->singleThreaded)
|
if (mtctx->singleBlockingThread)
|
||||||
return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
|
return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
|
||||||
return ZSTDMT_flushStream_internal(mtctx, output, 1 /* endFrame */);
|
return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_end);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,15 +30,15 @@
|
|||||||
|
|
||||||
/* === Memory management === */
|
/* === Memory management === */
|
||||||
typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx;
|
typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx;
|
||||||
ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbThreads);
|
ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers);
|
||||||
ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads,
|
ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers,
|
||||||
ZSTD_customMem cMem);
|
ZSTD_customMem cMem);
|
||||||
ZSTDLIB_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx);
|
ZSTDLIB_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx);
|
||||||
|
|
||||||
ZSTDLIB_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx);
|
ZSTDLIB_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx);
|
||||||
|
|
||||||
|
|
||||||
/* === Simple buffer-to-butter one-pass function === */
|
/* === Simple one-pass compression function === */
|
||||||
|
|
||||||
ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
|
ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
@@ -50,7 +50,7 @@ ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
|
|||||||
/* === Streaming functions === */
|
/* === Streaming functions === */
|
||||||
|
|
||||||
ZSTDLIB_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
|
ZSTDLIB_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
|
||||||
ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it may change in the future, to mean "empty" */
|
ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it will change in the future to mean "empty" */
|
||||||
|
|
||||||
ZSTDLIB_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
|
ZSTDLIB_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
|
|||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const ZSTD_CDict* cdict,
|
const ZSTD_CDict* cdict,
|
||||||
ZSTD_parameters const params,
|
ZSTD_parameters params,
|
||||||
unsigned overlapLog);
|
unsigned overlapLog);
|
||||||
|
|
||||||
ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
|
ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
|
||||||
@@ -85,7 +85,7 @@ ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
|
|||||||
* List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
|
* List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
|
||||||
typedef enum {
|
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_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_parameter;
|
||||||
|
|
||||||
/* ZSTDMT_setMTCtxParameter() :
|
/* ZSTDMT_setMTCtxParameter() :
|
||||||
@@ -97,30 +97,46 @@ ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter
|
|||||||
|
|
||||||
|
|
||||||
/*! ZSTDMT_compressStream_generic() :
|
/*! ZSTDMT_compressStream_generic() :
|
||||||
* Combines ZSTDMT_compressStream() with ZSTDMT_flushStream() or ZSTDMT_endStream()
|
* Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream()
|
||||||
* depending on flush directive.
|
* depending on flush directive.
|
||||||
* @return : minimum amount of data still to be flushed
|
* @return : minimum amount of data still to be flushed
|
||||||
* 0 if fully flushed
|
* 0 if fully flushed
|
||||||
* or an error code */
|
* or an error code
|
||||||
|
* note : needs to be init using any ZSTD_initCStream*() variant */
|
||||||
ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||||
ZSTD_outBuffer* output,
|
ZSTD_outBuffer* output,
|
||||||
ZSTD_inBuffer* input,
|
ZSTD_inBuffer* input,
|
||||||
ZSTD_EndDirective endOp);
|
ZSTD_EndDirective endOp);
|
||||||
|
|
||||||
|
|
||||||
/* === Private definitions; never ever use directly === */
|
/* ========================================================
|
||||||
|
* === Private interface, for use by ZSTD_compress.c ===
|
||||||
|
* === Not exposed in libzstd. Never invoke directly ===
|
||||||
|
* ======================================================== */
|
||||||
|
|
||||||
size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value);
|
size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value);
|
||||||
|
|
||||||
/* ZSTDMT_CCtxParam_setNbThreads()
|
/* ZSTDMT_CCtxParam_setNbWorkers()
|
||||||
* Set nbThreads, and clamp it correctly,
|
* Set nbWorkers, and clamp it.
|
||||||
* also reset jobSize and overlapLog */
|
* Also reset jobSize and overlapLog */
|
||||||
size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads);
|
size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers);
|
||||||
|
|
||||||
/* ZSTDMT_getNbThreads():
|
/*! ZSTDMT_updateCParams_whileCompressing() :
|
||||||
|
* Updates only a selected set of compression parameters, to remain compatible with current frame.
|
||||||
|
* New parameters will be applied to next compression job. */
|
||||||
|
void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams);
|
||||||
|
|
||||||
|
/* ZSTDMT_getNbWorkers():
|
||||||
* @return nb threads currently active in mtctx.
|
* @return nb threads currently active in mtctx.
|
||||||
* mtctx must be valid */
|
* mtctx must be valid */
|
||||||
size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx);
|
unsigned ZSTDMT_getNbWorkers(const ZSTDMT_CCtx* mtctx);
|
||||||
|
|
||||||
|
/* ZSTDMT_getFrameProgression():
|
||||||
|
* tells how much data has been consumed (input) and produced (output) for current frame.
|
||||||
|
* able to count progression inside worker threads.
|
||||||
|
*/
|
||||||
|
ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx);
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTDMT_initCStream_internal() :
|
/*! ZSTDMT_initCStream_internal() :
|
||||||
* Private use only. Init streaming operation.
|
* Private use only. Init streaming operation.
|
||||||
@@ -128,7 +144,7 @@ size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx);
|
|||||||
* must receive dict, or cdict, or none, but not both.
|
* must receive dict, or cdict, or none, but not both.
|
||||||
* @return : 0, or an error code */
|
* @return : 0, or an error code */
|
||||||
size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
|
size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
|
||||||
const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
|
const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
|
||||||
const ZSTD_CDict* cdict,
|
const ZSTD_CDict* cdict,
|
||||||
ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
|
ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
****************************************************************/
|
****************************************************************/
|
||||||
#define HUF_isError ERR_isError
|
#define HUF_isError ERR_isError
|
||||||
#define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
#define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||||
|
#define CHECK_F(f) { size_t const err_ = (f); if (HUF_isError(err_)) return err_; }
|
||||||
|
|
||||||
|
|
||||||
/* **************************************************************
|
/* **************************************************************
|
||||||
@@ -57,10 +58,10 @@
|
|||||||
#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1)
|
#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1)
|
||||||
#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||||
|
|
||||||
|
|
||||||
/*-***************************/
|
/*-***************************/
|
||||||
/* generic DTableDesc */
|
/* generic DTableDesc */
|
||||||
/*-***************************/
|
/*-***************************/
|
||||||
|
|
||||||
typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
|
typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
|
||||||
|
|
||||||
static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
|
static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
|
||||||
@@ -74,7 +75,6 @@ static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
|
|||||||
/*-***************************/
|
/*-***************************/
|
||||||
/* single-symbol decoding */
|
/* single-symbol decoding */
|
||||||
/*-***************************/
|
/*-***************************/
|
||||||
|
|
||||||
typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */
|
typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */
|
||||||
|
|
||||||
size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
|
size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
|
||||||
@@ -94,10 +94,7 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize
|
|||||||
huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32);
|
huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32);
|
||||||
spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
|
spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
|
||||||
|
|
||||||
if ((spaceUsed32 << 2) > wkspSize)
|
if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
workSpace = (U32 *)workSpace + spaceUsed32;
|
|
||||||
wkspSize -= (spaceUsed32 << 2);
|
|
||||||
|
|
||||||
HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
|
HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
|
||||||
/* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
|
/* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
|
||||||
@@ -144,8 +141,10 @@ size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
|
|||||||
workSpace, sizeof(workSpace));
|
workSpace, sizeof(workSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* double-symbols decoding */
|
||||||
|
|
||||||
static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog)
|
FORCE_INLINE_TEMPLATE BYTE
|
||||||
|
HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog)
|
||||||
{
|
{
|
||||||
size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
|
size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
|
||||||
BYTE const c = dt[val].byte;
|
BYTE const c = dt[val].byte;
|
||||||
@@ -164,30 +163,33 @@ static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, con
|
|||||||
if (MEM_64bits()) \
|
if (MEM_64bits()) \
|
||||||
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
||||||
|
|
||||||
HINT_INLINE size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX2* const dt, const U32 dtLog)
|
HINT_INLINE size_t
|
||||||
|
HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX2* const dt, const U32 dtLog)
|
||||||
{
|
{
|
||||||
BYTE* const pStart = p;
|
BYTE* const pStart = p;
|
||||||
|
|
||||||
/* up to 4 symbols at a time */
|
/* up to 4 symbols at a time */
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-4)) {
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) {
|
||||||
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
||||||
HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
|
HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
|
||||||
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
||||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* closer to the end */
|
/* [0-3] symbols remaining */
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd))
|
if (MEM_32bits())
|
||||||
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd))
|
||||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||||
|
|
||||||
/* no more data to retrieve from bitstream, hence no need to reload */
|
/* no more data to retrieve from bitstream, no need to reload */
|
||||||
while (p < pEnd)
|
while (p < pEnd)
|
||||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||||
|
|
||||||
return pEnd-pStart;
|
return pEnd-pStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t HUF_decompress1X2_usingDTable_internal(
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
HUF_decompress1X2_usingDTable_internal_body(
|
||||||
void* dst, size_t dstSize,
|
void* dst, size_t dstSize,
|
||||||
const void* cSrc, size_t cSrcSize,
|
const void* cSrc, size_t cSrcSize,
|
||||||
const HUF_DTable* DTable)
|
const HUF_DTable* DTable)
|
||||||
@@ -200,58 +202,17 @@ static size_t HUF_decompress1X2_usingDTable_internal(
|
|||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
U32 const dtLog = dtd.tableLog;
|
U32 const dtLog = dtd.tableLog;
|
||||||
|
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
|
CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
|
||||||
|
|
||||||
HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
|
HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
|
||||||
|
|
||||||
/* check */
|
|
||||||
if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
|
if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
|
||||||
|
|
||||||
return dstSize;
|
return dstSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_decompress1X2_usingDTable(
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
void* dst, size_t dstSize,
|
HUF_decompress4X2_usingDTable_internal_body(
|
||||||
const void* cSrc, size_t cSrcSize,
|
|
||||||
const HUF_DTable* DTable)
|
|
||||||
{
|
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
|
||||||
if (dtd.tableType != 0) return ERROR(GENERIC);
|
|
||||||
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
|
||||||
const void* cSrc, size_t cSrcSize,
|
|
||||||
void* workSpace, size_t wkspSize)
|
|
||||||
{
|
|
||||||
const BYTE* ip = (const BYTE*) cSrc;
|
|
||||||
|
|
||||||
size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize);
|
|
||||||
if (HUF_isError(hSize)) return hSize;
|
|
||||||
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
|
||||||
ip += hSize; cSrcSize -= hSize;
|
|
||||||
|
|
||||||
return HUF_decompress1X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
|
||||||
const void* cSrc, size_t cSrcSize)
|
|
||||||
{
|
|
||||||
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
|
||||||
return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
|
|
||||||
workSpace, sizeof(workSpace));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
|
||||||
{
|
|
||||||
HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
|
|
||||||
return HUF_decompress1X2_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static size_t HUF_decompress4X2_usingDTable_internal(
|
|
||||||
void* dst, size_t dstSize,
|
void* dst, size_t dstSize,
|
||||||
const void* cSrc, size_t cSrcSize,
|
const void* cSrc, size_t cSrcSize,
|
||||||
const HUF_DTable* DTable)
|
const HUF_DTable* DTable)
|
||||||
@@ -286,23 +247,19 @@ static size_t HUF_decompress4X2_usingDTable_internal(
|
|||||||
BYTE* op2 = opStart2;
|
BYTE* op2 = opStart2;
|
||||||
BYTE* op3 = opStart3;
|
BYTE* op3 = opStart3;
|
||||||
BYTE* op4 = opStart4;
|
BYTE* op4 = opStart4;
|
||||||
U32 endSignal;
|
U32 endSignal = BIT_DStream_unfinished;
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
U32 const dtLog = dtd.tableLog;
|
U32 const dtLog = dtd.tableLog;
|
||||||
|
|
||||||
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
|
CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
|
CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
|
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
|
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
|
||||||
|
|
||||||
/* 16-32 symbols per loop (4-8 symbols per stream) */
|
/* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||||
for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) {
|
while ( (endSignal==BIT_DStream_unfinished) && (op4<(oend-3)) ) {
|
||||||
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
||||||
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
||||||
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
||||||
@@ -319,10 +276,15 @@ static size_t HUF_decompress4X2_usingDTable_internal(
|
|||||||
HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
|
HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
|
||||||
HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
|
HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
|
||||||
HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
|
HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
BIT_reloadDStream(&bitD1);
|
||||||
|
BIT_reloadDStream(&bitD2);
|
||||||
|
BIT_reloadDStream(&bitD3);
|
||||||
|
BIT_reloadDStream(&bitD4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check corruption */
|
/* check corruption */
|
||||||
|
/* note : should not be necessary : op# advance in lock step, and we control op4.
|
||||||
|
* but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */
|
||||||
if (op1 > opStart2) return ERROR(corruption_detected);
|
if (op1 > opStart2) return ERROR(corruption_detected);
|
||||||
if (op2 > opStart3) return ERROR(corruption_detected);
|
if (op2 > opStart3) return ERROR(corruption_detected);
|
||||||
if (op3 > opStart4) return ERROR(corruption_detected);
|
if (op3 > opStart4) return ERROR(corruption_detected);
|
||||||
@@ -335,8 +297,8 @@ static size_t HUF_decompress4X2_usingDTable_internal(
|
|||||||
HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
|
HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
|
||||||
|
|
||||||
/* check */
|
/* check */
|
||||||
endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
{ U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
||||||
if (!endSignal) return ERROR(corruption_detected);
|
if (!endCheck) return ERROR(corruption_detected); }
|
||||||
|
|
||||||
/* decoded size */
|
/* decoded size */
|
||||||
return dstSize;
|
return dstSize;
|
||||||
@@ -344,6 +306,279 @@ static size_t HUF_decompress4X2_usingDTable_internal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE U32
|
||||||
|
HUF_decodeSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
||||||
|
memcpy(op, dt+val, 2);
|
||||||
|
BIT_skipBits(DStream, dt[val].nbBits);
|
||||||
|
return dt[val].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE U32
|
||||||
|
HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
||||||
|
memcpy(op, dt+val, 1);
|
||||||
|
if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
|
||||||
|
else {
|
||||||
|
if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
|
||||||
|
BIT_skipBits(DStream, dt[val].nbBits);
|
||||||
|
if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
|
||||||
|
/* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
|
||||||
|
DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8);
|
||||||
|
} }
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \
|
||||||
|
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
|
||||||
|
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||||
|
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
|
||||||
|
if (MEM_64bits()) \
|
||||||
|
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
||||||
|
|
||||||
|
HINT_INLINE size_t
|
||||||
|
HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
|
||||||
|
const HUF_DEltX4* const dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
BYTE* const pStart = p;
|
||||||
|
|
||||||
|
/* up to 8 symbols at a time */
|
||||||
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
|
||||||
|
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* closer to end : up to 2 symbols at a time */
|
||||||
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
|
||||||
|
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
||||||
|
|
||||||
|
while (p <= pEnd-2)
|
||||||
|
HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
|
||||||
|
|
||||||
|
if (p < pEnd)
|
||||||
|
p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
|
||||||
|
|
||||||
|
return p-pStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
HUF_decompress1X4_usingDTable_internal_body(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
BIT_DStream_t bitD;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
|
||||||
|
|
||||||
|
/* decode */
|
||||||
|
{ BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */
|
||||||
|
const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check */
|
||||||
|
if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
|
||||||
|
|
||||||
|
/* decoded size */
|
||||||
|
return dstSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
HUF_decompress4X4_usingDTable_internal_body(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
|
||||||
|
|
||||||
|
{ const BYTE* const istart = (const BYTE*) cSrc;
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
const void* const dtPtr = DTable+1;
|
||||||
|
const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
BIT_DStream_t bitD1;
|
||||||
|
BIT_DStream_t bitD2;
|
||||||
|
BIT_DStream_t bitD3;
|
||||||
|
BIT_DStream_t bitD4;
|
||||||
|
size_t const length1 = MEM_readLE16(istart);
|
||||||
|
size_t const length2 = MEM_readLE16(istart+2);
|
||||||
|
size_t const length3 = MEM_readLE16(istart+4);
|
||||||
|
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
|
||||||
|
const BYTE* const istart1 = istart + 6; /* jumpTable */
|
||||||
|
const BYTE* const istart2 = istart1 + length1;
|
||||||
|
const BYTE* const istart3 = istart2 + length2;
|
||||||
|
const BYTE* const istart4 = istart3 + length3;
|
||||||
|
size_t const segmentSize = (dstSize+3) / 4;
|
||||||
|
BYTE* const opStart2 = ostart + segmentSize;
|
||||||
|
BYTE* const opStart3 = opStart2 + segmentSize;
|
||||||
|
BYTE* const opStart4 = opStart3 + segmentSize;
|
||||||
|
BYTE* op1 = ostart;
|
||||||
|
BYTE* op2 = opStart2;
|
||||||
|
BYTE* op3 = opStart3;
|
||||||
|
BYTE* op4 = opStart4;
|
||||||
|
U32 endSignal;
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
U32 const dtLog = dtd.tableLog;
|
||||||
|
|
||||||
|
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
||||||
|
CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
|
||||||
|
CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
|
||||||
|
CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
|
||||||
|
CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
|
||||||
|
|
||||||
|
/* 16-32 symbols per loop (4-8 symbols per stream) */
|
||||||
|
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||||
|
for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) {
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
|
||||||
|
|
||||||
|
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check corruption */
|
||||||
|
if (op1 > opStart2) return ERROR(corruption_detected);
|
||||||
|
if (op2 > opStart3) return ERROR(corruption_detected);
|
||||||
|
if (op3 > opStart4) return ERROR(corruption_detected);
|
||||||
|
/* note : op4 already verified within main loop */
|
||||||
|
|
||||||
|
/* finish bitStreams one by one */
|
||||||
|
HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
|
||||||
|
HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
|
||||||
|
HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
|
||||||
|
HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
|
||||||
|
|
||||||
|
/* check */
|
||||||
|
{ U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
||||||
|
if (!endCheck) return ERROR(corruption_detected); }
|
||||||
|
|
||||||
|
/* decoded size */
|
||||||
|
return dstSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
|
||||||
|
const void *cSrc,
|
||||||
|
size_t cSrcSize,
|
||||||
|
const HUF_DTable *DTable);
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
|
||||||
|
#define X(fn) \
|
||||||
|
\
|
||||||
|
static size_t fn##_default( \
|
||||||
|
void* dst, size_t dstSize, \
|
||||||
|
const void* cSrc, size_t cSrcSize, \
|
||||||
|
const HUF_DTable* DTable) \
|
||||||
|
{ \
|
||||||
|
return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \
|
||||||
|
void* dst, size_t dstSize, \
|
||||||
|
const void* cSrc, size_t cSrcSize, \
|
||||||
|
const HUF_DTable* DTable) \
|
||||||
|
{ \
|
||||||
|
return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
|
||||||
|
size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
|
||||||
|
{ \
|
||||||
|
if (bmi2) { \
|
||||||
|
return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \
|
||||||
|
} \
|
||||||
|
return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define X(fn) \
|
||||||
|
static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
|
||||||
|
size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
|
||||||
|
{ \
|
||||||
|
(void)bmi2; \
|
||||||
|
return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
X(HUF_decompress1X2_usingDTable_internal)
|
||||||
|
X(HUF_decompress4X2_usingDTable_internal)
|
||||||
|
X(HUF_decompress1X4_usingDTable_internal)
|
||||||
|
X(HUF_decompress4X4_usingDTable_internal)
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_decompress1X2_usingDTable(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
|
if (dtd.tableType != 0) return ERROR(GENERIC);
|
||||||
|
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
|
size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize);
|
||||||
|
if (HUF_isError(hSize)) return hSize;
|
||||||
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
|
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||||
|
return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
|
||||||
|
workSpace, sizeof(workSpace));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
|
||||||
|
return HUF_decompress1X2_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
|
||||||
|
}
|
||||||
|
|
||||||
size_t HUF_decompress4X2_usingDTable(
|
size_t HUF_decompress4X2_usingDTable(
|
||||||
void* dst, size_t dstSize,
|
void* dst, size_t dstSize,
|
||||||
const void* cSrc, size_t cSrcSize,
|
const void* cSrc, size_t cSrcSize,
|
||||||
@@ -351,13 +586,12 @@ size_t HUF_decompress4X2_usingDTable(
|
|||||||
{
|
{
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
if (dtd.tableType != 0) return ERROR(GENERIC);
|
if (dtd.tableType != 0) return ERROR(GENERIC);
|
||||||
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||||
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
|
||||||
const void* cSrc, size_t cSrcSize,
|
const void* cSrc, size_t cSrcSize,
|
||||||
void* workSpace, size_t wkspSize)
|
void* workSpace, size_t wkspSize, int bmi2)
|
||||||
{
|
{
|
||||||
const BYTE* ip = (const BYTE*) cSrc;
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
@@ -367,7 +601,14 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
|||||||
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
ip += hSize; cSrcSize -= hSize;
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
return HUF_decompress4X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, dctx);
|
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -387,8 +628,6 @@ size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cS
|
|||||||
/* *************************/
|
/* *************************/
|
||||||
/* double-symbols decoding */
|
/* double-symbols decoding */
|
||||||
/* *************************/
|
/* *************************/
|
||||||
typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* double-symbols decoding */
|
|
||||||
|
|
||||||
typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
|
typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
|
||||||
|
|
||||||
/* HUF_fillDTableX4Level2() :
|
/* HUF_fillDTableX4Level2() :
|
||||||
@@ -508,10 +747,7 @@ size_t HUF_readDTableX4_wksp(HUF_DTable* DTable, const void* src,
|
|||||||
weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
|
weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
|
||||||
spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
|
spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
|
||||||
|
|
||||||
if ((spaceUsed32 << 2) > wkspSize)
|
if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
workSpace = (U32 *)workSpace + spaceUsed32;
|
|
||||||
wkspSize -= (spaceUsed32 << 2);
|
|
||||||
|
|
||||||
rankStart = rankStart0 + 1;
|
rankStart = rankStart0 + 1;
|
||||||
memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
|
memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
|
||||||
@@ -588,95 +824,6 @@ size_t HUF_readDTableX4(HUF_DTable* DTable, const void* src, size_t srcSize)
|
|||||||
workSpace, sizeof(workSpace));
|
workSpace, sizeof(workSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
static U32 HUF_decodeSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
|
||||||
memcpy(op, dt+val, 2);
|
|
||||||
BIT_skipBits(DStream, dt[val].nbBits);
|
|
||||||
return dt[val].length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static U32 HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
|
||||||
memcpy(op, dt+val, 1);
|
|
||||||
if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
|
|
||||||
else {
|
|
||||||
if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
|
|
||||||
BIT_skipBits(DStream, dt[val].nbBits);
|
|
||||||
if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
|
|
||||||
/* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
|
|
||||||
DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8);
|
|
||||||
} }
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \
|
|
||||||
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
|
|
||||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
|
||||||
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
|
|
||||||
if (MEM_64bits()) \
|
|
||||||
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
|
||||||
|
|
||||||
HINT_INLINE size_t HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, const HUF_DEltX4* const dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
BYTE* const pStart = p;
|
|
||||||
|
|
||||||
/* up to 8 symbols at a time */
|
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
|
|
||||||
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* closer to end : up to 2 symbols at a time */
|
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
|
|
||||||
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
|
||||||
|
|
||||||
while (p <= pEnd-2)
|
|
||||||
HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
|
|
||||||
|
|
||||||
if (p < pEnd)
|
|
||||||
p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
|
|
||||||
|
|
||||||
return p-pStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static size_t HUF_decompress1X4_usingDTable_internal(
|
|
||||||
void* dst, size_t dstSize,
|
|
||||||
const void* cSrc, size_t cSrcSize,
|
|
||||||
const HUF_DTable* DTable)
|
|
||||||
{
|
|
||||||
BIT_DStream_t bitD;
|
|
||||||
|
|
||||||
/* Init */
|
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
|
|
||||||
if (HUF_isError(errorCode)) return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decode */
|
|
||||||
{ BYTE* const ostart = (BYTE*) dst;
|
|
||||||
BYTE* const oend = ostart + dstSize;
|
|
||||||
const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */
|
|
||||||
const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check */
|
|
||||||
if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
|
|
||||||
|
|
||||||
/* decoded size */
|
|
||||||
return dstSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X4_usingDTable(
|
size_t HUF_decompress1X4_usingDTable(
|
||||||
void* dst, size_t dstSize,
|
void* dst, size_t dstSize,
|
||||||
const void* cSrc, size_t cSrcSize,
|
const void* cSrc, size_t cSrcSize,
|
||||||
@@ -684,7 +831,7 @@ size_t HUF_decompress1X4_usingDTable(
|
|||||||
{
|
{
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
if (dtd.tableType != 1) return ERROR(GENERIC);
|
if (dtd.tableType != 1) return ERROR(GENERIC);
|
||||||
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||||
@@ -699,7 +846,7 @@ size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
|||||||
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
ip += hSize; cSrcSize -= hSize;
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
return HUF_decompress1X4_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
|
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -717,99 +864,6 @@ size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cS
|
|||||||
return HUF_decompress1X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
return HUF_decompress1X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t HUF_decompress4X4_usingDTable_internal(
|
|
||||||
void* dst, size_t dstSize,
|
|
||||||
const void* cSrc, size_t cSrcSize,
|
|
||||||
const HUF_DTable* DTable)
|
|
||||||
{
|
|
||||||
if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
|
|
||||||
|
|
||||||
{ const BYTE* const istart = (const BYTE*) cSrc;
|
|
||||||
BYTE* const ostart = (BYTE*) dst;
|
|
||||||
BYTE* const oend = ostart + dstSize;
|
|
||||||
const void* const dtPtr = DTable+1;
|
|
||||||
const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
|
|
||||||
|
|
||||||
/* Init */
|
|
||||||
BIT_DStream_t bitD1;
|
|
||||||
BIT_DStream_t bitD2;
|
|
||||||
BIT_DStream_t bitD3;
|
|
||||||
BIT_DStream_t bitD4;
|
|
||||||
size_t const length1 = MEM_readLE16(istart);
|
|
||||||
size_t const length2 = MEM_readLE16(istart+2);
|
|
||||||
size_t const length3 = MEM_readLE16(istart+4);
|
|
||||||
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
|
|
||||||
const BYTE* const istart1 = istart + 6; /* jumpTable */
|
|
||||||
const BYTE* const istart2 = istart1 + length1;
|
|
||||||
const BYTE* const istart3 = istart2 + length2;
|
|
||||||
const BYTE* const istart4 = istart3 + length3;
|
|
||||||
size_t const segmentSize = (dstSize+3) / 4;
|
|
||||||
BYTE* const opStart2 = ostart + segmentSize;
|
|
||||||
BYTE* const opStart3 = opStart2 + segmentSize;
|
|
||||||
BYTE* const opStart4 = opStart3 + segmentSize;
|
|
||||||
BYTE* op1 = ostart;
|
|
||||||
BYTE* op2 = opStart2;
|
|
||||||
BYTE* op3 = opStart3;
|
|
||||||
BYTE* op4 = opStart4;
|
|
||||||
U32 endSignal;
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
U32 const dtLog = dtd.tableLog;
|
|
||||||
|
|
||||||
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
|
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
|
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
|
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
|
||||||
{ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
|
|
||||||
if (HUF_isError(errorCode)) return errorCode; }
|
|
||||||
|
|
||||||
/* 16-32 symbols per loop (4-8 symbols per stream) */
|
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
|
||||||
for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) {
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
|
|
||||||
|
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check corruption */
|
|
||||||
if (op1 > opStart2) return ERROR(corruption_detected);
|
|
||||||
if (op2 > opStart3) return ERROR(corruption_detected);
|
|
||||||
if (op3 > opStart4) return ERROR(corruption_detected);
|
|
||||||
/* note : op4 already verified within main loop */
|
|
||||||
|
|
||||||
/* finish bitStreams one by one */
|
|
||||||
HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
|
|
||||||
HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
|
|
||||||
HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
|
|
||||||
HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
|
|
||||||
|
|
||||||
/* check */
|
|
||||||
{ U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
|
||||||
if (!endCheck) return ERROR(corruption_detected); }
|
|
||||||
|
|
||||||
/* decoded size */
|
|
||||||
return dstSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t HUF_decompress4X4_usingDTable(
|
size_t HUF_decompress4X4_usingDTable(
|
||||||
void* dst, size_t dstSize,
|
void* dst, size_t dstSize,
|
||||||
const void* cSrc, size_t cSrcSize,
|
const void* cSrc, size_t cSrcSize,
|
||||||
@@ -817,13 +871,12 @@ size_t HUF_decompress4X4_usingDTable(
|
|||||||
{
|
{
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
if (dtd.tableType != 1) return ERROR(GENERIC);
|
if (dtd.tableType != 1) return ERROR(GENERIC);
|
||||||
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t HUF_decompress4X4_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||||
size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
|
||||||
const void* cSrc, size_t cSrcSize,
|
const void* cSrc, size_t cSrcSize,
|
||||||
void* workSpace, size_t wkspSize)
|
void* workSpace, size_t wkspSize, int bmi2)
|
||||||
{
|
{
|
||||||
const BYTE* ip = (const BYTE*) cSrc;
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
@@ -833,7 +886,14 @@ size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
|||||||
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
ip += hSize; cSrcSize -= hSize;
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
|
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return HUF_decompress4X4_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -861,8 +921,8 @@ size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
|
|||||||
const HUF_DTable* DTable)
|
const HUF_DTable* DTable)
|
||||||
{
|
{
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
|
return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
|
||||||
HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
|
HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
|
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
|
||||||
@@ -870,8 +930,8 @@ size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
|
|||||||
const HUF_DTable* DTable)
|
const HUF_DTable* DTable)
|
||||||
{
|
{
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
|
return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
|
||||||
HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
|
HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -899,20 +959,21 @@ static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, qu
|
|||||||
|
|
||||||
/** HUF_selectDecoder() :
|
/** HUF_selectDecoder() :
|
||||||
* Tells which decoder is likely to decode faster,
|
* Tells which decoder is likely to decode faster,
|
||||||
* based on a set of pre-determined metrics.
|
* based on a set of pre-computed metrics.
|
||||||
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
||||||
* Assumption : 0 < cSrcSize, dstSize <= 128 KB */
|
* Assumption : 0 < dstSize <= 128 KB */
|
||||||
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
|
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
|
||||||
{
|
{
|
||||||
|
assert(dstSize > 0);
|
||||||
|
assert(dstSize <= 128 KB);
|
||||||
/* decoder timing evaluation */
|
/* decoder timing evaluation */
|
||||||
U32 const Q = cSrcSize >= dstSize ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */
|
{ U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */
|
||||||
U32 const D256 = (U32)(dstSize >> 8);
|
U32 const D256 = (U32)(dstSize >> 8);
|
||||||
U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
|
U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
|
||||||
U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
|
U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
|
||||||
DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */
|
DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */
|
||||||
|
|
||||||
return DTime1 < DTime0;
|
return DTime1 < DTime0;
|
||||||
}
|
} }
|
||||||
|
|
||||||
|
|
||||||
typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
|
typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
|
||||||
@@ -994,3 +1055,42 @@ size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
|
|||||||
return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
|
return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
|
||||||
workSpace, sizeof(workSpace));
|
workSpace, sizeof(workSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
|
||||||
|
{
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
|
||||||
|
HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
|
size_t const hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize);
|
||||||
|
if (HUF_isError(hSize)) return hSize;
|
||||||
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
|
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
|
||||||
|
{
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
|
||||||
|
HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
|
||||||
|
{
|
||||||
|
/* validation checks */
|
||||||
|
if (dstSize == 0) return ERROR(dstSize_tooSmall);
|
||||||
|
if (cSrcSize == 0) return ERROR(corruption_detected);
|
||||||
|
|
||||||
|
{ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
||||||
|
return algoNb ? HUF_decompress4X4_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) :
|
||||||
|
HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,8 +14,9 @@
|
|||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
/*!
|
/*!
|
||||||
* HEAPMODE :
|
* HEAPMODE :
|
||||||
* Select how default decompression function ZSTD_decompress() will allocate memory,
|
* Select how default decompression function ZSTD_decompress() allocates its context,
|
||||||
* in memory stack (0), or in memory heap (1, requires malloc())
|
* on stack (0), or into heap (1, default; requires malloc()).
|
||||||
|
* Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.
|
||||||
*/
|
*/
|
||||||
#ifndef ZSTD_HEAPMODE
|
#ifndef ZSTD_HEAPMODE
|
||||||
# define ZSTD_HEAPMODE 1
|
# define ZSTD_HEAPMODE 1
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* LEGACY_SUPPORT :
|
* LEGACY_SUPPORT :
|
||||||
* if set to 1, ZSTD_decompress() can decode older formats (v0.1+)
|
* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)
|
||||||
*/
|
*/
|
||||||
#ifndef ZSTD_LEGACY_SUPPORT
|
#ifndef ZSTD_LEGACY_SUPPORT
|
||||||
# define ZSTD_LEGACY_SUPPORT 0
|
# define ZSTD_LEGACY_SUPPORT 0
|
||||||
@@ -31,8 +32,9 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* MAXWINDOWSIZE_DEFAULT :
|
* MAXWINDOWSIZE_DEFAULT :
|
||||||
* maximum window size accepted by DStream, by default.
|
* maximum window size accepted by DStream __by default__.
|
||||||
* Frames requiring more memory will be rejected.
|
* Frames requiring more memory will be rejected.
|
||||||
|
* It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().
|
||||||
*/
|
*/
|
||||||
#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
|
#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
|
||||||
# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_DEFAULTMAX) + 1)
|
# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_DEFAULTMAX) + 1)
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
* Dependencies
|
* Dependencies
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
#include <string.h> /* memcpy, memmove, memset */
|
#include <string.h> /* memcpy, memmove, memset */
|
||||||
|
#include "cpu.h"
|
||||||
#include "mem.h" /* low level memory routines */
|
#include "mem.h" /* low level memory routines */
|
||||||
#define FSE_STATIC_LINKING_ONLY
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
#include "fse.h"
|
#include "fse.h"
|
||||||
@@ -80,10 +83,25 @@ typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
|
|||||||
typedef enum { zdss_init=0, zdss_loadHeader,
|
typedef enum { zdss_init=0, zdss_loadHeader,
|
||||||
zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
|
zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)];
|
U32 fastMode;
|
||||||
FSE_DTable OFTable[FSE_DTABLE_SIZE_U32(OffFSELog)];
|
U32 tableLog;
|
||||||
FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)];
|
} ZSTD_seqSymbol_header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U16 nextState;
|
||||||
|
BYTE nbAdditionalBits;
|
||||||
|
BYTE nbBits;
|
||||||
|
U32 baseValue;
|
||||||
|
} ZSTD_seqSymbol;
|
||||||
|
|
||||||
|
#define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log)))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)];
|
||||||
|
ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)];
|
||||||
|
ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)];
|
||||||
HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
|
HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
|
||||||
U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||||
U32 rep[ZSTD_REP_NUM];
|
U32 rep[ZSTD_REP_NUM];
|
||||||
@@ -91,9 +109,9 @@ typedef struct {
|
|||||||
|
|
||||||
struct ZSTD_DCtx_s
|
struct ZSTD_DCtx_s
|
||||||
{
|
{
|
||||||
const FSE_DTable* LLTptr;
|
const ZSTD_seqSymbol* LLTptr;
|
||||||
const FSE_DTable* MLTptr;
|
const ZSTD_seqSymbol* MLTptr;
|
||||||
const FSE_DTable* OFTptr;
|
const ZSTD_seqSymbol* OFTptr;
|
||||||
const HUF_DTable* HUFptr;
|
const HUF_DTable* HUFptr;
|
||||||
ZSTD_entropyDTables_t entropy;
|
ZSTD_entropyDTables_t entropy;
|
||||||
const void* previousDstEnd; /* detect continuity */
|
const void* previousDstEnd; /* detect continuity */
|
||||||
@@ -116,6 +134,7 @@ struct ZSTD_DCtx_s
|
|||||||
size_t litSize;
|
size_t litSize;
|
||||||
size_t rleSize;
|
size_t rleSize;
|
||||||
size_t staticSize;
|
size_t staticSize;
|
||||||
|
int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
|
||||||
|
|
||||||
/* streaming */
|
/* streaming */
|
||||||
ZSTD_DDict* ddictLocal;
|
ZSTD_DDict* ddictLocal;
|
||||||
@@ -173,6 +192,7 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
|||||||
dctx->inBuffSize = 0;
|
dctx->inBuffSize = 0;
|
||||||
dctx->outBuffSize = 0;
|
dctx->outBuffSize = 0;
|
||||||
dctx->streamStage = zdss_init;
|
dctx->streamStage = zdss_init;
|
||||||
|
dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
|
ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
|
||||||
@@ -204,6 +224,7 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
|
|||||||
|
|
||||||
ZSTD_DCtx* ZSTD_createDCtx(void)
|
ZSTD_DCtx* ZSTD_createDCtx(void)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(3, "ZSTD_createDCtx");
|
||||||
return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
|
return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +255,7 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
|
|||||||
|
|
||||||
|
|
||||||
/*-*************************************************************
|
/*-*************************************************************
|
||||||
* Decompression section
|
* Frame header decoding
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
/*! ZSTD_isFrame() :
|
/*! ZSTD_isFrame() :
|
||||||
@@ -257,7 +278,7 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size)
|
|||||||
|
|
||||||
/** ZSTD_frameHeaderSize_internal() :
|
/** ZSTD_frameHeaderSize_internal() :
|
||||||
* srcSize must be large enough to reach header size fields.
|
* srcSize must be large enough to reach header size fields.
|
||||||
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
|
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
|
||||||
* @return : size of the Frame Header
|
* @return : size of the Frame Header
|
||||||
* or an error code, which can be tested with ZSTD_isError() */
|
* or an error code, which can be tested with ZSTD_isError() */
|
||||||
static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
|
static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
|
||||||
@@ -480,6 +501,10 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************************************
|
||||||
|
* Block decoding
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
/*! ZSTD_getcBlockSize() :
|
/*! ZSTD_getcBlockSize() :
|
||||||
* Provides the size of compressed block from block header `src` */
|
* Provides the size of compressed block from block header `src` */
|
||||||
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
|
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
|
||||||
@@ -566,13 +591,13 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
|||||||
|
|
||||||
if (HUF_isError((litEncType==set_repeat) ?
|
if (HUF_isError((litEncType==set_repeat) ?
|
||||||
( singleStream ?
|
( singleStream ?
|
||||||
HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) :
|
HUF_decompress1X_usingDTable_bmi2(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr, dctx->bmi2) :
|
||||||
HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) ) :
|
HUF_decompress4X_usingDTable_bmi2(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr, dctx->bmi2) ) :
|
||||||
( singleStream ?
|
( singleStream ?
|
||||||
HUF_decompress1X2_DCtx_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize,
|
HUF_decompress1X2_DCtx_wksp_bmi2(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize,
|
||||||
dctx->entropy.workspace, sizeof(dctx->entropy.workspace)) :
|
dctx->entropy.workspace, sizeof(dctx->entropy.workspace), dctx->bmi2) :
|
||||||
HUF_decompress4X_hufOnly_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize,
|
HUF_decompress4X_hufOnly_wksp_bmi2(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize,
|
||||||
dctx->entropy.workspace, sizeof(dctx->entropy.workspace)))))
|
dctx->entropy.workspace, sizeof(dctx->entropy.workspace), dctx->bmi2))))
|
||||||
return ERROR(corruption_detected);
|
return ERROR(corruption_detected);
|
||||||
|
|
||||||
dctx->litPtr = dctx->litBuffer;
|
dctx->litPtr = dctx->litBuffer;
|
||||||
@@ -647,114 +672,267 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default FSE distribution tables.
|
||||||
typedef union {
|
* These are pre-calculated FSE decoding tables using default distributions as defined in specification :
|
||||||
FSE_decode_t realData;
|
* https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions
|
||||||
U32 alignedBy4;
|
* They were generated programmatically with following method :
|
||||||
} FSE_decode_t4;
|
* - start from default distributions, present in /lib/common/zstd_internal.h
|
||||||
|
* - generate tables normally, using ZSTD_buildFSETable()
|
||||||
|
* - printout the content of tables
|
||||||
|
* - pretify output, report below, test with fuzzer to ensure it's correct */
|
||||||
|
|
||||||
/* Default FSE distribution table for Literal Lengths */
|
/* Default FSE distribution table for Literal Lengths */
|
||||||
static const FSE_decode_t4 LL_defaultDTable[(1<<LL_DEFAULTNORMLOG)+1] = {
|
static const ZSTD_seqSymbol LL_defaultDTable[(1<<LL_DEFAULTNORMLOG)+1] = {
|
||||||
{ { LL_DEFAULTNORMLOG, 1, 1 } }, /* header : tableLog, fastMode, fastMode */
|
{ 1, 1, 1, LL_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
|
||||||
/* base, symbol, bits */
|
/* nextState, nbAddBits, nbBits, baseVal */
|
||||||
{ { 0, 0, 4 } }, { { 16, 0, 4 } }, { { 32, 1, 5 } }, { { 0, 3, 5 } },
|
{ 0, 0, 4, 0}, { 16, 0, 4, 0},
|
||||||
{ { 0, 4, 5 } }, { { 0, 6, 5 } }, { { 0, 7, 5 } }, { { 0, 9, 5 } },
|
{ 32, 0, 5, 1}, { 0, 0, 5, 3},
|
||||||
{ { 0, 10, 5 } }, { { 0, 12, 5 } }, { { 0, 14, 6 } }, { { 0, 16, 5 } },
|
{ 0, 0, 5, 4}, { 0, 0, 5, 6},
|
||||||
{ { 0, 18, 5 } }, { { 0, 19, 5 } }, { { 0, 21, 5 } }, { { 0, 22, 5 } },
|
{ 0, 0, 5, 7}, { 0, 0, 5, 9},
|
||||||
{ { 0, 24, 5 } }, { { 32, 25, 5 } }, { { 0, 26, 5 } }, { { 0, 27, 6 } },
|
{ 0, 0, 5, 10}, { 0, 0, 5, 12},
|
||||||
{ { 0, 29, 6 } }, { { 0, 31, 6 } }, { { 32, 0, 4 } }, { { 0, 1, 4 } },
|
{ 0, 0, 6, 14}, { 0, 1, 5, 16},
|
||||||
{ { 0, 2, 5 } }, { { 32, 4, 5 } }, { { 0, 5, 5 } }, { { 32, 7, 5 } },
|
{ 0, 1, 5, 20}, { 0, 1, 5, 22},
|
||||||
{ { 0, 8, 5 } }, { { 32, 10, 5 } }, { { 0, 11, 5 } }, { { 0, 13, 6 } },
|
{ 0, 2, 5, 28}, { 0, 3, 5, 32},
|
||||||
{ { 32, 16, 5 } }, { { 0, 17, 5 } }, { { 32, 19, 5 } }, { { 0, 20, 5 } },
|
{ 0, 4, 5, 48}, { 32, 6, 5, 64},
|
||||||
{ { 32, 22, 5 } }, { { 0, 23, 5 } }, { { 0, 25, 4 } }, { { 16, 25, 4 } },
|
{ 0, 7, 5, 128}, { 0, 8, 6, 256},
|
||||||
{ { 32, 26, 5 } }, { { 0, 28, 6 } }, { { 0, 30, 6 } }, { { 48, 0, 4 } },
|
{ 0, 10, 6, 1024}, { 0, 12, 6, 4096},
|
||||||
{ { 16, 1, 4 } }, { { 32, 2, 5 } }, { { 32, 3, 5 } }, { { 32, 5, 5 } },
|
{ 32, 0, 4, 0}, { 0, 0, 4, 1},
|
||||||
{ { 32, 6, 5 } }, { { 32, 8, 5 } }, { { 32, 9, 5 } }, { { 32, 11, 5 } },
|
{ 0, 0, 5, 2}, { 32, 0, 5, 4},
|
||||||
{ { 32, 12, 5 } }, { { 0, 15, 6 } }, { { 32, 17, 5 } }, { { 32, 18, 5 } },
|
{ 0, 0, 5, 5}, { 32, 0, 5, 7},
|
||||||
{ { 32, 20, 5 } }, { { 32, 21, 5 } }, { { 32, 23, 5 } }, { { 32, 24, 5 } },
|
{ 0, 0, 5, 8}, { 32, 0, 5, 10},
|
||||||
{ { 0, 35, 6 } }, { { 0, 34, 6 } }, { { 0, 33, 6 } }, { { 0, 32, 6 } },
|
{ 0, 0, 5, 11}, { 0, 0, 6, 13},
|
||||||
|
{ 32, 1, 5, 16}, { 0, 1, 5, 18},
|
||||||
|
{ 32, 1, 5, 22}, { 0, 2, 5, 24},
|
||||||
|
{ 32, 3, 5, 32}, { 0, 3, 5, 40},
|
||||||
|
{ 0, 6, 4, 64}, { 16, 6, 4, 64},
|
||||||
|
{ 32, 7, 5, 128}, { 0, 9, 6, 512},
|
||||||
|
{ 0, 11, 6, 2048}, { 48, 0, 4, 0},
|
||||||
|
{ 16, 0, 4, 1}, { 32, 0, 5, 2},
|
||||||
|
{ 32, 0, 5, 3}, { 32, 0, 5, 5},
|
||||||
|
{ 32, 0, 5, 6}, { 32, 0, 5, 8},
|
||||||
|
{ 32, 0, 5, 9}, { 32, 0, 5, 11},
|
||||||
|
{ 32, 0, 5, 12}, { 0, 0, 6, 15},
|
||||||
|
{ 32, 1, 5, 18}, { 32, 1, 5, 20},
|
||||||
|
{ 32, 2, 5, 24}, { 32, 2, 5, 28},
|
||||||
|
{ 32, 3, 5, 40}, { 32, 4, 5, 48},
|
||||||
|
{ 0, 16, 6,65536}, { 0, 15, 6,32768},
|
||||||
|
{ 0, 14, 6,16384}, { 0, 13, 6, 8192},
|
||||||
}; /* LL_defaultDTable */
|
}; /* LL_defaultDTable */
|
||||||
|
|
||||||
|
/* Default FSE distribution table for Offset Codes */
|
||||||
|
static const ZSTD_seqSymbol OF_defaultDTable[(1<<OF_DEFAULTNORMLOG)+1] = {
|
||||||
|
{ 1, 1, 1, OF_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
|
||||||
|
/* nextState, nbAddBits, nbBits, baseVal */
|
||||||
|
{ 0, 0, 5, 0}, { 0, 6, 4, 61},
|
||||||
|
{ 0, 9, 5, 509}, { 0, 15, 5,32765},
|
||||||
|
{ 0, 21, 5,2097149}, { 0, 3, 5, 5},
|
||||||
|
{ 0, 7, 4, 125}, { 0, 12, 5, 4093},
|
||||||
|
{ 0, 18, 5,262141}, { 0, 23, 5,8388605},
|
||||||
|
{ 0, 5, 5, 29}, { 0, 8, 4, 253},
|
||||||
|
{ 0, 14, 5,16381}, { 0, 20, 5,1048573},
|
||||||
|
{ 0, 2, 5, 1}, { 16, 7, 4, 125},
|
||||||
|
{ 0, 11, 5, 2045}, { 0, 17, 5,131069},
|
||||||
|
{ 0, 22, 5,4194301}, { 0, 4, 5, 13},
|
||||||
|
{ 16, 8, 4, 253}, { 0, 13, 5, 8189},
|
||||||
|
{ 0, 19, 5,524285}, { 0, 1, 5, 1},
|
||||||
|
{ 16, 6, 4, 61}, { 0, 10, 5, 1021},
|
||||||
|
{ 0, 16, 5,65533}, { 0, 28, 5,268435453},
|
||||||
|
{ 0, 27, 5,134217725}, { 0, 26, 5,67108861},
|
||||||
|
{ 0, 25, 5,33554429}, { 0, 24, 5,16777213},
|
||||||
|
}; /* OF_defaultDTable */
|
||||||
|
|
||||||
|
|
||||||
/* Default FSE distribution table for Match Lengths */
|
/* Default FSE distribution table for Match Lengths */
|
||||||
static const FSE_decode_t4 ML_defaultDTable[(1<<ML_DEFAULTNORMLOG)+1] = {
|
static const ZSTD_seqSymbol ML_defaultDTable[(1<<ML_DEFAULTNORMLOG)+1] = {
|
||||||
{ { ML_DEFAULTNORMLOG, 1, 1 } }, /* header : tableLog, fastMode, fastMode */
|
{ 1, 1, 1, ML_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
|
||||||
/* base, symbol, bits */
|
/* nextState, nbAddBits, nbBits, baseVal */
|
||||||
{ { 0, 0, 6 } }, { { 0, 1, 4 } }, { { 32, 2, 5 } }, { { 0, 3, 5 } },
|
{ 0, 0, 6, 3}, { 0, 0, 4, 4},
|
||||||
{ { 0, 5, 5 } }, { { 0, 6, 5 } }, { { 0, 8, 5 } }, { { 0, 10, 6 } },
|
{ 32, 0, 5, 5}, { 0, 0, 5, 6},
|
||||||
{ { 0, 13, 6 } }, { { 0, 16, 6 } }, { { 0, 19, 6 } }, { { 0, 22, 6 } },
|
{ 0, 0, 5, 8}, { 0, 0, 5, 9},
|
||||||
{ { 0, 25, 6 } }, { { 0, 28, 6 } }, { { 0, 31, 6 } }, { { 0, 33, 6 } },
|
{ 0, 0, 5, 11}, { 0, 0, 6, 13},
|
||||||
{ { 0, 35, 6 } }, { { 0, 37, 6 } }, { { 0, 39, 6 } }, { { 0, 41, 6 } },
|
{ 0, 0, 6, 16}, { 0, 0, 6, 19},
|
||||||
{ { 0, 43, 6 } }, { { 0, 45, 6 } }, { { 16, 1, 4 } }, { { 0, 2, 4 } },
|
{ 0, 0, 6, 22}, { 0, 0, 6, 25},
|
||||||
{ { 32, 3, 5 } }, { { 0, 4, 5 } }, { { 32, 6, 5 } }, { { 0, 7, 5 } },
|
{ 0, 0, 6, 28}, { 0, 0, 6, 31},
|
||||||
{ { 0, 9, 6 } }, { { 0, 12, 6 } }, { { 0, 15, 6 } }, { { 0, 18, 6 } },
|
{ 0, 0, 6, 34}, { 0, 1, 6, 37},
|
||||||
{ { 0, 21, 6 } }, { { 0, 24, 6 } }, { { 0, 27, 6 } }, { { 0, 30, 6 } },
|
{ 0, 1, 6, 41}, { 0, 2, 6, 47},
|
||||||
{ { 0, 32, 6 } }, { { 0, 34, 6 } }, { { 0, 36, 6 } }, { { 0, 38, 6 } },
|
{ 0, 3, 6, 59}, { 0, 4, 6, 83},
|
||||||
{ { 0, 40, 6 } }, { { 0, 42, 6 } }, { { 0, 44, 6 } }, { { 32, 1, 4 } },
|
{ 0, 7, 6, 131}, { 0, 9, 6, 515},
|
||||||
{ { 48, 1, 4 } }, { { 16, 2, 4 } }, { { 32, 4, 5 } }, { { 32, 5, 5 } },
|
{ 16, 0, 4, 4}, { 0, 0, 4, 5},
|
||||||
{ { 32, 7, 5 } }, { { 32, 8, 5 } }, { { 0, 11, 6 } }, { { 0, 14, 6 } },
|
{ 32, 0, 5, 6}, { 0, 0, 5, 7},
|
||||||
{ { 0, 17, 6 } }, { { 0, 20, 6 } }, { { 0, 23, 6 } }, { { 0, 26, 6 } },
|
{ 32, 0, 5, 9}, { 0, 0, 5, 10},
|
||||||
{ { 0, 29, 6 } }, { { 0, 52, 6 } }, { { 0, 51, 6 } }, { { 0, 50, 6 } },
|
{ 0, 0, 6, 12}, { 0, 0, 6, 15},
|
||||||
{ { 0, 49, 6 } }, { { 0, 48, 6 } }, { { 0, 47, 6 } }, { { 0, 46, 6 } },
|
{ 0, 0, 6, 18}, { 0, 0, 6, 21},
|
||||||
|
{ 0, 0, 6, 24}, { 0, 0, 6, 27},
|
||||||
|
{ 0, 0, 6, 30}, { 0, 0, 6, 33},
|
||||||
|
{ 0, 1, 6, 35}, { 0, 1, 6, 39},
|
||||||
|
{ 0, 2, 6, 43}, { 0, 3, 6, 51},
|
||||||
|
{ 0, 4, 6, 67}, { 0, 5, 6, 99},
|
||||||
|
{ 0, 8, 6, 259}, { 32, 0, 4, 4},
|
||||||
|
{ 48, 0, 4, 4}, { 16, 0, 4, 5},
|
||||||
|
{ 32, 0, 5, 7}, { 32, 0, 5, 8},
|
||||||
|
{ 32, 0, 5, 10}, { 32, 0, 5, 11},
|
||||||
|
{ 0, 0, 6, 14}, { 0, 0, 6, 17},
|
||||||
|
{ 0, 0, 6, 20}, { 0, 0, 6, 23},
|
||||||
|
{ 0, 0, 6, 26}, { 0, 0, 6, 29},
|
||||||
|
{ 0, 0, 6, 32}, { 0, 16, 6,65539},
|
||||||
|
{ 0, 15, 6,32771}, { 0, 14, 6,16387},
|
||||||
|
{ 0, 13, 6, 8195}, { 0, 12, 6, 4099},
|
||||||
|
{ 0, 11, 6, 2051}, { 0, 10, 6, 1027},
|
||||||
}; /* ML_defaultDTable */
|
}; /* ML_defaultDTable */
|
||||||
|
|
||||||
/* Default FSE distribution table for Offset Codes */
|
|
||||||
static const FSE_decode_t4 OF_defaultDTable[(1<<OF_DEFAULTNORMLOG)+1] = {
|
static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddBits)
|
||||||
{ { OF_DEFAULTNORMLOG, 1, 1 } }, /* header : tableLog, fastMode, fastMode */
|
{
|
||||||
/* base, symbol, bits */
|
void* ptr = dt;
|
||||||
{ { 0, 0, 5 } }, { { 0, 6, 4 } },
|
ZSTD_seqSymbol_header* const DTableH = (ZSTD_seqSymbol_header*)ptr;
|
||||||
{ { 0, 9, 5 } }, { { 0, 15, 5 } },
|
ZSTD_seqSymbol* const cell = dt + 1;
|
||||||
{ { 0, 21, 5 } }, { { 0, 3, 5 } },
|
|
||||||
{ { 0, 7, 4 } }, { { 0, 12, 5 } },
|
DTableH->tableLog = 0;
|
||||||
{ { 0, 18, 5 } }, { { 0, 23, 5 } },
|
DTableH->fastMode = 0;
|
||||||
{ { 0, 5, 5 } }, { { 0, 8, 4 } },
|
|
||||||
{ { 0, 14, 5 } }, { { 0, 20, 5 } },
|
cell->nbBits = 0;
|
||||||
{ { 0, 2, 5 } }, { { 16, 7, 4 } },
|
cell->nextState = 0;
|
||||||
{ { 0, 11, 5 } }, { { 0, 17, 5 } },
|
assert(nbAddBits < 255);
|
||||||
{ { 0, 22, 5 } }, { { 0, 4, 5 } },
|
cell->nbAdditionalBits = (BYTE)nbAddBits;
|
||||||
{ { 16, 8, 4 } }, { { 0, 13, 5 } },
|
cell->baseValue = baseValue;
|
||||||
{ { 0, 19, 5 } }, { { 0, 1, 5 } },
|
}
|
||||||
{ { 16, 6, 4 } }, { { 0, 10, 5 } },
|
|
||||||
{ { 0, 16, 5 } }, { { 0, 28, 5 } },
|
|
||||||
{ { 0, 27, 5 } }, { { 0, 26, 5 } },
|
/* ZSTD_buildFSETable() :
|
||||||
{ { 0, 25, 5 } }, { { 0, 24, 5 } },
|
* generate FSE decoding table for one symbol (ll, ml or off) */
|
||||||
}; /* OF_defaultDTable */
|
static void
|
||||||
|
ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
|
||||||
|
const short* normalizedCounter, unsigned maxSymbolValue,
|
||||||
|
const U32* baseValue, const U32* nbAdditionalBits,
|
||||||
|
unsigned tableLog)
|
||||||
|
{
|
||||||
|
ZSTD_seqSymbol* const tableDecode = dt+1;
|
||||||
|
U16 symbolNext[MaxSeq+1];
|
||||||
|
|
||||||
|
U32 const maxSV1 = maxSymbolValue + 1;
|
||||||
|
U32 const tableSize = 1 << tableLog;
|
||||||
|
U32 highThreshold = tableSize-1;
|
||||||
|
|
||||||
|
/* Sanity Checks */
|
||||||
|
assert(maxSymbolValue <= MaxSeq);
|
||||||
|
assert(tableLog <= MaxFSELog);
|
||||||
|
|
||||||
|
/* Init, lay down lowprob symbols */
|
||||||
|
{ ZSTD_seqSymbol_header DTableH;
|
||||||
|
DTableH.tableLog = tableLog;
|
||||||
|
DTableH.fastMode = 1;
|
||||||
|
{ S16 const largeLimit= (S16)(1 << (tableLog-1));
|
||||||
|
U32 s;
|
||||||
|
for (s=0; s<maxSV1; s++) {
|
||||||
|
if (normalizedCounter[s]==-1) {
|
||||||
|
tableDecode[highThreshold--].baseValue = s;
|
||||||
|
symbolNext[s] = 1;
|
||||||
|
} else {
|
||||||
|
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
||||||
|
symbolNext[s] = normalizedCounter[s];
|
||||||
|
} } }
|
||||||
|
memcpy(dt, &DTableH, sizeof(DTableH));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spread symbols */
|
||||||
|
{ U32 const tableMask = tableSize-1;
|
||||||
|
U32 const step = FSE_TABLESTEP(tableSize);
|
||||||
|
U32 s, position = 0;
|
||||||
|
for (s=0; s<maxSV1; s++) {
|
||||||
|
int i;
|
||||||
|
for (i=0; i<normalizedCounter[s]; i++) {
|
||||||
|
tableDecode[position].baseValue = s;
|
||||||
|
position = (position + step) & tableMask;
|
||||||
|
while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
|
||||||
|
} }
|
||||||
|
assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build Decoding table */
|
||||||
|
{ U32 u;
|
||||||
|
for (u=0; u<tableSize; u++) {
|
||||||
|
U32 const symbol = tableDecode[u].baseValue;
|
||||||
|
U32 const nextState = symbolNext[symbol]++;
|
||||||
|
tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
|
||||||
|
tableDecode[u].nextState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
|
||||||
|
assert(nbAdditionalBits[symbol] < 255);
|
||||||
|
tableDecode[u].nbAdditionalBits = (BYTE)nbAdditionalBits[symbol];
|
||||||
|
tableDecode[u].baseValue = baseValue[symbol];
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTD_buildSeqTable() :
|
/*! ZSTD_buildSeqTable() :
|
||||||
* @return : nb bytes read from src,
|
* @return : nb bytes read from src,
|
||||||
* or an error code if it fails, testable with ZSTD_isError()
|
* or an error code if it fails */
|
||||||
*/
|
static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymbol** DTablePtr,
|
||||||
static size_t ZSTD_buildSeqTable(FSE_DTable* DTableSpace, const FSE_DTable** DTablePtr,
|
|
||||||
symbolEncodingType_e type, U32 max, U32 maxLog,
|
symbolEncodingType_e type, U32 max, U32 maxLog,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const FSE_decode_t4* defaultTable, U32 flagRepeatTable)
|
const U32* baseValue, const U32* nbAdditionalBits,
|
||||||
|
const ZSTD_seqSymbol* defaultTable, U32 flagRepeatTable)
|
||||||
{
|
{
|
||||||
const void* const tmpPtr = defaultTable; /* bypass strict aliasing */
|
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case set_rle :
|
case set_rle :
|
||||||
if (!srcSize) return ERROR(srcSize_wrong);
|
if (!srcSize) return ERROR(srcSize_wrong);
|
||||||
if ( (*(const BYTE*)src) > max) return ERROR(corruption_detected);
|
if ( (*(const BYTE*)src) > max) return ERROR(corruption_detected);
|
||||||
FSE_buildDTable_rle(DTableSpace, *(const BYTE*)src);
|
{ U32 const symbol = *(const BYTE*)src;
|
||||||
|
U32 const baseline = baseValue[symbol];
|
||||||
|
U32 const nbBits = nbAdditionalBits[symbol];
|
||||||
|
ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits);
|
||||||
|
}
|
||||||
*DTablePtr = DTableSpace;
|
*DTablePtr = DTableSpace;
|
||||||
return 1;
|
return 1;
|
||||||
case set_basic :
|
case set_basic :
|
||||||
*DTablePtr = (const FSE_DTable*)tmpPtr;
|
*DTablePtr = defaultTable;
|
||||||
return 0;
|
return 0;
|
||||||
case set_repeat:
|
case set_repeat:
|
||||||
if (!flagRepeatTable) return ERROR(corruption_detected);
|
if (!flagRepeatTable) return ERROR(corruption_detected);
|
||||||
return 0;
|
return 0;
|
||||||
default : /* impossible */
|
|
||||||
case set_compressed :
|
case set_compressed :
|
||||||
{ U32 tableLog;
|
{ U32 tableLog;
|
||||||
S16 norm[MaxSeq+1];
|
S16 norm[MaxSeq+1];
|
||||||
size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
|
size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
|
||||||
if (FSE_isError(headerSize)) return ERROR(corruption_detected);
|
if (FSE_isError(headerSize)) return ERROR(corruption_detected);
|
||||||
if (tableLog > maxLog) return ERROR(corruption_detected);
|
if (tableLog > maxLog) return ERROR(corruption_detected);
|
||||||
FSE_buildDTable(DTableSpace, norm, max, tableLog);
|
ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog);
|
||||||
*DTablePtr = DTableSpace;
|
*DTablePtr = DTableSpace;
|
||||||
return headerSize;
|
return headerSize;
|
||||||
} }
|
|
||||||
}
|
}
|
||||||
|
default : /* impossible */
|
||||||
|
assert(0);
|
||||||
|
return ERROR(GENERIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const U32 LL_base[MaxLL+1] = {
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
16, 18, 20, 22, 24, 28, 32, 40,
|
||||||
|
48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
|
||||||
|
0x2000, 0x4000, 0x8000, 0x10000 };
|
||||||
|
|
||||||
|
static const U32 OF_base[MaxOff+1] = {
|
||||||
|
0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
|
||||||
|
0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
|
||||||
|
0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
|
||||||
|
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
|
||||||
|
|
||||||
|
static const U32 OF_bits[MaxOff+1] = {
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
16, 17, 18, 19, 20, 21, 22, 23,
|
||||||
|
24, 25, 26, 27, 28, 29, 30, 31 };
|
||||||
|
|
||||||
|
static const U32 ML_base[MaxML+1] = {
|
||||||
|
3, 4, 5, 6, 7, 8, 9, 10,
|
||||||
|
11, 12, 13, 14, 15, 16, 17, 18,
|
||||||
|
19, 20, 21, 22, 23, 24, 25, 26,
|
||||||
|
27, 28, 29, 30, 31, 32, 33, 34,
|
||||||
|
35, 37, 39, 41, 43, 47, 51, 59,
|
||||||
|
67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
|
||||||
|
0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
|
size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
|
||||||
const void* src, size_t srcSize)
|
const void* src, size_t srcSize)
|
||||||
@@ -792,19 +970,27 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
|
|||||||
/* Build DTables */
|
/* Build DTables */
|
||||||
{ size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr,
|
{ size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr,
|
||||||
LLtype, MaxLL, LLFSELog,
|
LLtype, MaxLL, LLFSELog,
|
||||||
ip, iend-ip, LL_defaultDTable, dctx->fseEntropy);
|
ip, iend-ip,
|
||||||
|
LL_base, LL_bits,
|
||||||
|
LL_defaultDTable, dctx->fseEntropy);
|
||||||
if (ZSTD_isError(llhSize)) return ERROR(corruption_detected);
|
if (ZSTD_isError(llhSize)) return ERROR(corruption_detected);
|
||||||
ip += llhSize;
|
ip += llhSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr,
|
{ size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr,
|
||||||
OFtype, MaxOff, OffFSELog,
|
OFtype, MaxOff, OffFSELog,
|
||||||
ip, iend-ip, OF_defaultDTable, dctx->fseEntropy);
|
ip, iend-ip,
|
||||||
|
OF_base, OF_bits,
|
||||||
|
OF_defaultDTable, dctx->fseEntropy);
|
||||||
if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected);
|
if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected);
|
||||||
ip += ofhSize;
|
ip += ofhSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr,
|
{ size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr,
|
||||||
MLtype, MaxML, MLFSELog,
|
MLtype, MaxML, MLFSELog,
|
||||||
ip, iend-ip, ML_defaultDTable, dctx->fseEntropy);
|
ip, iend-ip,
|
||||||
|
ML_base, ML_bits,
|
||||||
|
ML_defaultDTable, dctx->fseEntropy);
|
||||||
if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected);
|
if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected);
|
||||||
ip += mlhSize;
|
ip += mlhSize;
|
||||||
}
|
}
|
||||||
@@ -821,11 +1007,16 @@ typedef struct {
|
|||||||
const BYTE* match;
|
const BYTE* match;
|
||||||
} seq_t;
|
} seq_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t state;
|
||||||
|
const ZSTD_seqSymbol* table;
|
||||||
|
} ZSTD_fseState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BIT_DStream_t DStream;
|
BIT_DStream_t DStream;
|
||||||
FSE_DState_t stateLL;
|
ZSTD_fseState stateLL;
|
||||||
FSE_DState_t stateOffb;
|
ZSTD_fseState stateOffb;
|
||||||
FSE_DState_t stateML;
|
ZSTD_fseState stateML;
|
||||||
size_t prevOffset[ZSTD_REP_NUM];
|
size_t prevOffset[ZSTD_REP_NUM];
|
||||||
const BYTE* prefixStart;
|
const BYTE* prefixStart;
|
||||||
const BYTE* dictEnd;
|
const BYTE* dictEnd;
|
||||||
@@ -880,118 +1071,6 @@ size_t ZSTD_execSequenceLast7(BYTE* op,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
|
|
||||||
|
|
||||||
/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
|
|
||||||
* offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
|
|
||||||
* bits before reloading. This value is the maximum number of bytes we read
|
|
||||||
* after reloading when we are decoding long offets.
|
|
||||||
*/
|
|
||||||
#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \
|
|
||||||
(ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \
|
|
||||||
? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \
|
|
||||||
: 0)
|
|
||||||
|
|
||||||
static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
|
|
||||||
{
|
|
||||||
seq_t seq;
|
|
||||||
|
|
||||||
U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
|
|
||||||
U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
|
|
||||||
U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= MaxOff, by table construction */
|
|
||||||
|
|
||||||
U32 const llBits = LL_bits[llCode];
|
|
||||||
U32 const mlBits = ML_bits[mlCode];
|
|
||||||
U32 const ofBits = ofCode;
|
|
||||||
U32 const totalBits = llBits+mlBits+ofBits;
|
|
||||||
|
|
||||||
static const U32 LL_base[MaxLL+1] = {
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7,
|
|
||||||
8, 9, 10, 11, 12, 13, 14, 15,
|
|
||||||
16, 18, 20, 22, 24, 28, 32, 40,
|
|
||||||
48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
|
|
||||||
0x2000, 0x4000, 0x8000, 0x10000 };
|
|
||||||
|
|
||||||
static const U32 ML_base[MaxML+1] = {
|
|
||||||
3, 4, 5, 6, 7, 8, 9, 10,
|
|
||||||
11, 12, 13, 14, 15, 16, 17, 18,
|
|
||||||
19, 20, 21, 22, 23, 24, 25, 26,
|
|
||||||
27, 28, 29, 30, 31, 32, 33, 34,
|
|
||||||
35, 37, 39, 41, 43, 47, 51, 59,
|
|
||||||
67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
|
|
||||||
0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
|
|
||||||
|
|
||||||
static const U32 OF_base[MaxOff+1] = {
|
|
||||||
0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
|
|
||||||
0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
|
|
||||||
0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
|
|
||||||
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
|
|
||||||
|
|
||||||
/* sequence */
|
|
||||||
{ size_t offset;
|
|
||||||
if (!ofCode)
|
|
||||||
offset = 0;
|
|
||||||
else {
|
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
|
||||||
ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
|
|
||||||
assert(ofBits <= MaxOff);
|
|
||||||
if (MEM_32bits() && longOffsets) {
|
|
||||||
U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
|
|
||||||
offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
|
|
||||||
if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
|
|
||||||
if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
|
|
||||||
} else {
|
|
||||||
offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
|
|
||||||
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ofCode <= 1) {
|
|
||||||
offset += (llCode==0);
|
|
||||||
if (offset) {
|
|
||||||
size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
|
|
||||||
temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
|
|
||||||
if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
|
|
||||||
seqState->prevOffset[1] = seqState->prevOffset[0];
|
|
||||||
seqState->prevOffset[0] = offset = temp;
|
|
||||||
} else {
|
|
||||||
offset = seqState->prevOffset[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
seqState->prevOffset[2] = seqState->prevOffset[1];
|
|
||||||
seqState->prevOffset[1] = seqState->prevOffset[0];
|
|
||||||
seqState->prevOffset[0] = offset;
|
|
||||||
}
|
|
||||||
seq.offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
seq.matchLength = ML_base[mlCode]
|
|
||||||
+ ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
|
|
||||||
if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
|
|
||||||
BIT_reloadDStream(&seqState->DStream);
|
|
||||||
if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
|
|
||||||
BIT_reloadDStream(&seqState->DStream);
|
|
||||||
/* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
|
|
||||||
ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
|
|
||||||
|
|
||||||
seq.litLength = LL_base[llCode]
|
|
||||||
+ ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
|
|
||||||
if (MEM_32bits())
|
|
||||||
BIT_reloadDStream(&seqState->DStream);
|
|
||||||
|
|
||||||
DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
|
|
||||||
(U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
|
|
||||||
|
|
||||||
/* ANS state update */
|
|
||||||
FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
|
|
||||||
FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
|
|
||||||
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
|
|
||||||
FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
|
|
||||||
|
|
||||||
return seq;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HINT_INLINE
|
HINT_INLINE
|
||||||
size_t ZSTD_execSequence(BYTE* op,
|
size_t ZSTD_execSequence(BYTE* op,
|
||||||
BYTE* const oend, seq_t sequence,
|
BYTE* const oend, seq_t sequence,
|
||||||
@@ -1073,173 +1152,6 @@ size_t ZSTD_execSequence(BYTE* op,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTD_decompressSequences(
|
|
||||||
ZSTD_DCtx* dctx,
|
|
||||||
void* dst, size_t maxDstSize,
|
|
||||||
const void* seqStart, size_t seqSize,
|
|
||||||
const ZSTD_longOffset_e isLongOffset)
|
|
||||||
{
|
|
||||||
const BYTE* ip = (const BYTE*)seqStart;
|
|
||||||
const BYTE* const iend = ip + seqSize;
|
|
||||||
BYTE* const ostart = (BYTE* const)dst;
|
|
||||||
BYTE* const oend = ostart + maxDstSize;
|
|
||||||
BYTE* op = ostart;
|
|
||||||
const BYTE* litPtr = dctx->litPtr;
|
|
||||||
const BYTE* const litEnd = litPtr + dctx->litSize;
|
|
||||||
const BYTE* const base = (const BYTE*) (dctx->base);
|
|
||||||
const BYTE* const vBase = (const BYTE*) (dctx->vBase);
|
|
||||||
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
|
||||||
int nbSeq;
|
|
||||||
DEBUGLOG(5, "ZSTD_decompressSequences");
|
|
||||||
|
|
||||||
/* Build Decoding Tables */
|
|
||||||
{ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
|
|
||||||
DEBUGLOG(5, "ZSTD_decodeSeqHeaders: size=%u, nbSeq=%i",
|
|
||||||
(U32)seqHSize, nbSeq);
|
|
||||||
if (ZSTD_isError(seqHSize)) return seqHSize;
|
|
||||||
ip += seqHSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Regen sequences */
|
|
||||||
if (nbSeq) {
|
|
||||||
seqState_t seqState;
|
|
||||||
dctx->fseEntropy = 1;
|
|
||||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
|
|
||||||
CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
|
|
||||||
FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
|
|
||||||
FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
|
|
||||||
FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
|
|
||||||
|
|
||||||
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) {
|
|
||||||
nbSeq--;
|
|
||||||
{ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
|
|
||||||
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
|
|
||||||
DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
|
|
||||||
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
|
||||||
op += oneSeqSize;
|
|
||||||
} }
|
|
||||||
|
|
||||||
/* check if reached exact end */
|
|
||||||
DEBUGLOG(5, "after decode loop, remaining nbSeq : %i", nbSeq);
|
|
||||||
if (nbSeq) return ERROR(corruption_detected);
|
|
||||||
/* save reps for next block */
|
|
||||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* last literal segment */
|
|
||||||
{ size_t const lastLLSize = litEnd - litPtr;
|
|
||||||
if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
|
|
||||||
memcpy(op, litPtr, lastLLSize);
|
|
||||||
op += lastLLSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return op-ostart;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HINT_INLINE
|
|
||||||
seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
|
|
||||||
{
|
|
||||||
seq_t seq;
|
|
||||||
|
|
||||||
U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
|
|
||||||
U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
|
|
||||||
U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= MaxOff, by table construction */
|
|
||||||
|
|
||||||
U32 const llBits = LL_bits[llCode];
|
|
||||||
U32 const mlBits = ML_bits[mlCode];
|
|
||||||
U32 const ofBits = ofCode;
|
|
||||||
U32 const totalBits = llBits+mlBits+ofBits;
|
|
||||||
|
|
||||||
static const U32 LL_base[MaxLL+1] = {
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7,
|
|
||||||
8, 9, 10, 11, 12, 13, 14, 15,
|
|
||||||
16, 18, 20, 22, 24, 28, 32, 40,
|
|
||||||
48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
|
|
||||||
0x2000, 0x4000, 0x8000, 0x10000 };
|
|
||||||
|
|
||||||
static const U32 ML_base[MaxML+1] = {
|
|
||||||
3, 4, 5, 6, 7, 8, 9, 10,
|
|
||||||
11, 12, 13, 14, 15, 16, 17, 18,
|
|
||||||
19, 20, 21, 22, 23, 24, 25, 26,
|
|
||||||
27, 28, 29, 30, 31, 32, 33, 34,
|
|
||||||
35, 37, 39, 41, 43, 47, 51, 59,
|
|
||||||
67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
|
|
||||||
0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
|
|
||||||
|
|
||||||
static const U32 OF_base[MaxOff+1] = {
|
|
||||||
0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
|
|
||||||
0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
|
|
||||||
0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
|
|
||||||
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
|
|
||||||
|
|
||||||
/* sequence */
|
|
||||||
{ size_t offset;
|
|
||||||
if (!ofCode)
|
|
||||||
offset = 0;
|
|
||||||
else {
|
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
|
||||||
ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
|
|
||||||
assert(ofBits <= MaxOff);
|
|
||||||
if (MEM_32bits() && longOffsets) {
|
|
||||||
U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
|
|
||||||
offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
|
|
||||||
if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
|
|
||||||
if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
|
|
||||||
} else {
|
|
||||||
offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
|
|
||||||
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ofCode <= 1) {
|
|
||||||
offset += (llCode==0);
|
|
||||||
if (offset) {
|
|
||||||
size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
|
|
||||||
temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
|
|
||||||
if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
|
|
||||||
seqState->prevOffset[1] = seqState->prevOffset[0];
|
|
||||||
seqState->prevOffset[0] = offset = temp;
|
|
||||||
} else {
|
|
||||||
offset = seqState->prevOffset[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
seqState->prevOffset[2] = seqState->prevOffset[1];
|
|
||||||
seqState->prevOffset[1] = seqState->prevOffset[0];
|
|
||||||
seqState->prevOffset[0] = offset;
|
|
||||||
}
|
|
||||||
seq.offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
seq.matchLength = ML_base[mlCode] + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
|
|
||||||
if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
|
|
||||||
BIT_reloadDStream(&seqState->DStream);
|
|
||||||
if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
|
|
||||||
BIT_reloadDStream(&seqState->DStream);
|
|
||||||
/* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
|
|
||||||
ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
|
|
||||||
|
|
||||||
seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
|
|
||||||
if (MEM_32bits())
|
|
||||||
BIT_reloadDStream(&seqState->DStream);
|
|
||||||
|
|
||||||
{ size_t const pos = seqState->pos + seq.litLength;
|
|
||||||
const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
|
|
||||||
seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
|
|
||||||
* No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */
|
|
||||||
seqState->pos = pos + seq.matchLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ANS state update */
|
|
||||||
FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
|
|
||||||
FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
|
|
||||||
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
|
|
||||||
FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
|
|
||||||
|
|
||||||
return seq;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HINT_INLINE
|
HINT_INLINE
|
||||||
size_t ZSTD_execSequenceLong(BYTE* op,
|
size_t ZSTD_execSequenceLong(BYTE* op,
|
||||||
BYTE* const oend, seq_t sequence,
|
BYTE* const oend, seq_t sequence,
|
||||||
@@ -1319,10 +1231,264 @@ size_t ZSTD_execSequenceLong(BYTE* op,
|
|||||||
return sequenceLength;
|
return sequenceLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_decompressSequencesLong(
|
static void
|
||||||
|
ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt)
|
||||||
|
{
|
||||||
|
const void* ptr = dt;
|
||||||
|
const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr;
|
||||||
|
DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
|
||||||
|
DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits",
|
||||||
|
(U32)DStatePtr->state, DTableH->tableLog);
|
||||||
|
BIT_reloadDStream(bitD);
|
||||||
|
DStatePtr->table = dt + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE void
|
||||||
|
ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state];
|
||||||
|
U32 const nbBits = DInfo.nbBits;
|
||||||
|
size_t const lowBits = BIT_readBits(bitD, nbBits);
|
||||||
|
DStatePtr->state = DInfo.nextState + lowBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
|
||||||
|
* offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
|
||||||
|
* bits before reloading. This value is the maximum number of bytes we read
|
||||||
|
* after reloading when we are decoding long offets.
|
||||||
|
*/
|
||||||
|
#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \
|
||||||
|
(ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \
|
||||||
|
? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \
|
||||||
|
: 0)
|
||||||
|
|
||||||
|
typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE seq_t
|
||||||
|
ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
|
||||||
|
{
|
||||||
|
seq_t seq;
|
||||||
|
U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
|
||||||
|
U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
|
||||||
|
U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
|
||||||
|
U32 const totalBits = llBits+mlBits+ofBits;
|
||||||
|
U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
|
||||||
|
U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
|
||||||
|
U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
|
||||||
|
|
||||||
|
/* sequence */
|
||||||
|
{ size_t offset;
|
||||||
|
if (!ofBits)
|
||||||
|
offset = 0;
|
||||||
|
else {
|
||||||
|
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
||||||
|
ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
|
||||||
|
assert(ofBits <= MaxOff);
|
||||||
|
if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) {
|
||||||
|
U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed);
|
||||||
|
offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
|
||||||
|
BIT_reloadDStream(&seqState->DStream);
|
||||||
|
if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
|
||||||
|
assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */
|
||||||
|
} else {
|
||||||
|
offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
|
||||||
|
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ofBits <= 1) {
|
||||||
|
offset += (llBase==0);
|
||||||
|
if (offset) {
|
||||||
|
size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
|
||||||
|
temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
|
||||||
|
if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
|
||||||
|
seqState->prevOffset[1] = seqState->prevOffset[0];
|
||||||
|
seqState->prevOffset[0] = offset = temp;
|
||||||
|
} else { /* offset == 0 */
|
||||||
|
offset = seqState->prevOffset[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
seqState->prevOffset[2] = seqState->prevOffset[1];
|
||||||
|
seqState->prevOffset[1] = seqState->prevOffset[0];
|
||||||
|
seqState->prevOffset[0] = offset;
|
||||||
|
}
|
||||||
|
seq.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq.matchLength = mlBase
|
||||||
|
+ ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/) : 0); /* <= 16 bits */
|
||||||
|
if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
|
||||||
|
BIT_reloadDStream(&seqState->DStream);
|
||||||
|
if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
|
||||||
|
BIT_reloadDStream(&seqState->DStream);
|
||||||
|
/* Ensure there are enough bits to read the rest of data in 64-bit mode. */
|
||||||
|
ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
|
||||||
|
|
||||||
|
seq.litLength = llBase
|
||||||
|
+ ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits/*>0*/) : 0); /* <= 16 bits */
|
||||||
|
if (MEM_32bits())
|
||||||
|
BIT_reloadDStream(&seqState->DStream);
|
||||||
|
|
||||||
|
DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
|
||||||
|
(U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
|
||||||
|
|
||||||
|
/* ANS state update */
|
||||||
|
ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
|
||||||
|
ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
|
||||||
|
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
|
||||||
|
ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
|
||||||
|
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*)seqStart;
|
||||||
|
const BYTE* const iend = ip + seqSize;
|
||||||
|
BYTE* const ostart = (BYTE* const)dst;
|
||||||
|
BYTE* const oend = ostart + maxDstSize;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
const BYTE* litPtr = dctx->litPtr;
|
||||||
|
const BYTE* const litEnd = litPtr + dctx->litSize;
|
||||||
|
const BYTE* const base = (const BYTE*) (dctx->base);
|
||||||
|
const BYTE* const vBase = (const BYTE*) (dctx->vBase);
|
||||||
|
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
||||||
|
DEBUGLOG(5, "ZSTD_decompressSequences");
|
||||||
|
|
||||||
|
/* Regen sequences */
|
||||||
|
if (nbSeq) {
|
||||||
|
seqState_t seqState;
|
||||||
|
dctx->fseEntropy = 1;
|
||||||
|
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
|
||||||
|
CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
|
||||||
|
ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
|
||||||
|
ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
|
||||||
|
ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
|
||||||
|
|
||||||
|
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) {
|
||||||
|
nbSeq--;
|
||||||
|
{ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
|
||||||
|
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
|
||||||
|
DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
|
||||||
|
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
||||||
|
op += oneSeqSize;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* check if reached exact end */
|
||||||
|
DEBUGLOG(5, "ZSTD_decompressSequences: after decode loop, remaining nbSeq : %i", nbSeq);
|
||||||
|
if (nbSeq) return ERROR(corruption_detected);
|
||||||
|
/* save reps for next block */
|
||||||
|
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* last literal segment */
|
||||||
|
{ size_t const lastLLSize = litEnd - litPtr;
|
||||||
|
if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
|
||||||
|
memcpy(op, litPtr, lastLLSize);
|
||||||
|
op += lastLLSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return op-ostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
|
{
|
||||||
|
return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE seq_t
|
||||||
|
ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
|
||||||
|
{
|
||||||
|
seq_t seq;
|
||||||
|
U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
|
||||||
|
U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
|
||||||
|
U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
|
||||||
|
U32 const totalBits = llBits+mlBits+ofBits;
|
||||||
|
U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
|
||||||
|
U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
|
||||||
|
U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
|
||||||
|
|
||||||
|
/* sequence */
|
||||||
|
{ size_t offset;
|
||||||
|
if (!ofBits)
|
||||||
|
offset = 0;
|
||||||
|
else {
|
||||||
|
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
||||||
|
ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
|
||||||
|
assert(ofBits <= MaxOff);
|
||||||
|
if (MEM_32bits() && longOffsets) {
|
||||||
|
U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
|
||||||
|
offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
|
||||||
|
if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
|
||||||
|
if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
|
||||||
|
} else {
|
||||||
|
offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
|
||||||
|
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ofBits <= 1) {
|
||||||
|
offset += (llBase==0);
|
||||||
|
if (offset) {
|
||||||
|
size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
|
||||||
|
temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
|
||||||
|
if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
|
||||||
|
seqState->prevOffset[1] = seqState->prevOffset[0];
|
||||||
|
seqState->prevOffset[0] = offset = temp;
|
||||||
|
} else {
|
||||||
|
offset = seqState->prevOffset[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
seqState->prevOffset[2] = seqState->prevOffset[1];
|
||||||
|
seqState->prevOffset[1] = seqState->prevOffset[0];
|
||||||
|
seqState->prevOffset[0] = offset;
|
||||||
|
}
|
||||||
|
seq.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq.matchLength = mlBase + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
|
||||||
|
if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
|
||||||
|
BIT_reloadDStream(&seqState->DStream);
|
||||||
|
if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
|
||||||
|
BIT_reloadDStream(&seqState->DStream);
|
||||||
|
/* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
|
||||||
|
ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
|
||||||
|
|
||||||
|
seq.litLength = llBase + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
|
||||||
|
if (MEM_32bits())
|
||||||
|
BIT_reloadDStream(&seqState->DStream);
|
||||||
|
|
||||||
|
{ size_t const pos = seqState->pos + seq.litLength;
|
||||||
|
const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
|
||||||
|
seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
|
||||||
|
* No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */
|
||||||
|
seqState->pos = pos + seq.matchLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ANS state update */
|
||||||
|
ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
|
||||||
|
ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
|
||||||
|
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
|
||||||
|
ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
|
||||||
|
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
ZSTD_decompressSequencesLong_body(
|
||||||
ZSTD_DCtx* dctx,
|
ZSTD_DCtx* dctx,
|
||||||
void* dst, size_t maxDstSize,
|
void* dst, size_t maxDstSize,
|
||||||
const void* seqStart, size_t seqSize,
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
const ZSTD_longOffset_e isLongOffset)
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
{
|
{
|
||||||
const BYTE* ip = (const BYTE*)seqStart;
|
const BYTE* ip = (const BYTE*)seqStart;
|
||||||
@@ -1335,13 +1501,6 @@ static size_t ZSTD_decompressSequencesLong(
|
|||||||
const BYTE* const prefixStart = (const BYTE*) (dctx->base);
|
const BYTE* const prefixStart = (const BYTE*) (dctx->base);
|
||||||
const BYTE* const dictStart = (const BYTE*) (dctx->vBase);
|
const BYTE* const dictStart = (const BYTE*) (dctx->vBase);
|
||||||
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
||||||
int nbSeq;
|
|
||||||
|
|
||||||
/* Build Decoding Tables */
|
|
||||||
{ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
|
|
||||||
if (ZSTD_isError(seqHSize)) return seqHSize;
|
|
||||||
ip += seqHSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Regen sequences */
|
/* Regen sequences */
|
||||||
if (nbSeq) {
|
if (nbSeq) {
|
||||||
@@ -1358,18 +1517,18 @@ static size_t ZSTD_decompressSequencesLong(
|
|||||||
seqState.pos = (size_t)(op-prefixStart);
|
seqState.pos = (size_t)(op-prefixStart);
|
||||||
seqState.dictEnd = dictEnd;
|
seqState.dictEnd = dictEnd;
|
||||||
CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
|
CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
|
||||||
FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
|
ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
|
||||||
FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
|
ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
|
||||||
FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
|
ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
|
||||||
|
|
||||||
/* prepare in advance */
|
/* prepare in advance */
|
||||||
for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && seqNb<seqAdvance; seqNb++) {
|
for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
|
||||||
sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
|
sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
|
||||||
}
|
}
|
||||||
if (seqNb<seqAdvance) return ERROR(corruption_detected);
|
if (seqNb<seqAdvance) return ERROR(corruption_detected);
|
||||||
|
|
||||||
/* decode and decompress */
|
/* decode and decompress */
|
||||||
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && seqNb<nbSeq ; seqNb++) {
|
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
|
||||||
seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
|
seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
|
||||||
size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
|
size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
|
||||||
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
||||||
@@ -1389,6 +1548,9 @@ static size_t ZSTD_decompressSequencesLong(
|
|||||||
|
|
||||||
/* save reps for next block */
|
/* save reps for next block */
|
||||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
|
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
|
||||||
|
#undef STORED_SEQS
|
||||||
|
#undef STOSEQ_MASK
|
||||||
|
#undef ADVANCED_SEQS
|
||||||
}
|
}
|
||||||
|
|
||||||
/* last literal segment */
|
/* last literal segment */
|
||||||
@@ -1401,6 +1563,96 @@ static size_t ZSTD_decompressSequencesLong(
|
|||||||
return op-ostart;
|
return op-ostart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
|
{
|
||||||
|
return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
|
||||||
|
static TARGET_ATTRIBUTE("bmi2") size_t
|
||||||
|
ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
|
{
|
||||||
|
return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TARGET_ATTRIBUTE("bmi2") size_t
|
||||||
|
ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
|
{
|
||||||
|
return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef size_t (*ZSTD_decompressSequences_t)(
|
||||||
|
ZSTD_DCtx *dctx, void *dst, size_t maxDstSize,
|
||||||
|
const void *seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset);
|
||||||
|
|
||||||
|
static size_t ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize,
|
||||||
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
|
{
|
||||||
|
DEBUGLOG(5, "ZSTD_decompressSequences");
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
if (dctx->bmi2) {
|
||||||
|
return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* seqStart, size_t seqSize, int nbSeq,
|
||||||
|
const ZSTD_longOffset_e isLongOffset)
|
||||||
|
{
|
||||||
|
DEBUGLOG(5, "ZSTD_decompressSequencesLong");
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
if (dctx->bmi2) {
|
||||||
|
return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTD_getLongOffsetsShare() :
|
||||||
|
* condition : offTable must be valid
|
||||||
|
* @return : "share" of long offsets (arbitrarily defined as > (1<<23))
|
||||||
|
* compared to maximum possible of (1<<OffFSELog) */
|
||||||
|
static unsigned
|
||||||
|
ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable)
|
||||||
|
{
|
||||||
|
const void* ptr = offTable;
|
||||||
|
U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog;
|
||||||
|
const ZSTD_seqSymbol* table = offTable + 1;
|
||||||
|
U32 const max = 1 << tableLog;
|
||||||
|
U32 u, total = 0;
|
||||||
|
DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog);
|
||||||
|
|
||||||
|
assert(max <= (1 << OffFSELog)); /* max not too large */
|
||||||
|
for (u=0; u<max; u++) {
|
||||||
|
if (table[u].nbAdditionalBits > 22) total += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(tableLog <= OffFSELog);
|
||||||
|
total <<= (OffFSELog - tableLog); /* scale to OffFSELog */
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
@@ -1410,13 +1662,9 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
|||||||
/* isLongOffset must be true if there are long offsets.
|
/* isLongOffset must be true if there are long offsets.
|
||||||
* Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN.
|
* Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN.
|
||||||
* We don't expect that to be the case in 64-bit mode.
|
* We don't expect that to be the case in 64-bit mode.
|
||||||
* If we are in block mode we don't know the window size, so we have to be
|
* In block mode, window size is not known, so we have to be conservative. (note: but it could be evaluated from current-lowLimit)
|
||||||
* conservative.
|
|
||||||
*/
|
*/
|
||||||
ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)));
|
ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)));
|
||||||
/* windowSize could be any value at this point, since it is only validated
|
|
||||||
* in the streaming API.
|
|
||||||
*/
|
|
||||||
DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
|
DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
|
||||||
|
|
||||||
if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
|
if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
|
||||||
@@ -1428,9 +1676,24 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
|||||||
ip += litCSize;
|
ip += litCSize;
|
||||||
srcSize -= litCSize;
|
srcSize -= litCSize;
|
||||||
}
|
}
|
||||||
if (frame && dctx->fParams.windowSize > (1<<23))
|
|
||||||
return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, isLongOffset);
|
/* Build Decoding Tables */
|
||||||
return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, isLongOffset);
|
{ int nbSeq;
|
||||||
|
size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize);
|
||||||
|
if (ZSTD_isError(seqHSize)) return seqHSize;
|
||||||
|
ip += seqHSize;
|
||||||
|
srcSize -= seqHSize;
|
||||||
|
|
||||||
|
if ( (!frame || dctx->fParams.windowSize > (1<<24))
|
||||||
|
&& (nbSeq>0) ) { /* could probably use a larger nbSeq limit */
|
||||||
|
U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr);
|
||||||
|
U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */
|
||||||
|
if (shareLongOffsets >= minShare)
|
||||||
|
return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1758,7 +2021,7 @@ static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skip
|
|||||||
* or an error code, which can be tested using ZSTD_isError() */
|
* or an error code, which can be tested using ZSTD_isError() */
|
||||||
size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
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 */
|
/* Sanity check */
|
||||||
if (srcSize != dctx->expected) return ERROR(srcSize_wrong); /* not allowed */
|
if (srcSize != dctx->expected) return ERROR(srcSize_wrong); /* not allowed */
|
||||||
if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
|
if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
|
||||||
@@ -1819,12 +2082,12 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
|||||||
|
|
||||||
case ZSTDds_decompressLastBlock:
|
case ZSTDds_decompressLastBlock:
|
||||||
case ZSTDds_decompressBlock:
|
case ZSTDds_decompressBlock:
|
||||||
DEBUGLOG(5, "case ZSTDds_decompressBlock");
|
DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
|
||||||
{ size_t rSize;
|
{ size_t rSize;
|
||||||
switch(dctx->bType)
|
switch(dctx->bType)
|
||||||
{
|
{
|
||||||
case bt_compressed:
|
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);
|
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
|
||||||
break;
|
break;
|
||||||
case bt_raw :
|
case bt_raw :
|
||||||
@@ -1838,12 +2101,12 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
|||||||
return ERROR(corruption_detected);
|
return ERROR(corruption_detected);
|
||||||
}
|
}
|
||||||
if (ZSTD_isError(rSize)) return rSize;
|
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;
|
dctx->decodedSize += rSize;
|
||||||
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
|
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
|
||||||
|
|
||||||
if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
|
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->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
|
||||||
if (dctx->decodedSize != dctx->fParams.frameContentSize) {
|
if (dctx->decodedSize != dctx->fParams.frameContentSize) {
|
||||||
return ERROR(corruption_detected);
|
return ERROR(corruption_detected);
|
||||||
@@ -1867,7 +2130,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
|||||||
assert(srcSize == 4); /* guaranteed by dctx->expected */
|
assert(srcSize == 4); /* guaranteed by dctx->expected */
|
||||||
{ U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
|
{ U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
|
||||||
U32 const check32 = MEM_readLE32(src);
|
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);
|
if (check32 != h32) return ERROR(checksum_wrong);
|
||||||
dctx->expected = 0;
|
dctx->expected = 0;
|
||||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||||
@@ -1925,8 +2188,12 @@ static size_t ZSTD_loadEntropy(ZSTD_entropyDTables_t* entropy, const void* const
|
|||||||
U32 offcodeMaxValue = MaxOff, offcodeLog;
|
U32 offcodeMaxValue = MaxOff, offcodeLog;
|
||||||
size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
|
size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
|
||||||
if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
|
if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
|
||||||
|
if (offcodeMaxValue > MaxOff) return ERROR(dictionary_corrupted);
|
||||||
if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
|
if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
|
||||||
CHECK_E(FSE_buildDTable(entropy->OFTable, offcodeNCount, offcodeMaxValue, offcodeLog), dictionary_corrupted);
|
ZSTD_buildFSETable(entropy->OFTable,
|
||||||
|
offcodeNCount, offcodeMaxValue,
|
||||||
|
OF_base, OF_bits,
|
||||||
|
offcodeLog);
|
||||||
dictPtr += offcodeHeaderSize;
|
dictPtr += offcodeHeaderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1934,8 +2201,12 @@ static size_t ZSTD_loadEntropy(ZSTD_entropyDTables_t* entropy, const void* const
|
|||||||
unsigned matchlengthMaxValue = MaxML, matchlengthLog;
|
unsigned matchlengthMaxValue = MaxML, matchlengthLog;
|
||||||
size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
|
size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
|
||||||
if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
|
if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
|
||||||
|
if (matchlengthMaxValue > MaxML) return ERROR(dictionary_corrupted);
|
||||||
if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
|
if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
|
||||||
CHECK_E(FSE_buildDTable(entropy->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog), dictionary_corrupted);
|
ZSTD_buildFSETable(entropy->MLTable,
|
||||||
|
matchlengthNCount, matchlengthMaxValue,
|
||||||
|
ML_base, ML_bits,
|
||||||
|
matchlengthLog);
|
||||||
dictPtr += matchlengthHeaderSize;
|
dictPtr += matchlengthHeaderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1943,8 +2214,12 @@ static size_t ZSTD_loadEntropy(ZSTD_entropyDTables_t* entropy, const void* const
|
|||||||
unsigned litlengthMaxValue = MaxLL, litlengthLog;
|
unsigned litlengthMaxValue = MaxLL, litlengthLog;
|
||||||
size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
|
size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
|
||||||
if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
|
if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
|
||||||
|
if (litlengthMaxValue > MaxLL) return ERROR(dictionary_corrupted);
|
||||||
if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
|
if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
|
||||||
CHECK_E(FSE_buildDTable(entropy->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog), dictionary_corrupted);
|
ZSTD_buildFSETable(entropy->LLTable,
|
||||||
|
litlengthNCount, litlengthMaxValue,
|
||||||
|
LL_base, LL_bits,
|
||||||
|
litlengthLog);
|
||||||
dictPtr += litlengthHeaderSize;
|
dictPtr += litlengthHeaderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2062,13 +2337,23 @@ size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict)
|
static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict, ZSTD_dictContentType_e dictContentType)
|
||||||
{
|
{
|
||||||
ddict->dictID = 0;
|
ddict->dictID = 0;
|
||||||
ddict->entropyPresent = 0;
|
ddict->entropyPresent = 0;
|
||||||
if (ddict->dictSize < 8) return 0;
|
if (dictContentType == ZSTD_dct_rawContent) return 0;
|
||||||
|
|
||||||
|
if (ddict->dictSize < 8) {
|
||||||
|
if (dictContentType == ZSTD_dct_fullDict)
|
||||||
|
return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
|
||||||
|
return 0; /* pure content mode */
|
||||||
|
}
|
||||||
{ U32 const magic = MEM_readLE32(ddict->dictContent);
|
{ U32 const magic = MEM_readLE32(ddict->dictContent);
|
||||||
if (magic != ZSTD_MAGIC_DICTIONARY) return 0; /* pure content mode */
|
if (magic != ZSTD_MAGIC_DICTIONARY) {
|
||||||
|
if (dictContentType == ZSTD_dct_fullDict)
|
||||||
|
return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
|
||||||
|
return 0; /* pure content mode */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_frameIdSize);
|
ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_frameIdSize);
|
||||||
|
|
||||||
@@ -2079,7 +2364,10 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
|
static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
|
||||||
|
const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType)
|
||||||
{
|
{
|
||||||
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
|
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
|
||||||
ddict->dictBuffer = NULL;
|
ddict->dictBuffer = NULL;
|
||||||
@@ -2095,12 +2383,15 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_
|
|||||||
ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
||||||
|
|
||||||
/* parse dictionary content */
|
/* parse dictionary content */
|
||||||
CHECK_F( ZSTD_loadEntropy_inDDict(ddict) );
|
CHECK_F( ZSTD_loadEntropy_inDDict(ddict, dictContentType) );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_customMem customMem)
|
ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType,
|
||||||
|
ZSTD_customMem customMem)
|
||||||
{
|
{
|
||||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||||
|
|
||||||
@@ -2108,7 +2399,7 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_di
|
|||||||
if (!ddict) return NULL;
|
if (!ddict) return NULL;
|
||||||
ddict->cMem = customMem;
|
ddict->cMem = customMem;
|
||||||
|
|
||||||
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, dictLoadMethod) )) {
|
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, dictLoadMethod, dictContentType) )) {
|
||||||
ZSTD_freeDDict(ddict);
|
ZSTD_freeDDict(ddict);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2124,7 +2415,7 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_di
|
|||||||
ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
|
ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
|
||||||
{
|
{
|
||||||
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
||||||
return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, allocator);
|
return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ZSTD_createDDict_byReference() :
|
/*! ZSTD_createDDict_byReference() :
|
||||||
@@ -2134,13 +2425,15 @@ ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
|
|||||||
ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
|
ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
|
||||||
{
|
{
|
||||||
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
||||||
return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, allocator);
|
return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
|
const ZSTD_DDict* ZSTD_initStaticDDict(
|
||||||
|
void* workspace, size_t workspaceSize,
|
||||||
const void* dict, size_t dictSize,
|
const void* dict, size_t dictSize,
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod)
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType)
|
||||||
{
|
{
|
||||||
size_t const neededSpace =
|
size_t const neededSpace =
|
||||||
sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||||
@@ -2153,7 +2446,7 @@ ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
|
|||||||
memcpy(ddict+1, dict, dictSize); /* local copy */
|
memcpy(ddict+1, dict, dictSize); /* local copy */
|
||||||
dict = ddict+1;
|
dict = ddict+1;
|
||||||
}
|
}
|
||||||
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, ZSTD_dlm_byRef) ))
|
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, ZSTD_dlm_byRef, dictContentType) ))
|
||||||
return NULL;
|
return NULL;
|
||||||
return ddict;
|
return ddict;
|
||||||
}
|
}
|
||||||
@@ -2247,6 +2540,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
|
|||||||
|
|
||||||
ZSTD_DStream* ZSTD_createDStream(void)
|
ZSTD_DStream* ZSTD_createDStream(void)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(3, "ZSTD_createDStream");
|
||||||
return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
|
return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2271,58 +2565,99 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds)
|
|||||||
size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
|
size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
|
||||||
size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
|
size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
|
||||||
|
|
||||||
|
size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
|
||||||
|
{
|
||||||
|
if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
|
||||||
|
ZSTD_freeDDict(dctx->ddictLocal);
|
||||||
|
if (dict && dictSize >= 8) {
|
||||||
|
dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
|
||||||
|
if (dctx->ddictLocal == NULL) return ERROR(memory_allocation);
|
||||||
|
} else {
|
||||||
|
dctx->ddictLocal = NULL;
|
||||||
|
}
|
||||||
|
dctx->ddict = dctx->ddictLocal;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
|
||||||
|
{
|
||||||
|
return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
|
||||||
|
{
|
||||||
|
return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
|
||||||
|
{
|
||||||
|
return ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)
|
||||||
|
{
|
||||||
|
return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ZSTD_initDStream_usingDict() :
|
||||||
|
* return : expected size, aka ZSTD_frameHeaderSize_prefix.
|
||||||
|
* this function cannot fail */
|
||||||
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
|
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
|
||||||
{
|
{
|
||||||
zds->streamStage = zdss_loadHeader;
|
DEBUGLOG(4, "ZSTD_initDStream_usingDict");
|
||||||
zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
|
zds->streamStage = zdss_init;
|
||||||
ZSTD_freeDDict(zds->ddictLocal);
|
CHECK_F( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) );
|
||||||
if (dict && dictSize >= 8) {
|
|
||||||
zds->ddictLocal = ZSTD_createDDict(dict, dictSize);
|
|
||||||
if (zds->ddictLocal == NULL) return ERROR(memory_allocation);
|
|
||||||
} else zds->ddictLocal = NULL;
|
|
||||||
zds->ddict = zds->ddictLocal;
|
|
||||||
zds->legacyVersion = 0;
|
|
||||||
zds->hostageByte = 0;
|
|
||||||
return ZSTD_frameHeaderSize_prefix;
|
return ZSTD_frameHeaderSize_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* note : this variant can't fail */
|
/* note : this variant can't fail */
|
||||||
size_t ZSTD_initDStream(ZSTD_DStream* zds)
|
size_t ZSTD_initDStream(ZSTD_DStream* zds)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(4, "ZSTD_initDStream");
|
||||||
return ZSTD_initDStream_usingDict(zds, NULL, 0);
|
return ZSTD_initDStream_usingDict(zds, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
|
||||||
|
{
|
||||||
|
if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
|
||||||
|
dctx->ddict = ddict;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ZSTD_initDStream_usingDDict() :
|
/* ZSTD_initDStream_usingDDict() :
|
||||||
* ddict will just be referenced, and must outlive decompression session
|
* ddict will just be referenced, and must outlive decompression session
|
||||||
* this function cannot fail */
|
* this function cannot fail */
|
||||||
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict)
|
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
|
||||||
{
|
{
|
||||||
size_t const initResult = ZSTD_initDStream(zds);
|
size_t const initResult = ZSTD_initDStream(dctx);
|
||||||
zds->ddict = ddict;
|
dctx->ddict = ddict;
|
||||||
return initResult;
|
return initResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_resetDStream(ZSTD_DStream* zds)
|
/* ZSTD_resetDStream() :
|
||||||
|
* return : expected size, aka ZSTD_frameHeaderSize_prefix.
|
||||||
|
* this function cannot fail */
|
||||||
|
size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
|
||||||
{
|
{
|
||||||
zds->streamStage = zdss_loadHeader;
|
DEBUGLOG(4, "ZSTD_resetDStream");
|
||||||
zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
|
dctx->streamStage = zdss_loadHeader;
|
||||||
zds->legacyVersion = 0;
|
dctx->lhSize = dctx->inPos = dctx->outStart = dctx->outEnd = 0;
|
||||||
zds->hostageByte = 0;
|
dctx->legacyVersion = 0;
|
||||||
|
dctx->hostageByte = 0;
|
||||||
return ZSTD_frameHeaderSize_prefix;
|
return ZSTD_frameHeaderSize_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds,
|
size_t ZSTD_setDStreamParameter(ZSTD_DStream* dctx,
|
||||||
ZSTD_DStreamParameter_e paramType, unsigned paramValue)
|
ZSTD_DStreamParameter_e paramType, unsigned paramValue)
|
||||||
{
|
{
|
||||||
ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
|
if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
|
||||||
if ((unsigned)zds->streamStage > (unsigned)zdss_loadHeader)
|
|
||||||
return ERROR(stage_wrong);
|
|
||||||
switch(paramType)
|
switch(paramType)
|
||||||
{
|
{
|
||||||
default : return ERROR(parameter_unsupported);
|
default : return ERROR(parameter_unsupported);
|
||||||
case DStream_p_maxWindowSize :
|
case DStream_p_maxWindowSize :
|
||||||
DEBUGLOG(4, "setting maxWindowSize = %u KB", paramValue >> 10);
|
DEBUGLOG(4, "setting maxWindowSize = %u KB", paramValue >> 10);
|
||||||
zds->maxWindowSize = paramValue ? paramValue : (U32)(-1);
|
dctx->maxWindowSize = paramValue ? paramValue : (U32)(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2330,9 +2665,7 @@ size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds,
|
|||||||
|
|
||||||
size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
|
size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
|
||||||
{
|
{
|
||||||
ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
|
if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
|
||||||
if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
|
|
||||||
return ERROR(stage_wrong);
|
|
||||||
dctx->maxWindowSize = maxWindowSize;
|
dctx->maxWindowSize = maxWindowSize;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2340,17 +2673,15 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
|
|||||||
size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
|
size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_DCtx_setFormat : %u", (unsigned)format);
|
DEBUGLOG(4, "ZSTD_DCtx_setFormat : %u", (unsigned)format);
|
||||||
ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
|
if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
|
||||||
if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
|
|
||||||
return ERROR(stage_wrong);
|
|
||||||
dctx->format = format;
|
dctx->format = format;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds)
|
size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
|
||||||
{
|
{
|
||||||
return ZSTD_sizeof_DCtx(zds);
|
return ZSTD_sizeof_DCtx(dctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
|
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
|
||||||
@@ -2417,23 +2748,25 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
|||||||
}
|
}
|
||||||
DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
|
DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
|
||||||
|
|
||||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
|
|
||||||
if (zds->legacyVersion) {
|
|
||||||
/* legacy support is incompatible with static dctx */
|
|
||||||
if (zds->staticSize) return ERROR(memory_allocation);
|
|
||||||
return ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (someMoreWork) {
|
while (someMoreWork) {
|
||||||
switch(zds->streamStage)
|
switch(zds->streamStage)
|
||||||
{
|
{
|
||||||
case zdss_init :
|
case zdss_init :
|
||||||
|
DEBUGLOG(5, "stage zdss_init => transparent reset ");
|
||||||
ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
|
ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
||||||
case zdss_loadHeader :
|
case zdss_loadHeader :
|
||||||
DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
|
DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
|
||||||
|
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
|
||||||
|
if (zds->legacyVersion) {
|
||||||
|
/* legacy support is incompatible with static dctx */
|
||||||
|
if (zds->staticSize) return ERROR(memory_allocation);
|
||||||
|
{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
|
||||||
|
if (hint==0) zds->streamStage = zdss_init;
|
||||||
|
return hint;
|
||||||
|
} }
|
||||||
|
#endif
|
||||||
{ size_t const hSize = ZSTD_getFrameHeader_internal(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
|
{ size_t const hSize = ZSTD_getFrameHeader_internal(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
|
||||||
DEBUGLOG(5, "header size : %u", (U32)hSize);
|
DEBUGLOG(5, "header size : %u", (U32)hSize);
|
||||||
if (ZSTD_isError(hSize)) {
|
if (ZSTD_isError(hSize)) {
|
||||||
@@ -2442,14 +2775,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
|||||||
if (legacyVersion) {
|
if (legacyVersion) {
|
||||||
const void* const dict = zds->ddict ? zds->ddict->dictContent : NULL;
|
const void* const dict = zds->ddict ? zds->ddict->dictContent : NULL;
|
||||||
size_t const dictSize = zds->ddict ? zds->ddict->dictSize : 0;
|
size_t const dictSize = zds->ddict ? zds->ddict->dictSize : 0;
|
||||||
|
DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);
|
||||||
/* legacy support is incompatible with static dctx */
|
/* legacy support is incompatible with static dctx */
|
||||||
if (zds->staticSize) return ERROR(memory_allocation);
|
if (zds->staticSize) return ERROR(memory_allocation);
|
||||||
CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext,
|
CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext,
|
||||||
zds->previousLegacyVersion, legacyVersion,
|
zds->previousLegacyVersion, legacyVersion,
|
||||||
dict, dictSize));
|
dict, dictSize));
|
||||||
zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
|
zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
|
||||||
return ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
|
{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
|
||||||
}
|
if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */
|
||||||
|
return hint;
|
||||||
|
} }
|
||||||
#endif
|
#endif
|
||||||
return hSize; /* error */
|
return hSize; /* error */
|
||||||
}
|
}
|
||||||
@@ -2559,6 +2895,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
|||||||
if (ip==iend) { someMoreWork = 0; break; } /* no more input */
|
if (ip==iend) { someMoreWork = 0; break; } /* no more input */
|
||||||
zds->streamStage = zdss_load;
|
zds->streamStage = zdss_load;
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
||||||
case zdss_load:
|
case zdss_load:
|
||||||
{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
|
{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
|
||||||
size_t const toLoad = neededInSize - zds->inPos;
|
size_t const toLoad = neededInSize - zds->inPos;
|
||||||
@@ -2585,6 +2922,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
|||||||
} }
|
} }
|
||||||
zds->streamStage = zdss_flush;
|
zds->streamStage = zdss_flush;
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
||||||
case zdss_flush:
|
case zdss_flush:
|
||||||
{ size_t const toFlushSize = zds->outEnd - zds->outStart;
|
{ size_t const toFlushSize = zds->outEnd - zds->outStart;
|
||||||
size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
|
size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
|
||||||
@@ -2631,8 +2969,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
|||||||
return 1;
|
return 1;
|
||||||
} /* nextSrcSizeHint==0 */
|
} /* nextSrcSizeHint==0 */
|
||||||
nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */
|
nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */
|
||||||
if (zds->inPos > nextSrcSizeHint) return ERROR(GENERIC); /* should never happen */
|
assert(zds->inPos <= nextSrcSizeHint);
|
||||||
nextSrcSizeHint -= zds->inPos; /* already loaded*/
|
nextSrcSizeHint -= zds->inPos; /* part already loaded*/
|
||||||
return nextSrcSizeHint;
|
return nextSrcSizeHint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -537,8 +537,8 @@ static int COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
|
|||||||
/* Checks */
|
/* Checks */
|
||||||
if (totalSamplesSize < MAX(d, sizeof(U64)) ||
|
if (totalSamplesSize < MAX(d, sizeof(U64)) ||
|
||||||
totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) {
|
totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) {
|
||||||
DISPLAYLEVEL(1, "Total samples size is too large, maximum size is %u MB\n",
|
DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n",
|
||||||
(COVER_MAX_SAMPLES_SIZE >> 20));
|
(U32)(totalSamplesSize>>20), (COVER_MAX_SAMPLES_SIZE >> 20));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Zero the context */
|
/* 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(
|
ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
|
||||||
void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
|
void *dictBuffer, size_t dictBufferCapacity,
|
||||||
const size_t *samplesSizes, unsigned nbSamples,
|
const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
|
||||||
ZDICT_cover_params_t parameters) {
|
ZDICT_cover_params_t parameters)
|
||||||
|
{
|
||||||
BYTE* const dict = (BYTE*)dictBuffer;
|
BYTE* const dict = (BYTE*)dictBuffer;
|
||||||
COVER_ctx_t ctx;
|
COVER_ctx_t ctx;
|
||||||
COVER_map_t activeDmers;
|
COVER_map_t activeDmers;
|
||||||
|
|
||||||
|
/* Initialize global data */
|
||||||
|
g_displayLevel = parameters.zParams.notificationLevel;
|
||||||
/* Checks */
|
/* Checks */
|
||||||
if (!COVER_checkParameters(parameters, dictBufferCapacity)) {
|
if (!COVER_checkParameters(parameters, dictBufferCapacity)) {
|
||||||
DISPLAYLEVEL(1, "Cover parameters incorrect\n");
|
DISPLAYLEVEL(1, "Cover parameters incorrect\n");
|
||||||
@@ -671,8 +675,6 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
|
|||||||
ZDICT_DICTSIZE_MIN);
|
ZDICT_DICTSIZE_MIN);
|
||||||
return ERROR(dstSize_tooSmall);
|
return ERROR(dstSize_tooSmall);
|
||||||
}
|
}
|
||||||
/* Initialize global data */
|
|
||||||
g_displayLevel = parameters.zParams.notificationLevel;
|
|
||||||
/* Initialize context and activeDmers */
|
/* Initialize context and activeDmers */
|
||||||
if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
|
if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
|
||||||
parameters.d)) {
|
parameters.d)) {
|
||||||
@@ -947,6 +949,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
|
|||||||
unsigned k;
|
unsigned k;
|
||||||
COVER_best_t best;
|
COVER_best_t best;
|
||||||
POOL_ctx *pool = NULL;
|
POOL_ctx *pool = NULL;
|
||||||
|
|
||||||
/* Checks */
|
/* Checks */
|
||||||
if (kMinK < kMaxD || kMaxK < kMinK) {
|
if (kMinK < kMaxD || kMaxK < kMinK) {
|
||||||
LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
|
LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
|
||||||
|
|||||||
@@ -207,7 +207,6 @@ static dictItem ZDICT_analyzePos(
|
|||||||
U32 cumulLength[LLIMIT] = {0};
|
U32 cumulLength[LLIMIT] = {0};
|
||||||
U32 savings[LLIMIT] = {0};
|
U32 savings[LLIMIT] = {0};
|
||||||
const BYTE* b = (const BYTE*)buffer;
|
const BYTE* b = (const BYTE*)buffer;
|
||||||
size_t length;
|
|
||||||
size_t maxLength = LLIMIT;
|
size_t maxLength = LLIMIT;
|
||||||
size_t pos = suffix[start];
|
size_t pos = suffix[start];
|
||||||
U32 end = 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+1) == MEM_read16(b+pos+3))
|
||||||
||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) {
|
||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) {
|
||||||
/* skip and mark segment */
|
/* skip and mark segment */
|
||||||
U16 u16 = MEM_read16(b+pos+4);
|
U16 const pattern16 = MEM_read16(b+pos+4);
|
||||||
U32 u, e = 6;
|
U32 u, patternEnd = 6;
|
||||||
while (MEM_read16(b+pos+e) == u16) e+=2 ;
|
while (MEM_read16(b+pos+patternEnd) == pattern16) patternEnd+=2 ;
|
||||||
if (b[pos+e] == b[pos+e-1]) e++;
|
if (b[pos+patternEnd] == b[pos+patternEnd-1]) patternEnd++;
|
||||||
for (u=1; u<e; u++)
|
for (u=1; u<patternEnd; u++)
|
||||||
doneMarks[pos+u] = 1;
|
doneMarks[pos+u] = 1;
|
||||||
return solution;
|
return solution;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* look forward */
|
/* look forward */
|
||||||
|
{ size_t length;
|
||||||
do {
|
do {
|
||||||
end++;
|
end++;
|
||||||
length = ZDICT_count(b + pos, b + suffix[end]);
|
length = ZDICT_count(b + pos, b + suffix[end]);
|
||||||
} while (length >= MINMATCHLENGTH);
|
} while (length >= MINMATCHLENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
/* look backward */
|
/* look backward */
|
||||||
|
{ size_t length;
|
||||||
do {
|
do {
|
||||||
length = ZDICT_count(b + pos, b + *(suffix+start-1));
|
length = ZDICT_count(b + pos, b + *(suffix+start-1));
|
||||||
if (length >=MINMATCHLENGTH) start--;
|
if (length >=MINMATCHLENGTH) start--;
|
||||||
} while(length >= MINMATCHLENGTH);
|
} while(length >= MINMATCHLENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
/* exit if not found a minimum nb of repetitions */
|
/* exit if not found a minimum nb of repetitions */
|
||||||
if (end-start < minRatio) {
|
if (end-start < minRatio) {
|
||||||
@@ -297,21 +300,24 @@ static dictItem ZDICT_analyzePos(
|
|||||||
memset(lengthList, 0, sizeof(lengthList));
|
memset(lengthList, 0, sizeof(lengthList));
|
||||||
|
|
||||||
/* look forward */
|
/* look forward */
|
||||||
|
{ size_t length;
|
||||||
do {
|
do {
|
||||||
end++;
|
end++;
|
||||||
length = ZDICT_count(b + pos, b + suffix[end]);
|
length = ZDICT_count(b + pos, b + suffix[end]);
|
||||||
if (length >= LLIMIT) length = LLIMIT-1;
|
if (length >= LLIMIT) length = LLIMIT-1;
|
||||||
lengthList[length]++;
|
lengthList[length]++;
|
||||||
} while (length >=MINMATCHLENGTH);
|
} while (length >=MINMATCHLENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
/* look backward */
|
/* look backward */
|
||||||
length = MINMATCHLENGTH;
|
{ size_t length = MINMATCHLENGTH;
|
||||||
while ((length >= MINMATCHLENGTH) & (start > 0)) {
|
while ((length >= MINMATCHLENGTH) & (start > 0)) {
|
||||||
length = ZDICT_count(b + pos, b + suffix[start - 1]);
|
length = ZDICT_count(b + pos, b + suffix[start - 1]);
|
||||||
if (length >= LLIMIT) length = LLIMIT - 1;
|
if (length >= LLIMIT) length = LLIMIT - 1;
|
||||||
lengthList[length]++;
|
lengthList[length]++;
|
||||||
if (length >= MINMATCHLENGTH) start--;
|
if (length >= MINMATCHLENGTH) start--;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* largest useful length */
|
/* largest useful length */
|
||||||
memset(cumulLength, 0, sizeof(cumulLength));
|
memset(cumulLength, 0, sizeof(cumulLength));
|
||||||
@@ -345,12 +351,12 @@ static dictItem ZDICT_analyzePos(
|
|||||||
/* mark positions done */
|
/* mark positions done */
|
||||||
{ U32 id;
|
{ U32 id;
|
||||||
for (id=start; id<end; id++) {
|
for (id=start; id<end; id++) {
|
||||||
U32 p, pEnd;
|
U32 p, pEnd, length;
|
||||||
U32 const testedPos = suffix[id];
|
U32 const testedPos = suffix[id];
|
||||||
if (testedPos == pos)
|
if (testedPos == pos)
|
||||||
length = solution.length;
|
length = solution.length;
|
||||||
else {
|
else {
|
||||||
length = ZDICT_count(b+pos, b+testedPos);
|
length = (U32)ZDICT_count(b+pos, b+testedPos);
|
||||||
if (length > solution.length) length = solution.length;
|
if (length > solution.length) length = solution.length;
|
||||||
}
|
}
|
||||||
pEnd = (U32)(testedPos + length);
|
pEnd = (U32)(testedPos + length);
|
||||||
@@ -575,8 +581,8 @@ static void ZDICT_fillNoise(void* buffer, size_t length)
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
ZSTD_CCtx* ref;
|
ZSTD_CCtx* ref; /* contains reference to dictionary */
|
||||||
ZSTD_CCtx* zc;
|
ZSTD_CCtx* zc; /* working context */
|
||||||
void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */
|
void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */
|
||||||
} EStats_ress_t;
|
} EStats_ress_t;
|
||||||
|
|
||||||
@@ -584,7 +590,8 @@ typedef struct
|
|||||||
|
|
||||||
static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params,
|
static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params,
|
||||||
U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* litlengthCount, U32* repOffsets,
|
U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* litlengthCount, U32* repOffsets,
|
||||||
const void* src, size_t srcSize, U32 notificationLevel)
|
const void* src, size_t srcSize,
|
||||||
|
U32 notificationLevel)
|
||||||
{
|
{
|
||||||
size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params.cParams.windowLog);
|
size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params.cParams.windowLog);
|
||||||
size_t cSize;
|
size_t cSize;
|
||||||
@@ -597,7 +604,7 @@ static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params,
|
|||||||
if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (U32)srcSize); return; }
|
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 */
|
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 */
|
/* literals stats */
|
||||||
{ const BYTE* bytePtr;
|
{ const BYTE* bytePtr;
|
||||||
@@ -659,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 */
|
#define OFFCODE_MAX 30 /* only applicable to first block */
|
||||||
static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
|
static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
|
||||||
@@ -688,6 +707,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
|
|||||||
BYTE* dstPtr = (BYTE*)dstBuffer;
|
BYTE* dstPtr = (BYTE*)dstBuffer;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
|
DEBUGLOG(4, "ZDICT_analyzeEntropy");
|
||||||
esr.ref = ZSTD_createCCtx();
|
esr.ref = ZSTD_createCCtx();
|
||||||
esr.zc = ZSTD_createCCtx();
|
esr.zc = ZSTD_createCCtx();
|
||||||
esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX);
|
esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX);
|
||||||
@@ -713,7 +733,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
|
|||||||
goto _cleanup;
|
goto _cleanup;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
/* collect stats on all files */
|
/* collect stats on all samples */
|
||||||
for (u=0; u<nbFiles; u++) {
|
for (u=0; u<nbFiles; u++) {
|
||||||
ZDICT_countEStats(esr, params,
|
ZDICT_countEStats(esr, params,
|
||||||
countLit, offcodeCount, matchLengthCount, litLengthCount, repOffset,
|
countLit, offcodeCount, matchLengthCount, litLengthCount, repOffset,
|
||||||
@@ -722,14 +742,21 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
|
|||||||
pos += fileSizes[u];
|
pos += fileSizes[u];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* analyze */
|
/* analyze, build stats, starting with literals */
|
||||||
errorCode = HUF_buildCTable (hufTable, countLit, 255, huffLog);
|
{ size_t maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
|
||||||
if (HUF_isError(errorCode)) {
|
if (HUF_isError(maxNbBits)) {
|
||||||
eSize = ERROR(GENERIC);
|
eSize = ERROR(GENERIC);
|
||||||
DISPLAYLEVEL(1, " HUF_buildCTable error \n");
|
DISPLAYLEVEL(1, " HUF_buildCTable error \n");
|
||||||
goto _cleanup;
|
goto _cleanup;
|
||||||
}
|
}
|
||||||
huffLog = (U32)errorCode;
|
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);
|
||||||
|
}
|
||||||
|
huffLog = (U32)maxNbBits;
|
||||||
|
}
|
||||||
|
|
||||||
/* looking for most common first offsets */
|
/* looking for most common first offsets */
|
||||||
{ U32 offset;
|
{ U32 offset;
|
||||||
@@ -850,6 +877,7 @@ size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,
|
|||||||
U32 const notificationLevel = params.notificationLevel;
|
U32 const notificationLevel = params.notificationLevel;
|
||||||
|
|
||||||
/* check conditions */
|
/* check conditions */
|
||||||
|
DEBUGLOG(4, "ZDICT_finalizeDictionary");
|
||||||
if (dictBufferCapacity < dictContentSize) return ERROR(dstSize_tooSmall);
|
if (dictBufferCapacity < dictContentSize) return ERROR(dstSize_tooSmall);
|
||||||
if (dictContentSize < ZDICT_CONTENTSIZE_MIN) return ERROR(srcSize_wrong);
|
if (dictContentSize < ZDICT_CONTENTSIZE_MIN) return ERROR(srcSize_wrong);
|
||||||
if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) return ERROR(dstSize_tooSmall);
|
if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) return ERROR(dstSize_tooSmall);
|
||||||
@@ -1025,7 +1053,8 @@ size_t ZDICT_trainFromBuffer_unsafe_legacy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* issue : samplesBuffer need to be followed by a noisy guard band.
|
/* ZDICT_trainFromBuffer_legacy() :
|
||||||
|
* issue : samplesBuffer need to be followed by a noisy guard band.
|
||||||
* work around : duplicate the buffer, and add the noise */
|
* work around : duplicate the buffer, and add the noise */
|
||||||
size_t ZDICT_trainFromBuffer_legacy(void* dictBuffer, size_t dictBufferCapacity,
|
size_t ZDICT_trainFromBuffer_legacy(void* dictBuffer, size_t dictBufferCapacity,
|
||||||
const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
|
const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
|
||||||
@@ -1054,14 +1083,18 @@ 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)
|
||||||
{
|
{
|
||||||
ZDICT_cover_params_t params;
|
ZDICT_cover_params_t params;
|
||||||
|
DEBUGLOG(3, "ZDICT_trainFromBuffer");
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
params.d = 8;
|
params.d = 8;
|
||||||
params.steps = 4;
|
params.steps = 4;
|
||||||
/* Default to level 6 since no compression level information is avaialble */
|
/* Default to level 6 since no compression level information is available */
|
||||||
params.zParams.compressionLevel = 6;
|
params.zParams.compressionLevel = 6;
|
||||||
|
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
|
||||||
|
params.zParams.notificationLevel = ZSTD_DEBUG;
|
||||||
|
#endif
|
||||||
return ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, dictBufferCapacity,
|
return ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, dictBufferCapacity,
|
||||||
samplesBuffer, samplesSizes,
|
samplesBuffer, samplesSizes, nbSamples,
|
||||||
nbSamples, ¶ms);
|
¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
|
size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ extern "C" {
|
|||||||
|
|
||||||
/*! ZDICT_trainFromBuffer():
|
/*! ZDICT_trainFromBuffer():
|
||||||
* Train a dictionary from an array of samples.
|
* Train a dictionary from an array of samples.
|
||||||
* Uses ZDICT_optimizeTrainFromBuffer_cover() single-threaded, with d=8 and steps=4.
|
* Redirect towards ZDICT_optimizeTrainFromBuffer_cover() single-threaded, with d=8 and steps=4.
|
||||||
* Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
|
* 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.
|
* supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
|
||||||
* The resulting dictionary will be saved into `dictBuffer`.
|
* The resulting dictionary will be saved into `dictBuffer`.
|
||||||
@@ -47,8 +47,8 @@ extern "C" {
|
|||||||
* or an error code, which can be tested with ZDICT_isError().
|
* or an error code, which can be tested with ZDICT_isError().
|
||||||
* Note: ZDICT_trainFromBuffer() requires about 9 bytes of memory for each input byte.
|
* 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.
|
* 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`.
|
* It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
|
||||||
* In general, it's recommended to provide a few thousands samples, but this can vary a lot.
|
* 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.
|
* 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,
|
ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
|
||||||
@@ -72,14 +72,14 @@ ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode);
|
|||||||
* ==================================================================================== */
|
* ==================================================================================== */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int compressionLevel; /* 0 means default; target a specific zstd compression level */
|
int compressionLevel; /* optimize for a specific zstd compression level; 0 means default */
|
||||||
unsigned notificationLevel; /* Write to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */
|
unsigned notificationLevel; /* Write log 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 */
|
unsigned dictID; /* force dictID value; 0 means auto mode (32-bits random value) */
|
||||||
} ZDICT_params_t;
|
} ZDICT_params_t;
|
||||||
|
|
||||||
/*! ZDICT_cover_params_t:
|
/*! ZDICT_cover_params_t:
|
||||||
* For all values 0 means default.
|
|
||||||
* k and d are the only required parameters.
|
* k and d are the only required parameters.
|
||||||
|
* For others, value 0 means default.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */
|
unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */
|
||||||
@@ -99,20 +99,20 @@ typedef struct {
|
|||||||
* or an error code, which can be tested with ZDICT_isError().
|
* 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.
|
* 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.
|
* 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`.
|
* It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
|
||||||
* In general, it's recommended to provide a few thousands samples, but this can vary a lot.
|
* 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.
|
* 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(
|
ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
|
||||||
void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
|
void *dictBuffer, size_t dictBufferCapacity,
|
||||||
const size_t *samplesSizes, unsigned nbSamples,
|
const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
|
||||||
ZDICT_cover_params_t parameters);
|
ZDICT_cover_params_t parameters);
|
||||||
|
|
||||||
/*! ZDICT_optimizeTrainFromBuffer_cover():
|
/*! ZDICT_optimizeTrainFromBuffer_cover():
|
||||||
* The same requirements as above hold for all the parameters except `parameters`.
|
* The same requirements as above hold for all the parameters except `parameters`.
|
||||||
* This function tries many parameter combinations and picks the best parameters.
|
* This function tries many parameter combinations and picks the best parameters.
|
||||||
* `*parameters` is filled with the best parameters found, and the dictionary
|
* `*parameters` is filled with the best parameters found,
|
||||||
* constructed with those parameters is stored in `dictBuffer`.
|
* dictionary constructed with those parameters is stored in `dictBuffer`.
|
||||||
*
|
*
|
||||||
* All of the parameters d, k, steps are optional.
|
* 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}.
|
* 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,8 +125,8 @@ 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.
|
* 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(
|
ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
|
||||||
void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
|
void* dictBuffer, size_t dictBufferCapacity,
|
||||||
const size_t *samplesSizes, unsigned nbSamples,
|
const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
|
||||||
ZDICT_cover_params_t* parameters);
|
ZDICT_cover_params_t* parameters);
|
||||||
|
|
||||||
/*! ZDICT_finalizeDictionary():
|
/*! ZDICT_finalizeDictionary():
|
||||||
@@ -165,14 +165,15 @@ typedef struct {
|
|||||||
* @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
|
* @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
|
||||||
* or an error code, which can be tested with ZDICT_isError().
|
* or an error code, which can be tested with ZDICT_isError().
|
||||||
* Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
|
* 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`.
|
* It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
|
||||||
* In general, it's recommended to provide a few thousands samples, but this can vary a lot.
|
* 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.
|
* 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(
|
ZDICTLIB_API size_t ZDICT_trainFromBuffer_legacy(
|
||||||
void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
|
void *dictBuffer, size_t dictBufferCapacity,
|
||||||
const size_t *samplesSizes, unsigned nbSamples, ZDICT_legacy_params_t parameters);
|
const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
|
||||||
|
ZDICT_legacy_params_t parameters);
|
||||||
|
|
||||||
/* Deprecation warnings */
|
/* Deprecation warnings */
|
||||||
/* It is generally possible to disable deprecation warnings from compiler,
|
/* It is generally possible to disable deprecation warnings from compiler,
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ MEM_STATIC size_t ZSTD_freeLegacyStreamContext(void* legacyContext, U32 version)
|
|||||||
MEM_STATIC size_t ZSTD_initLegacyStream(void** legacyContext, U32 prevVersion, U32 newVersion,
|
MEM_STATIC size_t ZSTD_initLegacyStream(void** legacyContext, U32 prevVersion, U32 newVersion,
|
||||||
const void* dict, size_t dictSize)
|
const void* dict, size_t dictSize)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(5, "ZSTD_initLegacyStream for v0.%u", newVersion);
|
||||||
if (prevVersion != newVersion) ZSTD_freeLegacyStreamContext(*legacyContext, prevVersion);
|
if (prevVersion != newVersion) ZSTD_freeLegacyStreamContext(*legacyContext, prevVersion);
|
||||||
switch(newVersion)
|
switch(newVersion)
|
||||||
{
|
{
|
||||||
@@ -304,6 +305,7 @@ MEM_STATIC size_t ZSTD_initLegacyStream(void** legacyContext, U32 prevVersion, U
|
|||||||
MEM_STATIC size_t ZSTD_decompressLegacyStream(void* legacyContext, U32 version,
|
MEM_STATIC size_t ZSTD_decompressLegacyStream(void* legacyContext, U32 version,
|
||||||
ZSTD_outBuffer* output, ZSTD_inBuffer* input)
|
ZSTD_outBuffer* output, ZSTD_inBuffer* input)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(5, "ZSTD_decompressLegacyStream for v0.%u", version);
|
||||||
switch(version)
|
switch(version)
|
||||||
{
|
{
|
||||||
default :
|
default :
|
||||||
|
|||||||
@@ -16,37 +16,6 @@
|
|||||||
|
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
mem.h
|
mem.h
|
||||||
low-level memory access routines
|
|
||||||
Copyright (C) 2013-2015, Yann Collet.
|
|
||||||
|
|
||||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
You can contact the author at :
|
|
||||||
- FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
|
||||||
****************************************************************** */
|
****************************************************************** */
|
||||||
#ifndef MEM_H_MODULE
|
#ifndef MEM_H_MODULE
|
||||||
#define MEM_H_MODULE
|
#define MEM_H_MODULE
|
||||||
@@ -103,6 +72,44 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Debug
|
||||||
|
***************************************/
|
||||||
|
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
|
||||||
|
# include <assert.h>
|
||||||
|
#else
|
||||||
|
# ifndef assert
|
||||||
|
# define assert(condition) ((void)0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
|
||||||
|
|
||||||
|
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
|
||||||
|
# include <stdio.h>
|
||||||
|
extern int g_debuglog_enable;
|
||||||
|
/* recommended values for ZSTD_DEBUG display levels :
|
||||||
|
* 1 : no display, enables assert() only
|
||||||
|
* 2 : reserved for currently active debug path
|
||||||
|
* 3 : events once per object lifetime (CCtx, CDict, etc.)
|
||||||
|
* 4 : events once per frame
|
||||||
|
* 5 : events once per block
|
||||||
|
* 6 : events once per sequence (*very* verbose) */
|
||||||
|
# define RAWLOG(l, ...) { \
|
||||||
|
if ((g_debuglog_enable) & (l<=ZSTD_DEBUG)) { \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
} }
|
||||||
|
# define DEBUGLOG(l, ...) { \
|
||||||
|
if ((g_debuglog_enable) & (l<=ZSTD_DEBUG)) { \
|
||||||
|
fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
|
||||||
|
fprintf(stderr, " \n"); \
|
||||||
|
} }
|
||||||
|
#else
|
||||||
|
# define RAWLOG(l, ...) {} /* disabled */
|
||||||
|
# define DEBUGLOG(l, ...) {} /* disabled */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Memory I/O
|
* Memory I/O
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
@@ -255,34 +262,6 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr)
|
|||||||
/*
|
/*
|
||||||
zstd - standard compression library
|
zstd - standard compression library
|
||||||
Header File for static linking only
|
Header File for static linking only
|
||||||
Copyright (C) 2014-2015, Yann Collet.
|
|
||||||
|
|
||||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
You can contact the author at :
|
|
||||||
- zstd source repository : https://github.com/Cyan4973/zstd
|
|
||||||
- ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
|
|
||||||
*/
|
*/
|
||||||
#ifndef ZSTD_STATIC_H
|
#ifndef ZSTD_STATIC_H
|
||||||
#define ZSTD_STATIC_H
|
#define ZSTD_STATIC_H
|
||||||
@@ -392,34 +371,6 @@ static size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstS
|
|||||||
/*
|
/*
|
||||||
zstd_internal - common functions to include
|
zstd_internal - common functions to include
|
||||||
Header File for include
|
Header File for include
|
||||||
Copyright (C) 2014-2015, Yann Collet.
|
|
||||||
|
|
||||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
You can contact the author at :
|
|
||||||
- zstd source repository : https://github.com/Cyan4973/zstd
|
|
||||||
- ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
|
|
||||||
*/
|
*/
|
||||||
#ifndef ZSTD_CCOMMON_H_MODULE
|
#ifndef ZSTD_CCOMMON_H_MODULE
|
||||||
#define ZSTD_CCOMMON_H_MODULE
|
#define ZSTD_CCOMMON_H_MODULE
|
||||||
@@ -507,36 +458,6 @@ static void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
|
|||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
FSE : Finite State Entropy coder
|
FSE : Finite State Entropy coder
|
||||||
header file
|
header file
|
||||||
Copyright (C) 2013-2015, Yann Collet.
|
|
||||||
|
|
||||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
You can contact the author at :
|
|
||||||
- Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
|
||||||
****************************************************************** */
|
****************************************************************** */
|
||||||
#ifndef FSE_H
|
#ifndef FSE_H
|
||||||
#define FSE_H
|
#define FSE_H
|
||||||
@@ -3528,12 +3449,14 @@ static size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDs
|
|||||||
char* const oend = ostart + *maxDstSizePtr;
|
char* const oend = ostart + *maxDstSizePtr;
|
||||||
U32 notDone = 1;
|
U32 notDone = 1;
|
||||||
|
|
||||||
|
DEBUGLOG(5, "ZBUFF_decompressContinue");
|
||||||
while (notDone)
|
while (notDone)
|
||||||
{
|
{
|
||||||
switch(zbc->stage)
|
switch(zbc->stage)
|
||||||
{
|
{
|
||||||
|
|
||||||
case ZBUFFds_init :
|
case ZBUFFds_init :
|
||||||
|
DEBUGLOG(5, "ZBUFF_decompressContinue: stage==ZBUFFds_init => ERROR(init_missing)");
|
||||||
return ERROR(init_missing);
|
return ERROR(init_missing);
|
||||||
|
|
||||||
case ZBUFFds_readHeader :
|
case ZBUFFds_readHeader :
|
||||||
@@ -3741,6 +3664,7 @@ size_t ZBUFFv04_decompressWithDictionary(ZBUFFv04_DCtx* dctx, const void* src, s
|
|||||||
|
|
||||||
size_t ZBUFFv04_decompressContinue(ZBUFFv04_DCtx* dctx, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr)
|
size_t ZBUFFv04_decompressContinue(ZBUFFv04_DCtx* dctx, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(5, "ZBUFFv04_decompressContinue");
|
||||||
return ZBUFF_decompressContinue(dctx, dst, maxDstSizePtr, src, srcSizePtr);
|
return ZBUFF_decompressContinue(dctx, dst, maxDstSizePtr, src, srcSizePtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ MEM_STATIC U32 MEM_swap32(U32 in)
|
|||||||
{
|
{
|
||||||
#if defined(_MSC_VER) /* Visual Studio */
|
#if defined(_MSC_VER) /* Visual Studio */
|
||||||
return _byteswap_ulong(in);
|
return _byteswap_ulong(in);
|
||||||
#elif defined (__GNUC__)
|
#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
|
||||||
return __builtin_bswap32(in);
|
return __builtin_bswap32(in);
|
||||||
#else
|
#else
|
||||||
return ((in << 24) & 0xff000000 ) |
|
return ((in << 24) & 0xff000000 ) |
|
||||||
@@ -203,7 +203,7 @@ MEM_STATIC U64 MEM_swap64(U64 in)
|
|||||||
{
|
{
|
||||||
#if defined(_MSC_VER) /* Visual Studio */
|
#if defined(_MSC_VER) /* Visual Studio */
|
||||||
return _byteswap_uint64(in);
|
return _byteswap_uint64(in);
|
||||||
#elif defined (__GNUC__)
|
#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
|
||||||
return __builtin_bswap64(in);
|
return __builtin_bswap64(in);
|
||||||
#else
|
#else
|
||||||
return ((in << 56) & 0xff00000000000000ULL) |
|
return ((in << 56) & 0xff00000000000000ULL) |
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ MEM_STATIC U32 MEM_swap32(U32 in)
|
|||||||
{
|
{
|
||||||
#if defined(_MSC_VER) /* Visual Studio */
|
#if defined(_MSC_VER) /* Visual Studio */
|
||||||
return _byteswap_ulong(in);
|
return _byteswap_ulong(in);
|
||||||
#elif defined (__GNUC__)
|
#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
|
||||||
return __builtin_bswap32(in);
|
return __builtin_bswap32(in);
|
||||||
#else
|
#else
|
||||||
return ((in << 24) & 0xff000000 ) |
|
return ((in << 24) & 0xff000000 ) |
|
||||||
@@ -362,7 +362,7 @@ MEM_STATIC U64 MEM_swap64(U64 in)
|
|||||||
{
|
{
|
||||||
#if defined(_MSC_VER) /* Visual Studio */
|
#if defined(_MSC_VER) /* Visual Studio */
|
||||||
return _byteswap_uint64(in);
|
return _byteswap_uint64(in);
|
||||||
#elif defined (__GNUC__)
|
#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
|
||||||
return __builtin_bswap64(in);
|
return __builtin_bswap64(in);
|
||||||
#else
|
#else
|
||||||
return ((in << 56) & 0xff00000000000000ULL) |
|
return ((in << 56) & 0xff00000000000000ULL) |
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ extern "C" {
|
|||||||
Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory.
|
Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory.
|
||||||
Compression can be done in:
|
Compression can be done in:
|
||||||
- a single step (described as Simple API)
|
- 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)
|
- unbounded multiple steps (described as Streaming compression)
|
||||||
The compression ratio achievable on small data can be highly improved using a dictionary in:
|
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 (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 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.
|
Advanced experimental APIs shall never be used with a dynamic library.
|
||||||
@@ -59,7 +59,7 @@ extern "C" {
|
|||||||
/*------ Version ------*/
|
/*------ Version ------*/
|
||||||
#define ZSTD_VERSION_MAJOR 1
|
#define ZSTD_VERSION_MAJOR 1
|
||||||
#define ZSTD_VERSION_MINOR 3
|
#define ZSTD_VERSION_MINOR 3
|
||||||
#define ZSTD_VERSION_RELEASE 3
|
#define ZSTD_VERSION_RELEASE 4
|
||||||
|
|
||||||
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
|
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
|
||||||
ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll version */
|
ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll version */
|
||||||
@@ -68,7 +68,7 @@ ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll versio
|
|||||||
#define ZSTD_QUOTE(str) #str
|
#define ZSTD_QUOTE(str) #str
|
||||||
#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)
|
#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)
|
||||||
#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)
|
#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,
|
ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t compressedSize);
|
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.
|
* `src` should point to the start of a ZSTD encoded frame.
|
||||||
* `srcSize` must be at least as large as the frame header.
|
* `srcSize` must be at least as large as the frame header.
|
||||||
* hint : any size >= `ZSTD_frameHeaderSize_max` is large enough.
|
* 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() :
|
/*! ZSTD_getDecompressedSize() :
|
||||||
* NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
|
* NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
|
||||||
* Both functions work the same way,
|
* Both functions work the same way, but ZSTD_getDecompressedSize() blends
|
||||||
* but ZSTD_getDecompressedSize() blends
|
* "empty", "unknown" and "error" results to the same return value (0),
|
||||||
* "empty", "unknown" and "error" results in the same return value (0),
|
* while ZSTD_getFrameContentSize() gives them separate return values.
|
||||||
* while ZSTD_getFrameContentSize() distinguishes them.
|
* `src` is the start of a zstd compressed frame.
|
||||||
*
|
|
||||||
* '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. */
|
* @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);
|
ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
||||||
/*====== Helper functions ======*/
|
/*====== 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 */
|
#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 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 const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */
|
||||||
ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
|
ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
|
||||||
|
|
||||||
|
|
||||||
/***************************************
|
/***************************************
|
||||||
* Explicit memory management
|
* Explicit context
|
||||||
***************************************/
|
***************************************/
|
||||||
/*= Compression context
|
/*= Compression context
|
||||||
* When compressing many times,
|
* 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) */
|
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 =====*/
|
/*===== ZSTD_DStream management functions =====*/
|
||||||
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
|
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
|
||||||
ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
|
ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
|
||||||
@@ -375,23 +373,24 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output
|
|||||||
/* --- Constants ---*/
|
/* --- Constants ---*/
|
||||||
#define ZSTD_MAGICNUMBER 0xFD2FB528 /* >= v0.8.0 */
|
#define ZSTD_MAGICNUMBER 0xFD2FB528 /* >= v0.8.0 */
|
||||||
#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U
|
#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_32 30
|
||||||
#define ZSTD_WINDOWLOG_MAX_64 31
|
#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_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64))
|
||||||
#define ZSTD_WINDOWLOG_MIN 10
|
#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_HASHLOG_MIN 6
|
||||||
#define ZSTD_CHAINLOG_MAX MIN(ZSTD_WINDOWLOG_MAX+1, 30)
|
#define ZSTD_CHAINLOG_MAX_32 29
|
||||||
|
#define ZSTD_CHAINLOG_MAX_64 30
|
||||||
|
#define ZSTD_CHAINLOG_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64))
|
||||||
#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
|
#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
|
||||||
#define ZSTD_HASHLOG3_MAX 17
|
#define ZSTD_HASHLOG3_MAX 17
|
||||||
#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
|
#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
|
||||||
#define ZSTD_SEARCHLOG_MIN 1
|
#define ZSTD_SEARCHLOG_MIN 1
|
||||||
#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
|
#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
|
||||||
#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */
|
#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */
|
||||||
#define ZSTD_TARGETLENGTH_MIN 4 /* only useful for btopt */
|
#define ZSTD_TARGETLENGTH_MIN 1 /* only used by btopt, btultra and btfast */
|
||||||
#define ZSTD_TARGETLENGTH_MAX 999 /* only useful for btopt */
|
|
||||||
#define ZSTD_LDM_MINMATCH_MIN 4
|
#define ZSTD_LDM_MINMATCH_MIN 4
|
||||||
#define ZSTD_LDM_MINMATCH_MAX 4096
|
#define ZSTD_LDM_MINMATCH_MAX 4096
|
||||||
#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
|
#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
|
||||||
@@ -432,12 +431,17 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
|
typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
|
||||||
|
|
||||||
/*--- Custom memory allocation functions ---*/
|
typedef enum {
|
||||||
typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
|
ZSTD_dct_auto=0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
|
||||||
typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
|
ZSTD_dct_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
|
||||||
typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
|
ZSTD_dct_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */
|
||||||
/* use this constant to defer to stdlib's functions */
|
} ZSTD_dictContentType_e;
|
||||||
static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL };
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************
|
/***************************************
|
||||||
@@ -483,12 +487,12 @@ ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
|
|||||||
|
|
||||||
|
|
||||||
/***************************************
|
/***************************************
|
||||||
* Context memory usage
|
* Memory management
|
||||||
***************************************/
|
***************************************/
|
||||||
|
|
||||||
/*! ZSTD_sizeof_*() :
|
/*! ZSTD_sizeof_*() :
|
||||||
* These functions give the current memory usage of selected object.
|
* 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_CCtx(const ZSTD_CCtx* cctx);
|
||||||
ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
|
ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
|
||||||
ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
|
ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
|
||||||
@@ -503,8 +507,8 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
|||||||
* It will also consider src size to be arbitrarily "large", which is worst case.
|
* It will also consider src size to be arbitrarily "large", which is worst case.
|
||||||
* If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
|
* 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_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.
|
* 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_nbWorkers 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(int compressionLevel);
|
||||||
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
|
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||||
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||||
@@ -515,8 +519,8 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
|
|||||||
* It will also consider src size to be arbitrarily "large", which is worst case.
|
* It will also consider src size to be arbitrarily "large", which is worst case.
|
||||||
* If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
* If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
||||||
* ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
* ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||||
* ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_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.
|
* 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_nbWorkers is >= 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.
|
* ZSTD_DStream memory budget depends on window Size.
|
||||||
* This information can be passed manually, using ZSTD_estimateDStreamSize,
|
* This information can be passed manually, using ZSTD_estimateDStreamSize,
|
||||||
* or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
|
* or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
|
||||||
@@ -529,46 +533,86 @@ 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(size_t windowSize);
|
||||||
ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
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_estimate?DictSize() :
|
||||||
* ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
|
* 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().
|
* ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced().
|
||||||
* Note : dictionary created by reference using ZSTD_dlm_byRef are smaller
|
* 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(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_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||||
ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
|
ZSTDLIB_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 const ZSTD_CDict* ZSTD_initStaticCDict(
|
||||||
|
void* workspace, size_t workspaceSize,
|
||||||
|
const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType,
|
||||||
|
ZSTD_compressionParameters cParams);
|
||||||
|
|
||||||
|
ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict(
|
||||||
|
void* workspace, size_t workspaceSize,
|
||||||
|
const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType);
|
||||||
|
|
||||||
|
/*! 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 <stdlib.h> 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_dictContentType_e dictContentType,
|
||||||
|
ZSTD_compressionParameters cParams,
|
||||||
|
ZSTD_customMem customMem);
|
||||||
|
|
||||||
|
ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType,
|
||||||
|
ZSTD_customMem customMem);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************
|
/***************************************
|
||||||
* Advanced compression functions
|
* 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_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() :
|
/*! ZSTD_createCDict_byReference() :
|
||||||
* Create a digested dictionary for compression
|
* Create a digested dictionary for compression
|
||||||
@@ -576,38 +620,6 @@ ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize
|
|||||||
* It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict */
|
* 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);
|
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,
|
|
||||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
|
||||||
ZSTD_dictMode_e dictMode,
|
|
||||||
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() :
|
/*! ZSTD_getCParams() :
|
||||||
* @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
|
* @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
|
||||||
* `estimatedSrcSize` value is optional, select 0 if not known */
|
* `estimatedSrcSize` value is optional, select 0 if not known */
|
||||||
@@ -652,28 +664,6 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
|
|||||||
* Note 3 : Skippable Frame Identifiers are considered valid. */
|
* Note 3 : Skippable Frame Identifiers are considered valid. */
|
||||||
ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);
|
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_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() :
|
/*! ZSTD_createDDict_byReference() :
|
||||||
* Create a digested dictionary, ready to start decompression operation without startup delay.
|
* Create a digested dictionary, ready to start decompression operation without startup delay.
|
||||||
* Dictionary content is referenced, and therefore stays in dictBuffer.
|
* Dictionary content is referenced, and therefore stays in dictBuffer.
|
||||||
@@ -681,26 +671,6 @@ ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize
|
|||||||
* it must remain read accessible throughout the lifetime of DDict */
|
* it must remain read accessible throughout the lifetime of DDict */
|
||||||
ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
|
ZSTDLIB_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_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() :
|
/*! ZSTD_getDictID_fromDict() :
|
||||||
* Provides the dictID stored within dictionary.
|
* Provides the dictID stored within dictionary.
|
||||||
@@ -732,8 +702,6 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
|
|||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
/*===== Advanced Streaming compression functions =====*/
|
/*===== 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_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_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,
|
ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
|
||||||
@@ -748,14 +716,28 @@ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const
|
|||||||
* If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
|
* If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
|
||||||
* If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
|
* If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
|
||||||
* For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
|
* For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
|
||||||
* but it may change to mean "empty" in some future version, so prefer using macro ZSTD_CONTENTSIZE_UNKNOWN.
|
* but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
|
||||||
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */
|
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */
|
||||||
ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
|
ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long long ingested;
|
||||||
|
unsigned long long consumed;
|
||||||
|
unsigned long long produced;
|
||||||
|
} ZSTD_frameProgression;
|
||||||
|
|
||||||
|
/* ZSTD_getFrameProgression():
|
||||||
|
* tells how much data has been ingested (read from input)
|
||||||
|
* consumed (input actually compressed) and produced (output) for current frame.
|
||||||
|
* Therefore, (ingested - consumed) is amount of input data buffered internally, not yet compressed.
|
||||||
|
* Can report progression inside worker threads (multi-threading and non-blocking mode).
|
||||||
|
*/
|
||||||
|
ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*===== Advanced Streaming decompression functions =====*/
|
/*===== 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;
|
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_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 */
|
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 */
|
||||||
@@ -924,10 +906,8 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
|||||||
* and then applied on all subsequent compression jobs.
|
* and then applied on all subsequent compression jobs.
|
||||||
* When no parameter is ever provided, CCtx is created with compression level ZSTD_CLEVEL_DEFAULT.
|
* When no parameter is ever provided, CCtx is created with compression level ZSTD_CLEVEL_DEFAULT.
|
||||||
*
|
*
|
||||||
* This API is intended to replace all others experimental API.
|
* This API is intended to replace all others advanced / experimental API entry points.
|
||||||
* It can basically do all other use cases, and even new ones.
|
* But it stands a reasonable chance to become "stable", after a reasonable testing period.
|
||||||
* In constrast with _advanced() variants, it stands a reasonable chance to become "stable",
|
|
||||||
* after a good testing period.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* note on naming convention :
|
/* note on naming convention :
|
||||||
@@ -944,12 +924,12 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
|||||||
* All enum will be pinned to explicit values before reaching "stable API" status */
|
* All enum will be pinned to explicit values before reaching "stable API" status */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Question : should we have a format ZSTD_f_auto ?
|
/* Opened question : should we have a format ZSTD_f_auto ?
|
||||||
* For the time being, it would mean exactly the same as ZSTD_f_zstd1.
|
* Today, it would mean exactly the same as ZSTD_f_zstd1.
|
||||||
* But, in the future, should several formats be supported,
|
* But, in the future, should several formats become supported,
|
||||||
* on the compression side, it would mean "default format".
|
* on the compression side, it would mean "default format".
|
||||||
* On the decompression side, it would mean "multi format",
|
* On the decompression side, it would mean "automatic format detection",
|
||||||
* and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames".
|
* so that ZSTD_f_zstd1 would mean "accept *only* zstd frames".
|
||||||
* Since meaning is a little different, another option could be to define different enums for compression and decompression.
|
* Since meaning is a little different, another option could be to define different enums for compression and decompression.
|
||||||
* This question could be kept for later, when there are actually multiple formats to support,
|
* This question could be kept for later, when there are actually multiple formats to support,
|
||||||
* but there is also the question of pinning enum values, and pinning value `0` is especially important */
|
* but there is also the question of pinning enum values, and pinning value `0` is especially important */
|
||||||
@@ -967,42 +947,76 @@ typedef enum {
|
|||||||
/* compression parameters */
|
/* compression parameters */
|
||||||
ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
|
ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
|
||||||
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
||||||
* Special: value 0 means "do not change cLevel". */
|
* Special: value 0 means "do not change cLevel".
|
||||||
|
* Note 1 : it's possible to pass a negative compression level by casting it to unsigned type.
|
||||||
|
* Note 2 : setting a level sets all default values of other compression parameters.
|
||||||
|
* Note 3 : setting compressionLevel automatically updates ZSTD_p_compressLiterals. */
|
||||||
ZSTD_p_windowLog, /* Maximum allowed back-reference distance, expressed as power of 2.
|
ZSTD_p_windowLog, /* Maximum allowed back-reference distance, expressed as power of 2.
|
||||||
* Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
|
* Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
|
||||||
* Special: value 0 means "do not change windowLog".
|
* Special: value 0 means "use default windowLog".
|
||||||
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
||||||
* requires setting the maximum window size at least as large during decompression. */
|
* requires explicitly allowing such window size during decompression stage. */
|
||||||
ZSTD_p_hashLog, /* Size of the probe table, as a power of 2.
|
ZSTD_p_hashLog, /* Size of the probe table, as a power of 2.
|
||||||
* Resulting table size is (1 << (hashLog+2)).
|
* Resulting table size is (1 << (hashLog+2)).
|
||||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
||||||
* Larger tables improve compression ratio of strategies <= dFast,
|
* Larger tables improve compression ratio of strategies <= dFast,
|
||||||
* and improve speed of strategies > dFast.
|
* and improve speed of strategies > dFast.
|
||||||
* Special: value 0 means "do not change hashLog". */
|
* Special: value 0 means "use default hashLog". */
|
||||||
ZSTD_p_chainLog, /* Size of the full-search table, as a power of 2.
|
ZSTD_p_chainLog, /* Size of the full-search table, as a power of 2.
|
||||||
* Resulting table size is (1 << (chainLog+2)).
|
* Resulting table size is (1 << (chainLog+2)).
|
||||||
* Larger tables result in better and slower compression.
|
* Larger tables result in better and slower compression.
|
||||||
* This parameter is useless when using "fast" strategy.
|
* This parameter is useless when using "fast" strategy.
|
||||||
* Special: value 0 means "do not change chainLog". */
|
* Special: value 0 means "use default chainLog". */
|
||||||
ZSTD_p_searchLog, /* Number of search attempts, as a power of 2.
|
ZSTD_p_searchLog, /* Number of search attempts, as a power of 2.
|
||||||
* More attempts result in better and slower compression.
|
* More attempts result in better and slower compression.
|
||||||
* This parameter is useless when using "fast" and "dFast" strategies.
|
* This parameter is useless when using "fast" and "dFast" strategies.
|
||||||
* Special: value 0 means "do not change searchLog". */
|
* Special: value 0 means "use default searchLog". */
|
||||||
ZSTD_p_minMatch, /* Minimum size of searched matches (note : repCode matches can be smaller).
|
ZSTD_p_minMatch, /* Minimum size of searched matches (note : repCode matches can be smaller).
|
||||||
* Larger values make faster compression and decompression, but decrease ratio.
|
* Larger values make faster compression and decompression, but decrease ratio.
|
||||||
* Must be clamped between ZSTD_SEARCHLENGTH_MIN and ZSTD_SEARCHLENGTH_MAX.
|
* Must be clamped between ZSTD_SEARCHLENGTH_MIN and ZSTD_SEARCHLENGTH_MAX.
|
||||||
* Note that currently, for all strategies < btopt, effective minimum is 4.
|
* Note that currently, for all strategies < btopt, effective minimum is 4.
|
||||||
* Note that currently, for all strategies > fast, effective maximum is 6.
|
* , for all strategies > fast, effective maximum is 6.
|
||||||
* Special: value 0 means "do not change minMatchLength". */
|
* Special: value 0 means "use default minMatchLength". */
|
||||||
ZSTD_p_targetLength, /* Only useful for strategies >= btopt.
|
ZSTD_p_targetLength, /* Impact of this field depends on strategy.
|
||||||
|
* For strategies btopt & btultra:
|
||||||
* Length of Match considered "good enough" to stop search.
|
* Length of Match considered "good enough" to stop search.
|
||||||
* Larger values make compression stronger and slower.
|
* Larger values make compression stronger, and slower.
|
||||||
* Special: value 0 means "do not change targetLength". */
|
* For strategy fast:
|
||||||
|
* Distance between match sampling.
|
||||||
|
* Larger values make compression faster, and weaker.
|
||||||
|
* Special: value 0 means "use default targetLength". */
|
||||||
ZSTD_p_compressionStrategy, /* See ZSTD_strategy enum definition.
|
ZSTD_p_compressionStrategy, /* See ZSTD_strategy enum definition.
|
||||||
* Cast selected strategy as unsigned for ZSTD_CCtx_setParameter() compatibility.
|
* Cast selected strategy as unsigned for ZSTD_CCtx_setParameter() compatibility.
|
||||||
* The higher the value of selected strategy, the more complex it is,
|
* The higher the value of selected strategy, the more complex it is,
|
||||||
* resulting in stronger and slower compression.
|
* resulting in stronger and slower compression.
|
||||||
* Special: value 0 means "do not change strategy". */
|
* Special: value 0 means "use default strategy". */
|
||||||
|
|
||||||
|
ZSTD_p_enableLongDistanceMatching=160, /* Enable long distance matching.
|
||||||
|
* This parameter is designed to improve compression ratio
|
||||||
|
* for large inputs, by finding large matches at long distance.
|
||||||
|
* It increases memory usage and window size.
|
||||||
|
* Note: enabling this parameter increases ZSTD_p_windowLog to 128 MB
|
||||||
|
* except when expressly set to a different value. */
|
||||||
|
ZSTD_p_ldmHashLog, /* Size of the table for long distance matching, as a power of 2.
|
||||||
|
* Larger values increase memory usage and compression ratio,
|
||||||
|
* but decrease compression speed.
|
||||||
|
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
|
||||||
|
* default: windowlog - 7.
|
||||||
|
* Special: value 0 means "automatically determine hashlog". */
|
||||||
|
ZSTD_p_ldmMinMatch, /* Minimum match size for long distance matcher.
|
||||||
|
* Larger/too small values usually decrease compression ratio.
|
||||||
|
* Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX.
|
||||||
|
* Special: value 0 means "use default value" (default: 64). */
|
||||||
|
ZSTD_p_ldmBucketSizeLog, /* Log size of each bucket in the LDM hash table for collision resolution.
|
||||||
|
* Larger values improve collision resolution but decrease compression speed.
|
||||||
|
* The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX .
|
||||||
|
* Special: value 0 means "use default value" (default: 3). */
|
||||||
|
ZSTD_p_ldmHashEveryLog, /* Frequency of inserting/looking up entries in the LDM hash table.
|
||||||
|
* Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN).
|
||||||
|
* Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage.
|
||||||
|
* Larger values improve compression speed.
|
||||||
|
* Deviating far from default value will likely result in a compression ratio decrease.
|
||||||
|
* Special: value 0 means "automatically determine hashEveryLog". */
|
||||||
|
|
||||||
/* frame parameters */
|
/* frame parameters */
|
||||||
ZSTD_p_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1)
|
ZSTD_p_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1)
|
||||||
@@ -1012,58 +1026,45 @@ typedef enum {
|
|||||||
ZSTD_p_dictIDFlag, /* When applicable, dictionary's ID is written into frame header (default:1) */
|
ZSTD_p_dictIDFlag, /* When applicable, dictionary's ID is written into frame header (default:1) */
|
||||||
|
|
||||||
/* multi-threading parameters */
|
/* multi-threading parameters */
|
||||||
ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1)
|
/* These parameters are only useful if multi-threading is enabled (ZSTD_MULTITHREAD).
|
||||||
* More threads improve speed, but also increase memory usage.
|
* They return an error otherwise. */
|
||||||
* Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled.
|
ZSTD_p_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel.
|
||||||
* Special: value 0 means "do not change nbThreads" */
|
* When nbWorkers >= 1, triggers asynchronous mode :
|
||||||
ZSTD_p_jobSize, /* Size of a compression job. This value is only enforced in streaming (non-blocking) mode.
|
* ZSTD_compress_generic() consumes some input, flush some output if possible, and immediately gives back control to caller,
|
||||||
* Each compression job is completed in parallel, so indirectly controls the nb of active threads.
|
* while compression work is performed in parallel, within worker threads.
|
||||||
|
* (note : a strong exception to this rule is when first invocation sets ZSTD_e_end : it becomes a blocking call).
|
||||||
|
* More workers improve speed, but also increase memory usage.
|
||||||
|
* Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */
|
||||||
|
ZSTD_p_jobSize, /* Size of a compression job. This value is enforced only in non-blocking mode.
|
||||||
|
* Each compression job is completed in parallel, so this value indirectly controls the nb of active threads.
|
||||||
* 0 means default, which is dynamically determined based on compression parameters.
|
* 0 means default, which is dynamically determined based on compression parameters.
|
||||||
* Job size must be a minimum of overlapSize, or 1 KB, whichever is largest
|
* Job size must be a minimum of overlapSize, or 1 MB, whichever is largest.
|
||||||
* The minimum size is automatically and transparently enforced */
|
* The minimum size is automatically and transparently enforced */
|
||||||
ZSTD_p_overlapSizeLog, /* Size of previous input reloaded at the beginning of each job.
|
ZSTD_p_overlapSizeLog, /* Size of previous input reloaded at the beginning of each job.
|
||||||
* 0 => no overlap, 6(default) => use 1/8th of windowSize, >=9 => use full windowSize */
|
* 0 => no overlap, 6(default) => use 1/8th of windowSize, >=9 => use full windowSize */
|
||||||
|
|
||||||
/* advanced parameters - may not remain available after API update */
|
/* =================================================================== */
|
||||||
|
/* experimental parameters - no stability guaranteed */
|
||||||
|
/* =================================================================== */
|
||||||
|
|
||||||
|
ZSTD_p_compressLiterals=1000, /* control huffman compression of literals (enabled) by default.
|
||||||
|
* disabling it improves speed and decreases compression ratio by a large amount.
|
||||||
|
* note : this setting is automatically updated when changing compression level.
|
||||||
|
* positive compression levels set ZSTD_p_compressLiterals to 1.
|
||||||
|
* negative compression levels set ZSTD_p_compressLiterals to 0. */
|
||||||
|
|
||||||
ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize,
|
ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize,
|
||||||
* even when referencing into Dictionary content (default:0) */
|
* even when referencing into Dictionary content (default:0) */
|
||||||
ZSTD_p_enableLongDistanceMatching=1200, /* Enable long distance matching.
|
|
||||||
* This parameter is designed to improve the compression
|
|
||||||
* ratio for large inputs with long distance matches.
|
|
||||||
* This increases the memory usage as well as window size.
|
|
||||||
* Note: setting this parameter sets all the LDM parameters
|
|
||||||
* as well as ZSTD_p_windowLog. It should be set after
|
|
||||||
* ZSTD_p_compressionLevel and before ZSTD_p_windowLog and
|
|
||||||
* other LDM parameters. Setting the compression level
|
|
||||||
* after this parameter overrides the window log, though LDM
|
|
||||||
* will remain enabled until explicitly disabled. */
|
|
||||||
ZSTD_p_ldmHashLog, /* Size of the table for long distance matching, as a power of 2.
|
|
||||||
* Larger values increase memory usage and compression ratio, but decrease
|
|
||||||
* compression speed.
|
|
||||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
|
|
||||||
* (default: windowlog - 7). */
|
|
||||||
ZSTD_p_ldmMinMatch, /* Minimum size of searched matches for long distance matcher.
|
|
||||||
* Larger/too small values usually decrease compression ratio.
|
|
||||||
* Must be clamped between ZSTD_LDM_MINMATCH_MIN
|
|
||||||
* and ZSTD_LDM_MINMATCH_MAX (default: 64). */
|
|
||||||
ZSTD_p_ldmBucketSizeLog, /* Log size of each bucket in the LDM hash table for collision resolution.
|
|
||||||
* Larger values usually improve collision resolution but may decrease
|
|
||||||
* compression speed.
|
|
||||||
* The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX (default: 3). */
|
|
||||||
ZSTD_p_ldmHashEveryLog, /* Frequency of inserting/looking up entries in the LDM hash table.
|
|
||||||
* The default is MAX(0, (windowLog - ldmHashLog)) to
|
|
||||||
* optimize hash table usage.
|
|
||||||
* Larger values improve compression speed. Deviating far from the
|
|
||||||
* default value will likely result in a decrease in compression ratio.
|
|
||||||
* Must be clamped between 0 and ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
|
|
||||||
|
|
||||||
} ZSTD_cParameter;
|
} ZSTD_cParameter;
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTD_CCtx_setParameter() :
|
/*! ZSTD_CCtx_setParameter() :
|
||||||
* Set one compression parameter, selected by enum ZSTD_cParameter.
|
* Set one compression parameter, selected by enum ZSTD_cParameter.
|
||||||
|
* Setting a parameter is generally only possible during frame initialization (before starting compression),
|
||||||
|
* except for a few exceptions which can be updated during compression: compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy.
|
||||||
* Note : when `value` is an enum, cast it to unsigned for proper type checking.
|
* Note : when `value` is an enum, cast it to unsigned for proper type checking.
|
||||||
* @result : informational value (typically, the one being set, possibly corrected),
|
* @result : informational value (typically, value being set clamped correctly),
|
||||||
* or an error code (which can be tested with ZSTD_isError()). */
|
* or an error code (which can be tested with ZSTD_isError()). */
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value);
|
ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value);
|
||||||
|
|
||||||
@@ -1079,26 +1080,24 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param
|
|||||||
ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
|
ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
|
||||||
|
|
||||||
/*! ZSTD_CCtx_loadDictionary() :
|
/*! ZSTD_CCtx_loadDictionary() :
|
||||||
* Create an internal CDict from dict buffer.
|
* Create an internal CDict from `dict` buffer.
|
||||||
* Decompression will have to use same buffer.
|
* Decompression will have to use same dictionary.
|
||||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||||
* Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
|
* Special: Adding a NULL (or 0-size) dictionary invalidates previous dictionary,
|
||||||
* meaning "return to no-dictionary mode".
|
* meaning "return to no-dictionary mode".
|
||||||
* Note 1 : `dict` content will be copied internally. Use
|
* Note 1 : Dictionary will be used for all future compression jobs.
|
||||||
* ZSTD_CCtx_loadDictionary_byReference() to reference dictionary
|
* To return to "no-dictionary" situation, load a NULL dictionary
|
||||||
* content instead. The dictionary buffer must then outlive its
|
|
||||||
* users.
|
|
||||||
* Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters.
|
* Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters.
|
||||||
* For this reason, compression parameters cannot be changed anymore after loading a dictionary.
|
* For this reason, compression parameters cannot be changed anymore after loading a dictionary.
|
||||||
* It's also a CPU-heavy operation, with non-negligible impact on latency.
|
* It's also a CPU consuming operation, with non-negligible impact on latency.
|
||||||
* Note 3 : Dictionary will be used for all future compression jobs.
|
* Note 3 :`dict` content will be copied internally.
|
||||||
* To return to "no-dictionary" situation, load a NULL dictionary
|
* Use ZSTD_CCtx_loadDictionary_byReference() to reference dictionary content instead.
|
||||||
* Note 5 : Use ZSTD_CCtx_loadDictionary_advanced() to select how dictionary
|
* In such a case, dictionary buffer must outlive its users.
|
||||||
* content will be interpreted.
|
* Note 4 : Use ZSTD_CCtx_loadDictionary_advanced()
|
||||||
*/
|
* to precisely select how dictionary content must be interpreted. */
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
|
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTD_CCtx_refCDict() :
|
/*! ZSTD_CCtx_refCDict() :
|
||||||
@@ -1110,8 +1109,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void
|
|||||||
* Special : adding a NULL CDict means "return to no-dictionary mode".
|
* Special : adding a NULL CDict means "return to no-dictionary mode".
|
||||||
* Note 1 : Currently, only one dictionary can be managed.
|
* Note 1 : Currently, only one dictionary can be managed.
|
||||||
* Adding a new dictionary effectively "discards" any previous one.
|
* Adding a new dictionary effectively "discards" any previous one.
|
||||||
* Note 2 : CDict is just referenced, its lifetime must outlive CCtx.
|
* Note 2 : CDict is just referenced, its lifetime must outlive CCtx. */
|
||||||
*/
|
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
||||||
|
|
||||||
/*! ZSTD_CCtx_refPrefix() :
|
/*! ZSTD_CCtx_refPrefix() :
|
||||||
@@ -1124,17 +1122,26 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
|||||||
* Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary
|
* Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary
|
||||||
* Note 1 : Prefix buffer is referenced. It must outlive compression job.
|
* Note 1 : Prefix buffer is referenced. It must outlive compression job.
|
||||||
* Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
* Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
||||||
* It's a CPU-heavy operation, with non-negligible impact on latency.
|
* It's a CPU consuming operation, with non-negligible impact on latency.
|
||||||
* Note 3 : By default, the prefix is treated as raw content
|
* Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||||
* (ZSTD_dm_rawContent). Use ZSTD_CCtx_refPrefix_advanced() to alter
|
* Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode. */
|
||||||
* dictMode. */
|
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize);
|
ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize);
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
|
ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
|
||||||
|
|
||||||
|
/*! ZSTD_CCtx_reset() :
|
||||||
|
* 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.
|
||||||
|
* Dictionary (if any) is dropped.
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ZSTD_e_continue=0, /* collect more data, encoder transparently decides when to output result, for optimal conditions */
|
ZSTD_e_continue=0, /* collect more data, encoder decides when to output compressed result, for optimal conditions */
|
||||||
ZSTD_e_flush, /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */
|
ZSTD_e_flush, /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */
|
||||||
ZSTD_e_end /* flush any remaining data and close current frame. Any additional data starts a new frame. */
|
ZSTD_e_end /* flush any remaining data and close current frame. Any additional data starts a new frame. */
|
||||||
} ZSTD_EndDirective;
|
} ZSTD_EndDirective;
|
||||||
@@ -1150,10 +1157,11 @@ typedef enum {
|
|||||||
* and then immediately returns, just indicating that there is some data remaining to be flushed.
|
* and then immediately returns, just indicating that there is some data remaining to be flushed.
|
||||||
* The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
|
* The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
|
||||||
* - Exception : in multi-threading mode, if the first call requests a ZSTD_e_end directive, it is blocking : it will complete compression before giving back control to caller.
|
* - Exception : in multi-threading mode, if the first call requests a ZSTD_e_end directive, it is blocking : it will complete compression before giving back control to caller.
|
||||||
* - @return provides the minimum amount of data remaining to be flushed from internal buffers
|
* - @return provides a minimum amount of data remaining to be flushed from internal buffers
|
||||||
* or an error code, which can be tested using ZSTD_isError().
|
* or an error code, which can be tested using ZSTD_isError().
|
||||||
* if @return != 0, flush is not fully completed, there is still some data left within internal buffers.
|
* if @return != 0, flush is not fully completed, there is still some data left within internal buffers.
|
||||||
* This is useful to determine if a ZSTD_e_flush or ZSTD_e_end directive is completed.
|
* This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers.
|
||||||
|
* For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed.
|
||||||
* - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
|
* - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
|
||||||
* only ZSTD_e_end or ZSTD_e_flush operations are allowed.
|
* only ZSTD_e_end or ZSTD_e_flush operations are allowed.
|
||||||
* Before starting a new compression job, or changing compression parameters,
|
* Before starting a new compression job, or changing compression parameters,
|
||||||
@@ -1164,16 +1172,6 @@ ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
|||||||
ZSTD_inBuffer* input,
|
ZSTD_inBuffer* input,
|
||||||
ZSTD_EndDirective endOp);
|
ZSTD_EndDirective endOp);
|
||||||
|
|
||||||
/*! ZSTD_CCtx_reset() :
|
|
||||||
* 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.
|
|
||||||
* Dictionary (if any) is dropped.
|
|
||||||
* 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 ! */
|
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTD_compress_generic_simpleArgs() :
|
/*! ZSTD_compress_generic_simpleArgs() :
|
||||||
* Same as ZSTD_compress_generic(),
|
* Same as ZSTD_compress_generic(),
|
||||||
@@ -1207,25 +1205,26 @@ ZSTDLIB_API size_t ZSTD_compress_generic_simpleArgs (
|
|||||||
* for static allocation for single-threaded compression.
|
* for static allocation for single-threaded compression.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
|
ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
|
||||||
|
ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
|
||||||
|
|
||||||
/*! ZSTD_resetCCtxParams() :
|
|
||||||
* Reset params to default, with the default compression level.
|
/*! ZSTD_CCtxParams_reset() :
|
||||||
|
* Reset params to default values.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
|
ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params);
|
||||||
|
|
||||||
/*! ZSTD_initCCtxParams() :
|
/*! ZSTD_CCtxParams_init() :
|
||||||
* Initializes the compression parameters of cctxParams according to
|
* Initializes the compression parameters of cctxParams according to
|
||||||
* compression level. All other parameters are reset to their default values.
|
* compression level. All other parameters are reset to their default values.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel);
|
ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel);
|
||||||
|
|
||||||
/*! ZSTD_initCCtxParams_advanced() :
|
/*! ZSTD_CCtxParams_init_advanced() :
|
||||||
* Initializes the compression and frame parameters of cctxParams according to
|
* Initializes the compression and frame parameters of cctxParams according to
|
||||||
* params. All other parameters are reset to their default values.
|
* params. All other parameters are reset to their default values.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
|
ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
|
||||||
|
|
||||||
ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
|
|
||||||
|
|
||||||
/*! ZSTD_CCtxParam_setParameter() :
|
/*! ZSTD_CCtxParam_setParameter() :
|
||||||
* Similar to ZSTD_CCtx_setParameter.
|
* Similar to ZSTD_CCtx_setParameter.
|
||||||
@@ -1238,9 +1237,10 @@ ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cP
|
|||||||
|
|
||||||
/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
|
/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
|
||||||
* Apply a set of ZSTD_CCtx_params to the compression context.
|
* Apply a set of ZSTD_CCtx_params to the compression context.
|
||||||
* This must be done before the dictionary is loaded.
|
* This can be done even after compression is started,
|
||||||
* The pledgedSrcSize is treated as unknown.
|
* if nbWorkers==0, this will have no impact until a new compression is started.
|
||||||
* Multithreading parameters are applied only if nbThreads > 1.
|
* if nbWorkers>=1, new parameters will be picked up at next job,
|
||||||
|
* with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated).
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
||||||
@@ -1267,9 +1267,9 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
|||||||
* Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select
|
* Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select
|
||||||
* how dictionary content will be interpreted and loaded.
|
* how dictionary content will be interpreted and loaded.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); /* not implemented */
|
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
|
||||||
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); /* not implemented */
|
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
|
||||||
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode); /* not implemented */
|
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTD_DCtx_refDDict() :
|
/*! ZSTD_DCtx_refDDict() :
|
||||||
@@ -1281,7 +1281,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void
|
|||||||
* Special : adding a NULL DDict means "return to no-dictionary mode".
|
* Special : adding a NULL DDict means "return to no-dictionary mode".
|
||||||
* Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
|
* Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); /* not implemented */
|
ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTD_DCtx_refPrefix() :
|
/*! ZSTD_DCtx_refPrefix() :
|
||||||
@@ -1295,8 +1295,8 @@ ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
|
|||||||
* Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
* Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
||||||
* Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
|
* Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize); /* not implemented */
|
ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);
|
||||||
ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode); /* not implemented */
|
ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
|
||||||
|
|
||||||
|
|
||||||
/*! ZSTD_DCtx_setMaxWindowSize() :
|
/*! ZSTD_DCtx_setMaxWindowSize() :
|
||||||
@@ -1389,7 +1389,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_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_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_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 */
|
#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */
|
||||||
|
|||||||
@@ -157,6 +157,8 @@ endif
|
|||||||
zstd-release: DEBUGFLAGS :=
|
zstd-release: DEBUGFLAGS :=
|
||||||
zstd-release: zstd
|
zstd-release: zstd
|
||||||
|
|
||||||
|
zstd32 : CPPFLAGS += $(THREAD_CPP)
|
||||||
|
zstd32 : LDFLAGS += $(THREAD_LD)
|
||||||
zstd32 : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT)
|
zstd32 : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT)
|
||||||
zstd32 : $(ZSTDLIB_FILES) zstdcli.c fileio.c bench.c datagen.c dibio.c
|
zstd32 : $(ZSTDLIB_FILES) zstdcli.c fileio.c bench.c datagen.c dibio.c
|
||||||
ifneq (,$(filter Windows%,$(OS)))
|
ifneq (,$(filter Windows%,$(OS)))
|
||||||
|
|||||||
@@ -11,44 +11,14 @@ There are however other Makefile targets that create different variations of CLI
|
|||||||
|
|
||||||
|
|
||||||
#### Compilation variables
|
#### Compilation variables
|
||||||
`zstd` scope can be altered by modifying the following compilation variables :
|
`zstd` scope can be altered by modifying the following `make` variables :
|
||||||
|
|
||||||
- __HAVE_THREAD__ : multithreading is automatically enabled when `pthread` is detected.
|
- __HAVE_THREAD__ : multithreading is automatically enabled when `pthread` is detected.
|
||||||
It's possible to disable multithread support, by setting HAVE_THREAD=0 .
|
It's possible to disable multithread support, by setting `HAVE_THREAD=0`.
|
||||||
Example : make zstd HAVE_THREAD=0
|
Example : `make zstd HAVE_THREAD=0`
|
||||||
It's also possible to force compilation with multithread support, using HAVE_THREAD=1.
|
It's also possible to force multithread support, using `HAVE_THREAD=1`.
|
||||||
In which case, linking stage will fail if `pthread` library cannot be found.
|
In which case, linking stage will fail if neither `pthread` nor `windows.h` library can be found.
|
||||||
This might be useful to prevent silent feature disabling.
|
This is useful to ensure this feature is not silently disabled.
|
||||||
|
|
||||||
- __HAVE_ZLIB__ : `zstd` can compress and decompress files in `.gz` format.
|
|
||||||
This is ordered through command `--format=gzip`.
|
|
||||||
Alternatively, symlinks named `gzip` or `gunzip` will mimic intended behavior.
|
|
||||||
`.gz` support is automatically enabled when `zlib` library is detected at build time.
|
|
||||||
It's possible to disable `.gz` support, by setting HAVE_ZLIB=0.
|
|
||||||
Example : make zstd HAVE_ZLIB=0
|
|
||||||
It's also possible to force compilation with zlib support, using HAVE_ZLIB=1.
|
|
||||||
In which case, linking stage will fail if `zlib` library cannot be found.
|
|
||||||
This might be useful to prevent silent feature disabling.
|
|
||||||
|
|
||||||
- __HAVE_LZMA__ : `zstd` can compress and decompress files in `.xz` and `.lzma` formats.
|
|
||||||
This is ordered through commands `--format=xz` and `--format=lzma` respectively.
|
|
||||||
Alternatively, symlinks named `xz`, `unxz`, `lzma`, or `unlzma` will mimic intended behavior.
|
|
||||||
`.xz` and `.lzma` support is automatically enabled when `lzma` library is detected at build time.
|
|
||||||
It's possible to disable `.xz` and `.lzma` support, by setting HAVE_LZMA=0 .
|
|
||||||
Example : make zstd HAVE_LZMA=0
|
|
||||||
It's also possible to force compilation with lzma support, using HAVE_LZMA=1.
|
|
||||||
In which case, linking stage will fail if `lzma` library cannot be found.
|
|
||||||
This might be useful to prevent silent feature disabling.
|
|
||||||
|
|
||||||
- __HAVE_LZ4__ : `zstd` can compress and decompress files in `.lz4` formats.
|
|
||||||
This is ordered through commands `--format=lz4`.
|
|
||||||
Alternatively, symlinks named `lz4`, or `unlz4` will mimic intended behavior.
|
|
||||||
`.lz4` support is automatically enabled when `lz4` library is detected at build time.
|
|
||||||
It's possible to disable `.lz4` support, by setting HAVE_LZ4=0 .
|
|
||||||
Example : make zstd HAVE_LZ4=0
|
|
||||||
It's also possible to force compilation with lz4 support, using HAVE_LZ4=1.
|
|
||||||
In which case, linking stage will fail if `lz4` library cannot be found.
|
|
||||||
This might be useful to prevent silent feature disabling.
|
|
||||||
|
|
||||||
- __ZSTD_LEGACY_SUPPORT__ : `zstd` can decompress files compressed by older versions of `zstd`.
|
- __ZSTD_LEGACY_SUPPORT__ : `zstd` can decompress files compressed by older versions of `zstd`.
|
||||||
Starting v0.8.0, all versions of `zstd` produce frames compliant with the [specification](../doc/zstd_compression_format.md), and are therefore compatible.
|
Starting v0.8.0, all versions of `zstd` produce frames compliant with the [specification](../doc/zstd_compression_format.md), and are therefore compatible.
|
||||||
@@ -61,11 +31,54 @@ There are however other Makefile targets that create different variations of CLI
|
|||||||
if `ZSTD_LEGACY_SUPPORT >= 8`, it's the same as `0`, since there is no legacy format after `7`.
|
if `ZSTD_LEGACY_SUPPORT >= 8`, it's the same as `0`, since there is no legacy format after `7`.
|
||||||
Note : `zstd` only supports decoding older formats, and cannot generate any legacy format.
|
Note : `zstd` only supports decoding older formats, and cannot generate any legacy format.
|
||||||
|
|
||||||
|
- __HAVE_ZLIB__ : `zstd` can compress and decompress files in `.gz` format.
|
||||||
|
This is ordered through command `--format=gzip`.
|
||||||
|
Alternatively, symlinks named `gzip` or `gunzip` will mimic intended behavior.
|
||||||
|
`.gz` support is automatically enabled when `zlib` library is detected at build time.
|
||||||
|
It's possible to disable `.gz` support, by setting `HAVE_ZLIB=0`.
|
||||||
|
Example : `make zstd HAVE_ZLIB=0`
|
||||||
|
It's also possible to force compilation with zlib support, `using HAVE_ZLIB=1`.
|
||||||
|
In which case, linking stage will fail if `zlib` library cannot be found.
|
||||||
|
This is useful to prevent silent feature disabling.
|
||||||
|
|
||||||
|
- __HAVE_LZMA__ : `zstd` can compress and decompress files in `.xz` and `.lzma` formats.
|
||||||
|
This is ordered through commands `--format=xz` and `--format=lzma` respectively.
|
||||||
|
Alternatively, symlinks named `xz`, `unxz`, `lzma`, or `unlzma` will mimic intended behavior.
|
||||||
|
`.xz` and `.lzma` support is automatically enabled when `lzma` library is detected at build time.
|
||||||
|
It's possible to disable `.xz` and `.lzma` support, by setting `HAVE_LZMA=0` .
|
||||||
|
Example : `make zstd HAVE_LZMA=0`
|
||||||
|
It's also possible to force compilation with lzma support, using `HAVE_LZMA=1`.
|
||||||
|
In which case, linking stage will fail if `lzma` library cannot be found.
|
||||||
|
This is useful to prevent silent feature disabling.
|
||||||
|
|
||||||
|
- __HAVE_LZ4__ : `zstd` can compress and decompress files in `.lz4` formats.
|
||||||
|
This is ordered through commands `--format=lz4`.
|
||||||
|
Alternatively, symlinks named `lz4`, or `unlz4` will mimic intended behavior.
|
||||||
|
`.lz4` support is automatically enabled when `lz4` library is detected at build time.
|
||||||
|
It's possible to disable `.lz4` support, by setting `HAVE_LZ4=0` .
|
||||||
|
Example : `make zstd HAVE_LZ4=0`
|
||||||
|
It's also possible to force compilation with lz4 support, using `HAVE_LZ4=1`.
|
||||||
|
In which case, linking stage will fail if `lz4` library cannot be found.
|
||||||
|
This is useful to prevent silent feature disabling.
|
||||||
|
|
||||||
|
|
||||||
#### Aggregation of parameters
|
#### Aggregation of parameters
|
||||||
CLI supports aggregation of parameters i.e. `-b1`, `-e18`, and `-i1` can be joined into `-b1e18i1`.
|
CLI supports aggregation of parameters i.e. `-b1`, `-e18`, and `-i1` can be joined into `-b1e18i1`.
|
||||||
|
|
||||||
|
|
||||||
|
#### Symlink shortcuts
|
||||||
|
It's possible to invoke `zstd` through a symlink.
|
||||||
|
When the name of the symlink has a specific value, it triggers an associated behavior.
|
||||||
|
- `zstdmt` : compress using all cores available on local system.
|
||||||
|
- `zcat` : will decompress and output target file using any of the supported formats. `gzcat` and `zstdcat` are also equivalent.
|
||||||
|
- `gzip` : if zlib support is enabled, will mimic `gzip` by compressing file using `.gz` format, removing source file by default (use `--keep` to preserve). If zlib is not supported, triggers an error.
|
||||||
|
- `xz` : if lzma support is enabled, will mimic `xz` by compressing file using `.xz` format, removing source file by default (use `--keep` to preserve). If xz is not supported, triggers an error.
|
||||||
|
- `lzma` : if lzma support is enabled, will mimic `lzma` by compressing file using `.lzma` format, removing source file by default (use `--keep` to preserve). If lzma is not supported, triggers an error.
|
||||||
|
- `lz4` : if lz4 support is enabled, will mimic `lz4` by compressing file using `.lz4` format. If lz4 is not supported, triggers an error.
|
||||||
|
- `unzstd` and `unlz4` will decompress any of the supported format.
|
||||||
|
- `ungz`, `unxz` and `unlzma` will do the same, and will also remove source file by default (use `--keep` to preserve).
|
||||||
|
|
||||||
|
|
||||||
#### Dictionary builder in Command Line Interface
|
#### Dictionary builder in Command Line Interface
|
||||||
Zstd offers a training mode, which can be used to tune the algorithm for a selected
|
Zstd offers a training mode, which can be used to tune the algorithm for a selected
|
||||||
type of data, by providing it with a few samples. The result of the training is stored
|
type of data, by providing it with a few samples. The result of the training is stored
|
||||||
@@ -144,7 +157,7 @@ Dictionary builder :
|
|||||||
--dictID=# : force dictionary ID to specified value (default: random)
|
--dictID=# : force dictionary ID to specified value (default: random)
|
||||||
|
|
||||||
Benchmark arguments :
|
Benchmark arguments :
|
||||||
-b# : benchmark file(s), using # compression level (default : 1)
|
-b# : benchmark file(s), using # compression level (default: 3)
|
||||||
-e# : test all compression levels from -bX to # (default: 1)
|
-e# : test all compression levels from -bX to # (default: 1)
|
||||||
-i# : minimum evaluation time in seconds (default: 3s)
|
-i# : minimum evaluation time in seconds (default: 3s)
|
||||||
-B# : cut file into independent blocks of size # (default: no block)
|
-B# : cut file into independent blocks of size # (default: no block)
|
||||||
@@ -202,8 +215,3 @@ The below table illustrates this on the [Silesia compression corpus].
|
|||||||
| `zstd -5 --long` | `3.319` | `51.7 MB/s` | `371.9 MB/s` |
|
| `zstd -5 --long` | `3.319` | `51.7 MB/s` | `371.9 MB/s` |
|
||||||
| `zstd -10` | `3.523` | `16.4 MB/s` | `489.2 MB/s` |
|
| `zstd -10` | `3.523` | `16.4 MB/s` | `489.2 MB/s` |
|
||||||
| `zstd -10 --long`| `3.566` | `16.2 MB/s` | `415.7 MB/s` |
|
| `zstd -10 --long`| `3.566` | `16.2 MB/s` | `415.7 MB/s` |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <stdlib.h> /* malloc, free */
|
#include <stdlib.h> /* malloc, free */
|
||||||
#include <string.h> /* memset */
|
#include <string.h> /* memset */
|
||||||
#include <stdio.h> /* fprintf, fopen */
|
#include <stdio.h> /* fprintf, fopen */
|
||||||
|
#include <assert.h> /* assert */
|
||||||
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#define ZSTD_STATIC_LINKING_ONLY
|
#define ZSTD_STATIC_LINKING_ONLY
|
||||||
@@ -51,8 +52,9 @@
|
|||||||
# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
|
# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TIMELOOP_MICROSEC 1*1000000ULL /* 1 second */
|
#define TIMELOOP_MICROSEC (1*1000000ULL) /* 1 second */
|
||||||
#define ACTIVEPERIOD_MICROSEC 70*1000000ULL /* 70 seconds */
|
#define TIMELOOP_NANOSEC (1*1000000000ULL) /* 1 second */
|
||||||
|
#define ACTIVEPERIOD_MICROSEC (70*TIMELOOP_MICROSEC) /* 70 seconds */
|
||||||
#define COOLPERIOD_SEC 10
|
#define COOLPERIOD_SEC 10
|
||||||
|
|
||||||
#define KB *(1 <<10)
|
#define KB *(1 <<10)
|
||||||
@@ -122,12 +124,12 @@ void BMK_setBlockSize(size_t blockSize)
|
|||||||
|
|
||||||
void BMK_setDecodeOnlyMode(unsigned decodeFlag) { g_decodeOnly = (decodeFlag>0); }
|
void BMK_setDecodeOnlyMode(unsigned decodeFlag) { g_decodeOnly = (decodeFlag>0); }
|
||||||
|
|
||||||
static U32 g_nbThreads = 1;
|
static U32 g_nbWorkers = 0;
|
||||||
void BMK_setNbThreads(unsigned nbThreads) {
|
void BMK_setNbWorkers(unsigned nbWorkers) {
|
||||||
#ifndef ZSTD_MULTITHREAD
|
#ifndef ZSTD_MULTITHREAD
|
||||||
if (nbThreads > 1) DISPLAYLEVEL(2, "Note : multi-threading is disabled \n");
|
if (nbWorkers > 0) DISPLAYLEVEL(2, "Note : multi-threading is disabled \n");
|
||||||
#endif
|
#endif
|
||||||
g_nbThreads = nbThreads;
|
g_nbWorkers = nbWorkers;
|
||||||
}
|
}
|
||||||
|
|
||||||
static U32 g_realTime = 0;
|
static U32 g_realTime = 0;
|
||||||
@@ -212,6 +214,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* display last 17 characters */
|
if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* display last 17 characters */
|
||||||
|
if (g_nbWorkers==1) g_nbWorkers=0; /* prefer synchronous mode */
|
||||||
|
|
||||||
if (g_decodeOnly) { /* benchmark only decompression : source must be already compressed */
|
if (g_decodeOnly) { /* benchmark only decompression : source must be already compressed */
|
||||||
const char* srcPtr = (const char*)srcBuffer;
|
const char* srcPtr = (const char*)srcBuffer;
|
||||||
@@ -258,13 +261,19 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
} } }
|
} } }
|
||||||
|
|
||||||
/* warmimg up memory */
|
/* warmimg up memory */
|
||||||
|
if (g_decodeOnly) {
|
||||||
|
memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
|
||||||
|
} else {
|
||||||
RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
|
RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Bench */
|
/* Bench */
|
||||||
{ U64 fastestC = (U64)(-1LL), fastestD = (U64)(-1LL);
|
{ U64 fastestC = (U64)(-1LL), fastestD = (U64)(-1LL);
|
||||||
U64 const crcOrig = g_decodeOnly ? 0 : XXH64(srcBuffer, srcSize, 0);
|
U64 const crcOrig = g_decodeOnly ? 0 : XXH64(srcBuffer, srcSize, 0);
|
||||||
UTIL_time_t coolTime;
|
UTIL_time_t coolTime;
|
||||||
U64 const maxTime = (g_nbSeconds * TIMELOOP_MICROSEC) + 1;
|
U64 const maxTime = (g_nbSeconds * TIMELOOP_NANOSEC) + 1;
|
||||||
|
U32 nbDecodeLoops = (U32)((100 MB) / (srcSize+1)) + 1; /* initial conservative speed estimate */
|
||||||
|
U32 nbCompressionLoops = (U32)((2 MB) / (srcSize+1)) + 1; /* initial conservative speed estimate */
|
||||||
U64 totalCTime=0, totalDTime=0;
|
U64 totalCTime=0, totalDTime=0;
|
||||||
U32 cCompleted=g_decodeOnly, dCompleted=0;
|
U32 cCompleted=g_decodeOnly, dCompleted=0;
|
||||||
# define NB_MARKS 4
|
# define NB_MARKS 4
|
||||||
@@ -283,19 +292,17 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!g_decodeOnly) {
|
if (!g_decodeOnly) {
|
||||||
UTIL_time_t clockStart;
|
|
||||||
/* Compression */
|
/* Compression */
|
||||||
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->\r", marks[markNb], displayName, (U32)srcSize);
|
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->\r", marks[markNb], displayName, (U32)srcSize);
|
||||||
if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */
|
if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */
|
||||||
|
|
||||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
UTIL_sleepMilli(5); /* give processor time to other processes */
|
||||||
UTIL_waitForNextTick();
|
UTIL_waitForNextTick();
|
||||||
clockStart = UTIL_getTime();
|
|
||||||
|
|
||||||
if (!cCompleted) { /* still some time to do compression tests */
|
if (!cCompleted) { /* still some time to do compression tests */
|
||||||
U64 const clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1;
|
|
||||||
U32 nbLoops = 0;
|
U32 nbLoops = 0;
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbThreads, g_nbThreads);
|
UTIL_time_t const clockStart = UTIL_getTime();
|
||||||
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbWorkers, g_nbWorkers);
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag);
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag);
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch);
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch);
|
||||||
@@ -307,13 +314,16 @@ 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_ldmHashEveryLog, g_ldmHashEveryLog);
|
||||||
}
|
}
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_windowLog, comprParams->windowLog);
|
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_chainLog, comprParams->chainLog);
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog);
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog);
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_minMatch, comprParams->searchLength);
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_minMatch, comprParams->searchLength);
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_targetLength, comprParams->targetLength);
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_targetLength, comprParams->targetLength);
|
||||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionStrategy, comprParams->strategy);
|
ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionStrategy, comprParams->strategy);
|
||||||
ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize);
|
ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize);
|
||||||
do {
|
|
||||||
|
if (!g_nbSeconds) nbCompressionLoops=1;
|
||||||
|
for (nbLoops=0; nbLoops<nbCompressionLoops; nbLoops++) {
|
||||||
U32 blockNb;
|
U32 blockNb;
|
||||||
for (blockNb=0; blockNb<nbBlocks; blockNb++) {
|
for (blockNb=0; blockNb<nbBlocks; blockNb++) {
|
||||||
#if 0 /* direct compression function, for occasional comparison */
|
#if 0 /* direct compression function, for occasional comparison */
|
||||||
@@ -342,12 +352,16 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
}
|
}
|
||||||
blockTable[blockNb].cSize = out.pos;
|
blockTable[blockNb].cSize = out.pos;
|
||||||
#endif
|
#endif
|
||||||
|
} }
|
||||||
|
{ U64 const loopDuration = UTIL_clockSpanNano(clockStart);
|
||||||
|
if (loopDuration > 0) {
|
||||||
|
if (loopDuration < fastestC * nbCompressionLoops)
|
||||||
|
fastestC = loopDuration / nbCompressionLoops;
|
||||||
|
nbCompressionLoops = (U32)(TIMELOOP_NANOSEC / fastestC) + 1;
|
||||||
|
} else {
|
||||||
|
assert(nbCompressionLoops < 40000000); /* avoid overflow */
|
||||||
|
nbCompressionLoops *= 100;
|
||||||
}
|
}
|
||||||
nbLoops++;
|
|
||||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
|
||||||
{ U64 const loopDuration = UTIL_clockSpanMicro(clockStart);
|
|
||||||
if (loopDuration < fastestC*nbLoops)
|
|
||||||
fastestC = loopDuration / nbLoops;
|
|
||||||
totalCTime += loopDuration;
|
totalCTime += loopDuration;
|
||||||
cCompleted = (totalCTime >= maxTime); /* end compression tests */
|
cCompleted = (totalCTime >= maxTime); /* end compression tests */
|
||||||
} }
|
} }
|
||||||
@@ -357,16 +371,14 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
ratio = (double)srcSize / (double)cSize;
|
ratio = (double)srcSize / (double)cSize;
|
||||||
markNb = (markNb+1) % NB_MARKS;
|
markNb = (markNb+1) % NB_MARKS;
|
||||||
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
||||||
double const compressionSpeed = (double)srcSize / fastestC;
|
double const compressionSpeed = ((double)srcSize / fastestC) * 1000;
|
||||||
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1;
|
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1;
|
||||||
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
|
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
|
||||||
marks[markNb], displayName, (U32)srcSize, (U32)cSize,
|
marks[markNb], displayName, (U32)srcSize, (U32)cSize,
|
||||||
ratioAccuracy, ratio,
|
ratioAccuracy, ratio,
|
||||||
cSpeedAccuracy, compressionSpeed );
|
cSpeedAccuracy, compressionSpeed );
|
||||||
}
|
}
|
||||||
} else { /* g_decodeOnly */
|
} /* if (!g_decodeOnly) */
|
||||||
memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 /* disable decompression test */
|
#if 0 /* disable decompression test */
|
||||||
dCompleted=1;
|
dCompleted=1;
|
||||||
@@ -375,16 +387,16 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
/* Decompression */
|
/* Decompression */
|
||||||
if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */
|
if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */
|
||||||
|
|
||||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
UTIL_sleepMilli(5); /* give processor time to other processes */
|
||||||
UTIL_waitForNextTick();
|
UTIL_waitForNextTick();
|
||||||
|
|
||||||
if (!dCompleted) {
|
if (!dCompleted) {
|
||||||
U64 clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1;
|
|
||||||
U32 nbLoops = 0;
|
U32 nbLoops = 0;
|
||||||
ZSTD_DDict* const ddict = ZSTD_createDDict(dictBuffer, dictBufferSize);
|
ZSTD_DDict* const ddict = ZSTD_createDDict(dictBuffer, dictBufferSize);
|
||||||
UTIL_time_t const clockStart = UTIL_getTime();
|
UTIL_time_t const clockStart = UTIL_getTime();
|
||||||
if (!ddict) EXM_THROW(2, "ZSTD_createDDict() allocation failure");
|
if (!ddict) EXM_THROW(2, "ZSTD_createDDict() allocation failure");
|
||||||
do {
|
if (!g_nbSeconds) nbDecodeLoops = 1;
|
||||||
|
for (nbLoops=0; nbLoops < nbDecodeLoops; nbLoops++) {
|
||||||
U32 blockNb;
|
U32 blockNb;
|
||||||
for (blockNb=0; blockNb<nbBlocks; blockNb++) {
|
for (blockNb=0; blockNb<nbBlocks; blockNb++) {
|
||||||
size_t const regenSize = ZSTD_decompress_usingDDict(dctx,
|
size_t const regenSize = ZSTD_decompress_usingDDict(dctx,
|
||||||
@@ -396,22 +408,26 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
blockNb, (U32)blockTable[blockNb].cSize, ZSTD_getErrorName(regenSize));
|
blockNb, (U32)blockTable[blockNb].cSize, ZSTD_getErrorName(regenSize));
|
||||||
}
|
}
|
||||||
blockTable[blockNb].resSize = regenSize;
|
blockTable[blockNb].resSize = regenSize;
|
||||||
}
|
} }
|
||||||
nbLoops++;
|
|
||||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
|
||||||
ZSTD_freeDDict(ddict);
|
ZSTD_freeDDict(ddict);
|
||||||
{ U64 const loopDuration = UTIL_clockSpanMicro(clockStart);
|
{ U64 const loopDuration = UTIL_clockSpanNano(clockStart);
|
||||||
if (loopDuration < fastestD*nbLoops)
|
if (loopDuration > 0) {
|
||||||
fastestD = loopDuration / nbLoops;
|
if (loopDuration < fastestD * nbDecodeLoops)
|
||||||
|
fastestD = loopDuration / nbDecodeLoops;
|
||||||
|
nbDecodeLoops = (U32)(TIMELOOP_NANOSEC / fastestD) + 1;
|
||||||
|
} else {
|
||||||
|
assert(nbDecodeLoops < 40000000); /* avoid overflow */
|
||||||
|
nbDecodeLoops *= 100;
|
||||||
|
}
|
||||||
totalDTime += loopDuration;
|
totalDTime += loopDuration;
|
||||||
dCompleted = (totalDTime >= maxTime);
|
dCompleted = (totalDTime >= maxTime);
|
||||||
} }
|
} }
|
||||||
|
|
||||||
markNb = (markNb+1) % NB_MARKS;
|
markNb = (markNb+1) % NB_MARKS;
|
||||||
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
||||||
double const compressionSpeed = (double)srcSize / fastestC;
|
double const compressionSpeed = ((double)srcSize / fastestC) * 1000;
|
||||||
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1;
|
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1;
|
||||||
double const decompressionSpeed = (double)srcSize / fastestD;
|
double const decompressionSpeed = ((double)srcSize / fastestD) * 1000;
|
||||||
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
|
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
|
||||||
marks[markNb], displayName, (U32)srcSize, (U32)cSize,
|
marks[markNb], displayName, (U32)srcSize, (U32)cSize,
|
||||||
ratioAccuracy, ratio,
|
ratioAccuracy, ratio,
|
||||||
@@ -460,8 +476,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
|||||||
} /* for (testNb = 1; testNb <= (g_nbSeconds + !g_nbSeconds); testNb++) */
|
} /* for (testNb = 1; testNb <= (g_nbSeconds + !g_nbSeconds); testNb++) */
|
||||||
|
|
||||||
if (g_displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
|
if (g_displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
|
||||||
double cSpeed = (double)srcSize / fastestC;
|
double const cSpeed = ((double)srcSize / fastestC) * 1000;
|
||||||
double dSpeed = (double)srcSize / fastestD;
|
double const dSpeed = ((double)srcSize / fastestD) * 1000;
|
||||||
if (g_additionalParam)
|
if (g_additionalParam)
|
||||||
DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, g_additionalParam);
|
DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, g_additionalParam);
|
||||||
else
|
else
|
||||||
@@ -518,9 +534,8 @@ static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
|
|||||||
if (g_displayLevel == 1 && !g_additionalParam)
|
if (g_displayLevel == 1 && !g_additionalParam)
|
||||||
DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n", ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, (U32)benchedSize, g_nbSeconds, (U32)(g_blockSize>>10));
|
DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n", ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, (U32)benchedSize, g_nbSeconds, (U32)(g_blockSize>>10));
|
||||||
|
|
||||||
if (cLevelLast < cLevel) cLevelLast = cLevel;
|
|
||||||
|
|
||||||
for (l=cLevel; l <= cLevelLast; l++) {
|
for (l=cLevel; l <= cLevelLast; l++) {
|
||||||
|
if (l==0) continue; /* skip level 0 */
|
||||||
BMK_benchMem(srcBuffer, benchedSize,
|
BMK_benchMem(srcBuffer, benchedSize,
|
||||||
displayName, l,
|
displayName, l,
|
||||||
fileSizes, nbFiles,
|
fileSizes, nbFiles,
|
||||||
@@ -530,8 +545,8 @@ static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
|
|||||||
|
|
||||||
|
|
||||||
/*! BMK_loadFiles() :
|
/*! BMK_loadFiles() :
|
||||||
Loads `buffer` with content of files listed within `fileNamesTable`.
|
* Loads `buffer` with content of files listed within `fileNamesTable`.
|
||||||
At most, fills `buffer` entirely */
|
* At most, fills `buffer` entirely. */
|
||||||
static void BMK_loadFiles(void* buffer, size_t bufferSize,
|
static void BMK_loadFiles(void* buffer, size_t bufferSize,
|
||||||
size_t* fileSizes,
|
size_t* fileSizes,
|
||||||
const char* const * const fileNamesTable, unsigned nbFiles)
|
const char* const * const fileNamesTable, unsigned nbFiles)
|
||||||
@@ -633,7 +648,8 @@ static void BMK_benchFileTable(const char* const * const fileNamesTable, unsigne
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility, const ZSTD_compressionParameters* compressionParams)
|
static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility,
|
||||||
|
const ZSTD_compressionParameters* compressionParams)
|
||||||
{
|
{
|
||||||
char name[20] = {0};
|
char name[20] = {0};
|
||||||
size_t benchedSize = 10000000;
|
size_t benchedSize = 10000000;
|
||||||
@@ -661,7 +677,6 @@ int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,
|
|||||||
{
|
{
|
||||||
double const compressibility = (double)g_compressibilityDefault / 100;
|
double const compressibility = (double)g_compressibilityDefault / 100;
|
||||||
|
|
||||||
if (cLevel < 1) cLevel = 1; /* minimum compression level */
|
|
||||||
if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
|
if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
|
||||||
if (cLevelLast > ZSTD_maxCLevel()) cLevelLast = ZSTD_maxCLevel();
|
if (cLevelLast > ZSTD_maxCLevel()) cLevelLast = ZSTD_maxCLevel();
|
||||||
if (cLevelLast < cLevel) cLevelLast = cLevel;
|
if (cLevelLast < cLevel) cLevelLast = cLevel;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, const char* di
|
|||||||
/* Set Parameters */
|
/* Set Parameters */
|
||||||
void BMK_setNbSeconds(unsigned nbLoops);
|
void BMK_setNbSeconds(unsigned nbLoops);
|
||||||
void BMK_setBlockSize(size_t blockSize);
|
void BMK_setBlockSize(size_t blockSize);
|
||||||
void BMK_setNbThreads(unsigned nbThreads);
|
void BMK_setNbWorkers(unsigned nbWorkers);
|
||||||
void BMK_setRealTime(unsigned priority);
|
void BMK_setRealTime(unsigned priority);
|
||||||
void BMK_setNotificationLevel(unsigned level);
|
void BMK_setNotificationLevel(unsigned level);
|
||||||
void BMK_setSeparateFiles(unsigned separate);
|
void BMK_setSeparateFiles(unsigned separate);
|
||||||
|
|||||||
@@ -36,18 +36,21 @@
|
|||||||
# include <io.h>
|
# include <io.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "bitstream.h"
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
|
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
|
||||||
#include "zstd.h"
|
#include "zstd.h"
|
||||||
|
#include "zstd_errors.h" /* ZSTD_error_frameParameter_windowTooLarge */
|
||||||
|
|
||||||
#if defined(ZSTD_GZCOMPRESS) || defined(ZSTD_GZDECOMPRESS)
|
#if defined(ZSTD_GZCOMPRESS) || defined(ZSTD_GZDECOMPRESS)
|
||||||
# include <zlib.h>
|
# include <zlib.h>
|
||||||
# if !defined(z_const)
|
# if !defined(z_const)
|
||||||
# define z_const
|
# define z_const
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ZSTD_LZMACOMPRESS) || defined(ZSTD_LZMADECOMPRESS)
|
#if defined(ZSTD_LZMACOMPRESS) || defined(ZSTD_LZMADECOMPRESS)
|
||||||
# include <lzma.h>
|
# include <lzma.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -84,10 +87,15 @@ void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; }
|
|||||||
static const U64 g_refreshRate = SEC_TO_MICRO / 6;
|
static const U64 g_refreshRate = SEC_TO_MICRO / 6;
|
||||||
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
|
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
|
||||||
|
|
||||||
#define DISPLAYUPDATE(l, ...) { if (g_displayLevel>=l) { \
|
#define READY_FOR_UPDATE() (UTIL_clockSpanMicro(g_displayClock) > g_refreshRate)
|
||||||
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
|
#define DELAY_NEXT_UPDATE() { g_displayClock = UTIL_getTime(); }
|
||||||
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
|
#define DISPLAYUPDATE(l, ...) { \
|
||||||
if (g_displayLevel>=4) fflush(stderr); } } }
|
if (g_displayLevel>=l) { \
|
||||||
|
if (READY_FOR_UPDATE() || (g_displayLevel>=4)) { \
|
||||||
|
DELAY_NEXT_UPDATE(); \
|
||||||
|
DISPLAY(__VA_ARGS__); \
|
||||||
|
if (g_displayLevel>=4) fflush(stderr); \
|
||||||
|
} } }
|
||||||
|
|
||||||
#undef MIN /* in case it would be already defined */
|
#undef MIN /* in case it would be already defined */
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
@@ -139,7 +147,10 @@ static void INThandler(int sig)
|
|||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio */
|
signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio */
|
||||||
#endif
|
#endif
|
||||||
if (g_artefact) remove(g_artefact);
|
if (g_artefact) {
|
||||||
|
assert(UTIL_isRegularFile(g_artefact));
|
||||||
|
remove(g_artefact);
|
||||||
|
}
|
||||||
DISPLAY("\n");
|
DISPLAY("\n");
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
@@ -209,23 +220,23 @@ static U32 g_removeSrcFile = 0;
|
|||||||
void FIO_setRemoveSrcFile(unsigned flag) { g_removeSrcFile = (flag>0); }
|
void FIO_setRemoveSrcFile(unsigned flag) { g_removeSrcFile = (flag>0); }
|
||||||
static U32 g_memLimit = 0;
|
static U32 g_memLimit = 0;
|
||||||
void FIO_setMemLimit(unsigned memLimit) { g_memLimit = memLimit; }
|
void FIO_setMemLimit(unsigned memLimit) { g_memLimit = memLimit; }
|
||||||
static U32 g_nbThreads = 1;
|
static U32 g_nbWorkers = 1;
|
||||||
void FIO_setNbThreads(unsigned nbThreads) {
|
void FIO_setNbWorkers(unsigned nbWorkers) {
|
||||||
#ifndef ZSTD_MULTITHREAD
|
#ifndef ZSTD_MULTITHREAD
|
||||||
if (nbThreads > 1) DISPLAYLEVEL(2, "Note : multi-threading is disabled \n");
|
if (nbWorkers > 0) DISPLAYLEVEL(2, "Note : multi-threading is disabled \n");
|
||||||
#endif
|
#endif
|
||||||
g_nbThreads = nbThreads;
|
g_nbWorkers = nbWorkers;
|
||||||
}
|
}
|
||||||
static U32 g_blockSize = 0;
|
static U32 g_blockSize = 0;
|
||||||
void FIO_setBlockSize(unsigned blockSize) {
|
void FIO_setBlockSize(unsigned blockSize) {
|
||||||
if (blockSize && g_nbThreads==1)
|
if (blockSize && g_nbWorkers==0)
|
||||||
DISPLAYLEVEL(2, "Setting block size is useless in single-thread mode \n");
|
DISPLAYLEVEL(2, "Setting block size is useless in single-thread mode \n");
|
||||||
g_blockSize = blockSize;
|
g_blockSize = blockSize;
|
||||||
}
|
}
|
||||||
#define FIO_OVERLAP_LOG_NOTSET 9999
|
#define FIO_OVERLAP_LOG_NOTSET 9999
|
||||||
static U32 g_overlapLog = FIO_OVERLAP_LOG_NOTSET;
|
static U32 g_overlapLog = FIO_OVERLAP_LOG_NOTSET;
|
||||||
void FIO_setOverlapLog(unsigned overlapLog){
|
void FIO_setOverlapLog(unsigned overlapLog){
|
||||||
if (overlapLog && g_nbThreads==1)
|
if (overlapLog && g_nbWorkers==0)
|
||||||
DISPLAYLEVEL(2, "Setting overlapLog is useless in single-thread mode \n");
|
DISPLAYLEVEL(2, "Setting overlapLog is useless in single-thread mode \n");
|
||||||
g_overlapLog = overlapLog;
|
g_overlapLog = overlapLog;
|
||||||
}
|
}
|
||||||
@@ -392,7 +403,7 @@ static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName)
|
|||||||
|
|
||||||
#ifndef ZSTD_NOCOMPRESS
|
#ifndef ZSTD_NOCOMPRESS
|
||||||
|
|
||||||
/*-**********************************************************************
|
/* **********************************************************************
|
||||||
* Compression
|
* Compression
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -411,6 +422,7 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
|||||||
cRess_t ress;
|
cRess_t ress;
|
||||||
memset(&ress, 0, sizeof(ress));
|
memset(&ress, 0, sizeof(ress));
|
||||||
|
|
||||||
|
DISPLAYLEVEL(6, "FIO_createCResources \n");
|
||||||
ress.cctx = ZSTD_createCCtx();
|
ress.cctx = ZSTD_createCCtx();
|
||||||
if (ress.cctx == NULL)
|
if (ress.cctx == NULL)
|
||||||
EXM_THROW(30, "allocation error : can't create ZSTD_CCtx");
|
EXM_THROW(30, "allocation error : can't create ZSTD_CCtx");
|
||||||
@@ -421,7 +433,7 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
|||||||
if (!ress.srcBuffer || !ress.dstBuffer)
|
if (!ress.srcBuffer || !ress.dstBuffer)
|
||||||
EXM_THROW(31, "allocation error : not enough memory");
|
EXM_THROW(31, "allocation error : not enough memory");
|
||||||
|
|
||||||
/* Advances parameters, including dictionary */
|
/* Advanced parameters, including dictionary */
|
||||||
{ void* dictBuffer;
|
{ void* dictBuffer;
|
||||||
size_t const dictBuffSize = FIO_createDictBuffer(&dictBuffer, dictFileName); /* works with dictFileName==NULL */
|
size_t const dictBuffSize = FIO_createDictBuffer(&dictBuffer, dictFileName); /* works with dictFileName==NULL */
|
||||||
if (dictFileName && (dictBuffer==NULL))
|
if (dictFileName && (dictBuffer==NULL))
|
||||||
@@ -431,10 +443,9 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
|||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) );
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) );
|
||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) );
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) );
|
||||||
/* compression level */
|
/* compression level */
|
||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, (unsigned)cLevel) );
|
||||||
/* long distance matching */
|
/* long distance matching */
|
||||||
CHECK( ZSTD_CCtx_setParameter(
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag) );
|
||||||
ress.cctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag) );
|
|
||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashLog, g_ldmHashLog) );
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashLog, g_ldmHashLog) );
|
||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch) );
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch) );
|
||||||
if (g_ldmBucketSizeLog != FIO_LDM_PARAM_NOTSET) {
|
if (g_ldmBucketSizeLog != FIO_LDM_PARAM_NOTSET) {
|
||||||
@@ -452,10 +463,12 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
|||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) );
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) );
|
||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) );
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) );
|
||||||
/* multi-threading */
|
/* multi-threading */
|
||||||
DISPLAYLEVEL(5,"set nb threads = %u \n", g_nbThreads);
|
#ifdef ZSTD_MULTITHREAD
|
||||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) );
|
DISPLAYLEVEL(5,"set nb workers = %u \n", g_nbWorkers);
|
||||||
|
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbWorkers, g_nbWorkers) );
|
||||||
|
#endif
|
||||||
/* dictionary */
|
/* dictionary */
|
||||||
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) ); /* just for dictionary loading, for compression parameters adaptation */
|
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) ); /* set the value temporarily for dictionary loading, to adapt compression parameters */
|
||||||
CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) );
|
CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) );
|
||||||
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, ZSTD_CONTENTSIZE_UNKNOWN) ); /* reset */
|
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, ZSTD_CONTENTSIZE_UNKNOWN) ); /* reset */
|
||||||
|
|
||||||
@@ -726,19 +739,93 @@ static unsigned long long FIO_compressLz4Frame(cRess_t* ress,
|
|||||||
* @return : 0 : compression completed correctly,
|
* @return : 0 : compression completed correctly,
|
||||||
* 1 : missing or pb opening srcFileName
|
* 1 : missing or pb opening srcFileName
|
||||||
*/
|
*/
|
||||||
static int FIO_compressFilename_internal(cRess_t ress,
|
static unsigned long long
|
||||||
const char* dstFileName, const char* srcFileName, int compressionLevel)
|
FIO_compressZstdFrame(const cRess_t* ressPtr,
|
||||||
|
const char* srcFileName, U64 fileSize,
|
||||||
|
int compressionLevel, U64* readsize)
|
||||||
{
|
{
|
||||||
|
cRess_t const ress = *ressPtr;
|
||||||
FILE* const srcFile = ress.srcFile;
|
FILE* const srcFile = ress.srcFile;
|
||||||
FILE* const dstFile = ress.dstFile;
|
FILE* const dstFile = ress.dstFile;
|
||||||
|
U64 compressedfilesize = 0;
|
||||||
|
ZSTD_EndDirective directive = ZSTD_e_continue;
|
||||||
|
DISPLAYLEVEL(6, "compression using zstd format \n");
|
||||||
|
|
||||||
|
/* init */
|
||||||
|
if (fileSize != UTIL_FILESIZE_UNKNOWN)
|
||||||
|
ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize);
|
||||||
|
(void)compressionLevel; (void)srcFileName;
|
||||||
|
|
||||||
|
/* Main compression loop */
|
||||||
|
do {
|
||||||
|
size_t result;
|
||||||
|
/* Fill input Buffer */
|
||||||
|
size_t const inSize = fread(ress.srcBuffer, (size_t)1, ress.srcBufferSize, srcFile);
|
||||||
|
ZSTD_inBuffer inBuff = { ress.srcBuffer, inSize, 0 };
|
||||||
|
DISPLAYLEVEL(6, "fread %u bytes from source \n", (U32)inSize);
|
||||||
|
*readsize += inSize;
|
||||||
|
|
||||||
|
if ((inSize == 0) || (*readsize == fileSize))
|
||||||
|
directive = ZSTD_e_end;
|
||||||
|
|
||||||
|
result = 1;
|
||||||
|
while (inBuff.pos != inBuff.size || (directive == ZSTD_e_end && result != 0)) {
|
||||||
|
ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 };
|
||||||
|
CHECK_V(result, ZSTD_compress_generic(ress.cctx, &outBuff, &inBuff, directive));
|
||||||
|
|
||||||
|
/* Write compressed stream */
|
||||||
|
DISPLAYLEVEL(6, "ZSTD_compress_generic(end:%u) => intput pos(%u)<=(%u)size ; output generated %u bytes \n",
|
||||||
|
(U32)directive, (U32)inBuff.pos, (U32)inBuff.size, (U32)outBuff.pos);
|
||||||
|
if (outBuff.pos) {
|
||||||
|
size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile);
|
||||||
|
if (sizeCheck!=outBuff.pos)
|
||||||
|
EXM_THROW(25, "Write error : cannot write compressed block");
|
||||||
|
compressedfilesize += outBuff.pos;
|
||||||
|
}
|
||||||
|
if (READY_FOR_UPDATE()) {
|
||||||
|
ZSTD_frameProgression const zfp = ZSTD_getFrameProgression(ress.cctx);
|
||||||
|
double const cShare = (double)zfp.produced / (zfp.consumed + !zfp.consumed/*avoid div0*/) * 100;
|
||||||
|
if (g_displayLevel >= 3) {
|
||||||
|
DISPLAYUPDATE(3, "\r(L%i) Buffered :%4u MB - Consumed :%4u MB - Compressed :%4u MB => %.2f%%",
|
||||||
|
compressionLevel,
|
||||||
|
(U32)((zfp.ingested - zfp.consumed) >> 20),
|
||||||
|
(U32)(zfp.consumed >> 20),
|
||||||
|
(U32)(zfp.produced >> 20),
|
||||||
|
cShare );
|
||||||
|
} else { /* g_displayLevel == 2 */
|
||||||
|
DISPLAYLEVEL(2, "\rRead : %u ", (U32)(zfp.consumed >> 20));
|
||||||
|
if (fileSize != UTIL_FILESIZE_UNKNOWN)
|
||||||
|
DISPLAYLEVEL(2, "/ %u ", (U32)(fileSize >> 20));
|
||||||
|
DISPLAYLEVEL(2, "MB ==> %2.f%% ", cShare);
|
||||||
|
DELAY_NEXT_UPDATE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (directive != ZSTD_e_end);
|
||||||
|
|
||||||
|
return compressedfilesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! FIO_compressFilename_internal() :
|
||||||
|
* same as FIO_compressFilename_extRess(), with `ress.desFile` already opened.
|
||||||
|
* @return : 0 : compression completed correctly,
|
||||||
|
* 1 : missing or pb opening srcFileName
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
FIO_compressFilename_internal(cRess_t ress,
|
||||||
|
const char* dstFileName, const char* srcFileName,
|
||||||
|
int compressionLevel)
|
||||||
|
{
|
||||||
U64 readsize = 0;
|
U64 readsize = 0;
|
||||||
U64 compressedfilesize = 0;
|
U64 compressedfilesize = 0;
|
||||||
U64 const fileSize = UTIL_getFileSize(srcFileName);
|
U64 const fileSize = UTIL_getFileSize(srcFileName);
|
||||||
ZSTD_EndDirective directive = ZSTD_e_continue;
|
|
||||||
DISPLAYLEVEL(5, "%s: %u bytes \n", srcFileName, (U32)fileSize);
|
DISPLAYLEVEL(5, "%s: %u bytes \n", srcFileName, (U32)fileSize);
|
||||||
|
|
||||||
|
/* compression format selection */
|
||||||
switch (g_compressionType) {
|
switch (g_compressionType) {
|
||||||
|
default:
|
||||||
case FIO_zstdCompression:
|
case FIO_zstdCompression:
|
||||||
|
compressedfilesize = FIO_compressZstdFrame(&ress, srcFileName, fileSize, compressionLevel, &readsize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FIO_gzipCompression:
|
case FIO_gzipCompression:
|
||||||
@@ -749,7 +836,7 @@ static int FIO_compressFilename_internal(cRess_t ress,
|
|||||||
EXM_THROW(20, "zstd: %s: file cannot be compressed as gzip (zstd compiled without ZSTD_GZCOMPRESS) -- ignored \n",
|
EXM_THROW(20, "zstd: %s: file cannot be compressed as gzip (zstd compiled without ZSTD_GZCOMPRESS) -- ignored \n",
|
||||||
srcFileName);
|
srcFileName);
|
||||||
#endif
|
#endif
|
||||||
goto finish;
|
break;
|
||||||
|
|
||||||
case FIO_xzCompression:
|
case FIO_xzCompression:
|
||||||
case FIO_lzmaCompression:
|
case FIO_lzmaCompression:
|
||||||
@@ -760,7 +847,7 @@ static int FIO_compressFilename_internal(cRess_t ress,
|
|||||||
EXM_THROW(20, "zstd: %s: file cannot be compressed as xz/lzma (zstd compiled without ZSTD_LZMACOMPRESS) -- ignored \n",
|
EXM_THROW(20, "zstd: %s: file cannot be compressed as xz/lzma (zstd compiled without ZSTD_LZMACOMPRESS) -- ignored \n",
|
||||||
srcFileName);
|
srcFileName);
|
||||||
#endif
|
#endif
|
||||||
goto finish;
|
break;
|
||||||
|
|
||||||
case FIO_lz4Compression:
|
case FIO_lz4Compression:
|
||||||
#ifdef ZSTD_LZ4COMPRESS
|
#ifdef ZSTD_LZ4COMPRESS
|
||||||
@@ -770,61 +857,13 @@ static int FIO_compressFilename_internal(cRess_t ress,
|
|||||||
EXM_THROW(20, "zstd: %s: file cannot be compressed as lz4 (zstd compiled without ZSTD_LZ4COMPRESS) -- ignored \n",
|
EXM_THROW(20, "zstd: %s: file cannot be compressed as lz4 (zstd compiled without ZSTD_LZ4COMPRESS) -- ignored \n",
|
||||||
srcFileName);
|
srcFileName);
|
||||||
#endif
|
#endif
|
||||||
goto finish;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* init */
|
|
||||||
if (fileSize != UTIL_FILESIZE_UNKNOWN)
|
|
||||||
ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize);
|
|
||||||
|
|
||||||
/* Main compression loop */
|
|
||||||
do {
|
|
||||||
size_t result;
|
|
||||||
/* Fill input Buffer */
|
|
||||||
size_t const inSize = fread(ress.srcBuffer, (size_t)1, ress.srcBufferSize, srcFile);
|
|
||||||
ZSTD_inBuffer inBuff = { ress.srcBuffer, inSize, 0 };
|
|
||||||
readsize += inSize;
|
|
||||||
|
|
||||||
if (inSize == 0 || (fileSize != UTIL_FILESIZE_UNKNOWN && readsize == fileSize))
|
|
||||||
directive = ZSTD_e_end;
|
|
||||||
|
|
||||||
result = 1;
|
|
||||||
while (inBuff.pos != inBuff.size || (directive == ZSTD_e_end && result != 0)) {
|
|
||||||
ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 };
|
|
||||||
CHECK_V(result, ZSTD_compress_generic(ress.cctx, &outBuff, &inBuff, directive));
|
|
||||||
|
|
||||||
/* Write compressed stream */
|
|
||||||
DISPLAYLEVEL(6, "ZSTD_compress_generic,ZSTD_e_continue: generated %u bytes \n",
|
|
||||||
(U32)outBuff.pos);
|
|
||||||
if (outBuff.pos) {
|
|
||||||
size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile);
|
|
||||||
if (sizeCheck!=outBuff.pos)
|
|
||||||
EXM_THROW(25, "Write error : cannot write compressed block into %s", dstFileName);
|
|
||||||
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));
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
} while (directive != ZSTD_e_end);
|
|
||||||
|
|
||||||
finish:
|
|
||||||
/* Status */
|
/* Status */
|
||||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||||
DISPLAYLEVEL(2,"%-20s :%6.2f%% (%6llu => %6llu bytes, %s) \n", srcFileName,
|
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,
|
(unsigned long long)readsize, (unsigned long long) compressedfilesize,
|
||||||
dstFileName);
|
dstFileName);
|
||||||
@@ -861,7 +900,7 @@ static int FIO_compressFilename_srcFile(cRess_t ress,
|
|||||||
* delete both the source and destination files.
|
* delete both the source and destination files.
|
||||||
*/
|
*/
|
||||||
clearHandler();
|
clearHandler();
|
||||||
if (remove(srcFileName))
|
if (FIO_remove(srcFileName))
|
||||||
EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno));
|
EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -881,6 +920,7 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
|
|||||||
stat_t statbuf;
|
stat_t statbuf;
|
||||||
int stat_result = 0;
|
int stat_result = 0;
|
||||||
|
|
||||||
|
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s", dstFileName);
|
||||||
ress.dstFile = FIO_openDstFile(dstFileName);
|
ress.dstFile = FIO_openDstFile(dstFileName);
|
||||||
if (ress.dstFile==NULL) return 1; /* could not open dstFileName */
|
if (ress.dstFile==NULL) return 1; /* could not open dstFileName */
|
||||||
/* Must ony be added after FIO_openDstFile() succeeds.
|
/* Must ony be added after FIO_openDstFile() succeeds.
|
||||||
@@ -898,11 +938,13 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
|
|||||||
DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno));
|
DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno));
|
||||||
result=1;
|
result=1;
|
||||||
}
|
}
|
||||||
if (result!=0) { /* remove operation artefact */
|
if ( (result != 0) /* operation failure */
|
||||||
if (remove(dstFileName))
|
&& strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null */
|
||||||
EXM_THROW(1, "zstd: %s: %s", dstFileName, strerror(errno));
|
&& 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) && stat_result)
|
else if ( strcmp(dstFileName, stdoutmark)
|
||||||
|
&& strcmp(dstFileName, nulmark)
|
||||||
|
&& stat_result)
|
||||||
UTIL_setFileStat(dstFileName, &statbuf);
|
UTIL_setFileStat(dstFileName, &statbuf);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -951,10 +993,14 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
|
|||||||
if (outFileName != NULL) {
|
if (outFileName != NULL) {
|
||||||
unsigned u;
|
unsigned u;
|
||||||
ress.dstFile = FIO_openDstFile(outFileName);
|
ress.dstFile = FIO_openDstFile(outFileName);
|
||||||
|
if (ress.dstFile==NULL) { /* could not open outFileName */
|
||||||
|
missed_files = nbFiles;
|
||||||
|
} else {
|
||||||
for (u=0; u<nbFiles; u++)
|
for (u=0; u<nbFiles; u++)
|
||||||
missed_files += FIO_compressFilename_srcFile(ress, outFileName, inFileNamesTable[u], compressionLevel);
|
missed_files += FIO_compressFilename_srcFile(ress, outFileName, inFileNamesTable[u], compressionLevel);
|
||||||
if (fclose(ress.dstFile))
|
if (fclose(ress.dstFile))
|
||||||
EXM_THROW(29, "Write error : cannot properly close stdout");
|
EXM_THROW(29, "Write error : cannot properly close stdout");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned u;
|
unsigned u;
|
||||||
for (u=0; u<nbFiles; u++) {
|
for (u=0; u<nbFiles; u++) {
|
||||||
@@ -1134,33 +1180,46 @@ static unsigned FIO_passThrough(FILE* foutput, FILE* finput, void* buffer, size_
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FIO_zstdErrorHelp(dRess_t* ress, size_t ret, char const* srcFileName)
|
/* FIO_highbit64() :
|
||||||
|
* gives position of highest bit.
|
||||||
|
* note : only works for v > 0 !
|
||||||
|
*/
|
||||||
|
static unsigned FIO_highbit64(unsigned long long v)
|
||||||
|
{
|
||||||
|
unsigned count = 0;
|
||||||
|
assert(v != 0);
|
||||||
|
v >>= 1;
|
||||||
|
while (v) { v >>= 1; count++; }
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIO_zstdErrorHelp() :
|
||||||
|
* detailed error message when requested window size is too large */
|
||||||
|
static void FIO_zstdErrorHelp(dRess_t* ress, size_t err, char const* srcFileName)
|
||||||
{
|
{
|
||||||
ZSTD_frameHeader header;
|
ZSTD_frameHeader header;
|
||||||
/* No special help for these errors */
|
|
||||||
if (ZSTD_getErrorCode(ret) != ZSTD_error_frameParameter_windowTooLarge)
|
/* Help message only for one specific error */
|
||||||
|
if (ZSTD_getErrorCode(err) != ZSTD_error_frameParameter_windowTooLarge)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Try to decode the frame header */
|
/* Try to decode the frame header */
|
||||||
ret = ZSTD_getFrameHeader(&header, ress->srcBuffer, ress->srcBufferLoaded);
|
err = ZSTD_getFrameHeader(&header, ress->srcBuffer, ress->srcBufferLoaded);
|
||||||
if (ret == 0) {
|
if (err == 0) {
|
||||||
U32 const windowSize = (U32)header.windowSize;
|
unsigned long long const windowSize = header.windowSize;
|
||||||
U32 const windowLog = BIT_highbit32(windowSize) + ((windowSize & (windowSize - 1)) != 0);
|
U32 const windowLog = FIO_highbit64(windowSize) + ((windowSize & (windowSize - 1)) != 0);
|
||||||
U32 const windowMB = (windowSize >> 20) + ((windowSize & ((1 MB) - 1)) != 0);
|
U32 const windowMB = (U32)((windowSize >> 20) + ((windowSize & ((1 MB) - 1)) != 0));
|
||||||
assert(header.windowSize <= (U64)((U32)-1));
|
assert(windowSize < (U64)(1ULL << 52));
|
||||||
assert(g_memLimit > 0);
|
assert(g_memLimit > 0);
|
||||||
DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u\n",
|
DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u\n",
|
||||||
srcFileName, header.windowSize, g_memLimit);
|
srcFileName, windowSize, g_memLimit);
|
||||||
if (windowLog <= ZSTD_WINDOWLOG_MAX) {
|
if (windowLog <= ZSTD_WINDOWLOG_MAX) {
|
||||||
DISPLAYLEVEL(1, "%s : Use --long=%u or --memory=%uMB\n",
|
DISPLAYLEVEL(1, "%s : Use --long=%u or --memory=%uMB\n",
|
||||||
srcFileName, windowLog, windowMB);
|
srcFileName, windowLog, windowMB);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (ZSTD_getErrorCode(ret) != ZSTD_error_frameParameter_windowTooLarge) {
|
|
||||||
DISPLAYLEVEL(1, "%s : Error decoding frame header to read window size : %s\n",
|
|
||||||
srcFileName, ZSTD_getErrorName(ret));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(1, "%s : Window log larger than ZSTD_WINDOWLOG_MAX=%u not supported\n",
|
DISPLAYLEVEL(1, "%s : Window log larger than ZSTD_WINDOWLOG_MAX=%u; not supported\n",
|
||||||
srcFileName, ZSTD_WINDOWLOG_MAX);
|
srcFileName, ZSTD_WINDOWLOG_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1571,7 +1630,7 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const ch
|
|||||||
* delete both the source and destination files.
|
* delete both the source and destination files.
|
||||||
*/
|
*/
|
||||||
clearHandler();
|
clearHandler();
|
||||||
if (remove(srcFileName)) {
|
if (FIO_remove(srcFileName)) {
|
||||||
/* failed to remove src file */
|
/* failed to remove src file */
|
||||||
DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno));
|
DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1614,7 +1673,7 @@ static int FIO_decompressDstFile(dRess_t ress,
|
|||||||
if ( (result != 0) /* operation failure */
|
if ( (result != 0) /* operation failure */
|
||||||
&& strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */
|
&& strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */
|
||||||
&& strcmp(dstFileName, stdoutmark) ) /* special case : don't remove() stdout */
|
&& 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 */
|
else { /* operation success */
|
||||||
if ( strcmp(dstFileName, stdoutmark) /* special case : don't chmod stdout */
|
if ( strcmp(dstFileName, stdoutmark) /* special case : don't chmod stdout */
|
||||||
&& strcmp(dstFileName, nulmark) /* special case : don't chmod /dev/null */
|
&& strcmp(dstFileName, nulmark) /* special case : don't chmod /dev/null */
|
||||||
@@ -1917,6 +1976,7 @@ static void displayInfo(const char* inFileName, const fileInfo_t* info, int disp
|
|||||||
static fileInfo_t FIO_addFInfo(fileInfo_t fi1, fileInfo_t fi2)
|
static fileInfo_t FIO_addFInfo(fileInfo_t fi1, fileInfo_t fi2)
|
||||||
{
|
{
|
||||||
fileInfo_t total;
|
fileInfo_t total;
|
||||||
|
memset(&total, 0, sizeof(total));
|
||||||
total.numActualFrames = fi1.numActualFrames + fi2.numActualFrames;
|
total.numActualFrames = fi1.numActualFrames + fi2.numActualFrames;
|
||||||
total.numSkippableFrames = fi1.numSkippableFrames + fi2.numSkippableFrames;
|
total.numSkippableFrames = fi1.numSkippableFrames + fi2.numSkippableFrames;
|
||||||
total.compressedSize = fi1.compressedSize + fi2.compressedSize;
|
total.compressedSize = fi1.compressedSize + fi2.compressedSize;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ void FIO_setDictIDFlag(unsigned dictIDFlag);
|
|||||||
void FIO_setChecksumFlag(unsigned checksumFlag);
|
void FIO_setChecksumFlag(unsigned checksumFlag);
|
||||||
void FIO_setRemoveSrcFile(unsigned flag);
|
void FIO_setRemoveSrcFile(unsigned flag);
|
||||||
void FIO_setMemLimit(unsigned memLimit);
|
void FIO_setMemLimit(unsigned memLimit);
|
||||||
void FIO_setNbThreads(unsigned nbThreads);
|
void FIO_setNbWorkers(unsigned nbWorkers);
|
||||||
void FIO_setBlockSize(unsigned blockSize);
|
void FIO_setBlockSize(unsigned blockSize);
|
||||||
void FIO_setOverlapLog(unsigned overlapLog);
|
void FIO_setOverlapLog(unsigned overlapLog);
|
||||||
void FIO_setLdmFlag(unsigned ldmFlag);
|
void FIO_setLdmFlag(unsigned ldmFlag);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ extern "C" {
|
|||||||
***************************************************************/
|
***************************************************************/
|
||||||
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) /* UNIX-like OS */ \
|
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) /* UNIX-like OS */ \
|
||||||
|| defined(__midipix__) || defined(__VMS))
|
|| defined(__midipix__) || defined(__VMS))
|
||||||
# if (defined(__APPLE__) && defined(__MACH__)) || defined(__SVR4) || defined(_AIX) || defined(__hpux) /* POSIX.1–2001 (SUSv3) conformant */ \
|
# if (defined(__APPLE__) && defined(__MACH__)) || defined(__SVR4) || defined(_AIX) || defined(__hpux) /* POSIX.1-2001 (SUSv3) conformant */ \
|
||||||
|| defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) /* BSD distros */
|
|| defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) /* BSD distros */
|
||||||
# define PLATFORM_POSIX_VERSION 200112L
|
# define PLATFORM_POSIX_VERSION 200112L
|
||||||
# else
|
# else
|
||||||
@@ -106,8 +106,7 @@ extern "C" {
|
|||||||
# include <io.h> /* _isatty */
|
# include <io.h> /* _isatty */
|
||||||
# include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
|
# include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
|
||||||
# include <stdio.h> /* FILE */
|
# include <stdio.h> /* FILE */
|
||||||
static __inline int IS_CONSOLE(FILE* stdStream)
|
static __inline int IS_CONSOLE(FILE* stdStream) {
|
||||||
{
|
|
||||||
DWORD dummy;
|
DWORD dummy;
|
||||||
return _isatty(_fileno(stdStream)) && GetConsoleMode((HANDLE)_get_osfhandle(_fileno(stdStream)), &dummy);
|
return _isatty(_fileno(stdStream)) && GetConsoleMode((HANDLE)_get_osfhandle(_fileno(stdStream)), &dummy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,9 @@ static int g_utilDisplayLevel;
|
|||||||
}
|
}
|
||||||
return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
|
return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__APPLE__) && defined(__MACH__)
|
#elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
|
||||||
#include <mach/mach_time.h>
|
#include <mach/mach_time.h>
|
||||||
#define UTIL_TIME_INITIALIZER 0
|
#define UTIL_TIME_INITIALIZER 0
|
||||||
typedef U64 UTIL_time_t;
|
typedef U64 UTIL_time_t;
|
||||||
@@ -167,7 +169,9 @@ static int g_utilDisplayLevel;
|
|||||||
}
|
}
|
||||||
return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom);
|
return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif (PLATFORM_POSIX_VERSION >= 200112L) && (defined __UCLIBC__ || ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2))
|
#elif (PLATFORM_POSIX_VERSION >= 200112L) && (defined __UCLIBC__ || ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2))
|
||||||
|
|
||||||
#define UTIL_TIME_INITIALIZER { 0, 0 }
|
#define UTIL_TIME_INITIALIZER { 0, 0 }
|
||||||
typedef struct timespec UTIL_freq_t;
|
typedef struct timespec UTIL_freq_t;
|
||||||
typedef struct timespec UTIL_time_t;
|
typedef struct timespec UTIL_time_t;
|
||||||
@@ -223,6 +227,12 @@ UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart )
|
|||||||
return UTIL_getSpanTimeMicro(clockStart, clockEnd);
|
return UTIL_getSpanTimeMicro(clockStart, clockEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* returns time span in microseconds */
|
||||||
|
UTIL_STATIC U64 UTIL_clockSpanNano(UTIL_time_t clockStart )
|
||||||
|
{
|
||||||
|
UTIL_time_t const clockEnd = UTIL_getTime();
|
||||||
|
return UTIL_getSpanTimeNano(clockStart, clockEnd);
|
||||||
|
}
|
||||||
|
|
||||||
UTIL_STATIC void UTIL_waitForNextTick(void)
|
UTIL_STATIC void UTIL_waitForNextTick(void)
|
||||||
{
|
{
|
||||||
@@ -246,11 +256,17 @@ UTIL_STATIC void UTIL_waitForNextTick(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
UTIL_STATIC int UTIL_isRegularFile(const char* infilename);
|
||||||
|
|
||||||
|
|
||||||
UTIL_STATIC int UTIL_setFileStat(const char *filename, stat_t *statbuf)
|
UTIL_STATIC int UTIL_setFileStat(const char *filename, stat_t *statbuf)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
struct utimbuf timebuf;
|
struct utimbuf timebuf;
|
||||||
|
|
||||||
|
if (!UTIL_isRegularFile(filename))
|
||||||
|
return -1;
|
||||||
|
|
||||||
timebuf.actime = time(NULL);
|
timebuf.actime = time(NULL);
|
||||||
timebuf.modtime = statbuf->st_mtime;
|
timebuf.modtime = statbuf->st_mtime;
|
||||||
res += utime(filename, &timebuf); /* set access and modification times */
|
res += utime(filename, &timebuf); /* set access and modification times */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.
|
.
|
||||||
.TH "ZSTD" "1" "December 2017" "zstd 1.3.3" "User Commands"
|
.TH "ZSTD" "1" "2018-01-27" "zstd 1.3.4" "User Commands"
|
||||||
.
|
.
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
\fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files
|
\fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files
|
||||||
@@ -179,7 +179,7 @@ add integrity check computed from uncompressed data (default : enabled)
|
|||||||
All arguments after \fB\-\-\fR are treated as files
|
All arguments after \fB\-\-\fR are treated as files
|
||||||
.
|
.
|
||||||
.SH "DICTIONARY BUILDER"
|
.SH "DICTIONARY BUILDER"
|
||||||
\fBzstd\fR offers \fIdictionary\fR compression, useful for very small files and messages\. It\'s possible to train \fBzstd\fR with some samples, the result of which is saved into a file called a \fBdictionary\fR\. Then during compression and decompression, reference the same dictionary\. It will improve compression ratio of small files\. Typical gains range from 10% (at 64KB) to x5 better (at <1KB)\.
|
\fBzstd\fR offers \fIdictionary\fR compression, which greatly improves efficiency on small files and messages\. It\'s possible to train \fBzstd\fR with a set of samples, the result of which is saved into a file called a \fBdictionary\fR\. Then during compression and decompression, reference the same dictionary, using command \fB\-D dictionaryFileName\fR\. Compression of small files similar to the sample set will be greatly improved\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-train FILEs\fR
|
\fB\-\-train FILEs\fR
|
||||||
@@ -197,6 +197,10 @@ Dictionary saved into \fBfile\fR (default name: dictionary)\.
|
|||||||
Limit dictionary to specified size (default: 112640)\.
|
Limit dictionary to specified size (default: 112640)\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-#\fR
|
||||||
|
Use \fB#\fR compression level during training (optional)\. Will generate statistics more tuned for selected compression level, resulting in a \fIsmall\fR compression ratio improvement for this level\.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
\fB\-B#\fR
|
\fB\-B#\fR
|
||||||
Split input files in blocks of size # (default: no split)
|
Split input files in blocks of size # (default: no split)
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -115,11 +115,25 @@ the last one takes effect.
|
|||||||
|
|
||||||
Note: If `windowLog` is set to larger than 27, `--long=windowLog` or
|
Note: If `windowLog` is set to larger than 27, `--long=windowLog` or
|
||||||
`--memory=windowSize` needs to be passed to the decompressor.
|
`--memory=windowSize` needs to be passed to the decompressor.
|
||||||
|
* `--fast[=#]`:
|
||||||
|
switch to ultra-fast compression levels.
|
||||||
|
If `=#` is not present, it defaults to `1`.
|
||||||
|
The higher the value, the faster the compression speed,
|
||||||
|
at the cost of some compression ratio.
|
||||||
|
This setting overwrites compression level if one was set previously.
|
||||||
|
Similarly, if a compression level is set after `--fast`, it overrides it.
|
||||||
|
|
||||||
* `-T#`, `--threads=#`:
|
* `-T#`, `--threads=#`:
|
||||||
Compress using `#` threads (default: 1).
|
Compress using `#` working threads (default: 1).
|
||||||
If `#` is 0, attempt to detect and use the number of physical CPU cores.
|
If `#` is 0, attempt to detect and use the number of physical CPU cores.
|
||||||
In all cases, the nb of threads is capped to ZSTDMT_NBTHREADS_MAX==256.
|
In all cases, the nb of threads is capped to ZSTDMT_NBTHREADS_MAX==200.
|
||||||
This modifier does nothing if `zstd` is compiled without multithread support.
|
This modifier does nothing if `zstd` is compiled without multithread support.
|
||||||
|
* `--single-thread`:
|
||||||
|
Does not spawn a thread for compression, use caller thread instead.
|
||||||
|
This is the only available mode when multithread support is disabled.
|
||||||
|
In this mode, compression is serialized with I/O.
|
||||||
|
(This is different from `-T1`, which spawns 1 compression thread in parallel of I/O).
|
||||||
|
Single-thread mode also features lower memory usage.
|
||||||
* `-D file`:
|
* `-D file`:
|
||||||
use `file` as Dictionary to compress or decompress FILE(s)
|
use `file` as Dictionary to compress or decompress FILE(s)
|
||||||
* `--nodictID`:
|
* `--nodictID`:
|
||||||
@@ -171,12 +185,12 @@ the last one takes effect.
|
|||||||
DICTIONARY BUILDER
|
DICTIONARY BUILDER
|
||||||
------------------
|
------------------
|
||||||
`zstd` offers _dictionary_ compression,
|
`zstd` offers _dictionary_ compression,
|
||||||
useful for very small files and messages.
|
which greatly improves efficiency on small files and messages.
|
||||||
It's possible to train `zstd` with some samples,
|
It's possible to train `zstd` with a set of samples,
|
||||||
the result of which is saved into a file called a `dictionary`.
|
the result of which is saved into a file called a `dictionary`.
|
||||||
Then during compression and decompression, reference the same dictionary.
|
Then during compression and decompression, reference the same dictionary,
|
||||||
It will improve compression ratio of small files.
|
using command `-D dictionaryFileName`.
|
||||||
Typical gains range from 10% (at 64KB) to x5 better (at <1KB).
|
Compression of small files similar to the sample set will be greatly improved.
|
||||||
|
|
||||||
* `--train FILEs`:
|
* `--train FILEs`:
|
||||||
Use FILEs as training set to create a dictionary.
|
Use FILEs as training set to create a dictionary.
|
||||||
@@ -192,6 +206,10 @@ Typical gains range from 10% (at 64KB) to x5 better (at <1KB).
|
|||||||
Dictionary saved into `file` (default name: dictionary).
|
Dictionary saved into `file` (default name: dictionary).
|
||||||
* `--maxdict=#`:
|
* `--maxdict=#`:
|
||||||
Limit dictionary to specified size (default: 112640).
|
Limit dictionary to specified size (default: 112640).
|
||||||
|
* `-#`:
|
||||||
|
Use `#` compression level during training (optional).
|
||||||
|
Will generate statistics more tuned for selected compression level,
|
||||||
|
resulting in a _small_ compression ratio improvement for this level.
|
||||||
* `-B#`:
|
* `-B#`:
|
||||||
Split input files in blocks of size # (default: no split)
|
Split input files in blocks of size # (default: no split)
|
||||||
* `--dictID=#`:
|
* `--dictID=#`:
|
||||||
@@ -329,14 +347,21 @@ The list of available _options_:
|
|||||||
The minimum _slen_ is 3 and the maximum is 7.
|
The minimum _slen_ is 3 and the maximum is 7.
|
||||||
|
|
||||||
- `targetLen`=_tlen_, `tlen`=_tlen_:
|
- `targetLen`=_tlen_, `tlen`=_tlen_:
|
||||||
Specify the minimum match length that causes a match finder to stop
|
The impact of this field vary depending on selected strategy.
|
||||||
searching for better matches.
|
|
||||||
|
|
||||||
A larger minimum match length usually improves compression ratio but
|
For ZSTD\_btopt and ZSTD\_btultra, it specifies the minimum match length
|
||||||
decreases compression speed.
|
that causes match finder to stop searching for better matches.
|
||||||
This option is only used with strategies ZSTD_btopt and ZSTD_btultra.
|
A larger `targetLen` usually improves compression ratio
|
||||||
|
but decreases compression speed.
|
||||||
|
|
||||||
The minimum _tlen_ is 4 and the maximum is 999.
|
For ZSTD\_fast, it specifies
|
||||||
|
the amount of data skipped between match sampling.
|
||||||
|
Impact is reversed : a larger `targetLen` increases compression speed
|
||||||
|
but decreases compression ratio.
|
||||||
|
|
||||||
|
For all other strategies, this field has no impact.
|
||||||
|
|
||||||
|
The minimum _tlen_ is 1 and the maximum is 999.
|
||||||
|
|
||||||
- `overlapLog`=_ovlog_, `ovlog`=_ovlog_:
|
- `overlapLog`=_ovlog_, `ovlog`=_ovlog_:
|
||||||
Determine `overlapSize`, amount of data reloaded from previous job.
|
Determine `overlapSize`, amount of data reloaded from previous job.
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
#define ZSTD_ZSTDMT "zstdmt"
|
#define ZSTD_ZSTDMT "zstdmt"
|
||||||
#define ZSTD_UNZSTD "unzstd"
|
#define ZSTD_UNZSTD "unzstd"
|
||||||
#define ZSTD_CAT "zstdcat"
|
#define ZSTD_CAT "zstdcat"
|
||||||
|
#define ZSTD_ZCAT "zcat"
|
||||||
#define ZSTD_GZ "gzip"
|
#define ZSTD_GZ "gzip"
|
||||||
#define ZSTD_GUNZIP "gunzip"
|
#define ZSTD_GUNZIP "gunzip"
|
||||||
#define ZSTD_GZCAT "gzcat"
|
#define ZSTD_GZCAT "gzcat"
|
||||||
@@ -133,8 +134,9 @@ static int usage_advanced(const char* programName)
|
|||||||
#ifndef ZSTD_NOCOMPRESS
|
#ifndef ZSTD_NOCOMPRESS
|
||||||
DISPLAY( "--ultra : enable levels beyond %i, up to %i (requires more memory)\n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel());
|
DISPLAY( "--ultra : enable levels beyond %i, up to %i (requires more memory)\n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel());
|
||||||
DISPLAY( "--long[=#]: enable long distance matching with given window log (default: %u)\n", g_defaultMaxWindowLog);
|
DISPLAY( "--long[=#]: enable long distance matching with given window log (default: %u)\n", g_defaultMaxWindowLog);
|
||||||
|
DISPLAY( "--fast[=#]: switch to ultra fast compression level (default: %u)\n", 1);
|
||||||
#ifdef ZSTD_MULTITHREAD
|
#ifdef ZSTD_MULTITHREAD
|
||||||
DISPLAY( " -T# : use # threads for compression (default:1) \n");
|
DISPLAY( " -T# : spawns # compression threads (default: 1, 0==# cores) \n");
|
||||||
DISPLAY( " -B# : select size of each job (default: 0==automatic) \n");
|
DISPLAY( " -B# : select size of each job (default: 0==automatic) \n");
|
||||||
#endif
|
#endif
|
||||||
DISPLAY( "--no-dictID : don't write dictID into header (dictionary compression)\n");
|
DISPLAY( "--no-dictID : don't write dictID into header (dictionary compression)\n");
|
||||||
@@ -176,7 +178,7 @@ static int usage_advanced(const char* programName)
|
|||||||
#ifndef ZSTD_NOBENCH
|
#ifndef ZSTD_NOBENCH
|
||||||
DISPLAY( "\n");
|
DISPLAY( "\n");
|
||||||
DISPLAY( "Benchmark arguments : \n");
|
DISPLAY( "Benchmark arguments : \n");
|
||||||
DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n");
|
DISPLAY( " -b# : benchmark file(s), using # compression level (default: %d) \n", ZSTDCLI_CLEVEL_DEFAULT);
|
||||||
DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n");
|
DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n");
|
||||||
DISPLAY( " -i# : minimum evaluation time in seconds (default: 3s) \n");
|
DISPLAY( " -i# : minimum evaluation time in seconds (default: 3s) \n");
|
||||||
DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n");
|
DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n");
|
||||||
@@ -218,10 +220,10 @@ static int exeNameMatch(const char* exeName, const char* test)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! readU32FromChar() :
|
/*! readU32FromChar() :
|
||||||
@return : unsigned integer value read from input in `char` format
|
* @return : unsigned integer value read from input in `char` format.
|
||||||
allows and interprets K, KB, KiB, M, MB and MiB suffix.
|
* allows and interprets K, KB, KiB, M, MB and MiB suffix.
|
||||||
Will also modify `*stringPtr`, advancing it to position where it stopped reading.
|
* Will also modify `*stringPtr`, advancing it to position where it stopped reading.
|
||||||
Note : function result can overflow if digit string > MAX_UINT */
|
* Note : function result can overflow if digit string > MAX_UINT */
|
||||||
static unsigned readU32FromChar(const char** stringPtr)
|
static unsigned readU32FromChar(const char** stringPtr)
|
||||||
{
|
{
|
||||||
unsigned result = 0;
|
unsigned result = 0;
|
||||||
@@ -318,12 +320,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, "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, "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; }
|
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;
|
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 */
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,27 +367,28 @@ typedef enum { zom_compress, zom_decompress, zom_test, zom_bench, zom_train, zom
|
|||||||
int main(int argCount, const char* argv[])
|
int main(int argCount, const char* argv[])
|
||||||
{
|
{
|
||||||
int argNb,
|
int argNb,
|
||||||
forceStdout=0,
|
|
||||||
followLinks = 0,
|
followLinks = 0,
|
||||||
|
forceStdout = 0,
|
||||||
|
lastCommand = 0,
|
||||||
|
ldmFlag = 0,
|
||||||
main_pause = 0,
|
main_pause = 0,
|
||||||
nextEntryIsDictionary=0,
|
nbWorkers = 0,
|
||||||
operationResult=0,
|
|
||||||
nextArgumentIsOutFileName = 0,
|
nextArgumentIsOutFileName = 0,
|
||||||
nextArgumentIsMaxDict = 0,
|
nextArgumentIsMaxDict = 0,
|
||||||
nextArgumentIsDictID = 0,
|
nextArgumentIsDictID = 0,
|
||||||
nextArgumentsAreFiles = 0,
|
nextArgumentsAreFiles = 0,
|
||||||
ultra=0,
|
nextEntryIsDictionary = 0,
|
||||||
lastCommand = 0,
|
operationResult = 0,
|
||||||
nbThreads = 1,
|
|
||||||
setRealTimePrio = 0,
|
|
||||||
separateFiles = 0,
|
separateFiles = 0,
|
||||||
ldmFlag = 0;
|
setRealTimePrio = 0,
|
||||||
|
singleThread = 0,
|
||||||
|
ultra=0;
|
||||||
unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */
|
unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */
|
||||||
size_t blockSize = 0;
|
size_t blockSize = 0;
|
||||||
zstd_operation_mode operation = zom_compress;
|
zstd_operation_mode operation = zom_compress;
|
||||||
ZSTD_compressionParameters compressionParams;
|
ZSTD_compressionParameters compressionParams;
|
||||||
int cLevel = ZSTDCLI_CLEVEL_DEFAULT;
|
int cLevel = ZSTDCLI_CLEVEL_DEFAULT;
|
||||||
int cLevelLast = 1;
|
int cLevelLast = -1000000000;
|
||||||
unsigned recursive = 0;
|
unsigned recursive = 0;
|
||||||
unsigned memLimit = 0;
|
unsigned memLimit = 0;
|
||||||
const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */
|
const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */
|
||||||
@@ -416,22 +420,25 @@ int main(int argCount, const char* argv[])
|
|||||||
if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); }
|
if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); }
|
||||||
filenameTable[0] = stdinmark;
|
filenameTable[0] = stdinmark;
|
||||||
g_displayOut = stderr;
|
g_displayOut = stderr;
|
||||||
|
|
||||||
programName = lastNameFromPath(programName);
|
programName = lastNameFromPath(programName);
|
||||||
|
#ifdef ZSTD_MULTITHREAD
|
||||||
|
nbWorkers = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* preset behaviors */
|
/* preset behaviors */
|
||||||
if (exeNameMatch(programName, ZSTD_ZSTDMT)) nbThreads=0;
|
if (exeNameMatch(programName, ZSTD_ZSTDMT)) nbWorkers=0;
|
||||||
if (exeNameMatch(programName, ZSTD_UNZSTD)) operation=zom_decompress;
|
if (exeNameMatch(programName, ZSTD_UNZSTD)) operation=zom_decompress;
|
||||||
if (exeNameMatch(programName, ZSTD_CAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; }
|
if (exeNameMatch(programName, ZSTD_CAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; } /* supports multiple formats */
|
||||||
|
if (exeNameMatch(programName, ZSTD_ZCAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; } /* behave like zcat, also supports multiple formats */
|
||||||
if (exeNameMatch(programName, ZSTD_GZ)) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); FIO_setRemoveSrcFile(1); } /* behave like gzip */
|
if (exeNameMatch(programName, ZSTD_GZ)) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); FIO_setRemoveSrcFile(1); } /* behave like gzip */
|
||||||
if (exeNameMatch(programName, ZSTD_GUNZIP)) { operation=zom_decompress; FIO_setRemoveSrcFile(1); } /* behave like gunzip */
|
if (exeNameMatch(programName, ZSTD_GUNZIP)) { operation=zom_decompress; FIO_setRemoveSrcFile(1); } /* behave like gunzip, also supports multiple formats */
|
||||||
if (exeNameMatch(programName, ZSTD_GZCAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; } /* behave like gzcat */
|
if (exeNameMatch(programName, ZSTD_GZCAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; } /* behave like gzcat, also supports multiple formats */
|
||||||
if (exeNameMatch(programName, ZSTD_LZMA)) { suffix = LZMA_EXTENSION; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like lzma */
|
if (exeNameMatch(programName, ZSTD_LZMA)) { suffix = LZMA_EXTENSION; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like lzma */
|
||||||
if (exeNameMatch(programName, ZSTD_UNLZMA)) { operation=zom_decompress; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like unlzma */
|
if (exeNameMatch(programName, ZSTD_UNLZMA)) { operation=zom_decompress; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like unlzma, also supports multiple formats */
|
||||||
if (exeNameMatch(programName, ZSTD_XZ)) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like xz */
|
if (exeNameMatch(programName, ZSTD_XZ)) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like xz */
|
||||||
if (exeNameMatch(programName, ZSTD_UNXZ)) { operation=zom_decompress; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like unxz */
|
if (exeNameMatch(programName, ZSTD_UNXZ)) { operation=zom_decompress; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like unxz, also supports multiple formats */
|
||||||
if (exeNameMatch(programName, ZSTD_LZ4)) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like xz */
|
if (exeNameMatch(programName, ZSTD_LZ4)) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); } /* behave like lz4 */
|
||||||
if (exeNameMatch(programName, ZSTD_UNLZ4)) { operation=zom_decompress; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like unxz */
|
if (exeNameMatch(programName, ZSTD_UNLZ4)) { operation=zom_decompress; FIO_setCompressionType(FIO_lz4Compression); } /* behave like unlz4, also supports multiple formats */
|
||||||
memset(&compressionParams, 0, sizeof(compressionParams));
|
memset(&compressionParams, 0, sizeof(compressionParams));
|
||||||
|
|
||||||
/* command switches */
|
/* command switches */
|
||||||
@@ -478,6 +485,7 @@ int main(int argCount, const char* argv[])
|
|||||||
if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; }
|
if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; }
|
||||||
if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; }
|
if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; }
|
||||||
if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; }
|
if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; }
|
||||||
|
if (!strcmp(argument, "--single-thread")) { nbWorkers = 0; singleThread = 1; continue; }
|
||||||
#ifdef ZSTD_GZCOMPRESS
|
#ifdef ZSTD_GZCOMPRESS
|
||||||
if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; }
|
if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; }
|
||||||
#endif
|
#endif
|
||||||
@@ -512,7 +520,7 @@ int main(int argCount, const char* argv[])
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (longCommandWArg(&argument, "--threads=")) { nbThreads = readU32FromChar(&argument); continue; }
|
if (longCommandWArg(&argument, "--threads=")) { nbWorkers = readU32FromChar(&argument); continue; }
|
||||||
if (longCommandWArg(&argument, "--memlimit=")) { memLimit = readU32FromChar(&argument); continue; }
|
if (longCommandWArg(&argument, "--memlimit=")) { memLimit = readU32FromChar(&argument); continue; }
|
||||||
if (longCommandWArg(&argument, "--memory=")) { memLimit = readU32FromChar(&argument); continue; }
|
if (longCommandWArg(&argument, "--memory=")) { memLimit = readU32FromChar(&argument); continue; }
|
||||||
if (longCommandWArg(&argument, "--memlimit-decompress=")) { memLimit = readU32FromChar(&argument); continue; }
|
if (longCommandWArg(&argument, "--memlimit-decompress=")) { memLimit = readU32FromChar(&argument); continue; }
|
||||||
@@ -536,6 +544,21 @@ int main(int argCount, const char* argv[])
|
|||||||
compressionParams.windowLog = ldmWindowLog;
|
compressionParams.windowLog = ldmWindowLog;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (longCommandWArg(&argument, "--fast")) {
|
||||||
|
/* Parse optional window log */
|
||||||
|
if (*argument == '=') {
|
||||||
|
U32 fastLevel;
|
||||||
|
++argument;
|
||||||
|
fastLevel = readU32FromChar(&argument);
|
||||||
|
if (fastLevel) cLevel = - (int)fastLevel;
|
||||||
|
} else if (*argument != 0) {
|
||||||
|
/* Invalid character following --fast */
|
||||||
|
CLEAN_RETURN(badusage(programName));
|
||||||
|
} else {
|
||||||
|
cLevel = -1; /* default for --fast */
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/* fall-through, will trigger bad_usage() later on */
|
/* fall-through, will trigger bad_usage() later on */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,7 +589,8 @@ int main(int argCount, const char* argv[])
|
|||||||
/* Decoding */
|
/* Decoding */
|
||||||
case 'd':
|
case 'd':
|
||||||
#ifndef ZSTD_NOBENCH
|
#ifndef ZSTD_NOBENCH
|
||||||
if (operation==zom_bench) { BMK_setDecodeOnlyMode(1); argument++; break; } /* benchmark decode (hidden option) */
|
BMK_setDecodeOnlyMode(1);
|
||||||
|
if (operation==zom_bench) { argument++; break; } /* benchmark decode (hidden option) */
|
||||||
#endif
|
#endif
|
||||||
operation=zom_decompress; argument++; break;
|
operation=zom_decompress; argument++; break;
|
||||||
|
|
||||||
@@ -645,7 +669,7 @@ int main(int argCount, const char* argv[])
|
|||||||
/* nb of threads (hidden option) */
|
/* nb of threads (hidden option) */
|
||||||
case 'T':
|
case 'T':
|
||||||
argument++;
|
argument++;
|
||||||
nbThreads = readU32FromChar(&argument);
|
nbWorkers = readU32FromChar(&argument);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Dictionary Selection level */
|
/* Dictionary Selection level */
|
||||||
@@ -713,11 +737,13 @@ int main(int argCount, const char* argv[])
|
|||||||
/* Welcome message (if verbose) */
|
/* Welcome message (if verbose) */
|
||||||
DISPLAYLEVEL(3, WELCOME_MESSAGE);
|
DISPLAYLEVEL(3, WELCOME_MESSAGE);
|
||||||
|
|
||||||
if (nbThreads == 0) {
|
#ifdef ZSTD_MULTITHREAD
|
||||||
/* try to guess */
|
if ((nbWorkers==0) && (!singleThread)) {
|
||||||
nbThreads = UTIL_countPhysicalCores();
|
/* automatically set # workers based on # of reported cpus */
|
||||||
DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbThreads);
|
nbWorkers = UTIL_countPhysicalCores();
|
||||||
|
DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
g_utilDisplayLevel = g_displayLevel;
|
g_utilDisplayLevel = g_displayLevel;
|
||||||
if (!followLinks) {
|
if (!followLinks) {
|
||||||
@@ -760,7 +786,7 @@ int main(int argCount, const char* argv[])
|
|||||||
BMK_setNotificationLevel(g_displayLevel);
|
BMK_setNotificationLevel(g_displayLevel);
|
||||||
BMK_setSeparateFiles(separateFiles);
|
BMK_setSeparateFiles(separateFiles);
|
||||||
BMK_setBlockSize(blockSize);
|
BMK_setBlockSize(blockSize);
|
||||||
BMK_setNbThreads(nbThreads);
|
BMK_setNbWorkers(nbWorkers);
|
||||||
BMK_setRealTime(setRealTimePrio);
|
BMK_setRealTime(setRealTimePrio);
|
||||||
BMK_setNbSeconds(bench_nbSeconds);
|
BMK_setNbSeconds(bench_nbSeconds);
|
||||||
BMK_setLdmFlag(ldmFlag);
|
BMK_setLdmFlag(ldmFlag);
|
||||||
@@ -788,7 +814,7 @@ int main(int argCount, const char* argv[])
|
|||||||
zParams.dictID = dictID;
|
zParams.dictID = dictID;
|
||||||
if (cover) {
|
if (cover) {
|
||||||
int const optimize = !coverParams.k || !coverParams.d;
|
int const optimize = !coverParams.k || !coverParams.d;
|
||||||
coverParams.nbThreads = nbThreads;
|
coverParams.nbThreads = nbWorkers;
|
||||||
coverParams.zParams = zParams;
|
coverParams.zParams = zParams;
|
||||||
operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, NULL, &coverParams, optimize);
|
operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, NULL, &coverParams, optimize);
|
||||||
} else {
|
} else {
|
||||||
@@ -808,11 +834,17 @@ int main(int argCount, const char* argv[])
|
|||||||
|
|
||||||
/* No input filename ==> use stdin and stdout */
|
/* No input filename ==> use stdin and stdout */
|
||||||
filenameIdx += !filenameIdx; /* filenameTable[0] is stdin by default */
|
filenameIdx += !filenameIdx; /* filenameTable[0] is stdin by default */
|
||||||
if (!strcmp(filenameTable[0], stdinmark) && !outFileName) outFileName = stdoutmark; /* when input is stdin, default output is stdout */
|
if (!strcmp(filenameTable[0], stdinmark) && !outFileName)
|
||||||
|
outFileName = stdoutmark; /* when input is stdin, default output is stdout */
|
||||||
|
|
||||||
/* Check if input/output defined as console; trigger an error in this case */
|
/* Check if input/output defined as console; trigger an error in this case */
|
||||||
if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName));
|
if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) )
|
||||||
if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !strcmp(filenameTable[0], stdinmark) && !forceStdout && operation!=zom_decompress)
|
CLEAN_RETURN(badusage(programName));
|
||||||
|
if ( outFileName && !strcmp(outFileName, stdoutmark)
|
||||||
|
&& IS_CONSOLE(stdout)
|
||||||
|
&& !strcmp(filenameTable[0], stdinmark)
|
||||||
|
&& !forceStdout
|
||||||
|
&& operation!=zom_decompress )
|
||||||
CLEAN_RETURN(badusage(programName));
|
CLEAN_RETURN(badusage(programName));
|
||||||
|
|
||||||
#ifndef ZSTD_NOCOMPRESS
|
#ifndef ZSTD_NOCOMPRESS
|
||||||
@@ -832,7 +864,7 @@ int main(int argCount, const char* argv[])
|
|||||||
FIO_setNotificationLevel(g_displayLevel);
|
FIO_setNotificationLevel(g_displayLevel);
|
||||||
if (operation==zom_compress) {
|
if (operation==zom_compress) {
|
||||||
#ifndef ZSTD_NOCOMPRESS
|
#ifndef ZSTD_NOCOMPRESS
|
||||||
FIO_setNbThreads(nbThreads);
|
FIO_setNbWorkers(nbWorkers);
|
||||||
FIO_setBlockSize((U32)blockSize);
|
FIO_setBlockSize((U32)blockSize);
|
||||||
FIO_setLdmFlag(ldmFlag);
|
FIO_setLdmFlag(ldmFlag);
|
||||||
FIO_setLdmHashLog(g_ldmHashLog);
|
FIO_setLdmHashLog(g_ldmHashLog);
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ decodecorpus
|
|||||||
pool
|
pool
|
||||||
poolTests
|
poolTests
|
||||||
invalidDictionaries
|
invalidDictionaries
|
||||||
|
checkTag
|
||||||
|
zcat
|
||||||
|
zstdcat
|
||||||
|
|
||||||
# Tmp test directory
|
# Tmp test directory
|
||||||
zstdtest
|
zstdtest
|
||||||
@@ -52,6 +55,7 @@ tmp*
|
|||||||
*.gz
|
*.gz
|
||||||
result
|
result
|
||||||
out
|
out
|
||||||
|
*.zstd
|
||||||
|
|
||||||
# fuzzer
|
# fuzzer
|
||||||
afl
|
afl
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
ZSTDDIR = ../lib
|
ZSTDDIR = ../lib
|
||||||
PRGDIR = ../programs
|
PRGDIR = ../programs
|
||||||
PYTHON ?= python3
|
PYTHON ?= python3
|
||||||
TESTARTEFACT := versionsTest namespaceTest
|
TESTARTEFACT := versionsTest
|
||||||
|
|
||||||
DEBUGLEVEL ?= 1
|
DEBUGLEVEL ?= 1
|
||||||
DEBUGFLAGS = -g -DZSTD_DEBUG=$(DEBUGLEVEL)
|
DEBUGFLAGS = -g -DZSTD_DEBUG=$(DEBUGLEVEL)
|
||||||
@@ -44,6 +44,16 @@ ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES)
|
|||||||
ZBUFF_FILES := $(ZSTDDIR)/deprecated/*.c
|
ZBUFF_FILES := $(ZSTDDIR)/deprecated/*.c
|
||||||
ZDICT_FILES := $(ZSTDDIR)/dictBuilder/*.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
|
# Define *.exe as extension for Windows systems
|
||||||
ifneq (,$(filter Windows%,$(OS)))
|
ifneq (,$(filter Windows%,$(OS)))
|
||||||
@@ -63,14 +73,17 @@ FUZZERTEST ?= -T200s
|
|||||||
ZSTDRTTEST = --test-large-data
|
ZSTDRTTEST = --test-large-data
|
||||||
DECODECORPUS_TESTTIME ?= -T30
|
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
|
default: fullbench
|
||||||
|
@echo $(ZSTDMT_OBJECTS)
|
||||||
|
|
||||||
all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus
|
all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus roundTripCrash
|
||||||
|
|
||||||
all32: fullbench32 fuzzer32 zstreamtest32
|
all32: fullbench32 fuzzer32 zstreamtest32
|
||||||
|
|
||||||
|
allnothread: MULTITHREAD_CPP=
|
||||||
|
allnothread: MULTITHREAD_LD=
|
||||||
allnothread: fullbench fuzzer paramgrill datagen decodecorpus
|
allnothread: fullbench fuzzer paramgrill datagen decodecorpus
|
||||||
|
|
||||||
dll: fuzzer-dll zstreamtest-dll
|
dll: fuzzer-dll zstreamtest-dll
|
||||||
@@ -85,37 +98,71 @@ zstd-nolegacy:
|
|||||||
$(MAKE) -C $(PRGDIR) $@ MOREFLAGS+="$(DEBUGFLAGS)"
|
$(MAKE) -C $(PRGDIR) $@ MOREFLAGS+="$(DEBUGFLAGS)"
|
||||||
|
|
||||||
gzstd:
|
gzstd:
|
||||||
$(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 MOREFLAGS="$(DEBUGFLAGS)"
|
$(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 MOREFLAGS+="$(DEBUGFLAGS)"
|
||||||
|
|
||||||
|
.PHONY: zstd-dll
|
||||||
|
zstd-dll :
|
||||||
|
$(MAKE) -C $(ZSTDDIR) libzstd
|
||||||
|
|
||||||
|
.PHONY: zstd-staticLib
|
||||||
|
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 += $(MULTITHREAD_CPP)
|
||||||
|
|
||||||
|
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
|
fullbench32: CPPFLAGS += -m32
|
||||||
fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP)
|
fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP)
|
||||||
fullbench fullbench32 : LDFLAGS += $(MULTITHREAD_LD)
|
fullbench fullbench32 : LDFLAGS += $(MULTITHREAD_LD)
|
||||||
fullbench fullbench32 : DEBUGFLAGS = # turn off assert() for speed measurements
|
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)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
|
fullbench-lib : zstd-staticLib
|
||||||
fullbench-lib : $(PRGDIR)/datagen.c fullbench.c
|
fullbench-lib : $(PRGDIR)/datagen.c fullbench.c
|
||||||
$(MAKE) -C $(ZSTDDIR) libzstd.a
|
$(CC) $(FLAGS) $(filter %.c,$^) -o $@$(EXT) $(ZSTDDIR)/libzstd.a
|
||||||
$(CC) $(FLAGS) $^ -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
|
fullbench-dll: $(PRGDIR)/datagen.c fullbench.c
|
||||||
$(MAKE) -C $(ZSTDDIR) libzstd
|
# $(CC) $(FLAGS) $(filter %.c,$^) -o $@$(EXT) -DZSTD_DLL_IMPORT=1 $(ZSTDDIR)/dll/libzstd.dll
|
||||||
$(CC) $(FLAGS) $^ -o $@$(EXT) -DZSTD_DLL_IMPORT=1 $(ZSTDDIR)/dll/libzstd.dll
|
$(CC) $(FLAGS) $(filter %.c,$^) -o $@$(EXT)
|
||||||
|
|
||||||
fuzzer : CPPFLAGS += $(MULTITHREAD_CPP)
|
fuzzer : CPPFLAGS += $(MULTITHREAD_CPP)
|
||||||
fuzzer : LDFLAGS += $(MULTITHREAD_LD)
|
fuzzer : LDFLAGS += $(MULTITHREAD_LD)
|
||||||
fuzzer32: CFLAGS += -m32
|
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)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
|
fuzzer-dll : zstd-dll
|
||||||
fuzzer-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
|
fuzzer-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
|
||||||
fuzzer-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c fuzzer.c
|
fuzzer-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c fuzzer.c
|
||||||
$(MAKE) -C $(ZSTDDIR) libzstd
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(filter %.c,$^) $(LDFLAGS) -o $@$(EXT)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@$(EXT)
|
|
||||||
|
|
||||||
zbufftest : CPPFLAGS += -I$(ZSTDDIR)/deprecated
|
zbufftest : CPPFLAGS += -I$(ZSTDDIR)/deprecated
|
||||||
zbufftest : CFLAGS += -Wno-deprecated-declarations # required to silence deprecation warnings
|
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)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
zbufftest32 : CPPFLAGS += -I$(ZSTDDIR)/deprecated
|
zbufftest32 : CPPFLAGS += -I$(ZSTDDIR)/deprecated
|
||||||
@@ -123,18 +170,22 @@ zbufftest32 : CFLAGS += -Wno-deprecated-declarations -m32
|
|||||||
zbufftest32 : $(ZSTD_FILES) $(ZBUFF_FILES) $(PRGDIR)/datagen.c zbufftest.c
|
zbufftest32 : $(ZSTD_FILES) $(ZBUFF_FILES) $(PRGDIR)/datagen.c zbufftest.c
|
||||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
|
zbufftest-dll : zstd-dll
|
||||||
zbufftest-dll : CPPFLAGS += -I$(ZSTDDIR)/deprecated
|
zbufftest-dll : CPPFLAGS += -I$(ZSTDDIR)/deprecated
|
||||||
zbufftest-dll : CFLAGS += -Wno-deprecated-declarations # required to silence deprecation warnings
|
zbufftest-dll : CFLAGS += -Wno-deprecated-declarations # required to silence deprecation warnings
|
||||||
zbufftest-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
|
zbufftest-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
|
||||||
zbufftest-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c zbufftest.c
|
zbufftest-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c zbufftest.c
|
||||||
$(MAKE) -C $(ZSTDDIR) libzstd
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(filter %.c,$^) $(LDFLAGS) -o $@$(EXT)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(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
|
zstreamtest32 : CFLAGS += -m32
|
||||||
zstreamtest zstreamtest32 : CPPFLAGS += $(MULTITHREAD_CPP)
|
zstreamtest zstreamtest32 : CPPFLAGS += $(MULTITHREAD_CPP)
|
||||||
zstreamtest zstreamtest32 : LDFLAGS += $(MULTITHREAD_LD)
|
zstreamtest zstreamtest32 : LDFLAGS += $(MULTITHREAD_LD)
|
||||||
zstreamtest zstreamtest32 : $(ZSTREAMFILES)
|
zstreamtest : $(ZSTDMT_OBJECTS) $(ZSTREAM_PROPER_FILES)
|
||||||
|
zstreamtest32 : $(ZSTREAMFILES)
|
||||||
|
zstreamtest zstreamtest32 :
|
||||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
zstreamtest_asan : CFLAGS += -fsanitize=address
|
zstreamtest_asan : CFLAGS += -fsanitize=address
|
||||||
@@ -145,54 +196,53 @@ zstreamtest_tsan : CFLAGS += -fsanitize=thread
|
|||||||
zstreamtest_tsan : $(ZSTREAMFILES)
|
zstreamtest_tsan : $(ZSTREAMFILES)
|
||||||
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
||||||
|
|
||||||
|
zstreamtest-dll : zstd-dll
|
||||||
zstreamtest-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
|
zstreamtest-dll : LDFLAGS+= -L$(ZSTDDIR) -lzstd
|
||||||
zstreamtest-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c zstreamtest.c
|
zstreamtest-dll : $(ZSTDDIR)/common/xxhash.c # xxh symbols not exposed from dll
|
||||||
$(MAKE) -C $(ZSTDDIR) libzstd
|
zstreamtest-dll : $(ZSTREAM_LOCAL_FILES)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@$(EXT)
|
$(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
|
paramgrill : $(ZSTD_FILES) $(PRGDIR)/datagen.c paramgrill.c
|
||||||
$(CC) $(FLAGS) $^ -lm -o $@$(EXT)
|
$(CC) $(FLAGS) $^ -lm -o $@$(EXT)
|
||||||
|
|
||||||
datagen : $(PRGDIR)/datagen.c datagencli.c
|
datagen : $(PRGDIR)/datagen.c datagencli.c
|
||||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
roundTripCrash : $(ZSTD_FILES) roundTripCrash.c
|
roundTripCrash : $(ZSTD_OBJECTS) roundTripCrash.c
|
||||||
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
||||||
|
|
||||||
longmatch : $(ZSTD_FILES) longmatch.c
|
longmatch : $(ZSTD_OBJECTS) longmatch.c
|
||||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
invalidDictionaries : $(ZSTD_FILES) invalidDictionaries.c
|
invalidDictionaries : $(ZSTD_OBJECTS) invalidDictionaries.c
|
||||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||||
|
|
||||||
legacy : CFLAGS+= -DZSTD_LEGACY_SUPPORT=4
|
legacy : CPPFLAGS += -I$(ZSTDDIR)/legacy -DZSTD_LEGACY_SUPPORT=4
|
||||||
legacy : CPPFLAGS+= -I$(ZSTDDIR)/legacy
|
|
||||||
legacy : $(ZSTD_FILES) $(wildcard $(ZSTDDIR)/legacy/*.c) legacy.c
|
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
|
decodecorpus : $(filter-out zstdc_zstd_compress.o, $(ZSTD_OBJECTS)) $(ZDICT_FILES) decodecorpus.c
|
||||||
$(CC) $(FLAGS) $^ -o $@$(EXT) -lm
|
$(CC) $(FLAGS) $^ -o $@$(EXT) -lm
|
||||||
|
|
||||||
symbols : symbols.c
|
symbols : symbols.c zstd-dll
|
||||||
$(MAKE) -C $(ZSTDDIR) libzstd
|
|
||||||
ifneq (,$(filter Windows%,$(OS)))
|
ifneq (,$(filter Windows%,$(OS)))
|
||||||
cp $(ZSTDDIR)/dll/libzstd.dll .
|
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
|
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
|
endif
|
||||||
|
|
||||||
poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c $(ZSTDDIR)/common/zstd_common.c $(ZSTDDIR)/common/error_private.c
|
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)
|
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
||||||
|
|
||||||
namespaceTest:
|
.PHONY: versionsTest
|
||||||
if $(CC) namespaceTest.c ../lib/common/xxhash.c -o $@ ; then echo compilation should fail; exit 1 ; fi
|
|
||||||
$(RM) $@
|
|
||||||
|
|
||||||
versionsTest: clean
|
versionsTest: clean
|
||||||
$(PYTHON) test-zstd-versions.py
|
$(PYTHON) test-zstd-versions.py
|
||||||
|
|
||||||
|
checkTag: checkTag.c $(ZSTDDIR)/zstd.h
|
||||||
|
$(CC) $(FLAGS) $< -o $@$(EXT)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C $(ZSTDDIR) clean
|
$(MAKE) -C $(ZSTDDIR) clean
|
||||||
@$(RM) -fR $(TESTARTEFACT)
|
@$(RM) -fR $(TESTARTEFACT)
|
||||||
@@ -205,7 +255,7 @@ clean:
|
|||||||
zstreamtest$(EXT) zstreamtest32$(EXT) \
|
zstreamtest$(EXT) zstreamtest32$(EXT) \
|
||||||
datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) longmatch$(EXT) \
|
datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) longmatch$(EXT) \
|
||||||
symbols$(EXT) invalidDictionaries$(EXT) legacy$(EXT) poolTests$(EXT) \
|
symbols$(EXT) invalidDictionaries$(EXT) legacy$(EXT) poolTests$(EXT) \
|
||||||
decodecorpus$(EXT)
|
decodecorpus$(EXT) checkTag$(EXT)
|
||||||
@echo Cleaning completed
|
@echo Cleaning completed
|
||||||
|
|
||||||
|
|
||||||
@@ -247,15 +297,23 @@ ifneq (,$(filter $(shell uname),SunOS))
|
|||||||
DIFF:=gdiff
|
DIFF:=gdiff
|
||||||
endif
|
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
|
zstd-playTests: datagen
|
||||||
file $(ZSTD)
|
file $(ZSTD)
|
||||||
ZSTD="$(QEMU_SYS) $(ZSTD)" ./playTests.sh $(ZSTDRTTEST)
|
ZSTD="$(QEMU_SYS) $(ZSTD)" ./playTests.sh $(ZSTDRTTEST)
|
||||||
|
|
||||||
|
.PHONY: shortest
|
||||||
shortest: ZSTDRTTEST=
|
shortest: ZSTDRTTEST=
|
||||||
shortest: test-zstd
|
shortest: test-zstd
|
||||||
|
|
||||||
|
.PHONY: fuzztest
|
||||||
fuzztest: test-fuzzer test-zstream test-decodecorpus
|
fuzztest: test-fuzzer test-zstream test-decodecorpus
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
test: test-zstd test-fullbench test-fuzzer test-zstream test-invalidDictionaries test-legacy test-decodecorpus
|
test: test-zstd test-fullbench test-fuzzer test-zstream test-invalidDictionaries test-legacy test-decodecorpus
|
||||||
ifeq ($(QEMU_SYS),)
|
ifeq ($(QEMU_SYS),)
|
||||||
test: test-pool
|
test: test-pool
|
||||||
|
|||||||
@@ -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 <stdio.h> /* printf */
|
||||||
|
#include <string.h> /* 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;
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "util.h" /* Compiler options, UTIL_GetFileSize */
|
#include "util.h" /* Compiler options, UTIL_GetFileSize */
|
||||||
#include <stdlib.h> /* malloc */
|
#include <stdlib.h> /* malloc */
|
||||||
#include <stdio.h> /* fprintf, fopen, ftello64 */
|
#include <stdio.h> /* fprintf, fopen, ftello64 */
|
||||||
|
#include <assert.h> /* assert */
|
||||||
|
|
||||||
#include "mem.h" /* U32 */
|
#include "mem.h" /* U32 */
|
||||||
#ifndef ZSTD_DLL_IMPORT
|
#ifndef ZSTD_DLL_IMPORT
|
||||||
@@ -181,7 +182,7 @@ static size_t local_ZSTD_compress_generic_T2_end(void* dst, size_t dstCapacity,
|
|||||||
ZSTD_inBuffer buffIn;
|
ZSTD_inBuffer buffIn;
|
||||||
(void)buff2;
|
(void)buff2;
|
||||||
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_compressionLevel, 1);
|
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_compressionLevel, 1);
|
||||||
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_nbThreads, 2);
|
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_nbWorkers, 2);
|
||||||
buffOut.dst = dst;
|
buffOut.dst = dst;
|
||||||
buffOut.size = dstCapacity;
|
buffOut.size = dstCapacity;
|
||||||
buffOut.pos = 0;
|
buffOut.pos = 0;
|
||||||
@@ -198,7 +199,7 @@ static size_t local_ZSTD_compress_generic_T2_continue(void* dst, size_t dstCapac
|
|||||||
ZSTD_inBuffer buffIn;
|
ZSTD_inBuffer buffIn;
|
||||||
(void)buff2;
|
(void)buff2;
|
||||||
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_compressionLevel, 1);
|
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_compressionLevel, 1);
|
||||||
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_nbThreads, 2);
|
ZSTD_CCtx_setParameter(g_cstream, ZSTD_p_nbWorkers, 2);
|
||||||
buffOut.dst = dst;
|
buffOut.dst = dst;
|
||||||
buffOut.size = dstCapacity;
|
buffOut.size = dstCapacity;
|
||||||
buffOut.pos = 0;
|
buffOut.pos = 0;
|
||||||
@@ -413,33 +414,48 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* test functions */
|
/* test functions */
|
||||||
/* by convention, test functions can be added > 100 */
|
/* convention: test functions have ID > 100 */
|
||||||
|
|
||||||
default : ;
|
default : ;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ size_t i; for (i=0; i<dstBuffSize; i++) dstBuff[i]=(BYTE)i; } /* warming up memory */
|
/* warming up memory */
|
||||||
|
{ size_t i; for (i=0; i<dstBuffSize; i++) dstBuff[i]=(BYTE)i; }
|
||||||
|
|
||||||
|
/* benchmark loop */
|
||||||
{ U32 loopNb;
|
{ U32 loopNb;
|
||||||
|
U32 nbRounds = (U32)((50 MB) / (srcSize+1)) + 1; /* initial conservative speed estimate */
|
||||||
# define TIME_SEC_MICROSEC (1*1000000ULL) /* 1 second */
|
# define TIME_SEC_MICROSEC (1*1000000ULL) /* 1 second */
|
||||||
U64 const clockLoop = TIMELOOP_S * TIME_SEC_MICROSEC;
|
# define TIME_SEC_NANOSEC (1*1000000000ULL) /* 1 second */
|
||||||
DISPLAY("%2i- %-30.30s : \r", benchNb, benchName);
|
DISPLAY("%2i- %-30.30s : \r", benchNb, benchName);
|
||||||
for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
|
for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
|
||||||
UTIL_time_t clockStart;
|
UTIL_time_t clockStart;
|
||||||
size_t benchResult=0;
|
size_t benchResult=0;
|
||||||
U32 nbRounds;
|
U32 roundNb;
|
||||||
|
|
||||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
UTIL_sleepMilli(5); /* give processor time to other processes */
|
||||||
UTIL_waitForNextTick();
|
UTIL_waitForNextTick();
|
||||||
clockStart = UTIL_getTime();
|
clockStart = UTIL_getTime();
|
||||||
for (nbRounds=0; UTIL_clockSpanMicro(clockStart) < clockLoop; nbRounds++) {
|
for (roundNb=0; roundNb < nbRounds; roundNb++) {
|
||||||
benchResult = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize);
|
benchResult = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize);
|
||||||
if (ZSTD_isError(benchResult)) { DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(benchResult)); exit(1); }
|
if (ZSTD_isError(benchResult)) {
|
||||||
}
|
DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(benchResult));
|
||||||
{ U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart);
|
exit(1);
|
||||||
double const averageTime = (double)clockSpanMicro / TIME_SEC_MICROSEC / nbRounds;
|
} }
|
||||||
|
{ U64 const clockSpanNano = UTIL_clockSpanNano(clockStart);
|
||||||
|
double const averageTime = (double)clockSpanNano / TIME_SEC_NANOSEC / nbRounds;
|
||||||
|
if (clockSpanNano > 0) {
|
||||||
if (averageTime < bestTime) bestTime = averageTime;
|
if (averageTime < bestTime) bestTime = averageTime;
|
||||||
DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r", loopNb, benchName, (double)srcSize / (1 MB) / bestTime, (U32)benchResult);
|
assert(bestTime > (1./2000000000));
|
||||||
|
nbRounds = (U32)(1. / bestTime); /* aim for 1 sec */
|
||||||
|
DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r",
|
||||||
|
loopNb, benchName,
|
||||||
|
(double)srcSize / (1 MB) / bestTime,
|
||||||
|
(U32)benchResult);
|
||||||
|
} else {
|
||||||
|
assert(nbRounds < 40000000); /* avoid overflow */
|
||||||
|
nbRounds *= 100;
|
||||||
|
}
|
||||||
} } }
|
} } }
|
||||||
DISPLAY("%2u\n", benchNb);
|
DISPLAY("%2u\n", benchNb);
|
||||||
|
|
||||||
@@ -573,7 +589,7 @@ int main(int argc, const char** argv)
|
|||||||
|
|
||||||
for(i=1; i<argc; i++) {
|
for(i=1; i<argc; i++) {
|
||||||
const char* argument = argv[i];
|
const char* argument = argv[i];
|
||||||
if(!argument) continue; /* Protection if argument empty */
|
assert(argument != NULL);
|
||||||
|
|
||||||
/* Commands (note : aggregated commands are allowed) */
|
/* Commands (note : aggregated commands are allowed) */
|
||||||
if (argument[0]=='-') {
|
if (argument[0]=='-') {
|
||||||
|
|||||||
@@ -2,4 +2,7 @@
|
|||||||
corpora
|
corpora
|
||||||
block_decompress
|
block_decompress
|
||||||
block_round_trip
|
block_round_trip
|
||||||
|
simple_decompress
|
||||||
simple_round_trip
|
simple_round_trip
|
||||||
|
stream_decompress
|
||||||
|
stream_round_trip
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state)
|
|||||||
cParams.searchLength = FUZZ_rand32(state, ZSTD_SEARCHLENGTH_MIN,
|
cParams.searchLength = FUZZ_rand32(state, ZSTD_SEARCHLENGTH_MIN,
|
||||||
ZSTD_SEARCHLENGTH_MAX);
|
ZSTD_SEARCHLENGTH_MAX);
|
||||||
cParams.targetLength = FUZZ_rand32(state, ZSTD_TARGETLENGTH_MIN,
|
cParams.targetLength = FUZZ_rand32(state, ZSTD_TARGETLENGTH_MIN,
|
||||||
ZSTD_TARGETLENGTH_MAX);
|
512);
|
||||||
cParams.strategy = FUZZ_rand32(state, ZSTD_fast, ZSTD_btultra);
|
cParams.strategy = FUZZ_rand32(state, ZSTD_fast, ZSTD_btultra);
|
||||||
return ZSTD_adjustCParams(cParams, srcSize, 0);
|
return ZSTD_adjustCParams(cParams, srcSize, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include "zdict.h" /* ZDICT_trainFromBuffer */
|
#include "zdict.h" /* ZDICT_trainFromBuffer */
|
||||||
#include "datagen.h" /* RDG_genBuffer */
|
#include "datagen.h" /* RDG_genBuffer */
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#define XXH_STATIC_LINKING_ONLY
|
#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
|
||||||
#include "xxhash.h" /* XXH64 */
|
#include "xxhash.h" /* XXH64 */
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ static const U32 nbTestsDefault = 30000;
|
|||||||
/*-************************************
|
/*-************************************
|
||||||
* Display Macros
|
* Display Macros
|
||||||
**************************************/
|
**************************************/
|
||||||
#define DISPLAY(...) fprintf(stdout, __VA_ARGS__)
|
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||||
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||||
static U32 g_displayLevel = 2;
|
static U32 g_displayLevel = 2;
|
||||||
|
|
||||||
@@ -65,11 +65,18 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
|
|||||||
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
|
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
|
||||||
if (g_displayLevel>=4) fflush(stderr); } }
|
if (g_displayLevel>=4) fflush(stderr); } }
|
||||||
|
|
||||||
/*-*******************************************************
|
|
||||||
* Fuzzer functions
|
|
||||||
*********************************************************/
|
|
||||||
#undef MIN
|
#undef MIN
|
||||||
#undef MAX
|
#undef MAX
|
||||||
|
void FUZ_bug976(void)
|
||||||
|
{ /* 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 MIN(a,b) ((a)<(b)?(a):(b))
|
||||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||||
|
|
||||||
@@ -219,7 +226,7 @@ static int FUZ_mallocTests(unsigned seed, double compressibility, unsigned part)
|
|||||||
ZSTD_outBuffer out = { outBuffer, outSize, 0 };
|
ZSTD_outBuffer out = { outBuffer, outSize, 0 };
|
||||||
ZSTD_inBuffer in = { inBuffer, inSize, 0 };
|
ZSTD_inBuffer in = { inBuffer, inSize, 0 };
|
||||||
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, (U32)compressionLevel) );
|
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, (U32)compressionLevel) );
|
||||||
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbThreads, nbThreads) );
|
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbWorkers, nbThreads) );
|
||||||
while ( ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end) ) {}
|
while ( ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end) ) {}
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
DISPLAYLEVEL(3, "compress_generic,-T%u,end level %i : ",
|
DISPLAYLEVEL(3, "compress_generic,-T%u,end level %i : ",
|
||||||
@@ -239,7 +246,7 @@ static int FUZ_mallocTests(unsigned seed, double compressibility, unsigned part)
|
|||||||
ZSTD_outBuffer out = { outBuffer, outSize, 0 };
|
ZSTD_outBuffer out = { outBuffer, outSize, 0 };
|
||||||
ZSTD_inBuffer in = { inBuffer, inSize, 0 };
|
ZSTD_inBuffer in = { inBuffer, inSize, 0 };
|
||||||
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, (U32)compressionLevel) );
|
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, (U32)compressionLevel) );
|
||||||
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbThreads, nbThreads) );
|
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbWorkers, nbThreads) );
|
||||||
CHECK_Z( ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_continue) );
|
CHECK_Z( ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_continue) );
|
||||||
while ( ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end) ) {}
|
while ( ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end) ) {}
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
@@ -286,91 +293,91 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
RDG_genBuffer(CNBuffer, CNBuffSize, compressibility, 0., seed);
|
RDG_genBuffer(CNBuffer, CNBuffSize, compressibility, 0., seed);
|
||||||
|
|
||||||
/* Basic tests */
|
/* Basic tests */
|
||||||
DISPLAYLEVEL(4, "test%3i : ZSTD_getErrorName : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : ZSTD_getErrorName : ", testNb++);
|
||||||
{ const char* errorString = ZSTD_getErrorName(0);
|
{ 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);
|
{ 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();
|
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||||
if (cctx==NULL) goto _output_error;
|
if (cctx==NULL) goto _output_error;
|
||||||
CHECKPLUS(r, ZSTD_compressCCtx(cctx,
|
CHECKPLUS(r, ZSTD_compressCCtx(cctx,
|
||||||
compressedBuffer, compressedBufferSize,
|
compressedBuffer, compressedBufferSize,
|
||||||
CNBuffer, CNBuffSize, 1),
|
CNBuffer, CNBuffSize, 1),
|
||||||
cSize=r );
|
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);
|
{ 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);
|
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);
|
{ unsigned long long const rSize = ZSTD_getFrameContentSize(compressedBuffer, cSize);
|
||||||
if (rSize != CNBuffSize) goto _output_error;
|
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);
|
{ unsigned long long const rSize = ZSTD_findDecompressedSize(compressedBuffer, cSize);
|
||||||
if (rSize != CNBuffSize) goto _output_error;
|
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);
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize);
|
||||||
if (r != CNBuffSize) goto _output_error; }
|
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;
|
{ size_t u;
|
||||||
for (u=0; u<CNBuffSize; u++) {
|
for (u=0; u<CNBuffSize; u++) {
|
||||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
|
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
|
||||||
} }
|
} }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : decompress with null dict : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress with null dict : ", testNb++);
|
||||||
{ size_t const r = ZSTD_decompress_usingDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, NULL, 0);
|
{ size_t const r = ZSTD_decompress_usingDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, NULL, 0);
|
||||||
if (r != CNBuffSize) goto _output_error; }
|
if (r != CNBuffSize) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : decompress with null DDict : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress with null DDict : ", testNb++);
|
||||||
{ size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, NULL);
|
{ size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, NULL);
|
||||||
if (r != CNBuffSize) goto _output_error; }
|
if (r != CNBuffSize) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : decompress with 1 missing byte : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress with 1 missing byte : ", testNb++);
|
||||||
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize-1);
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize-1);
|
||||||
if (!ZSTD_isError(r)) goto _output_error;
|
if (!ZSTD_isError(r)) goto _output_error;
|
||||||
if (ZSTD_getErrorCode((size_t)r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
if (ZSTD_getErrorCode((size_t)r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : decompress with 1 too much byte : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress with 1 too much byte : ", testNb++);
|
||||||
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize+1);
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize+1);
|
||||||
if (!ZSTD_isError(r)) goto _output_error;
|
if (!ZSTD_isError(r)) goto _output_error;
|
||||||
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%di : check CCtx size after compressing empty input : ", testNb++);
|
DISPLAYLEVEL(3, "test%3d : check CCtx size after compressing empty input : ", testNb++);
|
||||||
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||||
size_t const r = ZSTD_compressCCtx(cctx, compressedBuffer, compressedBufferSize, NULL, 0, 19);
|
size_t const r = ZSTD_compressCCtx(cctx, compressedBuffer, compressedBufferSize, NULL, 0, 19);
|
||||||
if (ZSTD_isError(r)) goto _output_error;
|
if (ZSTD_isError(r)) goto _output_error;
|
||||||
if (ZSTD_sizeof_CCtx(cctx) > (1U << 20)) goto _output_error;
|
if (ZSTD_sizeof_CCtx(cctx) > (1U << 20)) goto _output_error;
|
||||||
ZSTD_freeCCtx(cctx);
|
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_CCtx* const cctx = ZSTD_createCCtx();
|
||||||
ZSTD_parameters const params = ZSTD_getParams(1, ZSTD_CONTENTSIZE_UNKNOWN, 0);
|
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 */
|
assert(params.fParams.contentSizeFlag == 1); /* block size will be adapted if pledgedSrcSize is enabled */
|
||||||
@@ -385,11 +392,26 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
}
|
}
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
|
DISPLAYLEVEL(3, "test%3d : large window log smaller data : ", testNb++);
|
||||||
|
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||||
|
ZSTD_parameters params = ZSTD_getParams(1, ZSTD_CONTENTSIZE_UNKNOWN, 0);
|
||||||
|
size_t const nbCompressions = (1U << 31) / CNBuffSize + 1;
|
||||||
|
size_t i;
|
||||||
|
params.fParams.contentSizeFlag = 0;
|
||||||
|
params.cParams.windowLog = ZSTD_WINDOWLOG_MAX;
|
||||||
|
for (i = 0; i < nbCompressions; ++i) {
|
||||||
|
CHECK_Z( ZSTD_compressBegin_advanced(cctx, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN) ); /* re-use same parameters */
|
||||||
|
CHECK_Z( ZSTD_compressEnd(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBuffSize) );
|
||||||
|
}
|
||||||
|
ZSTD_freeCCtx(cctx);
|
||||||
|
}
|
||||||
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
/* Static CCtx tests */
|
/* Static CCtx tests */
|
||||||
#define STATIC_CCTX_LEVEL 3
|
#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);
|
{ size_t const staticCCtxSize = ZSTD_estimateCStreamSize(STATIC_CCTX_LEVEL);
|
||||||
void* const staticCCtxBuffer = malloc(staticCCtxSize);
|
void* const staticCCtxBuffer = malloc(staticCCtxSize);
|
||||||
size_t const staticDCtxSize = ZSTD_estimateDCtxSize();
|
size_t const staticDCtxSize = ZSTD_estimateDCtxSize();
|
||||||
@@ -404,57 +426,57 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
{ ZSTD_CCtx* staticCCtx = ZSTD_initStaticCCtx(staticCCtxBuffer, staticCCtxSize);
|
{ ZSTD_CCtx* staticCCtx = ZSTD_initStaticCCtx(staticCCtxBuffer, staticCCtxSize);
|
||||||
ZSTD_DCtx* staticDCtx = ZSTD_initStaticDCtx(staticDCtxBuffer, staticDCtxSize);
|
ZSTD_DCtx* staticDCtx = ZSTD_initStaticDCtx(staticDCtxBuffer, staticDCtxSize);
|
||||||
if ((staticCCtx==NULL) || (staticDCtx==NULL)) goto _output_error;
|
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);
|
{ size_t const r = ZSTD_compressBegin(staticCCtx, STATIC_CCTX_LEVEL);
|
||||||
if (ZSTD_isError(r)) goto _output_error; }
|
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,
|
CHECKPLUS(r, ZSTD_compressCCtx(staticCCtx,
|
||||||
compressedBuffer, compressedBufferSize,
|
compressedBuffer, compressedBufferSize,
|
||||||
CNBuffer, CNBuffSize, STATIC_CCTX_LEVEL),
|
CNBuffer, CNBuffSize, STATIC_CCTX_LEVEL),
|
||||||
cSize=r );
|
cSize=r );
|
||||||
DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n",
|
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n",
|
||||||
(U32)cSize, (double)cSize/CNBuffSize*100);
|
(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,
|
{ size_t const r = ZSTD_decompressDCtx(staticDCtx,
|
||||||
decodedBuffer, CNBuffSize,
|
decodedBuffer, CNBuffSize,
|
||||||
compressedBuffer, cSize);
|
compressedBuffer, cSize);
|
||||||
if (r != CNBuffSize) goto _output_error; }
|
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;
|
{ size_t u;
|
||||||
for (u=0; u<CNBuffSize; u++) {
|
for (u=0; u<CNBuffSize; u++) {
|
||||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u])
|
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u])
|
||||||
goto _output_error;;
|
goto _output_error;;
|
||||||
} }
|
} }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : init CCtx for too large level (must fail) : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : init CCtx for too large level (must fail) : ", testNb++);
|
||||||
{ size_t const r = ZSTD_compressBegin(staticCCtx, ZSTD_maxCLevel());
|
{ size_t const r = ZSTD_compressBegin(staticCCtx, ZSTD_maxCLevel());
|
||||||
if (!ZSTD_isError(r)) goto _output_error; }
|
if (!ZSTD_isError(r)) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : init CCtx for small level %u (should work again) : ", testNb++, 1);
|
DISPLAYLEVEL(3, "test%3i : init CCtx for small level %u (should work again) : ", testNb++, 1);
|
||||||
{ size_t const r = ZSTD_compressBegin(staticCCtx, 1);
|
{ size_t const r = ZSTD_compressBegin(staticCCtx, 1);
|
||||||
if (ZSTD_isError(r)) goto _output_error; }
|
if (ZSTD_isError(r)) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : init CStream for small level %u : ", testNb++, 1);
|
DISPLAYLEVEL(3, "test%3i : init CStream for small level %u : ", testNb++, 1);
|
||||||
{ size_t const r = ZSTD_initCStream(staticCCtx, 1);
|
{ size_t const r = ZSTD_initCStream(staticCCtx, 1);
|
||||||
if (ZSTD_isError(r)) goto _output_error; }
|
if (ZSTD_isError(r)) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : init CStream with dictionary (should fail) : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : init CStream with dictionary (should fail) : ", testNb++);
|
||||||
{ size_t const r = ZSTD_initCStream_usingDict(staticCCtx, CNBuffer, 64 KB, 1);
|
{ size_t const r = ZSTD_initCStream_usingDict(staticCCtx, CNBuffer, 64 KB, 1);
|
||||||
if (!ZSTD_isError(r)) goto _output_error; }
|
if (!ZSTD_isError(r)) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : init DStream (should fail) : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : init DStream (should fail) : ", testNb++);
|
||||||
{ size_t const r = ZSTD_initDStream(staticDCtx);
|
{ size_t const r = ZSTD_initDStream(staticDCtx);
|
||||||
if (ZSTD_isError(r)) goto _output_error; }
|
if (ZSTD_isError(r)) goto _output_error; }
|
||||||
{ ZSTD_outBuffer output = { decodedBuffer, CNBuffSize, 0 };
|
{ ZSTD_outBuffer output = { decodedBuffer, CNBuffSize, 0 };
|
||||||
@@ -462,53 +484,52 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
size_t const r = ZSTD_decompressStream(staticDCtx, &output, &input);
|
size_t const r = ZSTD_decompressStream(staticDCtx, &output, &input);
|
||||||
if (!ZSTD_isError(r)) goto _output_error;
|
if (!ZSTD_isError(r)) goto _output_error;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
}
|
}
|
||||||
free(staticCCtxBuffer);
|
free(staticCCtxBuffer);
|
||||||
free(staticDCtxBuffer);
|
free(staticDCtxBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ZSTDMT simple MT compression test */
|
/* ZSTDMT simple MT compression test */
|
||||||
DISPLAYLEVEL(4, "test%3i : create ZSTDMT CCtx : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : create ZSTDMT CCtx : ", testNb++);
|
||||||
{ ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
|
{ ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
|
||||||
if (mtctx==NULL) {
|
if (mtctx==NULL) {
|
||||||
DISPLAY("mtctx : mot enough memory, aborting \n");
|
DISPLAY("mtctx : mot enough memory, aborting \n");
|
||||||
testResult = 1;
|
testResult = 1;
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : compress %u bytes with 2 threads : ", testNb++, (U32)CNBuffSize);
|
DISPLAYLEVEL(3, "test%3i : compress %u bytes with 2 threads : ", testNb++, (U32)CNBuffSize);
|
||||||
CHECKPLUS(r, ZSTDMT_compressCCtx(mtctx,
|
CHECKPLUS(r, ZSTDMT_compressCCtx(mtctx,
|
||||||
compressedBuffer, compressedBufferSize,
|
compressedBuffer, compressedBufferSize,
|
||||||
CNBuffer, CNBuffSize,
|
CNBuffer, CNBuffSize,
|
||||||
1),
|
1),
|
||||||
cSize=r );
|
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 : decompressed size test : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompressed size test : ", testNb++);
|
||||||
{ unsigned long long const rSize = ZSTD_getFrameContentSize(compressedBuffer, cSize);
|
{ unsigned long long const rSize = ZSTD_getFrameContentSize(compressedBuffer, cSize);
|
||||||
if (rSize != CNBuffSize) {
|
if (rSize != CNBuffSize) {
|
||||||
DISPLAY("ZSTD_getFrameContentSize incorrect : %u != %u \n", (U32)rSize, (U32)CNBuffSize);
|
DISPLAY("ZSTD_getFrameContentSize incorrect : %u != %u \n", (U32)rSize, (U32)CNBuffSize);
|
||||||
goto _output_error;
|
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);
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize);
|
||||||
if (r != CNBuffSize) goto _output_error; }
|
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;
|
{ size_t u;
|
||||||
for (u=0; u<CNBuffSize; u++) {
|
for (u=0; u<CNBuffSize; u++) {
|
||||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
|
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
|
||||||
} }
|
} }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : compress -T2 with checksum : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : compress -T2 with checksum : ", testNb++);
|
||||||
{ ZSTD_parameters params = ZSTD_getParams(1, CNBuffSize, 0);
|
{ ZSTD_parameters params = ZSTD_getParams(1, CNBuffSize, 0);
|
||||||
params.fParams.checksumFlag = 1;
|
params.fParams.checksumFlag = 1;
|
||||||
params.fParams.contentSizeFlag = 1;
|
params.fParams.contentSizeFlag = 1;
|
||||||
@@ -518,19 +539,19 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
NULL, params, 3 /*overlapRLog*/),
|
NULL, params, 3 /*overlapRLog*/),
|
||||||
cSize=r );
|
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 : 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);
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize);
|
||||||
if (r != CNBuffSize) goto _output_error; }
|
if (r != CNBuffSize) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
ZSTDMT_freeCCtx(mtctx);
|
ZSTDMT_freeCCtx(mtctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Simple API multiframe test */
|
/* Simple API multiframe test */
|
||||||
DISPLAYLEVEL(4, "test%3i : compress multiple frames : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : compress multiple frames : ", testNb++);
|
||||||
{ size_t off = 0;
|
{ size_t off = 0;
|
||||||
int i;
|
int i;
|
||||||
int const segs = 4;
|
int const segs = 4;
|
||||||
@@ -552,53 +573,53 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
}
|
}
|
||||||
cSize = off;
|
cSize = off;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : get decompressed size of multiple frames : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : get decompressed size of multiple frames : ", testNb++);
|
||||||
{ unsigned long long const r = ZSTD_findDecompressedSize(compressedBuffer, cSize);
|
{ unsigned long long const r = ZSTD_findDecompressedSize(compressedBuffer, cSize);
|
||||||
if (r != CNBuffSize / 2) goto _output_error; }
|
if (r != CNBuffSize / 2) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : decompress multiple frames : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress multiple frames : ", testNb++);
|
||||||
{ CHECK_V(r, ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize));
|
{ CHECK_V(r, ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize));
|
||||||
if (r != CNBuffSize / 2) goto _output_error; }
|
if (r != CNBuffSize / 2) 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++);
|
||||||
if (memcmp(decodedBuffer, CNBuffer, CNBuffSize / 2) != 0) goto _output_error;
|
if (memcmp(decodedBuffer, CNBuffer, CNBuffSize / 2) != 0) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
/* Dictionary and CCtx Duplication tests */
|
/* Dictionary and CCtx Duplication tests */
|
||||||
{ ZSTD_CCtx* const ctxOrig = ZSTD_createCCtx();
|
{ ZSTD_CCtx* const ctxOrig = ZSTD_createCCtx();
|
||||||
ZSTD_CCtx* const ctxDuplicated = ZSTD_createCCtx();
|
ZSTD_CCtx* const ctxDuplicated = ZSTD_createCCtx();
|
||||||
static const size_t dictSize = 551;
|
static const size_t dictSize = 551;
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : copy context too soon : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : copy context too soon : ", testNb++);
|
||||||
{ size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig, 0);
|
{ size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig, 0);
|
||||||
if (!ZSTD_isError(copyResult)) goto _output_error; } /* error must be detected */
|
if (!ZSTD_isError(copyResult)) goto _output_error; } /* error must be detected */
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : load dictionary into context : ", testNb++);
|
||||||
CHECK( ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2) );
|
CHECK( ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2) );
|
||||||
CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig, 0) ); /* Begin_usingDict implies unknown srcSize, so match that */
|
CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig, 0) ); /* Begin_usingDict implies unknown srcSize, so match that */
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : compress with flat dictionary : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : compress with flat dictionary : ", testNb++);
|
||||||
cSize = 0;
|
cSize = 0;
|
||||||
CHECKPLUS(r, ZSTD_compressEnd(ctxOrig, compressedBuffer, compressedBufferSize,
|
CHECKPLUS(r, ZSTD_compressEnd(ctxOrig, compressedBuffer, compressedBufferSize,
|
||||||
(const char*)CNBuffer + dictSize, CNBuffSize - dictSize),
|
(const char*)CNBuffer + dictSize, CNBuffSize - dictSize),
|
||||||
cSize += r);
|
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 : frame built with flat dictionary should be decompressible : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : frame built with flat dictionary should be decompressible : ", testNb++);
|
||||||
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
||||||
decodedBuffer, CNBuffSize,
|
decodedBuffer, CNBuffSize,
|
||||||
compressedBuffer, cSize,
|
compressedBuffer, cSize,
|
||||||
CNBuffer, dictSize),
|
CNBuffer, dictSize),
|
||||||
if (r != CNBuffSize - dictSize) goto _output_error);
|
if (r != CNBuffSize - dictSize) goto _output_error);
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : compress with duplicated context : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : compress with duplicated context : ", testNb++);
|
||||||
{ size_t const cSizeOrig = cSize;
|
{ size_t const cSizeOrig = cSize;
|
||||||
cSize = 0;
|
cSize = 0;
|
||||||
CHECKPLUS(r, ZSTD_compressEnd(ctxDuplicated, compressedBuffer, compressedBufferSize,
|
CHECKPLUS(r, ZSTD_compressEnd(ctxDuplicated, compressedBuffer, compressedBufferSize,
|
||||||
@@ -606,37 +627,37 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
cSize += r);
|
cSize += r);
|
||||||
if (cSize != cSizeOrig) goto _output_error; /* should be identical ==> same size */
|
if (cSize != cSizeOrig) goto _output_error; /* should be identical ==> 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,
|
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
||||||
decodedBuffer, CNBuffSize,
|
decodedBuffer, CNBuffSize,
|
||||||
compressedBuffer, cSize,
|
compressedBuffer, cSize,
|
||||||
CNBuffer, dictSize),
|
CNBuffer, dictSize),
|
||||||
if (r != CNBuffSize - dictSize) goto _output_error);
|
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);
|
{ ZSTD_DDict* const ddict = ZSTD_createDDict(CNBuffer, dictSize);
|
||||||
size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, ddict);
|
size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, ddict);
|
||||||
if (r != CNBuffSize - dictSize) goto _output_error;
|
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);
|
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);
|
{ size_t const ddictBufferSize = ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
|
||||||
void* ddictBuffer = malloc(ddictBufferSize);
|
void* ddictBuffer = malloc(ddictBufferSize);
|
||||||
if (ddictBuffer == NULL) goto _output_error;
|
if (ddictBuffer == NULL) goto _output_error;
|
||||||
{ ZSTD_DDict* const ddict = ZSTD_initStaticDDict(ddictBuffer, ddictBufferSize, CNBuffer, dictSize, ZSTD_dlm_byCopy);
|
{ const ZSTD_DDict* const ddict = ZSTD_initStaticDDict(ddictBuffer, ddictBufferSize, CNBuffer, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
|
||||||
size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, ddict);
|
size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, ddict);
|
||||||
if (r != CNBuffSize - dictSize) goto _output_error;
|
if (r != CNBuffSize - dictSize) goto _output_error;
|
||||||
}
|
}
|
||||||
free(ddictBuffer);
|
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;
|
{ size_t const testSize = CNBuffSize / 3;
|
||||||
{ ZSTD_parameters p = ZSTD_getParams(2, testSize, dictSize);
|
{ ZSTD_parameters p = ZSTD_getParams(2, testSize, dictSize);
|
||||||
p.fParams.contentSizeFlag = 1;
|
p.fParams.contentSizeFlag = 1;
|
||||||
@@ -651,7 +672,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
if (ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize)) goto _output_error;
|
if (ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize)) goto _output_error;
|
||||||
if ((zfh.frameContentSize != testSize) && (zfh.frameContentSize != 0)) 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(ctxOrig);
|
||||||
ZSTD_freeCCtx(ctxDuplicated);
|
ZSTD_freeCCtx(ctxDuplicated);
|
||||||
@@ -659,12 +680,13 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
|
|
||||||
/* Dictionary and dictBuilder tests */
|
/* Dictionary and dictBuilder tests */
|
||||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||||
size_t dictSize = 16 KB;
|
size_t const dictBufferCapacity = 16 KB;
|
||||||
void* dictBuffer = malloc(dictSize);
|
void* dictBuffer = malloc(dictBufferCapacity);
|
||||||
size_t const totalSampleSize = 1 MB;
|
size_t const totalSampleSize = 1 MB;
|
||||||
size_t const sampleUnitSize = 8 KB;
|
size_t const sampleUnitSize = 8 KB;
|
||||||
U32 const nbSamples = (U32)(totalSampleSize / sampleUnitSize);
|
U32 const nbSamples = (U32)(totalSampleSize / sampleUnitSize);
|
||||||
size_t* const samplesSizes = (size_t*) malloc(nbSamples * sizeof(size_t));
|
size_t* const samplesSizes = (size_t*) malloc(nbSamples * sizeof(size_t));
|
||||||
|
size_t dictSize;
|
||||||
U32 dictID;
|
U32 dictID;
|
||||||
|
|
||||||
if (dictBuffer==NULL || samplesSizes==NULL) {
|
if (dictBuffer==NULL || samplesSizes==NULL) {
|
||||||
@@ -673,86 +695,100 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
goto _output_error;
|
goto _output_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : dictBuilder : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : dictBuilder on cyclic data : ", testNb++);
|
||||||
|
assert(compressedBufferSize >= totalSampleSize);
|
||||||
|
{ U32 u; for (u=0; u<totalSampleSize; u++) ((BYTE*)decodedBuffer)[u] = (BYTE)u; }
|
||||||
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
|
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
|
||||||
dictSize = ZDICT_trainFromBuffer(dictBuffer, dictSize,
|
{ size_t const sDictSize = ZDICT_trainFromBuffer(dictBuffer, dictBufferCapacity,
|
||||||
|
decodedBuffer, samplesSizes, nbSamples);
|
||||||
|
if (ZDICT_isError(sDictSize)) goto _output_error;
|
||||||
|
DISPLAYLEVEL(3, "OK, created dictionary of size %u \n", (U32)sDictSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
DISPLAYLEVEL(3, "test%3i : dictBuilder : ", testNb++);
|
||||||
|
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
|
||||||
|
dictSize = ZDICT_trainFromBuffer(dictBuffer, dictBufferCapacity,
|
||||||
CNBuffer, samplesSizes, nbSamples);
|
CNBuffer, samplesSizes, nbSamples);
|
||||||
if (ZDICT_isError(dictSize)) goto _output_error;
|
if (ZDICT_isError(dictSize)) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK, created dictionary of size %u \n", (U32)dictSize);
|
DISPLAYLEVEL(3, "OK, created dictionary of size %u \n", (U32)dictSize);
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : check dictID : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : check dictID : ", testNb++);
|
||||||
dictID = ZDICT_getDictID(dictBuffer, dictSize);
|
dictID = ZDICT_getDictID(dictBuffer, dictSize);
|
||||||
if (dictID==0) goto _output_error;
|
if (dictID==0) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK : %u \n", dictID);
|
DISPLAYLEVEL(3, "OK : %u \n", dictID);
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : compress with dictionary : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : compress with dictionary : ", testNb++);
|
||||||
cSize = ZSTD_compress_usingDict(cctx, compressedBuffer, compressedBufferSize,
|
cSize = ZSTD_compress_usingDict(cctx, compressedBuffer, compressedBufferSize,
|
||||||
CNBuffer, CNBuffSize,
|
CNBuffer, CNBuffSize,
|
||||||
dictBuffer, dictSize, 4);
|
dictBuffer, dictSize, 4);
|
||||||
if (ZSTD_isError(cSize)) goto _output_error;
|
if (ZSTD_isError(cSize)) goto _output_error;
|
||||||
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 : retrieve dictID from dictionary : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : retrieve dictID from dictionary : ", testNb++);
|
||||||
{ U32 const did = ZSTD_getDictID_fromDict(dictBuffer, dictSize);
|
{ U32 const did = ZSTD_getDictID_fromDict(dictBuffer, dictSize);
|
||||||
if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
|
if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : retrieve dictID from frame : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : retrieve dictID from frame : ", testNb++);
|
||||||
{ U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
|
{ U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
|
||||||
if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
|
if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
|
||||||
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
||||||
decodedBuffer, CNBuffSize,
|
decodedBuffer, CNBuffSize,
|
||||||
compressedBuffer, cSize,
|
compressedBuffer, cSize,
|
||||||
dictBuffer, dictSize),
|
dictBuffer, dictSize),
|
||||||
if (r != CNBuffSize) goto _output_error);
|
if (r != CNBuffSize) goto _output_error);
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : estimate CDict size : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : estimate CDict size : ", testNb++);
|
||||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||||
size_t const estimatedSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byRef);
|
size_t const estimatedSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byRef);
|
||||||
DISPLAYLEVEL(4, "OK : %u \n", (U32)estimatedSize);
|
DISPLAYLEVEL(3, "OK : %u \n", (U32)estimatedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : compress with CDict ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : compress with CDict ", testNb++);
|
||||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize,
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize,
|
||||||
ZSTD_dlm_byRef, ZSTD_dm_auto,
|
ZSTD_dlm_byRef, ZSTD_dct_auto,
|
||||||
cParams, ZSTD_defaultCMem);
|
cParams, ZSTD_defaultCMem);
|
||||||
DISPLAYLEVEL(4, "(size : %u) : ", (U32)ZSTD_sizeof_CDict(cdict));
|
DISPLAYLEVEL(3, "(size : %u) : ", (U32)ZSTD_sizeof_CDict(cdict));
|
||||||
cSize = ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize,
|
cSize = ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize,
|
||||||
CNBuffer, CNBuffSize, cdict);
|
CNBuffer, CNBuffSize, cdict);
|
||||||
ZSTD_freeCDict(cdict);
|
ZSTD_freeCDict(cdict);
|
||||||
if (ZSTD_isError(cSize)) goto _output_error;
|
if (ZSTD_isError(cSize)) goto _output_error;
|
||||||
}
|
}
|
||||||
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 : retrieve dictID from frame : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : retrieve dictID from frame : ", testNb++);
|
||||||
{ U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
|
{ U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
|
||||||
if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
|
if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
|
||||||
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
||||||
decodedBuffer, CNBuffSize,
|
decodedBuffer, CNBuffSize,
|
||||||
compressedBuffer, cSize,
|
compressedBuffer, cSize,
|
||||||
dictBuffer, dictSize),
|
dictBuffer, dictSize),
|
||||||
if (r != CNBuffSize) goto _output_error);
|
if (r != CNBuffSize) goto _output_error);
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : compress with static CDict : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : compress with static CDict : ", testNb++);
|
||||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
{ int const maxLevel = ZSTD_maxCLevel();
|
||||||
|
int level;
|
||||||
|
for (level = 1; level <= maxLevel; ++level) {
|
||||||
|
ZSTD_compressionParameters const cParams = ZSTD_getCParams(level, CNBuffSize, dictSize);
|
||||||
size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
|
size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
|
||||||
void* const cdictBuffer = malloc(cdictSize);
|
void* const cdictBuffer = malloc(cdictSize);
|
||||||
if (cdictBuffer==NULL) goto _output_error;
|
if (cdictBuffer==NULL) goto _output_error;
|
||||||
{ ZSTD_CDict* const cdict = ZSTD_initStaticCDict(cdictBuffer, cdictSize,
|
{ const ZSTD_CDict* const cdict = ZSTD_initStaticCDict(
|
||||||
|
cdictBuffer, cdictSize,
|
||||||
dictBuffer, dictSize,
|
dictBuffer, dictSize,
|
||||||
ZSTD_dlm_byCopy, ZSTD_dm_auto,
|
ZSTD_dlm_byCopy, ZSTD_dct_auto,
|
||||||
cParams);
|
cParams);
|
||||||
if (cdict == NULL) {
|
if (cdict == NULL) {
|
||||||
DISPLAY("ZSTD_initStaticCDict failed ");
|
DISPLAY("ZSTD_initStaticCDict failed ");
|
||||||
@@ -760,41 +796,41 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
}
|
}
|
||||||
cSize = ZSTD_compress_usingCDict(cctx,
|
cSize = ZSTD_compress_usingCDict(cctx,
|
||||||
compressedBuffer, compressedBufferSize,
|
compressedBuffer, compressedBufferSize,
|
||||||
CNBuffer, CNBuffSize, cdict);
|
CNBuffer, MIN(10 KB, CNBuffSize), cdict);
|
||||||
if (ZSTD_isError(cSize)) {
|
if (ZSTD_isError(cSize)) {
|
||||||
DISPLAY("ZSTD_compress_usingCDict failed ");
|
DISPLAY("ZSTD_compress_usingCDict failed ");
|
||||||
goto _output_error;
|
goto _output_error;
|
||||||
} }
|
} }
|
||||||
free(cdictBuffer);
|
free(cdictBuffer);
|
||||||
}
|
} }
|
||||||
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 : ZSTD_compress_usingCDict_advanced, no contentSize, no dictID : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : ZSTD_compress_usingCDict_advanced, no contentSize, no dictID : ", testNb++);
|
||||||
{ ZSTD_frameParameters const fParams = { 0 /* frameSize */, 1 /* checksum */, 1 /* noDictID*/ };
|
{ ZSTD_frameParameters const fParams = { 0 /* frameSize */, 1 /* checksum */, 1 /* noDictID*/ };
|
||||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, ZSTD_defaultCMem);
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem);
|
||||||
cSize = ZSTD_compress_usingCDict_advanced(cctx, compressedBuffer, compressedBufferSize,
|
cSize = ZSTD_compress_usingCDict_advanced(cctx, compressedBuffer, compressedBufferSize,
|
||||||
CNBuffer, CNBuffSize, cdict, fParams);
|
CNBuffer, CNBuffSize, cdict, fParams);
|
||||||
ZSTD_freeCDict(cdict);
|
ZSTD_freeCDict(cdict);
|
||||||
if (ZSTD_isError(cSize)) goto _output_error;
|
if (ZSTD_isError(cSize)) goto _output_error;
|
||||||
}
|
}
|
||||||
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 : try retrieving contentSize from frame : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : try retrieving contentSize from frame : ", testNb++);
|
||||||
{ U64 const contentSize = ZSTD_getFrameContentSize(compressedBuffer, cSize);
|
{ U64 const contentSize = ZSTD_getFrameContentSize(compressedBuffer, cSize);
|
||||||
if (contentSize != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
|
if (contentSize != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK (unknown)\n");
|
DISPLAYLEVEL(3, "OK (unknown)\n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : frame built without dictID should be decompressible : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : frame built without dictID should be decompressible : ", testNb++);
|
||||||
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
||||||
decodedBuffer, CNBuffSize,
|
decodedBuffer, CNBuffSize,
|
||||||
compressedBuffer, cSize,
|
compressedBuffer, cSize,
|
||||||
dictBuffer, dictSize),
|
dictBuffer, dictSize),
|
||||||
if (r != CNBuffSize) goto _output_error);
|
if (r != CNBuffSize) goto _output_error);
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : ZSTD_compress_advanced, no dictID : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : ZSTD_compress_advanced, no dictID : ", testNb++);
|
||||||
{ ZSTD_parameters p = ZSTD_getParams(3, CNBuffSize, dictSize);
|
{ ZSTD_parameters p = ZSTD_getParams(3, CNBuffSize, dictSize);
|
||||||
p.fParams.noDictIDFlag = 1;
|
p.fParams.noDictIDFlag = 1;
|
||||||
cSize = ZSTD_compress_advanced(cctx, compressedBuffer, compressedBufferSize,
|
cSize = ZSTD_compress_advanced(cctx, compressedBuffer, compressedBufferSize,
|
||||||
@@ -802,62 +838,62 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
dictBuffer, dictSize, p);
|
dictBuffer, dictSize, p);
|
||||||
if (ZSTD_isError(cSize)) goto _output_error;
|
if (ZSTD_isError(cSize)) goto _output_error;
|
||||||
}
|
}
|
||||||
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 without dictID should be decompressible : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : frame built without dictID should be decompressible : ", testNb++);
|
||||||
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
|
||||||
decodedBuffer, CNBuffSize,
|
decodedBuffer, CNBuffSize,
|
||||||
compressedBuffer, cSize,
|
compressedBuffer, cSize,
|
||||||
dictBuffer, dictSize),
|
dictBuffer, dictSize),
|
||||||
if (r != CNBuffSize) goto _output_error);
|
if (r != CNBuffSize) goto _output_error);
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : dictionary containing only header should return error : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : dictionary containing only header should return error : ", testNb++);
|
||||||
{
|
{
|
||||||
const size_t ret = ZSTD_decompress_usingDict(
|
const size_t ret = ZSTD_decompress_usingDict(
|
||||||
dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize,
|
dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize,
|
||||||
"\x37\xa4\x30\xec\x11\x22\x33\x44", 8);
|
"\x37\xa4\x30\xec\x11\x22\x33\x44", 8);
|
||||||
if (ZSTD_getErrorCode(ret) != ZSTD_error_dictionary_corrupted) goto _output_error;
|
if (ZSTD_getErrorCode(ret) != ZSTD_error_dictionary_corrupted) goto _output_error;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a good dictionary : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a good dictionary : ", testNb++);
|
||||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
|
||||||
if (cdict==NULL) goto _output_error;
|
if (cdict==NULL) goto _output_error;
|
||||||
ZSTD_freeCDict(cdict);
|
ZSTD_freeCDict(cdict);
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a rawContent (must fail) : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a rawContent (must fail) : ", testNb++);
|
||||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced((const char*)dictBuffer+1, dictSize-1, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced((const char*)dictBuffer+1, dictSize-1, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
|
||||||
if (cdict!=NULL) goto _output_error;
|
if (cdict!=NULL) goto _output_error;
|
||||||
ZSTD_freeCDict(cdict);
|
ZSTD_freeCDict(cdict);
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_auto should fail : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_auto should fail : ", testNb++);
|
||||||
{
|
{
|
||||||
size_t ret;
|
size_t ret;
|
||||||
MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY);
|
MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY);
|
||||||
ret = ZSTD_CCtx_loadDictionary_advanced(
|
ret = ZSTD_CCtx_loadDictionary_advanced(
|
||||||
cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_auto);
|
cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dct_auto);
|
||||||
if (!ZSTD_isError(ret)) goto _output_error;
|
if (!ZSTD_isError(ret)) goto _output_error;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_rawContent should pass : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_rawContent should pass : ", testNb++);
|
||||||
{
|
{
|
||||||
size_t ret;
|
size_t ret;
|
||||||
MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY);
|
MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY);
|
||||||
ret = ZSTD_CCtx_loadDictionary_advanced(
|
ret = ZSTD_CCtx_loadDictionary_advanced(
|
||||||
cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_rawContent);
|
cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dct_rawContent);
|
||||||
if (ZSTD_isError(ret)) goto _output_error;
|
if (ZSTD_isError(ret)) goto _output_error;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : Dictionary with non-default repcodes : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Dictionary with non-default repcodes : ", testNb++);
|
||||||
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
|
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
|
||||||
dictSize = ZDICT_trainFromBuffer(dictBuffer, dictSize,
|
dictSize = ZDICT_trainFromBuffer(dictBuffer, dictSize,
|
||||||
CNBuffer, samplesSizes, nbSamples);
|
CNBuffer, samplesSizes, nbSamples);
|
||||||
@@ -888,7 +924,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
BYTE data[1024];
|
BYTE data[1024];
|
||||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(19, CNBuffSize, dictSize);
|
ZSTD_compressionParameters const cParams = ZSTD_getCParams(19, CNBuffSize, dictSize);
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize,
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize,
|
||||||
ZSTD_dlm_byRef, ZSTD_dm_auto,
|
ZSTD_dlm_byRef, ZSTD_dct_auto,
|
||||||
cParams, ZSTD_defaultCMem);
|
cParams, ZSTD_defaultCMem);
|
||||||
memset(data, 'x', sizeof(data));
|
memset(data, 'x', sizeof(data));
|
||||||
cSize = ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize,
|
cSize = ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize,
|
||||||
@@ -899,7 +935,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
if (ZSTD_isError(dSize)) { DISPLAYLEVEL(5, "Decompression error %s : ", ZSTD_getErrorName(dSize)); goto _output_error; }
|
if (ZSTD_isError(dSize)) { DISPLAYLEVEL(5, "Decompression error %s : ", ZSTD_getErrorName(dSize)); goto _output_error; }
|
||||||
if (memcmp(data, decodedBuffer, sizeof(data))) { DISPLAYLEVEL(5, "Data corruption : "); goto _output_error; }
|
if (memcmp(data, decodedBuffer, sizeof(data))) { DISPLAYLEVEL(5, "Data corruption : "); goto _output_error; }
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
free(dictBuffer);
|
free(dictBuffer);
|
||||||
@@ -924,7 +960,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
goto _output_error;
|
goto _output_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : ZDICT_trainFromBuffer_cover : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : ZDICT_trainFromBuffer_cover : ", testNb++);
|
||||||
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
|
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
params.d = 1 + (FUZ_rand(&seed) % 16);
|
params.d = 1 + (FUZ_rand(&seed) % 16);
|
||||||
@@ -933,26 +969,26 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
CNBuffer, samplesSizes, nbSamples,
|
CNBuffer, samplesSizes, nbSamples,
|
||||||
params);
|
params);
|
||||||
if (ZDICT_isError(dictSize)) goto _output_error;
|
if (ZDICT_isError(dictSize)) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK, created dictionary of size %u \n", (U32)dictSize);
|
DISPLAYLEVEL(3, "OK, created dictionary of size %u \n", (U32)dictSize);
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : check dictID : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : check dictID : ", testNb++);
|
||||||
dictID = ZDICT_getDictID(dictBuffer, dictSize);
|
dictID = ZDICT_getDictID(dictBuffer, dictSize);
|
||||||
if (dictID==0) goto _output_error;
|
if (dictID==0) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK : %u \n", dictID);
|
DISPLAYLEVEL(3, "OK : %u \n", dictID);
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : ZDICT_optimizeTrainFromBuffer_cover : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : ZDICT_optimizeTrainFromBuffer_cover : ", testNb++);
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
params.steps = 4;
|
params.steps = 4;
|
||||||
optDictSize = ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, optDictSize,
|
optDictSize = ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, optDictSize,
|
||||||
CNBuffer, samplesSizes,
|
CNBuffer, samplesSizes,
|
||||||
nbSamples / 4, ¶ms);
|
nbSamples / 4, ¶ms);
|
||||||
if (ZDICT_isError(optDictSize)) goto _output_error;
|
if (ZDICT_isError(optDictSize)) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK, created dictionary of size %u \n", (U32)optDictSize);
|
DISPLAYLEVEL(3, "OK, created dictionary of size %u \n", (U32)optDictSize);
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : check dictID : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : check dictID : ", testNb++);
|
||||||
dictID = ZDICT_getDictID(dictBuffer, optDictSize);
|
dictID = ZDICT_getDictID(dictBuffer, optDictSize);
|
||||||
if (dictID==0) goto _output_error;
|
if (dictID==0) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK : %u \n", dictID);
|
DISPLAYLEVEL(3, "OK : %u \n", dictID);
|
||||||
|
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
free(dictBuffer);
|
free(dictBuffer);
|
||||||
@@ -960,20 +996,20 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Decompression defense tests */
|
/* Decompression defense tests */
|
||||||
DISPLAYLEVEL(4, "test%3i : Check input length for magic number : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Check input length for magic number : ", testNb++);
|
||||||
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 3); /* too small input */
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 3); /* too small input */
|
||||||
if (!ZSTD_isError(r)) goto _output_error;
|
if (!ZSTD_isError(r)) goto _output_error;
|
||||||
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
DISPLAYLEVEL(4, "test%3i : Check magic Number : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Check magic Number : ", testNb++);
|
||||||
((char*)(CNBuffer))[0] = 1;
|
((char*)(CNBuffer))[0] = 1;
|
||||||
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 4);
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 4);
|
||||||
if (!ZSTD_isError(r)) goto _output_error; }
|
if (!ZSTD_isError(r)) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
/* content size verification test */
|
/* content size verification test */
|
||||||
DISPLAYLEVEL(4, "test%3i : Content size verification : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : Content size verification : ", testNb++);
|
||||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||||
size_t const srcSize = 5000;
|
size_t const srcSize = 5000;
|
||||||
size_t const wrongSrcSize = (srcSize + 1000);
|
size_t const wrongSrcSize = (srcSize + 1000);
|
||||||
@@ -983,17 +1019,56 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
{ size_t const result = ZSTD_compressEnd(cctx, decodedBuffer, CNBuffSize, CNBuffer, srcSize);
|
{ size_t const result = ZSTD_compressEnd(cctx, decodedBuffer, CNBuffSize, CNBuffer, srcSize);
|
||||||
if (!ZSTD_isError(result)) goto _output_error;
|
if (!ZSTD_isError(result)) goto _output_error;
|
||||||
if (ZSTD_getErrorCode(result) != ZSTD_error_srcSize_wrong) goto _output_error;
|
if (ZSTD_getErrorCode(result) != ZSTD_error_srcSize_wrong) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK : %s \n", ZSTD_getErrorName(result));
|
DISPLAYLEVEL(3, "OK : %s \n", ZSTD_getErrorName(result));
|
||||||
}
|
}
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* parameters order test */
|
||||||
|
{ size_t const inputSize = CNBuffSize / 2;
|
||||||
|
U64 xxh64;
|
||||||
|
|
||||||
|
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||||
|
DISPLAYLEVEL(3, "test%3i : parameters in order : ", testNb++);
|
||||||
|
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, 2) );
|
||||||
|
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_enableLongDistanceMatching, 1) );
|
||||||
|
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_windowLog, 18) );
|
||||||
|
{ ZSTD_inBuffer in = { CNBuffer, inputSize, 0 };
|
||||||
|
ZSTD_outBuffer out = { compressedBuffer, ZSTD_compressBound(inputSize), 0 };
|
||||||
|
size_t const result = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||||
|
if (result != 0) goto _output_error;
|
||||||
|
if (in.pos != in.size) goto _output_error;
|
||||||
|
cSize = out.pos;
|
||||||
|
xxh64 = XXH64(out.dst, out.pos, 0);
|
||||||
|
}
|
||||||
|
DISPLAYLEVEL(3, "OK (compress : %u -> %u bytes)\n", (U32)inputSize, (U32)cSize);
|
||||||
|
ZSTD_freeCCtx(cctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||||
|
DISPLAYLEVEL(3, "test%3i : parameters disordered : ", testNb++);
|
||||||
|
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_windowLog, 18) );
|
||||||
|
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_enableLongDistanceMatching, 1) );
|
||||||
|
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, 2) );
|
||||||
|
{ ZSTD_inBuffer in = { CNBuffer, inputSize, 0 };
|
||||||
|
ZSTD_outBuffer out = { compressedBuffer, ZSTD_compressBound(inputSize), 0 };
|
||||||
|
size_t const result = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||||
|
if (result != 0) goto _output_error;
|
||||||
|
if (in.pos != in.size) goto _output_error;
|
||||||
|
if (out.pos != cSize) goto _output_error; /* must result in same compressed result, hence same size */
|
||||||
|
if (XXH64(out.dst, out.pos, 0) != xxh64) goto _output_error; /* must result in exactly same content, hence same hash */
|
||||||
|
DISPLAYLEVEL(3, "OK (compress : %u -> %u bytes)\n", (U32)inputSize, (U32)out.pos);
|
||||||
|
}
|
||||||
|
ZSTD_freeCCtx(cctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* custom formats tests */
|
/* custom formats tests */
|
||||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||||
size_t const inputSize = CNBuffSize / 2; /* won't cause pb with small dict size */
|
size_t const inputSize = CNBuffSize / 2; /* won't cause pb with small dict size */
|
||||||
|
|
||||||
/* basic block compression */
|
/* basic block compression */
|
||||||
DISPLAYLEVEL(4, "test%3i : magic-less format test : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : magic-less format test : ", testNb++);
|
||||||
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_format, ZSTD_f_zstd1_magicless) );
|
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_format, ZSTD_f_zstd1_magicless) );
|
||||||
{ ZSTD_inBuffer in = { CNBuffer, inputSize, 0 };
|
{ ZSTD_inBuffer in = { CNBuffer, inputSize, 0 };
|
||||||
ZSTD_outBuffer out = { compressedBuffer, ZSTD_compressBound(inputSize), 0 };
|
ZSTD_outBuffer out = { compressedBuffer, ZSTD_compressBound(inputSize), 0 };
|
||||||
@@ -1002,15 +1077,15 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
if (in.pos != in.size) goto _output_error;
|
if (in.pos != in.size) goto _output_error;
|
||||||
cSize = out.pos;
|
cSize = out.pos;
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK (compress : %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);
|
{ size_t const decodeResult = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize);
|
||||||
if (ZSTD_getErrorCode(decodeResult) != ZSTD_error_prefix_unknown) goto _output_error;
|
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);
|
ZSTD_DCtx_reset(dctx);
|
||||||
CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) );
|
CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) );
|
||||||
{ ZSTD_inBuffer in = { compressedBuffer, cSize, 0 };
|
{ ZSTD_inBuffer in = { compressedBuffer, cSize, 0 };
|
||||||
@@ -1019,7 +1094,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
if (result != 0) goto _output_error;
|
if (result != 0) goto _output_error;
|
||||||
if (in.pos != in.size) goto _output_error;
|
if (in.pos != in.size) goto _output_error;
|
||||||
if (out.pos != inputSize) 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);
|
ZSTD_freeCCtx(cctx);
|
||||||
@@ -1032,21 +1107,21 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
size_t cSize2;
|
size_t cSize2;
|
||||||
|
|
||||||
/* basic block compression */
|
/* 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_compressBegin(cctx, 5) );
|
||||||
CHECK( ZSTD_getBlockSize(cctx) >= blockSize);
|
CHECK( ZSTD_getBlockSize(cctx) >= blockSize);
|
||||||
cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
|
cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
|
||||||
if (ZSTD_isError(cSize)) goto _output_error;
|
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( ZSTD_decompressBegin(dctx) );
|
||||||
{ CHECK_V(r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
|
{ CHECK_V(r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
|
||||||
if (r != blockSize) goto _output_error; }
|
if (r != blockSize) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
/* dictionary block compression */
|
/* 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) );
|
CHECK( ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5) );
|
||||||
cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
|
cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
|
||||||
if (ZSTD_isError(cSize)) goto _output_error;
|
if (ZSTD_isError(cSize)) goto _output_error;
|
||||||
@@ -1056,16 +1131,16 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
cSize2 = ZSTD_compressBlock(cctx, (char*)compressedBuffer+cSize+blockSize, ZSTD_compressBound(blockSize),
|
cSize2 = ZSTD_compressBlock(cctx, (char*)compressedBuffer+cSize+blockSize, ZSTD_compressBound(blockSize),
|
||||||
(char*)CNBuffer+dictSize+2*blockSize, blockSize);
|
(char*)CNBuffer+dictSize+2*blockSize, blockSize);
|
||||||
if (ZSTD_isError(cSize2)) goto _output_error;
|
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( ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize) );
|
||||||
{ CHECK_V( r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
|
{ CHECK_V( r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
|
||||||
if (r != blockSize) goto _output_error; }
|
if (r != blockSize) goto _output_error; }
|
||||||
ZSTD_insertBlock(dctx, (char*)decodedBuffer+blockSize, blockSize); /* insert non-compressed block into dctx history */
|
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) );
|
{ CHECK_V( r, ZSTD_decompressBlock(dctx, (char*)decodedBuffer+2*blockSize, CNBuffSize, (char*)compressedBuffer+cSize+blockSize, cSize2) );
|
||||||
if (r != blockSize) goto _output_error; }
|
if (r != blockSize) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
ZSTD_freeCCtx(cctx);
|
ZSTD_freeCCtx(cctx);
|
||||||
}
|
}
|
||||||
@@ -1073,7 +1148,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
|
|
||||||
/* long rle test */
|
/* long rle test */
|
||||||
{ size_t sampleSize = 0;
|
{ 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);
|
RDG_genBuffer(CNBuffer, sampleSize, compressibility, 0., seed+1);
|
||||||
memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
|
memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
|
||||||
sampleSize += 256 KB - 1;
|
sampleSize += 256 KB - 1;
|
||||||
@@ -1083,21 +1158,21 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
if (ZSTD_isError(cSize)) goto _output_error;
|
if (ZSTD_isError(cSize)) goto _output_error;
|
||||||
{ CHECK_V(regenSize, ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize));
|
{ CHECK_V(regenSize, ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize));
|
||||||
if (regenSize!=sampleSize) goto _output_error; }
|
if (regenSize!=sampleSize) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All zeroes test (test bug #137) */
|
/* All zeroes test (test bug #137) */
|
||||||
#define ZEROESLENGTH 100
|
#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);
|
memset(CNBuffer, 0, ZEROESLENGTH);
|
||||||
{ CHECK_V(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1) );
|
{ CHECK_V(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1) );
|
||||||
cSize = r; }
|
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) );
|
{ CHECK_V(r, ZSTD_decompress(decodedBuffer, ZEROESLENGTH, compressedBuffer, cSize) );
|
||||||
if (r != ZEROESLENGTH) goto _output_error; }
|
if (r != ZEROESLENGTH) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
/* nbSeq limit test */
|
/* nbSeq limit test */
|
||||||
#define _3BYTESTESTLENGTH 131000
|
#define _3BYTESTESTLENGTH 131000
|
||||||
@@ -1124,18 +1199,18 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
|
((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
|
||||||
((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
|
((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),
|
{ CHECK_V(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH),
|
||||||
CNBuffer, _3BYTESTESTLENGTH, 19) );
|
CNBuffer, _3BYTESTESTLENGTH, 19) );
|
||||||
cSize = r; }
|
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) );
|
{ CHECK_V(r, ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize) );
|
||||||
if (r != _3BYTESTESTLENGTH) goto _output_error; }
|
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);
|
RDG_genBuffer(CNBuffer, CNBuffSize, 0.0, 0.1, seed);
|
||||||
{ /* Train a dictionary on low characters */
|
{ /* Train a dictionary on low characters */
|
||||||
size_t dictSize = 16 KB;
|
size_t dictSize = 16 KB;
|
||||||
@@ -1168,25 +1243,48 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
free(dictBuffer);
|
free(dictBuffer);
|
||||||
free(samplesSizes);
|
free(samplesSizes);
|
||||||
}
|
}
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
|
|
||||||
/* findFrameCompressedSize on skippable frames */
|
/* 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";
|
{ const char* frame = "\x50\x2a\x4d\x18\x05\x0\x0\0abcde";
|
||||||
size_t const frameSrcSize = 13;
|
size_t const frameSrcSize = 13;
|
||||||
if (ZSTD_findFrameCompressedSize(frame, frameSrcSize) != frameSrcSize) goto _output_error; }
|
if (ZSTD_findFrameCompressedSize(frame, frameSrcSize) != frameSrcSize) goto _output_error; }
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
/* error string tests */
|
/* 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_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("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("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_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("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;
|
if (strcmp("No error detected", ZSTD_getErrorName(ZSTD_error_GENERIC)) != 0) goto _output_error;
|
||||||
DISPLAYLEVEL(4, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
|
DISPLAYLEVEL(3, "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);
|
||||||
|
}
|
||||||
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
_end:
|
_end:
|
||||||
free(CNBuffer);
|
free(CNBuffer);
|
||||||
@@ -1338,10 +1436,14 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
crcOrig = XXH64(sampleBuffer, sampleSize, 0);
|
crcOrig = XXH64(sampleBuffer, sampleSize, 0);
|
||||||
|
|
||||||
/* compression tests */
|
/* compression tests */
|
||||||
{ unsigned const cLevel =
|
{ int const cLevelPositive =
|
||||||
( FUZ_rand(&lseed) %
|
( FUZ_rand(&lseed) %
|
||||||
(ZSTD_maxCLevel() - (FUZ_highbit32((U32)sampleSize) / cLevelLimiter)) )
|
(ZSTD_maxCLevel() - (FUZ_highbit32((U32)sampleSize) / cLevelLimiter)) )
|
||||||
+ 1;
|
+ 1;
|
||||||
|
int const cLevel = ((FUZ_rand(&lseed) & 15) == 3) ?
|
||||||
|
- (int)((FUZ_rand(&lseed) & 7) + 1) : /* test negative cLevel */
|
||||||
|
cLevelPositive;
|
||||||
|
DISPLAYLEVEL(5, "fuzzer t%u: Simple compression test (level %i) \n", testNb, cLevel);
|
||||||
cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
|
cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
|
||||||
CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed : %s", ZSTD_getErrorName(cSize));
|
CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed : %s", ZSTD_getErrorName(cSize));
|
||||||
|
|
||||||
@@ -1369,6 +1471,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* successful decompression test */
|
/* 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 margin = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
|
||||||
size_t const dSize = ZSTD_decompress(dstBuffer, sampleSize + margin, cBuffer, cSize);
|
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);
|
CHECK(dSize != sampleSize, "ZSTD_decompress failed (%s) (srcSize : %u ; cSize : %u)", ZSTD_getErrorName(dSize), (U32)sampleSize, (U32)cSize);
|
||||||
@@ -1379,6 +1482,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
free(sampleBuffer); /* no longer useful after this point */
|
free(sampleBuffer); /* no longer useful after this point */
|
||||||
|
|
||||||
/* truncated src decompression test */
|
/* 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 missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
|
||||||
size_t const tooSmallSize = cSize - missing;
|
size_t const tooSmallSize = cSize - missing;
|
||||||
void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch read overflows */
|
void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch read overflows */
|
||||||
@@ -1390,6 +1494,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* too small dst decompression test */
|
/* too small dst decompression test */
|
||||||
|
DISPLAYLEVEL(5, "fuzzer t%u: decompress into too small dst buffer \n", testNb);
|
||||||
if (sampleSize > 3) {
|
if (sampleSize > 3) {
|
||||||
size_t const missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
|
size_t const missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
|
||||||
size_t const tooSmallSize = sampleSize - missing;
|
size_t const tooSmallSize = sampleSize - missing;
|
||||||
@@ -1412,7 +1517,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
size_t const skipLength = FUZ_rand(&lseed) & mask;
|
size_t const skipLength = FUZ_rand(&lseed) & mask;
|
||||||
pos += skipLength;
|
pos += skipLength;
|
||||||
}
|
}
|
||||||
if (pos <= cSize) break;
|
if (pos >= cSize) break;
|
||||||
/* add noise */
|
/* add noise */
|
||||||
{ U32 const nbBitsCodes = FUZ_rand(&lseed) % maxNbBits;
|
{ U32 const nbBitsCodes = FUZ_rand(&lseed) % maxNbBits;
|
||||||
U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
|
U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
|
||||||
@@ -1425,6 +1530,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
} } }
|
} } }
|
||||||
|
|
||||||
/* decompress noisy source */
|
/* decompress noisy source */
|
||||||
|
DISPLAYLEVEL(5, "fuzzer t%u: decompress noisy source \n", testNb);
|
||||||
{ U32 const endMark = 0xA9B1C3D6;
|
{ U32 const endMark = 0xA9B1C3D6;
|
||||||
memcpy(dstBuffer+sampleSize, &endMark, 4);
|
memcpy(dstBuffer+sampleSize, &endMark, 4);
|
||||||
{ size_t const decompressResult = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
|
{ size_t const decompressResult = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
|
||||||
@@ -1436,8 +1542,8 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
|
CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
|
||||||
} } } /* noisy src decompression test */
|
} } } /* 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 testLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||||
U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
|
U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||||
int const cLevel = (FUZ_rand(&lseed) %
|
int const cLevel = (FUZ_rand(&lseed) %
|
||||||
@@ -1450,10 +1556,13 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
dictSize = FUZ_rLogLength(&lseed, dictLog); /* needed also for decompression */
|
dictSize = FUZ_rLogLength(&lseed, dictLog); /* needed also for decompression */
|
||||||
dict = srcBuffer + (FUZ_rand(&lseed) % (srcBufferSize - dictSize));
|
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) {
|
if (FUZ_rand(&lseed) & 0xF) {
|
||||||
CHECK_Z ( ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel) );
|
CHECK_Z ( ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel) );
|
||||||
} else {
|
} 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 */,
|
ZSTD_frameParameters const fPar = { FUZ_rand(&lseed)&1 /* contentSizeFlag */,
|
||||||
!(FUZ_rand(&lseed)&3) /* contentChecksumFlag*/,
|
!(FUZ_rand(&lseed)&3) /* contentChecksumFlag*/,
|
||||||
0 /*NodictID*/ }; /* note : since dictionary is fake, dictIDflag has no impact */
|
0 /*NodictID*/ }; /* note : since dictionary is fake, dictIDflag has no impact */
|
||||||
@@ -1491,6 +1600,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* streaming decompression test */
|
/* streaming decompression test */
|
||||||
|
DISPLAYLEVEL(5, "fuzzer t%u: Bufferless streaming decompression test \n", testNb);
|
||||||
/* ensure memory requirement is good enough (should always be true) */
|
/* ensure memory requirement is good enough (should always be true) */
|
||||||
{ ZSTD_frameHeader zfh;
|
{ ZSTD_frameHeader zfh;
|
||||||
CHECK( ZSTD_getFrameHeader(&zfh, cBuffer, ZSTD_frameHeaderSize_max),
|
CHECK( ZSTD_getFrameHeader(&zfh, cBuffer, ZSTD_frameHeaderSize_max),
|
||||||
@@ -1633,7 +1743,7 @@ int main(int argc, const char** argv)
|
|||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
argument++;
|
argument++;
|
||||||
g_displayLevel = 4;
|
g_displayLevel++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
|
|||||||
@@ -94,21 +94,19 @@ int testStreamingAPI(void)
|
|||||||
if (needsInit) {
|
if (needsInit) {
|
||||||
size_t const ret = ZSTD_initDStream(stream);
|
size_t const ret = ZSTD_initDStream(stream);
|
||||||
if (ZSTD_isError(ret)) {
|
if (ZSTD_isError(ret)) {
|
||||||
DISPLAY("ERROR: %s\n", ZSTD_getErrorName(ret));
|
DISPLAY("ERROR: ZSTD_initDStream: %s\n", ZSTD_getErrorName(ret));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} }
|
||||||
}
|
|
||||||
{
|
{ size_t const ret = ZSTD_decompressStream(stream, &output, &input);
|
||||||
size_t const ret = ZSTD_decompressStream(stream, &output, &input);
|
|
||||||
if (ZSTD_isError(ret)) {
|
if (ZSTD_isError(ret)) {
|
||||||
DISPLAY("ERROR: %s\n", ZSTD_getErrorName(ret));
|
DISPLAY("ERROR: ZSTD_decompressStream: %s\n", ZSTD_getErrorName(ret));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
needsInit = 1;
|
needsInit = 1;
|
||||||
}
|
} }
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(outBuff, EXPECTED + outputPos, output.pos) != 0) {
|
if (memcmp(outBuff, EXPECTED + outputPos, output.pos) != 0) {
|
||||||
DISPLAY("ERROR: Wrong decoded output produced\n");
|
DISPLAY("ERROR: Wrong decoded output produced\n");
|
||||||
@@ -128,15 +126,12 @@ int testStreamingAPI(void)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int ret;
|
{ int const ret = testSimpleAPI();
|
||||||
|
if (ret) return ret; }
|
||||||
ret = testSimpleAPI();
|
{ int const ret = testStreamingAPI();
|
||||||
if (ret) return ret;
|
if (ret) return ret; }
|
||||||
ret = testStreamingAPI();
|
|
||||||
if (ret) return ret;
|
|
||||||
|
|
||||||
DISPLAY("OK\n");
|
DISPLAY("OK\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 <stddef.h> /* size_t */
|
|
||||||
#include <string.h> /* 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;
|
|
||||||
}
|
|
||||||
@@ -547,12 +547,12 @@ static ZSTD_compressionParameters randomParams(void)
|
|||||||
U32 validated = 0;
|
U32 validated = 0;
|
||||||
while (!validated) {
|
while (!validated) {
|
||||||
/* totally random entry */
|
/* totally random entry */
|
||||||
p.chainLog = FUZ_rand(&g_rand) % (ZSTD_CHAINLOG_MAX+1 - ZSTD_CHAINLOG_MIN) + ZSTD_CHAINLOG_MIN;
|
p.chainLog = (FUZ_rand(&g_rand) % (ZSTD_CHAINLOG_MAX+1 - ZSTD_CHAINLOG_MIN)) + ZSTD_CHAINLOG_MIN;
|
||||||
p.hashLog = FUZ_rand(&g_rand) % (ZSTD_HASHLOG_MAX+1 - ZSTD_HASHLOG_MIN) + ZSTD_HASHLOG_MIN;
|
p.hashLog = (FUZ_rand(&g_rand) % (ZSTD_HASHLOG_MAX+1 - ZSTD_HASHLOG_MIN)) + ZSTD_HASHLOG_MIN;
|
||||||
p.searchLog = FUZ_rand(&g_rand) % (ZSTD_SEARCHLOG_MAX+1 - ZSTD_SEARCHLOG_MIN) + ZSTD_SEARCHLOG_MIN;
|
p.searchLog = (FUZ_rand(&g_rand) % (ZSTD_SEARCHLOG_MAX+1 - ZSTD_SEARCHLOG_MIN)) + ZSTD_SEARCHLOG_MIN;
|
||||||
p.windowLog = FUZ_rand(&g_rand) % (ZSTD_WINDOWLOG_MAX+1 - ZSTD_WINDOWLOG_MIN) + ZSTD_WINDOWLOG_MIN;
|
p.windowLog = (FUZ_rand(&g_rand) % (ZSTD_WINDOWLOG_MAX+1 - ZSTD_WINDOWLOG_MIN)) + ZSTD_WINDOWLOG_MIN;
|
||||||
p.searchLength=FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN) + ZSTD_SEARCHLENGTH_MIN;
|
p.searchLength=(FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN)) + ZSTD_SEARCHLENGTH_MIN;
|
||||||
p.targetLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN;
|
p.targetLength=(FUZ_rand(&g_rand) % (512)) + ZSTD_TARGETLENGTH_MIN;
|
||||||
p.strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btultra +1));
|
p.strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btultra +1));
|
||||||
validated = !ZSTD_isError(ZSTD_checkCParams(p));
|
validated = !ZSTD_isError(ZSTD_checkCParams(p));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ else
|
|||||||
hasMT="true"
|
hasMT="true"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
$ECHO "\n===> simple tests "
|
$ECHO "\n===> simple tests "
|
||||||
|
|
||||||
./datagen > tmp
|
./datagen > tmp
|
||||||
@@ -100,8 +101,12 @@ $ECHO "test : basic compression "
|
|||||||
$ZSTD -f tmp # trivial compression case, creates tmp.zst
|
$ZSTD -f tmp # trivial compression case, creates tmp.zst
|
||||||
$ECHO "test : basic decompression"
|
$ECHO "test : basic decompression"
|
||||||
$ZSTD -df tmp.zst # trivial decompression case (overwrites tmp)
|
$ZSTD -df tmp.zst # trivial decompression case (overwrites tmp)
|
||||||
$ECHO "test : too large compression level (must fail)"
|
$ECHO "test : too large compression level => auto-fix"
|
||||||
$ZSTD -99 -f tmp # too large compression level, automatic sized down
|
$ZSTD -99 -f tmp # too large compression level, automatic sized down
|
||||||
|
$ECHO "test : --fast aka negative compression levels"
|
||||||
|
$ZSTD --fast -f tmp # == -1
|
||||||
|
$ZSTD --fast=3 -f tmp # == -3
|
||||||
|
$ZSTD --fast=200000 -f tmp # == no compression
|
||||||
$ECHO "test : compress to stdout"
|
$ECHO "test : compress to stdout"
|
||||||
$ZSTD tmp -c > tmpCompressed
|
$ZSTD tmp -c > tmpCompressed
|
||||||
$ZSTD tmp --stdout > tmpCompressed # long command format
|
$ZSTD tmp --stdout > tmpCompressed # long command format
|
||||||
@@ -190,10 +195,16 @@ $ZSTD -t tmp1.zst tmp2.zst
|
|||||||
$ZSTD -dc tmp1.zst tmp2.zst
|
$ZSTD -dc tmp1.zst tmp2.zst
|
||||||
$ZSTD tmp1.zst tmp2.zst -o "$INTOVOID"
|
$ZSTD tmp1.zst tmp2.zst -o "$INTOVOID"
|
||||||
$ZSTD -d tmp1.zst tmp2.zst -o tmp
|
$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*
|
rm tmp*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$ECHO "\n===> Advanced compression parameters "
|
$ECHO "\n===> Advanced compression parameters "
|
||||||
$ECHO "Hello world!" | $ZSTD --zstd=windowLog=21, - -o tmp.zst && die "wrong parameters not detected!"
|
$ECHO "Hello world!" | $ZSTD --zstd=windowLog=21, - -o tmp.zst && die "wrong parameters not detected!"
|
||||||
$ECHO "Hello world!" | $ZSTD --zstd=windowLo=21 - -o tmp.zst && die "wrong parameters not detected!"
|
$ECHO "Hello world!" | $ZSTD --zstd=windowLo=21 - -o tmp.zst && die "wrong parameters not detected!"
|
||||||
@@ -203,8 +214,8 @@ roundTripTest -g512K
|
|||||||
roundTripTest -g512K " --zstd=slen=3,tlen=48,strat=6"
|
roundTripTest -g512K " --zstd=slen=3,tlen=48,strat=6"
|
||||||
roundTripTest -g512K " --zstd=strat=6,wlog=23,clog=23,hlog=22,slog=6"
|
roundTripTest -g512K " --zstd=strat=6,wlog=23,clog=23,hlog=22,slog=6"
|
||||||
roundTripTest -g512K " --zstd=windowLog=23,chainLog=23,hashLog=22,searchLog=6,searchLength=3,targetLength=48,strategy=6"
|
roundTripTest -g512K " --zstd=windowLog=23,chainLog=23,hashLog=22,searchLog=6,searchLength=3,targetLength=48,strategy=6"
|
||||||
roundTripTest -g512K " --long --zstd=ldmHashLog=20,ldmSearchLength=64,ldmBucketSizeLog=1,ldmHashEveryLog=7"
|
roundTripTest -g512K " --single-thread --long --zstd=ldmHashLog=20,ldmSearchLength=64,ldmBucketSizeLog=1,ldmHashEveryLog=7"
|
||||||
roundTripTest -g512K " --long --zstd=ldmhlog=20,ldmslen=64,ldmblog=1,ldmhevery=7"
|
roundTripTest -g512K " --single-thread --long --zstd=ldmhlog=20,ldmslen=64,ldmblog=1,ldmhevery=7"
|
||||||
roundTripTest -g512K 19
|
roundTripTest -g512K 19
|
||||||
|
|
||||||
|
|
||||||
@@ -231,8 +242,18 @@ $ZSTD -c hello.tmp > hello.zstd --no-check
|
|||||||
$ZSTD -c world.tmp > world.zstd --no-check
|
$ZSTD -c world.tmp > world.zstd --no-check
|
||||||
cat hello.zstd world.zstd > helloworld.zstd
|
cat hello.zstd world.zstd > helloworld.zstd
|
||||||
$ZSTD -dc helloworld.zstd > result.tmp
|
$ZSTD -dc helloworld.zstd > result.tmp
|
||||||
cat result.tmp
|
|
||||||
$DIFF helloworld.tmp result.tmp
|
$DIFF helloworld.tmp result.tmp
|
||||||
|
$ECHO "testing zstdcat symlink"
|
||||||
|
ln -sf $ZSTD zstdcat
|
||||||
|
./zstdcat helloworld.zstd > result.tmp
|
||||||
|
$DIFF helloworld.tmp result.tmp
|
||||||
|
rm zstdcat
|
||||||
|
rm result.tmp
|
||||||
|
$ECHO "testing zcat symlink"
|
||||||
|
ln -sf $ZSTD zcat
|
||||||
|
./zcat helloworld.zstd > result.tmp
|
||||||
|
$DIFF helloworld.tmp result.tmp
|
||||||
|
rm zcat
|
||||||
rm ./*.tmp ./*.zstd
|
rm ./*.tmp ./*.zstd
|
||||||
$ECHO "frame concatenation tests completed"
|
$ECHO "frame concatenation tests completed"
|
||||||
|
|
||||||
@@ -322,9 +343,14 @@ $ECHO "- Create first dictionary "
|
|||||||
TESTFILE=../programs/zstdcli.c
|
TESTFILE=../programs/zstdcli.c
|
||||||
$ZSTD --train *.c ../programs/*.c -o tmpDict
|
$ZSTD --train *.c ../programs/*.c -o tmpDict
|
||||||
cp $TESTFILE tmp
|
cp $TESTFILE tmp
|
||||||
|
$ECHO "- Dictionary compression roundtrip"
|
||||||
$ZSTD -f tmp -D tmpDict
|
$ZSTD -f tmp -D tmpDict
|
||||||
$ZSTD -d tmp.zst -D tmpDict -fo result
|
$ZSTD -d tmp.zst -D tmpDict -fo result
|
||||||
$DIFF $TESTFILE 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" ]
|
if [ -n "$hasMT" ]
|
||||||
then
|
then
|
||||||
$ECHO "- Test dictionary compression with multithreading "
|
$ECHO "- Test dictionary compression with multithreading "
|
||||||
@@ -451,6 +477,8 @@ $ECHO "bench one file"
|
|||||||
$ZSTD -bi0 tmp1
|
$ZSTD -bi0 tmp1
|
||||||
$ECHO "bench multiple levels"
|
$ECHO "bench multiple levels"
|
||||||
$ZSTD -i0b0e3 tmp1
|
$ZSTD -i0b0e3 tmp1
|
||||||
|
$ECHO "bench negative level"
|
||||||
|
$ZSTD -bi0 --fast tmp1
|
||||||
$ECHO "with recursive and quiet modes"
|
$ECHO "with recursive and quiet modes"
|
||||||
$ZSTD -rqi1b1e2 tmp1
|
$ZSTD -rqi1b1e2 tmp1
|
||||||
|
|
||||||
@@ -603,14 +631,15 @@ roundTripTest -g516K 19 # btopt
|
|||||||
fileRoundTripTest -g500K
|
fileRoundTripTest -g500K
|
||||||
|
|
||||||
$ECHO "\n===> zstd long distance matching round-trip tests "
|
$ECHO "\n===> zstd long distance matching round-trip tests "
|
||||||
roundTripTest -g0 "2 --long"
|
roundTripTest -g0 "2 --single-thread --long"
|
||||||
roundTripTest -g1000K "1 --long"
|
roundTripTest -g1000K "1 --single-thread --long"
|
||||||
roundTripTest -g517K "6 --long"
|
roundTripTest -g517K "6 --single-thread --long"
|
||||||
roundTripTest -g516K "16 --long"
|
roundTripTest -g516K "16 --single-thread --long"
|
||||||
roundTripTest -g518K "19 --long"
|
roundTripTest -g518K "19 --single-thread --long"
|
||||||
fileRoundTripTest -g5M "3 --long"
|
fileRoundTripTest -g5M "3 --single-thread --long"
|
||||||
|
|
||||||
|
|
||||||
|
roundTripTest -g96K "5 --single-thread"
|
||||||
if [ -n "$hasMT" ]
|
if [ -n "$hasMT" ]
|
||||||
then
|
then
|
||||||
$ECHO "\n===> zstdmt round-trip tests "
|
$ECHO "\n===> zstdmt round-trip tests "
|
||||||
@@ -620,7 +649,7 @@ then
|
|||||||
fileRoundTripTest -g4M "19 -T2 -B1M"
|
fileRoundTripTest -g4M "19 -T2 -B1M"
|
||||||
|
|
||||||
$ECHO "\n===> zstdmt long distance matching round-trip tests "
|
$ECHO "\n===> zstdmt long distance matching round-trip tests "
|
||||||
roundTripTest -g8M "3 --long -T2"
|
roundTripTest -g8M "3 --long=24 -T2"
|
||||||
else
|
else
|
||||||
$ECHO "\n===> no multithreading, skipping zstdmt tests "
|
$ECHO "\n===> no multithreading, skipping zstdmt tests "
|
||||||
fi
|
fi
|
||||||
@@ -671,13 +700,13 @@ rm tmp*
|
|||||||
|
|
||||||
|
|
||||||
$ECHO "\n===> zstd long distance matching tests "
|
$ECHO "\n===> zstd long distance matching tests "
|
||||||
roundTripTest -g0 " --long"
|
roundTripTest -g0 " --single-thread --long"
|
||||||
roundTripTest -g9M "2 --long"
|
roundTripTest -g9M "2 --single-thread --long"
|
||||||
# Test parameter parsing
|
# Test parameter parsing
|
||||||
roundTripTest -g1M -P50 "1 --long=29" " --memory=512MB"
|
roundTripTest -g1M -P50 "1 --single-thread --long=29" " --memory=512MB"
|
||||||
roundTripTest -g1M -P50 "1 --long=29 --zstd=wlog=28" " --memory=256MB"
|
roundTripTest -g1M -P50 "1 --single-thread --long=29 --zstd=wlog=28" " --memory=256MB"
|
||||||
roundTripTest -g1M -P50 "1 --long=29" " --long=28 --memory=512MB"
|
roundTripTest -g1M -P50 "1 --single-thread --long=29" " --long=28 --memory=512MB"
|
||||||
roundTripTest -g1M -P50 "1 --long=29" " --zstd=wlog=28 --memory=512MB"
|
roundTripTest -g1M -P50 "1 --single-thread --long=29" " --zstd=wlog=28 --memory=512MB"
|
||||||
|
|
||||||
|
|
||||||
if [ "$1" != "--test-large-data" ]; then
|
if [ "$1" != "--test-large-data" ]; then
|
||||||
@@ -712,18 +741,19 @@ roundTripTest -g18000018 -P94 18
|
|||||||
roundTripTest -g18000019 -P96 19
|
roundTripTest -g18000019 -P96 19
|
||||||
|
|
||||||
roundTripTest -g5000000000 -P99 1
|
roundTripTest -g5000000000 -P99 1
|
||||||
|
roundTripTest -g1700000000 -P0 "1 --zstd=strategy=6" # ensure btlazy2 can survive an overflow rescale
|
||||||
|
|
||||||
fileRoundTripTest -g4193M -P99 1
|
fileRoundTripTest -g4193M -P99 1
|
||||||
|
|
||||||
|
|
||||||
$ECHO "\n===> zstd long, long distance matching round-trip tests "
|
$ECHO "\n===> zstd long, long distance matching round-trip tests "
|
||||||
roundTripTest -g270000000 "1 --long"
|
roundTripTest -g270000000 "1 --single-thread --long"
|
||||||
roundTripTest -g130000000 -P60 "5 --long"
|
roundTripTest -g130000000 -P60 "5 --single-thread --long"
|
||||||
roundTripTest -g35000000 -P70 "8 --long"
|
roundTripTest -g35000000 -P70 "8 --single-thread --long"
|
||||||
roundTripTest -g18000001 -P80 "18 --long"
|
roundTripTest -g18000001 -P80 "18 --single-thread --long"
|
||||||
# Test large window logs
|
# Test large window logs
|
||||||
roundTripTest -g700M -P50 "1 --long=29"
|
roundTripTest -g700M -P50 "1 --single-thread --long=29"
|
||||||
roundTripTest -g600M -P50 "1 --long --zstd=wlog=29,clog=28"
|
roundTripTest -g600M -P50 "1 --single-thread --long --zstd=wlog=29,clog=28"
|
||||||
|
|
||||||
|
|
||||||
if [ -n "$hasMT" ]
|
if [ -n "$hasMT" ]
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ static size_t cctxParamRoundTripTest(void* resultBuff, size_t resultBuffCapacity
|
|||||||
|
|
||||||
/* Set parameters */
|
/* Set parameters */
|
||||||
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, cLevel) );
|
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, cLevel) );
|
||||||
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbThreads, 2) );
|
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbWorkers, 2) );
|
||||||
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_overlapSizeLog, 5) );
|
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_overlapSizeLog, 5) );
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
size_t cSize;
|
size_t cSize;
|
||||||
int testResult = 0;
|
int testResult = 0;
|
||||||
U32 testNb = 1;
|
U32 testNb = 1;
|
||||||
|
U32 coreSeed = 0; /* this name to conform with CHECK_Z macro display */
|
||||||
ZSTD_CStream* zc = ZSTD_createCStream();
|
ZSTD_CStream* zc = ZSTD_createCStream();
|
||||||
ZSTD_DStream* zd = ZSTD_createDStream();
|
ZSTD_DStream* zd = ZSTD_createDStream();
|
||||||
ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
|
ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
|
||||||
@@ -238,7 +239,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
|
|
||||||
/* Create dictionary */
|
/* Create dictionary */
|
||||||
DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
|
DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
|
||||||
dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 2, 8 KB, 40 KB);
|
dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 3, 16 KB, 48 KB);
|
||||||
if (!dictionary.start) {
|
if (!dictionary.start) {
|
||||||
DISPLAY("Error creating dictionary, aborting \n");
|
DISPLAY("Error creating dictionary, aborting \n");
|
||||||
goto _output_error;
|
goto _output_error;
|
||||||
@@ -372,7 +373,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
|
DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Byte-by-byte decompression test */
|
/* Decompression by small increment */
|
||||||
DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
|
||||||
{ /* skippable frame */
|
{ /* skippable frame */
|
||||||
size_t r = 1;
|
size_t r = 1;
|
||||||
@@ -382,8 +383,10 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
inBuff.pos = 0;
|
inBuff.pos = 0;
|
||||||
outBuff.pos = 0;
|
outBuff.pos = 0;
|
||||||
while (r) { /* skippable frame */
|
while (r) { /* skippable frame */
|
||||||
inBuff.size = inBuff.pos + 1;
|
size_t const inSize = FUZ_rand(&coreSeed) & 15;
|
||||||
outBuff.size = outBuff.pos + 1;
|
size_t const outSize = FUZ_rand(&coreSeed) & 15;
|
||||||
|
inBuff.size = inBuff.pos + inSize;
|
||||||
|
outBuff.size = outBuff.pos + outSize;
|
||||||
r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||||
if (ZSTD_isError(r)) goto _output_error;
|
if (ZSTD_isError(r)) goto _output_error;
|
||||||
}
|
}
|
||||||
@@ -391,8 +394,10 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
|
ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
|
||||||
r=1;
|
r=1;
|
||||||
while (r) {
|
while (r) {
|
||||||
inBuff.size = inBuff.pos + 1;
|
size_t const inSize = FUZ_rand(&coreSeed) & 15;
|
||||||
outBuff.size = outBuff.pos + 1;
|
size_t const outSize = FUZ_rand(&coreSeed) & 15;
|
||||||
|
inBuff.size = inBuff.pos + inSize;
|
||||||
|
outBuff.size = outBuff.pos + outSize;
|
||||||
r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||||
if (ZSTD_isError(r)) goto _output_error;
|
if (ZSTD_isError(r)) goto _output_error;
|
||||||
}
|
}
|
||||||
@@ -427,8 +432,8 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
|
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
|
||||||
|
|
||||||
/* wrong _srcSize compression test */
|
/* wrong _srcSize compression test */
|
||||||
DISPLAYLEVEL(3, "test%3i : wrong srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
|
DISPLAYLEVEL(3, "test%3i : too large srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
|
||||||
ZSTD_initCStream_srcSize(zc, 1, CNBufferSize-1);
|
ZSTD_initCStream_srcSize(zc, 1, CNBufferSize+1);
|
||||||
outBuff.dst = (char*)(compressedBuffer);
|
outBuff.dst = (char*)(compressedBuffer);
|
||||||
outBuff.size = compressedBufferSize;
|
outBuff.size = compressedBufferSize;
|
||||||
outBuff.pos = 0;
|
outBuff.pos = 0;
|
||||||
@@ -441,6 +446,20 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
|
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
|
||||||
DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
|
DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
|
||||||
|
|
||||||
|
/* wrong _srcSize compression test */
|
||||||
|
DISPLAYLEVEL(3, "test%3i : too small srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
|
||||||
|
ZSTD_initCStream_srcSize(zc, 1, CNBufferSize-1);
|
||||||
|
outBuff.dst = (char*)(compressedBuffer);
|
||||||
|
outBuff.size = compressedBufferSize;
|
||||||
|
outBuff.pos = 0;
|
||||||
|
inBuff.src = CNBuffer;
|
||||||
|
inBuff.size = CNBufferSize;
|
||||||
|
inBuff.pos = 0;
|
||||||
|
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||||
|
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
|
||||||
|
DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
|
||||||
|
}
|
||||||
|
|
||||||
/* Complex context re-use scenario */
|
/* Complex context re-use scenario */
|
||||||
DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
|
||||||
ZSTD_freeCStream(zc);
|
ZSTD_freeCStream(zc);
|
||||||
@@ -557,11 +576,50 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
{ size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
{ size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||||
if (!ZSTD_isError(r)) goto _output_error; /* must fail : frame requires > 100 bytes */
|
if (!ZSTD_isError(r)) goto _output_error; /* must fail : frame requires > 100 bytes */
|
||||||
DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
|
DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
|
||||||
|
ZSTD_DCtx_reset(zd); /* leave zd in good shape for next tests */
|
||||||
|
|
||||||
|
DISPLAYLEVEL(3, "test%3i : dictionary source size and level : ", testNb++);
|
||||||
|
{ ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||||
|
int const maxLevel = 16; /* first level with zstd_opt */
|
||||||
|
int level;
|
||||||
|
assert(maxLevel < ZSTD_maxCLevel());
|
||||||
|
CHECK_Z( ZSTD_DCtx_loadDictionary_byReference(dctx, dictionary.start, dictionary.filled) );
|
||||||
|
for (level = 1; level <= maxLevel; ++level) {
|
||||||
|
ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, level);
|
||||||
|
size_t const maxSize = MIN(1 MB, CNBufferSize);
|
||||||
|
size_t size;
|
||||||
|
for (size = 512; size <= maxSize; size <<= 1) {
|
||||||
|
U64 const crcOrig = XXH64(CNBuffer, size, 0);
|
||||||
|
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||||
|
outBuff.dst = compressedBuffer;
|
||||||
|
outBuff.size = compressedBufferSize;
|
||||||
|
outBuff.pos = 0;
|
||||||
|
inBuff.src = CNBuffer;
|
||||||
|
inBuff.size = size;
|
||||||
|
inBuff.pos = 0;
|
||||||
|
CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
|
||||||
|
CHECK_Z(ZSTD_compress_generic(cctx, &outBuff, &inBuff, ZSTD_e_end));
|
||||||
|
if (inBuff.pos != inBuff.size) goto _output_error;
|
||||||
|
{ ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
|
||||||
|
ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
|
||||||
|
CHECK_Z( ZSTD_decompress_generic(dctx, &decOut, &decIn) );
|
||||||
|
if (decIn.pos != decIn.size) goto _output_error;
|
||||||
|
if (decOut.pos != size) goto _output_error;
|
||||||
|
{ U64 const crcDec = XXH64(decOut.dst, decOut.pos, 0);
|
||||||
|
if (crcDec != crcOrig) goto _output_error;
|
||||||
|
} }
|
||||||
|
ZSTD_freeCCtx(cctx);
|
||||||
|
}
|
||||||
|
ZSTD_freeCDict(cdict);
|
||||||
|
}
|
||||||
|
ZSTD_freeDCtx(dctx);
|
||||||
|
}
|
||||||
|
DISPLAYLEVEL(3, "OK\n");
|
||||||
|
|
||||||
DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
|
||||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
|
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
|
||||||
ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
|
ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, ZSTD_defaultCMem);
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem);
|
||||||
size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
|
size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
|
||||||
if (ZSTD_isError(initError)) goto _output_error;
|
if (ZSTD_isError(initError)) goto _output_error;
|
||||||
cSize = 0;
|
cSize = 0;
|
||||||
@@ -605,14 +663,18 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
cSize = outBuff.pos;
|
cSize = outBuff.pos;
|
||||||
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
|
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
|
||||||
|
|
||||||
DISPLAYLEVEL(3, "test%3i : decompress with dictionary : ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress with ZSTD_DCtx_refPrefix : ", testNb++);
|
||||||
{ size_t const r = ZSTD_decompress_usingDict(zd,
|
CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) );
|
||||||
decodedBuffer, CNBufferSize,
|
outBuff.dst = decodedBuffer;
|
||||||
compressedBuffer, cSize,
|
outBuff.size = CNBufferSize;
|
||||||
dictionary.start, dictionary.filled);
|
outBuff.pos = 0;
|
||||||
if (ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
|
inBuff.src = compressedBuffer;
|
||||||
|
inBuff.size = cSize;
|
||||||
|
inBuff.pos = 0;
|
||||||
|
CHECK_Z( ZSTD_decompress_generic(zd, &outBuff, &inBuff) );
|
||||||
|
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||||
|
if (outBuff.pos != CNBufferSize) goto _output_error; /* must regenerate whole input */
|
||||||
DISPLAYLEVEL(3, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
}
|
|
||||||
|
|
||||||
DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
|
DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
|
||||||
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
|
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
|
||||||
@@ -694,16 +756,19 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
inBuff.src = CNBuffer;
|
inBuff.src = CNBuffer;
|
||||||
inBuff.size = CNBufferSize;
|
inBuff.size = CNBufferSize;
|
||||||
inBuff.pos = 0;
|
inBuff.pos = 0;
|
||||||
CHECK_Z( ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end) );
|
{ size_t const compressResult = ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end);
|
||||||
|
if (compressResult != 0) goto _output_error; /* compression must be completed in a single round */
|
||||||
|
}
|
||||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||||
{ size_t const r = ZSTDMT_endStream(mtctx, &outBuff);
|
{ size_t const compressedSize = ZSTD_findFrameCompressedSize(compressedBuffer, outBuff.pos);
|
||||||
if (r != 0) goto _output_error; } /* error, or some data not flushed */
|
if (compressedSize != outBuff.pos) goto _output_error; /* must be a full valid frame */
|
||||||
|
}
|
||||||
DISPLAYLEVEL(3, "OK \n");
|
DISPLAYLEVEL(3, "OK \n");
|
||||||
|
|
||||||
/* Complex multithreading + dictionary test */
|
/* Complex multithreading + dictionary test */
|
||||||
{ U32 const nbThreads = 2;
|
{ U32 const nbWorkers = 2;
|
||||||
size_t const jobSize = 4 * 1 MB;
|
size_t const jobSize = 4 * 1 MB;
|
||||||
size_t const srcSize = jobSize * nbThreads; /* we want each job to have predictable size */
|
size_t const srcSize = jobSize * nbWorkers; /* we want each job to have predictable size */
|
||||||
size_t const segLength = 2 KB;
|
size_t const segLength = 2 KB;
|
||||||
size_t const offset = 600 KB; /* must be larger than window defined in cdict */
|
size_t const offset = 600 KB; /* must be larger than window defined in cdict */
|
||||||
size_t const start = jobSize + (offset-1);
|
size_t const start = jobSize + (offset-1);
|
||||||
@@ -711,7 +776,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
BYTE* const dst = (BYTE*)CNBuffer + start - offset;
|
BYTE* const dst = (BYTE*)CNBuffer + start - offset;
|
||||||
DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (U32)srcSize);
|
DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (U32)srcSize);
|
||||||
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_compressionLevel, 3) );
|
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_compressionLevel, 3) );
|
||||||
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_nbThreads, 2) );
|
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_nbWorkers, nbWorkers) );
|
||||||
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_jobSize, jobSize) );
|
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_jobSize, jobSize) );
|
||||||
assert(start > offset);
|
assert(start > offset);
|
||||||
assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
|
assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
|
||||||
@@ -724,7 +789,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
inBuff.pos = 0;
|
inBuff.pos = 0;
|
||||||
}
|
}
|
||||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, 4 KB, dictionary.filled); /* intentionnally lies on estimatedSrcSize, to push cdict into targeting a small window size */
|
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, 4 KB, dictionary.filled); /* intentionnally lies on estimatedSrcSize, to push cdict into targeting a small window size */
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
|
||||||
DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
|
DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
|
||||||
CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
|
CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
|
||||||
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
|
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
|
||||||
@@ -767,7 +832,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
|||||||
|
|
||||||
XXH64_reset(&xxh, 0);
|
XXH64_reset(&xxh, 0);
|
||||||
cParams.windowLog = kMaxWindowLog;
|
cParams.windowLog = kMaxWindowLog;
|
||||||
cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
|
||||||
ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
|
ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
|
||||||
|
|
||||||
if (!cdict || !ddict) goto _output_error;
|
if (!cdict || !ddict) goto _output_error;
|
||||||
@@ -863,11 +928,21 @@ static size_t findDiff(const void* buf1, const void* buf2, size_t max)
|
|||||||
for (u=0; u<max; u++) {
|
for (u=0; u<max; u++) {
|
||||||
if (b1[u] != b2[u]) break;
|
if (b1[u] != b2[u]) break;
|
||||||
}
|
}
|
||||||
|
if (u==max) {
|
||||||
|
DISPLAY("=> No difference detected within %u bytes \n", (U32)max);
|
||||||
|
return u;
|
||||||
|
}
|
||||||
DISPLAY("Error at position %u / %u \n", (U32)u, (U32)max);
|
DISPLAY("Error at position %u / %u \n", (U32)u, (U32)max);
|
||||||
DISPLAY(" %02X %02X %02X :%02X: %02X %02X %02X %02X %02X \n",
|
if (u>=3)
|
||||||
b1[u-3], b1[u-2], b1[u-1], b1[u-0], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
|
DISPLAY(" %02X %02X %02X ",
|
||||||
DISPLAY(" %02X %02X %02X :%02X: %02X %02X %02X %02X %02X \n",
|
b1[u-3], b1[u-2], b1[u-1]);
|
||||||
b2[u-3], b2[u-2], b2[u-1], b2[u-0], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
|
DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
|
||||||
|
b1[u], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
|
||||||
|
if (u>=3)
|
||||||
|
DISPLAY(" %02X %02X %02X ",
|
||||||
|
b2[u-3], b2[u-2], b2[u-1]);
|
||||||
|
DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
|
||||||
|
b2[u], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -948,10 +1023,13 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
|
|||||||
size_t maxTestSize;
|
size_t maxTestSize;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
|
|
||||||
else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
|
|
||||||
FUZ_rand(&coreSeed);
|
FUZ_rand(&coreSeed);
|
||||||
lseed = coreSeed ^ prime32;
|
lseed = coreSeed ^ prime32;
|
||||||
|
if (nbTests >= testNb) {
|
||||||
|
DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
|
||||||
|
} else {
|
||||||
|
DISPLAYUPDATE(2, "\r%6u ", testNb);
|
||||||
|
}
|
||||||
|
|
||||||
/* states full reset (deliberately not synchronized) */
|
/* states full reset (deliberately not synchronized) */
|
||||||
/* some issues can only happen when reusing states */
|
/* some issues can only happen when reusing states */
|
||||||
@@ -1161,7 +1239,6 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
UTIL_time_t const startClock = UTIL_getTime();
|
UTIL_time_t const startClock = UTIL_getTime();
|
||||||
const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */
|
const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */
|
||||||
size_t dictSize = 0;
|
size_t dictSize = 0;
|
||||||
U32 oldTestLog = 0;
|
|
||||||
int const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
|
int const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
|
||||||
U32 const nbThreadsMax = bigTests ? 4 : 2;
|
U32 const nbThreadsMax = bigTests ? 4 : 2;
|
||||||
|
|
||||||
@@ -1183,6 +1260,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
|
RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
|
||||||
memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
|
memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
|
||||||
ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
|
ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
|
||||||
|
DISPLAYLEVEL(6, "Creating initial context with %u threads \n", nbThreads);
|
||||||
|
|
||||||
/* catch up testNb */
|
/* catch up testNb */
|
||||||
for (testNb=1; testNb < startTest; testNb++)
|
for (testNb=1; testNb < startTest; testNb++)
|
||||||
@@ -1195,14 +1273,14 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
size_t totalTestSize, totalGenSize, cSize;
|
size_t totalTestSize, totalGenSize, cSize;
|
||||||
XXH64_state_t xxhState;
|
XXH64_state_t xxhState;
|
||||||
U64 crcOrig;
|
U64 crcOrig;
|
||||||
U32 resetAllowed = 1;
|
|
||||||
size_t maxTestSize;
|
size_t maxTestSize;
|
||||||
|
|
||||||
/* init */
|
|
||||||
if (testNb < nbTests) {
|
|
||||||
DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
|
|
||||||
} else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
|
|
||||||
FUZ_rand(&coreSeed);
|
FUZ_rand(&coreSeed);
|
||||||
|
if (nbTests >= testNb) {
|
||||||
|
DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
|
||||||
|
} else {
|
||||||
|
DISPLAYUPDATE(2, "\r%6u ", testNb);
|
||||||
|
}
|
||||||
lseed = coreSeed ^ prime32;
|
lseed = coreSeed ^ prime32;
|
||||||
|
|
||||||
/* states full reset (deliberately not synchronized) */
|
/* states full reset (deliberately not synchronized) */
|
||||||
@@ -1213,7 +1291,6 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
ZSTDMT_freeCCtx(zc);
|
ZSTDMT_freeCCtx(zc);
|
||||||
zc = ZSTDMT_createCCtx(nbThreads);
|
zc = ZSTDMT_createCCtx(nbThreads);
|
||||||
CHECK(zc==NULL, "ZSTDMT_createCCtx allocation error")
|
CHECK(zc==NULL, "ZSTDMT_createCCtx allocation error")
|
||||||
resetAllowed=0;
|
|
||||||
}
|
}
|
||||||
if ((FUZ_rand(&lseed) & 0xFF) == 132) {
|
if ((FUZ_rand(&lseed) & 0xFF) == 132) {
|
||||||
ZSTD_freeDStream(zd);
|
ZSTD_freeDStream(zd);
|
||||||
@@ -1238,15 +1315,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* compression init */
|
/* compression init */
|
||||||
if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
|
{ U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||||
&& oldTestLog /* at least one test happened */ && resetAllowed) {
|
|
||||||
maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
|
|
||||||
if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
|
|
||||||
{ int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
|
|
||||||
CHECK_Z( ZSTDMT_initCStream(zc, compressionLevel) );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
|
|
||||||
U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
|
U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||||
int const cLevelCandidate = ( FUZ_rand(&lseed)
|
int const cLevelCandidate = ( FUZ_rand(&lseed)
|
||||||
% (ZSTD_maxCLevel() - (MAX(testLog, dictLog) / 2)) )
|
% (ZSTD_maxCLevel() - (MAX(testLog, dictLog) / 2)) )
|
||||||
@@ -1255,7 +1324,12 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
int const cLevelMin = MAX(cLevelThreadAdjusted, 1); /* no negative cLevel yet */
|
int const cLevelMin = MAX(cLevelThreadAdjusted, 1); /* no negative cLevel yet */
|
||||||
int const cLevel = MIN(cLevelMin, cLevelMax);
|
int const cLevel = MIN(cLevelMin, cLevelMax);
|
||||||
maxTestSize = FUZ_rLogLength(&lseed, testLog);
|
maxTestSize = FUZ_rLogLength(&lseed, testLog);
|
||||||
oldTestLog = testLog;
|
|
||||||
|
if (FUZ_rand(&lseed)&1) { /* simple init */
|
||||||
|
int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
|
||||||
|
DISPLAYLEVEL(5, "Init with compression level = %i \n", compressionLevel);
|
||||||
|
CHECK_Z( ZSTDMT_initCStream(zc, compressionLevel) );
|
||||||
|
} else { /* advanced init */
|
||||||
/* random dictionary selection */
|
/* random dictionary selection */
|
||||||
dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
|
dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
|
||||||
{ size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
|
{ size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
|
||||||
@@ -1272,7 +1346,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_overlapSectionLog, FUZ_rand(&lseed) % 12) );
|
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_overlapSectionLog, FUZ_rand(&lseed) % 12) );
|
||||||
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_jobSize, FUZ_rand(&lseed) % (2*maxTestSize+1)) ); /* custome job size */
|
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_jobSize, FUZ_rand(&lseed) % (2*maxTestSize+1)) ); /* custome job size */
|
||||||
CHECK_Z( ZSTDMT_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
|
CHECK_Z( ZSTDMT_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
|
||||||
} }
|
} } }
|
||||||
|
|
||||||
/* multi-segments compression test */
|
/* multi-segments compression test */
|
||||||
XXH64_reset(&xxhState, 0);
|
XXH64_reset(&xxhState, 0);
|
||||||
@@ -1301,9 +1375,12 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
if ((FUZ_rand(&lseed) & 15) == 0) {
|
if ((FUZ_rand(&lseed) & 15) == 0) {
|
||||||
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
|
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
|
||||||
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
|
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
|
||||||
|
size_t const previousPos = outBuff.pos;
|
||||||
outBuff.size = outBuff.pos + adjustedDstSize;
|
outBuff.size = outBuff.pos + adjustedDstSize;
|
||||||
DISPLAYLEVEL(5, "Flushing into dst buffer of size %u \n", (U32)adjustedDstSize);
|
DISPLAYLEVEL(5, "Flushing into dst buffer of size %u \n", (U32)adjustedDstSize);
|
||||||
CHECK_Z( ZSTDMT_flushStream(zc, &outBuff) );
|
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 */
|
/* final frame epilogue */
|
||||||
@@ -1311,18 +1388,24 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
while (remainingToFlush) {
|
while (remainingToFlush) {
|
||||||
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
|
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
|
||||||
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
|
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
|
||||||
|
size_t const previousPos = outBuff.pos;
|
||||||
outBuff.size = outBuff.pos + adjustedDstSize;
|
outBuff.size = outBuff.pos + adjustedDstSize;
|
||||||
DISPLAYLEVEL(5, "Ending into dst buffer of size %u \n", (U32)adjustedDstSize);
|
DISPLAYLEVEL(5, "Ending into dst buffer of size %u \n", (U32)adjustedDstSize);
|
||||||
remainingToFlush = ZSTDMT_endStream(zc, &outBuff);
|
remainingToFlush = ZSTDMT_endStream(zc, &outBuff);
|
||||||
CHECK (ZSTD_isError(remainingToFlush), "ZSTDMT_endStream error : %s", ZSTD_getErrorName(remainingToFlush));
|
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);
|
DISPLAYLEVEL(5, "endStream : remainingToFlush : %u \n", (U32)remainingToFlush);
|
||||||
} }
|
} }
|
||||||
crcOrig = XXH64_digest(&xxhState);
|
crcOrig = XXH64_digest(&xxhState);
|
||||||
cSize = outBuff.pos;
|
cSize = outBuff.pos;
|
||||||
DISPLAYLEVEL(5, "Frame completed : %u bytes \n", (U32)cSize);
|
DISPLAYLEVEL(5, "Frame completed : %u bytes compressed into %u bytes \n",
|
||||||
|
(U32)totalTestSize, (U32)cSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* multi - fragments decompression test */
|
/* multi - fragments decompression test */
|
||||||
|
assert(totalTestSize < dstBufferSize);
|
||||||
|
memset(dstBuffer, 170, totalTestSize); /* init dest area */
|
||||||
if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
|
if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
|
||||||
CHECK_Z( ZSTD_resetDStream(zd) );
|
CHECK_Z( ZSTD_resetDStream(zd) );
|
||||||
} else {
|
} else {
|
||||||
@@ -1337,10 +1420,16 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
|||||||
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
|
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
|
||||||
inBuff.size = inBuff.pos + readCSrcSize;
|
inBuff.size = inBuff.pos + readCSrcSize;
|
||||||
outBuff.size = outBuff.pos + dstBuffSize;
|
outBuff.size = outBuff.pos + dstBuffSize;
|
||||||
DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes \n", (U32)readCSrcSize);
|
DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes into outBuff %u bytes \n",
|
||||||
|
(U32)readCSrcSize, (U32)dstBuffSize);
|
||||||
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||||
|
if (ZSTD_isError(decompressionResult)) {
|
||||||
|
DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
|
||||||
|
findDiff(copyBuffer, dstBuffer, totalTestSize);
|
||||||
|
}
|
||||||
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
|
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
|
||||||
DISPLAYLEVEL(6, "inBuff.pos = %u \n", (U32)readCSrcSize);
|
DISPLAYLEVEL(6, "total ingested (inBuff.pos) = %u and produced (outBuff.pos) = %u \n",
|
||||||
|
(U32)inBuff.pos, (U32)outBuff.pos);
|
||||||
}
|
}
|
||||||
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
|
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
|
||||||
CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
|
CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
|
||||||
@@ -1579,7 +1668,11 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* mess with frame parameters */
|
/* mess with frame parameters */
|
||||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
if (FUZ_rand(&lseed) & 1) {
|
||||||
|
U32 const checksumFlag = FUZ_rand(&lseed) & 1;
|
||||||
|
DISPLAYLEVEL(5, "t%u: frame checksum : %u \n", testNb, checksumFlag);
|
||||||
|
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, checksumFlag, useOpaqueAPI) );
|
||||||
|
}
|
||||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
||||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
||||||
if (FUZ_rand(&lseed) & 1) {
|
if (FUZ_rand(&lseed) & 1) {
|
||||||
@@ -1592,7 +1685,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
|||||||
U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
|
U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
|
||||||
U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
|
U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
|
||||||
DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads);
|
DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads);
|
||||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) );
|
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbWorkers, nbThreads, useOpaqueAPI) );
|
||||||
if (nbThreads > 1) {
|
if (nbThreads > 1) {
|
||||||
U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
|
U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
|
||||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) );
|
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) );
|
||||||
@@ -1644,8 +1737,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
|||||||
outBuff.size = outBuff.pos + dstBuffSize;
|
outBuff.size = outBuff.pos + dstBuffSize;
|
||||||
|
|
||||||
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) );
|
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) );
|
||||||
DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) \n",
|
DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) ; flush: %u (total : %u) \n",
|
||||||
testNb, (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos));
|
testNb, (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos), (U32)flush, (U32)outBuff.pos);
|
||||||
|
|
||||||
XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
|
XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
|
||||||
memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
|
memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
|
||||||
@@ -1653,14 +1746,15 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* final frame epilogue */
|
/* final frame epilogue */
|
||||||
{ size_t remainingToFlush = (size_t)(-1);
|
{ size_t remainingToFlush = 1;
|
||||||
while (remainingToFlush) {
|
while (remainingToFlush) {
|
||||||
ZSTD_inBuffer inBuff = { NULL, 0, 0 };
|
ZSTD_inBuffer inBuff = { NULL, 0, 0 };
|
||||||
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
|
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
|
||||||
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
|
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
|
||||||
outBuff.size = outBuff.pos + adjustedDstSize;
|
outBuff.size = outBuff.pos + adjustedDstSize;
|
||||||
DISPLAYLEVEL(6, "End-flush into dst buffer of size %u \n", (U32)adjustedDstSize);
|
DISPLAYLEVEL(6, "t%u: End-flush into dst buffer of size %u \n", testNb, (U32)adjustedDstSize);
|
||||||
remainingToFlush = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end);
|
remainingToFlush = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end);
|
||||||
|
DISPLAYLEVEL(6, "t%u: Total flushed so far : %u bytes \n", testNb, (U32)outBuff.pos);
|
||||||
CHECK( ZSTD_isError(remainingToFlush),
|
CHECK( ZSTD_isError(remainingToFlush),
|
||||||
"ZSTD_compress_generic w/ ZSTD_e_end error : %s",
|
"ZSTD_compress_generic w/ ZSTD_e_end error : %s",
|
||||||
ZSTD_getErrorName(remainingToFlush) );
|
ZSTD_getErrorName(remainingToFlush) );
|
||||||
@@ -1687,14 +1781,20 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
|||||||
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
|
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
|
||||||
inBuff.size = inBuff.pos + readCSrcSize;
|
inBuff.size = inBuff.pos + readCSrcSize;
|
||||||
outBuff.size = outBuff.pos + dstBuffSize;
|
outBuff.size = outBuff.pos + dstBuffSize;
|
||||||
DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n",
|
DISPLAYLEVEL(6, "decompression presented %u new bytes (pos:%u/%u)\n",
|
||||||
(U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize);
|
(U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize);
|
||||||
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||||
|
DISPLAYLEVEL(6, "so far: consumed = %u, produced = %u \n",
|
||||||
|
(U32)inBuff.pos, (U32)outBuff.pos);
|
||||||
|
if (ZSTD_isError(decompressionResult)) {
|
||||||
|
DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
|
||||||
|
findDiff(copyBuffer, dstBuffer, totalTestSize);
|
||||||
|
}
|
||||||
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
|
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
|
||||||
DISPLAYLEVEL(6, "inBuff.pos = %u \n", (U32)readCSrcSize);
|
CHECK (inBuff.pos > cSize, "ZSTD_decompressStream consumes too much input : %u > %u ", (U32)inBuff.pos, (U32)cSize);
|
||||||
}
|
}
|
||||||
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
|
|
||||||
CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
|
CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
|
||||||
|
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
|
||||||
{ U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
|
{ U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
|
||||||
if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
|
if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
|
||||||
CHECK (crcDest!=crcOrig, "decompressed data corrupted");
|
CHECK (crcDest!=crcOrig, "decompressed data corrupted");
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
|||||||
if (compressor == BMK_ZSTD) {
|
if (compressor == BMK_ZSTD) {
|
||||||
ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize);
|
ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize);
|
||||||
ZSTD_customMem const cmem = { NULL, NULL, NULL };
|
ZSTD_customMem const cmem = { NULL, NULL, NULL };
|
||||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dm_auto, zparams.cParams, cmem);
|
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_auto, zparams.cParams, cmem);
|
||||||
if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure");
|
if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|||||||