Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90ae50224d | ||
|
|
a2c3a4cd0e | ||
|
|
0402fa9186 | ||
|
|
1fd621ff6d | ||
|
|
a300206ba4 | ||
|
|
1ab57a7ce1 | ||
|
|
71d27aaafb | ||
|
|
a02ecffb7a | ||
|
|
c10561c752 | ||
|
|
d1745245e0 | ||
|
|
a55ffbb31b | ||
|
|
c0007893b4 | ||
|
|
aef8486fee | ||
|
|
d947801569 | ||
|
|
a2263a93ed | ||
|
|
13138e0fdd | ||
|
|
9c277f137c | ||
|
|
121aa2c388 | ||
|
|
4746c30001 | ||
|
|
4489daec09 | ||
|
|
ff773bfcde | ||
|
|
5ec2d38870 | ||
|
|
7b9bbf77c9 | ||
|
|
25f3d54c40 | ||
|
|
f98ec46979 | ||
|
|
f741fb8fcd | ||
|
|
4e196b2ac3 | ||
|
|
b426bcc097 | ||
|
|
3b53bfe4f3 | ||
|
|
59bb5f7d58 | ||
|
|
31769ce702 | ||
|
|
3934e010a2 | ||
|
|
fbd5dfc1b1 | ||
|
|
d70c4a5074 | ||
|
|
1d5648ca10 | ||
|
|
f6242d30b7 | ||
|
|
698fd00afb | ||
|
|
c1e6347717 | ||
|
|
243cd9d8bb | ||
|
|
7639db939f | ||
|
|
818e72b4d5 | ||
|
|
01bb1c1016 | ||
|
|
3e91dc4d6a | ||
|
|
5bd3d4b7d2 | ||
|
|
3caba150c6 | ||
|
|
7d80ada5ca | ||
|
|
5da9bbc38e | ||
|
|
6de249c1c6 | ||
|
|
6b48eb12c0 | ||
|
|
a3cb97b038 | ||
|
|
5d81f71e83 | ||
|
|
9c14eafe3d | ||
|
|
0a6cf7cd1d | ||
|
|
ae1f3898a2 | ||
|
|
93702a7a62 | ||
|
|
ae0b7ffa0a | ||
|
|
62469c9f41 | ||
|
|
166901dc72 | ||
|
|
066fbbfe1c | ||
|
|
4567c57199 | ||
|
|
6768cf53fd | ||
|
|
c0b6ce95b1 | ||
|
|
03c39c540b | ||
|
|
de639502aa | ||
|
|
f0a13bcd68 | ||
|
|
cb45b41f16 | ||
|
|
87fe4788a3 | ||
|
|
4bb79f9c55 | ||
|
|
2091f34e9e | ||
|
|
64348a15f1 | ||
|
|
ade8586ce6 | ||
|
|
ce743312e2 | ||
|
|
a075864756 | ||
|
|
1e03377bde | ||
|
|
ccbf067973 | ||
|
|
d5d8240967 | ||
|
|
93c3184d44 | ||
|
|
5bac1db28f | ||
|
|
1c714fda3f | ||
|
|
c9e8ee93a7 | ||
|
|
1d0fcde45d | ||
|
|
3841dbac84 | ||
|
|
e30f13bde0 | ||
|
|
8ad7ce1c2c | ||
|
|
d8462ecba2 | ||
|
|
b7e5ebef2a | ||
|
|
9698d2fb72 | ||
|
|
507bef196d | ||
|
|
6901c94cd6 | ||
|
|
78e5e2887e | ||
|
|
f70f829ff5 | ||
|
|
a71513bec6 | ||
|
|
bf30b9caf4 | ||
|
|
1adf84ccb7 | ||
|
|
a09af5eb6b | ||
|
|
0c654d22c8 | ||
|
|
7fee966f02 | ||
|
|
fc682263d0 | ||
|
|
2d76defbfe | ||
|
|
6bca3fb4bf | ||
|
|
ec24f98cca | ||
|
|
0551de4b5a | ||
|
|
ace9cfa950 | ||
|
|
854825caac | ||
|
|
fa41bcc2c2 | ||
|
|
d53200a846 | ||
|
|
b82063b266 | ||
|
|
d53a04211c | ||
|
|
2162aa9f18 | ||
|
|
338bede9b5 | ||
|
|
555ab9f8cf | ||
|
|
c87dd2121d | ||
|
|
6204b6d592 | ||
|
|
211a61b69b | ||
|
|
2e93736a77 | ||
|
|
3b82a23a35 | ||
|
|
a2a24bebec | ||
|
|
f74c2cd673 | ||
|
|
c14db94450 | ||
|
|
5d90708a0a | ||
|
|
f84fc63a43 | ||
|
|
529d3a5acd | ||
|
|
33e2240fac | ||
|
|
90cfc799e5 | ||
|
|
a85ecb32bd | ||
|
|
c986dbf241 | ||
|
|
750ee87a92 | ||
|
|
01d940b670 | ||
|
|
b2632bcf6c | ||
|
|
b024e1e1f4 | ||
|
|
88ae51acb3 | ||
|
|
881defaeb3 | ||
|
|
5ca1d5c6f4 | ||
|
|
4c16608e3c | ||
|
|
869e2718f6 | ||
|
|
e8ef725e13 | ||
|
|
170f948eee | ||
|
|
8ebd0f3a17 | ||
|
|
b567ce9d68 | ||
|
|
c92ef71d86 | ||
|
|
0e808d608b | ||
|
|
e34c000e44 | ||
|
|
56961e4ced | ||
|
|
0b1833c2cb | ||
|
|
3050733042 | ||
|
|
c2c47e24e0 | ||
|
|
a57b4df85f | ||
|
|
8537bfd85c | ||
|
|
3158deef43 | ||
|
|
43a5697b24 | ||
|
|
8ef75547ef | ||
|
|
e3c42c739b | ||
|
|
3cdb342bd5 | ||
|
|
36922b1369 | ||
|
|
b27c7389e3 | ||
|
|
24319975b6 | ||
|
|
21ec9e9c30 | ||
|
|
f1ea383f45 | ||
|
|
e5e17d009f | ||
|
|
7f178ef9c0 | ||
|
|
97c60cdf36 | ||
|
|
830fd4468f | ||
|
|
79e83d1c16 | ||
|
|
30ee23e905 | ||
|
|
eab626292c | ||
|
|
7892f48080 | ||
|
|
8e6267503b | ||
|
|
f7392f3dc9 | ||
|
|
0fd450af7b | ||
|
|
51f20e9982 | ||
|
|
11d5bfdaa9 | ||
|
|
b2496ab606 | ||
|
|
3d523c741b | ||
|
|
bdb673666f | ||
|
|
b3ef314830 | ||
|
|
357c648c3f | ||
|
|
54f05641e3 | ||
|
|
609d72b0ca | ||
|
|
3f054dceb4 | ||
|
|
9437021d2f | ||
|
|
ddf143ba6a | ||
|
|
6a617d70ed | ||
|
|
65de25a463 | ||
|
|
2108decb41 | ||
|
|
5e586aa025 | ||
|
|
e355f0a580 | ||
|
|
d3615c28db | ||
|
|
ae6d1fd3fa | ||
|
|
2b5b2ea7df | ||
|
|
110ec9079d | ||
|
|
c9b4d20f02 | ||
|
|
41249bf34b | ||
|
|
53ea32cabe | ||
|
|
143fc9ff6c | ||
|
|
cfc3451dcc | ||
|
|
8984cc93d6 | ||
|
|
547096d672 | ||
|
|
c9b1068298 | ||
|
|
cec205c842 | ||
|
|
7c33b48221 | ||
|
|
5ff30fe2e5 | ||
|
|
140f59d38e | ||
|
|
48deab92de | ||
|
|
f86796639e | ||
|
|
9b979d0e33 | ||
|
|
a4c9c4defe | ||
|
|
ac4f7ead3b | ||
|
|
809f2f9322 | ||
|
|
463a0fe38b | ||
|
|
bb6eaf6495 | ||
|
|
e916c365a1 | ||
|
|
c6ccf435ae | ||
|
|
a7fdceeccd | ||
|
|
4b3a36d5d8 | ||
|
|
744f36aac4 | ||
|
|
5f177f1c53 | ||
|
|
e2c0e3d437 | ||
|
|
5b292b5685 | ||
|
|
88b733b380 | ||
|
|
1850025156 | ||
|
|
43606f9c83 | ||
|
|
ec7efe88f5 | ||
|
|
2bfe43267e | ||
|
|
b97ad3f457 | ||
|
|
2313cca1b7 | ||
|
|
0998f10813 | ||
|
|
50c5b2bb90 | ||
|
|
7a25f7ef5b | ||
|
|
8b241da4df | ||
|
|
7097a03749 | ||
|
|
aacbbf4f9a | ||
|
|
c10d1b4011 | ||
|
|
f6ad59ab5c | ||
|
|
a7c75740b3 | ||
|
|
fdd4d8510f | ||
|
|
ac852abb8b | ||
|
|
2a9975f77b | ||
|
|
e712a3a0a3 | ||
|
|
47d2331ed8 | ||
|
|
b5ef32fea7 | ||
|
|
776128d16f | ||
|
|
08c5be5db3 | ||
|
|
06b70179da | ||
|
|
712318a244 | ||
|
|
f2d0924b87 | ||
|
|
d9c7e67125 | ||
|
|
298d24fa57 | ||
|
|
7ef85e0618 | ||
|
|
582b7f85ed | ||
|
|
9c92223468 | ||
|
|
a44ab3b475 | ||
|
|
95bdf20a87 | ||
|
|
7e0402e738 | ||
|
|
3ba70cc759 | ||
|
|
b05ae9b608 | ||
|
|
1a7b34ef28 | ||
|
|
2d598e6fed | ||
|
|
d005e5daf4 | ||
|
|
154eb09419 | ||
|
|
191fc74a51 | ||
|
|
ae4fcf7816 | ||
|
|
ca26cecc7a | ||
|
|
66bc1ca641 | ||
|
|
c31ee3c7f8 | ||
|
|
b67196f30d | ||
|
|
265c2869d1 | ||
|
|
6929964d65 | ||
|
|
70a537d1d7 | ||
|
|
8d24ff0353 | ||
|
|
d18a405779 | ||
|
|
c92dd11940 | ||
|
|
a97e9a627a | ||
|
|
27dc078aa6 | ||
|
|
4a498f03dc | ||
|
|
73f4c890cd | ||
|
|
e3959d5eba | ||
|
|
7a8b3496b4 | ||
|
|
a8ddf1d370 | ||
|
|
49cf880513 | ||
|
|
27af35c110 | ||
|
|
ade583948d | ||
|
|
5381369cb1 | ||
|
|
ca06a1d82f | ||
|
|
38c2c46823 | ||
|
|
b0b3fb517d | ||
|
|
7cbb8bbbbf | ||
|
|
5cbef6e094 | ||
|
|
a95e9e80d1 | ||
|
|
44303428c6 | ||
|
|
291824f49d | ||
|
|
bd6417de7f | ||
|
|
16bb8f1f9e | ||
|
|
af3da079d1 | ||
|
|
8572b4d09f | ||
|
|
134388ba6b | ||
|
|
a243020d37 | ||
|
|
63eeeaa1dd | ||
|
|
18fc3d3cd5 | ||
|
|
9938b17d4c | ||
|
|
b14c4bff96 | ||
|
|
30d9c84b1a | ||
|
|
0b31304c8d | ||
|
|
2c26df0e13 | ||
|
|
f372ffc64d | ||
|
|
d59cf02df0 | ||
|
|
c8c67f7c84 | ||
|
|
174bd3d4a7 | ||
|
|
5d76201fee | ||
|
|
902db38798 | ||
|
|
3870db1ba5 | ||
|
|
4da0216db0 | ||
|
|
e26be5a7b3 | ||
|
|
2c392952f9 | ||
|
|
c9227ee16b | ||
|
|
b4250489cf | ||
|
|
9cd5c63771 | ||
|
|
3f89cd1081 | ||
|
|
b824d213cb | ||
|
|
50993901b2 | ||
|
|
a3f2e84a37 | ||
|
|
17c19fbbb5 | ||
|
|
761758982e | ||
|
|
66b81817b5 | ||
|
|
3193d692c2 | ||
|
|
99ddca43a6 | ||
|
|
0d7626672d | ||
|
|
09d0fa29ee | ||
|
|
1a26ec6e8d | ||
|
|
74b1c75d64 | ||
|
|
498ab7bb12 | ||
|
|
ac6105463a | ||
|
|
c39061cb7b | ||
|
|
4d5bd32a00 | ||
|
|
c0da0f5e9e | ||
|
|
33dfc54069 | ||
|
|
ba2ad9b6b9 | ||
|
|
1aff63b114 | ||
|
|
6a3c34aa58 | ||
|
|
338f738c24 | ||
|
|
a155061328 | ||
|
|
2dde9d5aba | ||
|
|
9a0643b633 | ||
|
|
87125c2c01 | ||
|
|
ad4524d605 | ||
|
|
ef1abd3c07 | ||
|
|
2dbe408a49 | ||
|
|
5ec92c4d96 | ||
|
|
263134ce66 | ||
|
|
b095bffac6 | ||
|
|
1fc15dfd9d | ||
|
|
82ad249645 | ||
|
|
64bfdca5b9 | ||
|
|
a11f0c67bb | ||
|
|
ca77822ddf | ||
|
|
12f60b8c98 | ||
|
|
449cccf6c9 | ||
|
|
ace856a835 | ||
|
|
62487b5e76 | ||
|
|
2c3ad05812 | ||
|
|
9de03cd748 | ||
|
|
e8c9dc5cea | ||
|
|
c0987986e5 | ||
|
|
9f76eebd17 | ||
|
|
3c3f59e68f | ||
|
|
1f25b17c7d | ||
|
|
280a236e9e | ||
|
|
04212178b5 | ||
|
|
ad5ba6cdcf | ||
|
|
1da629f2ad | ||
|
|
569e2abccd | ||
|
|
77e373bff5 | ||
|
|
00d52282d0 | ||
|
|
4195b36dd7 | ||
|
|
f35b8ba9da | ||
|
|
b1e4d891cf | ||
|
|
462aed6811 | ||
|
|
e5ea8d272a | ||
|
|
55f67502f4 | ||
|
|
295ab0dbfa | ||
|
|
e866f0919f | ||
|
|
5b616fa269 | ||
|
|
daf3ab0aad | ||
|
|
754a821f17 | ||
|
|
9d3048346d | ||
|
|
b7e2c8e723 | ||
|
|
8be984ec45 | ||
|
|
7188862d32 | ||
|
|
c7a5e60bc6 | ||
|
|
292d370ab4 | ||
|
|
678d0cacbf | ||
|
|
70c9b90eaf | ||
|
|
259fb2d0fb | ||
|
|
e6e848bfe9 | ||
|
|
a6694838e1 | ||
|
|
96b480a96d | ||
|
|
525f3fab33 |
@@ -23,6 +23,7 @@ zstdmt
|
||||
# Test artefacts
|
||||
tmp*
|
||||
dictionary*
|
||||
NUL
|
||||
|
||||
# Build artefacts
|
||||
projects/
|
||||
|
||||
@@ -1,48 +1,50 @@
|
||||
# Long tests: run on commits to master branch/cron builds
|
||||
# Medium Tests: Run on all commits/PRs to dev branch
|
||||
|
||||
language: c
|
||||
sudo: required
|
||||
dist: trusty
|
||||
sudo: required
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Ubuntu 14.04
|
||||
- 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 && CC=gcc-6 make -j all && make clean && CC=gcc-6 make clean uasan-test-zstd'
|
||||
- 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 gcc7install && CC=gcc-7 make clean uasan-test-zstd'
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-test-zstd'
|
||||
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-fuzztest'
|
||||
- env: Cmd='make gcc6install libc6install && CC=gcc-6 CFLAGS=-m32 make clean uasan-fuzztest'
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-fuzztest'
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean tsan-test-zstream'
|
||||
|
||||
- env: Cmd='make -C tests test-fuzzer-stackmode'
|
||||
|
||||
- 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 armfuzz'
|
||||
- env: Cmd='make arminstall && make aarch64fuzz'
|
||||
|
||||
- env: Cmd='make arminstall && make armtest'
|
||||
- env: Cmd='make arminstall && make aarch64test'
|
||||
- env: Cmd='make ppcinstall && make ppctest'
|
||||
- env: Cmd='make ppcinstall && make ppc64test'
|
||||
- env: Cmd='make ppcinstall && make ppcfuzz'
|
||||
- env: Cmd='make ppcinstall && make ppc64fuzz'
|
||||
- env: Cmd='make -j uasanregressiontest && make clean && make -j msanregressiontest'
|
||||
|
||||
- env: Cmd='make gpp6install valgrindinstall && make -C zlibWrapper test && make -C zlibWrapper valgrindTest'
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zstd-nolegacy'
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zbuff'
|
||||
|
||||
- env: Cmd='make -j uasanregressiontest'
|
||||
- env: Cmd='make -j msanregressiontest'
|
||||
|
||||
- env: Cmd='make -C tests versionsTest && make lz4install && make clean && make -C tests test-lz4'
|
||||
|
||||
# OS X Mavericks
|
||||
- env: Cmd="make test"
|
||||
os: osx
|
||||
|
||||
before_install:
|
||||
- if [ `uname` = "Darwin" ]; then brew update; fi
|
||||
|
||||
install:
|
||||
- if [ `uname` = "Darwin" ]; then brew install xz; fi
|
||||
- env: Cmd='make lz4install && make -C tests test-lz4 test-pool && make clean && bash tests/libzstd_partial_builds.sh'
|
||||
|
||||
# tag-specific test
|
||||
- if: tag =~ ^v[0-9]\.[0-9]
|
||||
env: Cmd='make -C tests checkTag && tests/checkTag $TRAVIS_BRANCH'
|
||||
|
||||
# additional tests for master branch and cron job
|
||||
- env: Cmd="make test"
|
||||
os: osx
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean tsan-test-zstream'
|
||||
- env: Cmd='make cxxtest && make clean && make gnu90build && make clean && make cmakebuild && make clean && make travis-install'
|
||||
- env: Cmd='make gpp6install valgrindinstall && make -C zlibWrapper test && make -C zlibWrapper valgrindTest'
|
||||
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
@@ -54,13 +56,7 @@ branches:
|
||||
script:
|
||||
- JOB_NUMBER=$(echo $TRAVIS_JOB_NUMBER | sed -e 's:[0-9][0-9]*\.\(.*\):\1:')
|
||||
- echo JOB_NUMBER=$JOB_NUMBER TRAVIS_BRANCH=$TRAVIS_BRANCH TRAVIS_EVENT_TYPE=$TRAVIS_EVENT_TYPE TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST
|
||||
- export FUZZERTEST=-T3mn;
|
||||
export ZSTREAM_TESTTIME=-T80s;
|
||||
export DECODECORPUS_TESTTIME=-T40s;
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then
|
||||
date;
|
||||
git fetch origin dev;
|
||||
git checkout -f FETCH_HEAD;
|
||||
date;
|
||||
fi;
|
||||
- export FUZZERTEST=-T2mn;
|
||||
export ZSTREAM_TESTTIME=-T2mn;
|
||||
export DECODECORPUS_TESTTIME=-T1mn;
|
||||
sh -c "$Cmd" || travis_terminate 1;
|
||||
|
||||
@@ -27,7 +27,7 @@ endif
|
||||
default: lib-release zstd-release
|
||||
|
||||
.PHONY: all
|
||||
all: | allmost examples manual contrib
|
||||
all: allmost examples manual contrib
|
||||
|
||||
.PHONY: allmost
|
||||
allmost: allzstd
|
||||
@@ -35,8 +35,7 @@ allmost: allzstd
|
||||
|
||||
#skip zwrapper, can't build that on alternate architectures without the proper zlib installed
|
||||
.PHONY: allzstd
|
||||
allzstd:
|
||||
$(MAKE) -C $(ZSTDDIR) all
|
||||
allzstd: lib
|
||||
$(MAKE) -C $(PRGDIR) all
|
||||
$(MAKE) -C $(TESTDIR) all
|
||||
|
||||
@@ -45,24 +44,15 @@ all32:
|
||||
$(MAKE) -C $(PRGDIR) zstd32
|
||||
$(MAKE) -C $(TESTDIR) all32
|
||||
|
||||
.PHONY: lib
|
||||
lib:
|
||||
.PHONY: lib lib-release
|
||||
lib lib-release:
|
||||
@$(MAKE) -C $(ZSTDDIR) $@
|
||||
|
||||
.PHONY: lib-release
|
||||
lib-release:
|
||||
@$(MAKE) -C $(ZSTDDIR)
|
||||
|
||||
.PHONY: zstd
|
||||
zstd:
|
||||
.PHONY: zstd zstd-release
|
||||
zstd zstd-release:
|
||||
@$(MAKE) -C $(PRGDIR) $@
|
||||
cp $(PRGDIR)/zstd$(EXT) .
|
||||
|
||||
.PHONY: zstd-release
|
||||
zstd-release:
|
||||
@$(MAKE) -C $(PRGDIR)
|
||||
cp $(PRGDIR)/zstd$(EXT) .
|
||||
|
||||
.PHONY: zstdmt
|
||||
zstdmt:
|
||||
@$(MAKE) -C $(PRGDIR) $@
|
||||
@@ -74,7 +64,7 @@ zlibwrapper:
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(MAKE) -C $(PRGDIR) allVariants MOREFLAGS+="-g -DZSTD_DEBUG=1"
|
||||
$(MAKE) -C $(PRGDIR) allVariants MOREFLAGS+="-g -DDEBUGLEVEL=1"
|
||||
$(MAKE) -C $(TESTDIR) $@
|
||||
|
||||
.PHONY: shortest
|
||||
@@ -85,7 +75,7 @@ shortest:
|
||||
check: shortest
|
||||
|
||||
.PHONY: examples
|
||||
examples:
|
||||
examples: lib
|
||||
CPPFLAGS=-I../lib LDFLAGS=-L../lib $(MAKE) -C examples/ all
|
||||
|
||||
.PHONY: manual
|
||||
@@ -118,9 +108,9 @@ clean:
|
||||
@echo Cleaning completed
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# make install is validated only for Linux, OSX, Hurd and some BSD targets
|
||||
# make install is validated only for Linux, macOS, Hurd and some BSD targets
|
||||
#------------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly NetBSD MSYS_NT))
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly NetBSD MSYS_NT))
|
||||
|
||||
HOST_OS = POSIX
|
||||
CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZLIB_SUPPORT:BOOL=ON -DZSTD_LZMA_SUPPORT:BOOL=ON
|
||||
@@ -183,6 +173,7 @@ armfuzz: clean
|
||||
CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static MOREFLAGS="-static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest
|
||||
|
||||
aarch64fuzz: clean
|
||||
ld -v
|
||||
CC=aarch64-linux-gnu-gcc QEMU_SYS=qemu-aarch64-static MOREFLAGS="-static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest
|
||||
|
||||
ppcfuzz: clean
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
v1.3.5
|
||||
perf: much faster dictionary compression, by @felixhandte
|
||||
perf: small quality improvement for dictionary generation, by @terrelln
|
||||
perf: slightly improved high compression levels (notably level 19)
|
||||
mem : automatic memory release for long duration contexts
|
||||
cli : fix : overlapLog can be manually set
|
||||
cli : fix : decoding invalid lz4 frames
|
||||
api : fix : performance degradation for dictionary compression when using advanced API, by @terrelln
|
||||
api : change : clarify ZSTD_CCtx_reset() vs ZSTD_CCtx_resetParameters(), by @terrelln
|
||||
build: select custom libzstd scope through control macros, by @GeorgeLu97
|
||||
build: OpenBSD patch, by @bket
|
||||
build: make and make all are compatible with -j
|
||||
doc : clarify zstd_compression_format.md, updated for IETF RFC process
|
||||
misc: pzstd compatible with reproducible compilation, by @lamby
|
||||
|
||||
v1.3.4
|
||||
perf: faster speed (especially decoding speed) on recent cpus (haswell+)
|
||||
perf: much better performance associating --long with multi-threading, by @terrelln
|
||||
|
||||
@@ -4,7 +4,7 @@ __Zstandard__, or `zstd` as short version, is a fast lossless compression algori
|
||||
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](https://github.com/Cyan4973/FiniteStateEntropy).
|
||||
|
||||
The project is provided as an open-source BSD-licensed **C** library,
|
||||
The project is provided as an open-source dual [BSD](LICENSE) and [GPLv2](COPYING) licensed **C** library,
|
||||
and a command line utility producing and decoding `.zst`, `.gz`, `.xz` and `.lz4` files.
|
||||
Should your project require another programming language,
|
||||
a list of known ports and bindings is provided on [Zstandard homepage](http://www.zstd.net/#other-languages).
|
||||
|
||||
@@ -41,4 +41,4 @@ They consist of the following tests:
|
||||
- `pzstd` with asan and tsan, as well as in 32-bits mode
|
||||
- Testing `zstd` with legacy mode off
|
||||
- Testing `zbuff` (old streaming API)
|
||||
- Entire test suite and make install on OS X
|
||||
- Entire test suite and make install on macOS
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
*.user
|
||||
*.opendb
|
||||
|
||||
VS2005/
|
||||
VS2008/
|
||||
VS2008/bin/
|
||||
VS2010/bin/
|
||||
VS2010/zwrapbench/
|
||||
VS2012/bin/
|
||||
VS2013/bin/
|
||||
VS2015/bin/
|
||||
VS2012/
|
||||
VS2013/
|
||||
VS2015/
|
||||
Studio*
|
||||
|
||||
# CMake
|
||||
cmake/build/
|
||||
|
||||
@@ -332,6 +332,10 @@
|
||||
RelativePath="..\..\..\lib\common\entropy_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\hist.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\common\error_private.c"
|
||||
>
|
||||
|
||||
@@ -352,6 +352,10 @@
|
||||
RelativePath="..\..\..\lib\common\entropy_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\hist.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\common\error_private.c"
|
||||
>
|
||||
|
||||
@@ -356,6 +356,10 @@
|
||||
RelativePath="..\..\..\lib\common\entropy_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\hist.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\common\error_private.c"
|
||||
>
|
||||
|
||||
@@ -348,6 +348,10 @@
|
||||
RelativePath="..\..\..\lib\common\entropy_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\hist.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\common\error_private.c"
|
||||
>
|
||||
|
||||
@@ -156,12 +156,14 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\lib\common\entropy_common.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\debug.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\fse_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\zstd_common.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\error_private.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\pool.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\threading.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\xxhash.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\hist.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\fse_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\huf_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_compress.c" />
|
||||
|
||||
@@ -156,8 +156,10 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\lib\common\pool.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\debug.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\threading.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\entropy_common.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\hist.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\error_private.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\fse_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\xxhash.c" />
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\lib\common\pool.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\debug.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\threading.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\entropy_common.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\hist.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\error_private.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\xxhash.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\zstd_common.c" />
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\lib\common\pool.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\debug.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\threading.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\entropy_common.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\hist.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\error_private.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\xxhash.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\zstd_common.c" />
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\lib\common\debug.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\entropy_common.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\error_private.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\pool.c" />
|
||||
@@ -26,6 +27,7 @@
|
||||
<ClCompile Include="..\..\..\lib\common\xxhash.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\zstd_common.c" />
|
||||
<ClCompile Include="..\..\..\lib\common\fse_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\hist.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\fse_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\huf_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstdmt_compress.c" />
|
||||
|
||||
@@ -34,6 +34,7 @@ SET(Sources
|
||||
${LIBRARY_DIR}/common/zstd_common.c
|
||||
${LIBRARY_DIR}/common/error_private.c
|
||||
${LIBRARY_DIR}/common/xxhash.c
|
||||
${LIBRARY_DIR}/compress/hist.c
|
||||
${LIBRARY_DIR}/compress/fse_compress.c
|
||||
${LIBRARY_DIR}/compress/huf_compress.c
|
||||
${LIBRARY_DIR}/compress/zstd_compress.c
|
||||
@@ -54,6 +55,7 @@ SET(Sources
|
||||
|
||||
SET(Headers
|
||||
${LIBRARY_DIR}/zstd.h
|
||||
${LIBRARY_DIR}/common/debug.h
|
||||
${LIBRARY_DIR}/common/pool.h
|
||||
${LIBRARY_DIR}/common/threading.h
|
||||
${LIBRARY_DIR}/common/bitstream.h
|
||||
@@ -63,6 +65,7 @@ SET(Headers
|
||||
${LIBRARY_DIR}/common/huf.h
|
||||
${LIBRARY_DIR}/common/mem.h
|
||||
${LIBRARY_DIR}/common/zstd_internal.h
|
||||
${LIBRARY_DIR}/compress/hist.h
|
||||
${LIBRARY_DIR}/compress/zstd_compress_internal.h
|
||||
${LIBRARY_DIR}/compress/zstd_fast.h
|
||||
${LIBRARY_DIR}/compress/zstd_double_fast.h
|
||||
@@ -105,9 +108,21 @@ ENDIF (MSVC)
|
||||
# Split project to static and shared libraries build
|
||||
IF (ZSTD_BUILD_SHARED)
|
||||
ADD_LIBRARY(libzstd_shared SHARED ${Sources} ${Headers} ${PlatformDependResources})
|
||||
IF (ZSTD_MULTITHREAD_SUPPORT)
|
||||
SET_PROPERTY(TARGET libzstd_shared APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
|
||||
IF (UNIX)
|
||||
TARGET_LINK_LIBRARIES(libzstd_shared ${THREADS_LIBS})
|
||||
ENDIF ()
|
||||
ENDIF()
|
||||
ENDIF (ZSTD_BUILD_SHARED)
|
||||
IF (ZSTD_BUILD_STATIC)
|
||||
ADD_LIBRARY(libzstd_static STATIC ${Sources} ${Headers})
|
||||
IF (ZSTD_MULTITHREAD_SUPPORT)
|
||||
SET_PROPERTY(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
|
||||
IF (UNIX)
|
||||
TARGET_LINK_LIBRARIES(libzstd_static ${THREADS_LIBS})
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
ENDIF (ZSTD_BUILD_STATIC)
|
||||
|
||||
# Add specific compile definitions for MSVC project
|
||||
@@ -120,17 +135,6 @@ IF (MSVC)
|
||||
ENDIF (ZSTD_BUILD_STATIC)
|
||||
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
|
||||
IF (MSVC)
|
||||
SET(STATIC_LIBRARY_BASE_NAME zstd_static)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ################################################################
|
||||
# zstd - Makefile
|
||||
# Copyright (C) Yann Collet 2014-2016
|
||||
# Copyright (C) Yann Collet 2014-present
|
||||
# All rights reserved.
|
||||
#
|
||||
# BSD license
|
||||
@@ -47,7 +47,7 @@ ADD_EXECUTABLE(fuzzer ${PROGRAMS_DIR}/datagen.c ${TESTS_DIR}/fuzzer.c)
|
||||
TARGET_LINK_LIBRARIES(fuzzer libzstd_static)
|
||||
|
||||
IF (UNIX)
|
||||
ADD_EXECUTABLE(paramgrill ${PROGRAMS_DIR}/datagen.c ${TESTS_DIR}/paramgrill.c)
|
||||
ADD_EXECUTABLE(paramgrill ${PROGRAMS_DIR}/bench.c ${PROGRAMS_DIR}/datagen.c ${TESTS_DIR}/paramgrill.c)
|
||||
TARGET_LINK_LIBRARIES(paramgrill libzstd_static m) #m is math library
|
||||
|
||||
ADD_EXECUTABLE(datagen ${PROGRAMS_DIR}/datagen.c ${TESTS_DIR}/datagencli.c)
|
||||
|
||||
@@ -48,7 +48,7 @@ clean:
|
||||
@echo "finished cleaning"
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets
|
||||
# make install is validated only for Linux, macOS, BSD, Hurd and Solaris targets
|
||||
#-----------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
CXXFLAGS ?= -O3
|
||||
CXXFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wno-comment
|
||||
CXXFLAGS += $(MOREFLAGS)
|
||||
FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(CXXFLAGS) $(LDFLAGS)
|
||||
FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
ZSTDAPI = ../../lib/zstd.h
|
||||
ZSTDMANUAL = ../../doc/zstd_manual.html
|
||||
|
||||
@@ -42,7 +42,7 @@ PZSTD_LDFLAGS =
|
||||
EXTRA_FLAGS =
|
||||
ALL_CFLAGS = $(EXTRA_FLAGS) $(CPPFLAGS) $(PZSTD_CPPFLAGS) $(CFLAGS) $(PZSTD_CFLAGS)
|
||||
ALL_CXXFLAGS = $(EXTRA_FLAGS) $(CPPFLAGS) $(PZSTD_CPPFLAGS) $(CXXFLAGS) $(PZSTD_CXXFLAGS)
|
||||
ALL_LDFLAGS = $(EXTRA_FLAGS) $(LDFLAGS) $(PZSTD_LDFLAGS)
|
||||
ALL_LDFLAGS = $(EXTRA_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(PZSTD_LDFLAGS)
|
||||
|
||||
|
||||
# gtest libraries need to go before "-lpthread" because they depend on it.
|
||||
@@ -50,7 +50,7 @@ GTEST_LIB = -L googletest/build/googlemock/gtest
|
||||
LIBS =
|
||||
|
||||
# Compilation commands
|
||||
LD_COMMAND = $(CXX) $^ $(ALL_LDFLAGS) $(LIBS) -lpthread -o $@
|
||||
LD_COMMAND = $(CXX) $^ $(ALL_LDFLAGS) $(LIBS) -pthread -o $@
|
||||
CC_COMMAND = $(CC) $(DEPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||
CXX_COMMAND = $(CXX) $(DEPFLAGS) $(ALL_CXXFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ void usage() {
|
||||
std::fprintf(stderr, "Usage:\n");
|
||||
std::fprintf(stderr, " pzstd [args] [FILE(s)]\n");
|
||||
std::fprintf(stderr, "Parallel ZSTD options:\n");
|
||||
std::fprintf(stderr, " -p, --processes # : number of threads to use for (de)compression (default:%d)\n", defaultNumThreads());
|
||||
std::fprintf(stderr, " -p, --processes # : number of threads to use for (de)compression (default:<numcpus>)\n");
|
||||
|
||||
std::fprintf(stderr, "ZSTD options:\n");
|
||||
std::fprintf(stderr, " -# : # compression level (1-%d, default:%d)\n", kMaxNonUltraCompressionLevel, kDefaultCompressionLevel);
|
||||
|
||||
@@ -9,13 +9,16 @@
|
||||
|
||||
# This Makefile presumes libzstd is built, using `make` in / or /lib/
|
||||
|
||||
LDFLAGS += ../../../lib/libzstd.a
|
||||
ZSTDLIB_PATH = ../../../lib
|
||||
ZSTDLIB_NAME = libzstd.a
|
||||
ZSTDLIB = $(ZSTDLIB_PATH)/$(ZSTDLIB_NAME)
|
||||
|
||||
CPPFLAGS += -I../ -I../../../lib -I../../../lib/common
|
||||
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -g
|
||||
|
||||
SEEKABLE_OBJS = ../zstdseek_compress.c ../zstdseek_decompress.c
|
||||
SEEKABLE_OBJS = ../zstdseek_compress.c ../zstdseek_decompress.c $(ZSTDLIB)
|
||||
|
||||
.PHONY: default all clean test
|
||||
|
||||
@@ -23,6 +26,9 @@ default: all
|
||||
|
||||
all: seekable_compression seekable_decompression parallel_processing
|
||||
|
||||
$(ZSTDLIB):
|
||||
make -C $(ZSTDLIB_PATH) $(ZSTDLIB_NAME)
|
||||
|
||||
seekable_compression : seekable_compression.c $(SEEKABLE_OBJS)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "zstd.h" /* ZSTDLIB_API */
|
||||
|
||||
static const unsigned ZSTD_seekTableFooterSize = 9;
|
||||
|
||||
#define ZSTD_seekTableFooterSize 9
|
||||
|
||||
#define ZSTD_SEEKABLE_MAGICNUMBER 0x8F92EAB1
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#endif
|
||||
|
||||
/* ************************************************************
|
||||
* Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW
|
||||
* Avoid fseek()'s 2GiB barrier with MSVC, macOS, *BSD, MinGW
|
||||
***************************************************************/
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
# define LONG_SEEK _fseeki64
|
||||
@@ -88,7 +88,7 @@ static int ZSTD_seekable_read_FILE(void* opaque, void* buffer, size_t n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ZSTD_seekable_seek_FILE(void* opaque, S64 offset, int origin)
|
||||
static int ZSTD_seekable_seek_FILE(void* opaque, long long offset, int origin)
|
||||
{
|
||||
int const ret = LONG_SEEK((FILE*)opaque, offset, origin);
|
||||
if (ret) return ret;
|
||||
@@ -110,7 +110,7 @@ static int ZSTD_seekable_read_buff(void* opaque, void* buffer, size_t n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ZSTD_seekable_seek_buff(void* opaque, S64 offset, int origin)
|
||||
static int ZSTD_seekable_seek_buff(void* opaque, long long offset, int origin)
|
||||
{
|
||||
buffWrapper_t* buff = (buffWrapper_t*) opaque;
|
||||
unsigned long long newOffset;
|
||||
@@ -197,7 +197,7 @@ size_t ZSTD_seekable_free(ZSTD_seekable* zs)
|
||||
* Performs a binary search to find the last frame with a decompressed offset
|
||||
* <= pos
|
||||
* @return : the frame's index */
|
||||
U32 ZSTD_seekable_offsetToFrameIndex(ZSTD_seekable* const zs, U64 pos)
|
||||
U32 ZSTD_seekable_offsetToFrameIndex(ZSTD_seekable* const zs, unsigned long long pos)
|
||||
{
|
||||
U32 lo = 0;
|
||||
U32 hi = zs->seekTable.tableLen;
|
||||
@@ -222,13 +222,13 @@ U32 ZSTD_seekable_getNumFrames(ZSTD_seekable* const zs)
|
||||
return zs->seekTable.tableLen;
|
||||
}
|
||||
|
||||
U64 ZSTD_seekable_getFrameCompressedOffset(ZSTD_seekable* const zs, U32 frameIndex)
|
||||
unsigned long long ZSTD_seekable_getFrameCompressedOffset(ZSTD_seekable* const zs, U32 frameIndex)
|
||||
{
|
||||
if (frameIndex >= zs->seekTable.tableLen) return ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE;
|
||||
return zs->seekTable.entries[frameIndex].cOffset;
|
||||
}
|
||||
|
||||
U64 ZSTD_seekable_getFrameDecompressedOffset(ZSTD_seekable* const zs, U32 frameIndex)
|
||||
unsigned long long ZSTD_seekable_getFrameDecompressedOffset(ZSTD_seekable* const zs, U32 frameIndex)
|
||||
{
|
||||
if (frameIndex >= zs->seekTable.tableLen) return ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE;
|
||||
return zs->seekTable.entries[frameIndex].dOffset;
|
||||
@@ -294,7 +294,6 @@ static size_t ZSTD_seekable_loadSeekTable(ZSTD_seekable* zs)
|
||||
{ /* Allocate an extra entry at the end so that we can do size
|
||||
* computations on the last element without special case */
|
||||
seekEntry_t* entries = (seekEntry_t*)malloc(sizeof(seekEntry_t) * (numFrames + 1));
|
||||
const BYTE* tableBase = zs->inBuff + ZSTD_skippableHeaderSize;
|
||||
|
||||
U32 idx = 0;
|
||||
U32 pos = 8;
|
||||
@@ -372,7 +371,7 @@ size_t ZSTD_seekable_initAdvanced(ZSTD_seekable* zs, ZSTD_seekable_customFile sr
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, U64 offset)
|
||||
size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsigned long long offset)
|
||||
{
|
||||
U32 targetFrame = ZSTD_seekable_offsetToFrameIndex(zs, offset);
|
||||
do {
|
||||
|
||||
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 92 KiB |
@@ -16,7 +16,7 @@ Distribution of this document is unlimited.
|
||||
|
||||
### Version
|
||||
|
||||
0.2.6 (19/08/17)
|
||||
0.2.8 (30/05/18)
|
||||
|
||||
|
||||
Introduction
|
||||
@@ -27,6 +27,8 @@ that is independent of CPU type, operating system,
|
||||
file system and character set, suitable for
|
||||
file compression, pipe and streaming compression,
|
||||
using the [Zstandard algorithm](http://www.zstandard.org).
|
||||
The text of the specification assumes a basic background in programming
|
||||
at the level of bits and other primitive data representations.
|
||||
|
||||
The data can be produced or consumed,
|
||||
even for an arbitrarily long sequentially presented input data stream,
|
||||
@@ -39,11 +41,6 @@ for detection of data corruption.
|
||||
The data format defined by this specification
|
||||
does not attempt to allow random access to compressed data.
|
||||
|
||||
This specification is intended for use by implementers of software
|
||||
to compress data into Zstandard format and/or decompress data from Zstandard format.
|
||||
The text of the specification assumes a basic background in programming
|
||||
at the level of bits and other primitive data representations.
|
||||
|
||||
Unless otherwise indicated below,
|
||||
a compliant compressor must produce data sets
|
||||
that conform to the specifications presented here.
|
||||
@@ -57,6 +54,12 @@ Whenever it does not support a parameter defined in the compressed stream,
|
||||
it must produce a non-ambiguous error code and associated error message
|
||||
explaining which parameter is unsupported.
|
||||
|
||||
This specification is intended for use by implementers of software
|
||||
to compress data into Zstandard format and/or decompress data from Zstandard format.
|
||||
The Zstandard format is supported by an open source reference implementation,
|
||||
written in portable C, and available at : https://github.com/facebook/zstd .
|
||||
|
||||
|
||||
### Overall conventions
|
||||
In this document:
|
||||
- square brackets i.e. `[` and `]` are used to indicate optional fields or parameters.
|
||||
@@ -92,14 +95,14 @@ Overview
|
||||
Frames
|
||||
------
|
||||
Zstandard compressed data is made of one or more __frames__.
|
||||
Each frame is independent and can be decompressed indepedently of other frames.
|
||||
Each frame is independent and can be decompressed independently of other frames.
|
||||
The decompressed content of multiple concatenated frames is the concatenation of
|
||||
each frame decompressed content.
|
||||
|
||||
There are two frame formats defined by Zstandard:
|
||||
Zstandard frames and Skippable frames.
|
||||
Zstandard frames contain compressed data, while
|
||||
skippable frames contain no data and can be used for metadata.
|
||||
skippable frames contain custom user metadata.
|
||||
|
||||
## Zstandard frames
|
||||
The structure of a single Zstandard frame is following:
|
||||
@@ -112,6 +115,11 @@ __`Magic_Number`__
|
||||
|
||||
4 Bytes, __little-endian__ format.
|
||||
Value : 0xFD2FB528
|
||||
Note: This value was selected to be less probable to find at the beginning of some random file.
|
||||
It avoids trivial patterns (0x00, 0xFF, repeated bytes, increasing bytes, etc.),
|
||||
contains byte values outside of ASCII range,
|
||||
and doesn't map into UTF8 space.
|
||||
It reduces the chances that a text file represent this value by accident.
|
||||
|
||||
__`Frame_Header`__
|
||||
|
||||
@@ -171,8 +179,8 @@ according to the following table:
|
||||
|`FCS_Field_Size`| 0 or 1 | 2 | 4 | 8 |
|
||||
|
||||
When `Flag_Value` is `0`, `FCS_Field_Size` depends on `Single_Segment_flag` :
|
||||
if `Single_Segment_flag` is set, `Field_Size` is 1.
|
||||
Otherwise, `Field_Size` is 0 : `Frame_Content_Size` is not provided.
|
||||
if `Single_Segment_flag` is set, `FCS_Field_Size` is 1.
|
||||
Otherwise, `FCS_Field_Size` is 0 : `Frame_Content_Size` is not provided.
|
||||
|
||||
__`Single_Segment_flag`__
|
||||
|
||||
@@ -196,10 +204,10 @@ depending on local limitations.
|
||||
|
||||
__`Unused_bit`__
|
||||
|
||||
The value of this bit should be set to zero.
|
||||
A decoder compliant with this specification version shall not interpret it.
|
||||
It might be used in a future version,
|
||||
to signal a property which is not mandatory to properly decode the frame.
|
||||
A decoder compliant with this specification version shall not interpret this bit.
|
||||
It might be used in any future version,
|
||||
to signal a property which is transparent to properly decode the frame.
|
||||
An encoder compliant with this specification version must set this bit to zero.
|
||||
|
||||
__`Reserved_bit`__
|
||||
|
||||
@@ -218,11 +226,11 @@ __`Dictionary_ID_flag`__
|
||||
|
||||
This is a 2-bits flag (`= FHD & 3`),
|
||||
telling if a dictionary ID is provided within the header.
|
||||
It also specifies the size of this field as `Field_Size`.
|
||||
It also specifies the size of this field as `DID_Field_Size`.
|
||||
|
||||
|`Flag_Value`| 0 | 1 | 2 | 3 |
|
||||
| ---------- | --- | --- | --- | --- |
|
||||
|`Field_Size`| 0 | 1 | 2 | 4 |
|
||||
|`Flag_Value` | 0 | 1 | 2 | 3 |
|
||||
| -------------- | --- | --- | --- | --- |
|
||||
|`DID_Field_Size`| 0 | 1 | 2 | 4 |
|
||||
|
||||
#### `Window_Descriptor`
|
||||
|
||||
@@ -249,6 +257,9 @@ Window_Size = windowBase + windowAdd;
|
||||
The minimum `Window_Size` is 1 KB.
|
||||
The maximum `Window_Size` is `(1<<41) + 7*(1<<38)` bytes, which is 3.75 TB.
|
||||
|
||||
In general, larger `Window_Size` tend to improve compression ratio,
|
||||
but at the cost of memory usage.
|
||||
|
||||
To properly decode compressed data,
|
||||
a decoder will need to allocate a buffer of at least `Window_Size` bytes.
|
||||
|
||||
@@ -257,8 +268,8 @@ a decoder is allowed to reject a compressed frame
|
||||
which requests a memory size beyond decoder's authorized range.
|
||||
|
||||
For improved interoperability,
|
||||
decoders are recommended to be compatible with `Window_Size <= 8 MB`,
|
||||
and encoders are recommended to not request more than 8 MB.
|
||||
it's recommended for decoders to support `Window_Size` of up to 8 MB,
|
||||
and it's recommended for encoders to not generate frame requiring `Window_Size` larger than 8 MB.
|
||||
It's merely a recommendation though,
|
||||
decoders are free to support larger or lower limits,
|
||||
depending on local limitations.
|
||||
@@ -268,9 +279,10 @@ depending on local limitations.
|
||||
This is a variable size field, which contains
|
||||
the ID of the dictionary required to properly decode the frame.
|
||||
`Dictionary_ID` field is optional. When it's not present,
|
||||
it's up to the decoder to make sure it uses the correct dictionary.
|
||||
it's up to the decoder to know which dictionary to use.
|
||||
|
||||
Field size depends on `Dictionary_ID_flag`.
|
||||
`Dictionary_ID` field size is provided by `DID_Field_Size`.
|
||||
`DID_Field_Size` is directly derived from value of `Dictionary_ID_flag`.
|
||||
1 byte can represent an ID 0-255.
|
||||
2 bytes can represent an ID 0-65535.
|
||||
4 bytes can represent an ID 0-4294967295.
|
||||
@@ -280,13 +292,21 @@ It's allowed to represent a small ID (for example `13`)
|
||||
with a large 4-bytes dictionary ID, even if it is less efficient.
|
||||
|
||||
_Reserved ranges :_
|
||||
If the frame is going to be distributed in a private environment,
|
||||
any dictionary ID can be used.
|
||||
However, for public distribution of compressed frames using a dictionary,
|
||||
the following ranges are reserved and shall not be used :
|
||||
Within private environments, any `Dictionary_ID` can be used.
|
||||
|
||||
However, for frames and dictionaries distributed in public space,
|
||||
`Dictionary_ID` must be attributed carefully.
|
||||
Rules for public environment are not yet decided,
|
||||
but the following ranges are reserved for some future registrar :
|
||||
- low range : `<= 32767`
|
||||
- high range : `>= (1 << 31)`
|
||||
|
||||
Outside of these ranges, any value of `Dictionary_ID`
|
||||
which is both `>= 32768` and `< (1<<31)` can be used freely,
|
||||
even in public environment.
|
||||
|
||||
|
||||
|
||||
#### `Frame_Content_Size`
|
||||
|
||||
This is the original (uncompressed) size. This information is optional.
|
||||
@@ -359,20 +379,21 @@ There are 4 block types :
|
||||
|
||||
- `Reserved` - this is not a block.
|
||||
This value cannot be used with current version of this specification.
|
||||
If such a value is present, it is considered corrupted data.
|
||||
|
||||
__`Block_Size`__
|
||||
|
||||
The upper 21 bits of `Block_Header` represent the `Block_Size`.
|
||||
`Block_Size` is the size of the block excluding the header.
|
||||
A block can contain any number of bytes (even zero), up to
|
||||
`Block_Maximum_Decompressed_Size`, which is the smallest of:
|
||||
- Window_Size
|
||||
- 128 KB
|
||||
|
||||
Block sizes must respect a few rules :
|
||||
- For `Compressed_Block`, `Block_Size` is always strictly less than decompressed size.
|
||||
- Block decompressed size is always <= `Window_Size`
|
||||
- Block decompressed size is always <= 128 KB.
|
||||
|
||||
A block can contain any number of bytes (even empty),
|
||||
up to `Block_Maximum_Decompressed_Size`, which is the smallest of :
|
||||
- `Window_Size`
|
||||
- 128 KB
|
||||
A `Compressed_Block` has the extra restriction that `Block_Size` is always
|
||||
strictly less than the decompressed size.
|
||||
If this condition cannot be respected,
|
||||
the block must be sent uncompressed instead (`Raw_Block`).
|
||||
|
||||
|
||||
Compressed Blocks
|
||||
@@ -390,10 +411,16 @@ data in [Sequence Execution](#sequence-execution)
|
||||
#### Prerequisites
|
||||
To decode a compressed block, the following elements are necessary :
|
||||
- Previous decoded data, up to a distance of `Window_Size`,
|
||||
or all previously decoded data when `Single_Segment_flag` is set.
|
||||
or beginning of the Frame, whichever is smaller.
|
||||
- List of "recent offsets" from previous `Compressed_Block`.
|
||||
- Decoding tables of previous `Compressed_Block` for each symbol type
|
||||
(literals, literals lengths, match lengths, offsets).
|
||||
- The previous Huffman tree, required by `Treeless_Literals_Block` type
|
||||
- Previous FSE decoding tables, required by `Repeat_Mode`
|
||||
for each symbol type (literals lengths, match lengths, offsets)
|
||||
|
||||
Note that decoding tables aren't always from the previous `Compressed_Block`.
|
||||
|
||||
- Every decoding table can come from a dictionary.
|
||||
- The Huffman tree comes from the previous `Compressed_Literals_Block`.
|
||||
|
||||
Literals Section
|
||||
----------------
|
||||
@@ -405,11 +432,11 @@ Literals can be stored uncompressed or compressed using Huffman prefix codes.
|
||||
When compressed, an optional tree description can be present,
|
||||
followed by 1 or 4 streams.
|
||||
|
||||
| `Literals_Section_Header` | [`Huffman_Tree_Description`] | Stream1 | [Stream2] | [Stream3] | [Stream4] |
|
||||
| ------------------------- | ---------------------------- | ------- | --------- | --------- | --------- |
|
||||
| `Literals_Section_Header` | [`Huffman_Tree_Description`] | [jumpTable] | Stream1 | [Stream2] | [Stream3] | [Stream4] |
|
||||
| ------------------------- | ---------------------------- | ----------- | ------- | --------- | --------- | --------- |
|
||||
|
||||
|
||||
#### `Literals_Section_Header`
|
||||
### `Literals_Section_Header`
|
||||
|
||||
Header is in charge of describing how literals are packed.
|
||||
It's a byte-aligned variable-size bitfield, ranging from 1 to 5 bytes,
|
||||
@@ -460,17 +487,20 @@ For values spanning several bytes, convention is __little-endian__.
|
||||
|
||||
__`Size_Format` for `Raw_Literals_Block` and `RLE_Literals_Block`__ :
|
||||
|
||||
- Value ?0 : `Size_Format` uses 1 bit.
|
||||
`Size_Format` uses 1 _or_ 2 bits.
|
||||
Its value is : `Size_Format = (Header[0]>>2) & 3`
|
||||
|
||||
- `Size_Format` == 00 or 10 : `Size_Format` uses 1 bit.
|
||||
`Regenerated_Size` uses 5 bits (0-31).
|
||||
`Literals_Section_Header` has 1 byte.
|
||||
`Literals_Section_Header` uses 1 byte.
|
||||
`Regenerated_Size = Header[0]>>3`
|
||||
- Value 01 : `Size_Format` uses 2 bits.
|
||||
- `Size_Format` == 01 : `Size_Format` uses 2 bits.
|
||||
`Regenerated_Size` uses 12 bits (0-4095).
|
||||
`Literals_Section_Header` has 2 bytes.
|
||||
`Literals_Section_Header` uses 2 bytes.
|
||||
`Regenerated_Size = (Header[0]>>4) + (Header[1]<<4)`
|
||||
- Value 11 : `Size_Format` uses 2 bits.
|
||||
- `Size_Format` == 11 : `Size_Format` uses 2 bits.
|
||||
`Regenerated_Size` uses 20 bits (0-1048575).
|
||||
`Literals_Section_Header` has 3 bytes.
|
||||
`Literals_Section_Header` uses 3 bytes.
|
||||
`Regenerated_Size = (Header[0]>>4) + (Header[1]<<4) + (Header[2]<<12)`
|
||||
|
||||
Only Stream1 is present for these cases.
|
||||
@@ -479,66 +509,74 @@ using a long format, even if it's less efficient.
|
||||
|
||||
__`Size_Format` for `Compressed_Literals_Block` and `Treeless_Literals_Block`__ :
|
||||
|
||||
- Value 00 : _A single stream_.
|
||||
`Size_Format` always uses 2 bits.
|
||||
|
||||
- `Size_Format` == 00 : _A single stream_.
|
||||
Both `Regenerated_Size` and `Compressed_Size` use 10 bits (0-1023).
|
||||
`Literals_Section_Header` has 3 bytes.
|
||||
- Value 01 : 4 streams.
|
||||
`Literals_Section_Header` uses 3 bytes.
|
||||
- `Size_Format` == 01 : 4 streams.
|
||||
Both `Regenerated_Size` and `Compressed_Size` use 10 bits (0-1023).
|
||||
`Literals_Section_Header` has 3 bytes.
|
||||
- Value 10 : 4 streams.
|
||||
`Literals_Section_Header` uses 3 bytes.
|
||||
- `Size_Format` == 10 : 4 streams.
|
||||
Both `Regenerated_Size` and `Compressed_Size` use 14 bits (0-16383).
|
||||
`Literals_Section_Header` has 4 bytes.
|
||||
- Value 11 : 4 streams.
|
||||
`Literals_Section_Header` uses 4 bytes.
|
||||
- `Size_Format` == 11 : 4 streams.
|
||||
Both `Regenerated_Size` and `Compressed_Size` use 18 bits (0-262143).
|
||||
`Literals_Section_Header` has 5 bytes.
|
||||
`Literals_Section_Header` uses 5 bytes.
|
||||
|
||||
Both `Compressed_Size` and `Regenerated_Size` fields follow __little-endian__ convention.
|
||||
Note: `Compressed_Size` __includes__ the size of the Huffman Tree description
|
||||
_when_ it is present.
|
||||
|
||||
### Raw Literals Block
|
||||
#### Raw Literals Block
|
||||
The data in Stream1 is `Regenerated_Size` bytes long,
|
||||
it contains the raw literals data to be used during [Sequence Execution].
|
||||
|
||||
### RLE Literals Block
|
||||
#### RLE Literals Block
|
||||
Stream1 consists of a single byte which should be repeated `Regenerated_Size` times
|
||||
to generate the decoded literals.
|
||||
|
||||
### Compressed Literals Block and Treeless Literals Block
|
||||
#### Compressed Literals Block and Treeless Literals Block
|
||||
Both of these modes contain Huffman encoded data.
|
||||
`Treeless_Literals_Block` does not have a `Huffman_Tree_Description`.
|
||||
|
||||
#### `Huffman_Tree_Description`
|
||||
For `Treeless_Literals_Block`,
|
||||
the Huffman table comes from previously compressed literals block,
|
||||
or from a dictionary.
|
||||
|
||||
|
||||
### `Huffman_Tree_Description`
|
||||
This section is only present when `Literals_Block_Type` type is `Compressed_Literals_Block` (`2`).
|
||||
The format of the Huffman tree description can be found at [Huffman Tree description](#huffman-tree-description).
|
||||
The size of `Huffman_Tree_Description` is determined during decoding process,
|
||||
it must be used to determine where streams begin.
|
||||
`Total_Streams_Size = Compressed_Size - Huffman_Tree_Description_Size`.
|
||||
|
||||
For `Treeless_Literals_Block`,
|
||||
the Huffman table comes from previously compressed literals block.
|
||||
|
||||
Huffman compressed data consists of either 1 or 4 Huffman-coded streams.
|
||||
### Jump Table
|
||||
The Jump Table is only present when there are 4 Huffman-coded streams.
|
||||
|
||||
Reminder : Huffman compressed data consists of either 1 or 4 Huffman-coded streams.
|
||||
|
||||
If only one stream is present, it is a single bitstream occupying the entire
|
||||
remaining portion of the literals block, encoded as described within
|
||||
[Huffman-Coded Streams](#huffman-coded-streams).
|
||||
|
||||
If there are four streams, the literals section header only provides enough
|
||||
information to know the decompressed and compressed sizes of all four streams _combined_.
|
||||
The decompressed size of each stream is equal to `(Regenerated_Size+3)/4`,
|
||||
If there are four streams, `Literals_Section_Header` only provided
|
||||
enough information to know the decompressed and compressed sizes
|
||||
of all four streams _combined_.
|
||||
The decompressed size of _each_ stream is equal to `(Regenerated_Size+3)/4`,
|
||||
except for the last stream which may be up to 3 bytes smaller,
|
||||
to reach a total decompressed size as specified in `Regenerated_Size`.
|
||||
|
||||
The compressed size of each stream is provided explicitly:
|
||||
the first 6 bytes of the compressed data consist of three 2-byte __little-endian__ fields,
|
||||
The compressed size of each stream is provided explicitly in the Jump Table.
|
||||
Jump Table is 6 bytes long, and consist of three 2-byte __little-endian__ fields,
|
||||
describing the compressed sizes of the first three streams.
|
||||
`Stream4_Size` is computed from total `Total_Streams_Size` minus sizes of other streams.
|
||||
|
||||
`Stream4_Size = Total_Streams_Size - 6 - Stream1_Size - Stream2_Size - Stream3_Size`.
|
||||
|
||||
Note: remember that `Total_Streams_Size` can be smaller than `Compressed_Size` in header,
|
||||
because `Compressed_Size` also contains `Huffman_Tree_Description_Size` when it is present.
|
||||
Note: if `Stream1_Size + Stream2_Size + Stream3_Size > Total_Streams_Size`,
|
||||
data is considered corrupted.
|
||||
|
||||
Each of these 4 bitstreams is then decoded independently as a Huffman-Coded stream,
|
||||
as described at [Huffman-Coded Streams](#huffman-coded-streams)
|
||||
@@ -556,7 +594,7 @@ When all _sequences_ are decoded,
|
||||
if there are literals left in the _literal section_,
|
||||
these bytes are added at the end of the block.
|
||||
|
||||
This is described in more detail in [Sequence Execution](#sequence-execution)
|
||||
This is described in more detail in [Sequence Execution](#sequence-execution).
|
||||
|
||||
The `Sequences_Section` regroup all symbols required to decode commands.
|
||||
There are 3 symbol types : literals lengths, offsets and match lengths.
|
||||
@@ -570,7 +608,8 @@ followed by the bitstream.
|
||||
| -------------------------- | ------------------------- | ---------------- | ---------------------- | --------- |
|
||||
|
||||
To decode the `Sequences_Section`, it's required to know its size.
|
||||
This size is deduced from `Block_Size - Literals_Section_Size`.
|
||||
This size is deduced from the literals section size:
|
||||
`Sequences_Section_Size = Block_Size - Literals_Section_Size`.
|
||||
|
||||
|
||||
#### `Sequences_Section_Header`
|
||||
@@ -586,6 +625,7 @@ Let's call its first byte `byte0`.
|
||||
- `if (byte0 == 0)` : there are no sequences.
|
||||
The sequence section stops there.
|
||||
Decompressed content is defined entirely as Literals Section content.
|
||||
The FSE tables used in `Repeat_Mode` aren't updated.
|
||||
- `if (byte0 < 128)` : `Number_of_Sequences = byte0` . Uses 1 byte.
|
||||
- `if (byte0 < 255)` : `Number_of_Sequences = ((byte0-128) << 8) + byte1` . Uses 2 bytes.
|
||||
- `if (byte0 == 255)`: `Number_of_Sequences = byte1 + (byte2<<8) + 0x7F00` . Uses 3 bytes.
|
||||
@@ -612,18 +652,22 @@ They follow the same enumeration :
|
||||
- `Predefined_Mode` : A predefined FSE distribution table is used, defined in
|
||||
[default distributions](#default-distributions).
|
||||
No distribution table will be present.
|
||||
- `RLE_Mode` : The table description consists of a single byte.
|
||||
This code will be repeated for all sequences.
|
||||
- `Repeat_Mode` : The table used in the previous compressed block will be used again.
|
||||
No distribution table will be present.
|
||||
Note: this includes RLE mode, so if `Repeat_Mode` follows `RLE_Mode`, the same symbol will be repeated.
|
||||
If this mode is used without any previous sequence table in the frame
|
||||
(or [dictionary](#dictionary-format)) to repeat, this should be treated as corruption.
|
||||
- `RLE_Mode` : The table description consists of a single byte, which contains the symbol's value.
|
||||
This symbol will be used for all sequences.
|
||||
- `FSE_Compressed_Mode` : standard FSE compression.
|
||||
A distribution table will be present.
|
||||
The format of this distribution table is described in [FSE Table Description](#fse-table-description).
|
||||
Note that the maximum allowed accuracy log for literals length and match length tables is 9,
|
||||
and the maximum accuracy log for the offsets table is 8.
|
||||
`FSE_Compressed_Mode` must not be used when only one symbol is present,
|
||||
`RLE_Mode` should be used instead (although any other mode will work).
|
||||
- `Repeat_Mode` : The table used in the previous `Compressed_Block` with `Number_of_Sequences > 0` will be used again,
|
||||
or if this is the first block, table in the dictionary will be used.
|
||||
Note that this includes `RLE_mode`, so if `Repeat_Mode` follows `RLE_Mode`, the same symbol will be repeated.
|
||||
It also includes `Predefined_Mode`, in which case `Repeat_Mode` will have same outcome as `Predefined_Mode`.
|
||||
No distribution table will be present.
|
||||
If this mode is used without any previous sequence table in the frame
|
||||
(nor [dictionary](#dictionary-format)) to repeat, this should be treated as corruption.
|
||||
|
||||
#### The codes for literals lengths, match lengths, and offsets.
|
||||
|
||||
@@ -696,7 +740,7 @@ Offset codes are values ranging from `0` to `N`.
|
||||
A decoder is free to limit its maximum `N` supported.
|
||||
Recommendation is to support at least up to `22`.
|
||||
For information, at the time of this writing.
|
||||
the reference decoder supports a maximum `N` value of `28` in 64-bits mode.
|
||||
the reference decoder supports a maximum `N` value of `31`.
|
||||
|
||||
An offset code is also the number of additional bits to read in __little-endian__ fashion,
|
||||
and can be translated into an `Offset_Value` using the following formulas :
|
||||
@@ -705,7 +749,8 @@ and can be translated into an `Offset_Value` using the following formulas :
|
||||
Offset_Value = (1 << offsetCode) + readNBits(offsetCode);
|
||||
if (Offset_Value > 3) offset = Offset_Value - 3;
|
||||
```
|
||||
It means that maximum `Offset_Value` is `(2^(N+1))-1` and it supports back-reference distance up to `(2^(N+1))-4`
|
||||
It means that maximum `Offset_Value` is `(2^(N+1))-1`
|
||||
supporting back-reference distances up to `(2^(N+1))-4`,
|
||||
but is limited by [maximum back-reference distance](#window_descriptor).
|
||||
|
||||
`Offset_Value` from 1 to 3 are special : they define "repeat codes".
|
||||
@@ -856,7 +901,9 @@ so an `offset_value` of 1 means `Repeated_Offset2`,
|
||||
an `offset_value` of 2 means `Repeated_Offset3`,
|
||||
and an `offset_value` of 3 means `Repeated_Offset1 - 1_byte`.
|
||||
|
||||
For the first block, the starting offset history is populated with the following values : 1, 4 and 8 (in order).
|
||||
For the first block, the starting offset history is populated with following values :
|
||||
`Repeated_Offset1`=1, `Repeated_Offset2`=4, `Repeated_Offset3`=8,
|
||||
unless a dictionary is used, in which case they come from the dictionary.
|
||||
|
||||
Then each block gets its starting offset history from the ending values of the most recent `Compressed_Block`.
|
||||
Note that blocks which are not `Compressed_Block` are skipped, they do not contribute to offset history.
|
||||
@@ -880,21 +927,28 @@ Skippable Frames
|
||||
|:--------------:|:------------:|:-----------:|
|
||||
| 4 bytes | 4 bytes | n bytes |
|
||||
|
||||
Skippable frames allow the insertion of user-defined data
|
||||
Skippable frames allow the insertion of user-defined metadata
|
||||
into a flow of concatenated frames.
|
||||
Its design is pretty straightforward,
|
||||
with the sole objective to allow the decoder to quickly skip
|
||||
over user-defined data and continue decoding.
|
||||
|
||||
Skippable frames defined in this specification are compatible with [LZ4] ones.
|
||||
|
||||
[LZ4]:http://www.lz4.org
|
||||
|
||||
From a compliant decoder perspective, skippable frames need just be skipped,
|
||||
and their content ignored, resuming decoding after the skippable frame.
|
||||
|
||||
It can be noted that a skippable frame
|
||||
can be used to watermark a stream of concatenated frames
|
||||
embedding any kind of tracking information (even just an UUID).
|
||||
Users wary of such possibility should scan the stream of concatenated frames
|
||||
in an attempt to detect such frame for analysis or removal.
|
||||
|
||||
__`Magic_Number`__
|
||||
|
||||
4 Bytes, __little-endian__ format.
|
||||
Value : 0x184D2A5?, which means any value from 0x184D2A50 to 0x184D2A5F.
|
||||
All 16 values are valid to identify a skippable frame.
|
||||
This specification doesn't detail any specific tagging for skippable frames.
|
||||
|
||||
__`Frame_Size`__
|
||||
|
||||
@@ -908,10 +962,16 @@ __`User_Data`__
|
||||
The `User_Data` can be anything. Data will just be skipped by the decoder.
|
||||
|
||||
|
||||
|
||||
Entropy Encoding
|
||||
----------------
|
||||
Two types of entropy encoding are used by the Zstandard format:
|
||||
FSE, and Huffman coding.
|
||||
Huffman is used to compress literals,
|
||||
while FSE is used for all other symbols
|
||||
(`Literals_Length_Code`, `Match_Length_Code`, offset codes)
|
||||
and to compress Huffman headers.
|
||||
|
||||
|
||||
FSE
|
||||
---
|
||||
@@ -919,6 +979,8 @@ FSE, short for Finite State Entropy, is an entropy codec based on [ANS].
|
||||
FSE encoding/decoding involves a state that is carried over between symbols,
|
||||
so decoding must be done in the opposite direction as encoding.
|
||||
Therefore, all FSE bitstreams are read from end to beginning.
|
||||
Note that the order of the bits in the stream is not reversed,
|
||||
we just read the elements in the reverse order they are written.
|
||||
|
||||
For additional details on FSE, see [Finite State Entropy].
|
||||
|
||||
@@ -927,7 +989,7 @@ For additional details on FSE, see [Finite State Entropy].
|
||||
FSE decoding involves a decoding table which has a power of 2 size, and contain three elements:
|
||||
`Symbol`, `Num_Bits`, and `Baseline`.
|
||||
The `log2` of the table size is its `Accuracy_Log`.
|
||||
The FSE state represents an index in this table.
|
||||
An FSE state value represents an index in this table.
|
||||
|
||||
To obtain the initial state value, consume `Accuracy_Log` bits from the stream as a __little-endian__ value.
|
||||
The next symbol in the stream is the `Symbol` indicated in the table for that state.
|
||||
@@ -943,12 +1005,14 @@ The Zstandard format encodes FSE table descriptions as follows:
|
||||
An FSE distribution table describes the probabilities of all symbols
|
||||
from `0` to the last present one (included)
|
||||
on a normalized scale of `1 << Accuracy_Log` .
|
||||
Note that there must be two or more symbols with nonzero probability.
|
||||
|
||||
It's a bitstream which is read forward, in __little-endian__ fashion.
|
||||
It's not necessary to know its exact size,
|
||||
since it will be discovered and reported by the decoding process.
|
||||
It's not necessary to know bitstream exact size,
|
||||
it will be discovered and reported by the decoding process.
|
||||
|
||||
The bitstream starts by reporting on which scale it operates.
|
||||
Let's `low4Bits` designate the lowest 4 bits of the first byte :
|
||||
`Accuracy_Log = low4bits + 5`.
|
||||
|
||||
Then follows each symbol value, from `0` to last present one.
|
||||
@@ -959,24 +1023,24 @@ It depends on :
|
||||
__example__ :
|
||||
Presuming an `Accuracy_Log` of 8,
|
||||
and presuming 100 probabilities points have already been distributed,
|
||||
the decoder may read any value from `0` to `255 - 100 + 1 == 156` (inclusive).
|
||||
Therefore, it must read `log2sup(156) == 8` bits.
|
||||
the decoder may read any value from `0` to `256 - 100 + 1 == 157` (inclusive).
|
||||
Therefore, it must read `log2sup(157) == 8` bits.
|
||||
|
||||
- Value decoded : small values use 1 less bit :
|
||||
__example__ :
|
||||
Presuming values from 0 to 156 (inclusive) are possible,
|
||||
255-156 = 99 values are remaining in an 8-bits field.
|
||||
Presuming values from 0 to 157 (inclusive) are possible,
|
||||
255-157 = 98 values are remaining in an 8-bits field.
|
||||
They are used this way :
|
||||
first 99 values (hence from 0 to 98) use only 7 bits,
|
||||
values from 99 to 156 use 8 bits.
|
||||
first 98 values (hence from 0 to 97) use only 7 bits,
|
||||
values from 98 to 157 use 8 bits.
|
||||
This is achieved through this scheme :
|
||||
|
||||
| Value read | Value decoded | Number of bits used |
|
||||
| ---------- | ------------- | ------------------- |
|
||||
| 0 - 98 | 0 - 98 | 7 |
|
||||
| 99 - 127 | 99 - 127 | 8 |
|
||||
| 128 - 226 | 0 - 98 | 7 |
|
||||
| 227 - 255 | 128 - 156 | 8 |
|
||||
| 0 - 97 | 0 - 97 | 7 |
|
||||
| 98 - 127 | 98 - 127 | 8 |
|
||||
| 128 - 225 | 0 - 97 | 7 |
|
||||
| 226 - 255 | 128 - 157 | 8 |
|
||||
|
||||
Symbols probabilities are read one by one, in order.
|
||||
|
||||
@@ -1006,7 +1070,7 @@ and how many symbols are present.
|
||||
The bitstream consumes a round number of bytes.
|
||||
Any remaining bit within the last byte is just unused.
|
||||
|
||||
##### From normalized distribution to decoding tables
|
||||
#### From normalized distribution to decoding tables
|
||||
|
||||
The distribution of normalized probabilities is enough
|
||||
to create a unique decoding table.
|
||||
@@ -1019,12 +1083,12 @@ and instructions to get the next state.
|
||||
|
||||
Symbols are scanned in their natural order for "less than 1" probabilities.
|
||||
Symbols with this probability are being attributed a single cell,
|
||||
starting from the end of the table.
|
||||
starting from the end of the table and retreating.
|
||||
These symbols define a full state reset, reading `Accuracy_Log` bits.
|
||||
|
||||
All remaining symbols are sorted in their natural order.
|
||||
All remaining symbols are allocated in their natural order.
|
||||
Starting from symbol `0` and table position `0`,
|
||||
each symbol gets attributed as many cells as its probability.
|
||||
each symbol gets allocated as many cells as its probability.
|
||||
Cell allocation is spreaded, not linear :
|
||||
each successor position follow this rule :
|
||||
|
||||
@@ -1044,6 +1108,7 @@ Each state will decode the current symbol.
|
||||
To get the `Number_of_Bits` and `Baseline` required for next state,
|
||||
it's first necessary to sort all states in their natural order.
|
||||
The lower states will need 1 more bit than higher ones.
|
||||
The process is repeated for each symbol.
|
||||
|
||||
__Example__ :
|
||||
Presuming a symbol has a probability of 5.
|
||||
@@ -1055,10 +1120,12 @@ Presuming the `Accuracy_Log` is 7, it defines 128 states.
|
||||
Divided by 8, each share is 16 large.
|
||||
|
||||
In order to reach 8, 8-5=3 lowest states will count "double",
|
||||
taking shares twice larger,
|
||||
doubling the number of shares (32 in width),
|
||||
requiring one more bit in the process.
|
||||
|
||||
Numbering starts from higher states using less bits.
|
||||
Baseline is assigned starting from the higher states using fewer bits,
|
||||
and proceeding naturally, then resuming at the first state,
|
||||
each takes its allocated width from Baseline.
|
||||
|
||||
| state order | 0 | 1 | 2 | 3 | 4 |
|
||||
| ---------------- | ----- | ----- | ------ | ---- | ----- |
|
||||
@@ -1075,6 +1142,7 @@ See [Appendix A] for the results of this process applied to the default distribu
|
||||
|
||||
[Appendix A]: #appendix-a---decoding-tables-for-predefined-codes
|
||||
|
||||
|
||||
Huffman Coding
|
||||
--------------
|
||||
Zstandard Huffman-coded streams are read backwards,
|
||||
@@ -1096,6 +1164,7 @@ The bitstream contains Huffman-coded symbols in __little-endian__ order,
|
||||
with the codes defined by the method below.
|
||||
|
||||
### Huffman Tree Description
|
||||
|
||||
Prefix coding represents symbols from an a priori known alphabet
|
||||
by bit sequences (codewords), one codeword for each symbol,
|
||||
in a manner such that different symbols may be represented
|
||||
@@ -1112,8 +1181,7 @@ More bits improve accuracy but cost more header size,
|
||||
and require more memory or more complex decoding operations.
|
||||
This specification limits maximum code length to 11 bits.
|
||||
|
||||
|
||||
##### Representation
|
||||
#### Representation
|
||||
|
||||
All literal values from zero (included) to last present one (excluded)
|
||||
are represented by `Weight` with values from `0` to `Max_Number_of_Bits`.
|
||||
@@ -1128,12 +1196,13 @@ This power of 2 gives `Max_Number_of_Bits`, the depth of the current tree.
|
||||
__Example__ :
|
||||
Let's presume the following Huffman tree must be described :
|
||||
|
||||
| literal | 0 | 1 | 2 | 3 | 4 | 5 |
|
||||
| literal value | 0 | 1 | 2 | 3 | 4 | 5 |
|
||||
| ---------------- | --- | --- | --- | --- | --- | --- |
|
||||
| `Number_of_Bits` | 1 | 2 | 3 | 0 | 4 | 4 |
|
||||
|
||||
The tree depth is 4, since its smallest element uses 4 bits.
|
||||
Value `5` will not be listed as it can be determined from the values for 0-4,
|
||||
The tree depth is 4, since its longest elements uses 4 bits
|
||||
(longest elements are the one with smallest frequency).
|
||||
Value `5` will not be listed, as it can be determined from values for 0-4,
|
||||
nor will values above `5` as they are all 0.
|
||||
Values from `0` to `4` will be listed using `Weight` instead of `Number_of_Bits`.
|
||||
Weight formula is :
|
||||
@@ -1142,9 +1211,9 @@ Weight = Number_of_Bits ? (Max_Number_of_Bits + 1 - Number_of_Bits) : 0
|
||||
```
|
||||
It gives the following series of weights :
|
||||
|
||||
| literal | 0 | 1 | 2 | 3 | 4 |
|
||||
| -------- | --- | --- | --- | --- | --- |
|
||||
| `Weight` | 4 | 3 | 2 | 0 | 1 |
|
||||
| literal value | 0 | 1 | 2 | 3 | 4 |
|
||||
| ------------- | --- | --- | --- | --- | --- |
|
||||
| `Weight` | 4 | 3 | 2 | 0 | 1 |
|
||||
|
||||
The decoder will do the inverse operation :
|
||||
having collected weights of literals from `0` to `4`,
|
||||
@@ -1153,12 +1222,16 @@ The weight of `5` can be determined by advancing to the next power of 2.
|
||||
The sum of `2^(Weight-1)` (excluding 0's) is :
|
||||
`8 + 4 + 2 + 0 + 1 = 15`.
|
||||
Nearest power of 2 is 16.
|
||||
Therefore, `Max_Number_of_Bits = 4` and `Weight[5] = 1`.
|
||||
Therefore, `Max_Number_of_Bits = 4` and `Weight[5] = 16-15 = 1`.
|
||||
|
||||
##### Huffman Tree header
|
||||
#### Huffman Tree header
|
||||
|
||||
This is a single byte value (0-255),
|
||||
which describes how to decode the list of weights.
|
||||
which describes how the series of weights is encoded.
|
||||
|
||||
- if `headerByte` < 128 :
|
||||
the series of weights is compressed using FSE (see below).
|
||||
The length of the FSE-compressed series is equal to `headerByte` (0-127).
|
||||
|
||||
- if `headerByte` >= 128 : this is a direct representation,
|
||||
where each `Weight` is written directly as a 4 bits field (0-15).
|
||||
@@ -1166,17 +1239,15 @@ which describes how to decode the list of weights.
|
||||
the top four bits and the second taking the bottom four (e.g. the following
|
||||
operations could be used to read the weights:
|
||||
`Weight[0] = (Byte[0] >> 4), Weight[1] = (Byte[0] & 0xf)`, etc.).
|
||||
The full representation occupies `((Number_of_Symbols+1)/2)` bytes,
|
||||
meaning it uses a last full byte even if `Number_of_Symbols` is odd.
|
||||
The full representation occupies `Ceiling(Number_of_Symbols/2)` bytes,
|
||||
meaning it uses only full bytes even if `Number_of_Symbols` is odd.
|
||||
`Number_of_Symbols = headerByte - 127`.
|
||||
Note that maximum `Number_of_Symbols` is 255-127 = 128.
|
||||
A larger series must necessarily use FSE compression.
|
||||
If any literal has a value > 128, raw header mode is not possible.
|
||||
In such case, it's necessary to use FSE compression.
|
||||
|
||||
- if `headerByte` < 128 :
|
||||
the series of weights is compressed by FSE.
|
||||
The length of the FSE-compressed series is equal to `headerByte` (0-127).
|
||||
|
||||
##### Finite State Entropy (FSE) compression of Huffman weights
|
||||
#### Finite State Entropy (FSE) compression of Huffman weights
|
||||
|
||||
In this case, the series of Huffman weights is compressed using FSE compression.
|
||||
It's a single bitstream with 2 interleaved states,
|
||||
@@ -1190,7 +1261,7 @@ and last symbol's weight is not represented.
|
||||
|
||||
An FSE bitstream starts by a header, describing probabilities distribution.
|
||||
It will create a Decoding Table.
|
||||
For a list of Huffman weights, the maximum accuracy log is 7 bits.
|
||||
For a list of Huffman weights, the maximum accuracy log is 6 bits.
|
||||
For more description see the [FSE header description](#fse-table-description)
|
||||
|
||||
The Huffman header compression uses 2 states,
|
||||
@@ -1205,18 +1276,19 @@ The number of symbols to decode is determined
|
||||
by tracking bitStream overflow condition:
|
||||
If updating state after decoding a symbol would require more bits than
|
||||
remain in the stream, it is assumed that extra bits are 0. Then,
|
||||
the symbols for each of the final states are decoded and the process is complete.
|
||||
symbols for each of the final states are decoded and the process is complete.
|
||||
|
||||
##### Conversion from weights to Huffman prefix codes
|
||||
#### Conversion from weights to Huffman prefix codes
|
||||
|
||||
All present symbols shall now have a `Weight` value.
|
||||
It is possible to transform weights into Number_of_Bits, using this formula:
|
||||
It is possible to transform weights into `Number_of_Bits`, using this formula:
|
||||
```
|
||||
Number_of_Bits = Number_of_Bits ? Max_Number_of_Bits + 1 - Weight : 0
|
||||
Number_of_Bits = (Weight>0) ? Max_Number_of_Bits + 1 - Weight : 0
|
||||
```
|
||||
Symbols are sorted by `Weight`. Within same `Weight`, symbols keep natural order.
|
||||
Symbols are sorted by `Weight`.
|
||||
Within same `Weight`, symbols keep natural sequential order.
|
||||
Symbols with a `Weight` of zero are removed.
|
||||
Then, starting from lowest weight, prefix codes are distributed in order.
|
||||
Then, starting from lowest weight, prefix codes are distributed in sequential order.
|
||||
|
||||
__Example__ :
|
||||
Let's presume the following list of weights has been decoded :
|
||||
@@ -1225,7 +1297,7 @@ Let's presume the following list of weights has been decoded :
|
||||
| -------- | --- | --- | --- | --- | --- | --- |
|
||||
| `Weight` | 4 | 3 | 2 | 0 | 1 | 1 |
|
||||
|
||||
Sorted by weight and then natural order,
|
||||
Sorted by weight and then natural sequential order,
|
||||
it gives the following distribution :
|
||||
|
||||
| Literal | 3 | 4 | 5 | 2 | 1 | 0 |
|
||||
@@ -1235,6 +1307,7 @@ it gives the following distribution :
|
||||
| prefix codes | N/A | 0000| 0001| 001 | 01 | 1 |
|
||||
|
||||
### Huffman-coded Streams
|
||||
|
||||
Given a Huffman decoding table,
|
||||
it's possible to decode a Huffman-coded stream.
|
||||
|
||||
@@ -1312,7 +1385,7 @@ _Reserved ranges :_
|
||||
- low range : <= 32767
|
||||
- high range : >= (2^31)
|
||||
|
||||
__`Entropy_Tables`__ : following the same format as the tables in compressed blocks.
|
||||
__`Entropy_Tables`__ : follow the same format as tables in [compressed blocks].
|
||||
See the relevant [FSE](#fse-table-description)
|
||||
and [Huffman](#huffman-tree-description) sections for how to decode these tables.
|
||||
They are stored in following order :
|
||||
@@ -1330,11 +1403,16 @@ __`Content`__ : The rest of the dictionary is its content.
|
||||
As long as the amount of data decoded from this frame is less than or
|
||||
equal to `Window_Size`, sequence commands may specify offsets longer
|
||||
than the total length of decoded output so far to reference back to the
|
||||
dictionary. After the total output has surpassed `Window_Size` however,
|
||||
dictionary, even parts of the dictionary with offsets larger than `Window_Size`.
|
||||
After the total output has surpassed `Window_Size` however,
|
||||
this is no longer allowed and the dictionary is no longer accessible.
|
||||
|
||||
[compressed blocks]: #the-format-of-compressed_block
|
||||
|
||||
If a dictionary is provided by an external source,
|
||||
it should be loaded with great care, its content considered untrusted.
|
||||
|
||||
|
||||
|
||||
Appendix A - Decoding tables for predefined codes
|
||||
-------------------------------------------------
|
||||
@@ -1521,8 +1599,30 @@ to crosscheck that an implementation build its decoding tables correctly.
|
||||
| 30 | 25 | 5 | 0 |
|
||||
| 31 | 24 | 5 | 0 |
|
||||
|
||||
|
||||
|
||||
Appendix B - Resources for implementers
|
||||
-------------------------------------------------
|
||||
|
||||
An open source reference implementation is available on :
|
||||
https://github.com/facebook/zstd
|
||||
|
||||
The project contains a frame generator, called [decodeCorpus],
|
||||
which can be used by any 3rd-party implementation
|
||||
to verify that a tested decoder is compliant with the specification.
|
||||
|
||||
[decodeCorpus]: https://github.com/facebook/zstd/tree/v1.3.4/tests#decodecorpus---tool-to-generate-zstandard-frames-for-decoder-testing
|
||||
|
||||
`decodeCorpus` generates random valid frames.
|
||||
A compliant decoder should be able to decode them all,
|
||||
or at least provide a meaningful error code explaining for which reason it cannot
|
||||
(memory limit restrictions for example).
|
||||
|
||||
|
||||
Version changes
|
||||
---------------
|
||||
- 0.2.8 : clarifications for IETF RFC discuss
|
||||
- 0.2.7 : clarifications from IETF RFC review, by Vijay Gurbani and Nick Terrell
|
||||
- 0.2.6 : fixed an error in huffman example, by Ulrich Kunitz
|
||||
- 0.2.5 : minor typos and clarifications
|
||||
- 0.2.4 : section restructuring, by Sean Purcell
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>zstd 1.3.4 Manual</title>
|
||||
<title>zstd 1.3.5 Manual</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>zstd 1.3.4 Manual</h1>
|
||||
<h1>zstd 1.3.5 Manual</h1>
|
||||
<hr>
|
||||
<a name="Contents"></a><h2>Contents</h2>
|
||||
<ol>
|
||||
<li><a href="#Chapter1">Introduction</a></li>
|
||||
<li><a href="#Chapter2">Version</a></li>
|
||||
<li><a href="#Chapter3">Simple API</a></li>
|
||||
<li><a href="#Chapter4">Explicit context</a></li>
|
||||
<li><a href="#Chapter5">Simple dictionary API</a></li>
|
||||
<li><a href="#Chapter6">Bulk processing dictionary API</a></li>
|
||||
<li><a href="#Chapter7">Streaming</a></li>
|
||||
<li><a href="#Chapter8">Streaming compression - 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="#Chapter11">Advanced types</a></li>
|
||||
<li><a href="#Chapter12">Frame size functions</a></li>
|
||||
<li><a href="#Chapter13">Memory management</a></li>
|
||||
<li><a href="#Chapter14">Advanced compression functions</a></li>
|
||||
<li><a href="#Chapter15">Advanced decompression functions</a></li>
|
||||
<li><a href="#Chapter16">Advanced streaming functions</a></li>
|
||||
<li><a href="#Chapter17">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 decompression (synchronous mode)</a></li>
|
||||
<li><a href="#Chapter20">New advanced API (experimental)</a></li>
|
||||
<li><a href="#Chapter21">Block level API</a></li>
|
||||
<li><a href="#Chapter3">Default constant</a></li>
|
||||
<li><a href="#Chapter4">Simple API</a></li>
|
||||
<li><a href="#Chapter5">Explicit context</a></li>
|
||||
<li><a href="#Chapter6">Simple dictionary API</a></li>
|
||||
<li><a href="#Chapter7">Bulk processing dictionary API</a></li>
|
||||
<li><a href="#Chapter8">Streaming</a></li>
|
||||
<li><a href="#Chapter9">Streaming compression - HowTo</a></li>
|
||||
<li><a href="#Chapter10">Streaming decompression - HowTo</a></li>
|
||||
<li><a href="#Chapter11">START OF ADVANCED AND EXPERIMENTAL FUNCTIONS</a></li>
|
||||
<li><a href="#Chapter12">Advanced types</a></li>
|
||||
<li><a href="#Chapter13">Frame size functions</a></li>
|
||||
<li><a href="#Chapter14">ZSTD_frameHeaderSize() :</a></li>
|
||||
<li><a href="#Chapter15">Memory management</a></li>
|
||||
<li><a href="#Chapter16">Advanced compression functions</a></li>
|
||||
<li><a href="#Chapter17">Advanced decompression functions</a></li>
|
||||
<li><a href="#Chapter18">Advanced streaming functions</a></li>
|
||||
<li><a href="#Chapter19">Buffer-less and synchronous inner streaming functions</a></li>
|
||||
<li><a href="#Chapter20">Buffer-less streaming compression (synchronous mode)</a></li>
|
||||
<li><a href="#Chapter21">Buffer-less streaming decompression (synchronous mode)</a></li>
|
||||
<li><a href="#Chapter22">New advanced API (experimental)</a></li>
|
||||
<li><a href="#Chapter23">ZSTD_getFrameHeader_advanced() :</a></li>
|
||||
<li><a href="#Chapter24">Block level API</a></li>
|
||||
</ol>
|
||||
<hr>
|
||||
<a name="Chapter1"></a><h2>Introduction</h2><pre>
|
||||
@@ -54,7 +57,9 @@
|
||||
|
||||
<pre><b>unsigned ZSTD_versionNumber(void); </b>/**< useful to check dll version */<b>
|
||||
</b></pre><BR>
|
||||
<a name="Chapter3"></a><h2>Simple API</h2><pre></pre>
|
||||
<a name="Chapter3"></a><h2>Default constant</h2><pre></pre>
|
||||
|
||||
<a name="Chapter4"></a><h2>Simple API</h2><pre></pre>
|
||||
|
||||
<pre><b>size_t ZSTD_compress( void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
@@ -80,7 +85,7 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
|
||||
</b><p> `src` should point to the start of a ZSTD encoded frame.
|
||||
`srcSize` must be at least as large as the frame header.
|
||||
hint : any size >= `ZSTD_frameHeaderSize_max` is large enough.
|
||||
@return : - decompressed size of the frame in `src`, if known
|
||||
@return : - decompressed size of `src` frame content, if known
|
||||
- ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
|
||||
- ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small)
|
||||
note 1 : a 0 return value means the frame is valid but "empty".
|
||||
@@ -90,7 +95,8 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
|
||||
Optionally, application can rely on some implicit limit,
|
||||
as ZSTD_decompress() only needs an upper bound of decompressed size.
|
||||
(For example, data could be necessarily cut into blocks <= 16 KB).
|
||||
note 3 : decompressed size is always present when compression is done with ZSTD_compress()
|
||||
note 3 : decompressed size is always present when compression is completed using single-pass functions,
|
||||
such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict().
|
||||
note 4 : decompressed size can be very large (64-bits value),
|
||||
potentially larger than what local system can handle as a single memory segment.
|
||||
In which case, it's necessary to use streaming mode to decompress data.
|
||||
@@ -105,8 +111,7 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
|
||||
Both functions work the same way, but ZSTD_getDecompressedSize() blends
|
||||
"empty", "unknown" and "error" results to the same return value (0),
|
||||
while ZSTD_getFrameContentSize() gives them separate return values.
|
||||
`src` is the start of a zstd compressed frame.
|
||||
@return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise.
|
||||
@return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise.
|
||||
</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>
|
||||
@@ -115,7 +120,7 @@ unsigned ZSTD_isError(size_t code); </b>/*!< tells if a `size_t` fun
|
||||
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>
|
||||
</pre></b><BR>
|
||||
<a name="Chapter4"></a><h2>Explicit context</h2><pre></pre>
|
||||
<a name="Chapter5"></a><h2>Explicit context</h2><pre></pre>
|
||||
|
||||
<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.
|
||||
@@ -147,7 +152,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
|
||||
</b><p> Same as ZSTD_decompress(), requires an allocated ZSTD_DCtx (see ZSTD_createDCtx())
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter5"></a><h2>Simple dictionary API</h2><pre></pre>
|
||||
<a name="Chapter6"></a><h2>Simple dictionary API</h2><pre></pre>
|
||||
|
||||
<pre><b>size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
@@ -169,7 +174,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
|
||||
Note : When `dict == NULL || dictSize < 8` no dictionary is used.
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter6"></a><h2>Bulk processing dictionary API</h2><pre></pre>
|
||||
<a name="Chapter7"></a><h2>Bulk processing dictionary API</h2><pre></pre>
|
||||
|
||||
<pre><b>ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize,
|
||||
int compressionLevel);
|
||||
@@ -210,7 +215,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
|
||||
Faster startup than ZSTD_decompress_usingDict(), recommended when same dictionary is used multiple times.
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter7"></a><h2>Streaming</h2><pre></pre>
|
||||
<a name="Chapter8"></a><h2>Streaming</h2><pre></pre>
|
||||
|
||||
<pre><b>typedef struct ZSTD_inBuffer_s {
|
||||
const void* src; </b>/**< start of input buffer */<b>
|
||||
@@ -224,7 +229,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
|
||||
size_t pos; </b>/**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */<b>
|
||||
} ZSTD_outBuffer;
|
||||
</b></pre><BR>
|
||||
<a name="Chapter8"></a><h2>Streaming compression - HowTo</h2><pre>
|
||||
<a name="Chapter9"></a><h2>Streaming compression - HowTo</h2><pre>
|
||||
A ZSTD_CStream object is required to track streaming operation.
|
||||
Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources.
|
||||
ZSTD_CStream objects can be reused multiple times on consecutive compression operations.
|
||||
@@ -232,33 +237,38 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
|
||||
since it will play nicer with system's memory, by re-using already allocated memory.
|
||||
Use one separate ZSTD_CStream per thread for parallel execution.
|
||||
|
||||
Start a new compression by initializing ZSTD_CStream.
|
||||
Start a new compression by initializing ZSTD_CStream context.
|
||||
Use ZSTD_initCStream() to start a new compression operation.
|
||||
Use ZSTD_initCStream_usingDict() or ZSTD_initCStream_usingCDict() for a compression which requires a dictionary (experimental section)
|
||||
Use variants ZSTD_initCStream_usingDict() or ZSTD_initCStream_usingCDict() for streaming with dictionary (experimental section)
|
||||
|
||||
Use ZSTD_compressStream() repetitively to consume input stream.
|
||||
The function will automatically update both `pos` fields.
|
||||
Note that it may not consume the entire input, in which case `pos < size`,
|
||||
and it's up to the caller to present again remaining data.
|
||||
Use ZSTD_compressStream() as many times as necessary to consume input stream.
|
||||
The function will automatically update both `pos` fields within `input` and `output`.
|
||||
Note that the function may not consume the entire input,
|
||||
for example, because the output buffer is already full,
|
||||
in which case `input.pos < input.size`.
|
||||
The caller must check if input has been entirely consumed.
|
||||
If not, the caller must make some room to receive more compressed data,
|
||||
typically by emptying output buffer, or allocating a new output buffer,
|
||||
and then present again remaining input data.
|
||||
@return : a size hint, preferred nb of bytes to use as input for next function call
|
||||
or an error code, which can be tested using ZSTD_isError().
|
||||
Note 1 : it's just a hint, to help latency a little, any other value will work fine.
|
||||
Note 2 : size hint is guaranteed to be <= ZSTD_CStreamInSize()
|
||||
|
||||
At any moment, it's possible to flush whatever data remains within internal buffer, using ZSTD_flushStream().
|
||||
`output->pos` will be updated.
|
||||
Note that some content might still be left within internal buffer if `output->size` is too small.
|
||||
@return : nb of bytes still present within internal buffer (0 if it's empty)
|
||||
At any moment, it's possible to flush whatever data might remain stuck within internal buffer,
|
||||
using ZSTD_flushStream(). `output->pos` will be updated.
|
||||
Note that, if `output->size` is too small, a single invocation of ZSTD_flushStream() might not be enough (return code > 0).
|
||||
In which case, make some room to receive more compressed data, and call again ZSTD_flushStream().
|
||||
@return : 0 if internal buffers are entirely flushed,
|
||||
>0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
|
||||
or an error code, which can be tested using ZSTD_isError().
|
||||
|
||||
ZSTD_endStream() instructs to finish a frame.
|
||||
It will perform a flush and write frame epilogue.
|
||||
The epilogue is required for decoders to consider a frame completed.
|
||||
ZSTD_endStream() may not be able to flush full data if `output->size` is too small.
|
||||
In which case, call again ZSTD_endStream() to complete the flush.
|
||||
flush() operation is the same, and follows same rules as ZSTD_flushStream().
|
||||
@return : 0 if frame fully completed and fully flushed,
|
||||
or >0 if some data is still present within internal buffer
|
||||
(value is minimum size estimation for remaining data to flush, but it could be more)
|
||||
>0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
|
||||
or an error code, which can be tested using ZSTD_isError().
|
||||
|
||||
|
||||
@@ -278,7 +288,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
|
||||
</b></pre><BR>
|
||||
<pre><b>size_t ZSTD_CStreamOutSize(void); </b>/**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block in all circumstances. */<b>
|
||||
</b></pre><BR>
|
||||
<a name="Chapter9"></a><h2>Streaming decompression - HowTo</h2><pre>
|
||||
<a name="Chapter10"></a><h2>Streaming decompression - HowTo</h2><pre>
|
||||
A ZSTD_DStream object is required to track streaming operations.
|
||||
Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources.
|
||||
ZSTD_DStream objects can be re-used multiple times.
|
||||
@@ -311,14 +321,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
</b></pre><BR>
|
||||
<pre><b>size_t ZSTD_DStreamOutSize(void); </b>/*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */<b>
|
||||
</b></pre><BR>
|
||||
<a name="Chapter10"></a><h2>START OF ADVANCED AND EXPERIMENTAL FUNCTIONS</h2><pre> The definitions in this section are considered experimental.
|
||||
<a name="Chapter11"></a><h2>START OF ADVANCED AND EXPERIMENTAL FUNCTIONS</h2><pre> The definitions in this section are considered experimental.
|
||||
They should never be used with a dynamic library, as prototypes may change in the future.
|
||||
They are provided for advanced scenarios.
|
||||
Use them only in association with static linking.
|
||||
|
||||
<BR></pre>
|
||||
|
||||
<a name="Chapter11"></a><h2>Advanced types</h2><pre></pre>
|
||||
<a name="Chapter12"></a><h2>Advanced types</h2><pre></pre>
|
||||
|
||||
<pre><b>typedef enum { ZSTD_fast=1, ZSTD_dfast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2,
|
||||
ZSTD_btlazy2, ZSTD_btopt, ZSTD_btultra } ZSTD_strategy; </b>/* from faster to stronger */<b>
|
||||
@@ -355,7 +365,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
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>
|
||||
<a name="Chapter13"></a><h2>Frame size functions</h2><pre></pre>
|
||||
|
||||
<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
|
||||
@@ -388,13 +398,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
however it does mean that all frame data must be present and valid.
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
|
||||
</b><p> `src` should point to the start of a ZSTD frame
|
||||
`srcSize` must be >= ZSTD_frameHeaderSize_prefix.
|
||||
@return : size of the Frame Header
|
||||
</p></pre><BR>
|
||||
<a name="Chapter14"></a><h2>ZSTD_frameHeaderSize() :</h2><pre> srcSize must be >= ZSTD_frameHeaderSize_prefix.
|
||||
@return : size of the Frame Header,
|
||||
or an error code (if srcSize is too small)
|
||||
<BR></pre>
|
||||
|
||||
<a name="Chapter13"></a><h2>Memory management</h2><pre></pre>
|
||||
<a name="Chapter15"></a><h2>Memory management</h2><pre></pre>
|
||||
|
||||
<pre><b>size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
|
||||
size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
|
||||
@@ -484,7 +493,7 @@ static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; </b>/**< t
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter14"></a><h2>Advanced compression functions</h2><pre></pre>
|
||||
<a name="Chapter16"></a><h2>Advanced compression functions</h2><pre></pre>
|
||||
|
||||
<pre><b>ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
|
||||
</b><p> Create a digested dictionary for compression
|
||||
@@ -526,7 +535,7 @@ static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; </b>/**< t
|
||||
</b><p> Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter15"></a><h2>Advanced decompression functions</h2><pre></pre>
|
||||
<a name="Chapter17"></a><h2>Advanced decompression functions</h2><pre></pre>
|
||||
|
||||
<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.
|
||||
@@ -566,7 +575,7 @@ static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; </b>/**< t
|
||||
When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code.
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter16"></a><h2>Advanced streaming functions</h2><pre></pre>
|
||||
<a name="Chapter18"></a><h2>Advanced streaming functions</h2><pre></pre>
|
||||
|
||||
<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>
|
||||
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>
|
||||
@@ -598,14 +607,14 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
|
||||
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>
|
||||
</pre></b><BR>
|
||||
<a name="Chapter17"></a><h2>Buffer-less and synchronous inner streaming functions</h2><pre>
|
||||
<a name="Chapter19"></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.
|
||||
But it's also a complex one, with several restrictions, documented below.
|
||||
Prefer normal streaming API for an easier experience.
|
||||
|
||||
<BR></pre>
|
||||
|
||||
<a name="Chapter18"></a><h2>Buffer-less streaming compression (synchronous mode)</h2><pre>
|
||||
<a name="Chapter20"></a><h2>Buffer-less streaming compression (synchronous mode)</h2><pre>
|
||||
A ZSTD_CCtx object is required to track streaming operations.
|
||||
Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
|
||||
ZSTD_CCtx object can be re-used multiple times within successive compression operations.
|
||||
@@ -641,7 +650,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_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>
|
||||
<a name="Chapter19"></a><h2>Buffer-less streaming decompression (synchronous mode)</h2><pre>
|
||||
<a name="Chapter21"></a><h2>Buffer-less streaming decompression (synchronous mode)</h2><pre>
|
||||
A ZSTD_DCtx object is required to track streaming operations.
|
||||
Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
|
||||
A ZSTD_DCtx object can be re-used multiple times.
|
||||
@@ -722,12 +731,17 @@ typedef struct {
|
||||
unsigned dictID;
|
||||
unsigned checksumFlag;
|
||||
} ZSTD_frameHeader;
|
||||
</b>/** ZSTD_getFrameHeader() :<b>
|
||||
* decode Frame Header, or requires larger `srcSize`.
|
||||
* @return : 0, `zfhPtr` is correctly filled,
|
||||
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
||||
* or an error code, which can be tested using ZSTD_isError() */
|
||||
size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); </b>/**< doesn't consume input */<b>
|
||||
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); </b>/**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */<b>
|
||||
</pre></b><BR>
|
||||
<pre><b>typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
|
||||
</b></pre><BR>
|
||||
<a name="Chapter20"></a><h2>New advanced API (experimental)</h2><pre></pre>
|
||||
<a name="Chapter22"></a><h2>New advanced API (experimental)</h2><pre></pre>
|
||||
|
||||
<pre><b>typedef enum {
|
||||
</b>/* Opened question : should we have a format ZSTD_f_auto ?<b>
|
||||
@@ -753,7 +767,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
</b>/* compression parameters */<b>
|
||||
ZSTD_p_compressionLevel=100, </b>/* Update all compression parameters according to pre-defined cLevel table<b>
|
||||
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
||||
* Special: value 0 means "do not change cLevel".
|
||||
* Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT.
|
||||
* 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. */
|
||||
@@ -762,16 +776,19 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
* Special: value 0 means "use default windowLog".
|
||||
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
||||
* 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 initial probe table, as a power of 2.<b>
|
||||
* Resulting table size is (1 << (hashLog+2)).
|
||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
||||
* Larger tables improve compression ratio of strategies <= dFast,
|
||||
* and improve speed of strategies > dFast.
|
||||
* 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 multi-probe search table, as a power of 2.<b>
|
||||
* Resulting table size is (1 << (chainLog+2)).
|
||||
* Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX.
|
||||
* Larger tables result in better and slower compression.
|
||||
* This parameter is useless when using "fast" strategy.
|
||||
* Note it's still useful when using "dfast" strategy,
|
||||
* in which case it defines a secondary probe table.
|
||||
* Special: value 0 means "use default chainLog". */
|
||||
ZSTD_p_searchLog, </b>/* Number of search attempts, as a power of 2.<b>
|
||||
* More attempts result in better and slower compression.
|
||||
@@ -853,26 +870,51 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
</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>
|
||||
* even when referencing into Dictionary content (default:0) */
|
||||
ZSTD_p_forceAttachDict, </b>/* ZSTD supports usage of a CDict in-place<b>
|
||||
* (avoiding having to copy the compression tables
|
||||
* from the CDict into the working context). Using
|
||||
* a CDict in this way saves an initial setup step,
|
||||
* but comes at the cost of more work per byte of
|
||||
* input. ZSTD has a simple internal heuristic that
|
||||
* guesses which strategy will be faster. You can
|
||||
* use this flag to override that guess.
|
||||
*
|
||||
* Note that the by-reference, in-place strategy is
|
||||
* only used when reusing a compression context
|
||||
* with compatible compression parameters. (If
|
||||
* incompatible / uninitialized, the working
|
||||
* context needs to be cleared anyways, which is
|
||||
* about as expensive as overwriting it with the
|
||||
* dictionary context, so there's no savings in
|
||||
* using the CDict by-ref.)
|
||||
*
|
||||
* Values greater than 0 force attaching the dict.
|
||||
* Values less than 0 force copying the dict.
|
||||
* 0 selects the default heuristic-guided behavior.
|
||||
*/
|
||||
|
||||
} ZSTD_cParameter;
|
||||
</b></pre><BR>
|
||||
<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.
|
||||
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.
|
||||
@result : informational value (typically, value being set clamped correctly),
|
||||
Setting a parameter is generally only possible during frame initialization (before starting compression).
|
||||
Exception : when using multi-threading mode (nbThreads >= 1),
|
||||
following parameters can be updated _during_ compression (within same frame):
|
||||
=> compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy.
|
||||
new parameters will be active on next job, or after a flush().
|
||||
Note : when `value` type is not unsigned (int, or enum), cast it to unsigned for proper type checking.
|
||||
@result : informational value (typically, value being set, correctly clamped),
|
||||
or an error code (which can be tested with ZSTD_isError()).
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned* value);
|
||||
</b><p> Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
|
||||
</b><p> Total input data size to be compressed as a single frame.
|
||||
This value will be controlled at the end, and result in error if not respected.
|
||||
@@ -916,18 +958,21 @@ size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size
|
||||
Note 2 : CDict is just referenced, its lifetime must outlive CCtx.
|
||||
</p></pre><BR>
|
||||
|
||||
<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_dictContentType_e dictContentType);
|
||||
<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_dictContentType_e dictContentType);
|
||||
</b><p> Reference a prefix (single-usage dictionary) for next compression job.
|
||||
Decompression need same prefix to properly regenerate data.
|
||||
Prefix is **only used once**. Tables are discarded at end of compression job.
|
||||
Subsequent compression jobs will be done without prefix (if none is explicitly referenced).
|
||||
If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_CDict instead.
|
||||
Prefix is **only used once**. Tables are discarded at end of compression job (ZSTD_e_end).
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
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.
|
||||
Its contain must remain unmodified up to end of compression (ZSTD_e_end).
|
||||
Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
||||
It's a CPU consuming operation, with non-negligible impact on latency.
|
||||
If there is a need to use same prefix multiple times, consider loadDictionary instead.
|
||||
Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||
Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
||||
</p></pre><BR>
|
||||
@@ -936,9 +981,16 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
</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.
|
||||
The parameters and dictionary are kept unchanged, to reset them use ZSTD_CCtx_resetParameters().
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_resetParameters(ZSTD_CCtx* cctx);
|
||||
</b><p> All parameters are back to default values (compression level is ZSTD_CLEVEL_DEFAULT).
|
||||
Dictionary (if any) is dropped.
|
||||
All parameters are back to default values.
|
||||
It's possible to modify compression parameters after a reset.
|
||||
Resetting parameters is only possible during frame initialization (before starting compression).
|
||||
To reset the context use ZSTD_CCtx_reset().
|
||||
@return 0 or an error code (which can be checked with ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
@@ -1033,6 +1085,13 @@ size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtxParam_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned* value);
|
||||
</b><p> Similar to ZSTD_CCtx_getParameter.
|
||||
Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
||||
</b><p> Apply a set of ZSTD_CCtx_params to the compression context.
|
||||
@@ -1043,7 +1102,8 @@ size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<h3>Advanced parameters for decompression API</h3><pre></pre><b><pre></pre></b><BR>
|
||||
<h3>Advanced decompression API</h3><pre></pre><b><pre></b>/* ==================================== */<b>
|
||||
</pre></b><BR>
|
||||
<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);
|
||||
size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
|
||||
@@ -1074,17 +1134,23 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<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_dictContentType_e dictContentType);
|
||||
<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_dictContentType_e dictContentType);
|
||||
</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.
|
||||
If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead.
|
||||
Prefix is **only used once**. Reference is discarded at end of frame.
|
||||
End of frame is reached when ZSTD_DCtx_decompress_generic() returns 0.
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
|
||||
Note 2 : Prefix buffer is referenced. It must outlive compression job.
|
||||
Note 2 : Prefix buffer is referenced. It **must** outlive decompression job.
|
||||
Prefix buffer must remain unmodified up to the end of frame,
|
||||
reached when ZSTD_DCtx_decompress_generic() returns 0.
|
||||
Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||
Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
||||
Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
|
||||
A fulldict prefix is more costly though.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
@@ -1105,6 +1171,10 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter23"></a><h2>ZSTD_getFrameHeader_advanced() :</h2><pre> same as ZSTD_getFrameHeader(),
|
||||
with added capability to select a format (like ZSTD_f_zstd1_magicless)
|
||||
<BR></pre>
|
||||
|
||||
<pre><b>size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx,
|
||||
ZSTD_outBuffer* output,
|
||||
ZSTD_inBuffer* input);
|
||||
@@ -1137,7 +1207,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter21"></a><h2>Block level API</h2><pre></pre>
|
||||
<a name="Chapter24"></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).
|
||||
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
|
||||
|
||||
@@ -22,7 +22,7 @@ all: simple_compression simple_decompression \
|
||||
multiple_streaming_compression streaming_memory_usage
|
||||
|
||||
$(LIB) :
|
||||
make -C ../lib libzstd.a
|
||||
$(MAKE) -C ../lib libzstd.a
|
||||
|
||||
simple_compression : simple_compression.c $(LIB)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
@@ -28,10 +28,44 @@ DEBUGFLAGS = -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
|
||||
CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
|
||||
FLAGS = $(CPPFLAGS) $(CFLAGS)
|
||||
|
||||
|
||||
ZSTD_FILES := $(sort $(wildcard common/*.c compress/*.c decompress/*.c dictBuilder/*.c deprecated/*.c))
|
||||
ZSTDCOMMON_FILES := $(sort $(wildcard common/*.c))
|
||||
ZSTDCOMP_FILES := $(sort $(wildcard compress/*.c))
|
||||
ZSTDDECOMP_FILES := $(sort $(wildcard decompress/*.c))
|
||||
ZDICT_FILES := $(sort $(wildcard dictBuilder/*.c))
|
||||
ZDEPR_FILES := $(sort $(wildcard deprecated/*.c))
|
||||
ZSTD_FILES := $(ZSTDCOMMON_FILES)
|
||||
|
||||
ZSTD_LEGACY_SUPPORT ?= 4
|
||||
ZSTD_LIB_COMPRESSION ?= 1
|
||||
ZSTD_LIB_DECOMPRESSION ?= 1
|
||||
ZSTD_LIB_DICTBUILDER ?= 1
|
||||
ZSTD_LIB_DEPRECATED ?= 1
|
||||
|
||||
ifeq ($(ZSTD_LIB_COMPRESSION), 0)
|
||||
ZSTD_LIB_DICTBUILDER = 0
|
||||
ZSTD_LIB_DEPRECATED = 0
|
||||
endif
|
||||
|
||||
ifeq ($(ZSTD_LIB_DECOMPRESSION), 0)
|
||||
ZSTD_LEGACY_SUPPORT = 0
|
||||
ZSTD_LIB_DEPRECATED = 0
|
||||
endif
|
||||
|
||||
ifneq ($(ZSTD_LIB_COMPRESSION), 0)
|
||||
ZSTD_FILES += $(ZSTDCOMP_FILES)
|
||||
endif
|
||||
|
||||
ifneq ($(ZSTD_LIB_DECOMPRESSION), 0)
|
||||
ZSTD_FILES += $(ZSTDDECOMP_FILES)
|
||||
endif
|
||||
|
||||
ifneq ($(ZSTD_LIB_DEPRECATED), 0)
|
||||
ZSTD_FILES += $(ZDEPR_FILES)
|
||||
endif
|
||||
|
||||
ifneq ($(ZSTD_LIB_DICTBUILDER), 0)
|
||||
ZSTD_FILES += $(ZDICT_FILES)
|
||||
endif
|
||||
|
||||
ifneq ($(ZSTD_LEGACY_SUPPORT), 0)
|
||||
ifeq ($(shell test $(ZSTD_LEGACY_SUPPORT) -lt 8; echo $$?), 0)
|
||||
@@ -43,7 +77,7 @@ CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT)
|
||||
|
||||
ZSTD_OBJ := $(patsubst %.c,%.o,$(ZSTD_FILES))
|
||||
|
||||
# OS X linker doesn't support -soname, and use different extension
|
||||
# macOS linker doesn't support -soname, and use different extension
|
||||
# see : https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
|
||||
ifeq ($(shell uname), Darwin)
|
||||
SHARED_EXT = dylib
|
||||
@@ -111,14 +145,14 @@ libzstd-nomt: $(ZSTD_NOMT_FILES)
|
||||
@$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@
|
||||
|
||||
clean:
|
||||
@$(RM) -r *.dSYM # Mac OS-X specific
|
||||
@$(RM) -r *.dSYM # macOS-specific
|
||||
@$(RM) core *.o *.a *.gcda *.$(SHARED_EXT) *.$(SHARED_EXT).* libzstd.pc
|
||||
@$(RM) dll/libzstd.dll dll/libzstd.lib libzstd-nomt*
|
||||
@$(RM) common/*.o compress/*.o decompress/*.o dictBuilder/*.o legacy/*.o deprecated/*.o
|
||||
@echo Cleaning library completed
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets
|
||||
# make install is validated only for Linux, macOS, BSD, Hurd and Solaris targets
|
||||
#-----------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
|
||||
@@ -134,7 +168,7 @@ LIBDIR ?= $(libdir)
|
||||
includedir ?= $(PREFIX)/include
|
||||
INCLUDEDIR ?= $(includedir)
|
||||
|
||||
ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly))
|
||||
ifneq (,$(filter $(shell uname),FreeBSD NetBSD DragonFly))
|
||||
PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig
|
||||
else
|
||||
PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig
|
||||
@@ -159,20 +193,32 @@ libzstd.pc: libzstd.pc.in
|
||||
-e 's|@VERSION@|$(VERSION)|' \
|
||||
$< >$@
|
||||
|
||||
install: libzstd.a libzstd libzstd.pc
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)/ $(DESTDIR)$(INCLUDEDIR)/
|
||||
install: install-pc install-static install-shared install-includes
|
||||
@echo zstd static and shared library installed
|
||||
|
||||
install-pc: libzstd.pc
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)/
|
||||
@$(INSTALL_DATA) libzstd.pc $(DESTDIR)$(PKGCONFIGDIR)/
|
||||
@echo Installing libraries
|
||||
|
||||
install-static: libzstd.a
|
||||
@echo Installing static library
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/
|
||||
@$(INSTALL_DATA) libzstd.a $(DESTDIR)$(LIBDIR)
|
||||
|
||||
install-shared: libzstd
|
||||
@echo Installing shared library
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/
|
||||
@$(INSTALL_PROGRAM) $(LIBZSTD) $(DESTDIR)$(LIBDIR)
|
||||
@ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR)
|
||||
@ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT)
|
||||
|
||||
install-includes:
|
||||
@echo Installing includes
|
||||
@$(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)/
|
||||
@$(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR)
|
||||
@$(INSTALL_DATA) common/zstd_errors.h $(DESTDIR)$(INCLUDEDIR)
|
||||
@$(INSTALL_DATA) deprecated/zbuff.h $(DESTDIR)$(INCLUDEDIR) # prototypes generate deprecation warnings
|
||||
@$(INSTALL_DATA) dictBuilder/zdict.h $(DESTDIR)$(INCLUDEDIR)
|
||||
@echo zstd static and shared library installed
|
||||
|
||||
uninstall:
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libzstd.a
|
||||
|
||||
@@ -61,6 +61,10 @@ It's possible to compile only a limited set of features.
|
||||
Each version also provides an additional dedicated set of advanced API.
|
||||
For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` .
|
||||
Note : `lib/legacy` only supports _decoding_ legacy formats.
|
||||
- Similarly, you can define `ZSTD_LIB_COMPRESSION, ZSTD_LIB_DECOMPRESSION`, `ZSTD_LIB_DICTBUILDER`,
|
||||
and `ZSTD_LIB_DEPRECATED` as 0 to forgo compilation of the corresponding features. This will
|
||||
also disable compilation of all dependencies (eg. `ZSTD_LIB_COMPRESSION=0` will also disable
|
||||
dictBuilder).
|
||||
|
||||
|
||||
#### Multithreading support
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* ******************************************************************
|
||||
bitstream
|
||||
Part of FSE library
|
||||
header file (to include)
|
||||
Copyright (C) 2013-2017, Yann Collet.
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
@@ -49,21 +48,10 @@ extern "C" {
|
||||
* Dependencies
|
||||
******************************************/
|
||||
#include "mem.h" /* unaligned access routines */
|
||||
#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
|
||||
#include "error_private.h" /* error codes and messages */
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Debug
|
||||
***************************************/
|
||||
#if defined(BIT_DEBUG) && (BIT_DEBUG>=1)
|
||||
# include <assert.h>
|
||||
#else
|
||||
# ifndef assert
|
||||
# define assert(condition) ((void)0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*=========================================
|
||||
* Target specific
|
||||
=========================================*/
|
||||
@@ -83,8 +71,7 @@ extern "C" {
|
||||
* A critical property of these streams is that they encode and decode in **reverse** direction.
|
||||
* So the first bit sequence you add will be the last to be read, like a LIFO stack.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
size_t bitContainer;
|
||||
unsigned bitPos;
|
||||
char* startPtr;
|
||||
@@ -118,8 +105,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
||||
/*-********************************************
|
||||
* bitStream decoding API (read backward)
|
||||
**********************************************/
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
size_t bitContainer;
|
||||
unsigned bitsConsumed;
|
||||
const char* ptr;
|
||||
@@ -236,7 +222,8 @@ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
|
||||
}
|
||||
|
||||
/*! BIT_addBitsFast() :
|
||||
* works only if `value` is _clean_, meaning all high bits above nbBits are 0 */
|
||||
* works only if `value` is _clean_,
|
||||
* meaning all high bits above nbBits are 0 */
|
||||
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
|
||||
size_t value, unsigned nbBits)
|
||||
{
|
||||
|
||||
@@ -77,9 +77,9 @@
|
||||
* Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
|
||||
*/
|
||||
#ifndef DYNAMIC_BMI2
|
||||
#if (defined(__clang__) && __has_attribute(__target__)) \
|
||||
#if ((defined(__clang__) && __has_attribute(__target__)) \
|
||||
|| (defined(__GNUC__) \
|
||||
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \
|
||||
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \
|
||||
&& (defined(__x86_64__) || defined(_M_X86)) \
|
||||
&& !defined(__BMI2__)
|
||||
# define DYNAMIC_BMI2 1
|
||||
@@ -92,7 +92,7 @@
|
||||
#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 */
|
||||
# define PREFETCH(ptr) _mm_prefetch((const char*)ptr, _MM_HINT_T0)
|
||||
#elif defined(__GNUC__)
|
||||
#elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
|
||||
# define PREFETCH(ptr) __builtin_prefetch(ptr, 0, 0)
|
||||
#else
|
||||
# define PREFETCH(ptr) /* disabled */
|
||||
|
||||
@@ -72,8 +72,7 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
|
||||
"cpuid\n\t"
|
||||
"popl %%ebx\n\t"
|
||||
: "=a"(f1a), "=c"(f1c), "=d"(f1d)
|
||||
: "a"(1)
|
||||
:);
|
||||
: "a"(1));
|
||||
}
|
||||
if (n >= 7) {
|
||||
__asm__(
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/* ******************************************************************
|
||||
debug
|
||||
Part of FSE library
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||
****************************************************************** */
|
||||
|
||||
|
||||
/*
|
||||
* This module only hosts one global variable
|
||||
* which can be used to dynamically influence the verbosity of traces,
|
||||
* such as DEBUGLOG and RAWLOG
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
int g_debuglevel = DEBUGLEVEL;
|
||||
@@ -0,0 +1,123 @@
|
||||
/* ******************************************************************
|
||||
debug
|
||||
Part of FSE library
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||
****************************************************************** */
|
||||
|
||||
|
||||
/*
|
||||
* The purpose of this header is to enable debug functions.
|
||||
* They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,
|
||||
* and DEBUG_STATIC_ASSERT() for compile-time.
|
||||
*
|
||||
* By default, DEBUGLEVEL==0, which means run-time debug is disabled.
|
||||
*
|
||||
* Level 1 enables assert() only.
|
||||
* Starting level 2, traces can be generated and pushed to stderr.
|
||||
* The higher the level, the more verbose the traces.
|
||||
*
|
||||
* It's possible to dynamically adjust level using variable g_debug_level,
|
||||
* which is only declared if DEBUGLEVEL>=2,
|
||||
* and is a global variable, not multi-thread protected (use with care)
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_H_12987983217
|
||||
#define DEBUG_H_12987983217
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* static assert is triggered at compile time, leaving no runtime artefact,
|
||||
* but can only work with compile-time constants.
|
||||
* This variant can only be used inside a function. */
|
||||
#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])
|
||||
|
||||
|
||||
/* DEBUGLEVEL is expected to be defined externally,
|
||||
* typically through compiler command line.
|
||||
* Value must be a number. */
|
||||
#ifndef DEBUGLEVEL
|
||||
# define DEBUGLEVEL 0
|
||||
#endif
|
||||
|
||||
/* recommended values for DEBUGLEVEL :
|
||||
* 0 : no debug, all run-time functions disabled
|
||||
* 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 (verbose)
|
||||
* 7+: events at every position (*very* verbose)
|
||||
*
|
||||
* It's generally inconvenient to output traces > 5.
|
||||
* In which case, it's possible to selectively enable higher verbosity levels
|
||||
* by modifying g_debug_level.
|
||||
*/
|
||||
|
||||
#if (DEBUGLEVEL>=1)
|
||||
# include <assert.h>
|
||||
#else
|
||||
# ifndef assert /* assert may be already defined, due to prior #include <assert.h> */
|
||||
# define assert(condition) ((void)0) /* disable assert (default) */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (DEBUGLEVEL>=2)
|
||||
# include <stdio.h>
|
||||
extern int g_debuglevel; /* here, this variable is only declared,
|
||||
it actually lives in debug.c,
|
||||
and is shared by the whole process.
|
||||
It's typically used to enable very verbose levels
|
||||
on selective conditions (such as position in src) */
|
||||
|
||||
# define RAWLOG(l, ...) { \
|
||||
if (l<=g_debuglevel) { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} }
|
||||
# define DEBUGLOG(l, ...) { \
|
||||
if (l<=g_debuglevel) { \
|
||||
fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
|
||||
fprintf(stderr, " \n"); \
|
||||
} }
|
||||
#else
|
||||
# define RAWLOG(l, ...) {} /* disabled */
|
||||
# define DEBUGLOG(l, ...) {} /* disabled */
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DEBUG_H_12987983217 */
|
||||
@@ -72,7 +72,21 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
|
||||
unsigned charnum = 0;
|
||||
int previous0 = 0;
|
||||
|
||||
if (hbSize < 4) return ERROR(srcSize_wrong);
|
||||
if (hbSize < 4) {
|
||||
/* This function only works when hbSize >= 4 */
|
||||
char buffer[4];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memcpy(buffer, headerBuffer, hbSize);
|
||||
{ size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
|
||||
buffer, sizeof(buffer));
|
||||
if (FSE_isError(countSize)) return countSize;
|
||||
if (countSize > hbSize) return ERROR(corruption_detected);
|
||||
return countSize;
|
||||
} }
|
||||
assert(hbSize >= 4);
|
||||
|
||||
/* init */
|
||||
memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */
|
||||
bitStream = MEM_readLE32(ip);
|
||||
nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
|
||||
if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
|
||||
@@ -105,6 +119,7 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
|
||||
if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
|
||||
while (charnum < n0) normalizedCounter[charnum++] = 0;
|
||||
if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
|
||||
assert((bitCount >> 3) <= 3); /* For first condition to work */
|
||||
ip += bitCount>>3;
|
||||
bitCount &= 7;
|
||||
bitStream = MEM_readLE32(ip) >> bitCount;
|
||||
|
||||
@@ -72,6 +72,7 @@ extern "C" {
|
||||
#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
|
||||
FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
|
||||
|
||||
|
||||
/*-****************************************
|
||||
* FSE simple functions
|
||||
******************************************/
|
||||
@@ -129,7 +130,7 @@ FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src,
|
||||
******************************************/
|
||||
/*!
|
||||
FSE_compress() does the following:
|
||||
1. count symbol occurrence from source[] into table count[]
|
||||
1. count symbol occurrence from source[] into table count[] (see hist.h)
|
||||
2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
|
||||
3. save normalized counters to memory buffer using writeNCount()
|
||||
4. build encoding table 'CTable' from normalized counters
|
||||
@@ -147,15 +148,6 @@ or to save and provide normalized distribution using external method.
|
||||
|
||||
/* *** COMPRESSION *** */
|
||||
|
||||
/*! FSE_count():
|
||||
Provides the precise count of each byte within a table 'count'.
|
||||
'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).
|
||||
*maxSymbolValuePtr will be updated if detected smaller than initial value.
|
||||
@return : the count of the most frequent symbol (which is not identified).
|
||||
if return == srcSize, there is only one symbol.
|
||||
Can also return an error code, which can be tested with FSE_isError(). */
|
||||
FSE_PUBLIC_API size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
|
||||
|
||||
/*! FSE_optimalTableLog():
|
||||
dynamically downsize 'tableLog' when conditions are met.
|
||||
It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
|
||||
@@ -167,7 +159,8 @@ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize
|
||||
'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
|
||||
@return : tableLog,
|
||||
or an errorCode, which can be tested using FSE_isError() */
|
||||
FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
|
||||
FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
|
||||
const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
|
||||
|
||||
/*! FSE_NCountWriteBound():
|
||||
Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
|
||||
@@ -178,8 +171,9 @@ FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tab
|
||||
Compactly save 'normalizedCounter' into 'buffer'.
|
||||
@return : size of the compressed table,
|
||||
or an errorCode, which can be tested using FSE_isError(). */
|
||||
FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
|
||||
|
||||
FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
|
||||
const short* normalizedCounter,
|
||||
unsigned maxSymbolValue, unsigned tableLog);
|
||||
|
||||
/*! Constructor and Destructor of FSE_CTable.
|
||||
Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
|
||||
@@ -250,7 +244,9 @@ If there is an error, the function will return an ErrorCode (which can be tested
|
||||
@return : size read from 'rBuffer',
|
||||
or an errorCode, which can be tested using FSE_isError().
|
||||
maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
|
||||
FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize);
|
||||
FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
|
||||
unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
|
||||
const void* rBuffer, size_t rBuffSize);
|
||||
|
||||
/*! Constructor and Destructor of FSE_DTable.
|
||||
Note that its size depends on 'tableLog' */
|
||||
@@ -325,33 +321,8 @@ If there is an error, the function will return an error code, which can be teste
|
||||
|
||||
|
||||
/* *****************************************
|
||||
* FSE advanced API
|
||||
*******************************************/
|
||||
/* FSE_count_wksp() :
|
||||
* Same as FSE_count(), but using an externally provided scratch buffer.
|
||||
* `workSpace` size must be table of >= `1024` unsigned
|
||||
*/
|
||||
size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize, unsigned* workSpace);
|
||||
|
||||
/** FSE_countFast() :
|
||||
* same as FSE_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr
|
||||
*/
|
||||
size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
|
||||
|
||||
/* FSE_countFast_wksp() :
|
||||
* Same as FSE_countFast(), but using an externally provided scratch buffer.
|
||||
* `workSpace` must be a table of minimum `1024` unsigned
|
||||
*/
|
||||
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* workSpace);
|
||||
|
||||
/*! FSE_count_simple() :
|
||||
* 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`).
|
||||
*/
|
||||
size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
|
||||
|
||||
|
||||
* FSE advanced API
|
||||
***************************************** */
|
||||
|
||||
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
|
||||
/**< same as FSE_optimalTableLog(), which used `minus==2` */
|
||||
@@ -576,6 +547,39 @@ MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePt
|
||||
}
|
||||
|
||||
|
||||
/* FSE_getMaxNbBits() :
|
||||
* Approximate maximum cost of a symbol, in bits.
|
||||
* Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
|
||||
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
|
||||
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
|
||||
MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
|
||||
{
|
||||
const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
|
||||
return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
|
||||
}
|
||||
|
||||
/* FSE_bitCost() :
|
||||
* Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
|
||||
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
|
||||
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
|
||||
MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
|
||||
{
|
||||
const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
|
||||
U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
|
||||
U32 const threshold = (minNbBits+1) << 16;
|
||||
assert(tableLog < 16);
|
||||
assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */
|
||||
{ U32 const tableSize = 1 << tableLog;
|
||||
U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
|
||||
U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */
|
||||
U32 const bitMultiplier = 1 << accuracyLog;
|
||||
assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
|
||||
assert(normalizedDeltaFromThreshold <= bitMultiplier);
|
||||
return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ====== Decompression ====== */
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
* Error Management
|
||||
****************************************************************/
|
||||
#define FSE_isError ERR_isError
|
||||
#define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||
#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
|
||||
|
||||
/* check and forward error code */
|
||||
#define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* ******************************************************************
|
||||
Huffman coder, part of New Generation Entropy library
|
||||
header file
|
||||
Copyright (C) 2013-2016, Yann Collet.
|
||||
huff0 huffman codec,
|
||||
part of Finite State Entropy library
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
@@ -163,25 +163,25 @@ HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
|
||||
/* static allocation of HUF's DTable */
|
||||
typedef U32 HUF_DTable;
|
||||
#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
|
||||
#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
|
||||
#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \
|
||||
HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
|
||||
#define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) \
|
||||
#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
|
||||
HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
|
||||
|
||||
|
||||
/* ****************************************
|
||||
* Advanced decompression functions
|
||||
******************************************/
|
||||
size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||
size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||
size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||
size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||
|
||||
size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
|
||||
size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
|
||||
size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */
|
||||
size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||
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); /**< single-symbol decoder */
|
||||
size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||
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); /**< double-symbols decoder */
|
||||
size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||
size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
|
||||
size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||
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); /**< double-symbols decoder */
|
||||
|
||||
|
||||
/* ****************************************
|
||||
@@ -208,7 +208,7 @@ size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, si
|
||||
typedef enum {
|
||||
HUF_repeat_none, /**< Cannot use the previous table */
|
||||
HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
|
||||
HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */
|
||||
HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */
|
||||
} HUF_repeat;
|
||||
/** HUF_compress4X_repeat() :
|
||||
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
||||
@@ -227,7 +227,9 @@ size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
|
||||
*/
|
||||
#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() :
|
||||
* Read compact Huffman tree, saved by HUF_writeCTable().
|
||||
@@ -242,10 +244,15 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
|
||||
* Loading a CTable saved with HUF_writeCTable() */
|
||||
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
|
||||
|
||||
/** HUF_getNbBits() :
|
||||
* Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
|
||||
* Note 1 : is not inlined, as HUF_CElt definition is private
|
||||
* Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */
|
||||
U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue);
|
||||
|
||||
/*
|
||||
* HUF_decompress() does the following:
|
||||
* 1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
|
||||
* 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
|
||||
* 2. build Huffman table from save, using HUF_readDTableX?()
|
||||
* 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
|
||||
*/
|
||||
@@ -253,13 +260,13 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
||||
/** HUF_selectDecoder() :
|
||||
* Tells which decoder is likely to decode faster,
|
||||
* based on a set of pre-computed metrics.
|
||||
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
||||
* @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
|
||||
* Assumption : 0 < dstSize <= 128 KB */
|
||||
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().
|
||||
* HUF_readDTableX1_wksp() and HUF_readDTableX2_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.
|
||||
@@ -270,14 +277,14 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
|
||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
|
||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
||||
|
||||
size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||
size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
||||
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_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||
size_t HUF_readDTableX4_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
||||
|
||||
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||
size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||
size_t HUF_decompress4X2_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);
|
||||
|
||||
|
||||
/* ====================== */
|
||||
@@ -298,25 +305,25 @@ size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
|
||||
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_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
|
||||
size_t HUF_decompress1X1 (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); /* double-symbol decoder */
|
||||
|
||||
size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
|
||||
size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
|
||||
size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||
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); /**< single-symbol decoder */
|
||||
size_t HUF_decompress1X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||
size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
|
||||
size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||
size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
|
||||
size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||
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); /**< double-symbols decoder */
|
||||
|
||||
size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
|
||||
size_t HUF_decompress1X1_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);
|
||||
|
||||
/* 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_decompress1X1_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);
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
|
||||
|
||||
/* ====== Dependencies ======= */
|
||||
#include <stddef.h> /* size_t */
|
||||
#include "pool.h"
|
||||
#include <stddef.h> /* size_t */
|
||||
#include "debug.h" /* assert */
|
||||
#include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */
|
||||
#include "pool.h"
|
||||
|
||||
/* ====== Compiler specifics ====== */
|
||||
#if defined(_MSC_VER)
|
||||
@@ -33,8 +34,9 @@ typedef struct POOL_job_s {
|
||||
struct POOL_ctx_s {
|
||||
ZSTD_customMem customMem;
|
||||
/* Keep track of the threads */
|
||||
ZSTD_pthread_t *threads;
|
||||
size_t numThreads;
|
||||
ZSTD_pthread_t* threads;
|
||||
size_t threadCapacity;
|
||||
size_t threadLimit;
|
||||
|
||||
/* The queue is a circular buffer */
|
||||
POOL_job *queue;
|
||||
@@ -58,10 +60,10 @@ struct POOL_ctx_s {
|
||||
};
|
||||
|
||||
/* POOL_thread() :
|
||||
Work thread for the thread pool.
|
||||
Waits for jobs and executes them.
|
||||
@returns : NULL on failure else non-null.
|
||||
*/
|
||||
* Work thread for the thread pool.
|
||||
* Waits for jobs and executes them.
|
||||
* @returns : NULL on failure else non-null.
|
||||
*/
|
||||
static void* POOL_thread(void* opaque) {
|
||||
POOL_ctx* const ctx = (POOL_ctx*)opaque;
|
||||
if (!ctx) { return NULL; }
|
||||
@@ -69,14 +71,17 @@ static void* POOL_thread(void* opaque) {
|
||||
/* Lock the mutex and wait for a non-empty queue or until shutdown */
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
|
||||
while (ctx->queueEmpty && !ctx->shutdown) {
|
||||
while ( ctx->queueEmpty
|
||||
|| (ctx->numThreadsBusy >= ctx->threadLimit) ) {
|
||||
if (ctx->shutdown) {
|
||||
/* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
|
||||
* a few threads will be shutdown while !queueEmpty,
|
||||
* but enough threads will remain active to finish the queue */
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
return opaque;
|
||||
}
|
||||
ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
|
||||
}
|
||||
/* empty => shutting down: so stop */
|
||||
if (ctx->queueEmpty) {
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
return opaque;
|
||||
}
|
||||
/* Pop a job off the queue */
|
||||
{ POOL_job const job = ctx->queue[ctx->queueHead];
|
||||
ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
|
||||
@@ -89,30 +94,32 @@ static void* POOL_thread(void* opaque) {
|
||||
job.function(job.opaque);
|
||||
|
||||
/* If the intended queue size was 0, signal after finishing job */
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
ctx->numThreadsBusy--;
|
||||
if (ctx->queueSize == 1) {
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
ctx->numThreadsBusy--;
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
ZSTD_pthread_cond_signal(&ctx->queuePushCond);
|
||||
} }
|
||||
}
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
}
|
||||
} /* for (;;) */
|
||||
/* Unreachable */
|
||||
assert(0); /* Unreachable */
|
||||
}
|
||||
|
||||
POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
|
||||
return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
|
||||
}
|
||||
|
||||
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
|
||||
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
|
||||
ZSTD_customMem customMem) {
|
||||
POOL_ctx* ctx;
|
||||
/* Check the parameters */
|
||||
/* Check parameters */
|
||||
if (!numThreads) { return NULL; }
|
||||
/* Allocate the context and zero initialize */
|
||||
ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
|
||||
if (!ctx) { return NULL; }
|
||||
/* Initialize the job queue.
|
||||
* It needs one extra space since one space is wasted to differentiate empty
|
||||
* and full queues.
|
||||
* It needs one extra space since one space is wasted to differentiate
|
||||
* empty and full queues.
|
||||
*/
|
||||
ctx->queueSize = queueSize + 1;
|
||||
ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem);
|
||||
@@ -126,7 +133,7 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
|
||||
ctx->shutdown = 0;
|
||||
/* Allocate space for the thread handles */
|
||||
ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
|
||||
ctx->numThreads = 0;
|
||||
ctx->threadCapacity = 0;
|
||||
ctx->customMem = customMem;
|
||||
/* Check for errors */
|
||||
if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
|
||||
@@ -134,11 +141,12 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
|
||||
{ size_t i;
|
||||
for (i = 0; i < numThreads; ++i) {
|
||||
if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
|
||||
ctx->numThreads = i;
|
||||
ctx->threadCapacity = i;
|
||||
POOL_free(ctx);
|
||||
return NULL;
|
||||
} }
|
||||
ctx->numThreads = numThreads;
|
||||
ctx->threadCapacity = numThreads;
|
||||
ctx->threadLimit = numThreads;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -156,8 +164,8 @@ static void POOL_join(POOL_ctx* ctx) {
|
||||
ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
|
||||
/* Join all of the threads */
|
||||
{ size_t i;
|
||||
for (i = 0; i < ctx->numThreads; ++i) {
|
||||
ZSTD_pthread_join(ctx->threads[i], NULL);
|
||||
for (i = 0; i < ctx->threadCapacity; ++i) {
|
||||
ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -172,24 +180,68 @@ void POOL_free(POOL_ctx *ctx) {
|
||||
ZSTD_free(ctx, ctx->customMem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t POOL_sizeof(POOL_ctx *ctx) {
|
||||
if (ctx==NULL) return 0; /* supports sizeof NULL */
|
||||
return sizeof(*ctx)
|
||||
+ ctx->queueSize * sizeof(POOL_job)
|
||||
+ ctx->numThreads * sizeof(ZSTD_pthread_t);
|
||||
+ ctx->threadCapacity * sizeof(ZSTD_pthread_t);
|
||||
}
|
||||
|
||||
|
||||
/* @return : 0 on success, 1 on error */
|
||||
static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
|
||||
{
|
||||
if (numThreads <= ctx->threadCapacity) {
|
||||
if (!numThreads) return 1;
|
||||
ctx->threadLimit = numThreads;
|
||||
return 0;
|
||||
}
|
||||
/* numThreads > threadCapacity */
|
||||
{ ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
|
||||
if (!threadPool) return 1;
|
||||
/* replace existing thread pool */
|
||||
memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
|
||||
ZSTD_free(ctx->threads, ctx->customMem);
|
||||
ctx->threads = threadPool;
|
||||
/* Initialize additional threads */
|
||||
{ size_t threadId;
|
||||
for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
|
||||
if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
|
||||
ctx->threadCapacity = threadId;
|
||||
return 1;
|
||||
} }
|
||||
} }
|
||||
/* successfully expanded */
|
||||
ctx->threadCapacity = numThreads;
|
||||
ctx->threadLimit = numThreads;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @return : 0 on success, 1 on error */
|
||||
int POOL_resize(POOL_ctx* ctx, size_t numThreads)
|
||||
{
|
||||
int result;
|
||||
if (ctx==NULL) return 1;
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
result = POOL_resize_internal(ctx, numThreads);
|
||||
ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if the queue is full and 0 otherwise.
|
||||
*
|
||||
* If the queueSize is 1 (the pool was created with an intended queueSize of 0),
|
||||
* then a queue is empty if there is a thread free and no job is waiting.
|
||||
* When queueSize is 1 (pool was created with an intended queueSize of 0),
|
||||
* then a queue is empty if there is a thread free _and_ no job is waiting.
|
||||
*/
|
||||
static int isQueueFull(POOL_ctx const* ctx) {
|
||||
if (ctx->queueSize > 1) {
|
||||
return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
|
||||
} else {
|
||||
return ctx->numThreadsBusy == ctx->numThreads ||
|
||||
return (ctx->numThreadsBusy == ctx->threadLimit) ||
|
||||
!ctx->queueEmpty;
|
||||
}
|
||||
}
|
||||
@@ -263,6 +315,11 @@ void POOL_free(POOL_ctx* ctx) {
|
||||
(void)ctx;
|
||||
}
|
||||
|
||||
int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
|
||||
(void)ctx; (void)numThreads;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
|
||||
(void)ctx;
|
||||
function(opaque);
|
||||
|
||||
@@ -30,40 +30,50 @@ typedef struct POOL_ctx_s POOL_ctx;
|
||||
*/
|
||||
POOL_ctx* POOL_create(size_t numThreads, size_t queueSize);
|
||||
|
||||
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem);
|
||||
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
|
||||
ZSTD_customMem customMem);
|
||||
|
||||
/*! POOL_free() :
|
||||
Free a thread pool returned by POOL_create().
|
||||
*/
|
||||
* Free a thread pool returned by POOL_create().
|
||||
*/
|
||||
void POOL_free(POOL_ctx* ctx);
|
||||
|
||||
/*! POOL_resize() :
|
||||
* Expands or shrinks pool's number of threads.
|
||||
* This is more efficient than releasing + creating a new context,
|
||||
* since it tries to preserve and re-use existing threads.
|
||||
* `numThreads` must be at least 1.
|
||||
* @return : 0 when resize was successful,
|
||||
* !0 (typically 1) if there is an error.
|
||||
* note : only numThreads can be resized, queueSize remains unchanged.
|
||||
*/
|
||||
int POOL_resize(POOL_ctx* ctx, size_t numThreads);
|
||||
|
||||
/*! POOL_sizeof() :
|
||||
return memory usage of pool returned by POOL_create().
|
||||
*/
|
||||
* @return threadpool memory usage
|
||||
* note : compatible with NULL (returns 0 in this case)
|
||||
*/
|
||||
size_t POOL_sizeof(POOL_ctx* ctx);
|
||||
|
||||
/*! POOL_function :
|
||||
The function type that can be added to a thread pool.
|
||||
*/
|
||||
* The function type that can be added to a thread pool.
|
||||
*/
|
||||
typedef void (*POOL_function)(void*);
|
||||
/*! POOL_add_function :
|
||||
The function type for a generic thread pool add function.
|
||||
*/
|
||||
typedef void (*POOL_add_function)(void*, POOL_function, void*);
|
||||
|
||||
/*! POOL_add() :
|
||||
Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
|
||||
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.
|
||||
*/
|
||||
* Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
|
||||
* Possibly blocks until there is room in the queue.
|
||||
* Note : The function may be executed asynchronously,
|
||||
* therefore, `opaque` must live until function has been completed.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
* Add the job `function(opaque)` to thread pool _if_ a worker is available.
|
||||
* Returns immediately even if not (does not block).
|
||||
* @return : 1 if successful, 0 if not.
|
||||
*/
|
||||
int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
|
||||
|
||||
|
||||
|
||||
@@ -46,11 +46,6 @@ ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
|
||||
* provides error code string from enum */
|
||||
const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
|
||||
|
||||
/*! g_debuglog_enable :
|
||||
* turn on/off debug traces (global switch) */
|
||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 2)
|
||||
int g_debuglog_enable = 1;
|
||||
#endif
|
||||
|
||||
|
||||
/*=**************************************************************
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
***************************************/
|
||||
#include "compiler.h"
|
||||
#include "mem.h"
|
||||
#include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */
|
||||
#include "error_private.h"
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
#include "zstd.h"
|
||||
@@ -38,43 +39,8 @@
|
||||
extern "C" {
|
||||
#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
|
||||
/* ---- static assert (debug) --- */
|
||||
#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
|
||||
|
||||
|
||||
/*-*************************************
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* ******************************************************************
|
||||
FSE : Finite State Entropy encoder
|
||||
Copyright (C) 2013-2015, Yann Collet.
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
@@ -37,9 +37,11 @@
|
||||
****************************************************************/
|
||||
#include <stdlib.h> /* malloc, free, qsort */
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include <stdio.h> /* printf (debug) */
|
||||
#include "bitstream.h"
|
||||
#include "compiler.h"
|
||||
#include "mem.h" /* U32, U16, etc. */
|
||||
#include "debug.h" /* assert, DEBUGLOG */
|
||||
#include "hist.h" /* HIST_count_wksp */
|
||||
#include "bitstream.h"
|
||||
#define FSE_STATIC_LINKING_ONLY
|
||||
#include "fse.h"
|
||||
#include "error_private.h"
|
||||
@@ -49,7 +51,6 @@
|
||||
* Error Management
|
||||
****************************************************************/
|
||||
#define FSE_isError ERR_isError
|
||||
#define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||
|
||||
|
||||
/* **************************************************************
|
||||
@@ -100,6 +101,7 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsi
|
||||
if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
|
||||
tableU16[-2] = (U16) tableLog;
|
||||
tableU16[-1] = (U16) maxSymbolValue;
|
||||
assert(tableLog < 16); /* required for the threshold strategy to work */
|
||||
|
||||
/* For explanations on how to distribute symbol values over the table :
|
||||
* http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
|
||||
@@ -143,7 +145,10 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsi
|
||||
for (s=0; s<=maxSymbolValue; s++) {
|
||||
switch (normalizedCounter[s])
|
||||
{
|
||||
case 0: break;
|
||||
case 0:
|
||||
/* filling nonetheless, for compatibility with FSE_getMaxNbBits() */
|
||||
symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog);
|
||||
break;
|
||||
|
||||
case -1:
|
||||
case 1:
|
||||
@@ -160,6 +165,18 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsi
|
||||
total += normalizedCounter[s];
|
||||
} } } }
|
||||
|
||||
#if 0 /* debug : symbol costs */
|
||||
DEBUGLOG(5, "\n --- table statistics : ");
|
||||
{ U32 symbol;
|
||||
for (symbol=0; symbol<=maxSymbolValue; symbol++) {
|
||||
DEBUGLOG(5, "%3u: w=%3i, maxBits=%u, fracBits=%.2f",
|
||||
symbol, normalizedCounter[symbol],
|
||||
FSE_getMaxNbBits(symbolTT, symbol),
|
||||
(double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -174,8 +191,9 @@ size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned
|
||||
|
||||
#ifndef FSE_COMMONDEFS_ONLY
|
||||
|
||||
|
||||
/*-**************************************************************
|
||||
* FSE NCount encoding-decoding
|
||||
* FSE NCount encoding
|
||||
****************************************************************/
|
||||
size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
|
||||
{
|
||||
@@ -283,159 +301,6 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalized
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-**************************************************************
|
||||
* Counting histogram
|
||||
****************************************************************/
|
||||
/*! FSE_count_simple
|
||||
This function counts byte values within `src`, and store the histogram into table `count`.
|
||||
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`.
|
||||
For this reason, prefer using a table `count` with 256 elements.
|
||||
@return : count of most numerous element.
|
||||
*/
|
||||
size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
const BYTE* const end = ip + srcSize;
|
||||
unsigned maxSymbolValue = *maxSymbolValuePtr;
|
||||
unsigned max=0;
|
||||
|
||||
memset(count, 0, (maxSymbolValue+1)*sizeof(*count));
|
||||
if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
|
||||
|
||||
while (ip<end) {
|
||||
assert(*ip <= maxSymbolValue);
|
||||
count[*ip++]++;
|
||||
}
|
||||
|
||||
while (!count[maxSymbolValue]) maxSymbolValue--;
|
||||
*maxSymbolValuePtr = maxSymbolValue;
|
||||
|
||||
{ U32 s; for (s=0; s<=maxSymbolValue; s++) if (count[s] > max) max = count[s]; }
|
||||
|
||||
return (size_t)max;
|
||||
}
|
||||
|
||||
|
||||
/* FSE_count_parallel_wksp() :
|
||||
* Same as FSE_count_parallel(), but using an externally provided scratch buffer.
|
||||
* `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(
|
||||
unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize,
|
||||
unsigned checkMax, unsigned* const workSpace)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)source;
|
||||
const BYTE* const iend = ip+sourceSize;
|
||||
unsigned maxSymbolValue = *maxSymbolValuePtr;
|
||||
unsigned max=0;
|
||||
U32* const Counting1 = workSpace;
|
||||
U32* const Counting2 = Counting1 + 256;
|
||||
U32* const Counting3 = Counting2 + 256;
|
||||
U32* const Counting4 = Counting3 + 256;
|
||||
|
||||
memset(workSpace, 0, 4*256*sizeof(unsigned));
|
||||
|
||||
/* safety checks */
|
||||
if (!sourceSize) {
|
||||
memset(count, 0, maxSymbolValue + 1);
|
||||
*maxSymbolValuePtr = 0;
|
||||
return 0;
|
||||
}
|
||||
if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
|
||||
|
||||
/* by stripes of 16 bytes */
|
||||
{ U32 cached = MEM_read32(ip); ip += 4;
|
||||
while (ip < iend-15) {
|
||||
U32 c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
}
|
||||
ip-=4;
|
||||
}
|
||||
|
||||
/* finish last symbols */
|
||||
while (ip<iend) Counting1[*ip++]++;
|
||||
|
||||
if (checkMax) { /* verify stats will fit into destination table */
|
||||
U32 s; for (s=255; s>maxSymbolValue; s--) {
|
||||
Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
|
||||
if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
|
||||
} }
|
||||
|
||||
{ U32 s;
|
||||
if (maxSymbolValue > 255) maxSymbolValue = 255;
|
||||
for (s=0; s<=maxSymbolValue; s++) {
|
||||
count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
|
||||
if (count[s] > max) max = count[s];
|
||||
} }
|
||||
|
||||
while (!count[maxSymbolValue]) maxSymbolValue--;
|
||||
*maxSymbolValuePtr = maxSymbolValue;
|
||||
return (size_t)max;
|
||||
}
|
||||
|
||||
/* FSE_countFast_wksp() :
|
||||
* Same as FSE_countFast(), but using an externally provided scratch buffer.
|
||||
* `workSpace` size must be table of >= `1024` unsigned */
|
||||
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize,
|
||||
unsigned* workSpace)
|
||||
{
|
||||
if (sourceSize < 1500) /* heuristic threshold */
|
||||
return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
|
||||
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
|
||||
}
|
||||
|
||||
/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
|
||||
size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize)
|
||||
{
|
||||
unsigned tmpCounters[1024];
|
||||
return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters);
|
||||
}
|
||||
|
||||
/* FSE_count_wksp() :
|
||||
* Same as FSE_count(), but using an externally provided scratch buffer.
|
||||
* `workSpace` size must be table of >= `1024` unsigned */
|
||||
size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize, unsigned* workSpace)
|
||||
{
|
||||
if (*maxSymbolValuePtr < 255)
|
||||
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace);
|
||||
*maxSymbolValuePtr = 255;
|
||||
return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace);
|
||||
}
|
||||
|
||||
size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
unsigned tmpCounters[1024];
|
||||
return FSE_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-**************************************************************
|
||||
* FSE Compression Code
|
||||
****************************************************************/
|
||||
@@ -629,11 +494,11 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
|
||||
U32 s;
|
||||
U32 nTotal = 0;
|
||||
for (s=0; s<=maxSymbolValue; s++)
|
||||
printf("%3i: %4i \n", s, normalizedCounter[s]);
|
||||
RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]);
|
||||
for (s=0; s<=maxSymbolValue; s++)
|
||||
nTotal += abs(normalizedCounter[s]);
|
||||
if (nTotal != (1U<<tableLog))
|
||||
printf("Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
|
||||
RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
|
||||
getchar();
|
||||
}
|
||||
#endif
|
||||
@@ -800,7 +665,7 @@ size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t src
|
||||
if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
|
||||
|
||||
/* Scan input and build symbol stats */
|
||||
{ CHECK_V_F(maxCount, FSE_count_wksp(count, &maxSymbolValue, src, srcSize, (unsigned*)scratchBuffer) );
|
||||
{ CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, (unsigned*)scratchBuffer) );
|
||||
if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */
|
||||
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
||||
if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
|
||||
@@ -835,7 +700,7 @@ typedef struct {
|
||||
size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
|
||||
{
|
||||
fseWkspMax_t scratchBuffer;
|
||||
FSE_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */
|
||||
DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */
|
||||
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
|
||||
return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/* ******************************************************************
|
||||
hist : Histogram functions
|
||||
part of Finite State Entropy project
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
****************************************************************** */
|
||||
|
||||
/* --- dependencies --- */
|
||||
#include "mem.h" /* U32, BYTE, etc. */
|
||||
#include "debug.h" /* assert, DEBUGLOG */
|
||||
#include "error_private.h" /* ERROR */
|
||||
#include "hist.h"
|
||||
|
||||
|
||||
/* --- Error management --- */
|
||||
unsigned HIST_isError(size_t code) { return ERR_isError(code); }
|
||||
|
||||
/*-**************************************************************
|
||||
* Histogram functions
|
||||
****************************************************************/
|
||||
unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
const BYTE* const end = ip + srcSize;
|
||||
unsigned maxSymbolValue = *maxSymbolValuePtr;
|
||||
unsigned largestCount=0;
|
||||
|
||||
memset(count, 0, (maxSymbolValue+1) * sizeof(*count));
|
||||
if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
|
||||
|
||||
while (ip<end) {
|
||||
assert(*ip <= maxSymbolValue);
|
||||
count[*ip++]++;
|
||||
}
|
||||
|
||||
while (!count[maxSymbolValue]) maxSymbolValue--;
|
||||
*maxSymbolValuePtr = maxSymbolValue;
|
||||
|
||||
{ U32 s;
|
||||
for (s=0; s<=maxSymbolValue; s++)
|
||||
if (count[s] > largestCount) largestCount = count[s];
|
||||
}
|
||||
|
||||
return largestCount;
|
||||
}
|
||||
|
||||
|
||||
/* HIST_count_parallel_wksp() :
|
||||
* store histogram into 4 intermediate tables, recombined at the end.
|
||||
* this design makes better use of OoO cpus,
|
||||
* and is noticeably faster when some values are heavily repeated.
|
||||
* But it needs some additional workspace for intermediate tables.
|
||||
* `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32.
|
||||
* @return : largest histogram frequency,
|
||||
* or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */
|
||||
static size_t HIST_count_parallel_wksp(
|
||||
unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize,
|
||||
unsigned checkMax,
|
||||
unsigned* const workSpace)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)source;
|
||||
const BYTE* const iend = ip+sourceSize;
|
||||
unsigned maxSymbolValue = *maxSymbolValuePtr;
|
||||
unsigned max=0;
|
||||
U32* const Counting1 = workSpace;
|
||||
U32* const Counting2 = Counting1 + 256;
|
||||
U32* const Counting3 = Counting2 + 256;
|
||||
U32* const Counting4 = Counting3 + 256;
|
||||
|
||||
memset(workSpace, 0, 4*256*sizeof(unsigned));
|
||||
|
||||
/* safety checks */
|
||||
if (!sourceSize) {
|
||||
memset(count, 0, maxSymbolValue + 1);
|
||||
*maxSymbolValuePtr = 0;
|
||||
return 0;
|
||||
}
|
||||
if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
|
||||
|
||||
/* by stripes of 16 bytes */
|
||||
{ U32 cached = MEM_read32(ip); ip += 4;
|
||||
while (ip < iend-15) {
|
||||
U32 c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||
Counting1[(BYTE) c ]++;
|
||||
Counting2[(BYTE)(c>>8) ]++;
|
||||
Counting3[(BYTE)(c>>16)]++;
|
||||
Counting4[ c>>24 ]++;
|
||||
}
|
||||
ip-=4;
|
||||
}
|
||||
|
||||
/* finish last symbols */
|
||||
while (ip<iend) Counting1[*ip++]++;
|
||||
|
||||
if (checkMax) { /* verify stats will fit into destination table */
|
||||
U32 s; for (s=255; s>maxSymbolValue; s--) {
|
||||
Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
|
||||
if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
|
||||
} }
|
||||
|
||||
{ U32 s;
|
||||
if (maxSymbolValue > 255) maxSymbolValue = 255;
|
||||
for (s=0; s<=maxSymbolValue; s++) {
|
||||
count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
|
||||
if (count[s] > max) max = count[s];
|
||||
} }
|
||||
|
||||
while (!count[maxSymbolValue]) maxSymbolValue--;
|
||||
*maxSymbolValuePtr = maxSymbolValue;
|
||||
return (size_t)max;
|
||||
}
|
||||
|
||||
/* HIST_countFast_wksp() :
|
||||
* Same as HIST_countFast(), but using an externally provided scratch buffer.
|
||||
* `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */
|
||||
size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize,
|
||||
unsigned* workSpace)
|
||||
{
|
||||
if (sourceSize < 1500) /* heuristic threshold */
|
||||
return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize);
|
||||
return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
|
||||
}
|
||||
|
||||
/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
|
||||
size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize)
|
||||
{
|
||||
unsigned tmpCounters[HIST_WKSP_SIZE_U32];
|
||||
return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters);
|
||||
}
|
||||
|
||||
/* HIST_count_wksp() :
|
||||
* Same as HIST_count(), but using an externally provided scratch buffer.
|
||||
* `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */
|
||||
size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* source, size_t sourceSize, unsigned* workSpace)
|
||||
{
|
||||
if (*maxSymbolValuePtr < 255)
|
||||
return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace);
|
||||
*maxSymbolValuePtr = 255;
|
||||
return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace);
|
||||
}
|
||||
|
||||
size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
unsigned tmpCounters[HIST_WKSP_SIZE_U32];
|
||||
return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/* ******************************************************************
|
||||
hist : Histogram functions
|
||||
part of Finite State Entropy project
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
****************************************************************** */
|
||||
|
||||
/* --- dependencies --- */
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/* --- simple histogram functions --- */
|
||||
|
||||
/*! HIST_count():
|
||||
* Provides the precise count of each byte within a table 'count'.
|
||||
* 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).
|
||||
* Updates *maxSymbolValuePtr with actual largest symbol value detected.
|
||||
* @return : count of the most frequent symbol (which isn't identified).
|
||||
* or an error code, which can be tested using HIST_isError().
|
||||
* note : if return == srcSize, there is only one symbol.
|
||||
*/
|
||||
size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
unsigned HIST_isError(size_t code); /*< tells if a return value is an error code */
|
||||
|
||||
|
||||
/* --- advanced histogram functions --- */
|
||||
|
||||
#define HIST_WKSP_SIZE_U32 1024
|
||||
/** HIST_count_wksp() :
|
||||
* Same as HIST_count(), but using an externally provided scratch buffer.
|
||||
* Benefit is this function will use very little stack space.
|
||||
* `workSpace` must be a table of unsigned of size >= HIST_WKSP_SIZE_U32
|
||||
*/
|
||||
size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize,
|
||||
unsigned* workSpace);
|
||||
|
||||
/** HIST_countFast() :
|
||||
* same as HIST_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr.
|
||||
* This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr`
|
||||
*/
|
||||
size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
/** HIST_countFast_wksp() :
|
||||
* Same as HIST_countFast(), but using an externally provided scratch buffer.
|
||||
* `workSpace` must be a table of unsigned of size >= HIST_WKSP_SIZE_U32
|
||||
*/
|
||||
size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize,
|
||||
unsigned* workSpace);
|
||||
|
||||
/*! HIST_count_simple() :
|
||||
* Same as HIST_countFast(), this function is unsafe,
|
||||
* and will segfault if any value within `src` is `> *maxSymbolValuePtr`.
|
||||
* It is also a bit slower for large inputs.
|
||||
* However, it does not need any additional memory (not even on stack).
|
||||
* @return : count of the most frequent symbol.
|
||||
* Note this function doesn't produce any error (i.e. it must succeed).
|
||||
*/
|
||||
unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||
const void* src, size_t srcSize);
|
||||
@@ -45,8 +45,9 @@
|
||||
****************************************************************/
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include <stdio.h> /* printf (debug) */
|
||||
#include "bitstream.h"
|
||||
#include "compiler.h"
|
||||
#include "bitstream.h"
|
||||
#include "hist.h"
|
||||
#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
|
||||
#include "fse.h" /* header compression */
|
||||
#define HUF_STATIC_LINKING_ONLY
|
||||
@@ -58,7 +59,7 @@
|
||||
* Error Management
|
||||
****************************************************************/
|
||||
#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) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
|
||||
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
|
||||
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
|
||||
|
||||
@@ -100,9 +101,9 @@ size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable,
|
||||
if (wtSize <= 1) return 0; /* Not compressible */
|
||||
|
||||
/* Scan input and build symbol stats */
|
||||
{ CHECK_V_F(maxCount, FSE_count_simple(count, &maxSymbolValue, weightTable, wtSize) );
|
||||
{ unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */
|
||||
if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
|
||||
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
||||
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
||||
}
|
||||
|
||||
tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
|
||||
@@ -216,6 +217,13 @@ size_t HUF_readCTable (HUF_CElt* CTable, U32* maxSymbolValuePtr, const void* src
|
||||
return readSize;
|
||||
}
|
||||
|
||||
U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue)
|
||||
{
|
||||
const HUF_CElt* table = (const HUF_CElt*)symbolTable;
|
||||
assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
|
||||
return table[symbolValue].nbBits;
|
||||
}
|
||||
|
||||
|
||||
typedef struct nodeElt_s {
|
||||
U32 count;
|
||||
@@ -660,9 +668,9 @@ static size_t HUF_compress_internal (
|
||||
}
|
||||
|
||||
/* Scan input and build symbol stats */
|
||||
{ CHECK_V_F(largest, FSE_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, table->count) );
|
||||
{ CHECK_V_F(largest, HIST_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 >> 7)+1) return 0; /* heuristic : probably not compressible enough */
|
||||
if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */
|
||||
}
|
||||
|
||||
/* Check validity of previous table */
|
||||
|
||||
@@ -8,21 +8,13 @@
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
#ifndef ZSTD_CLEVEL_DEFAULT
|
||||
# define ZSTD_CLEVEL_DEFAULT 3
|
||||
#endif
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Dependencies
|
||||
***************************************/
|
||||
#include <string.h> /* memset */
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
#include "hist.h" /* HIST_countFast_wksp */
|
||||
#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
|
||||
#include "fse.h"
|
||||
#define HUF_STATIC_LINKING_ONLY
|
||||
@@ -64,17 +56,26 @@ ZSTD_CCtx* ZSTD_createCCtx(void)
|
||||
return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
|
||||
}
|
||||
|
||||
static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
|
||||
{
|
||||
assert(cctx != NULL);
|
||||
memset(cctx, 0, sizeof(*cctx));
|
||||
cctx->customMem = memManager;
|
||||
cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||
{ size_t const err = ZSTD_CCtx_resetParameters(cctx);
|
||||
assert(!ZSTD_isError(err));
|
||||
(void)err;
|
||||
}
|
||||
}
|
||||
|
||||
ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
|
||||
{
|
||||
ZSTD_STATIC_ASSERT(zcss_init==0);
|
||||
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
|
||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||
{ ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
|
||||
{ ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
|
||||
if (!cctx) return NULL;
|
||||
cctx->customMem = customMem;
|
||||
cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
||||
cctx->requestedParams.fParams.contentSizeFlag = 1;
|
||||
cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||
ZSTD_initCCtx(cctx, customMem);
|
||||
return cctx;
|
||||
}
|
||||
}
|
||||
@@ -102,17 +103,24 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
|
||||
return cctx;
|
||||
}
|
||||
|
||||
size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
|
||||
static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
|
||||
{
|
||||
if (cctx==NULL) return 0; /* support free on NULL */
|
||||
if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
|
||||
assert(cctx != NULL);
|
||||
assert(cctx->staticSize == 0);
|
||||
ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL;
|
||||
ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL;
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
|
||||
{
|
||||
if (cctx==NULL) return 0; /* support free on NULL */
|
||||
if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
|
||||
ZSTD_freeCCtxContent(cctx);
|
||||
ZSTD_free(cctx, cctx->customMem);
|
||||
return 0; /* reserved as a potential error code in the future */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,21 +151,6 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
|
||||
/* private API call, for dictBuilder only */
|
||||
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
|
||||
|
||||
ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
||||
const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
|
||||
{
|
||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize);
|
||||
if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
|
||||
if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
|
||||
if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
|
||||
if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
|
||||
if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
|
||||
if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength;
|
||||
if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
|
||||
if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
|
||||
return cParams;
|
||||
}
|
||||
|
||||
static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
||||
ZSTD_compressionParameters cParams)
|
||||
{
|
||||
@@ -251,7 +244,6 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
|
||||
case ZSTD_p_minMatch:
|
||||
case ZSTD_p_targetLength:
|
||||
case ZSTD_p_compressionStrategy:
|
||||
case ZSTD_p_compressLiterals:
|
||||
return 1;
|
||||
|
||||
case ZSTD_p_format:
|
||||
@@ -268,6 +260,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
|
||||
case ZSTD_p_ldmMinMatch:
|
||||
case ZSTD_p_ldmBucketSizeLog:
|
||||
case ZSTD_p_ldmHashEveryLog:
|
||||
case ZSTD_p_forceAttachDict:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -302,7 +295,6 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_compressLiterals:
|
||||
case ZSTD_p_contentSizeFlag:
|
||||
case ZSTD_p_checksumFlag:
|
||||
case ZSTD_p_dictIDFlag:
|
||||
@@ -313,6 +305,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
|
||||
* default : 0 when using a CDict, 1 when using a Prefix */
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_forceAttachDict:
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_nbWorkers:
|
||||
if ((value>0) && cctx->staticSize) {
|
||||
return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
|
||||
@@ -351,7 +346,6 @@ size_t ZSTD_CCtxParam_setParameter(
|
||||
int cLevel = (int)value; /* cast expected to restore negative sign */
|
||||
if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
|
||||
if (cLevel) { /* 0 : does not change current level */
|
||||
CCtxParams->disableLiteralCompression = (cLevel<0); /* negative levels disable huffman */
|
||||
CCtxParams->compressionLevel = cLevel;
|
||||
}
|
||||
if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel;
|
||||
@@ -399,10 +393,6 @@ size_t ZSTD_CCtxParam_setParameter(
|
||||
CCtxParams->cParams.strategy = (ZSTD_strategy)value;
|
||||
return (size_t)CCtxParams->cParams.strategy;
|
||||
|
||||
case ZSTD_p_compressLiterals:
|
||||
CCtxParams->disableLiteralCompression = !value;
|
||||
return !CCtxParams->disableLiteralCompression;
|
||||
|
||||
case ZSTD_p_contentSizeFlag :
|
||||
/* Content size written in frame header _when known_ (default:1) */
|
||||
DEBUGLOG(4, "set content size flag = %u", (value>0));
|
||||
@@ -423,6 +413,12 @@ size_t ZSTD_CCtxParam_setParameter(
|
||||
CCtxParams->forceWindow = (value > 0);
|
||||
return CCtxParams->forceWindow;
|
||||
|
||||
case ZSTD_p_forceAttachDict :
|
||||
CCtxParams->attachDictPref = value ?
|
||||
(value > 0 ? ZSTD_dictForceAttach : ZSTD_dictForceCopy) :
|
||||
ZSTD_dictDefaultAttach;
|
||||
return CCtxParams->attachDictPref;
|
||||
|
||||
case ZSTD_p_nbWorkers :
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
if (value>0) return ERROR(parameter_unsupported);
|
||||
@@ -477,6 +473,98 @@ size_t ZSTD_CCtxParam_setParameter(
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned* value)
|
||||
{
|
||||
return ZSTD_CCtxParam_getParameter(&cctx->requestedParams, param, value);
|
||||
}
|
||||
|
||||
size_t ZSTD_CCtxParam_getParameter(
|
||||
ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned* value)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case ZSTD_p_format :
|
||||
*value = CCtxParams->format;
|
||||
break;
|
||||
case ZSTD_p_compressionLevel :
|
||||
*value = CCtxParams->compressionLevel;
|
||||
break;
|
||||
case ZSTD_p_windowLog :
|
||||
*value = CCtxParams->cParams.windowLog;
|
||||
break;
|
||||
case ZSTD_p_hashLog :
|
||||
*value = CCtxParams->cParams.hashLog;
|
||||
break;
|
||||
case ZSTD_p_chainLog :
|
||||
*value = CCtxParams->cParams.chainLog;
|
||||
break;
|
||||
case ZSTD_p_searchLog :
|
||||
*value = CCtxParams->cParams.searchLog;
|
||||
break;
|
||||
case ZSTD_p_minMatch :
|
||||
*value = CCtxParams->cParams.searchLength;
|
||||
break;
|
||||
case ZSTD_p_targetLength :
|
||||
*value = CCtxParams->cParams.targetLength;
|
||||
break;
|
||||
case ZSTD_p_compressionStrategy :
|
||||
*value = (unsigned)CCtxParams->cParams.strategy;
|
||||
break;
|
||||
case ZSTD_p_contentSizeFlag :
|
||||
*value = CCtxParams->fParams.contentSizeFlag;
|
||||
break;
|
||||
case ZSTD_p_checksumFlag :
|
||||
*value = CCtxParams->fParams.checksumFlag;
|
||||
break;
|
||||
case ZSTD_p_dictIDFlag :
|
||||
*value = !CCtxParams->fParams.noDictIDFlag;
|
||||
break;
|
||||
case ZSTD_p_forceMaxWindow :
|
||||
*value = CCtxParams->forceWindow;
|
||||
break;
|
||||
case ZSTD_p_forceAttachDict :
|
||||
*value = CCtxParams->attachDictPref;
|
||||
break;
|
||||
case ZSTD_p_nbWorkers :
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
assert(CCtxParams->nbWorkers == 0);
|
||||
#endif
|
||||
*value = CCtxParams->nbWorkers;
|
||||
break;
|
||||
case ZSTD_p_jobSize :
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
return ERROR(parameter_unsupported);
|
||||
#else
|
||||
*value = CCtxParams->jobSize;
|
||||
break;
|
||||
#endif
|
||||
case ZSTD_p_overlapSizeLog :
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
return ERROR(parameter_unsupported);
|
||||
#else
|
||||
*value = CCtxParams->overlapSizeLog;
|
||||
break;
|
||||
#endif
|
||||
case ZSTD_p_enableLongDistanceMatching :
|
||||
*value = CCtxParams->ldmParams.enableLdm;
|
||||
break;
|
||||
case ZSTD_p_ldmHashLog :
|
||||
*value = CCtxParams->ldmParams.hashLog;
|
||||
break;
|
||||
case ZSTD_p_ldmMinMatch :
|
||||
*value = CCtxParams->ldmParams.minMatchLength;
|
||||
break;
|
||||
case ZSTD_p_ldmBucketSizeLog :
|
||||
*value = CCtxParams->ldmParams.bucketSizeLog;
|
||||
break;
|
||||
case ZSTD_p_ldmHashEveryLog :
|
||||
*value = CCtxParams->ldmParams.hashEveryLog;
|
||||
break;
|
||||
default: return ERROR(parameter_unsupported);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ZSTD_CCtx_setParametersUsingCCtxParams() :
|
||||
* just applies `params` into `cctx`
|
||||
* no action is performed, parameters are merely stored.
|
||||
@@ -487,6 +575,7 @@ size_t ZSTD_CCtxParam_setParameter(
|
||||
size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
|
||||
@@ -565,18 +654,19 @@ size_t ZSTD_CCtx_refPrefix_advanced(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ZSTD_startNewCompression(ZSTD_CCtx* cctx)
|
||||
/*! ZSTD_CCtx_reset() :
|
||||
* Also dumps dictionary */
|
||||
void ZSTD_CCtx_reset(ZSTD_CCtx* cctx)
|
||||
{
|
||||
cctx->streamStage = zcss_init;
|
||||
cctx->pledgedSrcSizePlusOne = 0;
|
||||
}
|
||||
|
||||
/*! ZSTD_CCtx_reset() :
|
||||
* Also dumps dictionary */
|
||||
void ZSTD_CCtx_reset(ZSTD_CCtx* cctx)
|
||||
size_t ZSTD_CCtx_resetParameters(ZSTD_CCtx* cctx)
|
||||
{
|
||||
ZSTD_startNewCompression(cctx);
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
cctx->cdict = NULL;
|
||||
return ZSTD_CCtxParams_reset(&cctx->requestedParams);
|
||||
}
|
||||
|
||||
/** ZSTD_checkCParams() :
|
||||
@@ -589,8 +679,6 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
|
||||
CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||
CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
||||
CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
||||
if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN)
|
||||
return ERROR(parameter_unsupported);
|
||||
if ((U32)(cParams.strategy) > (U32)ZSTD_btultra)
|
||||
return ERROR(parameter_unsupported);
|
||||
return 0;
|
||||
@@ -599,7 +687,8 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
|
||||
/** ZSTD_clampCParams() :
|
||||
* make CParam values within valid range.
|
||||
* @return : valid CParams */
|
||||
static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams)
|
||||
static ZSTD_compressionParameters
|
||||
ZSTD_clampCParams(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
# define CLAMP(val,min,max) { \
|
||||
if (val<min) val=min; \
|
||||
@@ -610,8 +699,7 @@ static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters c
|
||||
CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||
CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
||||
CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
||||
if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN) cParams.targetLength = ZSTD_TARGETLENGTH_MIN;
|
||||
if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra;
|
||||
CLAMP(cParams.strategy, ZSTD_fast, ZSTD_btultra);
|
||||
return cParams;
|
||||
}
|
||||
|
||||
@@ -627,8 +715,11 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
|
||||
optimize `cPar` for a given input (`srcSize` and `dictSize`).
|
||||
mostly downsizing to reduce memory consumption and initialization latency.
|
||||
Both `srcSize` and `dictSize` are optional (use 0 if unknown).
|
||||
Note : cPar is considered validated at this stage. Use ZSTD_checkCParams() to ensure that condition. */
|
||||
ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
|
||||
Note : cPar is assumed validated. Use ZSTD_checkCParams() to ensure this condition. */
|
||||
static ZSTD_compressionParameters
|
||||
ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
|
||||
unsigned long long srcSize,
|
||||
size_t dictSize)
|
||||
{
|
||||
static const U64 minSrcSize = 513; /* (1<<9) + 1 */
|
||||
static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
|
||||
@@ -648,7 +739,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter
|
||||
ZSTD_highbit32(tSize-1) + 1;
|
||||
if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
|
||||
}
|
||||
if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
|
||||
if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
|
||||
{ U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
|
||||
if (cycleLog > cPar.windowLog)
|
||||
cPar.chainLog -= (cycleLog - cPar.windowLog);
|
||||
@@ -660,13 +751,34 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter
|
||||
return cPar;
|
||||
}
|
||||
|
||||
ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
|
||||
ZSTD_compressionParameters
|
||||
ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
|
||||
unsigned long long srcSize,
|
||||
size_t dictSize)
|
||||
{
|
||||
cPar = ZSTD_clampCParams(cPar);
|
||||
return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
|
||||
}
|
||||
|
||||
static size_t ZSTD_sizeof_matchState(ZSTD_compressionParameters const* cParams, const U32 forCCtx)
|
||||
ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
||||
const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
|
||||
{
|
||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize);
|
||||
if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
|
||||
if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
|
||||
if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
|
||||
if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
|
||||
if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
|
||||
if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength;
|
||||
if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
|
||||
if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
|
||||
assert(!ZSTD_checkCParams(cParams));
|
||||
return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
|
||||
}
|
||||
|
||||
static size_t
|
||||
ZSTD_sizeof_matchState(const 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;
|
||||
@@ -752,12 +864,14 @@ size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
|
||||
return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
|
||||
}
|
||||
|
||||
static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) {
|
||||
static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
|
||||
{
|
||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
|
||||
return ZSTD_estimateCStreamSize_usingCParams(cParams);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCStreamSize(int compressionLevel) {
|
||||
size_t ZSTD_estimateCStreamSize(int compressionLevel)
|
||||
{
|
||||
int level;
|
||||
size_t memBudget = 0;
|
||||
for (level=1; level<=compressionLevel; level++) {
|
||||
@@ -851,10 +965,10 @@ 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;
|
||||
bs->entropy.huf.repeatMode = HUF_repeat_none;
|
||||
bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
|
||||
bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
|
||||
bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
|
||||
}
|
||||
|
||||
/*! ZSTD_invalidateMatchState()
|
||||
@@ -866,8 +980,10 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
|
||||
ZSTD_window_clear(&ms->window);
|
||||
|
||||
ms->nextToUpdate = ms->window.dictLimit + 1;
|
||||
ms->nextToUpdate3 = ms->window.dictLimit + 1;
|
||||
ms->loadedDictEnd = 0;
|
||||
ms->opt.litLengthSum = 0; /* force reset of btopt stats */
|
||||
ms->dictMatchState = NULL;
|
||||
}
|
||||
|
||||
/*! ZSTD_continueCCtx() :
|
||||
@@ -900,7 +1016,11 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
|
||||
|
||||
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)
|
||||
static void*
|
||||
ZSTD_reset_matchState(ZSTD_matchState_t* ms,
|
||||
void* ptr,
|
||||
const ZSTD_compressionParameters* 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;
|
||||
@@ -941,10 +1061,18 @@ static void* ZSTD_reset_matchState(ZSTD_matchState_t* ms, void* ptr, ZSTD_compre
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */
|
||||
#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large
|
||||
* during at least this number of times,
|
||||
* context's memory usage is considered wasteful,
|
||||
* because it's sized to handle a worst case scenario which rarely happens.
|
||||
* In which case, resize it down to free some memory */
|
||||
|
||||
/*! ZSTD_resetCCtx_internal() :
|
||||
note : `params` are assumed fully validated at this stage */
|
||||
static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
ZSTD_CCtx_params params, U64 pledgedSrcSize,
|
||||
ZSTD_CCtx_params params,
|
||||
U64 pledgedSrcSize,
|
||||
ZSTD_compResetPolicy_e const crp,
|
||||
ZSTD_buffered_policy_e const zbuff)
|
||||
{
|
||||
@@ -956,20 +1084,20 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
if (ZSTD_equivalentParams(zc->appliedParams, params,
|
||||
zc->inBuffSize, zc->blockSize,
|
||||
zbuff, pledgedSrcSize)) {
|
||||
DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%u)",
|
||||
zc->appliedParams.cParams.windowLog, (U32)zc->blockSize);
|
||||
return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
|
||||
DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)",
|
||||
zc->appliedParams.cParams.windowLog, zc->blockSize);
|
||||
zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */
|
||||
if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION)
|
||||
return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
|
||||
} }
|
||||
DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
|
||||
|
||||
if (params.ldmParams.enableLdm) {
|
||||
/* Adjust long distance matching parameters */
|
||||
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);
|
||||
zc->ldmState.hashPower =
|
||||
ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
|
||||
zc->ldmState.hashPower = ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
|
||||
}
|
||||
|
||||
{ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
|
||||
@@ -981,7 +1109,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
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; /* used to partition workSpace */
|
||||
|
||||
/* Check if workSpace is large enough, alloc a new one if needed */
|
||||
{ size_t const entropySpace = HUF_WORKSPACE_SIZE;
|
||||
@@ -993,14 +1121,20 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace +
|
||||
ldmSeqSpace + matchStateSize + tokenSpace +
|
||||
bufferSpace;
|
||||
DEBUGLOG(4, "Need %uKB workspace, including %uKB for match state, and %uKB for buffers",
|
||||
(U32)(neededSpace>>10), (U32)(matchStateSize>>10), (U32)(bufferSpace>>10));
|
||||
DEBUGLOG(4, "windowSize: %u - blockSize: %u", (U32)windowSize, (U32)blockSize);
|
||||
|
||||
if (zc->workSpaceSize < neededSpace) { /* too small : resize */
|
||||
DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK",
|
||||
(unsigned)(zc->workSpaceSize>>10),
|
||||
(unsigned)(neededSpace>>10));
|
||||
int const workSpaceTooSmall = zc->workSpaceSize < neededSpace;
|
||||
int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace;
|
||||
int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION);
|
||||
zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0;
|
||||
|
||||
DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
|
||||
neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
|
||||
DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
|
||||
|
||||
if (workSpaceTooSmall || workSpaceWasteful) {
|
||||
DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB",
|
||||
zc->workSpaceSize >> 10,
|
||||
neededSpace >> 10);
|
||||
/* static cctx : no resize, error out */
|
||||
if (zc->staticSize) return ERROR(memory_allocation);
|
||||
|
||||
@@ -1009,9 +1143,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
|
||||
if (zc->workSpace == NULL) return ERROR(memory_allocation);
|
||||
zc->workSpaceSize = neededSpace;
|
||||
zc->workSpaceOversizedDuration = 0;
|
||||
ptr = zc->workSpace;
|
||||
|
||||
/* Statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
|
||||
/* Statically sized space.
|
||||
* entropyWorkspace never moves,
|
||||
* though prev/next block swap places */
|
||||
assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
|
||||
assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t));
|
||||
zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace;
|
||||
@@ -1100,48 +1237,98 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
|
||||
|
||||
static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
|
||||
const ZSTD_CDict* cdict,
|
||||
unsigned windowLog,
|
||||
ZSTD_frameParameters fParams,
|
||||
ZSTD_CCtx_params params,
|
||||
U64 pledgedSrcSize,
|
||||
ZSTD_buffered_policy_e zbuff)
|
||||
{
|
||||
{ ZSTD_CCtx_params params = cctx->requestedParams;
|
||||
/* We have a choice between copying the dictionary context into the working
|
||||
* context, or referencing the dictionary context from the working context
|
||||
* in-place. We decide here which strategy to use. */
|
||||
const U64 attachDictSizeCutoffs[(unsigned)ZSTD_btultra+1] = {
|
||||
8 KB, /* unused */
|
||||
8 KB, /* ZSTD_fast */
|
||||
16 KB, /* ZSTD_dfast */
|
||||
32 KB, /* ZSTD_greedy */
|
||||
32 KB, /* ZSTD_lazy */
|
||||
32 KB, /* ZSTD_lazy2 */
|
||||
32 KB, /* ZSTD_btlazy2 */
|
||||
32 KB, /* ZSTD_btopt */
|
||||
8 KB /* ZSTD_btultra */
|
||||
};
|
||||
const int attachDict = ( pledgedSrcSize <= attachDictSizeCutoffs[cdict->cParams.strategy]
|
||||
|| pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
|
||||
|| params.attachDictPref == ZSTD_dictForceAttach )
|
||||
&& params.attachDictPref != ZSTD_dictForceCopy
|
||||
&& !params.forceWindow /* dictMatchState isn't correctly
|
||||
* handled in _enforceMaxDist */
|
||||
&& ZSTD_equivalentCParams(cctx->appliedParams.cParams,
|
||||
cdict->cParams);
|
||||
|
||||
DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
|
||||
|
||||
|
||||
{ unsigned const windowLog = params.cParams.windowLog;
|
||||
assert(windowLog != 0);
|
||||
/* Copy only compression parameters related to tables. */
|
||||
params.cParams = cdict->cParams;
|
||||
if (windowLog) params.cParams.windowLog = windowLog;
|
||||
params.fParams = fParams;
|
||||
params.cParams.windowLog = windowLog;
|
||||
ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
|
||||
ZSTDcrp_noMemset, zbuff);
|
||||
attachDict ? ZSTDcrp_continue : 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));
|
||||
if (attachDict) {
|
||||
const U32 cdictLen = (U32)( cdict->matchState.window.nextSrc
|
||||
- cdict->matchState.window.base);
|
||||
if (cdictLen == 0) {
|
||||
/* don't even attach dictionaries with no contents */
|
||||
DEBUGLOG(4, "skipping attaching empty dictionary");
|
||||
} else {
|
||||
DEBUGLOG(4, "attaching dictionary into context");
|
||||
cctx->blockState.matchState.dictMatchState = &cdict->matchState;
|
||||
|
||||
/* prep working match state so dict matches never have negative indices
|
||||
* when they are translated to the working context's index space. */
|
||||
if (cctx->blockState.matchState.window.dictLimit < cdictLen) {
|
||||
cctx->blockState.matchState.window.nextSrc =
|
||||
cctx->blockState.matchState.window.base + cdictLen;
|
||||
ZSTD_window_clear(&cctx->blockState.matchState.window);
|
||||
}
|
||||
cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
|
||||
}
|
||||
} else {
|
||||
DEBUGLOG(4, "copying dictionary into context");
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
@@ -1192,7 +1379,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
||||
|
||||
/* copy dictionary offsets */
|
||||
{
|
||||
ZSTD_matchState_t const* srcMatchState = &srcCCtx->blockState.matchState;
|
||||
const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
|
||||
ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
|
||||
dstMatchState->window = srcMatchState->window;
|
||||
dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
|
||||
@@ -1356,16 +1543,24 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, cons
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
|
||||
/* ZSTD_minGain() :
|
||||
* minimum compression required
|
||||
* to generate a compress block or a compressed literals section.
|
||||
* note : use same formula for both situations */
|
||||
static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
|
||||
{
|
||||
U32 const minlog = (strat==ZSTD_btultra) ? 7 : 6;
|
||||
return (srcSize >> minlog) + 2;
|
||||
}
|
||||
|
||||
static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy,
|
||||
ZSTD_entropyCTables_t* nextEntropy,
|
||||
static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
||||
ZSTD_hufCTables_t* nextHuf,
|
||||
ZSTD_strategy strategy, int disableLiteralCompression,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
U32* workspace, const int bmi2)
|
||||
{
|
||||
size_t const minGain = ZSTD_minGain(srcSize);
|
||||
size_t const minGain = ZSTD_minGain(srcSize, strategy);
|
||||
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
||||
BYTE* const ostart = (BYTE*)dst;
|
||||
U32 singleStream = srcSize < 256;
|
||||
@@ -1376,27 +1571,25 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy,
|
||||
disableLiteralCompression);
|
||||
|
||||
/* Prepare nextEntropy assuming reusing the existing table */
|
||||
nextEntropy->hufCTable_repeatMode = prevEntropy->hufCTable_repeatMode;
|
||||
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable,
|
||||
sizeof(prevEntropy->hufCTable));
|
||||
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||
|
||||
if (disableLiteralCompression)
|
||||
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||
|
||||
/* small ? don't even attempt compression (speed opt) */
|
||||
# define COMPRESS_LITERALS_SIZE_MIN 63
|
||||
{ size_t const minLitSize = (prevEntropy->hufCTable_repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
|
||||
{ size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
|
||||
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
|
||||
if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
|
||||
{ HUF_repeat repeat = prevEntropy->hufCTable_repeatMode;
|
||||
{ HUF_repeat repeat = prevHuf->repeatMode;
|
||||
int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
|
||||
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
||||
cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
||||
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat, bmi2)
|
||||
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2)
|
||||
: HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
||||
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat, bmi2);
|
||||
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
|
||||
if (repeat != HUF_repeat_none) {
|
||||
/* reused the existing table */
|
||||
hType = set_repeat;
|
||||
@@ -1404,17 +1597,17 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy,
|
||||
}
|
||||
|
||||
if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
|
||||
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
|
||||
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
if (cLitSize==1) {
|
||||
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
|
||||
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
|
||||
if (hType == set_compressed) {
|
||||
/* using a newly constructed table */
|
||||
nextEntropy->hufCTable_repeatMode = HUF_repeat_check;
|
||||
nextHuf->repeatMode = HUF_repeat_check;
|
||||
}
|
||||
|
||||
/* Build header */
|
||||
@@ -1464,61 +1657,234 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
|
||||
mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* -log2(x / 256) lookup table for x in [0, 256).
|
||||
* If x == 0: Return 0
|
||||
* Else: Return floor(-log2(x / 256) * 256)
|
||||
*/
|
||||
static unsigned const kInverseProbabiltyLog256[256] = {
|
||||
0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
|
||||
1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889,
|
||||
874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734,
|
||||
724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626,
|
||||
618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542,
|
||||
535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473,
|
||||
468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415,
|
||||
411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366,
|
||||
362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322,
|
||||
318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282,
|
||||
279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247,
|
||||
244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215,
|
||||
212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185,
|
||||
182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157,
|
||||
155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132,
|
||||
130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108,
|
||||
106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85,
|
||||
83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64,
|
||||
62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44,
|
||||
42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25,
|
||||
23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7,
|
||||
5, 4, 2, 1,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the cost in bits of encoding the distribution described by count
|
||||
* using the entropy bound.
|
||||
*/
|
||||
static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total)
|
||||
{
|
||||
unsigned cost = 0;
|
||||
unsigned s;
|
||||
for (s = 0; s <= max; ++s) {
|
||||
unsigned norm = (unsigned)((256 * count[s]) / total);
|
||||
if (count[s] != 0 && norm == 0)
|
||||
norm = 1;
|
||||
assert(count[s] < total);
|
||||
cost += count[s] * kInverseProbabiltyLog256[norm];
|
||||
}
|
||||
return cost >> 8;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the cost in bits of encoding the distribution in count using the
|
||||
* table described by norm. The max symbol support by norm is assumed >= max.
|
||||
* norm must be valid for every symbol with non-zero probability in count.
|
||||
*/
|
||||
static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
|
||||
unsigned const* count, unsigned const max)
|
||||
{
|
||||
unsigned const shift = 8 - accuracyLog;
|
||||
size_t cost = 0;
|
||||
unsigned s;
|
||||
assert(accuracyLog <= 8);
|
||||
for (s = 0; s <= max; ++s) {
|
||||
unsigned const normAcc = norm[s] != -1 ? norm[s] : 1;
|
||||
unsigned const norm256 = normAcc << shift;
|
||||
assert(norm256 > 0);
|
||||
assert(norm256 < 256);
|
||||
cost += count[s] * kInverseProbabiltyLog256[norm256];
|
||||
}
|
||||
return cost >> 8;
|
||||
}
|
||||
|
||||
|
||||
static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
|
||||
void const* ptr = ctable;
|
||||
U16 const* u16ptr = (U16 const*)ptr;
|
||||
U32 const maxSymbolValue = MEM_read16(u16ptr + 1);
|
||||
return maxSymbolValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the cost in bits of encoding the distribution in count using ctable.
|
||||
* Returns an error if ctable cannot represent all the symbols in count.
|
||||
*/
|
||||
static size_t ZSTD_fseBitCost(
|
||||
FSE_CTable const* ctable,
|
||||
unsigned const* count,
|
||||
unsigned const max)
|
||||
{
|
||||
unsigned const kAccuracyLog = 8;
|
||||
size_t cost = 0;
|
||||
unsigned s;
|
||||
FSE_CState_t cstate;
|
||||
FSE_initCState(&cstate, ctable);
|
||||
if (ZSTD_getFSEMaxSymbolValue(ctable) < max) {
|
||||
DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u",
|
||||
ZSTD_getFSEMaxSymbolValue(ctable), max);
|
||||
return ERROR(GENERIC);
|
||||
}
|
||||
for (s = 0; s <= max; ++s) {
|
||||
unsigned const tableLog = cstate.stateLog;
|
||||
unsigned const badCost = (tableLog + 1) << kAccuracyLog;
|
||||
unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog);
|
||||
if (count[s] == 0)
|
||||
continue;
|
||||
if (bitCost >= badCost) {
|
||||
DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s);
|
||||
return ERROR(GENERIC);
|
||||
}
|
||||
cost += count[s] * bitCost;
|
||||
}
|
||||
return cost >> kAccuracyLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cost in bytes of encoding the normalized count header.
|
||||
* Returns an error if any of the helper functions return an error.
|
||||
*/
|
||||
static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
|
||||
size_t const nbSeq, unsigned const FSELog)
|
||||
{
|
||||
BYTE wksp[FSE_NCOUNTBOUND];
|
||||
S16 norm[MaxSeq + 1];
|
||||
const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
|
||||
CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq, max));
|
||||
return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
ZSTD_defaultDisallowed = 0,
|
||||
ZSTD_defaultAllowed = 1
|
||||
} ZSTD_defaultPolicy_e;
|
||||
|
||||
MEM_STATIC
|
||||
symbolEncodingType_e ZSTD_selectEncodingType(
|
||||
FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq,
|
||||
U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed)
|
||||
MEM_STATIC symbolEncodingType_e
|
||||
ZSTD_selectEncodingType(
|
||||
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
||||
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
||||
FSE_CTable const* prevCTable,
|
||||
short const* defaultNorm, U32 defaultNormLog,
|
||||
ZSTD_defaultPolicy_e const isDefaultAllowed,
|
||||
ZSTD_strategy const strategy)
|
||||
{
|
||||
#define MIN_SEQ_FOR_DYNAMIC_FSE 64
|
||||
#define MAX_SEQ_FOR_STATIC_FSE 1000
|
||||
ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
|
||||
if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) {
|
||||
if (mostFrequent == nbSeq) {
|
||||
*repeatMode = FSE_repeat_none;
|
||||
if (isDefaultAllowed && nbSeq <= 2) {
|
||||
/* Prefer set_basic over set_rle when there are 2 or less symbols,
|
||||
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
|
||||
* If basic encoding isn't possible, always choose RLE.
|
||||
*/
|
||||
DEBUGLOG(5, "Selected set_basic");
|
||||
return set_basic;
|
||||
}
|
||||
DEBUGLOG(5, "Selected set_rle");
|
||||
/* Prefer set_basic over set_rle when there are 2 or less symbols,
|
||||
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
|
||||
* If basic encoding isn't possible, always choose RLE.
|
||||
*/
|
||||
*repeatMode = FSE_repeat_check;
|
||||
return set_rle;
|
||||
}
|
||||
if ( isDefaultAllowed
|
||||
&& (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
|
||||
DEBUGLOG(5, "Selected set_repeat");
|
||||
return set_repeat;
|
||||
}
|
||||
if ( isDefaultAllowed
|
||||
&& ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) ) {
|
||||
DEBUGLOG(5, "Selected set_basic");
|
||||
/* The format allows default tables to be repeated, but it isn't useful.
|
||||
* When using simple heuristics to select encoding type, we don't want
|
||||
* to confuse these tables with dictionaries. When running more careful
|
||||
* analysis, we don't need to waste time checking both repeating tables
|
||||
* and default tables.
|
||||
*/
|
||||
*repeatMode = FSE_repeat_none;
|
||||
return set_basic;
|
||||
if (strategy < ZSTD_lazy) {
|
||||
if (isDefaultAllowed) {
|
||||
size_t const staticFse_nbSeq_max = 1000;
|
||||
size_t const mult = 10 - strategy;
|
||||
size_t const baseLog = 3;
|
||||
size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */
|
||||
assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */
|
||||
assert(mult <= 9 && mult >= 7);
|
||||
if ( (*repeatMode == FSE_repeat_valid)
|
||||
&& (nbSeq < staticFse_nbSeq_max) ) {
|
||||
DEBUGLOG(5, "Selected set_repeat");
|
||||
return set_repeat;
|
||||
}
|
||||
if ( (nbSeq < dynamicFse_nbSeq_min)
|
||||
|| (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) {
|
||||
DEBUGLOG(5, "Selected set_basic");
|
||||
/* The format allows default tables to be repeated, but it isn't useful.
|
||||
* When using simple heuristics to select encoding type, we don't want
|
||||
* to confuse these tables with dictionaries. When running more careful
|
||||
* analysis, we don't need to waste time checking both repeating tables
|
||||
* and default tables.
|
||||
*/
|
||||
*repeatMode = FSE_repeat_none;
|
||||
return set_basic;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC);
|
||||
size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC);
|
||||
size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog);
|
||||
size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq);
|
||||
|
||||
if (isDefaultAllowed) {
|
||||
assert(!ZSTD_isError(basicCost));
|
||||
assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost)));
|
||||
}
|
||||
assert(!ZSTD_isError(NCountCost));
|
||||
assert(compressedCost < ERROR(maxCode));
|
||||
DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u",
|
||||
(U32)basicCost, (U32)repeatCost, (U32)compressedCost);
|
||||
if (basicCost <= repeatCost && basicCost <= compressedCost) {
|
||||
DEBUGLOG(5, "Selected set_basic");
|
||||
assert(isDefaultAllowed);
|
||||
*repeatMode = FSE_repeat_none;
|
||||
return set_basic;
|
||||
}
|
||||
if (repeatCost <= compressedCost) {
|
||||
DEBUGLOG(5, "Selected set_repeat");
|
||||
assert(!ZSTD_isError(repeatCost));
|
||||
return set_repeat;
|
||||
}
|
||||
assert(compressedCost < basicCost && compressedCost < repeatCost);
|
||||
}
|
||||
DEBUGLOG(5, "Selected set_compressed");
|
||||
*repeatMode = FSE_repeat_check;
|
||||
return set_compressed;
|
||||
}
|
||||
|
||||
MEM_STATIC
|
||||
size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
||||
U32* count, U32 max,
|
||||
BYTE const* codeTable, size_t nbSeq,
|
||||
S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||
FSE_CTable const* prevCTable, size_t prevCTableSize,
|
||||
void* workspace, size_t workspaceSize)
|
||||
MEM_STATIC size_t
|
||||
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
||||
U32* count, U32 max,
|
||||
const BYTE* codeTable, size_t nbSeq,
|
||||
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||
const FSE_CTable* prevCTable, size_t prevCTableSize,
|
||||
void* workspace, size_t workspaceSize)
|
||||
{
|
||||
BYTE* op = (BYTE*)dst;
|
||||
BYTE const* const oend = op + dstCapacity;
|
||||
const BYTE* const oend = op + dstCapacity;
|
||||
|
||||
switch (type) {
|
||||
case set_rle:
|
||||
@@ -1706,10 +2072,11 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
const int bmi2)
|
||||
{
|
||||
const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
|
||||
ZSTD_strategy const strategy = cctxParams->cParams.strategy;
|
||||
U32 count[MaxSeq+1];
|
||||
FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
|
||||
FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
|
||||
FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
|
||||
FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
|
||||
FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
|
||||
FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
|
||||
U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
|
||||
const seqDef* const sequences = seqStorePtr->sequencesStart;
|
||||
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
|
||||
@@ -1720,15 +2087,17 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
BYTE* op = ostart;
|
||||
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
||||
BYTE* seqHead;
|
||||
BYTE* lastNCount = NULL;
|
||||
|
||||
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||
|
||||
/* Compress literals */
|
||||
{ const BYTE* const literals = seqStorePtr->litStart;
|
||||
size_t const litSize = seqStorePtr->lit - literals;
|
||||
int const disableLiteralCompression = (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0);
|
||||
size_t const cSize = ZSTD_compressLiterals(
|
||||
prevEntropy, nextEntropy,
|
||||
cctxParams->cParams.strategy, cctxParams->disableLiteralCompression,
|
||||
&prevEntropy->huf, &nextEntropy->huf,
|
||||
cctxParams->cParams.strategy, disableLiteralCompression,
|
||||
op, dstCapacity,
|
||||
literals, litSize,
|
||||
workspace, bmi2);
|
||||
@@ -1747,13 +2116,9 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
else
|
||||
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
||||
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;
|
||||
/* Copy the old tables over as if we repeated them */
|
||||
memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
|
||||
return op - ostart;
|
||||
}
|
||||
|
||||
/* seqHead : flags for FSE encoding type */
|
||||
@@ -1763,43 +2128,53 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
ZSTD_seqToCodes(seqStorePtr);
|
||||
/* build CTable for Literal Lengths */
|
||||
{ U32 max = MaxLL;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace);
|
||||
size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace); /* can't fail */
|
||||
DEBUGLOG(5, "Building LL table");
|
||||
nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
|
||||
LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
|
||||
nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
|
||||
LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, count, max, mostFrequent, nbSeq, LLFSELog, prevEntropy->fse.litlengthCTable, LL_defaultNorm, LL_defaultNormLog, ZSTD_defaultAllowed, strategy);
|
||||
assert(set_basic < set_compressed && set_rle < set_compressed);
|
||||
assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
|
||||
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
||||
prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
||||
prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
if (ZSTD_isError(countSize)) return countSize;
|
||||
if (LLtype == set_compressed)
|
||||
lastNCount = op;
|
||||
op += countSize;
|
||||
} }
|
||||
/* build CTable for Offsets */
|
||||
{ U32 max = MaxOff;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace);
|
||||
size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace); /* can't fail */
|
||||
/* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
|
||||
ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
|
||||
DEBUGLOG(5, "Building OF table");
|
||||
nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
|
||||
Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
|
||||
nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
|
||||
Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, count, max, mostFrequent, nbSeq, OffFSELog, prevEntropy->fse.offcodeCTable, OF_defaultNorm, OF_defaultNormLog, defaultPolicy, strategy);
|
||||
assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
|
||||
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
||||
prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
||||
prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
if (ZSTD_isError(countSize)) return countSize;
|
||||
if (Offtype == set_compressed)
|
||||
lastNCount = op;
|
||||
op += countSize;
|
||||
} }
|
||||
/* build CTable for MatchLengths */
|
||||
{ U32 max = MaxML;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace);
|
||||
size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace); /* can't fail */
|
||||
DEBUGLOG(5, "Building ML table");
|
||||
nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
|
||||
MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
|
||||
nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
|
||||
MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, count, max, mostFrequent, nbSeq, MLFSELog, prevEntropy->fse.matchlengthCTable, ML_defaultNorm, ML_defaultNormLog, ZSTD_defaultAllowed, strategy);
|
||||
assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
|
||||
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
|
||||
prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
|
||||
prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
if (ZSTD_isError(countSize)) return countSize;
|
||||
if (MLtype == set_compressed)
|
||||
lastNCount = op;
|
||||
op += countSize;
|
||||
} }
|
||||
|
||||
@@ -1814,21 +2189,37 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
longOffsets, bmi2);
|
||||
if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
|
||||
op += bitstreamSize;
|
||||
/* zstd versions <= 1.3.4 mistakenly report corruption when
|
||||
* FSE_readNCount() recieves a buffer < 4 bytes.
|
||||
* Fixed by https://github.com/facebook/zstd/pull/1146.
|
||||
* This can happen when the last set_compressed table present is 2
|
||||
* bytes and the bitstream is only one byte.
|
||||
* In this exceedingly rare case, we will simply emit an uncompressed
|
||||
* block, since it isn't worth optimizing.
|
||||
*/
|
||||
if (lastNCount && (op - lastNCount) < 4) {
|
||||
/* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
|
||||
assert(op - lastNCount == 3);
|
||||
DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
|
||||
"emitting an uncompressed block.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return op - ostart;
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||
ZSTD_entropyCTables_t const* prevEntropy,
|
||||
const ZSTD_entropyCTables_t* prevEntropy,
|
||||
ZSTD_entropyCTables_t* nextEntropy,
|
||||
ZSTD_CCtx_params const* cctxParams,
|
||||
const ZSTD_CCtx_params* cctxParams,
|
||||
void* dst, size_t dstCapacity,
|
||||
size_t srcSize, U32* workspace, int bmi2)
|
||||
{
|
||||
size_t const cSize = ZSTD_compressSequences_internal(
|
||||
seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity,
|
||||
workspace, bmi2);
|
||||
if (cSize == 0) return 0;
|
||||
/* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
|
||||
* Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
|
||||
*/
|
||||
@@ -1837,7 +2228,7 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||
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 */
|
||||
{ size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
|
||||
if (cSize >= maxCSize) return 0; /* block not compressed */
|
||||
}
|
||||
|
||||
@@ -1845,8 +2236,8 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||
* block. After the first block, the offcode table might not have large
|
||||
* enough codes to represent the offsets in the data.
|
||||
*/
|
||||
if (nextEntropy->offcode_repeatMode == FSE_repeat_valid)
|
||||
nextEntropy->offcode_repeatMode = FSE_repeat_check;
|
||||
if (nextEntropy->fse.offcode_repeatMode == FSE_repeat_valid)
|
||||
nextEntropy->fse.offcode_repeatMode = FSE_repeat_check;
|
||||
|
||||
return cSize;
|
||||
}
|
||||
@@ -1854,23 +2245,45 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||
/* ZSTD_selectBlockCompressor() :
|
||||
* Not static, but internal use only (used by long distance matcher)
|
||||
* assumption : strat is a valid strategy */
|
||||
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
|
||||
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
|
||||
static const ZSTD_blockCompressor blockCompressor[3][(unsigned)ZSTD_btultra+1] = {
|
||||
{ ZSTD_compressBlock_fast /* default for 0 */,
|
||||
ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
|
||||
ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
|
||||
ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
|
||||
ZSTD_compressBlock_fast,
|
||||
ZSTD_compressBlock_doubleFast,
|
||||
ZSTD_compressBlock_greedy,
|
||||
ZSTD_compressBlock_lazy,
|
||||
ZSTD_compressBlock_lazy2,
|
||||
ZSTD_compressBlock_btlazy2,
|
||||
ZSTD_compressBlock_btopt,
|
||||
ZSTD_compressBlock_btultra },
|
||||
{ ZSTD_compressBlock_fast_extDict /* default for 0 */,
|
||||
ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
|
||||
ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
|
||||
ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
|
||||
ZSTD_compressBlock_fast_extDict,
|
||||
ZSTD_compressBlock_doubleFast_extDict,
|
||||
ZSTD_compressBlock_greedy_extDict,
|
||||
ZSTD_compressBlock_lazy_extDict,
|
||||
ZSTD_compressBlock_lazy2_extDict,
|
||||
ZSTD_compressBlock_btlazy2_extDict,
|
||||
ZSTD_compressBlock_btopt_extDict,
|
||||
ZSTD_compressBlock_btultra_extDict },
|
||||
{ ZSTD_compressBlock_fast_dictMatchState /* default for 0 */,
|
||||
ZSTD_compressBlock_fast_dictMatchState,
|
||||
ZSTD_compressBlock_doubleFast_dictMatchState,
|
||||
ZSTD_compressBlock_greedy_dictMatchState,
|
||||
ZSTD_compressBlock_lazy_dictMatchState,
|
||||
ZSTD_compressBlock_lazy2_dictMatchState,
|
||||
ZSTD_compressBlock_btlazy2_dictMatchState,
|
||||
ZSTD_compressBlock_btopt_dictMatchState,
|
||||
ZSTD_compressBlock_btultra_dictMatchState }
|
||||
};
|
||||
ZSTD_blockCompressor selectedCompressor;
|
||||
ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
|
||||
|
||||
assert((U32)strat >= (U32)ZSTD_fast);
|
||||
assert((U32)strat <= (U32)ZSTD_btultra);
|
||||
return blockCompressor[extDict!=0][(U32)strat];
|
||||
selectedCompressor = blockCompressor[(int)dictMode][(U32)strat];
|
||||
assert(selectedCompressor != NULL);
|
||||
return selectedCompressor;
|
||||
}
|
||||
|
||||
static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
|
||||
@@ -1880,7 +2293,7 @@ static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
|
||||
static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
|
||||
void ZSTD_resetSeqStore(seqStore_t* ssPtr)
|
||||
{
|
||||
ssPtr->lit = ssPtr->litStart;
|
||||
ssPtr->sequences = ssPtr->sequencesStart;
|
||||
@@ -1892,24 +2305,32 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_matchState_t* const ms = &zc->blockState.matchState;
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
|
||||
(U32)dstCapacity, ms->window.dictLimit, ms->nextToUpdate);
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%zu, dictLimit=%u, nextToUpdate=%u)",
|
||||
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 */
|
||||
}
|
||||
ZSTD_resetSeqStore(&(zc->seqStore));
|
||||
ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; /* required for optimal parser to read stats from dictionary */
|
||||
|
||||
/* a gap between an attached dict and the current window is not safe,
|
||||
* they must remain adjacent, and when that stops being the case, the dict
|
||||
* must be unset */
|
||||
assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit);
|
||||
|
||||
/* limited update after a very long match */
|
||||
{ const BYTE* const base = ms->window.base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const U32 current = (U32)(istart-base);
|
||||
if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */
|
||||
if (current > ms->nextToUpdate + 384)
|
||||
ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
|
||||
}
|
||||
|
||||
/* select and store sequences */
|
||||
{ U32 const extDict = ZSTD_window_hasExtDict(ms->window);
|
||||
{ ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms);
|
||||
size_t lastLLSize;
|
||||
{ int i;
|
||||
for (i = 0; i < ZSTD_REP_NUM; ++i)
|
||||
@@ -1923,7 +2344,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
||||
ms, &zc->seqStore,
|
||||
zc->blockState.nextCBlock->rep,
|
||||
&zc->appliedParams.cParams,
|
||||
src, srcSize, extDict);
|
||||
src, srcSize);
|
||||
assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
|
||||
} else if (zc->appliedParams.ldmParams.enableLdm) {
|
||||
rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
|
||||
@@ -1940,10 +2361,10 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
||||
ms, &zc->seqStore,
|
||||
zc->blockState.nextCBlock->rep,
|
||||
&zc->appliedParams.cParams,
|
||||
src, srcSize, extDict);
|
||||
src, srcSize);
|
||||
assert(ldmSeqStore.pos == ldmSeqStore.size);
|
||||
} else { /* not long range mode */
|
||||
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
|
||||
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
|
||||
lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, &zc->appliedParams.cParams, src, srcSize);
|
||||
}
|
||||
{ const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
|
||||
@@ -2010,8 +2431,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
||||
if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
|
||||
else ms->nextToUpdate -= correction;
|
||||
ms->loadedDictEnd = 0;
|
||||
ms->dictMatchState = NULL;
|
||||
}
|
||||
ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd);
|
||||
ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState);
|
||||
if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
|
||||
|
||||
{ size_t cSize = ZSTD_compressBlock_internal(cctx,
|
||||
@@ -2060,6 +2482,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
|
||||
BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
|
||||
size_t pos=0;
|
||||
|
||||
assert(!(params.fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN));
|
||||
if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
|
||||
DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
|
||||
!params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
|
||||
@@ -2153,7 +2576,9 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
||||
if (ZSTD_isError(cSize)) return cSize;
|
||||
cctx->consumedSrcSize += srcSize;
|
||||
cctx->producedCSize += (cSize + fhSize);
|
||||
if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
|
||||
assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
|
||||
if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
|
||||
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
|
||||
if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) {
|
||||
DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u",
|
||||
(U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
|
||||
@@ -2190,7 +2615,10 @@ size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const
|
||||
/*! ZSTD_loadDictionaryContent() :
|
||||
* @return : 0, or an error code
|
||||
*/
|
||||
static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, 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,
|
||||
ZSTD_dictTableLoadMethod_e dtlm)
|
||||
{
|
||||
const BYTE* const ip = (const BYTE*) src;
|
||||
const BYTE* const iend = ip + srcSize;
|
||||
@@ -2204,10 +2632,10 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_CCtx_params
|
||||
switch(params->cParams.strategy)
|
||||
{
|
||||
case ZSTD_fast:
|
||||
ZSTD_fillHashTable(ms, cParams, iend);
|
||||
ZSTD_fillHashTable(ms, cParams, iend, dtlm);
|
||||
break;
|
||||
case ZSTD_dfast:
|
||||
ZSTD_fillDoubleHashTable(ms, cParams, iend);
|
||||
ZSTD_fillDoubleHashTable(ms, cParams, iend, dtlm);
|
||||
break;
|
||||
|
||||
case ZSTD_greedy:
|
||||
@@ -2256,7 +2684,12 @@ static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSym
|
||||
* assumptions : magic number supposed already checked
|
||||
* dictSize supposed > 8
|
||||
*/
|
||||
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)
|
||||
static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
|
||||
ZSTD_matchState_t* ms,
|
||||
ZSTD_CCtx_params const* params,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictTableLoadMethod_e dtlm,
|
||||
void* workspace)
|
||||
{
|
||||
const BYTE* dictPtr = (const BYTE*)dict;
|
||||
const BYTE* const dictEnd = dictPtr + dictSize;
|
||||
@@ -2265,13 +2698,15 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matc
|
||||
size_t dictID;
|
||||
|
||||
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||
assert(dictSize > 8);
|
||||
assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
|
||||
|
||||
dictPtr += 4; /* skip magic number */
|
||||
dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
|
||||
dictPtr += 4;
|
||||
|
||||
{ unsigned maxSymbolValue = 255;
|
||||
size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
|
||||
size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
|
||||
if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
|
||||
if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
|
||||
dictPtr += hufHeaderSize;
|
||||
@@ -2282,7 +2717,8 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matc
|
||||
if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
|
||||
if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
|
||||
/* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
/* fill all offset symbols to avoid garbage at end of table */
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.offcodeCTable, offcodeNCount, MaxOff, offcodeLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
dictionary_corrupted);
|
||||
dictPtr += offcodeHeaderSize;
|
||||
}
|
||||
@@ -2294,7 +2730,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matc
|
||||
if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
|
||||
/* Every match length code must have non-zero probability */
|
||||
CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
dictionary_corrupted);
|
||||
dictPtr += matchlengthHeaderSize;
|
||||
}
|
||||
@@ -2306,7 +2742,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matc
|
||||
if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
|
||||
/* Every literal length code must have non-zero probability */
|
||||
CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
dictionary_corrupted);
|
||||
dictPtr += litlengthHeaderSize;
|
||||
}
|
||||
@@ -2332,22 +2768,25 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matc
|
||||
if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
|
||||
} }
|
||||
|
||||
bs->entropy.hufCTable_repeatMode = HUF_repeat_valid;
|
||||
bs->entropy.offcode_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.matchlength_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.litlength_repeatMode = FSE_repeat_valid;
|
||||
CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize));
|
||||
bs->entropy.huf.repeatMode = HUF_repeat_valid;
|
||||
bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
|
||||
CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize, dtlm));
|
||||
return dictID;
|
||||
}
|
||||
}
|
||||
|
||||
/** ZSTD_compress_insertDictionary() :
|
||||
* @return : dictID, or an error code */
|
||||
static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms,
|
||||
ZSTD_CCtx_params const* params,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictContentType_e dictContentType,
|
||||
void* workspace)
|
||||
static size_t
|
||||
ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
|
||||
ZSTD_matchState_t* ms,
|
||||
const ZSTD_CCtx_params* params,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictContentType_e dictContentType,
|
||||
ZSTD_dictTableLoadMethod_e dtlm,
|
||||
void* workspace)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
|
||||
if ((dict==NULL) || (dictSize<=8)) return 0;
|
||||
@@ -2356,12 +2795,12 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZS
|
||||
|
||||
/* dict restricted modes */
|
||||
if (dictContentType == ZSTD_dct_rawContent)
|
||||
return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
|
||||
return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm);
|
||||
|
||||
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
|
||||
if (dictContentType == ZSTD_dct_auto) {
|
||||
DEBUGLOG(4, "raw content dictionary detected");
|
||||
return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
|
||||
return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm);
|
||||
}
|
||||
if (dictContentType == ZSTD_dct_fullDict)
|
||||
return ERROR(dictionary_wrong);
|
||||
@@ -2369,7 +2808,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZS
|
||||
}
|
||||
|
||||
/* dict as full zstd dictionary */
|
||||
return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, workspace);
|
||||
return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, dtlm, workspace);
|
||||
}
|
||||
|
||||
/*! ZSTD_compressBegin_internal() :
|
||||
@@ -2377,6 +2816,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZS
|
||||
size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictContentType_e dictContentType,
|
||||
ZSTD_dictTableLoadMethod_e dtlm,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params params, U64 pledgedSrcSize,
|
||||
ZSTD_buffered_policy_e zbuff)
|
||||
@@ -2387,9 +2827,7 @@ size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||
|
||||
if (cdict && cdict->dictContentSize>0) {
|
||||
cctx->requestedParams = params;
|
||||
return ZSTD_resetCCtx_usingCDict(cctx, cdict, params.cParams.windowLog,
|
||||
params.fParams, pledgedSrcSize, zbuff);
|
||||
return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
|
||||
}
|
||||
|
||||
CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
|
||||
@@ -2397,7 +2835,7 @@ size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||
{
|
||||
size_t const dictID = ZSTD_compress_insertDictionary(
|
||||
cctx->blockState.prevCBlock, &cctx->blockState.matchState,
|
||||
¶ms, dict, dictSize, dictContentType, cctx->entropyWorkspace);
|
||||
¶ms, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace);
|
||||
if (ZSTD_isError(dictID)) return dictID;
|
||||
assert(dictID <= (size_t)(U32)-1);
|
||||
cctx->dictID = (U32)dictID;
|
||||
@@ -2408,6 +2846,7 @@ size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictContentType_e dictContentType,
|
||||
ZSTD_dictTableLoadMethod_e dtlm,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params params,
|
||||
unsigned long long pledgedSrcSize)
|
||||
@@ -2416,7 +2855,7 @@ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
||||
/* compression parameters verification and optimization */
|
||||
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
||||
return ZSTD_compressBegin_internal(cctx,
|
||||
dict, dictSize, dictContentType,
|
||||
dict, dictSize, dictContentType, dtlm,
|
||||
cdict,
|
||||
params, pledgedSrcSize,
|
||||
ZSTDb_not_buffered);
|
||||
@@ -2431,7 +2870,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||
return ZSTD_compressBegin_advanced_internal(cctx,
|
||||
dict, dictSize, ZSTD_dct_auto,
|
||||
dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
|
||||
NULL /*cdict*/,
|
||||
cctxParams, pledgedSrcSize);
|
||||
}
|
||||
@@ -2442,7 +2881,7 @@ size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t di
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||
DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (U32)dictSize);
|
||||
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL,
|
||||
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
|
||||
cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
|
||||
}
|
||||
|
||||
@@ -2505,7 +2944,9 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
|
||||
if (ZSTD_isError(cSize)) return cSize;
|
||||
endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
|
||||
if (ZSTD_isError(endResult)) return endResult;
|
||||
if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
|
||||
assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
|
||||
if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
|
||||
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
|
||||
DEBUGLOG(4, "end of frame : controlling src size");
|
||||
if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
|
||||
DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u",
|
||||
@@ -2517,22 +2958,22 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
|
||||
|
||||
|
||||
static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict,size_t dictSize,
|
||||
ZSTD_parameters params)
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict,size_t dictSize,
|
||||
ZSTD_parameters params)
|
||||
{
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||
DEBUGLOG(4, "ZSTD_compress_internal");
|
||||
return ZSTD_compress_advanced_internal(cctx,
|
||||
dst, dstCapacity,
|
||||
src, srcSize,
|
||||
dict, dictSize,
|
||||
cctxParams);
|
||||
dst, dstCapacity,
|
||||
src, srcSize,
|
||||
dict, dictSize,
|
||||
cctxParams);
|
||||
}
|
||||
|
||||
size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
|
||||
size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict,size_t dictSize,
|
||||
@@ -2540,7 +2981,11 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_compress_advanced");
|
||||
CHECK_F(ZSTD_checkCParams(params.cParams));
|
||||
return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
|
||||
return ZSTD_compress_internal(cctx,
|
||||
dst, dstCapacity,
|
||||
src, srcSize,
|
||||
dict, dictSize,
|
||||
params);
|
||||
}
|
||||
|
||||
/* Internal */
|
||||
@@ -2551,37 +2996,44 @@ size_t ZSTD_compress_advanced_internal(
|
||||
const void* dict,size_t dictSize,
|
||||
ZSTD_CCtx_params params)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)",
|
||||
(U32)srcSize);
|
||||
CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL,
|
||||
params, srcSize, ZSTDb_not_buffered) );
|
||||
DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (U32)srcSize);
|
||||
CHECK_F( ZSTD_compressBegin_internal(cctx,
|
||||
dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
|
||||
params, srcSize, ZSTDb_not_buffered) );
|
||||
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, 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)
|
||||
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)
|
||||
{
|
||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize ? srcSize : 1, dict ? dictSize : 0);
|
||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0);
|
||||
ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||
assert(params.fParams.contentSizeFlag == 1);
|
||||
ZSTD_CCtxParam_setParameter(&cctxParams, ZSTD_p_compressLiterals, compressionLevel>=0);
|
||||
return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressCCtx (ZSTD_CCtx* cctx, 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)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (U32)srcSize);
|
||||
assert(cctx != NULL);
|
||||
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)
|
||||
{
|
||||
size_t result;
|
||||
ZSTD_CCtx ctxBody;
|
||||
memset(&ctxBody, 0, sizeof(ctxBody));
|
||||
ctxBody.customMem = ZSTD_defaultCMem;
|
||||
ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
|
||||
result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
|
||||
ZSTD_free(ctxBody.workSpace, ZSTD_defaultCMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
|
||||
ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2619,7 +3071,7 @@ static size_t ZSTD_initCDict_internal(
|
||||
ZSTD_dictContentType_e dictContentType,
|
||||
ZSTD_compressionParameters cParams)
|
||||
{
|
||||
DEBUGLOG(3, "ZSTD_initCDict_internal, dictContentType %u", (U32)dictContentType);
|
||||
DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (U32)dictContentType);
|
||||
assert(!ZSTD_checkCParams(cParams));
|
||||
cdict->cParams = cParams;
|
||||
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
|
||||
@@ -2654,7 +3106,7 @@ static size_t ZSTD_initCDict_internal(
|
||||
{ size_t const dictID = ZSTD_compress_insertDictionary(
|
||||
&cdict->cBlockState, &cdict->matchState, ¶ms,
|
||||
cdict->dictContent, cdict->dictContentSize,
|
||||
dictContentType, cdict->workspace);
|
||||
dictContentType, ZSTD_dtlm_full, cdict->workspace);
|
||||
if (ZSTD_isError(dictID)) return dictID;
|
||||
assert(dictID <= (size_t)(U32)-1);
|
||||
cdict->dictID = (U32)dictID;
|
||||
@@ -2799,7 +3251,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
|
||||
}
|
||||
params.fParams = fParams;
|
||||
return ZSTD_compressBegin_internal(cctx,
|
||||
NULL, 0, ZSTD_dct_auto,
|
||||
NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
|
||||
cdict,
|
||||
params, pledgedSrcSize,
|
||||
ZSTDb_not_buffered);
|
||||
@@ -2813,7 +3265,7 @@ size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
|
||||
{
|
||||
ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
|
||||
DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
|
||||
return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
|
||||
return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
|
||||
}
|
||||
|
||||
size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
|
||||
@@ -2882,14 +3334,13 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
|
||||
const ZSTD_CDict* const cdict,
|
||||
ZSTD_CCtx_params const params, unsigned long long const pledgedSrcSize)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_resetCStream_internal (disableLiteralCompression=%i)",
|
||||
params.disableLiteralCompression);
|
||||
DEBUGLOG(4, "ZSTD_resetCStream_internal");
|
||||
/* params are supposed to be fully validated at this point */
|
||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||
|
||||
CHECK_F( ZSTD_compressBegin_internal(cctx,
|
||||
dict, dictSize, dictContentType,
|
||||
dict, dictSize, dictContentType, ZSTD_dtlm_fast,
|
||||
cdict,
|
||||
params, pledgedSrcSize,
|
||||
ZSTDb_buffered) );
|
||||
@@ -3073,7 +3524,7 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
||||
ip = iend;
|
||||
op += cSize;
|
||||
zcs->frameEnded = 1;
|
||||
ZSTD_startNewCompression(zcs);
|
||||
ZSTD_CCtx_reset(zcs);
|
||||
someMoreWork = 0; break;
|
||||
}
|
||||
/* complete loading into inBuffer */
|
||||
@@ -3126,7 +3577,7 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
||||
if (zcs->frameEnded) {
|
||||
DEBUGLOG(5, "Frame completed directly in outBuffer");
|
||||
someMoreWork = 0;
|
||||
ZSTD_startNewCompression(zcs);
|
||||
ZSTD_CCtx_reset(zcs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3154,7 +3605,7 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
||||
if (zcs->frameEnded) {
|
||||
DEBUGLOG(5, "Frame completed on flush");
|
||||
someMoreWork = 0;
|
||||
ZSTD_startNewCompression(zcs);
|
||||
ZSTD_CCtx_reset(zcs);
|
||||
break;
|
||||
}
|
||||
zcs->streamStage = zcss_load;
|
||||
@@ -3207,19 +3658,16 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
params.cParams = ZSTD_getCParamsFromCCtxParams(
|
||||
&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
|
||||
|
||||
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
|
||||
params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
|
||||
}
|
||||
if (params.nbWorkers > 0) {
|
||||
/* mt context creation */
|
||||
if (cctx->mtctx == NULL || (params.nbWorkers != ZSTDMT_getNbWorkers(cctx->mtctx))) {
|
||||
if (cctx->mtctx == NULL) {
|
||||
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);
|
||||
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem);
|
||||
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
|
||||
}
|
||||
@@ -3251,7 +3699,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
{ size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
|
||||
if ( ZSTD_isError(flushMin)
|
||||
|| (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
|
||||
ZSTD_startNewCompression(cctx);
|
||||
ZSTD_CCtx_reset(cctx);
|
||||
}
|
||||
return flushMin;
|
||||
} }
|
||||
@@ -3313,77 +3761,77 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
|
||||
{ /* "default" - guarantees a monotonically increasing memory budget */
|
||||
/* W, C, H, S, L, TL, strat */
|
||||
{ 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */
|
||||
{ 19, 13, 14, 1, 7, 1, ZSTD_fast }, /* level 1 */
|
||||
{ 19, 15, 16, 1, 6, 1, ZSTD_fast }, /* level 2 */
|
||||
{ 20, 16, 17, 1, 5, 8, ZSTD_dfast }, /* level 3 */
|
||||
{ 20, 17, 18, 1, 5, 8, ZSTD_dfast }, /* level 4 */
|
||||
{ 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */
|
||||
{ 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
|
||||
{ 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */
|
||||
{ 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
|
||||
{ 21, 19, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
|
||||
{ 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
|
||||
{ 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
|
||||
{ 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */
|
||||
{ 19, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */
|
||||
{ 20, 16, 17, 1, 5, 1, ZSTD_dfast }, /* level 3 */
|
||||
{ 20, 18, 18, 1, 5, 1, ZSTD_dfast }, /* level 4 */
|
||||
{ 20, 18, 18, 2, 5, 2, ZSTD_greedy }, /* level 5 */
|
||||
{ 21, 18, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */
|
||||
{ 21, 18, 19, 3, 5, 8, ZSTD_lazy2 }, /* level 7 */
|
||||
{ 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
|
||||
{ 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */
|
||||
{ 21, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
|
||||
{ 21, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
|
||||
{ 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
|
||||
{ 22, 21, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */
|
||||
{ 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */
|
||||
{ 22, 22, 22, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */
|
||||
{ 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */
|
||||
{ 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */
|
||||
{ 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */
|
||||
{ 23, 23, 22, 7, 3,128, ZSTD_btopt }, /* level 19 */
|
||||
{ 25, 25, 23, 7, 3,128, ZSTD_btultra }, /* level 20 */
|
||||
{ 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */
|
||||
{ 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
|
||||
{ 23, 22, 22, 4, 4, 64, ZSTD_btopt }, /* level 17 */
|
||||
{ 23, 23, 22, 6, 3,256, ZSTD_btopt }, /* level 18 */
|
||||
{ 23, 24, 22, 7, 3,256, ZSTD_btultra }, /* level 19 */
|
||||
{ 25, 25, 23, 7, 3,256, ZSTD_btultra }, /* level 20 */
|
||||
{ 26, 26, 24, 7, 3,512, ZSTD_btultra }, /* level 21 */
|
||||
{ 27, 27, 25, 9, 3,999, ZSTD_btultra }, /* level 22 */
|
||||
},
|
||||
{ /* for srcSize <= 256 KB */
|
||||
/* W, C, H, S, L, T, strat */
|
||||
{ 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
|
||||
{ 18, 13, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */
|
||||
{ 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
|
||||
{ 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
|
||||
{ 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
|
||||
{ 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
|
||||
{ 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
|
||||
{ 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
|
||||
{ 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
|
||||
{ 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
|
||||
{ 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
|
||||
{ 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
|
||||
{ 18, 18, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 12.*/
|
||||
{ 18, 19, 17, 7, 4, 8, ZSTD_btlazy2 }, /* level 13 */
|
||||
{ 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
|
||||
{ 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
|
||||
{ 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
|
||||
{ 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
|
||||
{ 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
|
||||
{ 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
|
||||
{ 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
|
||||
{ 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
|
||||
{ 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
|
||||
{ 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */
|
||||
{ 18, 14, 14, 1, 5, 1, ZSTD_dfast }, /* level 2 */
|
||||
{ 18, 16, 16, 1, 4, 1, ZSTD_dfast }, /* level 3 */
|
||||
{ 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/
|
||||
{ 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/
|
||||
{ 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/
|
||||
{ 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */
|
||||
{ 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
|
||||
{ 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
|
||||
{ 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
|
||||
{ 18, 18, 19, 5, 4, 16, ZSTD_btlazy2 }, /* level 11.*/
|
||||
{ 18, 19, 19, 6, 4, 16, ZSTD_btlazy2 }, /* level 12.*/
|
||||
{ 18, 19, 19, 8, 4, 16, ZSTD_btlazy2 }, /* level 13 */
|
||||
{ 18, 18, 19, 4, 4, 24, ZSTD_btopt }, /* level 14.*/
|
||||
{ 18, 18, 19, 4, 3, 24, ZSTD_btopt }, /* level 15.*/
|
||||
{ 18, 19, 19, 6, 3, 64, ZSTD_btopt }, /* level 16.*/
|
||||
{ 18, 19, 19, 8, 3,128, ZSTD_btopt }, /* level 17.*/
|
||||
{ 18, 19, 19, 10, 3,256, ZSTD_btopt }, /* level 18.*/
|
||||
{ 18, 19, 19, 10, 3,256, ZSTD_btultra }, /* level 19.*/
|
||||
{ 18, 19, 19, 11, 3,512, ZSTD_btultra }, /* level 20.*/
|
||||
{ 18, 19, 19, 12, 3,512, ZSTD_btultra }, /* level 21.*/
|
||||
{ 18, 19, 19, 13, 3,999, ZSTD_btultra }, /* level 22.*/
|
||||
},
|
||||
{ /* for srcSize <= 128 KB */
|
||||
/* W, C, H, S, L, T, strat */
|
||||
{ 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* level 0 - not used */
|
||||
{ 17, 12, 13, 1, 6, 1, ZSTD_fast }, /* level 1 */
|
||||
{ 17, 13, 16, 1, 5, 1, ZSTD_fast }, /* level 2 */
|
||||
{ 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
|
||||
{ 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
|
||||
{ 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
|
||||
{ 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
|
||||
{ 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
|
||||
{ 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
|
||||
{ 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */
|
||||
{ 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */
|
||||
{ 17, 15, 16, 2, 5, 1, ZSTD_dfast }, /* level 3 */
|
||||
{ 17, 17, 17, 2, 4, 1, ZSTD_dfast }, /* level 4 */
|
||||
{ 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */
|
||||
{ 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
|
||||
{ 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */
|
||||
{ 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
|
||||
{ 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
|
||||
{ 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
|
||||
{ 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
|
||||
{ 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
|
||||
{ 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
|
||||
{ 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
|
||||
{ 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
|
||||
{ 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
|
||||
{ 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
|
||||
{ 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
|
||||
{ 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
|
||||
{ 17, 18, 17, 6, 4, 16, ZSTD_btlazy2 }, /* level 12 */
|
||||
{ 17, 18, 17, 8, 4, 16, ZSTD_btlazy2 }, /* level 13.*/
|
||||
{ 17, 18, 17, 4, 4, 32, ZSTD_btopt }, /* level 14.*/
|
||||
{ 17, 18, 17, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
|
||||
{ 17, 18, 17, 7, 3,128, ZSTD_btopt }, /* level 16.*/
|
||||
{ 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 17.*/
|
||||
{ 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 18.*/
|
||||
{ 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 19.*/
|
||||
{ 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
|
||||
{ 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
|
||||
{ 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
|
||||
@@ -3391,28 +3839,28 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
|
||||
{ /* for srcSize <= 16 KB */
|
||||
/* W, C, H, S, L, T, strat */
|
||||
{ 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
|
||||
{ 14, 14, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */
|
||||
{ 14, 14, 14, 1, 4, 1, ZSTD_fast }, /* level 2 */
|
||||
{ 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
|
||||
{ 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
|
||||
{ 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
|
||||
{ 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
|
||||
{ 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
|
||||
{ 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
|
||||
{ 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
|
||||
{ 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
|
||||
{ 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
|
||||
{ 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */
|
||||
{ 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */
|
||||
{ 14, 14, 14, 2, 4, 1, ZSTD_dfast }, /* level 3.*/
|
||||
{ 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4.*/
|
||||
{ 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/
|
||||
{ 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */
|
||||
{ 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */
|
||||
{ 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/
|
||||
{ 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/
|
||||
{ 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/
|
||||
{ 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/
|
||||
{ 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
|
||||
{ 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
|
||||
{ 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
|
||||
{ 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
|
||||
{ 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
|
||||
{ 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
|
||||
{ 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
|
||||
{ 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
|
||||
{ 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 18.*/
|
||||
{ 14, 15, 15, 6, 3,256, ZSTD_btultra }, /* level 19.*/
|
||||
{ 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
|
||||
{ 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
|
||||
{ 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
|
||||
{ 14, 15, 15, 10, 3,512, ZSTD_btultra }, /* level 22.*/
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
@@ -37,7 +38,8 @@ extern "C" {
|
||||
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 */
|
||||
The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy
|
||||
Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
|
||||
|
||||
|
||||
/*-*************************************
|
||||
@@ -46,6 +48,12 @@ extern "C" {
|
||||
typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
|
||||
typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
|
||||
|
||||
typedef enum {
|
||||
ZSTD_dictDefaultAttach = 0,
|
||||
ZSTD_dictForceAttach = 1,
|
||||
ZSTD_dictForceCopy = -1,
|
||||
} ZSTD_dictAttachPref_e;
|
||||
|
||||
typedef struct ZSTD_prefixDict_s {
|
||||
const void* dict;
|
||||
size_t dictSize;
|
||||
@@ -53,14 +61,22 @@ typedef struct ZSTD_prefixDict_s {
|
||||
} ZSTD_prefixDict;
|
||||
|
||||
typedef struct {
|
||||
U32 hufCTable[HUF_CTABLE_SIZE_U32(255)];
|
||||
U32 CTable[HUF_CTABLE_SIZE_U32(255)];
|
||||
HUF_repeat repeatMode;
|
||||
} ZSTD_hufCTables_t;
|
||||
|
||||
typedef struct {
|
||||
FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
|
||||
FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
|
||||
FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
|
||||
HUF_repeat hufCTable_repeatMode;
|
||||
FSE_repeat offcode_repeatMode;
|
||||
FSE_repeat matchlength_repeatMode;
|
||||
FSE_repeat litlength_repeatMode;
|
||||
} ZSTD_fseCTables_t;
|
||||
|
||||
typedef struct {
|
||||
ZSTD_hufCTables_t huf;
|
||||
ZSTD_fseCTables_t fse;
|
||||
} ZSTD_entropyCTables_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -76,26 +92,27 @@ typedef struct {
|
||||
U32 rep[ZSTD_REP_NUM];
|
||||
} ZSTD_optimal_t;
|
||||
|
||||
typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
|
||||
|
||||
typedef struct {
|
||||
/* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
|
||||
U32* litFreq; /* table of literals statistics, of size 256 */
|
||||
U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
|
||||
U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
|
||||
U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
|
||||
ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
|
||||
ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
|
||||
U32* litFreq; /* table of literals statistics, of size 256 */
|
||||
U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
|
||||
U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
|
||||
U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
|
||||
ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
|
||||
ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
|
||||
|
||||
U32 litSum; /* nb of literals */
|
||||
U32 litLengthSum; /* nb of litLength codes */
|
||||
U32 matchLengthSum; /* nb of matchLength codes */
|
||||
U32 offCodeSum; /* nb of offset codes */
|
||||
/* begin updated by ZSTD_setLog2Prices */
|
||||
U32 log2litSum; /* pow2 to compare log2(litfreq) to */
|
||||
U32 log2litLengthSum; /* pow2 to compare log2(llfreq) to */
|
||||
U32 log2matchLengthSum; /* pow2 to compare log2(mlfreq) to */
|
||||
U32 log2offCodeSum; /* pow2 to compare log2(offreq) to */
|
||||
/* end : updated by ZSTD_setLog2Prices */
|
||||
U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */
|
||||
U32 litSumBasePrice; /* to compare to log2(litfreq) */
|
||||
U32 litLengthSumBasePrice; /* to compare to log2(llfreq) */
|
||||
U32 matchLengthSumBasePrice;/* to compare to log2(mlfreq) */
|
||||
U32 offCodeSumBasePrice; /* to compare to log2(offreq) */
|
||||
ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */
|
||||
const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */
|
||||
} optState_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -111,17 +128,19 @@ typedef struct {
|
||||
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 */
|
||||
typedef struct ZSTD_matchState_t ZSTD_matchState_t;
|
||||
struct ZSTD_matchState_t {
|
||||
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;
|
||||
const ZSTD_matchState_t *dictMatchState;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ZSTD_compressedBlockState_t* prevCBlock;
|
||||
@@ -161,7 +180,7 @@ 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 */
|
||||
size_t capacity; /* The capacity starting from `seq` pointer */
|
||||
} rawSeqStore_t;
|
||||
|
||||
struct ZSTD_CCtx_params_s {
|
||||
@@ -170,10 +189,11 @@ struct ZSTD_CCtx_params_s {
|
||||
ZSTD_frameParameters fParams;
|
||||
|
||||
int compressionLevel;
|
||||
int disableLiteralCompression;
|
||||
int forceWindow; /* force back-references to respect limit of
|
||||
* 1<<wLog, even for dictionary */
|
||||
|
||||
ZSTD_dictAttachPref_e attachDictPref;
|
||||
|
||||
/* Multithreading: used to pass parameters to mtctx */
|
||||
unsigned nbWorkers;
|
||||
unsigned jobSize;
|
||||
@@ -193,6 +213,8 @@ struct ZSTD_CCtx_s {
|
||||
ZSTD_CCtx_params requestedParams;
|
||||
ZSTD_CCtx_params appliedParams;
|
||||
U32 dictID;
|
||||
|
||||
int workSpaceOversizedDuration;
|
||||
void* workSpace;
|
||||
size_t workSpaceSize;
|
||||
size_t blockSize;
|
||||
@@ -235,11 +257,15 @@ struct ZSTD_CCtx_s {
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
|
||||
|
||||
typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
|
||||
|
||||
|
||||
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);
|
||||
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
|
||||
|
||||
|
||||
MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
|
||||
@@ -280,11 +306,11 @@ MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
|
||||
*/
|
||||
MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t mlBase)
|
||||
{
|
||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
|
||||
#if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6)
|
||||
static const BYTE* g_start = NULL;
|
||||
if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */
|
||||
{ U32 const pos = (U32)((const BYTE*)literals - g_start);
|
||||
DEBUGLOG(6, "Cpos%7u :%3u literals, match%3u bytes at dist.code%7u",
|
||||
DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u",
|
||||
pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode);
|
||||
}
|
||||
#endif
|
||||
@@ -420,6 +446,11 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
|
||||
const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
|
||||
size_t const matchLength = ZSTD_count(ip, match, vEnd);
|
||||
if (match + matchLength != mEnd) return matchLength;
|
||||
DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength);
|
||||
DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match);
|
||||
DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip);
|
||||
DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart);
|
||||
DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd));
|
||||
return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
|
||||
}
|
||||
|
||||
@@ -496,6 +527,20 @@ MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
|
||||
return window.lowLimit < window.dictLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* ZSTD_matchState_dictMode():
|
||||
* Inspects the provided matchState and figures out what dictMode should be
|
||||
* passed to the compressor.
|
||||
*/
|
||||
MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
|
||||
{
|
||||
return ZSTD_window_hasExtDict(ms->window) ?
|
||||
ZSTD_extDict :
|
||||
ms->dictMatchState != NULL ?
|
||||
ZSTD_dictMatchState :
|
||||
ZSTD_noDict;
|
||||
}
|
||||
|
||||
/**
|
||||
* ZSTD_window_needOverflowCorrection():
|
||||
* Returns non-zero if the indices are getting too large and need overflow
|
||||
@@ -563,31 +608,41 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
|
||||
* 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.
|
||||
*
|
||||
* In normal dict mode, the dict is between lowLimit and dictLimit. In
|
||||
* dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary
|
||||
* is below them. forceWindow and dictMatchState are therefore incompatible.
|
||||
*/
|
||||
MEM_STATIC void ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
|
||||
void const* srcEnd, U32 maxDist,
|
||||
U32* loadedDictEndPtr)
|
||||
U32* loadedDictEndPtr,
|
||||
const ZSTD_matchState_t** dictMatchStatePtr)
|
||||
{
|
||||
U32 const current = (U32)((BYTE const*)srcEnd - window->base);
|
||||
U32 loadedDictEnd = loadedDictEndPtr != NULL ? *loadedDictEndPtr : 0;
|
||||
DEBUGLOG(5, "ZSTD_window_enforceMaxDist: current=%u, maxDist=%u", current, maxDist);
|
||||
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);
|
||||
DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u",
|
||||
window->dictLimit, window->lowLimit);
|
||||
window->dictLimit = window->lowLimit;
|
||||
}
|
||||
if (loadedDictEndPtr)
|
||||
*loadedDictEndPtr = 0;
|
||||
if (dictMatchStatePtr)
|
||||
*dictMatchStatePtr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,12 +658,12 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||
{
|
||||
BYTE const* const ip = (BYTE const*)src;
|
||||
U32 contiguous = 1;
|
||||
DEBUGLOG(5, "ZSTD_window_update");
|
||||
/* 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);
|
||||
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;
|
||||
@@ -625,10 +680,38 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||
ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
|
||||
U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
|
||||
window->lowLimit = lowLimitMax;
|
||||
DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit);
|
||||
}
|
||||
return contiguous;
|
||||
}
|
||||
|
||||
|
||||
/* debug functions */
|
||||
|
||||
MEM_STATIC double ZSTD_fWeight(U32 rawStat)
|
||||
{
|
||||
U32 const fp_accuracy = 8;
|
||||
U32 const fp_multiplier = (1 << fp_accuracy);
|
||||
U32 const stat = rawStat + 1;
|
||||
U32 const hb = ZSTD_highbit32(stat);
|
||||
U32 const BWeight = hb * fp_multiplier;
|
||||
U32 const FWeight = (stat << fp_accuracy) >> hb;
|
||||
U32 const weight = BWeight + FWeight;
|
||||
assert(hb + fp_accuracy < 31);
|
||||
return (double)weight / fp_multiplier;
|
||||
}
|
||||
|
||||
MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
|
||||
{
|
||||
unsigned u, sum;
|
||||
for (u=0, sum=0; u<=max; u++) sum += table[u];
|
||||
DEBUGLOG(2, "total nb elts: %u", sum);
|
||||
for (u=0; u<=max; u++) {
|
||||
DEBUGLOG(2, "%2u: %5u (%.2f)",
|
||||
u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) );
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -640,7 +723,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||
* ============================================================== */
|
||||
|
||||
/* ZSTD_getCParamsFromCCtxParams() :
|
||||
* cParams are built depending on compressionLevel, src size hints,
|
||||
* cParams are built depending on compressionLevel, src size hints,
|
||||
* LDM and manually set compression parameters.
|
||||
*/
|
||||
ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
||||
@@ -656,6 +739,8 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
|
||||
|
||||
void ZSTD_resetSeqStore(seqStore_t* ssPtr);
|
||||
|
||||
/*! ZSTD_compressStream_generic() :
|
||||
* Private use only. To be called from zstdmt_compress.c in single-thread mode. */
|
||||
size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
||||
@@ -672,6 +757,7 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
|
||||
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictContentType_e dictContentType,
|
||||
ZSTD_dictTableLoadMethod_e dtlm,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params params,
|
||||
unsigned long long pledgedSrcSize);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
void const* end)
|
||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm)
|
||||
{
|
||||
U32* const hashLarge = ms->hashTable;
|
||||
U32 const hBitsL = cParams->hashLog;
|
||||
@@ -40,6 +40,9 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
||||
hashSmall[smHash] = current + i;
|
||||
if (i == 0 || hashLarge[lgHash] == 0)
|
||||
hashLarge[lgHash] = current + i;
|
||||
/* Only load extra positions for ZSTD_dtlm_full */
|
||||
if (dtlm == ZSTD_dtlm_fast)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +52,7 @@ FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_doubleFast_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
|
||||
U32 const mls /* template */)
|
||||
U32 const mls /* template */, ZSTD_dictMode_e const dictMode)
|
||||
{
|
||||
U32* const hashLong = ms->hashTable;
|
||||
const U32 hBitsL = cParams->hashLog;
|
||||
@@ -59,70 +62,178 @@ size_t ZSTD_compressBlock_doubleFast_generic(
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ms->window.dictLimit;
|
||||
const BYTE* const lowest = base + lowestIndex;
|
||||
const U32 prefixLowestIndex = ms->window.dictLimit;
|
||||
const BYTE* const prefixLowest = base + prefixLowestIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
U32 offset_1=rep[0], offset_2=rep[1];
|
||||
U32 offsetSaved = 0;
|
||||
|
||||
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
||||
const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ?
|
||||
dms->hashTable : NULL;
|
||||
const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ?
|
||||
dms->chainTable : NULL;
|
||||
const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.dictLimit : 0;
|
||||
const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.base : NULL;
|
||||
const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
|
||||
dictBase + dictStartIndex : NULL;
|
||||
const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.nextSrc : NULL;
|
||||
const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
|
||||
prefixLowestIndex - (U32)(dictEnd - dictBase) :
|
||||
0;
|
||||
const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart);
|
||||
|
||||
assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
|
||||
|
||||
/* init */
|
||||
ip += (ip==lowest);
|
||||
{ U32 const maxRep = (U32)(ip-lowest);
|
||||
ip += (dictAndPrefixLength == 0);
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
U32 const maxRep = (U32)(ip - prefixLowest);
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
/* dictMatchState repCode checks don't currently handle repCode == 0
|
||||
* disabling. */
|
||||
assert(offset_1 <= dictAndPrefixLength);
|
||||
assert(offset_2 <= dictAndPrefixLength);
|
||||
}
|
||||
|
||||
/* Main Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||
size_t mLength;
|
||||
U32 offset;
|
||||
size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
|
||||
size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
|
||||
U32 const current = (U32)(ip-base);
|
||||
U32 const matchIndexL = hashLong[h2];
|
||||
U32 const matchIndexS = hashSmall[h];
|
||||
U32 matchIndexS = hashSmall[h];
|
||||
const BYTE* matchLong = base + matchIndexL;
|
||||
const BYTE* match = base + matchIndexS;
|
||||
const U32 repIndex = current + 1 - offset_1;
|
||||
const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
|
||||
&& repIndex < prefixLowestIndex) ?
|
||||
dictBase + (repIndex - dictIndexDelta) :
|
||||
base + repIndex;
|
||||
hashLong[h2] = hashSmall[h] = current; /* update hash tables */
|
||||
|
||||
assert(offset_1 <= current); /* supposed guaranteed by construction */
|
||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
||||
/* favor repcode */
|
||||
/* check dictMatchState repcode */
|
||||
if (dictMode == ZSTD_dictMatchState
|
||||
&& ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
goto _match_stored;
|
||||
}
|
||||
|
||||
/* check noDict repcode */
|
||||
if ( dictMode == ZSTD_noDict
|
||||
&& ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
|
||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
U32 offset;
|
||||
if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
|
||||
mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
|
||||
offset = (U32)(ip-matchLong);
|
||||
while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||
} else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
|
||||
size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||
U32 const matchIndexL3 = hashLong[hl3];
|
||||
const BYTE* matchL3 = base + matchIndexL3;
|
||||
hashLong[hl3] = current + 1;
|
||||
if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
|
||||
mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
|
||||
ip++;
|
||||
offset = (U32)(ip-matchL3);
|
||||
while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
|
||||
} else {
|
||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||
offset = (U32)(ip-match);
|
||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
}
|
||||
} else {
|
||||
ip += ((ip-anchor) >> kSearchStrength) + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
goto _match_stored;
|
||||
}
|
||||
|
||||
/* check prefix long match */
|
||||
if ( (matchIndexL > prefixLowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
|
||||
mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
|
||||
offset = (U32)(ip-matchLong);
|
||||
while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||
goto _match_found;
|
||||
}
|
||||
|
||||
/* check dictMatchState long match */
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
U32 const dictMatchIndexL = dictHashLong[h2];
|
||||
const BYTE* dictMatchL = dictBase + dictMatchIndexL;
|
||||
assert(dictMatchL < dictEnd);
|
||||
|
||||
if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
|
||||
mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
|
||||
offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
|
||||
while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
|
||||
goto _match_found;
|
||||
}
|
||||
}
|
||||
|
||||
/* check prefix short match */
|
||||
if ( (matchIndexS > prefixLowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
|
||||
goto _search_next_long;
|
||||
}
|
||||
|
||||
/* check dictMatchState short match */
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
U32 const dictMatchIndexS = dictHashSmall[h];
|
||||
match = dictBase + dictMatchIndexS;
|
||||
matchIndexS = dictMatchIndexS + dictIndexDelta;
|
||||
|
||||
if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
|
||||
goto _search_next_long;
|
||||
}
|
||||
}
|
||||
|
||||
ip += ((ip-anchor) >> kSearchStrength) + 1;
|
||||
continue;
|
||||
|
||||
_search_next_long:
|
||||
|
||||
{
|
||||
size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||
U32 const matchIndexL3 = hashLong[hl3];
|
||||
const BYTE* matchL3 = base + matchIndexL3;
|
||||
hashLong[hl3] = current + 1;
|
||||
|
||||
/* check prefix long +1 match */
|
||||
if ( (matchIndexL3 > prefixLowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
|
||||
mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
|
||||
ip++;
|
||||
offset = (U32)(ip-matchL3);
|
||||
while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
|
||||
goto _match_found;
|
||||
}
|
||||
|
||||
/* check dict long +1 match */
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
U32 const dictMatchIndexL3 = dictHashLong[hl3];
|
||||
const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
|
||||
assert(dictMatchL3 < dictEnd);
|
||||
if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
|
||||
mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
|
||||
ip++;
|
||||
offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
|
||||
while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
|
||||
goto _match_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if no long +1 match, explore the short match we found */
|
||||
if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
|
||||
offset = (U32)(current - matchIndexS);
|
||||
while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
} else {
|
||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||
offset = (U32)(ip - match);
|
||||
while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
}
|
||||
|
||||
/* fall-through */
|
||||
|
||||
_match_found:
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
|
||||
_match_stored:
|
||||
/* match found */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
@@ -135,19 +246,44 @@ size_t ZSTD_compressBlock_doubleFast_generic(
|
||||
hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
|
||||
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
{ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } }
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState
|
||||
&& repIndex2 < prefixLowestIndex ?
|
||||
dictBase - dictIndexDelta + repIndex2 :
|
||||
base + repIndex2;
|
||||
if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
|
||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
||||
ip += repLength2;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } } }
|
||||
|
||||
/* save reps for next block */
|
||||
rep[0] = offset_1 ? offset_1 : offsetSaved;
|
||||
@@ -167,13 +303,33 @@ size_t ZSTD_compressBlock_doubleFast(
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4);
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4, ZSTD_noDict);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5);
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5, ZSTD_noDict);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6);
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6, ZSTD_noDict);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7);
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7, ZSTD_noDict);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_doubleFast_dictMatchState(
|
||||
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 = cParams->searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4, ZSTD_dictMatchState);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5, ZSTD_dictMatchState);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6, ZSTD_dictMatchState);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7, ZSTD_dictMatchState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,75 +343,78 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||
U32 const hBitsL = cParams->hashLog;
|
||||
U32* const hashSmall = ms->chainTable;
|
||||
U32 const hBitsS = cParams->chainLog;
|
||||
const BYTE* const base = ms->window.base;
|
||||
const BYTE* const dictBase = ms->window.dictBase;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ms->window.lowLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const U32 dictLimit = ms->window.dictLimit;
|
||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const U32 prefixStartIndex = ms->window.dictLimit;
|
||||
const BYTE* const base = ms->window.base;
|
||||
const BYTE* const prefixStart = base + prefixStartIndex;
|
||||
const U32 dictStartIndex = ms->window.lowLimit;
|
||||
const BYTE* const dictBase = ms->window.dictBase;
|
||||
const BYTE* const dictStart = dictBase + dictStartIndex;
|
||||
const BYTE* const dictEnd = dictBase + prefixStartIndex;
|
||||
U32 offset_1=rep[0], offset_2=rep[1];
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
|
||||
|
||||
/* Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||
const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
|
||||
const U32 matchIndex = hashSmall[hSmall];
|
||||
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
|
||||
const BYTE* match = matchBase + matchIndex;
|
||||
|
||||
const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
|
||||
const U32 matchLongIndex = hashLong[hLong];
|
||||
const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
|
||||
const BYTE* matchLong = matchLongBase + matchLongIndex;
|
||||
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
|
||||
const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* repMatch = repBase + repIndex;
|
||||
const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
size_t mLength;
|
||||
hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
|
||||
|
||||
if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||
if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
|
||||
& (repIndex > dictStartIndex))
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
||||
const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
||||
const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
|
||||
const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
|
||||
U32 offset;
|
||||
mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
|
||||
mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
|
||||
offset = current - matchLongIndex;
|
||||
while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
|
||||
} else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
|
||||
} else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
|
||||
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||
U32 const matchIndex3 = hashLong[h3];
|
||||
const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
|
||||
const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
|
||||
const BYTE* match3 = match3Base + matchIndex3;
|
||||
U32 offset;
|
||||
hashLong[h3] = current + 1;
|
||||
if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
|
||||
const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
|
||||
mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
|
||||
if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
|
||||
const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
|
||||
const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
|
||||
mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
|
||||
ip++;
|
||||
offset = current+1 - matchIndex3;
|
||||
while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
|
||||
} else {
|
||||
const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
|
||||
const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
|
||||
const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
|
||||
offset = current - matchIndex;
|
||||
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
}
|
||||
@@ -282,12 +441,13 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
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 = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
|
||||
& (repIndex2 > dictStartIndex))
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
|
||||
U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
||||
|
||||
@@ -20,10 +20,13 @@ extern "C" {
|
||||
|
||||
void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
void const* end);
|
||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm);
|
||||
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_dictMatchState(
|
||||
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);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
void const* end)
|
||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm)
|
||||
{
|
||||
U32* const hashTable = ms->hashTable;
|
||||
U32 const hBits = cParams->hashLog;
|
||||
@@ -34,6 +34,9 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
|
||||
size_t const hash = ZSTD_hashPtr(ip + i, hBits, mls);
|
||||
if (i == 0 || hashTable[hash] == 0)
|
||||
hashTable[hash] = current + i;
|
||||
/* Only load extra positions for ZSTD_dtlm_full */
|
||||
if (dtlm == ZSTD_dtlm_fast)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,26 +45,58 @@ FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_fast_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize,
|
||||
U32 const hlog, U32 const stepSize, U32 const mls)
|
||||
U32 const hlog, U32 stepSize, U32 const mls,
|
||||
ZSTD_dictMode_e const dictMode)
|
||||
{
|
||||
U32* const hashTable = ms->hashTable;
|
||||
const BYTE* const base = ms->window.base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ms->window.dictLimit;
|
||||
const BYTE* const lowest = base + lowestIndex;
|
||||
const U32 prefixStartIndex = ms->window.dictLimit;
|
||||
const BYTE* const prefixStart = base + prefixStartIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
U32 offset_1=rep[0], offset_2=rep[1];
|
||||
U32 offsetSaved = 0;
|
||||
|
||||
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
||||
const U32* const dictHashTable = dictMode == ZSTD_dictMatchState ?
|
||||
dms->hashTable : NULL;
|
||||
const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.dictLimit : 0;
|
||||
const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.base : NULL;
|
||||
const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
|
||||
dictBase + dictStartIndex : NULL;
|
||||
const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.nextSrc : NULL;
|
||||
const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
|
||||
prefixStartIndex - (U32)(dictEnd - dictBase) :
|
||||
0;
|
||||
const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart);
|
||||
|
||||
assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
|
||||
|
||||
/* otherwise, we would get index underflow when translating a dict index
|
||||
* into a local index */
|
||||
assert(dictMode != ZSTD_dictMatchState
|
||||
|| prefixStartIndex >= (U32)(dictEnd - dictBase));
|
||||
|
||||
/* init */
|
||||
ip += (ip==lowest);
|
||||
{ U32 const maxRep = (U32)(ip-lowest);
|
||||
stepSize += !stepSize; /* support stepSize of 0 */
|
||||
ip += (dictAndPrefixLength == 0);
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
U32 const maxRep = (U32)(ip - prefixStart);
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
/* dictMatchState repCode checks don't currently handle repCode == 0
|
||||
* disabling. */
|
||||
assert(offset_1 <= dictAndPrefixLength);
|
||||
assert(offset_2 <= dictAndPrefixLength);
|
||||
}
|
||||
|
||||
/* Main Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||
@@ -70,26 +105,62 @@ size_t ZSTD_compressBlock_fast_generic(
|
||||
U32 const current = (U32)(ip-base);
|
||||
U32 const matchIndex = hashTable[h];
|
||||
const BYTE* match = base + matchIndex;
|
||||
const U32 repIndex = current + 1 - offset_1;
|
||||
const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
|
||||
&& repIndex < prefixStartIndex) ?
|
||||
dictBase + (repIndex - dictIndexDelta) :
|
||||
base + repIndex;
|
||||
hashTable[h] = current; /* update hash table */
|
||||
|
||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
||||
if ( (dictMode == ZSTD_dictMatchState)
|
||||
&& ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else if ( dictMode == ZSTD_noDict
|
||||
&& ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
|
||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
if ( (matchIndex <= lowestIndex)
|
||||
|| (MEM_read32(match) != MEM_read32(ip)) ) {
|
||||
} else if ( (matchIndex <= prefixStartIndex)
|
||||
|| (MEM_read32(match) != MEM_read32(ip)) ) {
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
U32 const dictMatchIndex = dictHashTable[h];
|
||||
const BYTE* dictMatch = dictBase + dictMatchIndex;
|
||||
if (dictMatchIndex <= dictStartIndex ||
|
||||
MEM_read32(dictMatch) != MEM_read32(ip)) {
|
||||
assert(stepSize >= 1);
|
||||
ip += ((ip-anchor) >> kSearchStrength) + stepSize;
|
||||
continue;
|
||||
} else {
|
||||
/* found a dict match */
|
||||
U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
|
||||
mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
|
||||
while (((ip>anchor) & (dictMatch>dictStart))
|
||||
&& (ip[-1] == dictMatch[-1])) {
|
||||
ip--; dictMatch--; mLength++;
|
||||
} /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
}
|
||||
} else {
|
||||
assert(stepSize >= 1);
|
||||
ip += ((ip-anchor) >> kSearchStrength) + stepSize;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* found a regular match */
|
||||
U32 const offset = (U32)(ip-match);
|
||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||
{ U32 const offset = (U32)(ip-match);
|
||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
} }
|
||||
while (((ip>anchor) & (match>prefixStart))
|
||||
&& (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
}
|
||||
|
||||
/* match found */
|
||||
ip += mLength;
|
||||
@@ -99,19 +170,43 @@ size_t ZSTD_compressBlock_fast_generic(
|
||||
/* Fill Table */
|
||||
hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */
|
||||
hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
|
||||
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
{ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
|
||||
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } }
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
const BYTE* repMatch2 = repIndex2 < prefixStartIndex ?
|
||||
dictBase - dictIndexDelta + repIndex2 :
|
||||
base + repIndex2;
|
||||
if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
|
||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
|
||||
ip += repLength2;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
|
||||
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } } }
|
||||
|
||||
/* save reps for next block */
|
||||
rep[0] = offset_1 ? offset_1 : offsetSaved;
|
||||
@@ -129,17 +224,40 @@ size_t ZSTD_compressBlock_fast(
|
||||
U32 const hlog = cParams->hashLog;
|
||||
U32 const mls = cParams->searchLength;
|
||||
U32 const stepSize = cParams->targetLength;
|
||||
assert(ms->dictMatchState == NULL);
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4);
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4, ZSTD_noDict);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5);
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5, ZSTD_noDict);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6);
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6, ZSTD_noDict);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7);
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7, ZSTD_noDict);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_fast_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
|
||||
{
|
||||
U32 const hlog = cParams->hashLog;
|
||||
U32 const mls = cParams->searchLength;
|
||||
U32 const stepSize = cParams->targetLength;
|
||||
assert(ms->dictMatchState != NULL);
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4, ZSTD_dictMatchState);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5, ZSTD_dictMatchState);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6, ZSTD_dictMatchState);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7, ZSTD_dictMatchState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +265,7 @@ size_t ZSTD_compressBlock_fast(
|
||||
static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize,
|
||||
U32 const hlog, U32 const stepSize, U32 const mls)
|
||||
U32 const hlog, U32 stepSize, U32 const mls)
|
||||
{
|
||||
U32* hashTable = ms->hashTable;
|
||||
const BYTE* const base = ms->window.base;
|
||||
@@ -155,45 +273,48 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ms->window.lowLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const U32 dictLimit = ms->window.dictLimit;
|
||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const U32 dictStartIndex = ms->window.lowLimit;
|
||||
const BYTE* const dictStart = dictBase + dictStartIndex;
|
||||
const U32 prefixStartIndex = ms->window.dictLimit;
|
||||
const BYTE* const prefixStart = base + prefixStartIndex;
|
||||
const BYTE* const dictEnd = dictBase + prefixStartIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
U32 offset_1=rep[0], offset_2=rep[1];
|
||||
|
||||
stepSize += !stepSize; /* support stepSize == 0 */
|
||||
|
||||
/* Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||
const size_t h = ZSTD_hashPtr(ip, hlog, mls);
|
||||
const U32 matchIndex = hashTable[h];
|
||||
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* match = matchBase + matchIndex;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
|
||||
const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* repMatch = repBase + repIndex;
|
||||
const U32 matchIndex = hashTable[h];
|
||||
const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
|
||||
const BYTE* match = matchBase + matchIndex;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 repIndex = current + 1 - offset_1;
|
||||
const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
size_t mLength;
|
||||
hashTable[h] = current; /* update hash table */
|
||||
assert(offset_1 <= current +1); /* check repIndex */
|
||||
|
||||
if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
|
||||
if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||
const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
if ( (matchIndex < lowestIndex) ||
|
||||
if ( (matchIndex < dictStartIndex) ||
|
||||
(MEM_read32(match) != MEM_read32(ip)) ) {
|
||||
assert(stepSize >= 1);
|
||||
ip += ((ip-anchor) >> kSearchStrength) + stepSize;
|
||||
continue;
|
||||
}
|
||||
{ const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
{ const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
|
||||
U32 offset;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
|
||||
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
offset = current - matchIndex;
|
||||
offset_2 = offset_1;
|
||||
@@ -213,11 +334,11 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
|
||||
const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
|
||||
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
|
||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
|
||||
|
||||
@@ -20,10 +20,13 @@ extern "C" {
|
||||
|
||||
void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
void const* end);
|
||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm);
|
||||
size_t ZSTD_compressBlock_fast(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_fast_dictMatchState(
|
||||
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);
|
||||
|
||||
@@ -62,7 +62,7 @@ void ZSTD_updateDUBT(
|
||||
static void ZSTD_insertDUBT1(
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
U32 current, const BYTE* inputEnd,
|
||||
U32 nbCompares, U32 btLow, int extDict)
|
||||
U32 nbCompares, U32 btLow, const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
U32* const bt = ms->chainTable;
|
||||
U32 const btLog = cParams->chainLog - 1;
|
||||
@@ -92,10 +92,12 @@ static void ZSTD_insertDUBT1(
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
assert(matchIndex < current);
|
||||
|
||||
if ( (!extDict)
|
||||
if ( (dictMode != ZSTD_extDict)
|
||||
|| (matchIndex+matchLength >= dictLimit) /* both in current segment*/
|
||||
|| (current < dictLimit) /* both in extDict */) {
|
||||
const BYTE* const mBase = !extDict || ((matchIndex+matchLength) >= dictLimit) ? base : dictBase;
|
||||
const BYTE* const mBase = ( (dictMode != ZSTD_extDict)
|
||||
|| (matchIndex+matchLength >= dictLimit)) ?
|
||||
base : dictBase;
|
||||
assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */
|
||||
|| (current < dictLimit) );
|
||||
match = mBase + matchIndex;
|
||||
@@ -138,12 +140,90 @@ static void ZSTD_insertDUBT1(
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_DUBT_findBetterDictMatch (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
size_t* offsetPtr,
|
||||
size_t bestLength,
|
||||
U32 nbCompares,
|
||||
U32 const mls,
|
||||
const ZSTD_dictMode_e dictMode) {
|
||||
const ZSTD_matchState_t * const dms = ms->dictMatchState;
|
||||
const U32 * const dictHashTable = dms->hashTable;
|
||||
U32 const hashLog = cParams->hashLog;
|
||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||
U32 dictMatchIndex = dictHashTable[h];
|
||||
|
||||
const BYTE* const base = ms->window.base;
|
||||
const BYTE* const prefixStart = base + ms->window.dictLimit;
|
||||
U32 const current = (U32)(ip-base);
|
||||
const BYTE* const dictBase = dms->window.base;
|
||||
const BYTE* const dictEnd = dms->window.nextSrc;
|
||||
U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base);
|
||||
U32 const dictLowLimit = dms->window.lowLimit;
|
||||
U32 const dictIndexDelta = ms->window.lowLimit - dictHighLimit;
|
||||
|
||||
U32* const dictBt = dms->chainTable;
|
||||
U32 const btLog = cParams->chainLog - 1;
|
||||
U32 const btMask = (1 << btLog) - 1;
|
||||
U32 const btLow = (btMask >= dictHighLimit - dictLowLimit) ? dictLowLimit : dictHighLimit - btMask;
|
||||
|
||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||
U32 matchEndIdx = current+8+1;
|
||||
|
||||
(void)dictMode;
|
||||
assert(dictMode == ZSTD_dictMatchState);
|
||||
|
||||
while (nbCompares-- && (dictMatchIndex > dictLowLimit)) {
|
||||
U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match = dictBase + dictMatchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
|
||||
if (dictMatchIndex+matchLength >= dictHighLimit)
|
||||
match = base + dictMatchIndex + dictIndexDelta; /* to prepare for next usage of match[matchLength] */
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
U32 matchIndex = dictMatchIndex + dictIndexDelta;
|
||||
if (matchLength > matchEndIdx - matchIndex)
|
||||
matchEndIdx = matchIndex + (U32)matchLength;
|
||||
if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) {
|
||||
DEBUGLOG(9, "ZSTD_DUBT_findBestDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)",
|
||||
current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex);
|
||||
bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
|
||||
}
|
||||
if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
|
||||
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
||||
}
|
||||
}
|
||||
|
||||
if (match[matchLength] < ip[matchLength]) {
|
||||
if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
|
||||
commonLengthLarger = matchLength;
|
||||
dictMatchIndex = nextPtr[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (bestLength >= MINMATCH) {
|
||||
U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
|
||||
DEBUGLOG(8, "ZSTD_DUBT_findBestDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
|
||||
current, (U32)bestLength, (U32)*offsetPtr, mIndex);
|
||||
}
|
||||
return bestLength;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_DUBT_findBestMatch (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
size_t* offsetPtr,
|
||||
U32 const mls,
|
||||
U32 const extDict)
|
||||
const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
U32* const hashTable = ms->hashTable;
|
||||
U32 const hashLog = cParams->hashLog;
|
||||
@@ -196,7 +276,7 @@ static size_t ZSTD_DUBT_findBestMatch (
|
||||
U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
|
||||
U32 const nextCandidateIdx = *nextCandidateIdxPtr;
|
||||
ZSTD_insertDUBT1(ms, cParams, matchIndex, iend,
|
||||
nbCandidates, unsortLimit, extDict);
|
||||
nbCandidates, unsortLimit, dictMode);
|
||||
matchIndex = nextCandidateIdx;
|
||||
nbCandidates++;
|
||||
}
|
||||
@@ -221,7 +301,7 @@ static size_t ZSTD_DUBT_findBestMatch (
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match;
|
||||
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
if ((dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
match = base + matchIndex;
|
||||
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
|
||||
} else {
|
||||
@@ -259,6 +339,10 @@ static size_t ZSTD_DUBT_findBestMatch (
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
|
||||
if (dictMode == ZSTD_dictMatchState && nbCompares) {
|
||||
bestLength = ZSTD_DUBT_findBetterDictMatch(ms, cParams, ip, iend, offsetPtr, bestLength, nbCompares, mls, dictMode);
|
||||
}
|
||||
|
||||
assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
|
||||
ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
|
||||
if (bestLength >= MINMATCH) {
|
||||
@@ -272,16 +356,17 @@ static size_t ZSTD_DUBT_findBestMatch (
|
||||
|
||||
|
||||
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
|
||||
static size_t ZSTD_BtFindBestMatch (
|
||||
FORCE_INLINE_TEMPLATE size_t ZSTD_BtFindBestMatch (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 mls /* template */)
|
||||
const U32 mls /* template */,
|
||||
const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
DEBUGLOG(7, "ZSTD_BtFindBestMatch");
|
||||
if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateDUBT(ms, cParams, ip, iLimit, mls);
|
||||
return ZSTD_DUBT_findBestMatch(ms, cParams, ip, iLimit, offsetPtr, mls, 0);
|
||||
return ZSTD_DUBT_findBestMatch(ms, cParams, ip, iLimit, offsetPtr, mls, dictMode);
|
||||
}
|
||||
|
||||
|
||||
@@ -293,29 +378,15 @@ static size_t ZSTD_BtFindBestMatch_selectMLS (
|
||||
switch(cParams->searchLength)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 4);
|
||||
case 5 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 5);
|
||||
case 4 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
|
||||
case 5 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 6);
|
||||
case 6 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Tree updater, providing best match */
|
||||
static size_t ZSTD_BtFindBestMatch_extDict (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 mls)
|
||||
{
|
||||
DEBUGLOG(7, "ZSTD_BtFindBestMatch_extDict");
|
||||
if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateDUBT(ms, cParams, ip, iLimit, mls);
|
||||
return ZSTD_DUBT_findBestMatch(ms, cParams, ip, iLimit, offsetPtr, mls, 1);
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
|
||||
static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr)
|
||||
@@ -323,10 +394,26 @@ static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
|
||||
switch(cParams->searchLength)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 4);
|
||||
case 5 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 5);
|
||||
case 4 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
|
||||
case 5 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtFindBestMatch_extDict(ms, cParams, ip, iLimit, offsetPtr, 6);
|
||||
case 6 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr)
|
||||
{
|
||||
switch(cParams->searchLength)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
|
||||
case 5 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtFindBestMatch(ms, cParams, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +463,7 @@ size_t ZSTD_HcFindBestMatch_generic (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 mls, const U32 extDict)
|
||||
const U32 mls, const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
U32* const chainTable = ms->chainTable;
|
||||
const U32 chainSize = (1 << cParams->chainLog);
|
||||
@@ -397,7 +484,7 @@ size_t ZSTD_HcFindBestMatch_generic (
|
||||
|
||||
for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
|
||||
size_t currentMl=0;
|
||||
if ((!extDict) || matchIndex >= dictLimit) {
|
||||
if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
|
||||
const BYTE* const match = base + matchIndex;
|
||||
if (match[ml] == ip[ml]) /* potentially better */
|
||||
currentMl = ZSTD_count(ip, match, iLimit);
|
||||
@@ -419,6 +506,37 @@ size_t ZSTD_HcFindBestMatch_generic (
|
||||
matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
|
||||
}
|
||||
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
||||
const U32* const dmsChainTable = dms->chainTable;
|
||||
const U32 dmsLowestIndex = dms->window.dictLimit;
|
||||
const BYTE* const dmsBase = dms->window.base;
|
||||
const BYTE* const dmsEnd = dms->window.nextSrc;
|
||||
const U32 dmsSize = (U32)(dmsEnd - dmsBase);
|
||||
const U32 dmsIndexDelta = dictLimit - dmsSize;
|
||||
const U32 dmsMinChain = dmsSize > chainSize ? dmsSize - chainSize : 0;
|
||||
|
||||
matchIndex = dms->hashTable[ZSTD_hashPtr(ip, cParams->hashLog, mls)];
|
||||
|
||||
for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) {
|
||||
size_t currentMl=0;
|
||||
const BYTE* const match = dmsBase + matchIndex;
|
||||
assert(match+4 <= dmsEnd);
|
||||
if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
|
||||
currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4;
|
||||
|
||||
/* save best solution */
|
||||
if (currentMl > ml) {
|
||||
ml = currentMl;
|
||||
*offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
|
||||
if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
|
||||
}
|
||||
|
||||
if (matchIndex <= dmsMinChain) break;
|
||||
matchIndex = dmsChainTable[matchIndex & chainMask];
|
||||
}
|
||||
}
|
||||
|
||||
return ml;
|
||||
}
|
||||
|
||||
@@ -431,10 +549,26 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
|
||||
switch(cParams->searchLength)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, 0);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, 0);
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 6, 0);
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr)
|
||||
{
|
||||
switch(cParams->searchLength)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,15 +576,15 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
|
||||
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* const offsetPtr)
|
||||
size_t* offsetPtr)
|
||||
{
|
||||
switch(cParams->searchLength)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, 1);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, 1);
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 6, 1);
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(ms, cParams, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,28 +598,56 @@ size_t ZSTD_compressBlock_lazy_generic(
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 searchMethod, const U32 depth)
|
||||
const U32 searchMethod, const U32 depth,
|
||||
ZSTD_dictMode_e const dictMode)
|
||||
{
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ms->window.base + ms->window.dictLimit;
|
||||
const BYTE* const base = ms->window.base;
|
||||
const U32 prefixLowestIndex = ms->window.dictLimit;
|
||||
const BYTE* const prefixLowest = base + prefixLowestIndex;
|
||||
|
||||
typedef size_t (*searchMax_f)(
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
||||
searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
|
||||
searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
|
||||
(searchMethod ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
|
||||
(searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS);
|
||||
U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
|
||||
|
||||
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
||||
const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.dictLimit : 0;
|
||||
const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.base : NULL;
|
||||
const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ?
|
||||
dictBase + dictLowestIndex : NULL;
|
||||
const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
|
||||
dms->window.nextSrc : NULL;
|
||||
const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
|
||||
prefixLowestIndex - (U32)(dictEnd - dictBase) :
|
||||
0;
|
||||
const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictLowest);
|
||||
|
||||
(void)dictMode;
|
||||
|
||||
/* init */
|
||||
ip += (ip==base);
|
||||
ip += (dictAndPrefixLength == 0);
|
||||
ms->nextToUpdate3 = ms->nextToUpdate;
|
||||
{ U32 const maxRep = (U32)(ip-base);
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
U32 const maxRep = (U32)(ip - prefixLowest);
|
||||
if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
|
||||
}
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
/* dictMatchState repCode checks don't currently handle repCode == 0
|
||||
* disabling. */
|
||||
assert(offset_1 <= dictAndPrefixLength);
|
||||
assert(offset_2 <= dictAndPrefixLength);
|
||||
}
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
@@ -494,8 +656,21 @@ size_t ZSTD_compressBlock_lazy_generic(
|
||||
const BYTE* start=ip+1;
|
||||
|
||||
/* check repCode */
|
||||
if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
|
||||
/* repcode : we take it */
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
const U32 repIndex = (U32)(ip - base) + 1 - offset_1;
|
||||
const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
|
||||
&& repIndex < prefixLowestIndex) ?
|
||||
dictBase + (repIndex - dictIndexDelta) :
|
||||
base + repIndex;
|
||||
if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
|
||||
matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
|
||||
if (depth==0) goto _storeSequence;
|
||||
}
|
||||
}
|
||||
if ( dictMode == ZSTD_noDict
|
||||
&& ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
|
||||
matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
if (depth==0) goto _storeSequence;
|
||||
}
|
||||
@@ -516,13 +691,29 @@ size_t ZSTD_compressBlock_lazy_generic(
|
||||
if (depth>=1)
|
||||
while (ip<ilimit) {
|
||||
ip ++;
|
||||
if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
if ( (dictMode == ZSTD_noDict)
|
||||
&& (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
|
||||
int const gain2 = (int)(mlRep * 3);
|
||||
int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((mlRep >= 4) && (gain2 > gain1))
|
||||
matchLength = mlRep, offset = 0, start = ip;
|
||||
}
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
const U32 repIndex = (U32)(ip - base) - offset_1;
|
||||
const BYTE* repMatch = repIndex < prefixLowestIndex ?
|
||||
dictBase + (repIndex - dictIndexDelta) :
|
||||
base + repIndex;
|
||||
if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
|
||||
size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
|
||||
int const gain2 = (int)(mlRep * 3);
|
||||
int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((mlRep >= 4) && (gain2 > gain1))
|
||||
matchLength = mlRep, offset = 0, start = ip;
|
||||
}
|
||||
}
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ms, cParams, ip, iend, &offset2);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
@@ -535,12 +726,28 @@ size_t ZSTD_compressBlock_lazy_generic(
|
||||
/* let's find an even better one */
|
||||
if ((depth==2) && (ip<ilimit)) {
|
||||
ip ++;
|
||||
if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
|
||||
int const gain2 = (int)(ml2 * 4);
|
||||
if ( (dictMode == ZSTD_noDict)
|
||||
&& (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
|
||||
int const gain2 = (int)(mlRep * 4);
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((ml2 >= 4) && (gain2 > gain1))
|
||||
matchLength = ml2, offset = 0, start = ip;
|
||||
if ((mlRep >= 4) && (gain2 > gain1))
|
||||
matchLength = mlRep, offset = 0, start = ip;
|
||||
}
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
const U32 repIndex = (U32)(ip - base) - offset_1;
|
||||
const BYTE* repMatch = repIndex < prefixLowestIndex ?
|
||||
dictBase + (repIndex - dictIndexDelta) :
|
||||
base + repIndex;
|
||||
if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
|
||||
size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
|
||||
int const gain2 = (int)(mlRep * 4);
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((mlRep >= 4) && (gain2 > gain1))
|
||||
matchLength = mlRep, offset = 0, start = ip;
|
||||
}
|
||||
}
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ms, cParams, ip, iend, &offset2);
|
||||
@@ -560,9 +767,17 @@ size_t ZSTD_compressBlock_lazy_generic(
|
||||
*/
|
||||
/* catch up */
|
||||
if (offset) {
|
||||
while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > base))
|
||||
&& (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */
|
||||
{ start--; matchLength++; }
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest))
|
||||
&& (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */
|
||||
{ start--; matchLength++; }
|
||||
}
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
|
||||
const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex;
|
||||
const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest;
|
||||
while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
|
||||
}
|
||||
offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
|
||||
}
|
||||
/* store sequence */
|
||||
@@ -573,16 +788,39 @@ _storeSequence:
|
||||
}
|
||||
|
||||
/* check immediate repcode */
|
||||
while ( ((ip <= ilimit) & (offset_2>0))
|
||||
&& (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
|
||||
/* store sequence */
|
||||
matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
|
||||
ip += matchLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} }
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex = current2 - offset_2;
|
||||
const BYTE* repMatch = dictMode == ZSTD_dictMatchState
|
||||
&& repIndex < prefixLowestIndex ?
|
||||
dictBase - dictIndexDelta + repIndex :
|
||||
base + repIndex;
|
||||
if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */)
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend;
|
||||
matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4;
|
||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
|
||||
ip += matchLength;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
while ( ((ip <= ilimit) & (offset_2>0))
|
||||
&& (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
|
||||
/* store sequence */
|
||||
matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
|
||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
|
||||
ip += matchLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } }
|
||||
|
||||
/* Save reps for next block */
|
||||
rep[0] = offset_1 ? offset_1 : savedOffset;
|
||||
@@ -597,28 +835,56 @@ 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(ms, seqStore, rep, cParams, src, srcSize, 1, 2);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 1, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
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(ms, seqStore, rep, cParams, src, srcSize, 0, 2);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
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(ms, seqStore, rep, cParams, src, srcSize, 0, 1);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 1, ZSTD_noDict);
|
||||
}
|
||||
|
||||
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(ms, seqStore, rep, cParams, src, srcSize, 0, 0);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, cParams, src, srcSize, 0, 0, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
||||
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(ms, seqStore, rep, cParams, src, srcSize, 1, 2, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
||||
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(ms, seqStore, rep, cParams, src, srcSize, 0, 2, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
||||
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(ms, seqStore, rep, cParams, src, srcSize, 0, 1, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_dictMatchState(
|
||||
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(ms, seqStore, rep, cParams, src, srcSize, 0, 0, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
|
||||
@@ -646,7 +912,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
typedef size_t (*searchMax_f)(
|
||||
ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
|
||||
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
||||
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
|
||||
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
|
||||
|
||||
U32 offset_1 = rep[0], offset_2 = rep[1];
|
||||
|
||||
|
||||
@@ -36,6 +36,19 @@ 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_btlazy2_dictMatchState(
|
||||
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_dictMatchState(
|
||||
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_dictMatchState(
|
||||
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_dictMatchState(
|
||||
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);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "zstd_ldm.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "zstd_fast.h" /* ZSTD_fillHashTable() */
|
||||
#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
|
||||
|
||||
@@ -20,7 +21,7 @@
|
||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
||||
ZSTD_compressionParameters const* cParams)
|
||||
{
|
||||
U32 const windowLog = cParams->windowLog;
|
||||
params->windowLog = cParams->windowLog;
|
||||
ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
|
||||
DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
|
||||
if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
|
||||
@@ -33,12 +34,13 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
||||
params->minMatchLength = minMatch;
|
||||
}
|
||||
if (params->hashLog == 0) {
|
||||
params->hashLog = MAX(ZSTD_HASHLOG_MIN, windowLog - LDM_HASH_RLOG);
|
||||
params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
|
||||
assert(params->hashLog <= ZSTD_HASHLOG_MAX);
|
||||
}
|
||||
if (params->hashEveryLog == 0) {
|
||||
params->hashEveryLog =
|
||||
windowLog < params->hashLog ? 0 : windowLog - params->hashLog;
|
||||
params->hashEveryLog = params->windowLog < params->hashLog
|
||||
? 0
|
||||
: params->windowLog - params->hashLog;
|
||||
}
|
||||
params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
|
||||
}
|
||||
@@ -224,13 +226,11 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
|
||||
switch(cParams->strategy)
|
||||
{
|
||||
case ZSTD_fast:
|
||||
ZSTD_fillHashTable(ms, cParams, iend);
|
||||
ms->nextToUpdate = (U32)(iend - ms->window.base);
|
||||
ZSTD_fillHashTable(ms, cParams, iend, ZSTD_dtlm_fast);
|
||||
break;
|
||||
|
||||
case ZSTD_dfast:
|
||||
ZSTD_fillDoubleHashTable(ms, cParams, iend);
|
||||
ms->nextToUpdate = (U32)(iend - ms->window.base);
|
||||
ZSTD_fillDoubleHashTable(ms, cParams, iend, ZSTD_dtlm_fast);
|
||||
break;
|
||||
|
||||
case ZSTD_greedy:
|
||||
@@ -508,7 +508,7 @@ size_t ZSTD_ldm_generateSequences(
|
||||
* * Try invalidation after the sequence generation and test the
|
||||
* the offset against maxDist directly.
|
||||
*/
|
||||
ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL);
|
||||
ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL, NULL);
|
||||
/* 3. Generate the sequences for the chunk, and get newLeftoverSize. */
|
||||
newLeftoverSize = ZSTD_ldm_generateSequences_internal(
|
||||
ldmState, sequences, params, chunkStart, chunkSize);
|
||||
@@ -591,19 +591,18 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
|
||||
|
||||
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_compressionParameters const* cParams, void const* src, size_t srcSize)
|
||||
{
|
||||
unsigned const minMatch = cParams->searchLength;
|
||||
ZSTD_blockCompressor const blockCompressor =
|
||||
ZSTD_selectBlockCompressor(cParams->strategy, extDict);
|
||||
BYTE const* const base = ms->window.base;
|
||||
ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
|
||||
/* Input bounds */
|
||||
BYTE const* const istart = (BYTE const*)src;
|
||||
BYTE const* const iend = istart + srcSize;
|
||||
/* Input positions */
|
||||
BYTE const* ip = istart;
|
||||
|
||||
DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
|
||||
assert(rawSeqStore->pos <= rawSeqStore->size);
|
||||
assert(rawSeqStore->size <= rawSeqStore->capacity);
|
||||
/* Loop through each sequence and apply the block compressor to the lits */
|
||||
@@ -623,12 +622,12 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||
ZSTD_ldm_limitTableUpdate(ms, ip);
|
||||
ZSTD_ldm_fillFastTables(ms, cParams, ip);
|
||||
/* Run the block compressor */
|
||||
DEBUGLOG(5, "calling block compressor on segment of size %u", sequence.litLength);
|
||||
{
|
||||
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];
|
||||
@@ -644,10 +643,6 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||
ZSTD_ldm_limitTableUpdate(ms, ip);
|
||||
ZSTD_ldm_fillFastTables(ms, cParams, ip);
|
||||
/* Compress the last literals */
|
||||
{
|
||||
size_t const lastLiterals = blockCompressor(ms, seqStore, rep, cParams,
|
||||
ip, iend - ip);
|
||||
ms->nextToUpdate = (U32)(iend - base);
|
||||
return lastLiterals;
|
||||
}
|
||||
return blockCompressor(ms, seqStore, rep, cParams,
|
||||
ip, iend - ip);
|
||||
}
|
||||
|
||||
@@ -62,8 +62,7 @@ size_t ZSTD_ldm_generateSequences(
|
||||
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
void const* src, size_t srcSize,
|
||||
int const extDict);
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
/**
|
||||
* ZSTD_ldm_skipSequences():
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
*/
|
||||
|
||||
#include "zstd_compress_internal.h"
|
||||
#include "hist.h"
|
||||
#include "zstd_opt.h"
|
||||
|
||||
|
||||
#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 */
|
||||
#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */
|
||||
#define ZSTD_MAX_PRICE (1<<30)
|
||||
|
||||
@@ -20,128 +21,210 @@
|
||||
/*-*************************************
|
||||
* Price functions for optimal parser
|
||||
***************************************/
|
||||
static void ZSTD_setLog2Prices(optState_t* optPtr)
|
||||
|
||||
#if 0 /* approximation at bit level */
|
||||
# define BITCOST_ACCURACY 0
|
||||
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
|
||||
# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat))
|
||||
#elif 0 /* fractional bit accuracy */
|
||||
# define BITCOST_ACCURACY 8
|
||||
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
|
||||
# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat))
|
||||
#else /* opt==approx, ultra==accurate */
|
||||
# define BITCOST_ACCURACY 8
|
||||
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
|
||||
# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
|
||||
#endif
|
||||
|
||||
MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
|
||||
{
|
||||
optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
|
||||
optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
|
||||
optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
|
||||
optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
|
||||
return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
|
||||
}
|
||||
|
||||
MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
|
||||
{
|
||||
U32 const stat = rawStat + 1;
|
||||
U32 const hb = ZSTD_highbit32(stat);
|
||||
U32 const BWeight = hb * BITCOST_MULTIPLIER;
|
||||
U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
|
||||
U32 const weight = BWeight + FWeight;
|
||||
assert(hb + BITCOST_ACCURACY < 31);
|
||||
return weight;
|
||||
}
|
||||
|
||||
/* debugging function, @return price in bytes */
|
||||
MEM_STATIC double ZSTD_fCost(U32 price)
|
||||
{
|
||||
return (double)price / (BITCOST_MULTIPLIER*8);
|
||||
}
|
||||
|
||||
static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel)
|
||||
{
|
||||
optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel);
|
||||
optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel);
|
||||
optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel);
|
||||
optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel);
|
||||
}
|
||||
|
||||
|
||||
static U32 ZSTD_downscaleStat(U32* table, U32 lastEltIndex, int malus)
|
||||
{
|
||||
U32 s, sum=0;
|
||||
assert(ZSTD_FREQ_DIV+malus > 0 && ZSTD_FREQ_DIV+malus < 31);
|
||||
for (s=0; s<=lastEltIndex; s++) {
|
||||
table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus));
|
||||
sum += table[s];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static void ZSTD_rescaleFreqs(optState_t* const optPtr,
|
||||
const BYTE* const src, size_t const srcSize)
|
||||
const BYTE* const src, size_t const srcSize,
|
||||
int optLevel)
|
||||
{
|
||||
optPtr->staticPrices = 0;
|
||||
optPtr->priceType = zop_dynamic;
|
||||
|
||||
if (optPtr->litLengthSum == 0) { /* first init */
|
||||
unsigned u;
|
||||
if (srcSize <= 1024) optPtr->staticPrices = 1;
|
||||
if (optPtr->litLengthSum == 0) { /* first block : init */
|
||||
if (srcSize <= 1024) /* heuristic */
|
||||
optPtr->priceType = zop_predef;
|
||||
|
||||
assert(optPtr->symbolCosts != NULL);
|
||||
if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) { /* huffman table presumed generated by dictionary */
|
||||
optPtr->priceType = zop_dynamic;
|
||||
|
||||
assert(optPtr->litFreq != NULL);
|
||||
optPtr->litSum = 0;
|
||||
{ unsigned lit;
|
||||
for (lit=0; lit<=MaxLit; lit++) {
|
||||
U32 const scaleLog = 11; /* scale to 2K */
|
||||
U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit);
|
||||
assert(bitCost <= scaleLog);
|
||||
optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
||||
optPtr->litSum += optPtr->litFreq[lit];
|
||||
} }
|
||||
|
||||
{ unsigned ll;
|
||||
FSE_CState_t llstate;
|
||||
FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable);
|
||||
optPtr->litLengthSum = 0;
|
||||
for (ll=0; ll<=MaxLL; ll++) {
|
||||
U32 const scaleLog = 10; /* scale to 1K */
|
||||
U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll);
|
||||
assert(bitCost < scaleLog);
|
||||
optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
||||
optPtr->litLengthSum += optPtr->litLengthFreq[ll];
|
||||
} }
|
||||
|
||||
{ unsigned ml;
|
||||
FSE_CState_t mlstate;
|
||||
FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable);
|
||||
optPtr->matchLengthSum = 0;
|
||||
for (ml=0; ml<=MaxML; ml++) {
|
||||
U32 const scaleLog = 10;
|
||||
U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml);
|
||||
assert(bitCost < scaleLog);
|
||||
optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
||||
optPtr->matchLengthSum += optPtr->matchLengthFreq[ml];
|
||||
} }
|
||||
|
||||
{ unsigned of;
|
||||
FSE_CState_t ofstate;
|
||||
FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable);
|
||||
optPtr->offCodeSum = 0;
|
||||
for (of=0; of<=MaxOff; of++) {
|
||||
U32 const scaleLog = 10;
|
||||
U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of);
|
||||
assert(bitCost < scaleLog);
|
||||
optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
||||
optPtr->offCodeSum += optPtr->offCodeFreq[of];
|
||||
} }
|
||||
|
||||
} else { /* not a dictionary */
|
||||
|
||||
assert(optPtr->litFreq != NULL);
|
||||
{ unsigned lit = MaxLit;
|
||||
HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */
|
||||
}
|
||||
optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
|
||||
|
||||
{ unsigned ll;
|
||||
for (ll=0; ll<=MaxLL; ll++)
|
||||
optPtr->litLengthFreq[ll] = 1;
|
||||
}
|
||||
optPtr->litLengthSum = MaxLL+1;
|
||||
|
||||
{ unsigned ml;
|
||||
for (ml=0; ml<=MaxML; ml++)
|
||||
optPtr->matchLengthFreq[ml] = 1;
|
||||
}
|
||||
optPtr->matchLengthSum = MaxML+1;
|
||||
|
||||
{ unsigned of;
|
||||
for (of=0; of<=MaxOff; of++)
|
||||
optPtr->offCodeFreq[of] = 1;
|
||||
}
|
||||
optPtr->offCodeSum = MaxOff+1;
|
||||
|
||||
assert(optPtr->litFreq!=NULL);
|
||||
for (u=0; u<=MaxLit; u++)
|
||||
optPtr->litFreq[u] = 0;
|
||||
for (u=0; u<srcSize; u++)
|
||||
optPtr->litFreq[src[u]]++;
|
||||
optPtr->litSum = 0;
|
||||
for (u=0; u<=MaxLit; u++) {
|
||||
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> ZSTD_FREQ_DIV);
|
||||
optPtr->litSum += optPtr->litFreq[u];
|
||||
}
|
||||
|
||||
for (u=0; u<=MaxLL; u++)
|
||||
optPtr->litLengthFreq[u] = 1;
|
||||
optPtr->litLengthSum = MaxLL+1;
|
||||
for (u=0; u<=MaxML; u++)
|
||||
optPtr->matchLengthFreq[u] = 1;
|
||||
optPtr->matchLengthSum = MaxML+1;
|
||||
for (u=0; u<=MaxOff; u++)
|
||||
optPtr->offCodeFreq[u] = 1;
|
||||
optPtr->offCodeSum = (MaxOff+1);
|
||||
} else { /* new block : re-use previous statistics, scaled down */
|
||||
|
||||
} else {
|
||||
unsigned u;
|
||||
|
||||
optPtr->litSum = 0;
|
||||
for (u=0; u<=MaxLit; u++) {
|
||||
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> (ZSTD_FREQ_DIV+1));
|
||||
optPtr->litSum += optPtr->litFreq[u];
|
||||
}
|
||||
optPtr->litLengthSum = 0;
|
||||
for (u=0; u<=MaxLL; u++) {
|
||||
optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
|
||||
optPtr->litLengthSum += optPtr->litLengthFreq[u];
|
||||
}
|
||||
optPtr->matchLengthSum = 0;
|
||||
for (u=0; u<=MaxML; u++) {
|
||||
optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
|
||||
}
|
||||
optPtr->offCodeSum = 0;
|
||||
for (u=0; u<=MaxOff; u++) {
|
||||
optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->offCodeSum += optPtr->offCodeFreq[u];
|
||||
}
|
||||
optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
|
||||
optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0);
|
||||
optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0);
|
||||
optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0);
|
||||
}
|
||||
|
||||
ZSTD_setLog2Prices(optPtr);
|
||||
ZSTD_setBasePrices(optPtr, optLevel);
|
||||
}
|
||||
|
||||
|
||||
/* ZSTD_rawLiteralsCost() :
|
||||
* cost of literals (only) in given segment (which length can be null)
|
||||
* does not include cost of literalLength symbol */
|
||||
* price of literals (only) in specified segment (which length can be 0).
|
||||
* does not include price of literalLength symbol */
|
||||
static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
|
||||
const optState_t* const optPtr)
|
||||
const optState_t* const optPtr,
|
||||
int optLevel)
|
||||
{
|
||||
if (optPtr->staticPrices) return (litLength*6); /* 6 bit per literal - no statistic used */
|
||||
if (litLength == 0) return 0;
|
||||
if (optPtr->priceType == zop_predef)
|
||||
return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */
|
||||
|
||||
/* literals */
|
||||
{ U32 u;
|
||||
U32 cost = litLength * optPtr->log2litSum;
|
||||
for (u=0; u < litLength; u++)
|
||||
cost -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
|
||||
return cost;
|
||||
}
|
||||
}
|
||||
|
||||
/* ZSTD_litLengthPrice() :
|
||||
* cost of literalLength symbol */
|
||||
static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr)
|
||||
{
|
||||
if (optPtr->staticPrices) return ZSTD_highbit32((U32)litLength+1);
|
||||
|
||||
/* literal Length */
|
||||
{ U32 const llCode = ZSTD_LLcode(litLength);
|
||||
U32 const price = LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
|
||||
/* dynamic statistics */
|
||||
{ U32 price = litLength * optPtr->litSumBasePrice;
|
||||
U32 u;
|
||||
for (u=0; u < litLength; u++) {
|
||||
assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */
|
||||
price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel);
|
||||
}
|
||||
return price;
|
||||
}
|
||||
}
|
||||
|
||||
/* ZSTD_litLengthPrice() :
|
||||
* cost of the literal part of a sequence,
|
||||
* including literals themselves, and literalLength symbol */
|
||||
static U32 ZSTD_fullLiteralsCost(const BYTE* const literals, U32 const litLength,
|
||||
const optState_t* const optPtr)
|
||||
* cost of literalLength symbol */
|
||||
static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel)
|
||||
{
|
||||
return ZSTD_rawLiteralsCost(literals, litLength, optPtr)
|
||||
+ ZSTD_litLengthPrice(litLength, optPtr);
|
||||
if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel);
|
||||
|
||||
/* dynamic statistics */
|
||||
{ U32 const llCode = ZSTD_LLcode(litLength);
|
||||
return (LL_bits[llCode] * BITCOST_MULTIPLIER) + (optPtr->litLengthSumBasePrice - WEIGHT(optPtr->litLengthFreq[llCode], optLevel));
|
||||
}
|
||||
}
|
||||
|
||||
/* ZSTD_litLengthContribution() :
|
||||
* @return ( cost(litlength) - cost(0) )
|
||||
* this value can then be added to rawLiteralsCost()
|
||||
* to provide a cost which is directly comparable to a match ending at same position */
|
||||
static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr)
|
||||
static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel)
|
||||
{
|
||||
if (optPtr->staticPrices) return ZSTD_highbit32(litLength+1);
|
||||
if (optPtr->priceType >= zop_predef) return WEIGHT(litLength, optLevel);
|
||||
|
||||
/* literal Length */
|
||||
/* dynamic statistics */
|
||||
{ U32 const llCode = ZSTD_LLcode(litLength);
|
||||
int const contribution = LL_bits[llCode]
|
||||
+ ZSTD_highbit32(optPtr->litLengthFreq[0]+1)
|
||||
- ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
|
||||
int const contribution = (LL_bits[llCode] * BITCOST_MULTIPLIER)
|
||||
+ WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */
|
||||
- WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
|
||||
#if 1
|
||||
return contribution;
|
||||
#else
|
||||
@@ -155,10 +238,11 @@ static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* con
|
||||
* which can be compared to the ending cost of a match
|
||||
* should a new match start at this position */
|
||||
static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength,
|
||||
const optState_t* const optPtr)
|
||||
const optState_t* const optPtr,
|
||||
int optLevel)
|
||||
{
|
||||
int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr)
|
||||
+ ZSTD_litLengthContribution(litLength, optPtr);
|
||||
int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel)
|
||||
+ ZSTD_litLengthContribution(litLength, optPtr, optLevel);
|
||||
return contribution;
|
||||
}
|
||||
|
||||
@@ -166,31 +250,38 @@ static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLe
|
||||
* Provides the cost of the match part (offset + matchLength) of a sequence
|
||||
* Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
|
||||
* optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_getMatchPrice(
|
||||
U32 const offset, U32 const matchLength,
|
||||
const optState_t* const optPtr,
|
||||
int const optLevel)
|
||||
FORCE_INLINE_TEMPLATE U32
|
||||
ZSTD_getMatchPrice(U32 const offset,
|
||||
U32 const matchLength,
|
||||
const optState_t* const optPtr,
|
||||
int const optLevel)
|
||||
{
|
||||
U32 price;
|
||||
U32 const offCode = ZSTD_highbit32(offset+1);
|
||||
U32 const mlBase = matchLength - MINMATCH;
|
||||
assert(matchLength >= MINMATCH);
|
||||
|
||||
if (optPtr->staticPrices) /* fixed scheme, do not use statistics */
|
||||
return ZSTD_highbit32((U32)mlBase+1) + 16 + offCode;
|
||||
if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */
|
||||
return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER);
|
||||
|
||||
price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
|
||||
if ((optLevel<2) /*static*/ && offCode >= 20) price += (offCode-19)*2; /* handicap for long distance offsets, favor decompression speed */
|
||||
/* dynamic statistics */
|
||||
price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
|
||||
if ((optLevel<2) /*static*/ && offCode >= 20)
|
||||
price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */
|
||||
|
||||
/* match Length */
|
||||
{ U32 const mlCode = ZSTD_MLcode(mlBase);
|
||||
price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
|
||||
price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel));
|
||||
}
|
||||
|
||||
price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */
|
||||
|
||||
DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
|
||||
return price;
|
||||
}
|
||||
|
||||
/* ZSTD_updateStats() :
|
||||
* assumption : literals + litLengtn <= iend */
|
||||
static void ZSTD_updateStats(optState_t* const optPtr,
|
||||
U32 litLength, const BYTE* literals,
|
||||
U32 offsetCode, U32 matchLength)
|
||||
@@ -271,7 +362,7 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE*
|
||||
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 mls, const int extDict)
|
||||
{
|
||||
U32* const hashTable = ms->hashTable;
|
||||
U32 const hashLog = cParams->hashLog;
|
||||
@@ -293,6 +384,7 @@ static U32 ZSTD_insertBt1(
|
||||
U32* largerPtr = smallerPtr + 1;
|
||||
U32 dummy32; /* to be nullified at the end */
|
||||
U32 const windowLow = ms->window.lowLimit;
|
||||
U32 const matchLow = windowLow ? windowLow : 1;
|
||||
U32 matchEndIdx = current+8+1;
|
||||
size_t bestLength = 8;
|
||||
U32 nbCompares = 1U << cParams->searchLog;
|
||||
@@ -308,7 +400,7 @@ static U32 ZSTD_insertBt1(
|
||||
assert(ip <= iend-8); /* required for h calculation */
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
while (nbCompares-- && (matchIndex >= matchLow)) {
|
||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
assert(matchIndex < current);
|
||||
@@ -334,8 +426,8 @@ static U32 ZSTD_insertBt1(
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
assert(matchIndex+matchLength >= dictLimit); /* might be wrong if extDict is incorrectly set to 0 */
|
||||
if (!extDict || (matchIndex+matchLength >= dictLimit)) {
|
||||
assert(matchIndex+matchLength >= dictLimit); /* might be wrong if actually extDict */
|
||||
match = base + matchIndex;
|
||||
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
|
||||
} else {
|
||||
@@ -381,16 +473,16 @@ 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 U32 mls, const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
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);
|
||||
DEBUGLOG(5, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
|
||||
idx, target, dictMode);
|
||||
|
||||
while(idx < target)
|
||||
idx += ZSTD_insertBt1(ms, cParams, base+idx, iend, mls, extDict);
|
||||
idx += ZSTD_insertBt1(ms, cParams, base+idx, iend, mls, dictMode == ZSTD_extDict);
|
||||
ms->nextToUpdate = target;
|
||||
}
|
||||
|
||||
@@ -398,13 +490,13 @@ 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*/);
|
||||
ZSTD_updateTree_internal(ms, cParams, ip, iend, cParams->searchLength, ZSTD_noDict);
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
U32 ZSTD_insertBtAndGetAllMatches (
|
||||
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, const ZSTD_dictMode_e dictMode,
|
||||
U32 rep[ZSTD_REP_NUM], U32 const ll0,
|
||||
ZSTD_match_t* matches, const U32 lengthToBeat, U32 const mls /* template */)
|
||||
{
|
||||
@@ -426,6 +518,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
U32 const btLow = btMask >= current ? 0 : current - btMask;
|
||||
U32 const windowLow = ms->window.lowLimit;
|
||||
U32 const matchLow = windowLow ? windowLow : 1;
|
||||
U32* smallerPtr = bt + 2*(current&btMask);
|
||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||
U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */
|
||||
@@ -433,8 +526,16 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
U32 mnum = 0;
|
||||
U32 nbCompares = 1U << cParams->searchLog;
|
||||
|
||||
const ZSTD_matchState_t* dms = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL;
|
||||
const BYTE* const dmsBase = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL;
|
||||
const BYTE* const dmsEnd = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL;
|
||||
U32 const dmsHighLimit = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0;
|
||||
U32 const dmsLowLimit = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0;
|
||||
U32 const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0;
|
||||
U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && btMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - btMask : dmsLowLimit;
|
||||
|
||||
size_t bestLength = lengthToBeat-1;
|
||||
DEBUGLOG(7, "ZSTD_insertBtAndGetAllMatches");
|
||||
DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current);
|
||||
|
||||
/* check repCode */
|
||||
{ U32 const lastR = ZSTD_REP_NUM + ll0;
|
||||
@@ -449,18 +550,26 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
|
||||
}
|
||||
} else { /* repIndex < dictLimit || repIndex >= current */
|
||||
const BYTE* const repMatch = dictBase + repIndex;
|
||||
const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
|
||||
dmsBase + repIndex - dmsIndexDelta :
|
||||
dictBase + repIndex;
|
||||
assert(current >= windowLow);
|
||||
if ( extDict /* this case only valid in extDict mode */
|
||||
if ( dictMode == ZSTD_extDict
|
||||
&& ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */
|
||||
& (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
|
||||
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
||||
repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
|
||||
}
|
||||
if (dictMode == ZSTD_dictMatchState
|
||||
&& ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */
|
||||
& ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */
|
||||
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
||||
repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
|
||||
} }
|
||||
/* save longer solution */
|
||||
if (repLen > bestLength) {
|
||||
DEBUGLOG(8, "found rep-match %u of length %u",
|
||||
repCode - ll0, (U32)repLen);
|
||||
DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u",
|
||||
repCode, ll0, repOffset, repLen);
|
||||
bestLength = repLen;
|
||||
matches[mnum].off = repCode - ll0;
|
||||
matches[mnum].len = (U32)repLen;
|
||||
@@ -473,10 +582,10 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
/* HC3 match finder */
|
||||
if ((mls == 3) /*static*/ && (bestLength < mls)) {
|
||||
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip);
|
||||
if ((matchIndex3 > windowLow)
|
||||
if ((matchIndex3 >= matchLow)
|
||||
& (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
|
||||
size_t mlen;
|
||||
if ((!extDict) /*static*/ || (matchIndex3 >= dictLimit)) {
|
||||
if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
|
||||
const BYTE* const match = base + matchIndex3;
|
||||
mlen = ZSTD_count(ip, match, iLimit);
|
||||
} else {
|
||||
@@ -498,17 +607,21 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
(ip+mlen == iLimit) ) { /* best possible length */
|
||||
ms->nextToUpdate = current+1; /* skip insertion */
|
||||
return 1;
|
||||
} } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no dictMatchState lookup: dicts don't have a populated HC3 table */
|
||||
}
|
||||
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
while (nbCompares-- && (matchIndex >= matchLow)) {
|
||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match;
|
||||
assert(current > matchIndex);
|
||||
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
|
||||
assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
|
||||
match = base + matchIndex;
|
||||
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
|
||||
@@ -520,8 +633,8 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
}
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
DEBUGLOG(8, "found match of length %u at distance %u",
|
||||
(U32)matchLength, current - matchIndex);
|
||||
DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)",
|
||||
(U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
|
||||
assert(matchEndIdx > matchIndex);
|
||||
if (matchLength > matchEndIdx - matchIndex)
|
||||
matchEndIdx = matchIndex + (U32)matchLength;
|
||||
@@ -529,9 +642,10 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
|
||||
matches[mnum].len = (U32)matchLength;
|
||||
mnum++;
|
||||
if (matchLength > ZSTD_OPT_NUM) break;
|
||||
if (ip+matchLength == iLimit) { /* equal : no way to know if inf or sup */
|
||||
break; /* drop, to preserve bt consistency (miss a little bit of compression) */
|
||||
if ( (matchLength > ZSTD_OPT_NUM)
|
||||
| (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
|
||||
if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */
|
||||
break; /* drop, to preserve bt consistency (miss a little bit of compression) */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,6 +666,46 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
|
||||
if (dictMode == ZSTD_dictMatchState && nbCompares) {
|
||||
U32 dictMatchIndex = dms->hashTable[h];
|
||||
const U32* const dmsBt = dms->chainTable;
|
||||
commonLengthSmaller = commonLengthLarger = 0;
|
||||
while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) {
|
||||
const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match = dmsBase + dictMatchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart);
|
||||
if (dictMatchIndex+matchLength >= dmsHighLimit)
|
||||
match = base + dictMatchIndex + dmsIndexDelta; /* to prepare for next usage of match[matchLength] */
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
matchIndex = dictMatchIndex + dmsIndexDelta;
|
||||
DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)",
|
||||
(U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
|
||||
if (matchLength > matchEndIdx - matchIndex)
|
||||
matchEndIdx = matchIndex + (U32)matchLength;
|
||||
bestLength = matchLength;
|
||||
matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
|
||||
matches[mnum].len = (U32)matchLength;
|
||||
mnum++;
|
||||
if ( (matchLength > ZSTD_OPT_NUM)
|
||||
| (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
|
||||
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
||||
}
|
||||
}
|
||||
|
||||
if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */
|
||||
if (match[matchLength] < ip[matchLength]) {
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
commonLengthLarger = matchLength;
|
||||
dictMatchIndex = nextPtr[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(matchEndIdx > current+8);
|
||||
ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
|
||||
return mnum;
|
||||
@@ -560,22 +714,22 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
|
||||
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, const ZSTD_dictMode_e dictMode,
|
||||
U32 rep[ZSTD_REP_NUM], U32 const ll0,
|
||||
ZSTD_match_t* matches, U32 const lengthToBeat)
|
||||
{
|
||||
U32 const matchLengthSearch = cParams->searchLength;
|
||||
DEBUGLOG(7, "ZSTD_BtGetAllMatches");
|
||||
DEBUGLOG(8, "ZSTD_BtGetAllMatches");
|
||||
if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree_internal(ms, cParams, ip, iHighLimit, matchLengthSearch, extDict);
|
||||
ZSTD_updateTree_internal(ms, cParams, ip, iHighLimit, matchLengthSearch, dictMode);
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
case 3 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 3);
|
||||
case 3 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 3);
|
||||
default :
|
||||
case 4 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 4);
|
||||
case 5 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 5);
|
||||
case 4 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 4);
|
||||
case 5 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 5);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 6);
|
||||
case 6 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,65 +763,18 @@ repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
const BYTE* anchor;
|
||||
U32 litlen;
|
||||
U32 rawLitCost;
|
||||
} cachedLiteralPrice_t;
|
||||
|
||||
static U32 ZSTD_rawLiteralsCost_cached(
|
||||
cachedLiteralPrice_t* const cachedLitPrice,
|
||||
const BYTE* const anchor, U32 const litlen,
|
||||
const optState_t* const optStatePtr)
|
||||
static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
|
||||
{
|
||||
U32 startCost;
|
||||
U32 remainingLength;
|
||||
const BYTE* startPosition;
|
||||
|
||||
if (anchor == cachedLitPrice->anchor) {
|
||||
startCost = cachedLitPrice->rawLitCost;
|
||||
startPosition = anchor + cachedLitPrice->litlen;
|
||||
assert(litlen >= cachedLitPrice->litlen);
|
||||
remainingLength = litlen - cachedLitPrice->litlen;
|
||||
} else {
|
||||
startCost = 0;
|
||||
startPosition = anchor;
|
||||
remainingLength = litlen;
|
||||
}
|
||||
|
||||
{ U32 const rawLitCost = startCost + ZSTD_rawLiteralsCost(startPosition, remainingLength, optStatePtr);
|
||||
cachedLitPrice->anchor = anchor;
|
||||
cachedLitPrice->litlen = litlen;
|
||||
cachedLitPrice->rawLitCost = rawLitCost;
|
||||
return rawLitCost;
|
||||
}
|
||||
return sol.litlen + sol.mlen;
|
||||
}
|
||||
|
||||
static U32 ZSTD_fullLiteralsCost_cached(
|
||||
cachedLiteralPrice_t* const cachedLitPrice,
|
||||
const BYTE* const anchor, U32 const litlen,
|
||||
const optState_t* const optStatePtr)
|
||||
{
|
||||
return ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
|
||||
+ ZSTD_litLengthPrice(litlen, optStatePtr);
|
||||
}
|
||||
|
||||
static int ZSTD_literalsContribution_cached(
|
||||
cachedLiteralPrice_t* const cachedLitPrice,
|
||||
const BYTE* const anchor, U32 const litlen,
|
||||
const optState_t* const optStatePtr)
|
||||
{
|
||||
int const contribution = ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
|
||||
+ ZSTD_litLengthContribution(litlen, optStatePtr);
|
||||
return contribution;
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
const void* src, size_t srcSize,
|
||||
const int optLevel, const int extDict)
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
const ZSTD_compressionParameters* cParams,
|
||||
const void* src, size_t srcSize,
|
||||
const int optLevel, const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
optState_t* const optStatePtr = &ms->opt;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
@@ -683,66 +790,69 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,seqStore_t* seqStore
|
||||
|
||||
ZSTD_optimal_t* const opt = optStatePtr->priceTable;
|
||||
ZSTD_match_t* const matches = optStatePtr->matchTable;
|
||||
cachedLiteralPrice_t cachedLitPrice;
|
||||
ZSTD_optimal_t lastSequence;
|
||||
|
||||
/* init */
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
|
||||
assert(optLevel <= 2);
|
||||
ms->nextToUpdate3 = ms->nextToUpdate;
|
||||
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
|
||||
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel);
|
||||
ip += (ip==prefixStart);
|
||||
memset(&cachedLitPrice, 0, sizeof(cachedLitPrice));
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
U32 cur, last_pos = 0;
|
||||
U32 best_mlen, best_off;
|
||||
|
||||
/* find first match */
|
||||
{ U32 const litlen = (U32)(ip - anchor);
|
||||
U32 const ll0 = !litlen;
|
||||
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, ip, iend, extDict, rep, ll0, matches, minMatch);
|
||||
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, ip, iend, dictMode, rep, ll0, matches, minMatch);
|
||||
if (!nbMatches) { ip++; continue; }
|
||||
|
||||
/* initialize opt[0] */
|
||||
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||
opt[0].mlen = 1;
|
||||
opt[0].mlen = 0; /* means is_a_literal */
|
||||
opt[0].litlen = litlen;
|
||||
opt[0].price = ZSTD_literalsContribution(anchor, litlen, optStatePtr, optLevel);
|
||||
|
||||
/* large match -> immediate encoding */
|
||||
{ U32 const maxML = matches[nbMatches-1].len;
|
||||
DEBUGLOG(7, "found %u matches of maxLength=%u and offset=%u at cPos=%u => start new serie",
|
||||
nbMatches, maxML, matches[nbMatches-1].off, (U32)(ip-prefixStart));
|
||||
U32 const maxOffset = matches[nbMatches-1].off;
|
||||
DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new serie",
|
||||
nbMatches, maxML, maxOffset, (U32)(ip-prefixStart));
|
||||
|
||||
if (maxML > sufficient_len) {
|
||||
best_mlen = maxML;
|
||||
best_off = matches[nbMatches-1].off;
|
||||
DEBUGLOG(7, "large match (%u>%u), immediate encoding",
|
||||
best_mlen, sufficient_len);
|
||||
lastSequence.litlen = litlen;
|
||||
lastSequence.mlen = maxML;
|
||||
lastSequence.off = maxOffset;
|
||||
DEBUGLOG(6, "large match (%u>%u), immediate encoding",
|
||||
maxML, sufficient_len);
|
||||
cur = 0;
|
||||
last_pos = 1;
|
||||
last_pos = ZSTD_totalLen(lastSequence);
|
||||
goto _shortestPath;
|
||||
} }
|
||||
|
||||
/* set prices for first matches starting position == 0 */
|
||||
{ U32 const literalsPrice = ZSTD_fullLiteralsCost_cached(&cachedLitPrice, anchor, litlen, optStatePtr);
|
||||
{ U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
||||
U32 pos;
|
||||
U32 matchNb;
|
||||
for (pos = 0; pos < minMatch; pos++) {
|
||||
opt[pos].mlen = 1;
|
||||
opt[pos].price = ZSTD_MAX_PRICE;
|
||||
for (pos = 1; pos < minMatch; pos++) {
|
||||
opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */
|
||||
}
|
||||
for (matchNb = 0; matchNb < nbMatches; matchNb++) {
|
||||
U32 const offset = matches[matchNb].off;
|
||||
U32 const end = matches[matchNb].len;
|
||||
repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0);
|
||||
for ( ; pos <= end ; pos++ ) {
|
||||
U32 const matchPrice = literalsPrice + ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
|
||||
DEBUGLOG(7, "rPos:%u => set initial price : %u",
|
||||
pos, matchPrice);
|
||||
U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
|
||||
U32 const sequencePrice = literalsPrice + matchPrice;
|
||||
DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
|
||||
pos, ZSTD_fCost(sequencePrice));
|
||||
opt[pos].mlen = pos;
|
||||
opt[pos].off = offset;
|
||||
opt[pos].litlen = litlen;
|
||||
opt[pos].price = matchPrice;
|
||||
opt[pos].price = sequencePrice;
|
||||
ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
|
||||
memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
|
||||
} }
|
||||
last_pos = pos-1;
|
||||
@@ -753,55 +863,67 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,seqStore_t* seqStore
|
||||
for (cur = 1; cur <= last_pos; cur++) {
|
||||
const BYTE* const inr = ip + cur;
|
||||
assert(cur < ZSTD_OPT_NUM);
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur)
|
||||
|
||||
/* Fix current position with one literal if cheaper */
|
||||
{ U32 const litlen = (opt[cur-1].mlen == 1) ? opt[cur-1].litlen + 1 : 1;
|
||||
int price; /* note : contribution can be negative */
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_literalsContribution(inr-litlen, litlen, optStatePtr);
|
||||
} else {
|
||||
price = ZSTD_literalsContribution_cached(&cachedLitPrice, anchor, litlen, optStatePtr);
|
||||
}
|
||||
{ U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1;
|
||||
int const price = opt[cur-1].price
|
||||
+ ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
|
||||
+ ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
|
||||
- ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
|
||||
assert(price < 1000000000); /* overflow check */
|
||||
if (price <= opt[cur].price) {
|
||||
DEBUGLOG(7, "rPos:%u : better price (%u<%u) using literal",
|
||||
cur, price, opt[cur].price);
|
||||
opt[cur].mlen = 1;
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
|
||||
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
|
||||
opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
|
||||
opt[cur].mlen = 0;
|
||||
opt[cur].off = 0;
|
||||
opt[cur].litlen = litlen;
|
||||
opt[cur].price = price;
|
||||
memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep));
|
||||
} }
|
||||
} else {
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)",
|
||||
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price),
|
||||
opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
|
||||
}
|
||||
}
|
||||
|
||||
/* last match must start at a minimum distance of 8 from oend */
|
||||
if (inr > ilimit) continue;
|
||||
|
||||
if (cur == last_pos) break;
|
||||
|
||||
if ( (optLevel==0) /*static*/
|
||||
&& (opt[cur+1].price <= opt[cur].price) )
|
||||
if ( (optLevel==0) /*static_test*/
|
||||
&& (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
|
||||
DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1);
|
||||
continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
|
||||
}
|
||||
|
||||
{ U32 const ll0 = (opt[cur].mlen != 1);
|
||||
U32 const litlen = (opt[cur].mlen == 1) ? opt[cur].litlen : 0;
|
||||
U32 const previousPrice = (cur > litlen) ? opt[cur-litlen].price : 0;
|
||||
U32 const basePrice = previousPrice + ZSTD_fullLiteralsCost(inr-litlen, litlen, optStatePtr);
|
||||
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, inr, iend, extDict, opt[cur].rep, ll0, matches, minMatch);
|
||||
{ U32 const ll0 = (opt[cur].mlen != 0);
|
||||
U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
|
||||
U32 const previousPrice = opt[cur].price;
|
||||
U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
||||
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, inr, iend, dictMode, opt[cur].rep, ll0, matches, minMatch);
|
||||
U32 matchNb;
|
||||
if (!nbMatches) continue;
|
||||
if (!nbMatches) {
|
||||
DEBUGLOG(7, "rPos:%u : no match found", cur);
|
||||
continue;
|
||||
}
|
||||
|
||||
{ U32 const maxML = matches[nbMatches-1].len;
|
||||
DEBUGLOG(7, "rPos:%u, found %u matches, of maxLength=%u",
|
||||
cur, nbMatches, maxML);
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
|
||||
inr-istart, cur, nbMatches, maxML);
|
||||
|
||||
if ( (maxML > sufficient_len)
|
||||
| (cur + maxML >= ZSTD_OPT_NUM) ) {
|
||||
best_mlen = maxML;
|
||||
best_off = matches[nbMatches-1].off;
|
||||
last_pos = cur + 1;
|
||||
|| (cur + maxML >= ZSTD_OPT_NUM) ) {
|
||||
lastSequence.mlen = maxML;
|
||||
lastSequence.off = matches[nbMatches-1].off;
|
||||
lastSequence.litlen = litlen;
|
||||
cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */
|
||||
last_pos = cur + ZSTD_totalLen(lastSequence);
|
||||
if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */
|
||||
goto _shortestPath;
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
/* set prices using matches found at position == cur */
|
||||
for (matchNb = 0; matchNb < nbMatches; matchNb++) {
|
||||
@@ -811,81 +933,97 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,seqStore_t* seqStore
|
||||
U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
|
||||
U32 mlen;
|
||||
|
||||
DEBUGLOG(7, "testing match %u => offCode=%u, mlen=%u, llen=%u",
|
||||
DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u",
|
||||
matchNb, matches[matchNb].off, lastML, litlen);
|
||||
|
||||
for (mlen = lastML; mlen >= startML; mlen--) {
|
||||
for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
|
||||
U32 const pos = cur + mlen;
|
||||
int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
|
||||
|
||||
if ((pos > last_pos) || (price < opt[pos].price)) {
|
||||
DEBUGLOG(7, "rPos:%u => new better price (%u<%u)",
|
||||
pos, price, opt[pos].price);
|
||||
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; }
|
||||
DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
|
||||
pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
|
||||
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */
|
||||
opt[pos].mlen = mlen;
|
||||
opt[pos].off = offset;
|
||||
opt[pos].litlen = litlen;
|
||||
opt[pos].price = price;
|
||||
ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
|
||||
memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
|
||||
} else {
|
||||
if (optLevel==0) break; /* gets ~+10% speed for about -0.01 ratio loss */
|
||||
DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
|
||||
pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
|
||||
if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
|
||||
}
|
||||
} } }
|
||||
} /* for (cur = 1; cur <= last_pos; cur++) */
|
||||
|
||||
best_mlen = opt[last_pos].mlen;
|
||||
best_off = opt[last_pos].off;
|
||||
cur = last_pos - best_mlen;
|
||||
lastSequence = opt[last_pos];
|
||||
cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */
|
||||
assert(cur < ZSTD_OPT_NUM); /* control overflow*/
|
||||
|
||||
_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
assert(opt[0].mlen == 1);
|
||||
assert(opt[0].mlen == 0);
|
||||
|
||||
/* reverse traversal */
|
||||
DEBUGLOG(7, "start reverse traversal (last_pos:%u, cur:%u)",
|
||||
last_pos, cur);
|
||||
{ U32 selectedMatchLength = best_mlen;
|
||||
U32 selectedOffset = best_off;
|
||||
U32 pos = cur;
|
||||
while (1) {
|
||||
U32 const mlen = opt[pos].mlen;
|
||||
U32 const off = opt[pos].off;
|
||||
opt[pos].mlen = selectedMatchLength;
|
||||
opt[pos].off = selectedOffset;
|
||||
selectedMatchLength = mlen;
|
||||
selectedOffset = off;
|
||||
if (mlen > pos) break;
|
||||
pos -= mlen;
|
||||
} }
|
||||
{ U32 const storeEnd = cur + 1;
|
||||
U32 storeStart = storeEnd;
|
||||
U32 seqPos = cur;
|
||||
|
||||
/* save sequences */
|
||||
{ U32 pos;
|
||||
for (pos=0; pos < last_pos; ) {
|
||||
U32 const llen = (U32)(ip - anchor);
|
||||
U32 const mlen = opt[pos].mlen;
|
||||
U32 const offset = opt[pos].off;
|
||||
if (mlen == 1) { ip++; pos++; continue; } /* literal position => move on */
|
||||
pos += mlen; ip += mlen;
|
||||
DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
|
||||
last_pos, cur);
|
||||
assert(storeEnd < ZSTD_OPT_NUM);
|
||||
DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
||||
storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off);
|
||||
opt[storeEnd] = lastSequence;
|
||||
while (seqPos > 0) {
|
||||
U32 const backDist = ZSTD_totalLen(opt[seqPos]);
|
||||
storeStart--;
|
||||
DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
||||
seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off);
|
||||
opt[storeStart] = opt[seqPos];
|
||||
seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
|
||||
}
|
||||
|
||||
/* repcodes update : like ZSTD_updateRep(), but update in place */
|
||||
if (offset >= ZSTD_REP_NUM) { /* full offset */
|
||||
rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = offset - ZSTD_REP_MOVE;
|
||||
} else { /* repcode */
|
||||
U32 const repCode = offset + (llen==0);
|
||||
if (repCode) { /* note : if repCode==0, no change */
|
||||
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
|
||||
if (repCode >= 2) rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = currentOffset;
|
||||
/* save sequences */
|
||||
DEBUGLOG(6, "sending selected sequences into seqStore")
|
||||
{ U32 storePos;
|
||||
for (storePos=storeStart; storePos <= storeEnd; storePos++) {
|
||||
U32 const llen = opt[storePos].litlen;
|
||||
U32 const mlen = opt[storePos].mlen;
|
||||
U32 const offCode = opt[storePos].off;
|
||||
U32 const advance = llen + mlen;
|
||||
DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u",
|
||||
anchor - istart, llen, mlen);
|
||||
|
||||
if (mlen==0) { /* only literals => must be last "sequence", actually starting a new stream of sequences */
|
||||
assert(storePos == storeEnd); /* must be last sequence */
|
||||
ip = anchor + llen; /* last "sequence" is a bunch of literals => don't progress anchor */
|
||||
continue; /* will finish */
|
||||
}
|
||||
}
|
||||
|
||||
ZSTD_updateStats(optStatePtr, llen, anchor, offset, mlen);
|
||||
ZSTD_storeSeq(seqStore, llen, anchor, offset, mlen-MINMATCH);
|
||||
anchor = ip;
|
||||
} }
|
||||
ZSTD_setLog2Prices(optStatePtr);
|
||||
/* repcodes update : like ZSTD_updateRep(), but update in place */
|
||||
if (offCode >= ZSTD_REP_NUM) { /* full offset */
|
||||
rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = offCode - ZSTD_REP_MOVE;
|
||||
} else { /* repcode */
|
||||
U32 const repCode = offCode + (llen==0);
|
||||
if (repCode) { /* note : if repCode==0, no change */
|
||||
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
|
||||
if (repCode >= 2) rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = currentOffset;
|
||||
} }
|
||||
|
||||
assert(anchor + llen <= iend);
|
||||
ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen);
|
||||
ZSTD_storeSeq(seqStore, llen, anchor, offCode, mlen-MINMATCH);
|
||||
anchor += advance;
|
||||
ip = anchor;
|
||||
} }
|
||||
ZSTD_setBasePrices(optStatePtr, optLevel);
|
||||
}
|
||||
|
||||
} /* while (ip < ilimit) */
|
||||
|
||||
/* Return the last literals size */
|
||||
@@ -895,29 +1033,94 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
|
||||
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)
|
||||
const ZSTD_compressionParameters* cParams, const void* src, size_t srcSize)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_btopt");
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, 0 /*extDict*/);
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, ZSTD_noDict);
|
||||
}
|
||||
|
||||
|
||||
/* used in 2-pass strategy */
|
||||
static U32 ZSTD_upscaleStat(U32* table, U32 lastEltIndex, int bonus)
|
||||
{
|
||||
U32 s, sum=0;
|
||||
assert(ZSTD_FREQ_DIV+bonus > 0);
|
||||
for (s=0; s<=lastEltIndex; s++) {
|
||||
table[s] <<= ZSTD_FREQ_DIV+bonus;
|
||||
table[s]--;
|
||||
sum += table[s];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/* used in 2-pass strategy */
|
||||
MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr)
|
||||
{
|
||||
optPtr->litSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0);
|
||||
optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 1);
|
||||
optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 1);
|
||||
optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 1);
|
||||
}
|
||||
|
||||
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)
|
||||
const ZSTD_compressionParameters* cParams, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, 0 /*extDict*/);
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize);
|
||||
#if 0
|
||||
/* 2-pass strategy (disabled)
|
||||
* this strategy makes a first pass over first block to collect statistics
|
||||
* and seed next round's statistics with it.
|
||||
* The compression ratio gain is generally small (~0.5% on first block),
|
||||
* the cost is 2x cpu time on first block. */
|
||||
assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
|
||||
if ( (ms->opt.litLengthSum==0) /* first block */
|
||||
&& (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
|
||||
&& (ms->window.dictLimit == ms->window.lowLimit) ) { /* no dictionary */
|
||||
U32 tmpRep[ZSTD_REP_NUM];
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_btultra: first block: collecting statistics");
|
||||
assert(ms->nextToUpdate >= ms->window.dictLimit
|
||||
&& ms->nextToUpdate <= ms->window.dictLimit + 1);
|
||||
memcpy(tmpRep, rep, sizeof(tmpRep));
|
||||
ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, cParams, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/
|
||||
ZSTD_resetSeqStore(seqStore);
|
||||
/* invalidate first scan from history */
|
||||
ms->window.base -= srcSize;
|
||||
ms->window.dictLimit += (U32)srcSize;
|
||||
ms->window.lowLimit = ms->window.dictLimit;
|
||||
ms->nextToUpdate = ms->window.dictLimit;
|
||||
ms->nextToUpdate3 = ms->window.dictLimit;
|
||||
/* re-inforce weight of collected statistics */
|
||||
ZSTD_upscaleStats(&ms->opt);
|
||||
}
|
||||
#endif
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btopt_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const ZSTD_compressionParameters* cParams, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const ZSTD_compressionParameters* cParams, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
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)
|
||||
const ZSTD_compressionParameters* cParams, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, 1 /*extDict*/);
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, ZSTD_extDict);
|
||||
}
|
||||
|
||||
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)
|
||||
const ZSTD_compressionParameters* cParams, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, 1 /*extDict*/);
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, ZSTD_extDict);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,13 @@ 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_dictMatchState(
|
||||
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_dictMatchState(
|
||||
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);
|
||||
|
||||
@@ -37,18 +37,17 @@
|
||||
#define ZSTD_RESIZE_SEQPOOL 0
|
||||
|
||||
/* ====== Debug ====== */
|
||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
|
||||
#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=2) && !defined(_MSC_VER)
|
||||
|
||||
# include <stdio.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/times.h>
|
||||
# define DEBUGLOGRAW(l, ...) if (l<=ZSTD_DEBUG) { fprintf(stderr, __VA_ARGS__); }
|
||||
|
||||
# define DEBUG_PRINTHEX(l,p,n) { \
|
||||
unsigned debug_u; \
|
||||
for (debug_u=0; debug_u<(n); debug_u++) \
|
||||
DEBUGLOGRAW(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
|
||||
DEBUGLOGRAW(l, " \n"); \
|
||||
RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
|
||||
RAWLOG(l, " \n"); \
|
||||
}
|
||||
|
||||
static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
||||
@@ -62,7 +61,7 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
||||
|
||||
#define MUTEX_WAIT_TIME_DLEVEL 6
|
||||
#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) { \
|
||||
if (ZSTD_DEBUG >= MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
{ unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
|
||||
@@ -160,6 +159,25 @@ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
}
|
||||
|
||||
|
||||
static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, U32 nbWorkers)
|
||||
{
|
||||
unsigned const maxNbBuffers = 2*nbWorkers + 3;
|
||||
if (srcBufPool==NULL) return NULL;
|
||||
if (srcBufPool->totalBuffers >= maxNbBuffers) /* good enough */
|
||||
return srcBufPool;
|
||||
/* need a larger buffer pool */
|
||||
{ ZSTD_customMem const cMem = srcBufPool->cMem;
|
||||
size_t const bSize = srcBufPool->bufferSize; /* forward parameters */
|
||||
ZSTDMT_bufferPool* newBufPool;
|
||||
ZSTDMT_freeBufferPool(srcBufPool);
|
||||
newBufPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
|
||||
if (newBufPool==NULL) return newBufPool;
|
||||
ZSTDMT_setBufferSize(newBufPool, bSize);
|
||||
return newBufPool;
|
||||
}
|
||||
}
|
||||
|
||||
/** ZSTDMT_getBuffer() :
|
||||
* assumption : bufPool must be valid
|
||||
* @return : a buffer, with start pointer and size
|
||||
@@ -310,6 +328,10 @@ static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool)
|
||||
ZSTDMT_freeBufferPool(seqPool);
|
||||
}
|
||||
|
||||
static ZSTDMT_seqPool* ZSTDMT_expandSeqPool(ZSTDMT_seqPool* pool, U32 nbWorkers)
|
||||
{
|
||||
return ZSTDMT_expandBufferPool(pool, nbWorkers);
|
||||
}
|
||||
|
||||
|
||||
/* ===== CCtx Pool ===== */
|
||||
@@ -355,6 +377,18 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbWorkers,
|
||||
return cctxPool;
|
||||
}
|
||||
|
||||
static ZSTDMT_CCtxPool* ZSTDMT_expandCCtxPool(ZSTDMT_CCtxPool* srcPool,
|
||||
unsigned nbWorkers)
|
||||
{
|
||||
if (srcPool==NULL) return NULL;
|
||||
if (nbWorkers <= srcPool->totalCCtx) return srcPool; /* good enough */
|
||||
/* need a larger cctx pool */
|
||||
{ ZSTD_customMem const cMem = srcPool->cMem;
|
||||
ZSTDMT_freeCCtxPool(srcPool);
|
||||
return ZSTDMT_createCCtxPool(nbWorkers, cMem);
|
||||
}
|
||||
}
|
||||
|
||||
/* only works during initialization phase, not during compression */
|
||||
static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
|
||||
{
|
||||
@@ -425,12 +459,11 @@ typedef struct {
|
||||
ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */
|
||||
} serialState_t;
|
||||
|
||||
static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* seqPool, ZSTD_CCtx_params params)
|
||||
static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* seqPool, ZSTD_CCtx_params params, size_t jobSize)
|
||||
{
|
||||
/* 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);
|
||||
@@ -453,7 +486,7 @@ static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool*
|
||||
serialState->params.ldmParams.hashLog -
|
||||
serialState->params.ldmParams.bucketSizeLog;
|
||||
/* Size the seq pool tables */
|
||||
ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, params.jobSize));
|
||||
ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize));
|
||||
/* Reset the window */
|
||||
ZSTD_window_clear(&serialState->ldmState.window);
|
||||
serialState->ldmWindow = serialState->ldmState.window;
|
||||
@@ -473,6 +506,7 @@ static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool*
|
||||
memset(serialState->ldmState.bucketOffsets, 0, bucketSize);
|
||||
}
|
||||
serialState->params = params;
|
||||
serialState->params.jobSize = (U32)jobSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -514,6 +548,7 @@ static void ZSTDMT_serialState_update(serialState_t* serialState,
|
||||
size_t error;
|
||||
assert(seqStore.seq != NULL && seqStore.pos == 0 &&
|
||||
seqStore.size == 0 && seqStore.capacity > 0);
|
||||
assert(src.size <= serialState->params.jobSize);
|
||||
ZSTD_window_update(&serialState->ldmState.window, src.start, src.size);
|
||||
error = ZSTD_ldm_generateSequences(
|
||||
&serialState->ldmState, &seqStore,
|
||||
@@ -602,13 +637,6 @@ void ZSTDMT_compressionJob(void* jobDescription)
|
||||
rawSeqStore_t rawSeqStore = ZSTDMT_getSeq(job->seqPool);
|
||||
buffer_t dstBuff = job->dstBuff;
|
||||
|
||||
/* 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) {
|
||||
job->cSize = ERROR(memory_allocation);
|
||||
@@ -622,10 +650,22 @@ void ZSTDMT_compressionJob(void* jobDescription)
|
||||
}
|
||||
job->dstBuff = dstBuff; /* this value can be read in ZSTDMT_flush, when it copies the whole job */
|
||||
}
|
||||
if (jobParams.ldmParams.enableLdm && rawSeqStore.seq == NULL) {
|
||||
job->cSize = ERROR(memory_allocation);
|
||||
goto _endJob;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
|
||||
/* init */
|
||||
if (job->cdict) {
|
||||
size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dct_auto, job->cdict, jobParams, job->fullFrameSize);
|
||||
size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, job->cdict, jobParams, job->fullFrameSize);
|
||||
assert(job->firstJob); /* only allowed for first job */
|
||||
if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
|
||||
} else { /* srcStart points at reloaded section */
|
||||
@@ -637,6 +677,7 @@ void ZSTDMT_compressionJob(void* jobDescription)
|
||||
} }
|
||||
{ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
|
||||
job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
|
||||
ZSTD_dtlm_fast,
|
||||
NULL, /*cdict*/
|
||||
jobParams, pledgedSrcSize);
|
||||
if (ZSTD_isError(initError)) {
|
||||
@@ -745,9 +786,9 @@ struct ZSTDMT_CCtx_s {
|
||||
ZSTD_CCtx_params params;
|
||||
size_t targetSectionSize;
|
||||
size_t targetPrefixSize;
|
||||
roundBuff_t roundBuff;
|
||||
int jobReady; /* 1 => one job is already prepared, but pool has shortage of workers. Don't create a new job. */
|
||||
inBuff_t inBuff;
|
||||
int jobReady; /* 1 => one job is already prepared, but pool has shortage of workers. Don't create another one. */
|
||||
roundBuff_t roundBuff;
|
||||
serialState_t serial;
|
||||
unsigned singleBlockingThread;
|
||||
unsigned jobIDMask;
|
||||
@@ -798,6 +839,20 @@ static ZSTDMT_jobDescription* ZSTDMT_createJobsTable(U32* nbJobsPtr, ZSTD_custom
|
||||
return jobTable;
|
||||
}
|
||||
|
||||
static size_t ZSTDMT_expandJobsTable (ZSTDMT_CCtx* mtctx, U32 nbWorkers) {
|
||||
U32 nbJobs = nbWorkers + 2;
|
||||
if (nbJobs > mtctx->jobIDMask+1) { /* need more job capacity */
|
||||
ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
|
||||
mtctx->jobIDMask = 0;
|
||||
mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, mtctx->cMem);
|
||||
if (mtctx->jobs==NULL) return ERROR(memory_allocation);
|
||||
assert((nbJobs != 0) && ((nbJobs & (nbJobs - 1)) == 0)); /* ensure nbJobs is a power of 2 */
|
||||
mtctx->jobIDMask = nbJobs - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ZSTDMT_CCtxParam_setNbWorkers():
|
||||
* Internal use only */
|
||||
size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers)
|
||||
@@ -924,6 +979,8 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params,
|
||||
if ( (value > 0) /* value==0 => automatic job size */
|
||||
& (value < ZSTDMT_JOBSIZE_MIN) )
|
||||
value = ZSTDMT_JOBSIZE_MIN;
|
||||
if (value > ZSTDMT_JOBSIZE_MAX)
|
||||
value = ZSTDMT_JOBSIZE_MAX;
|
||||
params->jobSize = value;
|
||||
return value;
|
||||
case ZSTDMT_p_overlapSectionLog :
|
||||
@@ -950,6 +1007,21 @@ size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter,
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned* value)
|
||||
{
|
||||
switch (parameter) {
|
||||
case ZSTDMT_p_jobSize:
|
||||
*value = mtctx->params.jobSize;
|
||||
break;
|
||||
case ZSTDMT_p_overlapSectionLog:
|
||||
*value = mtctx->params.overlapSizeLog;
|
||||
break;
|
||||
default:
|
||||
return ERROR(parameter_unsupported);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sets parameters relevant to the compression job,
|
||||
* initializing others to default values. */
|
||||
static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(ZSTD_CCtx_params const params)
|
||||
@@ -960,11 +1032,28 @@ static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(ZSTD_CCtx_params const params)
|
||||
jobParams.cParams = params.cParams;
|
||||
jobParams.fParams = params.fParams;
|
||||
jobParams.compressionLevel = params.compressionLevel;
|
||||
jobParams.disableLiteralCompression = params.disableLiteralCompression;
|
||||
|
||||
return jobParams;
|
||||
}
|
||||
|
||||
|
||||
/* ZSTDMT_resize() :
|
||||
* @return : error code if fails, 0 on success */
|
||||
static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers)
|
||||
{
|
||||
if (POOL_resize(mtctx->factory, nbWorkers)) return ERROR(memory_allocation);
|
||||
CHECK_F( ZSTDMT_expandJobsTable(mtctx, nbWorkers) );
|
||||
mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, nbWorkers);
|
||||
if (mtctx->bufPool == NULL) return ERROR(memory_allocation);
|
||||
mtctx->cctxPool = ZSTDMT_expandCCtxPool(mtctx->cctxPool, nbWorkers);
|
||||
if (mtctx->cctxPool == NULL) return ERROR(memory_allocation);
|
||||
mtctx->seqPool = ZSTDMT_expandSeqPool(mtctx->seqPool, nbWorkers);
|
||||
if (mtctx->seqPool == NULL) return ERROR(memory_allocation);
|
||||
ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! 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. */
|
||||
@@ -981,15 +1070,6 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -1087,18 +1167,10 @@ static size_t ZSTDMT_compress_advanced_internal(
|
||||
|
||||
assert(avgJobSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), required to compress directly into Dst (no additional buffer) */
|
||||
ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgJobSize) );
|
||||
if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params))
|
||||
if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, avgJobSize))
|
||||
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->jobs = ZSTDMT_createJobsTable(&jobsTableSize, mtctx->cMem);
|
||||
if (mtctx->jobs==NULL) return ERROR(memory_allocation);
|
||||
assert((jobsTableSize != 0) && ((jobsTableSize & (jobsTableSize - 1)) == 0)); /* ensure jobsTableSize is a power of 2 */
|
||||
mtctx->jobIDMask = jobsTableSize - 1;
|
||||
}
|
||||
CHECK_F( ZSTDMT_expandJobsTable(mtctx, nbJobs) ); /* only expands if necessary */
|
||||
|
||||
{ unsigned u;
|
||||
for (u=0; u<nbJobs; u++) {
|
||||
@@ -1221,17 +1293,18 @@ size_t ZSTDMT_initCStream_internal(
|
||||
const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
|
||||
unsigned long long 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 */
|
||||
DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u, nbWorkers=%u, cctxPool=%u)",
|
||||
(U32)pledgedSrcSize, params.nbWorkers, mtctx->cctxPool->totalCCtx);
|
||||
|
||||
/* params supposed partially fully validated at this point */
|
||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||
assert(mtctx->cctxPool->totalCCtx == params.nbWorkers);
|
||||
|
||||
/* init */
|
||||
if (params.jobSize == 0) {
|
||||
params.jobSize = 1U << ZSTDMT_computeTargetJobLog(params);
|
||||
}
|
||||
if (params.nbWorkers != mtctx->params.nbWorkers)
|
||||
CHECK_F( ZSTDMT_resize(mtctx, params.nbWorkers) );
|
||||
|
||||
if (params.jobSize > 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN;
|
||||
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 */
|
||||
@@ -1270,7 +1343,9 @@ size_t ZSTDMT_initCStream_internal(
|
||||
mtctx->targetPrefixSize = (size_t)1 << ZSTDMT_computeOverlapLog(params);
|
||||
DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(mtctx->targetPrefixSize>>10));
|
||||
mtctx->targetSectionSize = params.jobSize;
|
||||
if (mtctx->targetSectionSize < ZSTDMT_JOBSIZE_MIN) mtctx->targetSectionSize = ZSTDMT_JOBSIZE_MIN;
|
||||
if (mtctx->targetSectionSize == 0) {
|
||||
mtctx->targetSectionSize = 1ULL << ZSTDMT_computeTargetJobLog(params);
|
||||
}
|
||||
if (mtctx->targetSectionSize < mtctx->targetPrefixSize) mtctx->targetSectionSize = mtctx->targetPrefixSize; /* job size must be >= overlap size */
|
||||
DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(mtctx->targetSectionSize>>10), params.jobSize);
|
||||
DEBUGLOG(4, "inBuff Size : %u KB", (U32)(mtctx->targetSectionSize>>10));
|
||||
@@ -1312,7 +1387,7 @@ size_t ZSTDMT_initCStream_internal(
|
||||
mtctx->allJobsCompleted = 0;
|
||||
mtctx->consumed = 0;
|
||||
mtctx->produced = 0;
|
||||
if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params))
|
||||
if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize))
|
||||
return ERROR(memory_allocation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,11 @@ typedef enum {
|
||||
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */
|
||||
ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value);
|
||||
|
||||
/* ZSTDMT_getMTCtxParameter() :
|
||||
* Query the ZSTDMT_CCtx for a parameter value.
|
||||
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */
|
||||
ZSTDLIB_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned* value);
|
||||
|
||||
|
||||
/*! ZSTDMT_compressStream_generic() :
|
||||
* Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream()
|
||||
@@ -126,11 +131,6 @@ size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorker
|
||||
* 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.
|
||||
* mtctx must be valid */
|
||||
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.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* ******************************************************************
|
||||
Huffman decoder, part of New Generation Entropy library
|
||||
Copyright (C) 2013-2016, Yann Collet.
|
||||
huff0 huffman decoder,
|
||||
part of Finite State Entropy library
|
||||
Copyright (C) 2013-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
@@ -29,16 +30,15 @@
|
||||
|
||||
You can contact the author at :
|
||||
- FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
****************************************************************** */
|
||||
|
||||
/* **************************************************************
|
||||
* Dependencies
|
||||
****************************************************************/
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "bitstream.h" /* BIT_* */
|
||||
#include "compiler.h"
|
||||
#include "fse.h" /* header compression */
|
||||
#include "bitstream.h" /* BIT_* */
|
||||
#include "fse.h" /* to compress headers */
|
||||
#define HUF_STATIC_LINKING_ONLY
|
||||
#include "huf.h"
|
||||
#include "error_private.h"
|
||||
@@ -48,7 +48,6 @@
|
||||
* Error Management
|
||||
****************************************************************/
|
||||
#define HUF_isError ERR_isError
|
||||
#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_; }
|
||||
|
||||
|
||||
@@ -75,15 +74,15 @@ static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
|
||||
/*-***************************/
|
||||
/* single-symbol decoding */
|
||||
/*-***************************/
|
||||
typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */
|
||||
typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* 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_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
|
||||
{
|
||||
U32 tableLog = 0;
|
||||
U32 nbSymbols = 0;
|
||||
size_t iSize;
|
||||
void* const dtPtr = DTable + 1;
|
||||
HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
|
||||
HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr;
|
||||
|
||||
U32* rankVal;
|
||||
BYTE* huffWeight;
|
||||
@@ -96,7 +95,7 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize
|
||||
|
||||
if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
|
||||
|
||||
HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
|
||||
DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
|
||||
/* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
|
||||
|
||||
iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
|
||||
@@ -124,7 +123,7 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize
|
||||
U32 const w = huffWeight[n];
|
||||
U32 const length = (1 << w) >> 1;
|
||||
U32 u;
|
||||
HUF_DEltX2 D;
|
||||
HUF_DEltX1 D;
|
||||
D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
|
||||
for (u = rankVal[w]; u < rankVal[w] + length; u++)
|
||||
dt[u] = D;
|
||||
@@ -134,17 +133,15 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize
|
||||
return iSize;
|
||||
}
|
||||
|
||||
size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
|
||||
size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize)
|
||||
{
|
||||
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||
return HUF_readDTableX2_wksp(DTable, src, srcSize,
|
||||
return HUF_readDTableX1_wksp(DTable, src, srcSize,
|
||||
workSpace, sizeof(workSpace));
|
||||
}
|
||||
|
||||
typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* double-symbols decoding */
|
||||
|
||||
FORCE_INLINE_TEMPLATE BYTE
|
||||
HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog)
|
||||
HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog)
|
||||
{
|
||||
size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
|
||||
BYTE const c = dt[val].byte;
|
||||
@@ -152,44 +149,44 @@ HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog
|
||||
return c;
|
||||
}
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
|
||||
*ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
|
||||
#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \
|
||||
*ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
||||
#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
||||
#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
|
||||
if (MEM_64bits()) \
|
||||
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
||||
HUF_DECODE_SYMBOLX1_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)
|
||||
HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog)
|
||||
{
|
||||
BYTE* const pStart = p;
|
||||
|
||||
/* up to 4 symbols at a time */
|
||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) {
|
||||
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX1_1(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
|
||||
}
|
||||
|
||||
/* [0-3] symbols remaining */
|
||||
if (MEM_32bits())
|
||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd))
|
||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
|
||||
|
||||
/* no more data to retrieve from bitstream, no need to reload */
|
||||
while (p < pEnd)
|
||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
|
||||
|
||||
return pEnd-pStart;
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
HUF_decompress1X2_usingDTable_internal_body(
|
||||
HUF_decompress1X1_usingDTable_internal_body(
|
||||
void* dst, size_t dstSize,
|
||||
const void* cSrc, size_t cSrcSize,
|
||||
const HUF_DTable* DTable)
|
||||
@@ -197,14 +194,14 @@ HUF_decompress1X2_usingDTable_internal_body(
|
||||
BYTE* op = (BYTE*)dst;
|
||||
BYTE* const oend = op + dstSize;
|
||||
const void* dtPtr = DTable + 1;
|
||||
const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
|
||||
const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
|
||||
BIT_DStream_t bitD;
|
||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||
U32 const dtLog = dtd.tableLog;
|
||||
|
||||
CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
|
||||
|
||||
HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
|
||||
HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog);
|
||||
|
||||
if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
|
||||
|
||||
@@ -212,7 +209,7 @@ HUF_decompress1X2_usingDTable_internal_body(
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
HUF_decompress4X2_usingDTable_internal_body(
|
||||
HUF_decompress4X1_usingDTable_internal_body(
|
||||
void* dst, size_t dstSize,
|
||||
const void* cSrc, size_t cSrcSize,
|
||||
const HUF_DTable* DTable)
|
||||
@@ -224,7 +221,7 @@ HUF_decompress4X2_usingDTable_internal_body(
|
||||
BYTE* const ostart = (BYTE*) dst;
|
||||
BYTE* const oend = ostart + dstSize;
|
||||
const void* const dtPtr = DTable + 1;
|
||||
const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
|
||||
const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
|
||||
|
||||
/* Init */
|
||||
BIT_DStream_t bitD1;
|
||||
@@ -260,22 +257,22 @@ HUF_decompress4X2_usingDTable_internal_body(
|
||||
/* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */
|
||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||
while ( (endSignal==BIT_DStream_unfinished) && (op4<(oend-3)) ) {
|
||||
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX1_1(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX1_1(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX1_1(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX1_1(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX1_0(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX1_0(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX1_0(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX1_0(op4, &bitD4);
|
||||
BIT_reloadDStream(&bitD1);
|
||||
BIT_reloadDStream(&bitD2);
|
||||
BIT_reloadDStream(&bitD3);
|
||||
@@ -291,191 +288,10 @@ HUF_decompress4X2_usingDTable_internal_body(
|
||||
/* note : op4 supposed already verified within main loop */
|
||||
|
||||
/* finish bitStreams one by one */
|
||||
HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
|
||||
HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
|
||||
HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
|
||||
HUF_decodeStreamX2(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog);
|
||||
HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog);
|
||||
HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog);
|
||||
HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog);
|
||||
|
||||
/* check */
|
||||
{ U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
||||
@@ -493,7 +309,7 @@ typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
|
||||
const HUF_DTable *DTable);
|
||||
#if DYNAMIC_BMI2
|
||||
|
||||
#define X(fn) \
|
||||
#define HUF_DGEN(fn) \
|
||||
\
|
||||
static size_t fn##_default( \
|
||||
void* dst, size_t dstSize, \
|
||||
@@ -522,7 +338,7 @@ typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
|
||||
|
||||
#else
|
||||
|
||||
#define X(fn) \
|
||||
#define HUF_DGEN(fn) \
|
||||
static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
|
||||
size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
|
||||
{ \
|
||||
@@ -532,112 +348,114 @@ typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
|
||||
|
||||
#endif
|
||||
|
||||
X(HUF_decompress1X2_usingDTable_internal)
|
||||
X(HUF_decompress4X2_usingDTable_internal)
|
||||
X(HUF_decompress1X4_usingDTable_internal)
|
||||
X(HUF_decompress4X4_usingDTable_internal)
|
||||
|
||||
#undef X
|
||||
HUF_DGEN(HUF_decompress1X1_usingDTable_internal)
|
||||
HUF_DGEN(HUF_decompress4X1_usingDTable_internal)
|
||||
|
||||
|
||||
size_t HUF_decompress1X2_usingDTable(
|
||||
|
||||
size_t HUF_decompress1X1_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);
|
||||
return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
}
|
||||
|
||||
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||
size_t HUF_decompress1X1_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);
|
||||
size_t const hSize = HUF_readDTableX1_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);
|
||||
return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
|
||||
}
|
||||
|
||||
|
||||
size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||
size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||
const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||
return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
|
||||
return HUF_decompress1X1_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)
|
||||
size_t HUF_decompress1X1 (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);
|
||||
HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
|
||||
return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
|
||||
}
|
||||
|
||||
size_t HUF_decompress4X2_usingDTable(
|
||||
size_t HUF_decompress4X1_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_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
return HUF_decompress4X1_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,
|
||||
static size_t HUF_decompress4X1_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,
|
||||
size_t const hSize = HUF_readDTableX1_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_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
|
||||
return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
|
||||
}
|
||||
|
||||
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||
size_t HUF_decompress4X1_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);
|
||||
return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0);
|
||||
}
|
||||
|
||||
|
||||
size_t HUF_decompress4X2_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||
return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
|
||||
return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
|
||||
workSpace, sizeof(workSpace));
|
||||
}
|
||||
size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
|
||||
return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
||||
HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
|
||||
return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
||||
}
|
||||
|
||||
|
||||
/* *************************/
|
||||
/* double-symbols decoding */
|
||||
/* *************************/
|
||||
typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
|
||||
|
||||
/* HUF_fillDTableX4Level2() :
|
||||
typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */
|
||||
typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
|
||||
typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
|
||||
typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
|
||||
|
||||
|
||||
/* HUF_fillDTableX2Level2() :
|
||||
* `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
|
||||
static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 consumed,
|
||||
static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed,
|
||||
const U32* rankValOrigin, const int minWeight,
|
||||
const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
|
||||
U32 nbBitsBaseline, U16 baseSeq)
|
||||
{
|
||||
HUF_DEltX4 DElt;
|
||||
HUF_DEltX2 DElt;
|
||||
U32 rankVal[HUF_TABLELOG_MAX + 1];
|
||||
|
||||
/* get pre-calculated rankVal */
|
||||
@@ -672,10 +490,8 @@ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 co
|
||||
} }
|
||||
}
|
||||
|
||||
typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
|
||||
typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
|
||||
|
||||
static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog,
|
||||
static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
|
||||
const sortedSymbol_t* sortedList, const U32 sortedListSize,
|
||||
const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
|
||||
const U32 nbBitsBaseline)
|
||||
@@ -700,12 +516,12 @@ static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog,
|
||||
int minWeight = nbBits + scaleLog;
|
||||
if (minWeight < 1) minWeight = 1;
|
||||
sortedRank = rankStart[minWeight];
|
||||
HUF_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits,
|
||||
HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits,
|
||||
rankValOrigin[nbBits], minWeight,
|
||||
sortedList+sortedRank, sortedListSize-sortedRank,
|
||||
nbBitsBaseline, symbol);
|
||||
} else {
|
||||
HUF_DEltX4 DElt;
|
||||
HUF_DEltX2 DElt;
|
||||
MEM_writeLE16(&(DElt.sequence), symbol);
|
||||
DElt.nbBits = (BYTE)(nbBits);
|
||||
DElt.length = 1;
|
||||
@@ -717,7 +533,7 @@ static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog,
|
||||
}
|
||||
}
|
||||
|
||||
size_t HUF_readDTableX4_wksp(HUF_DTable* DTable, const void* src,
|
||||
size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src,
|
||||
size_t srcSize, void* workSpace,
|
||||
size_t wkspSize)
|
||||
{
|
||||
@@ -726,7 +542,7 @@ size_t HUF_readDTableX4_wksp(HUF_DTable* DTable, const void* src,
|
||||
U32 const maxTableLog = dtd.maxTableLog;
|
||||
size_t iSize;
|
||||
void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */
|
||||
HUF_DEltX4* const dt = (HUF_DEltX4*)dtPtr;
|
||||
HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
|
||||
U32 *rankStart;
|
||||
|
||||
rankValCol_t* rankVal;
|
||||
@@ -752,7 +568,7 @@ size_t HUF_readDTableX4_wksp(HUF_DTable* DTable, const void* src,
|
||||
rankStart = rankStart0 + 1;
|
||||
memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
|
||||
|
||||
HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
|
||||
DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
|
||||
if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||
/* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
|
||||
|
||||
@@ -806,7 +622,7 @@ size_t HUF_readDTableX4_wksp(HUF_DTable* DTable, const void* src,
|
||||
rankValPtr[w] = rankVal0[w] >> consumed;
|
||||
} } } }
|
||||
|
||||
HUF_fillDTableX4(dt, maxTableLog,
|
||||
HUF_fillDTableX2(dt, maxTableLog,
|
||||
sortedSymbol, sizeOfSort,
|
||||
rankStart0, rankVal, maxW,
|
||||
tableLog+1);
|
||||
@@ -817,112 +633,296 @@ size_t HUF_readDTableX4_wksp(HUF_DTable* DTable, const void* src,
|
||||
return iSize;
|
||||
}
|
||||
|
||||
size_t HUF_readDTableX4(HUF_DTable* DTable, const void* src, size_t srcSize)
|
||||
size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
|
||||
{
|
||||
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||
return HUF_readDTableX4_wksp(DTable, src, srcSize,
|
||||
return HUF_readDTableX2_wksp(DTable, src, srcSize,
|
||||
workSpace, sizeof(workSpace));
|
||||
}
|
||||
|
||||
size_t HUF_decompress1X4_usingDTable(
|
||||
|
||||
FORCE_INLINE_TEMPLATE U32
|
||||
HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
|
||||
{
|
||||
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
||||
memcpy(op, dt+val, 2);
|
||||
BIT_skipBits(DStream, dt[val].nbBits);
|
||||
return dt[val].length;
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE U32
|
||||
HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
|
||||
{
|
||||
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
||||
memcpy(op, dt+val, 1);
|
||||
if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
|
||||
else {
|
||||
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_SYMBOLX2_0(ptr, DStreamPtr) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
||||
if (MEM_64bits()) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
|
||||
HINT_INLINE size_t
|
||||
HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
|
||||
const HUF_DEltX2* 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_SYMBOLX2_2(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
||||
HUF_DECODE_SYMBOLX2_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_SYMBOLX2_0(p, bitDPtr);
|
||||
|
||||
while (p <= pEnd-2)
|
||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
|
||||
|
||||
if (p < pEnd)
|
||||
p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog);
|
||||
|
||||
return p-pStart;
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
HUF_decompress1X2_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_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
|
||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||
HUF_decodeStreamX2(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_decompress4X2_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_DEltX2* const dt = (const HUF_DEltX2*)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_SYMBOLX2_2(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
||||
HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
|
||||
HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
|
||||
HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
|
||||
HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
|
||||
|
||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||
}
|
||||
|
||||
/* 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_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
|
||||
HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
|
||||
HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
|
||||
HUF_decodeStreamX2(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;
|
||||
}
|
||||
}
|
||||
|
||||
HUF_DGEN(HUF_decompress1X2_usingDTable_internal)
|
||||
HUF_DGEN(HUF_decompress4X2_usingDTable_internal)
|
||||
|
||||
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 != 1) return ERROR(GENERIC);
|
||||
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
return HUF_decompress1X2_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_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_readDTableX4_wksp(DCtx, cSrc, cSrcSize,
|
||||
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_decompress1X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
|
||||
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
|
||||
}
|
||||
|
||||
|
||||
size_t HUF_decompress1X4_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||
size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
|
||||
const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||
return HUF_decompress1X4_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
|
||||
return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
|
||||
workSpace, sizeof(workSpace));
|
||||
}
|
||||
|
||||
size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_TABLELOG_MAX);
|
||||
return HUF_decompress1X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
||||
HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
|
||||
return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
||||
}
|
||||
|
||||
size_t HUF_decompress4X4_usingDTable(
|
||||
size_t HUF_decompress4X2_usingDTable(
|
||||
void* dst, size_t dstSize,
|
||||
const void* cSrc, size_t cSrcSize,
|
||||
const HUF_DTable* DTable)
|
||||
{
|
||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||
if (dtd.tableType != 1) return ERROR(GENERIC);
|
||||
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
return HUF_decompress4X2_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,
|
||||
static size_t HUF_decompress4X2_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 hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize,
|
||||
size_t 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_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
|
||||
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
|
||||
}
|
||||
|
||||
size_t HUF_decompress4X4_DCtx_wksp(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,
|
||||
void* workSpace, size_t wkspSize)
|
||||
{
|
||||
return HUF_decompress4X4_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0);
|
||||
return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0);
|
||||
}
|
||||
|
||||
|
||||
size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||
size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||
const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
|
||||
return HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
|
||||
return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
|
||||
workSpace, sizeof(workSpace));
|
||||
}
|
||||
|
||||
size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_TABLELOG_MAX);
|
||||
return HUF_decompress4X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
||||
HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
|
||||
return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
|
||||
}
|
||||
|
||||
|
||||
/* ********************************/
|
||||
/* Generic decompression selector */
|
||||
/* ********************************/
|
||||
/* ***********************************/
|
||||
/* Universal decompression selectors */
|
||||
/* ***********************************/
|
||||
|
||||
size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
|
||||
const void* cSrc, size_t cSrcSize,
|
||||
const HUF_DTable* DTable)
|
||||
{
|
||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||
return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
|
||||
HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
|
||||
HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
}
|
||||
|
||||
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
|
||||
@@ -930,8 +930,8 @@ size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
|
||||
const HUF_DTable* DTable)
|
||||
{
|
||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||
return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
|
||||
HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
|
||||
HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -960,12 +960,12 @@ static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, qu
|
||||
/** HUF_selectDecoder() :
|
||||
* Tells which decoder is likely to decode faster,
|
||||
* based on a set of pre-computed metrics.
|
||||
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
||||
* @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
|
||||
* Assumption : 0 < dstSize <= 128 KB */
|
||||
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
|
||||
{
|
||||
assert(dstSize > 0);
|
||||
assert(dstSize <= 128 KB);
|
||||
assert(dstSize <= 128*1024);
|
||||
/* decoder timing evaluation */
|
||||
{ U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */
|
||||
U32 const D256 = (U32)(dstSize >> 8);
|
||||
@@ -980,7 +980,7 @@ typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc,
|
||||
|
||||
size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||
{
|
||||
static const decompressionAlgo decompress[2] = { HUF_decompress4X2, HUF_decompress4X4 };
|
||||
static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 };
|
||||
|
||||
/* validation checks */
|
||||
if (dstSize == 0) return ERROR(dstSize_tooSmall);
|
||||
@@ -1002,8 +1002,8 @@ size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const
|
||||
if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
|
||||
|
||||
{ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
||||
return algoNb ? HUF_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
|
||||
HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
|
||||
return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
|
||||
HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,8 +1025,8 @@ size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst,
|
||||
if (cSrcSize == 0) return ERROR(corruption_detected);
|
||||
|
||||
{ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
||||
return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize):
|
||||
HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
|
||||
return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize):
|
||||
HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,9 +1041,9 @@ size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||
if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
|
||||
|
||||
{ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
||||
return algoNb ? HUF_decompress1X4_DCtx_wksp(dctx, dst, dstSize, cSrc,
|
||||
return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
|
||||
cSrcSize, workSpace, wkspSize):
|
||||
HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
|
||||
HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
|
||||
cSrcSize, workSpace, wkspSize);
|
||||
}
|
||||
}
|
||||
@@ -1060,27 +1060,27 @@ size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||
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);
|
||||
return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
|
||||
HUF_decompress1X1_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)
|
||||
size_t HUF_decompress1X1_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);
|
||||
size_t const hSize = HUF_readDTableX1_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);
|
||||
return HUF_decompress1X1_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);
|
||||
return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
|
||||
HUF_decompress4X1_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)
|
||||
@@ -1090,7 +1090,7 @@ size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t ds
|
||||
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);
|
||||
return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) :
|
||||
HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,17 @@
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
* NO_FORWARD_PROGRESS_MAX :
|
||||
* maximum allowed nb of calls to ZSTD_decompressStream() and ZSTD_decompress_generic()
|
||||
* without any forward progress
|
||||
* (defined as: no byte read from input, and no byte flushed to output)
|
||||
* before triggering an error.
|
||||
*/
|
||||
#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
|
||||
# define ZSTD_NO_FORWARD_PROGRESS_MAX 16
|
||||
#endif
|
||||
|
||||
/*-*******************************************************
|
||||
* Dependencies
|
||||
*********************************************************/
|
||||
@@ -115,8 +126,8 @@ struct ZSTD_DCtx_s
|
||||
const HUF_DTable* HUFptr;
|
||||
ZSTD_entropyDTables_t entropy;
|
||||
const void* previousDstEnd; /* detect continuity */
|
||||
const void* base; /* start of current segment */
|
||||
const void* vBase; /* virtual start of previous segment if it was just before current one */
|
||||
const void* prefixStart; /* start of current segment */
|
||||
const void* virtualStart; /* virtual start of previous segment if it was just before current one */
|
||||
const void* dictEnd; /* end of previous segment */
|
||||
size_t expected;
|
||||
ZSTD_frameHeader fParams;
|
||||
@@ -153,6 +164,7 @@ struct ZSTD_DCtx_s
|
||||
U32 previousLegacyVersion;
|
||||
U32 legacyVersion;
|
||||
U32 hostageByte;
|
||||
int noForwardProgress;
|
||||
|
||||
/* workspace */
|
||||
BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH];
|
||||
@@ -192,6 +204,9 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||
dctx->inBuffSize = 0;
|
||||
dctx->outBuffSize = 0;
|
||||
dctx->streamStage = zdss_init;
|
||||
dctx->legacyContext = NULL;
|
||||
dctx->previousLegacyVersion = 0;
|
||||
dctx->noForwardProgress = 0;
|
||||
dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||
}
|
||||
|
||||
@@ -215,8 +230,6 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
|
||||
{ ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
|
||||
if (!dctx) return NULL;
|
||||
dctx->customMem = customMem;
|
||||
dctx->legacyContext = NULL;
|
||||
dctx->previousLegacyVersion = 0;
|
||||
ZSTD_initDCtx_internal(dctx);
|
||||
return dctx;
|
||||
}
|
||||
@@ -298,20 +311,21 @@ static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZST
|
||||
|
||||
/** ZSTD_frameHeaderSize() :
|
||||
* srcSize must be >= ZSTD_frameHeaderSize_prefix.
|
||||
* @return : size of the Frame Header */
|
||||
* @return : size of the Frame Header,
|
||||
* or an error code (if srcSize is too small) */
|
||||
size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
|
||||
}
|
||||
|
||||
|
||||
/** ZSTD_getFrameHeader_internal() :
|
||||
/** ZSTD_getFrameHeader_advanced() :
|
||||
* decode Frame Header, or require larger `srcSize`.
|
||||
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
|
||||
* @return : 0, `zfhPtr` is correctly filled,
|
||||
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
||||
* or an error code, which can be tested using ZSTD_isError() */
|
||||
static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
|
||||
size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
size_t const minInputSize = ZSTD_startingInputLength(format);
|
||||
@@ -394,7 +408,7 @@ static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void*
|
||||
* or an error code, which can be tested using ZSTD_isError() */
|
||||
size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_getFrameHeader_internal(zfhPtr, src, srcSize, ZSTD_f_zstd1);
|
||||
return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
|
||||
}
|
||||
|
||||
|
||||
@@ -491,7 +505,7 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
|
||||
* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
|
||||
static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
|
||||
{
|
||||
size_t const result = ZSTD_getFrameHeader_internal(&(dctx->fParams), src, headerSize, dctx->format);
|
||||
size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
|
||||
if (ZSTD_isError(result)) return result; /* invalid header */
|
||||
if (result>0) return ERROR(srcSize_wrong); /* headerSize too small */
|
||||
if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
|
||||
@@ -594,7 +608,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
||||
HUF_decompress1X_usingDTable_bmi2(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr, dctx->bmi2) :
|
||||
HUF_decompress4X_usingDTable_bmi2(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr, dctx->bmi2) ) :
|
||||
( singleStream ?
|
||||
HUF_decompress1X2_DCtx_wksp_bmi2(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize,
|
||||
HUF_decompress1X1_DCtx_wksp_bmi2(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize,
|
||||
dctx->entropy.workspace, sizeof(dctx->entropy.workspace), dctx->bmi2) :
|
||||
HUF_decompress4X_hufOnly_wksp_bmi2(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize,
|
||||
dctx->entropy.workspace, sizeof(dctx->entropy.workspace), dctx->bmi2))))
|
||||
@@ -1075,7 +1089,7 @@ HINT_INLINE
|
||||
size_t ZSTD_execSequence(BYTE* op,
|
||||
BYTE* const oend, seq_t sequence,
|
||||
const BYTE** litPtr, const BYTE* const litLimit,
|
||||
const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
|
||||
const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd)
|
||||
{
|
||||
BYTE* const oLitEnd = op + sequence.litLength;
|
||||
size_t const sequenceLength = sequence.litLength + sequence.matchLength;
|
||||
@@ -1087,7 +1101,7 @@ size_t ZSTD_execSequence(BYTE* op,
|
||||
/* check */
|
||||
if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
|
||||
if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
|
||||
if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
|
||||
if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd);
|
||||
|
||||
/* copy Literals */
|
||||
ZSTD_copy8(op, *litPtr);
|
||||
@@ -1097,11 +1111,11 @@ size_t ZSTD_execSequence(BYTE* op,
|
||||
*litPtr = iLitEnd; /* update for next sequence */
|
||||
|
||||
/* copy Match */
|
||||
if (sequence.offset > (size_t)(oLitEnd - base)) {
|
||||
if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
|
||||
/* offset beyond prefix -> go into extDict */
|
||||
if (sequence.offset > (size_t)(oLitEnd - vBase))
|
||||
if (sequence.offset > (size_t)(oLitEnd - virtualStart))
|
||||
return ERROR(corruption_detected);
|
||||
match = dictEnd + (match - base);
|
||||
match = dictEnd + (match - prefixStart);
|
||||
if (match + sequence.matchLength <= dictEnd) {
|
||||
memmove(oLitEnd, match, sequence.matchLength);
|
||||
return sequenceLength;
|
||||
@@ -1111,7 +1125,7 @@ size_t ZSTD_execSequence(BYTE* op,
|
||||
memmove(oLitEnd, match, length1);
|
||||
op = oLitEnd + length1;
|
||||
sequence.matchLength -= length1;
|
||||
match = base;
|
||||
match = prefixStart;
|
||||
if (op > oend_w || sequence.matchLength < MINMATCH) {
|
||||
U32 i;
|
||||
for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
|
||||
@@ -1354,10 +1368,10 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
||||
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 prefixStart = (const BYTE*) (dctx->prefixStart);
|
||||
const BYTE* const vBase = (const BYTE*) (dctx->virtualStart);
|
||||
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
||||
DEBUGLOG(5, "ZSTD_decompressSequences");
|
||||
DEBUGLOG(5, "ZSTD_decompressSequences_body");
|
||||
|
||||
/* Regen sequences */
|
||||
if (nbSeq) {
|
||||
@@ -1372,14 +1386,14 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
||||
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);
|
||||
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, 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);
|
||||
DEBUGLOG(5, "ZSTD_decompressSequences_body: 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]); }
|
||||
@@ -1498,8 +1512,8 @@ ZSTD_decompressSequencesLong_body(
|
||||
BYTE* op = ostart;
|
||||
const BYTE* litPtr = dctx->litPtr;
|
||||
const BYTE* const litEnd = litPtr + dctx->litSize;
|
||||
const BYTE* const prefixStart = (const BYTE*) (dctx->base);
|
||||
const BYTE* const dictStart = (const BYTE*) (dctx->vBase);
|
||||
const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
|
||||
const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart);
|
||||
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
||||
|
||||
/* Regen sequences */
|
||||
@@ -1701,8 +1715,8 @@ static void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
|
||||
{
|
||||
if (dst != dctx->previousDstEnd) { /* not contiguous */
|
||||
dctx->dictEnd = dctx->previousDstEnd;
|
||||
dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
|
||||
dctx->base = dst;
|
||||
dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
|
||||
dctx->prefixStart = dst;
|
||||
dctx->previousDstEnd = dst;
|
||||
}
|
||||
}
|
||||
@@ -1881,6 +1895,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
const ZSTD_DDict* ddict)
|
||||
{
|
||||
void* const dststart = dst;
|
||||
int moreThan1Frame = 0;
|
||||
assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */
|
||||
|
||||
if (ddict) {
|
||||
@@ -1889,7 +1904,6 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
}
|
||||
|
||||
while (srcSize >= ZSTD_frameHeaderSize_prefix) {
|
||||
U32 magicNumber;
|
||||
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
if (ZSTD_isLegacy(src, srcSize)) {
|
||||
@@ -1911,10 +1925,9 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
}
|
||||
#endif
|
||||
|
||||
magicNumber = MEM_readLE32(src);
|
||||
DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
|
||||
(U32)magicNumber, (U32)ZSTD_MAGICNUMBER);
|
||||
if (magicNumber != ZSTD_MAGICNUMBER) {
|
||||
{ U32 const magicNumber = MEM_readLE32(src);
|
||||
DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
|
||||
(U32)magicNumber, (U32)ZSTD_MAGICNUMBER);
|
||||
if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||
size_t skippableSize;
|
||||
if (srcSize < ZSTD_skippableHeaderSize)
|
||||
@@ -1926,9 +1939,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
src = (const BYTE *)src + skippableSize;
|
||||
srcSize -= skippableSize;
|
||||
continue;
|
||||
}
|
||||
return ERROR(prefix_unknown);
|
||||
}
|
||||
} }
|
||||
|
||||
if (ddict) {
|
||||
/* we were called from ZSTD_decompress_usingDDict */
|
||||
@@ -1942,11 +1953,25 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
|
||||
{ const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
|
||||
&src, &srcSize);
|
||||
if ( (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
|
||||
&& (moreThan1Frame==1) ) {
|
||||
/* at least one frame successfully completed,
|
||||
* but following bytes are garbage :
|
||||
* it's more likely to be a srcSize error,
|
||||
* specifying more bytes than compressed size of frame(s).
|
||||
* This error message replaces ERROR(prefix_unknown),
|
||||
* which would be confusing, as the first header is actually correct.
|
||||
* Note that one could be unlucky, it might be a corruption error instead,
|
||||
* happening right at the place where we expect zstd magic bytes.
|
||||
* But this is _much_ less likely than a srcSize field error. */
|
||||
return ERROR(srcSize_wrong);
|
||||
}
|
||||
if (ZSTD_isError(res)) return res;
|
||||
/* no need to bound check, ZSTD_decompressFrame already has */
|
||||
dst = (BYTE*)dst + res;
|
||||
dstCapacity -= res;
|
||||
}
|
||||
moreThan1Frame = 1;
|
||||
} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
|
||||
|
||||
if (srcSize) return ERROR(srcSize_wrong); /* input not entirely consumed */
|
||||
@@ -1980,6 +2005,7 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr
|
||||
return regenSize;
|
||||
#else /* stack mode */
|
||||
ZSTD_DCtx dctx;
|
||||
ZSTD_initDCtx_internal(&dctx);
|
||||
return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
|
||||
#endif
|
||||
}
|
||||
@@ -2159,8 +2185,8 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
|
||||
{
|
||||
dctx->dictEnd = dctx->previousDstEnd;
|
||||
dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
|
||||
dctx->base = dict;
|
||||
dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
|
||||
dctx->prefixStart = dict;
|
||||
dctx->previousDstEnd = (const char*)dict + dictSize;
|
||||
return 0;
|
||||
}
|
||||
@@ -2177,7 +2203,7 @@ static size_t ZSTD_loadEntropy(ZSTD_entropyDTables_t* entropy, const void* const
|
||||
dictPtr += 8; /* skip header = magic + dictID */
|
||||
|
||||
|
||||
{ size_t const hSize = HUF_readDTableX4_wksp(
|
||||
{ size_t const hSize = HUF_readDTableX2_wksp(
|
||||
entropy->hufTable, dictPtr, dictEnd - dictPtr,
|
||||
entropy->workspace, sizeof(entropy->workspace));
|
||||
if (HUF_isError(hSize)) return ERROR(dictionary_corrupted);
|
||||
@@ -2264,8 +2290,8 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
dctx->decodedSize = 0;
|
||||
dctx->previousDstEnd = NULL;
|
||||
dctx->base = NULL;
|
||||
dctx->vBase = NULL;
|
||||
dctx->prefixStart = NULL;
|
||||
dctx->virtualStart = NULL;
|
||||
dctx->dictEnd = NULL;
|
||||
dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
||||
dctx->litEntropy = dctx->fseEntropy = 0;
|
||||
@@ -2315,8 +2341,8 @@ size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddi
|
||||
CHECK_F( ZSTD_decompressBegin(dstDCtx) );
|
||||
if (ddict) { /* support begin on NULL */
|
||||
dstDCtx->dictID = ddict->dictID;
|
||||
dstDCtx->base = ddict->dictContent;
|
||||
dstDCtx->vBase = ddict->dictContent;
|
||||
dstDCtx->prefixStart = ddict->dictContent;
|
||||
dstDCtx->virtualStart = ddict->dictContent;
|
||||
dstDCtx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
|
||||
dstDCtx->previousDstEnd = dstDCtx->dictEnd;
|
||||
if (ddict->entropyPresent) {
|
||||
@@ -2607,6 +2633,7 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_initDStream_usingDict");
|
||||
zds->streamStage = zdss_init;
|
||||
zds->noForwardProgress = 0;
|
||||
CHECK_F( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) );
|
||||
return ZSTD_frameHeaderSize_prefix;
|
||||
}
|
||||
@@ -2767,7 +2794,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
return hint;
|
||||
} }
|
||||
#endif
|
||||
{ size_t const hSize = ZSTD_getFrameHeader_internal(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
|
||||
{ size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
|
||||
DEBUGLOG(5, "header size : %u", (U32)hSize);
|
||||
if (ZSTD_isError(hSize)) {
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
|
||||
@@ -2947,8 +2974,18 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
} }
|
||||
|
||||
/* result */
|
||||
input->pos += (size_t)(ip-istart);
|
||||
output->pos += (size_t)(op-ostart);
|
||||
input->pos = (size_t)(ip - (const char*)(input->src));
|
||||
output->pos = (size_t)(op - (char*)(output->dst));
|
||||
if ((ip==istart) && (op==ostart)) { /* no forward progress */
|
||||
zds->noForwardProgress ++;
|
||||
if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
|
||||
if (op==oend) return ERROR(dstSize_tooSmall);
|
||||
if (ip==iend) return ERROR(srcSize_wrong);
|
||||
assert(0);
|
||||
}
|
||||
} else {
|
||||
zds->noForwardProgress = 0;
|
||||
}
|
||||
{ size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
|
||||
if (!nextSrcSizeHint) { /* frame fully decoded */
|
||||
if (zds->outEnd == zds->outStart) { /* output fully flushed */
|
||||
|
||||
@@ -581,10 +581,17 @@ static int COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
|
||||
for (i = 0; i < ctx->suffixSize; ++i) {
|
||||
ctx->suffix[i] = i;
|
||||
}
|
||||
/* qsort doesn't take an opaque pointer, so pass as a global */
|
||||
/* qsort doesn't take an opaque pointer, so pass as a global.
|
||||
* On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is.
|
||||
*/
|
||||
g_ctx = ctx;
|
||||
#if defined(__OpenBSD__)
|
||||
mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32),
|
||||
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
|
||||
#else
|
||||
qsort(ctx->suffix, ctx->suffixSize, sizeof(U32),
|
||||
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
|
||||
#endif
|
||||
}
|
||||
DISPLAYLEVEL(2, "Computing frequencies\n");
|
||||
/* For each dmer group (group of positions with the same first d bytes):
|
||||
@@ -613,7 +620,7 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
|
||||
/* Divide the data up into epochs of equal size.
|
||||
* We will select at least one segment from each epoch.
|
||||
*/
|
||||
const U32 epochs = (U32)(dictBufferCapacity / parameters.k);
|
||||
const U32 epochs = MAX(1, (U32)(dictBufferCapacity / parameters.k / 4));
|
||||
const U32 epochSize = (U32)(ctx->suffixSize / epochs);
|
||||
size_t epoch;
|
||||
DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", epochs,
|
||||
|
||||
@@ -724,7 +724,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
|
||||
memset(repOffset, 0, sizeof(repOffset));
|
||||
repOffset[1] = repOffset[4] = repOffset[8] = 1;
|
||||
memset(bestRepOffset, 0, sizeof(bestRepOffset));
|
||||
if (compressionLevel<=0) compressionLevel = g_compressionLevel_default;
|
||||
if (compressionLevel==0) compressionLevel = g_compressionLevel_default;
|
||||
params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize);
|
||||
{ size_t const beginResult = ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params, 0);
|
||||
if (ZSTD_isError(beginResult)) {
|
||||
@@ -873,7 +873,7 @@ size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,
|
||||
size_t hSize;
|
||||
#define HBUFFSIZE 256 /* should prove large enough for all entropy headers */
|
||||
BYTE header[HBUFFSIZE];
|
||||
int const compressionLevel = (params.compressionLevel <= 0) ? g_compressionLevel_default : params.compressionLevel;
|
||||
int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
|
||||
U32 const notificationLevel = params.notificationLevel;
|
||||
|
||||
/* check conditions */
|
||||
@@ -918,7 +918,7 @@ size_t ZDICT_addEntropyTablesFromBuffer_advanced(void* dictBuffer, size_t dictCo
|
||||
const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
|
||||
ZDICT_params_t params)
|
||||
{
|
||||
int const compressionLevel = (params.compressionLevel <= 0) ? g_compressionLevel_default : params.compressionLevel;
|
||||
int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
|
||||
U32 const notificationLevel = params.notificationLevel;
|
||||
size_t hSize = 8;
|
||||
|
||||
@@ -1089,8 +1089,8 @@ size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
|
||||
params.steps = 4;
|
||||
/* Default to level 6 since no compression level information is available */
|
||||
params.zParams.compressionLevel = 6;
|
||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
|
||||
params.zParams.notificationLevel = ZSTD_DEBUG;
|
||||
#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1)
|
||||
params.zParams.notificationLevel = DEBUGLEVEL;
|
||||
#endif
|
||||
return ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, dictBufferCapacity,
|
||||
samplesBuffer, samplesSizes, nbSamples,
|
||||
|
||||
@@ -9,14 +9,19 @@
|
||||
*/
|
||||
|
||||
|
||||
/*- Dependencies -*/
|
||||
/******************************************
|
||||
* Includes
|
||||
******************************************/
|
||||
#include <stddef.h> /* size_t, ptrdiff_t */
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "zstd_v04.h"
|
||||
#include "error_private.h"
|
||||
|
||||
|
||||
/* ******************************************************************
|
||||
mem.h
|
||||
****************************************************************** */
|
||||
* mem.h
|
||||
*******************************************************************/
|
||||
#ifndef MEM_H_MODULE
|
||||
#define MEM_H_MODULE
|
||||
|
||||
@@ -24,12 +29,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/******************************************
|
||||
* Includes
|
||||
******************************************/
|
||||
#include <stddef.h> /* size_t, ptrdiff_t */
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
|
||||
/******************************************
|
||||
* Compiler-specific
|
||||
@@ -75,38 +74,9 @@ extern "C" {
|
||||
/*-*************************************
|
||||
* 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 */
|
||||
#include "debug.h"
|
||||
#ifndef assert
|
||||
# define assert(condition) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -266,14 +236,6 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr)
|
||||
#ifndef ZSTD_STATIC_H
|
||||
#define ZSTD_STATIC_H
|
||||
|
||||
/* The objects defined into this file shall be considered experimental.
|
||||
* They are not considered stable, as their prototype may change in the future.
|
||||
* You can use them for tests, provide feedback, or if you can endure risks of future changes.
|
||||
*/
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* *************************************
|
||||
* Types
|
||||
@@ -360,9 +322,6 @@ static size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstS
|
||||
*/
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* ZSTD_STATIC_H */
|
||||
@@ -375,10 +334,6 @@ static size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstS
|
||||
#ifndef ZSTD_CCOMMON_H_MODULE
|
||||
#define ZSTD_CCOMMON_H_MODULE
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* *************************************
|
||||
* Common macros
|
||||
***************************************/
|
||||
@@ -450,10 +405,6 @@ static void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
|
||||
}
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* ******************************************************************
|
||||
FSE : Finite State Entropy coder
|
||||
@@ -2991,7 +2942,7 @@ static size_t ZSTD_execSequence(BYTE* op,
|
||||
}
|
||||
else
|
||||
{
|
||||
ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */
|
||||
ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8, but must be signed */
|
||||
}
|
||||
return sequenceLength;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ extern "C" {
|
||||
/*------ Version ------*/
|
||||
#define ZSTD_VERSION_MAJOR 1
|
||||
#define ZSTD_VERSION_MINOR 3
|
||||
#define ZSTD_VERSION_RELEASE 4
|
||||
#define ZSTD_VERSION_RELEASE 5
|
||||
|
||||
#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 */
|
||||
@@ -70,6 +70,12 @@ ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll versio
|
||||
#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)
|
||||
ZSTDLIB_API const char* ZSTD_versionString(void); /* added in v1.3.0 */
|
||||
|
||||
/***************************************
|
||||
* Default constant
|
||||
***************************************/
|
||||
#ifndef ZSTD_CLEVEL_DEFAULT
|
||||
# define ZSTD_CLEVEL_DEFAULT 3
|
||||
#endif
|
||||
|
||||
/***************************************
|
||||
* Simple API
|
||||
@@ -96,7 +102,7 @@ ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
|
||||
* `src` should point to the start of a ZSTD encoded frame.
|
||||
* `srcSize` must be at least as large as the frame header.
|
||||
* hint : any size >= `ZSTD_frameHeaderSize_max` is large enough.
|
||||
* @return : - decompressed size of the frame in `src`, if known
|
||||
* @return : - decompressed size of `src` frame content, if known
|
||||
* - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
|
||||
* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small)
|
||||
* note 1 : a 0 return value means the frame is valid but "empty".
|
||||
@@ -106,7 +112,8 @@ ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
|
||||
* Optionally, application can rely on some implicit limit,
|
||||
* as ZSTD_decompress() only needs an upper bound of decompressed size.
|
||||
* (For example, data could be necessarily cut into blocks <= 16 KB).
|
||||
* note 3 : decompressed size is always present when compression is done with ZSTD_compress()
|
||||
* note 3 : decompressed size is always present when compression is completed using single-pass functions,
|
||||
* such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict().
|
||||
* note 4 : decompressed size can be very large (64-bits value),
|
||||
* potentially larger than what local system can handle as a single memory segment.
|
||||
* In which case, it's necessary to use streaming mode to decompress data.
|
||||
@@ -123,8 +130,7 @@ ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t
|
||||
* Both functions work the same way, but ZSTD_getDecompressedSize() blends
|
||||
* "empty", "unknown" and "error" results to the same return value (0),
|
||||
* while ZSTD_getFrameContentSize() gives them separate return values.
|
||||
* `src` is the start of a zstd compressed frame.
|
||||
* @return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise. */
|
||||
* @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */
|
||||
ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
|
||||
|
||||
|
||||
@@ -272,33 +278,38 @@ typedef struct ZSTD_outBuffer_s {
|
||||
* since it will play nicer with system's memory, by re-using already allocated memory.
|
||||
* Use one separate ZSTD_CStream per thread for parallel execution.
|
||||
*
|
||||
* Start a new compression by initializing ZSTD_CStream.
|
||||
* Start a new compression by initializing ZSTD_CStream context.
|
||||
* Use ZSTD_initCStream() to start a new compression operation.
|
||||
* Use ZSTD_initCStream_usingDict() or ZSTD_initCStream_usingCDict() for a compression which requires a dictionary (experimental section)
|
||||
* Use variants ZSTD_initCStream_usingDict() or ZSTD_initCStream_usingCDict() for streaming with dictionary (experimental section)
|
||||
*
|
||||
* Use ZSTD_compressStream() repetitively to consume input stream.
|
||||
* The function will automatically update both `pos` fields.
|
||||
* Note that it may not consume the entire input, in which case `pos < size`,
|
||||
* and it's up to the caller to present again remaining data.
|
||||
* Use ZSTD_compressStream() as many times as necessary to consume input stream.
|
||||
* The function will automatically update both `pos` fields within `input` and `output`.
|
||||
* Note that the function may not consume the entire input,
|
||||
* for example, because the output buffer is already full,
|
||||
* in which case `input.pos < input.size`.
|
||||
* The caller must check if input has been entirely consumed.
|
||||
* If not, the caller must make some room to receive more compressed data,
|
||||
* typically by emptying output buffer, or allocating a new output buffer,
|
||||
* and then present again remaining input data.
|
||||
* @return : a size hint, preferred nb of bytes to use as input for next function call
|
||||
* or an error code, which can be tested using ZSTD_isError().
|
||||
* Note 1 : it's just a hint, to help latency a little, any other value will work fine.
|
||||
* Note 2 : size hint is guaranteed to be <= ZSTD_CStreamInSize()
|
||||
*
|
||||
* At any moment, it's possible to flush whatever data remains within internal buffer, using ZSTD_flushStream().
|
||||
* `output->pos` will be updated.
|
||||
* Note that some content might still be left within internal buffer if `output->size` is too small.
|
||||
* @return : nb of bytes still present within internal buffer (0 if it's empty)
|
||||
* At any moment, it's possible to flush whatever data might remain stuck within internal buffer,
|
||||
* using ZSTD_flushStream(). `output->pos` will be updated.
|
||||
* Note that, if `output->size` is too small, a single invocation of ZSTD_flushStream() might not be enough (return code > 0).
|
||||
* In which case, make some room to receive more compressed data, and call again ZSTD_flushStream().
|
||||
* @return : 0 if internal buffers are entirely flushed,
|
||||
* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
|
||||
* or an error code, which can be tested using ZSTD_isError().
|
||||
*
|
||||
* ZSTD_endStream() instructs to finish a frame.
|
||||
* It will perform a flush and write frame epilogue.
|
||||
* The epilogue is required for decoders to consider a frame completed.
|
||||
* ZSTD_endStream() may not be able to flush full data if `output->size` is too small.
|
||||
* In which case, call again ZSTD_endStream() to complete the flush.
|
||||
* flush() operation is the same, and follows same rules as ZSTD_flushStream().
|
||||
* @return : 0 if frame fully completed and fully flushed,
|
||||
or >0 if some data is still present within internal buffer
|
||||
(value is minimum size estimation for remaining data to flush, but it could be more)
|
||||
* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
|
||||
* or an error code, which can be tested using ZSTD_isError().
|
||||
*
|
||||
* *******************************************************************/
|
||||
@@ -390,7 +401,6 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output
|
||||
#define ZSTD_SEARCHLOG_MIN 1
|
||||
#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_TARGETLENGTH_MIN 1 /* only used by btopt, btultra and btfast */
|
||||
#define ZSTD_LDM_MINMATCH_MIN 4
|
||||
#define ZSTD_LDM_MINMATCH_MAX 4096
|
||||
#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
|
||||
@@ -479,10 +489,10 @@ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize)
|
||||
* however it does mean that all frame data must be present and valid. */
|
||||
ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize);
|
||||
|
||||
/*! ZSTD_frameHeaderSize() :
|
||||
* `src` should point to the start of a ZSTD frame
|
||||
* `srcSize` must be >= ZSTD_frameHeaderSize_prefix.
|
||||
* @return : size of the Frame Header */
|
||||
/** ZSTD_frameHeaderSize() :
|
||||
* srcSize must be >= ZSTD_frameHeaderSize_prefix.
|
||||
* @return : size of the Frame Header,
|
||||
* or an error code (if srcSize is too small) */
|
||||
ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
|
||||
|
||||
|
||||
@@ -880,6 +890,11 @@ typedef struct {
|
||||
unsigned dictID;
|
||||
unsigned checksumFlag;
|
||||
} ZSTD_frameHeader;
|
||||
/** ZSTD_getFrameHeader() :
|
||||
* decode Frame Header, or requires larger `srcSize`.
|
||||
* @return : 0, `zfhPtr` is correctly filled,
|
||||
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
||||
* or an error code, which can be tested using ZSTD_isError() */
|
||||
ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */
|
||||
ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */
|
||||
|
||||
@@ -901,23 +916,15 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
||||
/** New advanced API (experimental) */
|
||||
/* ============================================ */
|
||||
|
||||
/* notes on API design :
|
||||
* In this proposal, parameters are pushed one by one into an existing context,
|
||||
* and then applied on all subsequent compression jobs.
|
||||
* When no parameter is ever provided, CCtx is created with compression level ZSTD_CLEVEL_DEFAULT.
|
||||
/* API design :
|
||||
* In this advanced API, parameters are pushed one by one into an existing context,
|
||||
* using ZSTD_CCtx_set*() functions.
|
||||
* Pushed parameters are sticky : they are applied to next job, and any subsequent job.
|
||||
* It's possible to reset parameters to "default" using ZSTD_CCtx_reset().
|
||||
* Important : "sticky" parameters only work with `ZSTD_compress_generic()` !
|
||||
* For any other entry point, "sticky" parameters are ignored !
|
||||
*
|
||||
* This API is intended to replace all others advanced / experimental API entry points.
|
||||
* But it stands a reasonable chance to become "stable", after a reasonable testing period.
|
||||
*/
|
||||
|
||||
/* note on naming convention :
|
||||
* Initially, the API favored names like ZSTD_setCCtxParameter() .
|
||||
* In this proposal, convention is changed towards ZSTD_CCtx_setParameter() .
|
||||
* The main driver is that it identifies more clearly the target object type.
|
||||
* It feels clearer when considering multiple targets :
|
||||
* ZSTD_CDict_setParameter() (rather than ZSTD_setCDictParameter())
|
||||
* ZSTD_CCtxParams_setParameter() (rather than ZSTD_setCCtxParamsParameter() )
|
||||
* etc...
|
||||
*/
|
||||
|
||||
/* note on enum design :
|
||||
@@ -947,7 +954,7 @@ typedef enum {
|
||||
/* compression parameters */
|
||||
ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
|
||||
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
||||
* Special: value 0 means "do not change cLevel".
|
||||
* Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT.
|
||||
* 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. */
|
||||
@@ -956,16 +963,19 @@ typedef enum {
|
||||
* Special: value 0 means "use default windowLog".
|
||||
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
||||
* 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 initial probe table, as a power of 2.
|
||||
* Resulting table size is (1 << (hashLog+2)).
|
||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
||||
* Larger tables improve compression ratio of strategies <= dFast,
|
||||
* and improve speed of strategies > dFast.
|
||||
* 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 multi-probe search table, as a power of 2.
|
||||
* Resulting table size is (1 << (chainLog+2)).
|
||||
* Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX.
|
||||
* Larger tables result in better and slower compression.
|
||||
* This parameter is useless when using "fast" strategy.
|
||||
* Note it's still useful when using "dfast" strategy,
|
||||
* in which case it defines a secondary probe table.
|
||||
* Special: value 0 means "use default chainLog". */
|
||||
ZSTD_p_searchLog, /* Number of search attempts, as a power of 2.
|
||||
* More attempts result in better and slower compression.
|
||||
@@ -1047,27 +1057,52 @@ typedef enum {
|
||||
/* 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,
|
||||
* even when referencing into Dictionary content (default:0) */
|
||||
ZSTD_p_forceAttachDict, /* ZSTD supports usage of a CDict in-place
|
||||
* (avoiding having to copy the compression tables
|
||||
* from the CDict into the working context). Using
|
||||
* a CDict in this way saves an initial setup step,
|
||||
* but comes at the cost of more work per byte of
|
||||
* input. ZSTD has a simple internal heuristic that
|
||||
* guesses which strategy will be faster. You can
|
||||
* use this flag to override that guess.
|
||||
*
|
||||
* Note that the by-reference, in-place strategy is
|
||||
* only used when reusing a compression context
|
||||
* with compatible compression parameters. (If
|
||||
* incompatible / uninitialized, the working
|
||||
* context needs to be cleared anyways, which is
|
||||
* about as expensive as overwriting it with the
|
||||
* dictionary context, so there's no savings in
|
||||
* using the CDict by-ref.)
|
||||
*
|
||||
* Values greater than 0 force attaching the dict.
|
||||
* Values less than 0 force copying the dict.
|
||||
* 0 selects the default heuristic-guided behavior.
|
||||
*/
|
||||
|
||||
} ZSTD_cParameter;
|
||||
|
||||
|
||||
/*! ZSTD_CCtx_setParameter() :
|
||||
* 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.
|
||||
* @result : informational value (typically, value being set clamped correctly),
|
||||
* Setting a parameter is generally only possible during frame initialization (before starting compression).
|
||||
* Exception : when using multi-threading mode (nbThreads >= 1),
|
||||
* following parameters can be updated _during_ compression (within same frame):
|
||||
* => compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy.
|
||||
* new parameters will be active on next job, or after a flush().
|
||||
* Note : when `value` type is not unsigned (int, or enum), cast it to unsigned for proper type checking.
|
||||
* @result : informational value (typically, value being set, correctly clamped),
|
||||
* 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);
|
||||
|
||||
/*! ZSTD_CCtx_getParameter() :
|
||||
* Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned* value);
|
||||
|
||||
/*! ZSTD_CCtx_setPledgedSrcSize() :
|
||||
* Total input data size to be compressed as a single frame.
|
||||
* This value will be controlled at the end, and result in error if not respected.
|
||||
@@ -1115,29 +1150,39 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
||||
/*! ZSTD_CCtx_refPrefix() :
|
||||
* Reference a prefix (single-usage dictionary) for next compression job.
|
||||
* Decompression need same prefix to properly regenerate data.
|
||||
* Prefix is **only used once**. Tables are discarded at end of compression job.
|
||||
* Subsequent compression jobs will be done without prefix (if none is explicitly referenced).
|
||||
* If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_CDict instead.
|
||||
* Prefix is **only used once**. Tables are discarded at end of compression job (ZSTD_e_end).
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
* 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.
|
||||
* Its contain must remain unmodified up to end of compression (ZSTD_e_end).
|
||||
* Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
||||
* It's a CPU consuming operation, with non-negligible impact on latency.
|
||||
* If there is a need to use same prefix multiple times, consider loadDictionary instead.
|
||||
* Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||
* Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode. */
|
||||
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_dictContentType_e dictContentType);
|
||||
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_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.
|
||||
* The parameters and dictionary are kept unchanged, to reset them use ZSTD_CCtx_resetParameters().
|
||||
*/
|
||||
ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);
|
||||
|
||||
/*! ZSTD_CCtx_resetParameters() :
|
||||
* All parameters are back to default values (compression level is ZSTD_CLEVEL_DEFAULT).
|
||||
* Dictionary (if any) is dropped.
|
||||
* Resetting parameters is only possible during frame initialization (before starting compression).
|
||||
* To reset the context use ZSTD_CCtx_reset().
|
||||
* @return 0 or an error code (which can be checked with ZSTD_isError()).
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_resetParameters(ZSTD_CCtx* cctx);
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
@@ -1235,6 +1280,13 @@ ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, Z
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value);
|
||||
|
||||
/*! ZSTD_CCtxParam_getParameter() :
|
||||
* Similar to ZSTD_CCtx_getParameter.
|
||||
* Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_CCtxParam_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned* value);
|
||||
|
||||
/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
|
||||
* Apply a set of ZSTD_CCtx_params to the compression context.
|
||||
* This can be done even after compression is started,
|
||||
@@ -1246,10 +1298,13 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
||||
|
||||
|
||||
/*=== Advanced parameters for decompression API ===*/
|
||||
/* ==================================== */
|
||||
/*=== Advanced decompression API ===*/
|
||||
/* ==================================== */
|
||||
|
||||
/* The following parameters must be set after creating a ZSTD_DCtx* (or ZSTD_DStream*) object,
|
||||
* but before starting decompression of a frame.
|
||||
/* The following API works the same way as the advanced compression API :
|
||||
* a context is created, parameters are pushed into it one by one,
|
||||
* then the context can be used to decompress data using an interface similar to the straming API.
|
||||
*/
|
||||
|
||||
/*! ZSTD_DCtx_loadDictionary() :
|
||||
@@ -1286,17 +1341,23 @@ ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
|
||||
|
||||
/*! ZSTD_DCtx_refPrefix() :
|
||||
* Reference a prefix (single-usage dictionary) for next compression job.
|
||||
* 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.
|
||||
* Prefix is **only used once**. Reference is discarded at end of frame.
|
||||
* End of frame is reached when ZSTD_DCtx_decompress_generic() returns 0.
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
* Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
|
||||
* Note 2 : Prefix buffer is referenced. It must outlive compression job.
|
||||
* Note 2 : Prefix buffer is referenced. It **must** outlive decompression job.
|
||||
* Prefix buffer must remain unmodified up to the end of frame,
|
||||
* reached when ZSTD_DCtx_decompress_generic() returns 0.
|
||||
* Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||
* Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
||||
* Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
|
||||
* A fulldict prefix is more costly though.
|
||||
*/
|
||||
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_dictContentType_e dictContentType);
|
||||
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_dictContentType_e dictContentType);
|
||||
|
||||
|
||||
/*! ZSTD_DCtx_setMaxWindowSize() :
|
||||
@@ -1318,6 +1379,13 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
|
||||
|
||||
|
||||
/** ZSTD_getFrameHeader_advanced() :
|
||||
* same as ZSTD_getFrameHeader(),
|
||||
* with added capability to select a format (like ZSTD_f_zstd1_magicless) */
|
||||
ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr,
|
||||
const void* src, size_t srcSize, ZSTD_format_e format);
|
||||
|
||||
|
||||
/*! ZSTD_decompress_generic() :
|
||||
* Behave the same as ZSTD_decompressStream.
|
||||
* Decompression parameters cannot be changed once decompression is started.
|
||||
|
||||
@@ -243,7 +243,7 @@ preview-man: clean-man man
|
||||
man ./zstd.1
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets
|
||||
# make install is validated only for Linux, macOS, BSD, Hurd and Solaris targets
|
||||
#-----------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "zstd.h"
|
||||
#include "datagen.h" /* RDG_genBuffer */
|
||||
#include "xxhash.h"
|
||||
#include "bench.h"
|
||||
|
||||
|
||||
/* *************************************
|
||||
@@ -70,16 +71,16 @@ static U32 g_compressibilityDefault = 50;
|
||||
* console display
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
static int g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
/* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
|
||||
|
||||
static const U64 g_refreshRate = SEC_TO_MICRO / 6;
|
||||
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
|
||||
|
||||
#define DISPLAYUPDATE(l, ...) { if (g_displayLevel>=l) { \
|
||||
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
|
||||
#define DISPLAYUPDATE(l, ...) { if (displayLevel>=l) { \
|
||||
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (displayLevel>=4)) \
|
||||
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
|
||||
if (g_displayLevel>=4) fflush(stderr); } } }
|
||||
if (displayLevel>=4) fflush(stderr); } } }
|
||||
|
||||
|
||||
/* *************************************
|
||||
@@ -104,30 +105,34 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
|
||||
static int g_additionalParam = 0;
|
||||
static U32 g_decodeOnly = 0;
|
||||
|
||||
void BMK_setNotificationLevel(unsigned level) { g_displayLevel=level; }
|
||||
|
||||
void BMK_setAdditionalParam(int additionalParam) { g_additionalParam=additionalParam; }
|
||||
|
||||
|
||||
//TODO : Deal with DISPLAYLEVEL for all these set functions
|
||||
|
||||
static U32 g_nbSeconds = BMK_TIMETEST_DEFAULT_S;
|
||||
|
||||
void BMK_setNbSeconds(unsigned nbSeconds)
|
||||
{
|
||||
g_nbSeconds = nbSeconds;
|
||||
DISPLAYLEVEL(3, "- test >= %u seconds per compression / decompression - \n", g_nbSeconds);
|
||||
DISPLAY("- test >= %u seconds per compression / decompression - \n", g_nbSeconds);
|
||||
}
|
||||
|
||||
static size_t g_blockSize = 0;
|
||||
|
||||
void BMK_setBlockSize(size_t blockSize)
|
||||
{
|
||||
g_blockSize = blockSize;
|
||||
if (g_blockSize) DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10));
|
||||
if (g_blockSize) DISPLAY("using blocks of size %u KB \n", (U32)(blockSize>>10));
|
||||
}
|
||||
|
||||
void BMK_setDecodeOnlyMode(unsigned decodeFlag) { g_decodeOnly = (decodeFlag>0); }
|
||||
|
||||
static U32 g_nbWorkers = 0;
|
||||
|
||||
void BMK_setNbWorkers(unsigned nbWorkers) {
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
if (nbWorkers > 0) DISPLAYLEVEL(2, "Note : multi-threading is disabled \n");
|
||||
if (nbWorkers > 0) DISPLAY("Note : multi-threading is disabled \n");
|
||||
#endif
|
||||
g_nbWorkers = nbWorkers;
|
||||
}
|
||||
@@ -168,7 +173,6 @@ void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
|
||||
g_ldmHashEveryLog = ldmHashEveryLog;
|
||||
}
|
||||
|
||||
|
||||
/* ********************************************************
|
||||
* Bench functions
|
||||
**********************************************************/
|
||||
@@ -182,18 +186,18 @@ typedef struct {
|
||||
size_t resSize;
|
||||
} blockParam_t;
|
||||
|
||||
|
||||
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
const char* displayName, int cLevel,
|
||||
const size_t* fileSizes, U32 nbFiles,
|
||||
BMK_return_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
const int cLevel, const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
const ZSTD_compressionParameters* const comprParams)
|
||||
ZSTD_CCtx* ctx, ZSTD_DCtx* dctx,
|
||||
int displayLevel, const char* displayName)
|
||||
|
||||
{
|
||||
size_t const blockSize = ((g_blockSize>=32 && !g_decodeOnly) ? g_blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;
|
||||
U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;
|
||||
@@ -201,17 +205,20 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
size_t const maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */
|
||||
void* const compressedBuffer = malloc(maxCompressedSize);
|
||||
void* resultBuffer = malloc(srcSize);
|
||||
ZSTD_CCtx* const ctx = ZSTD_createCCtx();
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
BMK_return_t results;
|
||||
|
||||
size_t const loadedCompressedSize = srcSize;
|
||||
size_t cSize = 0;
|
||||
double ratio = 0.;
|
||||
U32 nbBlocks;
|
||||
|
||||
/* checks */
|
||||
if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx)
|
||||
if (!compressedBuffer || !resultBuffer || !blockTable)
|
||||
EXM_THROW(31, "allocation error : not enough memory");
|
||||
|
||||
if(!ctx || !dctx)
|
||||
EXM_THROW(31, "error: passed in null context");
|
||||
|
||||
/* init */
|
||||
if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* display last 17 characters */
|
||||
if (g_nbWorkers==1) g_nbWorkers=0; /* prefer synchronous mode */
|
||||
@@ -369,10 +376,12 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
cSize = 0;
|
||||
{ U32 blockNb; for (blockNb=0; blockNb<nbBlocks; blockNb++) cSize += blockTable[blockNb].cSize; }
|
||||
ratio = (double)srcSize / (double)cSize;
|
||||
results.result.cSize = cSize;
|
||||
markNb = (markNb+1) % NB_MARKS;
|
||||
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
||||
double const compressionSpeed = ((double)srcSize / fastestC) * 1000;
|
||||
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1;
|
||||
results.result.cSpeed = compressionSpeed * 1000000;
|
||||
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
|
||||
marks[markNb], displayName, (U32)srcSize, (U32)cSize,
|
||||
ratioAccuracy, ratio,
|
||||
@@ -428,6 +437,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
double const compressionSpeed = ((double)srcSize / fastestC) * 1000;
|
||||
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1;
|
||||
double const decompressionSpeed = ((double)srcSize / fastestD) * 1000;
|
||||
results.result.cSpeed = compressionSpeed * 1000000;
|
||||
results.result.dSpeed = decompressionSpeed * 1000000;
|
||||
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,
|
||||
ratioAccuracy, ratio,
|
||||
@@ -475,7 +486,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
#endif
|
||||
} /* for (testNb = 1; testNb <= (g_nbSeconds + !g_nbSeconds); testNb++) */
|
||||
|
||||
if (g_displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
|
||||
if (displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
|
||||
double const cSpeed = ((double)srcSize / fastestC) * 1000;
|
||||
double const dSpeed = ((double)srcSize / fastestD) * 1000;
|
||||
if (g_additionalParam)
|
||||
@@ -490,11 +501,30 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
free(blockTable);
|
||||
free(compressedBuffer);
|
||||
free(resultBuffer);
|
||||
ZSTD_freeCCtx(ctx);
|
||||
ZSTD_freeDCtx(dctx);
|
||||
return 0;
|
||||
results.errorCode = 0;
|
||||
return results;
|
||||
}
|
||||
|
||||
static void BMK_benchMemCtxless(const void* srcBuffer, size_t srcSize,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
int cLevel, const ZSTD_compressionParameters* const comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
int displayLevel, const char* displayName)
|
||||
{
|
||||
ZSTD_CCtx* ctx = ZSTD_createCCtx();
|
||||
ZSTD_DCtx* dctx = ZSTD_createDCtx();
|
||||
if(ctx == NULL || dctx == NULL) {
|
||||
EXM_THROW(12, "not enough memory for contexts");
|
||||
}
|
||||
BMK_benchMem(srcBuffer, srcSize,
|
||||
fileSizes, nbFiles,
|
||||
cLevel, comprParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
ctx, dctx,
|
||||
displayLevel, displayName);
|
||||
ZSTD_freeCCtx(ctx);
|
||||
ZSTD_freeDCtx(dctx);
|
||||
}
|
||||
|
||||
static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
{
|
||||
@@ -514,11 +544,12 @@ static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
return (size_t)(requiredMem);
|
||||
}
|
||||
|
||||
/* returns average stats over all range [cLevel, cLevelLast] */
|
||||
static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
|
||||
const char* displayName, int cLevel, int cLevelLast,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
const int cLevel, const int cLevelLast, const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
const ZSTD_compressionParameters* const compressionParams)
|
||||
int displayLevel, const char* displayName)
|
||||
{
|
||||
int l;
|
||||
|
||||
@@ -531,16 +562,19 @@ static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
|
||||
SET_REALTIME_PRIORITY;
|
||||
}
|
||||
|
||||
if (g_displayLevel == 1 && !g_additionalParam)
|
||||
if (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));
|
||||
|
||||
for (l=cLevel; l <= cLevelLast; l++) {
|
||||
if (l==0) continue; /* skip level 0 */
|
||||
BMK_benchMem(srcBuffer, benchedSize,
|
||||
displayName, l,
|
||||
fileSizes, nbFiles,
|
||||
dictBuffer, dictBufferSize, compressionParams);
|
||||
BMK_benchMemCtxless(srcBuffer, benchedSize,
|
||||
fileSizes, nbFiles,
|
||||
l, comprParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
displayLevel, displayName);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -548,8 +582,8 @@ static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
|
||||
* Loads `buffer` with content of files listed within `fileNamesTable`.
|
||||
* At most, fills `buffer` entirely. */
|
||||
static void BMK_loadFiles(void* buffer, size_t bufferSize,
|
||||
size_t* fileSizes,
|
||||
const char* const * const fileNamesTable, unsigned nbFiles)
|
||||
size_t* fileSizes, const char* const * const fileNamesTable,
|
||||
unsigned nbFiles, int displayLevel)
|
||||
{
|
||||
size_t pos = 0, totalSize = 0;
|
||||
unsigned n;
|
||||
@@ -582,9 +616,8 @@ static void BMK_loadFiles(void* buffer, size_t bufferSize,
|
||||
}
|
||||
|
||||
static void BMK_benchFileTable(const char* const * const fileNamesTable, unsigned const nbFiles,
|
||||
const char* const dictFileName,
|
||||
int const cLevel, int const cLevelLast,
|
||||
const ZSTD_compressionParameters* const compressionParams)
|
||||
const char* const dictFileName, int const cLevel, int const cLevelLast,
|
||||
const ZSTD_compressionParameters* const compressionParams, int displayLevel)
|
||||
{
|
||||
void* srcBuffer;
|
||||
size_t benchedSize;
|
||||
@@ -605,7 +638,7 @@ static void BMK_benchFileTable(const char* const * const fileNamesTable, unsigne
|
||||
if (dictBuffer==NULL)
|
||||
EXM_THROW(11, "not enough memory for dictionary (%u bytes)",
|
||||
(U32)dictBufferSize);
|
||||
BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1);
|
||||
BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1, displayLevel);
|
||||
}
|
||||
|
||||
/* Memory allocation & restrictions */
|
||||
@@ -617,28 +650,33 @@ static void BMK_benchFileTable(const char* const * const fileNamesTable, unsigne
|
||||
if (!srcBuffer) EXM_THROW(12, "not enough memory");
|
||||
|
||||
/* Load input buffer */
|
||||
BMK_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles);
|
||||
BMK_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles, displayLevel);
|
||||
|
||||
/* Bench */
|
||||
if (g_separateFiles) {
|
||||
const BYTE* srcPtr = (const BYTE*)srcBuffer;
|
||||
U32 fileNb;
|
||||
BMK_result_t* resultarray = (BMK_result_t*)malloc(sizeof(BMK_result_t) * nbFiles);
|
||||
if(resultarray == NULL) EXM_THROW(12, "not enough memory");
|
||||
for (fileNb=0; fileNb<nbFiles; fileNb++) {
|
||||
size_t const fileSize = fileSizes[fileNb];
|
||||
BMK_benchCLevel(srcPtr, fileSize,
|
||||
fileNamesTable[fileNb], cLevel, cLevelLast,
|
||||
fileSizes+fileNb, 1,
|
||||
dictBuffer, dictBufferSize, compressionParams);
|
||||
fileSizes+fileNb, 1,
|
||||
cLevel, cLevelLast, compressionParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
displayLevel, fileNamesTable[fileNb]);
|
||||
srcPtr += fileSize;
|
||||
}
|
||||
|
||||
} else {
|
||||
char mfName[20] = {0};
|
||||
snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
|
||||
{ const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
|
||||
BMK_benchCLevel(srcBuffer, benchedSize,
|
||||
displayName, cLevel, cLevelLast,
|
||||
fileSizes, nbFiles,
|
||||
dictBuffer, dictBufferSize, compressionParams);
|
||||
BMK_benchCLevel(srcBuffer, benchedSize,
|
||||
fileSizes, nbFiles,
|
||||
cLevel, cLevelLast, compressionParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
displayLevel, displayName);
|
||||
} }
|
||||
|
||||
/* clean up */
|
||||
@@ -649,7 +687,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)
|
||||
const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel)
|
||||
{
|
||||
char name[20] = {0};
|
||||
size_t benchedSize = 10000000;
|
||||
@@ -663,17 +702,21 @@ static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility
|
||||
|
||||
/* Bench */
|
||||
snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
|
||||
BMK_benchCLevel(srcBuffer, benchedSize, name, cLevel, cLevelLast, &benchedSize, 1, NULL, 0, compressionParams);
|
||||
BMK_benchCLevel(srcBuffer, benchedSize,
|
||||
&benchedSize, 1,
|
||||
cLevel, cLevelLast, compressionParams,
|
||||
NULL, 0,
|
||||
displayLevel, name);
|
||||
|
||||
/* clean up */
|
||||
free(srcBuffer);
|
||||
}
|
||||
|
||||
|
||||
int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,
|
||||
const char* dictFileName,
|
||||
int cLevel, int cLevelLast,
|
||||
const ZSTD_compressionParameters* compressionParams)
|
||||
static void BMK_benchFilesFull(const char** fileNamesTable, unsigned nbFiles,
|
||||
const char* dictFileName,
|
||||
int cLevel, int cLevelLast,
|
||||
const ZSTD_compressionParameters* compressionParams, int displayLevel)
|
||||
{
|
||||
double const compressibility = (double)g_compressibilityDefault / 100;
|
||||
|
||||
@@ -684,8 +727,16 @@ int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,
|
||||
DISPLAYLEVEL(2, "Benchmarking levels from %d to %d\n", cLevel, cLevelLast);
|
||||
|
||||
if (nbFiles == 0)
|
||||
BMK_syntheticTest(cLevel, cLevelLast, compressibility, compressionParams);
|
||||
BMK_syntheticTest(cLevel, cLevelLast, compressibility, compressionParams, displayLevel);
|
||||
else
|
||||
BMK_benchFileTable(fileNamesTable, nbFiles, dictFileName, cLevel, cLevelLast, compressionParams);
|
||||
BMK_benchFileTable(fileNamesTable, nbFiles, dictFileName, cLevel, cLevelLast, compressionParams, displayLevel);
|
||||
}
|
||||
|
||||
int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,
|
||||
const char* dictFileName,
|
||||
int cLevel, int cLevelLast,
|
||||
const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel) {
|
||||
BMK_benchFilesFull(fileNamesTable, nbFiles, dictFileName, cLevel, cLevelLast, compressionParams, displayLevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef BENCH_H_121279284357
|
||||
#define BENCH_H_121279284357
|
||||
@@ -16,8 +19,31 @@
|
||||
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */
|
||||
#include "zstd.h" /* ZSTD_compressionParameters */
|
||||
|
||||
typedef struct {
|
||||
size_t cSize;
|
||||
double cSpeed; /* bytes / sec */
|
||||
double dSpeed;
|
||||
} BMK_result_t;
|
||||
|
||||
/* 0 = no Error */
|
||||
typedef struct {
|
||||
int errorCode;
|
||||
BMK_result_t result;
|
||||
} BMK_return_t;
|
||||
|
||||
/* called in cli */
|
||||
int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, const char* dictFileName,
|
||||
int cLevel, int cLevelLast, const ZSTD_compressionParameters* compressionParams);
|
||||
int cLevel, int cLevelLast, const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel);
|
||||
|
||||
/* basic benchmarking function, called in paramgrill
|
||||
* ctx, dctx must be valid */
|
||||
BMK_return_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
const int cLevel, const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
ZSTD_CCtx* ctx, ZSTD_DCtx* dctx,
|
||||
int displayLevel, const char* displayName);
|
||||
|
||||
/* Set Parameters */
|
||||
void BMK_setNbSeconds(unsigned nbLoops);
|
||||
@@ -35,3 +61,7 @@ void BMK_setLdmBucketSizeLog(unsigned ldmBucketSizeLog);
|
||||
void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog);
|
||||
|
||||
#endif /* BENCH_H_121279284357 */
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "mem.h"
|
||||
#include "fileio.h"
|
||||
#include "util.h"
|
||||
@@ -101,21 +102,6 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Debug
|
||||
***************************************/
|
||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
|
||||
# include <assert.h>
|
||||
#else
|
||||
# ifndef assert
|
||||
# define assert(condition) ((void)0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_DEBUG
|
||||
# define ZSTD_DEBUG 0
|
||||
#endif
|
||||
#define DEBUGLOG(l,...) if (l<=ZSTD_DEBUG) DISPLAY(__VA_ARGS__);
|
||||
#define EXM_THROW(error, ...) \
|
||||
{ \
|
||||
DISPLAYLEVEL(1, "zstd: "); \
|
||||
@@ -172,7 +158,7 @@ static void clearHandler(void)
|
||||
|
||||
|
||||
/* ************************************************************
|
||||
* Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW
|
||||
* Avoid fseek()'s 2GiB barrier with MSVC, macOS, *BSD, MinGW
|
||||
***************************************************************/
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
# define LONG_SEEK _fseeki64
|
||||
@@ -466,6 +452,13 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
DISPLAYLEVEL(5,"set nb workers = %u \n", g_nbWorkers);
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbWorkers, g_nbWorkers) );
|
||||
if ( (g_overlapLog == FIO_OVERLAP_LOG_NOTSET)
|
||||
&& (cLevel == ZSTD_maxCLevel()) )
|
||||
g_overlapLog = 9; /* full overlap */
|
||||
if (g_overlapLog != FIO_OVERLAP_LOG_NOTSET) {
|
||||
DISPLAYLEVEL(3,"set overlapLog = %u \n", g_overlapLog);
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_overlapSizeLog, g_overlapLog) );
|
||||
}
|
||||
#endif
|
||||
/* dictionary */
|
||||
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) ); /* set the value temporarily for dictionary loading, to adapt compression parameters */
|
||||
@@ -752,8 +745,9 @@ FIO_compressZstdFrame(const cRess_t* ressPtr,
|
||||
DISPLAYLEVEL(6, "compression using zstd format \n");
|
||||
|
||||
/* init */
|
||||
if (fileSize != UTIL_FILESIZE_UNKNOWN)
|
||||
ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize);
|
||||
if (fileSize != UTIL_FILESIZE_UNKNOWN) {
|
||||
CHECK(ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize));
|
||||
}
|
||||
(void)compressionLevel; (void)srcFileName;
|
||||
|
||||
/* Main compression loop */
|
||||
@@ -1480,7 +1474,7 @@ static unsigned long long FIO_decompressLz4Frame(dRess_t* ress,
|
||||
if (LZ4F_isError(nextToLoad)) {
|
||||
DISPLAYLEVEL(1, "zstd: %s: lz4 decompression error : %s \n",
|
||||
srcFileName, LZ4F_getErrorName(nextToLoad));
|
||||
decodingError = 1; break;
|
||||
decodingError = 1; nextToLoad = 0; break;
|
||||
}
|
||||
pos += remaining;
|
||||
|
||||
@@ -1488,7 +1482,7 @@ static unsigned long long FIO_decompressLz4Frame(dRess_t* ress,
|
||||
if (decodedBytes) {
|
||||
if (fwrite(ress->dstBuffer, 1, decodedBytes, ress->dstFile) != decodedBytes) {
|
||||
DISPLAYLEVEL(1, "zstd: %s \n", strerror(errno));
|
||||
decodingError = 1; break;
|
||||
decodingError = 1; nextToLoad = 0; break;
|
||||
}
|
||||
filesize += decodedBytes;
|
||||
DISPLAYUPDATE(2, "\rDecompressed : %u MB ", (unsigned)(filesize>>20));
|
||||
@@ -1747,8 +1741,19 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles
|
||||
&& strcmp(suffixPtr, ZSTD_EXTENSION)
|
||||
&& strcmp(suffixPtr, LZMA_EXTENSION)
|
||||
&& strcmp(suffixPtr, LZ4_EXTENSION)) ) {
|
||||
DISPLAYLEVEL(1, "zstd: %s: unknown suffix (%s/%s/%s/%s/%s expected) -- ignored \n",
|
||||
srcFileName, GZ_EXTENSION, XZ_EXTENSION, ZSTD_EXTENSION, LZMA_EXTENSION, LZ4_EXTENSION);
|
||||
const char* suffixlist = ZSTD_EXTENSION
|
||||
#ifdef ZSTD_GZCOMPRESS
|
||||
"/" GZ_EXTENSION
|
||||
#endif
|
||||
#ifdef ZSTD_LZMACOMPRESS
|
||||
"/" XZ_EXTENSION "/" LZMA_EXTENSION
|
||||
#endif
|
||||
#ifdef ZSTD_LZ4COMPRESS
|
||||
"/" LZ4_EXTENSION
|
||||
#endif
|
||||
;
|
||||
DISPLAYLEVEL(1, "zstd: %s: unknown suffix (%s expected) -- ignored \n",
|
||||
srcFileName, suffixlist);
|
||||
skippedFiles++;
|
||||
continue;
|
||||
} else {
|
||||
@@ -2012,6 +2017,12 @@ static int FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLe
|
||||
}
|
||||
|
||||
int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int displayLevel){
|
||||
|
||||
if (!IS_CONSOLE(stdin)) {
|
||||
DISPLAYOUT("zstd: --list does not support reading from standard input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (numFiles == 0) {
|
||||
DISPLAYOUT("No files given\n");
|
||||
return 0;
|
||||
|
||||
@@ -96,7 +96,10 @@ extern "C" {
|
||||
/*-*********************************************
|
||||
* Detect if isatty() and fileno() are available
|
||||
************************************************/
|
||||
#if (defined(__linux__) && (PLATFORM_POSIX_VERSION >= 1)) || (PLATFORM_POSIX_VERSION >= 200112L) || defined(__DJGPP__)
|
||||
#if (defined(__linux__) && (PLATFORM_POSIX_VERSION >= 1)) \
|
||||
|| (PLATFORM_POSIX_VERSION >= 200112L) \
|
||||
|| defined(__DJGPP__) \
|
||||
|| defined(__MSYS__)
|
||||
# include <unistd.h> /* isatty */
|
||||
# define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
|
||||
#elif defined(MSDOS) || defined(OS2) || defined(__CYGWIN__)
|
||||
|
||||
@@ -40,7 +40,7 @@ extern "C" {
|
||||
|
||||
|
||||
/* ************************************************************
|
||||
* Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW
|
||||
* Avoid fseek()'s 2GiB barrier with MSVC, macOS, *BSD, MinGW
|
||||
***************************************************************/
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
# define UTIL_fseek _fseeki64
|
||||
@@ -513,7 +513,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
|
||||
|
||||
UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
|
||||
{
|
||||
(void)bufStart; (void)bufEnd; (void)pos;
|
||||
(void)bufStart; (void)bufEnd; (void)pos; (void)followLinks;
|
||||
UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.
|
||||
.TH "ZSTD" "1" "2018-01-27" "zstd 1.3.4" "User Commands"
|
||||
.TH "ZSTD" "1" "2018-06-27" "zstd 1.3.5" "User Commands"
|
||||
.
|
||||
.SH "NAME"
|
||||
\fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files
|
||||
@@ -17,7 +17,7 @@
|
||||
\fBzstdcat\fR is equivalent to \fBzstd \-dcf\fR
|
||||
.
|
||||
.SH "DESCRIPTION"
|
||||
\fBzstd\fR is a fast lossless compression algorithm and data compression tool, with command line syntax similar to \fBgzip (1)\fR and \fBxz (1)\fR\. It is based on the \fBLZ77\fR family, with further FSE & huff0 entropy stages\. \fBzstd\fR offers highly configurable compression speed, with fast modes at > 200 MB/s per code, and strong modes nearing lzma compression ratios\. It also features a very fast decoder, with speeds > 500 MB/s per core\.
|
||||
\fBzstd\fR is a fast lossless compression algorithm and data compression tool, with command line syntax similar to \fBgzip (1)\fR and \fBxz (1)\fR\. It is based on the \fBLZ77\fR family, with further FSE & huff0 entropy stages\. \fBzstd\fR offers highly configurable compression speed, with fast modes at > 200 MB/s per core, and strong modes nearing lzma compression ratios\. It also features a very fast decoder, with speeds > 500 MB/s per core\.
|
||||
.
|
||||
.P
|
||||
\fBzstd\fR command line syntax is generally similar to gzip, but features the following differences :
|
||||
@@ -111,15 +111,23 @@ enables long distance matching with \fB#\fR \fBwindowLog\fR, if not \fB#\fR is n
|
||||
Note: If \fBwindowLog\fR is set to larger than 27, \fB\-\-long=windowLog\fR or \fB\-\-memory=windowSize\fR needs to be passed to the decompressor\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-fast[=#]\fR
|
||||
switch to ultra\-fast compression levels\. If \fB=#\fR is not present, it defaults to \fB1\fR\. 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 \fB\-\-fast\fR, it overrides it\.
|
||||
.
|
||||
.TP
|
||||
\fB\-T#\fR, \fB\-\-threads=#\fR
|
||||
Compress using \fB#\fR threads (default: 1)\. If \fB#\fR 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\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\.
|
||||
Compress using \fB#\fR working threads (default: 1)\. If \fB#\fR 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==200\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-single\-thread\fR
|
||||
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 \fB\-T1\fR, which spawns 1 compression thread in parallel of I/O)\. Single\-thread mode also features lower memory usage\.
|
||||
.
|
||||
.TP
|
||||
\fB\-D file\fR
|
||||
use \fBfile\fR as Dictionary to compress or decompress FILE(s)
|
||||
.
|
||||
.TP
|
||||
\fB\-\-nodictID\fR
|
||||
\fB\-\-no\-dictID\fR
|
||||
do not store dictionary ID within frame header (dictionary compression)\. The decoder will have to rely on implicit knowledge about which dictionary to use, it won\'t be able to check if it\'s correct\.
|
||||
.
|
||||
.TP
|
||||
@@ -152,7 +160,7 @@ operate recursively on dictionaries
|
||||
.
|
||||
.TP
|
||||
\fB\-\-format=FORMAT\fR
|
||||
compress and decompress in other formats\. If compiled with support, zstd can compress to or decompress from other compression algorithm formats\. Possibly available options are \fBgzip\fR, \fBxz\fR, \fBlzma\fR, and \fBlz4\fR\.
|
||||
compress and decompress in other formats\. If compiled with support, zstd can compress to or decompress from other compression algorithm formats\. Possibly available options are \fBzstd\fR, \fBgzip\fR, \fBxz\fR, \fBlzma\fR, and \fBlz4\fR\. If no such format is provided, \fBzstd\fR is the default\.
|
||||
.
|
||||
.TP
|
||||
\fB\-h\fR/\fB\-H\fR, \fB\-\-help\fR
|
||||
@@ -335,13 +343,19 @@ The minimum \fIslen\fR is 3 and the maximum is 7\.
|
||||
.
|
||||
.TP
|
||||
\fBtargetLen\fR=\fItlen\fR, \fBtlen\fR=\fItlen\fR
|
||||
Specify the minimum match length that causes a match finder to stop searching for better matches\.
|
||||
The impact of this field vary depending on selected strategy\.
|
||||
.
|
||||
.IP
|
||||
A larger minimum match length usually improves compression ratio but decreases compression speed\. This option is only used with strategies ZSTD_btopt and ZSTD_btultra\.
|
||||
For ZSTD_btopt and ZSTD_btultra, it specifies the minimum match length that causes match finder to stop searching for better matches\. A larger \fBtargetLen\fR usually improves compression ratio but decreases compression speed\.
|
||||
.
|
||||
.IP
|
||||
The minimum \fItlen\fR is 4 and the maximum is 999\.
|
||||
For ZSTD_fast, it triggers ultra\-fast mode when > 0\. The value represents the amount of data skipped between match sampling\. Impact is reversed : a larger \fBtargetLen\fR increases compression speed but decreases compression ratio\.
|
||||
.
|
||||
.IP
|
||||
For all other strategies, this field has no impact\.
|
||||
.
|
||||
.IP
|
||||
The minimum \fItlen\fR is 0 and the maximum is 999\.
|
||||
.
|
||||
.TP
|
||||
\fBoverlapLog\fR=\fIovlog\fR, \fBovlog\fR=\fIovlog\fR
|
||||
@@ -374,7 +388,7 @@ This option is ignored unless long distance matching is enabled\.
|
||||
Larger/very small values usually decrease compression ratio\.
|
||||
.
|
||||
.IP
|
||||
The minumum \fIldmslen\fR is 4 and the maximum is 4096 (default: 64)\.
|
||||
The minimum \fIldmslen\fR is 4 and the maximum is 4096 (default: 64)\.
|
||||
.
|
||||
.TP
|
||||
\fBldmBucketSizeLog\fR=\fIldmblog\fR, \fBldmblog\fR=\fIldmblog\fR
|
||||
@@ -402,14 +416,14 @@ Larger values will improve compression speed\. Deviating far from the default va
|
||||
.IP
|
||||
The default value is \fBwlog \- ldmhlog\fR\.
|
||||
.
|
||||
.SS "\-B#:"
|
||||
Select the size of each compression job\. This parameter is available only when multi\-threading is enabled\. Default value is \fB4 * windowSize\fR, which means it varies depending on compression level\. \fB\-B#\fR makes it possible to select a custom value\. Note that job size must respect a minimum value which is enforced transparently\. This minimum is either 1 MB, or \fBoverlapSize\fR, whichever is largest\.
|
||||
.
|
||||
.SS "Example"
|
||||
The following parameters sets advanced compression options to those of predefined level 19 for files bigger than 256 KB:
|
||||
The following parameters sets advanced compression options to something similar to predefined level 19 for files bigger than 256 KB:
|
||||
.
|
||||
.P
|
||||
\fB\-\-zstd\fR=windowLog=23,chainLog=23,hashLog=22,searchLog=6,searchLength=3,targetLength=48,strategy=6
|
||||
\fB\-\-zstd\fR=wlog=23,clog=23,hlog=22,slog=6,slen=3,tlen=48,strat=6
|
||||
.
|
||||
.SS "\-B#:"
|
||||
Select the size of each compression job\. This parameter is available only when multi\-threading is enabled\. Default value is \fB4 * windowSize\fR, which means it varies depending on compression level\. \fB\-B#\fR makes it possible to select a custom value\. Note that job size must respect a minimum value which is enforced transparently\. This minimum is either 1 MB, or \fBoverlapSize\fR, whichever is largest\.
|
||||
.
|
||||
.SH "BUGS"
|
||||
Report bugs at: https://github\.com/facebook/zstd/issues
|
||||
|
||||
@@ -19,7 +19,7 @@ DESCRIPTION
|
||||
with command line syntax similar to `gzip (1)` and `xz (1)`.
|
||||
It is based on the **LZ77** family, with further FSE & huff0 entropy stages.
|
||||
`zstd` offers highly configurable compression speed,
|
||||
with fast modes at > 200 MB/s per code,
|
||||
with fast modes at > 200 MB/s per core,
|
||||
and strong modes nearing lzma compression ratios.
|
||||
It also features a very fast decoder, with speeds > 500 MB/s per core.
|
||||
|
||||
@@ -136,7 +136,7 @@ the last one takes effect.
|
||||
Single-thread mode also features lower memory usage.
|
||||
* `-D file`:
|
||||
use `file` as Dictionary to compress or decompress FILE(s)
|
||||
* `--nodictID`:
|
||||
* `--no-dictID`:
|
||||
do not store dictionary ID within frame header (dictionary compression).
|
||||
The decoder will have to rely on implicit knowledge about which dictionary to use,
|
||||
it won't be able to check if it's correct.
|
||||
@@ -164,7 +164,8 @@ the last one takes effect.
|
||||
* `--format=FORMAT`:
|
||||
compress and decompress in other formats. If compiled with
|
||||
support, zstd can compress to or decompress from other compression algorithm
|
||||
formats. Possibly available options are `gzip`, `xz`, `lzma`, and `lz4`.
|
||||
formats. Possibly available options are `zstd`, `gzip`, `xz`, `lzma`, and `lz4`.
|
||||
If no such format is provided, `zstd` is the default.
|
||||
* `-h`/`-H`, `--help`:
|
||||
display help/long help and exit
|
||||
* `-V`, `--version`:
|
||||
@@ -354,14 +355,14 @@ The list of available _options_:
|
||||
A larger `targetLen` usually improves compression ratio
|
||||
but decreases compression speed.
|
||||
|
||||
For ZSTD\_fast, it specifies
|
||||
the amount of data skipped between match sampling.
|
||||
For ZSTD\_fast, it triggers ultra-fast mode when > 0.
|
||||
The value represents 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.
|
||||
The minimum _tlen_ is 0 and the maximum is 999.
|
||||
|
||||
- `overlapLog`=_ovlog_, `ovlog`=_ovlog_:
|
||||
Determine `overlapSize`, amount of data reloaded from previous job.
|
||||
@@ -392,7 +393,7 @@ The list of available _options_:
|
||||
|
||||
Larger/very small values usually decrease compression ratio.
|
||||
|
||||
The minumum _ldmslen_ is 4 and the maximum is 4096 (default: 64).
|
||||
The minimum _ldmslen_ is 4 and the maximum is 4096 (default: 64).
|
||||
|
||||
- `ldmBucketSizeLog`=_ldmblog_, `ldmblog`=_ldmblog_:
|
||||
Specify the size of each bucket for the hash table used for long distance
|
||||
@@ -416,6 +417,12 @@ The list of available _options_:
|
||||
|
||||
The default value is `wlog - ldmhlog`.
|
||||
|
||||
### Example
|
||||
The following parameters sets advanced compression options to something
|
||||
similar to predefined level 19 for files bigger than 256 KB:
|
||||
|
||||
`--zstd`=wlog=23,clog=23,hlog=22,slog=6,slen=3,tlen=48,strat=6
|
||||
|
||||
### -B#:
|
||||
Select the size of each compression job.
|
||||
This parameter is available only when multi-threading is enabled.
|
||||
@@ -424,12 +431,6 @@ Default value is `4 * windowSize`, which means it varies depending on compressio
|
||||
Note that job size must respect a minimum value which is enforced transparently.
|
||||
This minimum is either 1 MB, or `overlapSize`, whichever is largest.
|
||||
|
||||
### Example
|
||||
The following parameters sets advanced compression options to those of
|
||||
predefined level 19 for files bigger than 256 KB:
|
||||
|
||||
`--zstd`=windowLog=23,chainLog=23,hashLog=22,searchLog=6,searchLength=3,targetLength=48,strategy=6
|
||||
|
||||
BUGS
|
||||
----
|
||||
Report bugs at: https://github.com/facebook/zstd/issues
|
||||
|
||||
@@ -145,6 +145,7 @@ static int usage_advanced(const char* programName)
|
||||
#ifdef UTIL_HAS_CREATEFILELIST
|
||||
DISPLAY( " -r : operate recursively on directories \n");
|
||||
#endif
|
||||
DISPLAY( "--format=zstd : compress files to the .zstd format (default) \n");
|
||||
#ifdef ZSTD_GZCOMPRESS
|
||||
DISPLAY( "--format=gzip : compress files to the .gz format \n");
|
||||
#endif
|
||||
@@ -219,20 +220,34 @@ static int exeNameMatch(const char* exeName, const char* test)
|
||||
(exeName[strlen(test)] == '\0' || exeName[strlen(test)] == '.');
|
||||
}
|
||||
|
||||
static void errorOut(const char* msg)
|
||||
{
|
||||
DISPLAY("%s \n", msg); exit(1);
|
||||
}
|
||||
|
||||
/*! readU32FromChar() :
|
||||
* @return : unsigned integer value read from input in `char` format.
|
||||
* allows and interprets K, KB, KiB, M, MB and MiB suffix.
|
||||
* Will also modify `*stringPtr`, advancing it to position where it stopped reading.
|
||||
* Note : function result can overflow if digit string > MAX_UINT */
|
||||
* Note : function will exit() program if digit sequence overflows */
|
||||
static unsigned readU32FromChar(const char** stringPtr)
|
||||
{
|
||||
const char errorMsg[] = "error: numeric value too large";
|
||||
unsigned result = 0;
|
||||
while ((**stringPtr >='0') && (**stringPtr <='9'))
|
||||
while ((**stringPtr >='0') && (**stringPtr <='9')) {
|
||||
unsigned const max = (((unsigned)(-1)) / 10) - 1;
|
||||
if (result > max) errorOut(errorMsg);
|
||||
result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
|
||||
}
|
||||
if ((**stringPtr=='K') || (**stringPtr=='M')) {
|
||||
unsigned const maxK = ((unsigned)(-1)) >> 10;
|
||||
if (result > maxK) errorOut(errorMsg);
|
||||
result <<= 10;
|
||||
if (**stringPtr=='M') result <<= 10;
|
||||
(*stringPtr)++ ;
|
||||
if (**stringPtr=='M') {
|
||||
if (result > maxK) errorOut(errorMsg);
|
||||
result <<= 10;
|
||||
}
|
||||
(*stringPtr)++; /* skip `K` or `M` */
|
||||
if (**stringPtr=='i') (*stringPtr)++;
|
||||
if (**stringPtr=='B') (*stringPtr)++;
|
||||
}
|
||||
@@ -486,6 +501,7 @@ int main(int argCount, const char* argv[])
|
||||
if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; }
|
||||
if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; }
|
||||
if (!strcmp(argument, "--single-thread")) { nbWorkers = 0; singleThread = 1; continue; }
|
||||
if (!strcmp(argument, "--format=zstd")) { suffix = ZSTD_EXTENSION; FIO_setCompressionType(FIO_zstdCompression); continue; }
|
||||
#ifdef ZSTD_GZCOMPRESS
|
||||
if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; }
|
||||
#endif
|
||||
@@ -545,12 +561,16 @@ int main(int argCount, const char* argv[])
|
||||
continue;
|
||||
}
|
||||
if (longCommandWArg(&argument, "--fast")) {
|
||||
/* Parse optional window log */
|
||||
/* Parse optional acceleration factor */
|
||||
if (*argument == '=') {
|
||||
U32 fastLevel;
|
||||
++argument;
|
||||
fastLevel = readU32FromChar(&argument);
|
||||
if (fastLevel) cLevel = - (int)fastLevel;
|
||||
if (fastLevel) {
|
||||
dictCLevel = cLevel = -(int)fastLevel;
|
||||
} else {
|
||||
CLEAN_RETURN(badusage(programName));
|
||||
}
|
||||
} else if (*argument != 0) {
|
||||
/* Invalid character following --fast */
|
||||
CLEAN_RETURN(badusage(programName));
|
||||
@@ -743,8 +763,11 @@ int main(int argCount, const char* argv[])
|
||||
nbWorkers = UTIL_countPhysicalCores();
|
||||
DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers);
|
||||
}
|
||||
#else
|
||||
(void)singleThread;
|
||||
#endif
|
||||
|
||||
#ifdef UTIL_HAS_CREATEFILELIST
|
||||
g_utilDisplayLevel = g_displayLevel;
|
||||
if (!followLinks) {
|
||||
unsigned u;
|
||||
@@ -757,7 +780,6 @@ int main(int argCount, const char* argv[])
|
||||
}
|
||||
filenameIdx = fileNamesNb;
|
||||
}
|
||||
#ifdef UTIL_HAS_CREATEFILELIST
|
||||
if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */
|
||||
extendedFileList = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb, followLinks);
|
||||
if (extendedFileList) {
|
||||
@@ -768,6 +790,8 @@ int main(int argCount, const char* argv[])
|
||||
filenameIdx = fileNamesNb;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)followLinks;
|
||||
#endif
|
||||
|
||||
if (operation == zom_list) {
|
||||
@@ -783,7 +807,6 @@ int main(int argCount, const char* argv[])
|
||||
/* Check if benchmark is selected */
|
||||
if (operation==zom_bench) {
|
||||
#ifndef ZSTD_NOBENCH
|
||||
BMK_setNotificationLevel(g_displayLevel);
|
||||
BMK_setSeparateFiles(separateFiles);
|
||||
BMK_setBlockSize(blockSize);
|
||||
BMK_setNbWorkers(nbWorkers);
|
||||
@@ -798,7 +821,7 @@ int main(int argCount, const char* argv[])
|
||||
if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) {
|
||||
BMK_setLdmHashEveryLog(g_ldmHashEveryLog);
|
||||
}
|
||||
BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams);
|
||||
BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams, g_displayLevel);
|
||||
#else
|
||||
(void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio; (void)separateFiles;
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,7 @@ PYTHON ?= python3
|
||||
TESTARTEFACT := versionsTest
|
||||
|
||||
DEBUGLEVEL ?= 1
|
||||
DEBUGFLAGS = -g -DZSTD_DEBUG=$(DEBUGLEVEL)
|
||||
DEBUGFLAGS = -g -DDEBUGLEVEL=$(DEBUGLEVEL)
|
||||
CPPFLAGS += -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
|
||||
-I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR)
|
||||
CFLAGS ?= -O3
|
||||
@@ -203,7 +203,7 @@ zstreamtest-dll : $(ZSTREAM_LOCAL_FILES)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(filter %.c,$^) $(LDFLAGS) -o $@$(EXT)
|
||||
|
||||
paramgrill : DEBUGFLAGS = # turn off assert() for speed measurements
|
||||
paramgrill : $(ZSTD_FILES) $(PRGDIR)/datagen.c paramgrill.c
|
||||
paramgrill : $(ZSTD_FILES) $(PRGDIR)/bench.c $(PRGDIR)/datagen.c paramgrill.c
|
||||
$(CC) $(FLAGS) $^ -lm -o $@$(EXT)
|
||||
|
||||
datagen : $(PRGDIR)/datagen.c datagencli.c
|
||||
@@ -260,7 +260,7 @@ clean:
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------------
|
||||
#make valgrindTest is validated only for Linux, OSX, BSD, Hurd and Solaris targets
|
||||
#make valgrindTest is validated only for Linux, macOS, BSD, Hurd and Solaris targets
|
||||
#----------------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
HOST_OS = POSIX
|
||||
@@ -360,6 +360,9 @@ test-fullbench32: fullbench32 datagen
|
||||
test-fuzzer: fuzzer
|
||||
$(QEMU_SYS) ./fuzzer -v $(FUZZERTEST) $(FUZZER_FLAGS)
|
||||
|
||||
test-fuzzer-stackmode: MOREFLAGS += -DZSTD_HEAPMODE=0
|
||||
test-fuzzer-stackmode: test-fuzzer
|
||||
|
||||
test-fuzzer32: fuzzer32
|
||||
$(QEMU_SYS) ./fuzzer32 -v $(FUZZERTEST) $(FUZZER_FLAGS)
|
||||
|
||||
@@ -373,7 +376,6 @@ test-zstream: zstreamtest
|
||||
$(QEMU_SYS) ./zstreamtest -v $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --mt -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --newapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --opaqueapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
|
||||
test-zstream32: zstreamtest32
|
||||
$(QEMU_SYS) ./zstreamtest32 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
|
||||
@@ -437,7 +437,8 @@ static size_t writeHufHeader(U32* seed, HUF_CElt* hufTable, void* dst, size_t ds
|
||||
U32 count[HUF_SYMBOLVALUE_MAX+1];
|
||||
|
||||
/* Scan input and build symbol stats */
|
||||
{ size_t const largest = FSE_count_wksp (count, &maxSymbolValue, (const BYTE*)src, srcSize, WKSP);
|
||||
{ size_t const largest = HIST_count_wksp (count, &maxSymbolValue, (const BYTE*)src, srcSize, WKSP);
|
||||
assert(!HIST_isError(largest));
|
||||
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 0; } /* single symbol, rle */
|
||||
if (largest <= (srcSize >> 7)+1) return 0; /* Fast heuristic : not compressible enough */
|
||||
}
|
||||
@@ -834,7 +835,8 @@ static size_t writeSequences(U32* seed, frame_t* frame, seqStore_t* seqStorePtr,
|
||||
|
||||
/* CTable for Literal Lengths */
|
||||
{ U32 max = MaxLL;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, WKSP);
|
||||
size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, WKSP); /* cannot fail */
|
||||
assert(!HIST_isError(mostFrequent));
|
||||
if (mostFrequent == nbSeq) {
|
||||
/* do RLE if we have the chance */
|
||||
*op++ = llCodeTable[0];
|
||||
@@ -865,7 +867,8 @@ static size_t writeSequences(U32* seed, frame_t* frame, seqStore_t* seqStorePtr,
|
||||
/* CTable for Offsets */
|
||||
/* see Literal Lengths for descriptions of mode choices */
|
||||
{ U32 max = MaxOff;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, WKSP);
|
||||
size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, WKSP); /* cannot fail */
|
||||
assert(!HIST_isError(mostFrequent));
|
||||
if (mostFrequent == nbSeq) {
|
||||
*op++ = ofCodeTable[0];
|
||||
FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
|
||||
@@ -892,7 +895,8 @@ static size_t writeSequences(U32* seed, frame_t* frame, seqStore_t* seqStorePtr,
|
||||
/* CTable for MatchLengths */
|
||||
/* see Literal Lengths for descriptions of mode choices */
|
||||
{ U32 max = MaxML;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, WKSP);
|
||||
size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, WKSP); /* cannot fail */
|
||||
assert(!HIST_isError(mostFrequent));
|
||||
if (mostFrequent == nbSeq) {
|
||||
*op++ = *mlCodeTable;
|
||||
FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
* the data to zstd functions. Every fuzzer initializes the RNG exactly
|
||||
* once before doing anything else, even if it is unused.
|
||||
* Default: 4.
|
||||
* @param ZSTD_DEBUG:
|
||||
* This is a parameter for the zstd library. Defining `ZSTD_DEBUG=1`
|
||||
* @param DEBUGLEVEL:
|
||||
* This is a parameter for the zstd library. Defining `DEBUGLEVEL=1`
|
||||
* enables assert() statements in the zstd library. Higher levels enable
|
||||
* logging, so aren't recommended. Defining `ZSTD_DEBUG=1` is
|
||||
* logging, so aren't recommended. Defining `DEBUGLEVEL=1` is
|
||||
* recommended.
|
||||
* @param MEM_FORCE_MEMORY_ACCESS:
|
||||
* This flag controls how the zstd library accesses unaligned memory.
|
||||
|
||||
@@ -147,15 +147,18 @@ def compiler_version(cc, cxx):
|
||||
"""
|
||||
cc_version_bytes = subprocess.check_output([cc, "--version"])
|
||||
cxx_version_bytes = subprocess.check_output([cxx, "--version"])
|
||||
if cc_version_bytes.startswith(b'clang'):
|
||||
assert(cxx_version_bytes.startswith(b'clang'))
|
||||
compiler = None
|
||||
version = None
|
||||
if b'clang' in cc_version_bytes:
|
||||
assert(b'clang' in cxx_version_bytes)
|
||||
compiler = 'clang'
|
||||
if cc_version_bytes.startswith(b'gcc'):
|
||||
assert(cxx_version_bytes.startswith(b'g++'))
|
||||
elif b'gcc' in cc_version_bytes:
|
||||
assert(b'gcc' in cxx_version_bytes)
|
||||
compiler = 'gcc'
|
||||
version_regex = b'([0-9])+\.([0-9])+\.([0-9])+'
|
||||
version_match = re.search(version_regex, cc_version_bytes)
|
||||
version = tuple(int(version_match.group(i)) for i in range(1, 4))
|
||||
if compiler is not None:
|
||||
version_regex = b'([0-9])+\.([0-9])+\.([0-9])+'
|
||||
version_match = re.search(version_regex, cc_version_bytes)
|
||||
version = tuple(int(version_match.group(i)) for i in range(1, 4))
|
||||
return compiler, version
|
||||
|
||||
|
||||
@@ -248,7 +251,7 @@ def build_parser(args):
|
||||
dest='debug',
|
||||
type=int,
|
||||
default=1,
|
||||
help='Set ZSTD_DEBUG (default: 1)')
|
||||
help='Set DEBUGLEVEL (default: 1)')
|
||||
parser.add_argument(
|
||||
'--force-memory-access',
|
||||
dest='memory_access',
|
||||
@@ -265,7 +268,7 @@ def build_parser(args):
|
||||
'--disable-fuzzing-mode',
|
||||
dest='fuzzing_mode',
|
||||
action='store_false',
|
||||
help='Do not define FUZZING_BUILD_MORE_UNSAFE_FOR_PRODUCTION')
|
||||
help='Do not define FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION')
|
||||
parser.add_argument(
|
||||
'--enable-stateful-fuzzing',
|
||||
dest='stateful_fuzzing',
|
||||
@@ -355,7 +358,7 @@ def build(args):
|
||||
common_flags = []
|
||||
|
||||
cppflags += [
|
||||
'-DZSTD_DEBUG={}'.format(args.debug),
|
||||
'-DDEBUGLEVEL={}'.format(args.debug),
|
||||
'-DMEM_FORCE_MEMORY_ACCESS={}'.format(args.memory_access),
|
||||
'-DFUZZ_RNG_SEED_SIZE={}'.format(args.fuzz_rng_seed_size),
|
||||
]
|
||||
@@ -399,7 +402,7 @@ def build(args):
|
||||
cppflags += ['-DSTATEFUL_FUZZING']
|
||||
|
||||
if args.fuzzing_mode:
|
||||
cppflags += ['-DFUZZING_BUILD_MORE_UNSAFE_FOR_PRODUCTION']
|
||||
cppflags += ['-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION']
|
||||
|
||||
if args.lib_fuzzing_engine == 'libregression.a':
|
||||
targets = ['libregression.a'] + targets
|
||||
@@ -750,11 +753,10 @@ def zip_cmd(args):
|
||||
for target in args.TARGET:
|
||||
# Zip the seed_corpus
|
||||
seed_corpus = abs_join(CORPORA_DIR, "{}_seed_corpus".format(target))
|
||||
seeds = [abs_join(seed_corpus, f) for f in os.listdir(seed_corpus)]
|
||||
zip_file = "{}.zip".format(seed_corpus)
|
||||
cmd = ["zip", "-q", "-j", "-9", zip_file]
|
||||
print(' '.join(cmd + [abs_join(seed_corpus, '*')]))
|
||||
subprocess.check_call(cmd + seeds)
|
||||
cmd = ["zip", "-r", "-q", "-j", "-9", zip_file, "."]
|
||||
print(' '.join(cmd))
|
||||
subprocess.check_call(cmd, cwd=seed_corpus)
|
||||
|
||||
|
||||
def list_cmd(args):
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char const **argv) {
|
||||
size_t const kMaxFileSize = (size_t)1 << 20;
|
||||
size_t const kMaxFileSize = (size_t)1 << 27;
|
||||
int const kFollowLinks = 1;
|
||||
char *fileNamesBuf = NULL;
|
||||
char const **files = argv + 1;
|
||||
|
||||
@@ -34,8 +34,7 @@ ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state)
|
||||
cParams.searchLog = FUZZ_rand32(state, ZSTD_SEARCHLOG_MIN, 9);
|
||||
cParams.searchLength = FUZZ_rand32(state, ZSTD_SEARCHLENGTH_MIN,
|
||||
ZSTD_SEARCHLENGTH_MAX);
|
||||
cParams.targetLength = FUZZ_rand32(state, ZSTD_TARGETLENGTH_MIN,
|
||||
512);
|
||||
cParams.targetLength = FUZZ_rand32(state, 0, 512);
|
||||
cParams.strategy = FUZZ_rand32(state, ZSTD_fast, ZSTD_btultra);
|
||||
return ZSTD_adjustCParams(cParams, srcSize, 0);
|
||||
}
|
||||
@@ -72,6 +71,7 @@ void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state)
|
||||
setRand(cctx, ZSTD_p_contentSizeFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_p_checksumFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_p_dictIDFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_p_forceAttachDict, -2, 2, state);
|
||||
/* Select long distance matchig parameters */
|
||||
setRand(cctx, ZSTD_p_enableLongDistanceMatching, 0, 1, state);
|
||||
setRand(cctx, ZSTD_p_ldmHashLog, ZSTD_HASHLOG_MIN, 16, state);
|
||||
|
||||
@@ -66,6 +66,9 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
|
||||
if (g_displayLevel>=4) fflush(stderr); } }
|
||||
|
||||
|
||||
/*-*******************************************************
|
||||
* Compile time test
|
||||
*********************************************************/
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
void FUZ_bug976(void)
|
||||
@@ -74,6 +77,7 @@ void FUZ_bug976(void)
|
||||
assert(ZSTD_CHAINLOG_MAX < 31);
|
||||
}
|
||||
|
||||
|
||||
/*-*******************************************************
|
||||
* Internal functions
|
||||
*********************************************************/
|
||||
@@ -117,6 +121,13 @@ static unsigned FUZ_highbit32(U32 v32)
|
||||
#define CHECK(fn) { CHECK_V(err, fn); }
|
||||
#define CHECKPLUS(var, fn, more) { CHECK_V(var, fn); more; }
|
||||
|
||||
#define CHECK_EQ(lhs, rhs) { \
|
||||
if ((lhs) != (rhs)) { \
|
||||
DISPLAY("Error L%u => %s != %s ", __LINE__, #lhs, #rhs); \
|
||||
goto _output_error; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/*=============================================
|
||||
* Memory Tests
|
||||
@@ -368,6 +379,12 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : decompress too large input : ", testNb++);
|
||||
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, compressedBufferSize);
|
||||
if (!ZSTD_isError(r)) goto _output_error;
|
||||
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3d : check CCtx size after compressing empty input : ", testNb++);
|
||||
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||
size_t const r = ZSTD_compressCCtx(cctx, compressedBuffer, compressedBufferSize, NULL, 0, 19);
|
||||
@@ -394,14 +411,60 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3d : large window log smaller data : ", testNb++);
|
||||
DISPLAYLEVEL(3, "test%3d : ZSTD_CCtx_getParameter() : ", 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;
|
||||
ZSTD_outBuffer out = {NULL, 0, 0};
|
||||
ZSTD_inBuffer in = {NULL, 0, 0};
|
||||
unsigned value;
|
||||
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_compressionLevel, &value));
|
||||
CHECK_EQ(value, 3);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_hashLog, &value));
|
||||
CHECK_EQ(value, 0);
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_p_hashLog, ZSTD_HASHLOG_MIN));
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_compressionLevel, &value));
|
||||
CHECK_EQ(value, 3);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_hashLog, &value));
|
||||
CHECK_EQ(value, ZSTD_HASHLOG_MIN);
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, 7));
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_compressionLevel, &value));
|
||||
CHECK_EQ(value, 7);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_hashLog, &value));
|
||||
CHECK_EQ(value, ZSTD_HASHLOG_MIN);
|
||||
/* Start a compression job */
|
||||
ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_continue);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_compressionLevel, &value));
|
||||
CHECK_EQ(value, 7);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_hashLog, &value));
|
||||
CHECK_EQ(value, ZSTD_HASHLOG_MIN);
|
||||
/* Reset the CCtx */
|
||||
ZSTD_CCtx_reset(cctx);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_compressionLevel, &value));
|
||||
CHECK_EQ(value, 7);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_hashLog, &value));
|
||||
CHECK_EQ(value, ZSTD_HASHLOG_MIN);
|
||||
/* Reset the parameters */
|
||||
ZSTD_CCtx_resetParameters(cctx);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_compressionLevel, &value));
|
||||
CHECK_EQ(value, 3);
|
||||
CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_p_hashLog, &value));
|
||||
CHECK_EQ(value, 0);
|
||||
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* this test is really too long, and should be made faster */
|
||||
DISPLAYLEVEL(3, "test%3d : overflow protection with large windowLog : ", testNb++);
|
||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
ZSTD_parameters params = ZSTD_getParams(-9, ZSTD_CONTENTSIZE_UNKNOWN, 0);
|
||||
size_t const nbCompressions = ((1U << 31) / CNBuffSize) + 1; /* ensure U32 overflow protection is triggered */
|
||||
size_t cnb;
|
||||
assert(cctx != NULL);
|
||||
params.fParams.contentSizeFlag = 0;
|
||||
params.cParams.windowLog = ZSTD_WINDOWLOG_MAX;
|
||||
for (i = 0; i < nbCompressions; ++i) {
|
||||
for (cnb = 0; cnb < nbCompressions; ++cnb) {
|
||||
DISPLAYLEVEL(6, "run %zu / %zu \n", cnb, nbCompressions);
|
||||
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) );
|
||||
}
|
||||
@@ -409,6 +472,39 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3d : size down context : ", testNb++);
|
||||
{ ZSTD_CCtx* const largeCCtx = ZSTD_createCCtx();
|
||||
assert(largeCCtx != NULL);
|
||||
CHECK_Z( ZSTD_compressBegin(largeCCtx, 19) ); /* streaming implies ZSTD_CONTENTSIZE_UNKNOWN, which maximizes memory usage */
|
||||
CHECK_Z( ZSTD_compressEnd(largeCCtx, compressedBuffer, compressedBufferSize, CNBuffer, 1) );
|
||||
{ size_t const largeCCtxSize = ZSTD_sizeof_CCtx(largeCCtx); /* size of context must be measured after compression */
|
||||
{ ZSTD_CCtx* const smallCCtx = ZSTD_createCCtx();
|
||||
assert(smallCCtx != NULL);
|
||||
CHECK_Z(ZSTD_compressCCtx(smallCCtx, compressedBuffer, compressedBufferSize, CNBuffer, 1, 1));
|
||||
{ size_t const smallCCtxSize = ZSTD_sizeof_CCtx(smallCCtx);
|
||||
DISPLAYLEVEL(5, "(large) %zuKB > 32*%zuKB (small) : ",
|
||||
largeCCtxSize>>10, smallCCtxSize>>10);
|
||||
assert(largeCCtxSize > 32* smallCCtxSize); /* note : "too large" definition is handled within zstd_compress.c .
|
||||
* make this test case extreme, so that it doesn't depend on a possibly fluctuating definition */
|
||||
}
|
||||
ZSTD_freeCCtx(smallCCtx);
|
||||
}
|
||||
{ U32 const maxNbAttempts = 1100; /* nb of usages before triggering size down is handled within zstd_compress.c.
|
||||
* currently defined as 128x, but could be adjusted in the future.
|
||||
* make this test long enough so that it's not too much tied to the current definition within zstd_compress.c */
|
||||
U32 u;
|
||||
for (u=0; u<maxNbAttempts; u++) {
|
||||
CHECK_Z(ZSTD_compressCCtx(largeCCtx, compressedBuffer, compressedBufferSize, CNBuffer, 1, 1));
|
||||
if (ZSTD_sizeof_CCtx(largeCCtx) < largeCCtxSize) break; /* sized down */
|
||||
}
|
||||
DISPLAYLEVEL(5, "size down after %u attempts : ", u);
|
||||
if (u==maxNbAttempts) goto _output_error; /* no sizedown happened */
|
||||
}
|
||||
}
|
||||
ZSTD_freeCCtx(largeCCtx);
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* Static CCtx tests */
|
||||
#define STATIC_CCTX_LEVEL 3
|
||||
DISPLAYLEVEL(3, "test%3i : create static CCtx for level %u :", testNb++, STATIC_CCTX_LEVEL);
|
||||
@@ -1024,12 +1120,40 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
|
||||
/* negative compression level test : ensure simple API and advanced API produce same result */
|
||||
DISPLAYLEVEL(3, "test%3i : negative compression level : ", testNb++);
|
||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
size_t const srcSize = CNBuffSize / 5;
|
||||
int const compressionLevel = -1;
|
||||
|
||||
assert(cctx != NULL);
|
||||
{ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize, 0);
|
||||
size_t const cSize_1pass = ZSTD_compress_advanced(cctx,
|
||||
compressedBuffer, compressedBufferSize,
|
||||
CNBuffer, srcSize,
|
||||
NULL, 0,
|
||||
params);
|
||||
if (ZSTD_isError(cSize_1pass)) goto _output_error;
|
||||
|
||||
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_compressionLevel, (unsigned)compressionLevel) );
|
||||
{ ZSTD_inBuffer in = { CNBuffer, srcSize, 0 };
|
||||
ZSTD_outBuffer out = { compressedBuffer, compressedBufferSize, 0 };
|
||||
size_t const compressionResult = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||
DISPLAYLEVEL(5, "simple=%zu vs %zu=advanced : ", cSize_1pass, out.pos);
|
||||
if (ZSTD_isError(compressionResult)) goto _output_error;
|
||||
if (out.pos != cSize_1pass) goto _output_error;
|
||||
} }
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* parameters order test */
|
||||
{ size_t const inputSize = CNBuffSize / 2;
|
||||
U64 xxh64;
|
||||
|
||||
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
DISPLAYLEVEL(3, "test%3i : parameters in order : ", testNb++);
|
||||
assert(cctx != NULL);
|
||||
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) );
|
||||
@@ -1085,9 +1209,13 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
DISPLAYLEVEL(3, "OK : %s \n", ZSTD_getErrorName(decodeResult));
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : decompress with magic-less instruction : ", testNb++);
|
||||
DISPLAYLEVEL(3, "test%3i : decompress of magic-less frame : ", testNb++);
|
||||
ZSTD_DCtx_reset(dctx);
|
||||
CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) );
|
||||
{ ZSTD_frameHeader zfh;
|
||||
size_t const zfhrt = ZSTD_getFrameHeader_advanced(&zfh, compressedBuffer, cSize, ZSTD_f_zstd1_magicless);
|
||||
if (zfhrt != 0) goto _output_error;
|
||||
}
|
||||
{ ZSTD_inBuffer in = { compressedBuffer, cSize, 0 };
|
||||
ZSTD_outBuffer out = { decodedBuffer, CNBuffSize, 0 };
|
||||
size_t const result = ZSTD_decompress_generic(dctx, &out, &in);
|
||||
@@ -1142,6 +1270,15 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
if (r != blockSize) goto _output_error; }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : Block compression with CDict : ", testNb++);
|
||||
{ ZSTD_CDict* const cdict = ZSTD_createCDict(CNBuffer, dictSize, 3);
|
||||
if (cdict==NULL) goto _output_error;
|
||||
CHECK( ZSTD_compressBegin_usingCDict(cctx, cdict) );
|
||||
CHECK( ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize) );
|
||||
ZSTD_freeCDict(cdict);
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
ZSTD_freeDCtx(dctx);
|
||||
|
||||
@@ -33,7 +33,7 @@ clean:
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# validated only for Linux, OSX, Hurd and some BSD targets
|
||||
# validated only for Linux, macOS, Hurd and some BSD targets
|
||||
#------------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly NetBSD))
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
die() {
|
||||
$ECHO "$@" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
INTOVOID="/dev/null"
|
||||
case "$OS" in
|
||||
Windows*)
|
||||
INTOVOID="NUL"
|
||||
;;
|
||||
esac
|
||||
|
||||
ZSTD_LIB_COMPRESSION=0 CFLAGS= make -C $DIR/../lib libzstd.a > $INTOVOID
|
||||
nm $DIR/../lib/libzstd.a | grep ".*\.o:" > tmplog
|
||||
! grep -q "zstd_compress" tmplog && grep -q "zstd_decompress" tmplog && ! grep -q "dict" tmplog && grep -q "zstd_v" tmplog && ! grep -q "zbuff" tmplog && make clean && rm -f tmplog || die "Compression macro failed"
|
||||
|
||||
|
||||
ZSTD_LIB_DECOMPRESSION=0 CFLAGS= make -C $DIR/../lib libzstd.a > $INTOVOID
|
||||
nm $DIR/../lib/libzstd.a | grep ".*\.o:" > tmplog
|
||||
grep -q "zstd_compress" tmplog && ! grep -q "zstd_decompress" tmplog && grep -q "dict" tmplog && ! grep -q "zstd_v" tmplog && ! grep -q "zbuff" tmplog && make clean && rm -f tmplog || die "Decompression macro failed"
|
||||
|
||||
ZSTD_LIB_DEPRECATED=0 CFLAGS= make -C $DIR/../lib libzstd.a > $INTOVOID
|
||||
nm $DIR/../lib/libzstd.a | grep ".*\.o:" > tmplog
|
||||
grep -q "zstd_compress" tmplog && grep -q "zstd_decompress" tmplog && grep -q "dict" tmplog && grep -q "zstd_v" tmplog && ! grep -q "zbuff" tmplog && make clean && rm -f tmplog || die "Deprecated macro failed"
|
||||
|
||||
ZSTD_LIB_DICTBUILDER=0 CFLAGS= make -C $DIR/../lib libzstd.a > $INTOVOID
|
||||
nm $DIR/../lib/libzstd.a | grep ".*\.o:" > tmplog
|
||||
grep -q "zstd_compress" tmplog && grep -q "zstd_decompress" tmplog && ! grep -q "dict" tmplog && grep -q "zstd_v" tmplog && grep -q "zbuff" tmplog && make clean && rm -f tmplog || die "Dictbuilder macro failed"
|
||||
|
||||
ZSTD_LIB_DECOMPRESSION=0 ZSTD_LIB_DICTBUILDER=0 CFLAGS= make -C $DIR/../lib libzstd.a > $INTOVOID
|
||||
nm $DIR/../lib/libzstd.a | grep ".*\.o:" > tmplog
|
||||
grep -q "zstd_compress" tmplog && ! grep -q "zstd_decompress" tmplog && ! grep -q "dict" tmplog && ! grep -q "zstd_v" tmplog && ! grep -q "zbuff" tmplog && make clean && rm -f tmplog || die "Multi-macro failed"
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h> /* strcmp */
|
||||
#include <math.h> /* log */
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mem.h"
|
||||
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_estimateCCtxSize */
|
||||
@@ -25,6 +26,7 @@
|
||||
#include "datagen.h"
|
||||
#include "xxhash.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
|
||||
/*-************************************
|
||||
@@ -32,7 +34,7 @@
|
||||
**************************************/
|
||||
#define PROGRAM_DESCRIPTION "ZSTD parameters tester"
|
||||
#define AUTHOR "Yann Collet"
|
||||
#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", PROGRAM_DESCRIPTION, ZSTD_VERSION_STRING, (int)(sizeof(void*)*8), AUTHOR, __DATE__
|
||||
#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s ***\n", PROGRAM_DESCRIPTION, ZSTD_VERSION_STRING, (int)(sizeof(void*)*8), AUTHOR
|
||||
|
||||
|
||||
#define KB *(1<<10)
|
||||
@@ -41,20 +43,15 @@
|
||||
|
||||
#define NBLOOPS 2
|
||||
#define TIMELOOP (2 * SEC_TO_MICRO)
|
||||
|
||||
#define NB_LEVELS_TRACKED 30
|
||||
#define NB_LEVELS_TRACKED 22 /* ensured being >= ZSTD_maxCLevel() in BMK_init_level_constraints() */
|
||||
|
||||
static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31));
|
||||
|
||||
#define COMPRESSIBILITY_DEFAULT 0.50
|
||||
static const size_t sampleSize = 10000000;
|
||||
|
||||
static const double g_grillDuration_s = 90000; /* about 24 hours */
|
||||
static const U64 g_maxParamTime = 15 * SEC_TO_MICRO;
|
||||
static const U64 g_maxVariationTime = 60 * SEC_TO_MICRO;
|
||||
static const int g_maxNbVariations = 64;
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Macros
|
||||
**************************************/
|
||||
@@ -64,11 +61,13 @@ static const int g_maxNbVariations = 64;
|
||||
#undef MAX
|
||||
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
|
||||
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
|
||||
|
||||
#define CUSTOM_LEVEL 99
|
||||
|
||||
/*-************************************
|
||||
* Benchmark Parameters
|
||||
**************************************/
|
||||
|
||||
static double g_grillDuration_s = 99999; /* about 27 hours */
|
||||
static U32 g_nbIterations = NBLOOPS;
|
||||
static double g_compressibility = COMPRESSIBILITY_DEFAULT;
|
||||
static U32 g_blockSize = 0;
|
||||
@@ -84,7 +83,6 @@ void BMK_SetNbIterations(int nbLoops)
|
||||
DISPLAY("- %u iterations -\n", g_nbIterations);
|
||||
}
|
||||
|
||||
|
||||
/*-*******************************************************
|
||||
* Private functions
|
||||
*********************************************************/
|
||||
@@ -128,15 +126,23 @@ U32 FUZ_rand(U32* src)
|
||||
return rand32 >> 5;
|
||||
}
|
||||
|
||||
/** longCommandWArg() :
|
||||
* check if *stringPtr is the same as longCommand.
|
||||
* If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
|
||||
* @return 0 and doesn't modify *stringPtr otherwise.
|
||||
* from zstdcli.c
|
||||
*/
|
||||
static unsigned longCommandWArg(const char** stringPtr, const char* longCommand)
|
||||
{
|
||||
size_t const comSize = strlen(longCommand);
|
||||
int const result = !strncmp(*stringPtr, longCommand, comSize);
|
||||
if (result) *stringPtr += comSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*-*******************************************************
|
||||
* Bench functions
|
||||
*********************************************************/
|
||||
typedef struct {
|
||||
size_t cSize;
|
||||
double cSpeed; /* bytes / sec */
|
||||
double dSpeed;
|
||||
} BMK_result_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -150,181 +156,42 @@ typedef struct
|
||||
} blockParam_t;
|
||||
|
||||
|
||||
static size_t BMK_benchParam(BMK_result_t* resultPtr,
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
ZSTD_CCtx* ctx,
|
||||
const ZSTD_compressionParameters cParams)
|
||||
{
|
||||
const size_t blockSize = g_blockSize ? g_blockSize : srcSize;
|
||||
const U32 nbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize);
|
||||
blockParam_t* const blockTable = (blockParam_t*) malloc(nbBlocks * sizeof(blockParam_t));
|
||||
const size_t maxCompressedSize = (size_t)nbBlocks * ZSTD_compressBound(blockSize);
|
||||
void* const compressedBuffer = malloc(maxCompressedSize);
|
||||
void* const resultBuffer = malloc(srcSize);
|
||||
ZSTD_parameters params;
|
||||
U32 Wlog = cParams.windowLog;
|
||||
U32 Clog = cParams.chainLog;
|
||||
U32 Hlog = cParams.hashLog;
|
||||
U32 Slog = cParams.searchLog;
|
||||
U32 Slength = cParams.searchLength;
|
||||
U32 Tlength = cParams.targetLength;
|
||||
ZSTD_strategy strat = cParams.strategy;
|
||||
char name[30] = { 0 };
|
||||
U64 crcOrig;
|
||||
|
||||
/* init result for early exit */
|
||||
resultPtr->cSize = srcSize;
|
||||
resultPtr->cSpeed = 0.;
|
||||
resultPtr->dSpeed = 0.;
|
||||
|
||||
/* Memory allocation & restrictions */
|
||||
snprintf(name, 30, "Sw%02uc%02uh%02us%02ul%1ut%03uS%1u", Wlog, Clog, Hlog, Slog, Slength, Tlength, strat);
|
||||
if (!compressedBuffer || !resultBuffer || !blockTable) {
|
||||
DISPLAY("\nError: not enough memory!\n");
|
||||
free(compressedBuffer);
|
||||
free(resultBuffer);
|
||||
free(blockTable);
|
||||
return 12;
|
||||
}
|
||||
|
||||
/* Calculating input Checksum */
|
||||
crcOrig = XXH64(srcBuffer, srcSize, 0);
|
||||
|
||||
/* Init blockTable data */
|
||||
{
|
||||
U32 i;
|
||||
size_t remaining = srcSize;
|
||||
const char* srcPtr = (const char*)srcBuffer;
|
||||
char* cPtr = (char*)compressedBuffer;
|
||||
char* resPtr = (char*)resultBuffer;
|
||||
for (i=0; i<nbBlocks; i++) {
|
||||
size_t thisBlockSize = MIN(remaining, blockSize);
|
||||
blockTable[i].srcPtr = srcPtr;
|
||||
blockTable[i].cPtr = cPtr;
|
||||
blockTable[i].resPtr = resPtr;
|
||||
blockTable[i].srcSize = thisBlockSize;
|
||||
blockTable[i].cRoom = ZSTD_compressBound(thisBlockSize);
|
||||
srcPtr += thisBlockSize;
|
||||
cPtr += blockTable[i].cRoom;
|
||||
resPtr += thisBlockSize;
|
||||
remaining -= thisBlockSize;
|
||||
} }
|
||||
|
||||
/* warmimg up memory */
|
||||
RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.10, 1);
|
||||
|
||||
/* Bench */
|
||||
{ U32 loopNb;
|
||||
size_t cSize = 0;
|
||||
double fastestC = 100000000., fastestD = 100000000.;
|
||||
double ratio = 0.;
|
||||
UTIL_time_t const benchStart = UTIL_getTime();
|
||||
|
||||
DISPLAY("\r%79s\r", "");
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.cParams = cParams;
|
||||
for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
|
||||
int nbLoops;
|
||||
U32 blockNb;
|
||||
UTIL_time_t roundStart;
|
||||
U64 roundClock;
|
||||
|
||||
{ U64 const benchTime = UTIL_clockSpanMicro(benchStart);
|
||||
if (benchTime > g_maxParamTime) break; }
|
||||
|
||||
/* Compression */
|
||||
DISPLAY("\r%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
|
||||
memset(compressedBuffer, 0xE5, maxCompressedSize);
|
||||
|
||||
nbLoops = 0;
|
||||
UTIL_waitForNextTick();
|
||||
roundStart = UTIL_getTime();
|
||||
while (UTIL_clockSpanMicro(roundStart) < TIMELOOP) {
|
||||
for (blockNb=0; blockNb<nbBlocks; blockNb++)
|
||||
blockTable[blockNb].cSize = ZSTD_compress_advanced(ctx,
|
||||
blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,
|
||||
blockTable[blockNb].srcPtr, blockTable[blockNb].srcSize,
|
||||
NULL, 0,
|
||||
params);
|
||||
nbLoops++;
|
||||
}
|
||||
roundClock = UTIL_clockSpanMicro(roundStart);
|
||||
|
||||
cSize = 0;
|
||||
for (blockNb=0; blockNb<nbBlocks; blockNb++)
|
||||
cSize += blockTable[blockNb].cSize;
|
||||
ratio = (double)srcSize / (double)cSize;
|
||||
if ((double)roundClock < fastestC * SEC_TO_MICRO * nbLoops) fastestC = ((double)roundClock / SEC_TO_MICRO) / nbLoops;
|
||||
DISPLAY("\r");
|
||||
DISPLAY("%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
|
||||
DISPLAY(" %9u (%4.3f),%7.1f MB/s", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
|
||||
resultPtr->cSize = cSize;
|
||||
resultPtr->cSpeed = (double)srcSize / fastestC;
|
||||
|
||||
#if 1
|
||||
/* Decompression */
|
||||
memset(resultBuffer, 0xD6, srcSize);
|
||||
|
||||
nbLoops = 0;
|
||||
UTIL_waitForNextTick();
|
||||
roundStart = UTIL_getTime();
|
||||
for ( ; UTIL_clockSpanMicro(roundStart) < TIMELOOP; nbLoops++) {
|
||||
for (blockNb=0; blockNb<nbBlocks; blockNb++)
|
||||
blockTable[blockNb].resSize = ZSTD_decompress(blockTable[blockNb].resPtr, blockTable[blockNb].srcSize,
|
||||
blockTable[blockNb].cPtr, blockTable[blockNb].cSize);
|
||||
}
|
||||
roundClock = UTIL_clockSpanMicro(roundStart);
|
||||
|
||||
if ((double)roundClock < fastestD * SEC_TO_MICRO * nbLoops) fastestD = ((double)roundClock / SEC_TO_MICRO) / nbLoops;
|
||||
DISPLAY("\r");
|
||||
DISPLAY("%1u-%s : %9u -> ", loopNb, name, (U32)srcSize);
|
||||
DISPLAY("%9u (%4.3f),%7.1f MB/s, ", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
|
||||
DISPLAY("%7.1f MB/s", (double)srcSize / fastestD / 1000000.);
|
||||
resultPtr->dSpeed = (double)srcSize / fastestD;
|
||||
|
||||
/* CRC Checking */
|
||||
{ U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
|
||||
if (crcOrig!=crcCheck) {
|
||||
unsigned u;
|
||||
unsigned eBlockSize = (unsigned)(MIN(65536*2, blockSize));
|
||||
DISPLAY("\n!!! WARNING !!! Invalid Checksum : %x != %x\n", (unsigned)crcOrig, (unsigned)crcCheck);
|
||||
for (u=0; u<srcSize; u++) {
|
||||
if (((const BYTE*)srcBuffer)[u] != ((BYTE*)resultBuffer)[u]) {
|
||||
printf("Decoding error at pos %u (block %u, pos %u) \n", u, u / eBlockSize, u % eBlockSize);
|
||||
break;
|
||||
} }
|
||||
break;
|
||||
} }
|
||||
#endif
|
||||
} }
|
||||
|
||||
/* End cleaning */
|
||||
DISPLAY("\r");
|
||||
free(compressedBuffer);
|
||||
free(resultBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char* g_stratName[ZSTD_btultra+1] = {
|
||||
"(none) ", "ZSTD_fast ", "ZSTD_dfast ",
|
||||
"ZSTD_greedy ", "ZSTD_lazy ", "ZSTD_lazy2 ",
|
||||
"ZSTD_btlazy2 ", "ZSTD_btopt ", "ZSTD_btultra "};
|
||||
|
||||
/* TODO: support additional parameters (more files, fileSizes) */
|
||||
|
||||
//TODO: benchMem dctx can't = NULL in new system
|
||||
static size_t
|
||||
BMK_benchParam(BMK_result_t* resultPtr,
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
ZSTD_CCtx* ctx, ZSTD_DCtx* dctx,
|
||||
const ZSTD_compressionParameters cParams) {
|
||||
|
||||
|
||||
BMK_return_t res = BMK_benchMem(srcBuffer,srcSize, &srcSize, 1, 0, &cParams, NULL, 0, ctx, dctx, 0, "File");
|
||||
*resultPtr = res.result;
|
||||
return res.errorCode;
|
||||
}
|
||||
|
||||
static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_compressionParameters params, size_t srcSize)
|
||||
{
|
||||
char lvlstr[15] = "Custom Level";
|
||||
DISPLAY("\r%79s\r", "");
|
||||
fprintf(f," {%3u,%3u,%3u,%3u,%3u,%3u, %s }, ",
|
||||
params.windowLog, params.chainLog, params.hashLog, params.searchLog, params.searchLength,
|
||||
params.targetLength, g_stratName[(U32)(params.strategy)]);
|
||||
if(cLevel != CUSTOM_LEVEL) {
|
||||
snprintf(lvlstr, 15, " Level %2u ", cLevel);
|
||||
}
|
||||
fprintf(f,
|
||||
"/* level %2u */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */\n",
|
||||
cLevel, (double)srcSize / result.cSize, result.cSpeed / 1000000., result.dSpeed / 1000000.);
|
||||
"/* %s */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */\n",
|
||||
lvlstr, (double)srcSize / result.cSize, result.cSpeed / 1000000., result.dSpeed / 1000000.);
|
||||
}
|
||||
|
||||
|
||||
static double g_cSpeedTarget[NB_LEVELS_TRACKED] = { 0. }; /* NB_LEVELS_TRACKED : checked at main() */
|
||||
|
||||
typedef struct {
|
||||
BMK_result_t result;
|
||||
ZSTD_compressionParameters params;
|
||||
@@ -337,7 +204,7 @@ static void BMK_printWinners2(FILE* f, const winnerInfo_t* winners, size_t srcSi
|
||||
fprintf(f, "\n /* Proposed configurations : */ \n");
|
||||
fprintf(f, " /* W, C, H, S, L, T, strat */ \n");
|
||||
|
||||
for (cLevel=0; cLevel <= ZSTD_maxCLevel(); cLevel++)
|
||||
for (cLevel=0; cLevel <= NB_LEVELS_TRACKED; cLevel++)
|
||||
BMK_printWinner(f, cLevel, winners[cLevel].result, winners[cLevel].params, srcSize);
|
||||
}
|
||||
|
||||
@@ -350,19 +217,55 @@ static void BMK_printWinners(FILE* f, const winnerInfo_t* winners, size_t srcSiz
|
||||
BMK_printWinners2(stdout, winners, srcSize);
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
double cSpeed_min;
|
||||
double dSpeed_min;
|
||||
U32 windowLog_max;
|
||||
ZSTD_strategy strategy_max;
|
||||
} level_constraints_t;
|
||||
|
||||
static level_constraints_t g_level_constraint[NB_LEVELS_TRACKED+1];
|
||||
|
||||
static void BMK_init_level_constraints(int bytePerSec_level1)
|
||||
{
|
||||
assert(NB_LEVELS_TRACKED >= ZSTD_maxCLevel());
|
||||
memset(g_level_constraint, 0, sizeof(g_level_constraint));
|
||||
g_level_constraint[1].cSpeed_min = bytePerSec_level1;
|
||||
g_level_constraint[1].dSpeed_min = 0.;
|
||||
g_level_constraint[1].windowLog_max = 19;
|
||||
g_level_constraint[1].strategy_max = ZSTD_fast;
|
||||
|
||||
/* establish speed objectives (relative to level 1) */
|
||||
{ int l;
|
||||
for (l=2; l<=NB_LEVELS_TRACKED; l++) {
|
||||
g_level_constraint[l].cSpeed_min = (g_level_constraint[l-1].cSpeed_min * 49) / 64;
|
||||
g_level_constraint[l].dSpeed_min = 0.;
|
||||
g_level_constraint[l].windowLog_max = (l<20) ? 23 : l+5; /* only --ultra levels >= 20 can use windowlog > 23 */
|
||||
g_level_constraint[l].strategy_max = (l<19) ? ZSTD_btopt : ZSTD_btultra; /* level 19 is allowed to use btultra */
|
||||
} }
|
||||
}
|
||||
|
||||
static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters params,
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
ZSTD_CCtx* ctx)
|
||||
ZSTD_CCtx* ctx, ZSTD_DCtx* dctx)
|
||||
{
|
||||
BMK_result_t testResult;
|
||||
int better = 0;
|
||||
int cLevel;
|
||||
|
||||
BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
|
||||
BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, dctx, params);
|
||||
|
||||
for (cLevel = 1; cLevel <= ZSTD_maxCLevel(); cLevel++) {
|
||||
if (testResult.cSpeed < g_cSpeedTarget[cLevel])
|
||||
|
||||
for (cLevel = 1; cLevel <= NB_LEVELS_TRACKED; cLevel++) {
|
||||
if (testResult.cSpeed < g_level_constraint[cLevel].cSpeed_min)
|
||||
continue; /* not fast enough for this level */
|
||||
if (testResult.dSpeed < g_level_constraint[cLevel].dSpeed_min)
|
||||
continue; /* not fast enough for this level */
|
||||
if (params.windowLog > g_level_constraint[cLevel].windowLog_max)
|
||||
continue; /* too much memory for this level */
|
||||
if (params.strategy > g_level_constraint[cLevel].strategy_max)
|
||||
continue; /* forbidden strategy for this level */
|
||||
if (winners[cLevel].result.cSize==0) {
|
||||
/* first solution for this cLevel */
|
||||
winners[cLevel].result = testResult;
|
||||
@@ -514,7 +417,7 @@ static BYTE g_alreadyTested[PARAMTABLESIZE] = {0}; /* init to zero */
|
||||
static void playAround(FILE* f, winnerInfo_t* winners,
|
||||
ZSTD_compressionParameters params,
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
ZSTD_CCtx* ctx)
|
||||
ZSTD_CCtx* ctx, ZSTD_DCtx* dctx)
|
||||
{
|
||||
int nbVariations = 0;
|
||||
UTIL_time_t const clockStart = UTIL_getTime();
|
||||
@@ -531,11 +434,11 @@ static void playAround(FILE* f, winnerInfo_t* winners,
|
||||
|
||||
/* test */
|
||||
NB_TESTS_PLAYED(p)++;
|
||||
if (!BMK_seed(winners, p, srcBuffer, srcSize, ctx)) continue;
|
||||
if (!BMK_seed(winners, p, srcBuffer, srcSize, ctx, dctx)) continue;
|
||||
|
||||
/* improvement found => search more */
|
||||
BMK_printWinners(f, winners, srcSize);
|
||||
playAround(f, winners, p, srcBuffer, srcSize, ctx);
|
||||
playAround(f, winners, p, srcBuffer, srcSize, ctx, dctx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -552,7 +455,7 @@ static ZSTD_compressionParameters randomParams(void)
|
||||
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.searchLength=(FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN)) + ZSTD_SEARCHLENGTH_MIN;
|
||||
p.targetLength=(FUZ_rand(&g_rand) % (512)) + ZSTD_TARGETLENGTH_MIN;
|
||||
p.targetLength=(FUZ_rand(&g_rand) % (512));
|
||||
p.strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btultra +1));
|
||||
validated = !ZSTD_isError(ZSTD_checkCParams(p));
|
||||
}
|
||||
@@ -562,55 +465,50 @@ static ZSTD_compressionParameters randomParams(void)
|
||||
static void BMK_selectRandomStart(
|
||||
FILE* f, winnerInfo_t* winners,
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
ZSTD_CCtx* ctx)
|
||||
ZSTD_CCtx* ctx, ZSTD_DCtx* dctx)
|
||||
{
|
||||
U32 const id = (FUZ_rand(&g_rand) % (ZSTD_maxCLevel()+1));
|
||||
U32 const id = FUZ_rand(&g_rand) % (NB_LEVELS_TRACKED+1);
|
||||
if ((id==0) || (winners[id].params.windowLog==0)) {
|
||||
/* totally random entry */
|
||||
/* use some random entry */
|
||||
ZSTD_compressionParameters const p = ZSTD_adjustCParams(randomParams(), srcSize, 0);
|
||||
playAround(f, winners, p, srcBuffer, srcSize, ctx);
|
||||
playAround(f, winners, p, srcBuffer, srcSize, ctx, dctx);
|
||||
} else {
|
||||
playAround(f, winners, winners[id].params, srcBuffer, srcSize, ctx, dctx);
|
||||
}
|
||||
else
|
||||
playAround(f, winners, winners[id].params, srcBuffer, srcSize, ctx);
|
||||
}
|
||||
|
||||
|
||||
static void BMK_benchMem(void* srcBuffer, size_t srcSize)
|
||||
static void BMK_benchOnce(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx, const void* srcBuffer, size_t srcSize)
|
||||
{
|
||||
BMK_result_t testResult;
|
||||
g_params = ZSTD_adjustCParams(g_params, srcSize, 0);
|
||||
BMK_benchParam(&testResult, srcBuffer, srcSize, cctx, dctx, g_params);
|
||||
DISPLAY("Compression Ratio: %.3f Compress Speed: %.1f MB/s Decompress Speed: %.1f MB/s\n", (double)srcSize / testResult.cSize,
|
||||
testResult.cSpeed / 1000000, testResult.dSpeed / 1000000);
|
||||
return;
|
||||
}
|
||||
|
||||
static void BMK_benchFullTable(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx, const void* srcBuffer, size_t srcSize)
|
||||
{
|
||||
ZSTD_CCtx* const ctx = ZSTD_createCCtx();
|
||||
ZSTD_compressionParameters params;
|
||||
winnerInfo_t winners[NB_LEVELS_TRACKED];
|
||||
winnerInfo_t winners[NB_LEVELS_TRACKED+1];
|
||||
const char* const rfName = "grillResults.txt";
|
||||
FILE* const f = fopen(rfName, "w");
|
||||
const size_t blockSize = g_blockSize ? g_blockSize : srcSize;
|
||||
const size_t blockSize = g_blockSize ? g_blockSize : srcSize; /* cut by block or not ? */
|
||||
|
||||
/* init */
|
||||
if (ctx==NULL) { DISPLAY("ZSTD_createCCtx() failed \n"); exit(1); }
|
||||
assert(g_singleRun==0);
|
||||
memset(winners, 0, sizeof(winners));
|
||||
if (f==NULL) { DISPLAY("error opening %s \n", rfName); exit(1); }
|
||||
|
||||
if (g_singleRun) {
|
||||
BMK_result_t testResult;
|
||||
g_params = ZSTD_adjustCParams(g_params, srcSize, 0);
|
||||
BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, g_params);
|
||||
DISPLAY("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_target)
|
||||
g_cSpeedTarget[1] = g_target * 1000000;
|
||||
else {
|
||||
if (g_target) {
|
||||
BMK_init_level_constraints(g_target*1000000);
|
||||
} else {
|
||||
/* baseline config for level 1 */
|
||||
ZSTD_compressionParameters const l1params = ZSTD_getCParams(1, blockSize, 0);
|
||||
BMK_result_t testResult;
|
||||
params = ZSTD_getCParams(1, blockSize, 0);
|
||||
BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
|
||||
g_cSpeedTarget[1] = (testResult.cSpeed * 31) / 32;
|
||||
}
|
||||
|
||||
/* establish speed objectives (relative to level 1) */
|
||||
{ int i;
|
||||
for (i=2; i<=ZSTD_maxCLevel(); i++)
|
||||
g_cSpeedTarget[i] = (g_cSpeedTarget[i-1] * 25) / 32;
|
||||
BMK_benchParam(&testResult, srcBuffer, srcSize, cctx, dctx, l1params);
|
||||
BMK_init_level_constraints((int)((testResult.cSpeed * 31) / 32));
|
||||
}
|
||||
|
||||
/* populate initial solution */
|
||||
@@ -618,14 +516,14 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize)
|
||||
int i;
|
||||
for (i=0; i<=maxSeeds; i++) {
|
||||
params = ZSTD_getCParams(i, blockSize, 0);
|
||||
BMK_seed(winners, params, srcBuffer, srcSize, ctx);
|
||||
BMK_seed(winners, params, srcBuffer, srcSize, cctx, dctx);
|
||||
} }
|
||||
BMK_printWinners(f, winners, srcSize);
|
||||
|
||||
/* start tests */
|
||||
{ const time_t grillStart = time(NULL);
|
||||
do {
|
||||
BMK_selectRandomStart(f, winners, srcBuffer, srcSize, ctx);
|
||||
BMK_selectRandomStart(f, winners, srcBuffer, srcSize, cctx, dctx);
|
||||
} while (BMK_timeSpan(grillStart) < g_grillDuration_s);
|
||||
}
|
||||
|
||||
@@ -635,19 +533,33 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize)
|
||||
|
||||
/* clean up*/
|
||||
fclose(f);
|
||||
ZSTD_freeCCtx(ctx);
|
||||
}
|
||||
|
||||
static void BMK_benchMem_usingCCtx(ZSTD_CCtx* const cctx, ZSTD_DCtx* const dctx, const void* srcBuffer, size_t srcSize)
|
||||
{
|
||||
if (g_singleRun)
|
||||
return BMK_benchOnce(cctx, dctx, srcBuffer, srcSize);
|
||||
else
|
||||
return BMK_benchFullTable(cctx, dctx, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
static void BMK_benchMemCCtxInit(const void* srcBuffer, size_t srcSize)
|
||||
{
|
||||
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
if (cctx==NULL || dctx==NULL) { DISPLAY("Context Creation failed \n"); exit(1); }
|
||||
BMK_benchMem_usingCCtx(cctx, dctx, srcBuffer, srcSize);
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
|
||||
|
||||
static int benchSample(void)
|
||||
{
|
||||
void* origBuff;
|
||||
size_t const benchedSize = sampleSize;
|
||||
const char* const name = "Sample 10MiB";
|
||||
const char* const name = "Sample 10MB";
|
||||
size_t const benchedSize = 10000000;
|
||||
|
||||
/* Allocation */
|
||||
origBuff = malloc(benchedSize);
|
||||
if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; }
|
||||
void* origBuff = malloc(benchedSize);
|
||||
if (!origBuff) { perror("not enough memory"); return 12; }
|
||||
|
||||
/* Fill buffer */
|
||||
RDG_genBuffer(origBuff, benchedSize, g_compressibility, 0.0, 0);
|
||||
@@ -655,13 +567,16 @@ static int benchSample(void)
|
||||
/* bench */
|
||||
DISPLAY("\r%79s\r", "");
|
||||
DISPLAY("using %s %i%%: \n", name, (int)(g_compressibility*100));
|
||||
BMK_benchMem(origBuff, benchedSize);
|
||||
BMK_benchMemCCtxInit(origBuff, benchedSize);
|
||||
|
||||
free(origBuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* benchFiles() :
|
||||
* note: while this function takes a table of filenames,
|
||||
* in practice, only the first filename will be used */
|
||||
int benchFiles(const char** fileNamesTable, int nbFiles)
|
||||
{
|
||||
int fileIdx=0;
|
||||
@@ -680,7 +595,7 @@ int benchFiles(const char** fileNamesTable, int nbFiles)
|
||||
return 11;
|
||||
}
|
||||
if (inFileSize == UTIL_FILESIZE_UNKNOWN) {
|
||||
DISPLAY("Pb evaluatin size of %s \n", inFileName);
|
||||
DISPLAY("Pb evaluating size of %s \n", inFileName);
|
||||
fclose(inFile);
|
||||
return 11;
|
||||
}
|
||||
@@ -710,7 +625,7 @@ int benchFiles(const char** fileNamesTable, int nbFiles)
|
||||
/* bench */
|
||||
DISPLAY("\r%79s\r", "");
|
||||
DISPLAY("using %s : \n", inFileName);
|
||||
BMK_benchMem(origBuff, benchedSize);
|
||||
BMK_benchMemCCtxInit(origBuff, benchedSize);
|
||||
|
||||
/* clean */
|
||||
free(origBuff);
|
||||
@@ -734,7 +649,6 @@ int optimizeForSize(const char* inFileName, U32 targetSpeed)
|
||||
U64 const inFileSize = UTIL_getFileSize(inFileName);
|
||||
size_t benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
|
||||
void* origBuff;
|
||||
|
||||
/* Init */
|
||||
if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; }
|
||||
if (inFileSize == UTIL_FILESIZE_UNKNOWN) {
|
||||
@@ -773,8 +687,8 @@ int optimizeForSize(const char* inFileName, U32 targetSpeed)
|
||||
DISPLAY("\r%79s\r", "");
|
||||
DISPLAY("optimizing for %s - limit speed %u MB/s \n", inFileName, targetSpeed);
|
||||
targetSpeed *= 1000000;
|
||||
|
||||
{ ZSTD_CCtx* const ctx = ZSTD_createCCtx();
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
winnerInfo_t winner;
|
||||
BMK_result_t candidate;
|
||||
const size_t blockSize = g_blockSize ? g_blockSize : benchedSize;
|
||||
@@ -789,9 +703,10 @@ int optimizeForSize(const char* inFileName, U32 targetSpeed)
|
||||
int i;
|
||||
for (i=1; i<=maxSeeds; i++) {
|
||||
ZSTD_compressionParameters const CParams = ZSTD_getCParams(i, blockSize, 0);
|
||||
BMK_benchParam(&candidate, origBuff, benchedSize, ctx, CParams);
|
||||
if (candidate.cSpeed < targetSpeed)
|
||||
BMK_benchParam(&candidate, origBuff, benchedSize, ctx, dctx, CParams);
|
||||
if (candidate.cSpeed < (double)targetSpeed) {
|
||||
break;
|
||||
}
|
||||
if ( (candidate.cSize < winner.result.cSize)
|
||||
| ((candidate.cSize == winner.result.cSize) & (candidate.cSpeed > winner.result.cSpeed)) )
|
||||
{
|
||||
@@ -800,7 +715,9 @@ int optimizeForSize(const char* inFileName, U32 targetSpeed)
|
||||
BMK_printWinner(stdout, i, winner.result, winner.params, benchedSize);
|
||||
} }
|
||||
}
|
||||
BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
|
||||
|
||||
BMK_printWinner(stdout, CUSTOM_LEVEL, winner.result, winner.params, benchedSize);
|
||||
|
||||
BMK_translateAdvancedParams(winner.params);
|
||||
|
||||
/* start tests */
|
||||
@@ -816,7 +733,7 @@ int optimizeForSize(const char* inFileName, U32 targetSpeed)
|
||||
|
||||
/* test */
|
||||
NB_TESTS_PLAYED(params)++;
|
||||
BMK_benchParam(&candidate, origBuff, benchedSize, ctx, params);
|
||||
BMK_benchParam(&candidate, origBuff, benchedSize, ctx, dctx, params);
|
||||
|
||||
/* improvement found => new winner */
|
||||
if ( (candidate.cSpeed > targetSpeed)
|
||||
@@ -825,24 +742,59 @@ int optimizeForSize(const char* inFileName, U32 targetSpeed)
|
||||
{
|
||||
winner.params = params;
|
||||
winner.result = candidate;
|
||||
BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
|
||||
BMK_printWinner(stdout, CUSTOM_LEVEL, winner.result, winner.params, benchedSize);
|
||||
BMK_translateAdvancedParams(winner.params);
|
||||
}
|
||||
} while (BMK_timeSpan(grillStart) < g_grillDuration_s);
|
||||
}
|
||||
|
||||
/* end summary */
|
||||
BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
|
||||
|
||||
BMK_printWinner(stdout, CUSTOM_LEVEL, winner.result, winner.params, benchedSize);
|
||||
BMK_translateAdvancedParams(winner.params);
|
||||
DISPLAY("grillParams size - optimizer completed \n");
|
||||
|
||||
/* clean up*/
|
||||
ZSTD_freeCCtx(ctx);
|
||||
ZSTD_freeDCtx(dctx);
|
||||
}
|
||||
|
||||
free(origBuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void errorOut(const char* msg)
|
||||
{
|
||||
DISPLAY("%s \n", msg); exit(1);
|
||||
}
|
||||
|
||||
/*! readU32FromChar() :
|
||||
* @return : unsigned integer value read from input in `char` format.
|
||||
* allows and interprets K, KB, KiB, M, MB and MiB suffix.
|
||||
* Will also modify `*stringPtr`, advancing it to position where it stopped reading.
|
||||
* Note : function will exit() program if digit sequence overflows */
|
||||
static unsigned readU32FromChar(const char** stringPtr)
|
||||
{
|
||||
const char errorMsg[] = "error: numeric value too large";
|
||||
unsigned result = 0;
|
||||
while ((**stringPtr >='0') && (**stringPtr <='9')) {
|
||||
unsigned const max = (((unsigned)(-1)) / 10) - 1;
|
||||
if (result > max) errorOut(errorMsg);
|
||||
result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
|
||||
}
|
||||
if ((**stringPtr=='K') || (**stringPtr=='M')) {
|
||||
unsigned const maxK = ((unsigned)(-1)) >> 10;
|
||||
if (result > maxK) errorOut(errorMsg);
|
||||
result <<= 10;
|
||||
if (**stringPtr=='M') {
|
||||
if (result > maxK) errorOut(errorMsg);
|
||||
result <<= 10;
|
||||
}
|
||||
(*stringPtr)++; /* skip `K` or `M` */
|
||||
if (**stringPtr=='i') (*stringPtr)++;
|
||||
if (**stringPtr=='B') (*stringPtr)++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int usage(const char* exename)
|
||||
{
|
||||
@@ -862,7 +814,10 @@ static int usage_advanced(void)
|
||||
DISPLAY( " -i# : iteration loops [1-9](default : %i) \n", NBLOOPS);
|
||||
DISPLAY( " -O# : find Optimized parameters for # MB/s compression speed (default : 0) \n");
|
||||
DISPLAY( " -S : Single run \n");
|
||||
DISPLAY( " --zstd : Single run, parameter selection same as zstdcli \n");
|
||||
DISPLAY( " -P# : generated sample compressibility (default : %.1f%%) \n", COMPRESSIBILITY_DEFAULT * 100);
|
||||
DISPLAY( " -t# : Caps runtime of operation in seconds (default : %u seconds (%.1f hours)) \n", (U32)g_grillDuration_s, g_grillDuration_s / 3600);
|
||||
DISPLAY( " -v : Prints Benchmarking output\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -884,26 +839,40 @@ int main(int argc, const char** argv)
|
||||
U32 main_pause = 0;
|
||||
U32 targetSpeed = 0;
|
||||
|
||||
/* checks */
|
||||
if (NB_LEVELS_TRACKED <= ZSTD_maxCLevel()) {
|
||||
DISPLAY("Error : NB_LEVELS_TRACKED <= ZSTD_maxCLevel() \n");
|
||||
exit(1);
|
||||
}
|
||||
assert(argc>=1); /* for exename */
|
||||
|
||||
/* Welcome message */
|
||||
DISPLAY(WELCOME_MESSAGE);
|
||||
|
||||
if (argc<1) { badusage(exename); return 1; }
|
||||
|
||||
for(i=1; i<argc; i++) {
|
||||
const char* argument = argv[i];
|
||||
|
||||
if(!argument) continue; /* Protection if argument empty */
|
||||
assert(argument != NULL);
|
||||
|
||||
if(!strcmp(argument,"--no-seed")) { g_noSeed = 1; continue; }
|
||||
|
||||
/* Decode command (note : aggregated commands are allowed) */
|
||||
if (argument[0]=='-') {
|
||||
if (longCommandWArg(&argument, "--zstd=")) {
|
||||
g_singleRun = 1;
|
||||
g_params = ZSTD_getCParams(2, g_blockSize, 0);
|
||||
for ( ; ;) {
|
||||
if (longCommandWArg(&argument, "windowLog=") || longCommandWArg(&argument, "wlog=")) { g_params.windowLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
if (longCommandWArg(&argument, "chainLog=") || longCommandWArg(&argument, "clog=")) { g_params.chainLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
if (longCommandWArg(&argument, "hashLog=") || longCommandWArg(&argument, "hlog=")) { g_params.hashLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
if (longCommandWArg(&argument, "searchLog=") || longCommandWArg(&argument, "slog=")) { g_params.searchLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
if (longCommandWArg(&argument, "searchLength=") || longCommandWArg(&argument, "slen=")) { g_params.searchLength = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
if (longCommandWArg(&argument, "targetLength=") || longCommandWArg(&argument, "tlen=")) { g_params.targetLength = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
if (longCommandWArg(&argument, "strategy=") || longCommandWArg(&argument, "strat=")) { g_params.strategy = (ZSTD_strategy)(readU32FromChar(&argument)); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
if (longCommandWArg(&argument, "level=") || longCommandWArg(&argument, "lvl=")) { g_params = ZSTD_getCParams(readU32FromChar(&argument), g_blockSize, 0); if (argument[0]==',') { argument++; continue; } else break; }
|
||||
DISPLAY("invalid compression parameter \n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argument[0] != 0) {
|
||||
DISPLAY("invalid --zstd= format\n");
|
||||
return 1; /* check the end of string */
|
||||
}
|
||||
/* if not return, success */
|
||||
} else if (argument[0]=='-') {
|
||||
argument++;
|
||||
|
||||
while (argument[0]!=0) {
|
||||
@@ -916,30 +885,25 @@ int main(int argc, const char** argv)
|
||||
|
||||
/* Pause at the end (hidden option) */
|
||||
case 'p': main_pause = 1; argument++; break;
|
||||
|
||||
/* Modify Nb Iterations */
|
||||
|
||||
case 'i':
|
||||
argument++;
|
||||
if ((argument[0] >='0') & (argument[0] <='9'))
|
||||
g_nbIterations = *argument++ - '0';
|
||||
g_nbIterations = readU32FromChar(&argument);
|
||||
break;
|
||||
|
||||
/* Sample compressibility (when no file provided) */
|
||||
case 'P':
|
||||
argument++;
|
||||
{ U32 proba32 = 0;
|
||||
while ((argument[0]>= '0') & (argument[0]<= '9'))
|
||||
proba32 = (proba32*10) + (*argument++ - '0');
|
||||
{ U32 const proba32 = readU32FromChar(&argument);
|
||||
g_compressibility = (double)proba32 / 100.;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
argument++;
|
||||
optimizer=1;
|
||||
targetSpeed = 0;
|
||||
while ((*argument >= '0') & (*argument <= '9'))
|
||||
targetSpeed = (targetSpeed*10) + (*argument++ - '0');
|
||||
optimizer = 1;
|
||||
targetSpeed = readU32FromChar(&argument);
|
||||
break;
|
||||
|
||||
/* Run Single conf */
|
||||
@@ -951,51 +915,35 @@ int main(int argc, const char** argv)
|
||||
switch(*argument)
|
||||
{
|
||||
case 'w':
|
||||
g_params.windowLog = 0;
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
g_params.windowLog *= 10, g_params.windowLog += *argument++ - '0';
|
||||
g_params.windowLog = readU32FromChar(&argument);
|
||||
continue;
|
||||
case 'c':
|
||||
g_params.chainLog = 0;
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
g_params.chainLog *= 10, g_params.chainLog += *argument++ - '0';
|
||||
g_params.chainLog = readU32FromChar(&argument);
|
||||
continue;
|
||||
case 'h':
|
||||
g_params.hashLog = 0;
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
g_params.hashLog *= 10, g_params.hashLog += *argument++ - '0';
|
||||
g_params.hashLog = readU32FromChar(&argument);
|
||||
continue;
|
||||
case 's':
|
||||
g_params.searchLog = 0;
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
g_params.searchLog *= 10, g_params.searchLog += *argument++ - '0';
|
||||
g_params.searchLog = readU32FromChar(&argument);
|
||||
continue;
|
||||
case 'l': /* search length */
|
||||
g_params.searchLength = 0;
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
g_params.searchLength *= 10, g_params.searchLength += *argument++ - '0';
|
||||
g_params.searchLength = readU32FromChar(&argument);
|
||||
continue;
|
||||
case 't': /* target length */
|
||||
g_params.targetLength = 0;
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
g_params.targetLength *= 10, g_params.targetLength += *argument++ - '0';
|
||||
g_params.targetLength = readU32FromChar(&argument);
|
||||
continue;
|
||||
case 'S': /* strategy */
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
g_params.strategy = (ZSTD_strategy)(*argument++ - '0');
|
||||
g_params.strategy = (ZSTD_strategy)readU32FromChar(&argument);
|
||||
continue;
|
||||
case 'L':
|
||||
{ int cLevel = 0;
|
||||
argument++;
|
||||
while ((*argument>= '0') && (*argument<='9'))
|
||||
cLevel *= 10, cLevel += *argument++ - '0';
|
||||
{ int const cLevel = readU32FromChar(&argument);
|
||||
g_params = ZSTD_getCParams(cLevel, g_blockSize, 0);
|
||||
continue;
|
||||
}
|
||||
@@ -1003,28 +951,28 @@ int main(int argc, const char** argv)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* target level1 speed objective, in MB/s */
|
||||
case 'T':
|
||||
argument++;
|
||||
g_target = 0;
|
||||
while ((*argument >= '0') && (*argument <= '9'))
|
||||
g_target = (g_target*10) + (*argument++ - '0');
|
||||
g_target = readU32FromChar(&argument);
|
||||
break;
|
||||
|
||||
/* cut input into blocks */
|
||||
case 'B':
|
||||
g_blockSize = 0;
|
||||
argument++;
|
||||
while ((*argument >='0') & (*argument <='9'))
|
||||
g_blockSize = (g_blockSize*10) + (*argument++ - '0');
|
||||
if (*argument=='K') g_blockSize<<=10, argument++; /* allows using KB notation */
|
||||
if (*argument=='M') g_blockSize<<=20, argument++;
|
||||
if (*argument=='B') argument++;
|
||||
g_blockSize = readU32FromChar(&argument);
|
||||
DISPLAY("using %u KB block size \n", g_blockSize>>10);
|
||||
break;
|
||||
|
||||
/* caps runtime (in seconds) */
|
||||
case 't':
|
||||
argument++;
|
||||
g_grillDuration_s = (double)readU32FromChar(&argument);
|
||||
break;
|
||||
|
||||
/* Unknown command */
|
||||
default : return badusage(exename);
|
||||
}
|
||||
@@ -1036,14 +984,19 @@ int main(int argc, const char** argv)
|
||||
if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
|
||||
}
|
||||
|
||||
if (filenamesStart==0)
|
||||
result = benchSample();
|
||||
else {
|
||||
if (optimizer)
|
||||
if (filenamesStart==0) {
|
||||
if (optimizer) {
|
||||
DISPLAY("Optimizer Expects File\n");
|
||||
return 1;
|
||||
} else {
|
||||
result = benchSample();
|
||||
}
|
||||
} else {
|
||||
if (optimizer) {
|
||||
result = optimizeForSize(input_filename, targetSpeed);
|
||||
else
|
||||
} else {
|
||||
result = benchFiles(argv+filenamesStart, argc-filenamesStart);
|
||||
}
|
||||
} }
|
||||
|
||||
if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; }
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ fi
|
||||
|
||||
isWindows=false
|
||||
INTOVOID="/dev/null"
|
||||
DEVDEVICE="/dev/zero"
|
||||
DEVDEVICE="/dev/random"
|
||||
case "$OS" in
|
||||
Windows*)
|
||||
isWindows=true
|
||||
@@ -69,6 +69,7 @@ UNAME=$(uname)
|
||||
case "$UNAME" in
|
||||
Darwin) MD5SUM="md5 -r" ;;
|
||||
FreeBSD) MD5SUM="gmd5sum" ;;
|
||||
OpenBSD) MD5SUM="md5" ;;
|
||||
*) MD5SUM="md5sum" ;;
|
||||
esac
|
||||
|
||||
@@ -107,6 +108,9 @@ $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
|
||||
! $ZSTD -c --fast=0 tmp > $INTOVOID # should fail
|
||||
$ECHO "test : too large numeric argument"
|
||||
$ZSTD --fast=9999999999 -f tmp && die "should have refused numeric value"
|
||||
$ECHO "test : compress to stdout"
|
||||
$ZSTD tmp -c > tmpCompressed
|
||||
$ZSTD tmp --stdout > tmpCompressed # long command format
|
||||
@@ -175,7 +179,7 @@ $ECHO hello > tmp
|
||||
$ZSTD tmp -f -o "$DEVDEVICE" 2>tmplog > "$INTOVOID"
|
||||
grep -v "Refusing to remove non-regular file" tmplog
|
||||
rm -f tmplog
|
||||
$ZSTD tmp -f -o "$INTONULL" 2>&1 | grep -v "Refusing to remove non-regular file"
|
||||
$ZSTD tmp -f -o "$INTOVOID" 2>&1 | grep -v "Refusing to remove non-regular file"
|
||||
$ECHO "test : --rm on stdin"
|
||||
$ECHO a | $ZSTD --rm > $INTOVOID # --rm should remain silent
|
||||
rm tmp
|
||||
@@ -183,6 +187,7 @@ $ZSTD -f tmp && die "tmp not present : should have failed"
|
||||
test ! -f tmp.zst # tmp.zst should not be created
|
||||
|
||||
$ECHO "test : compress multiple files"
|
||||
rm tmp*
|
||||
$ECHO hello > tmp1
|
||||
$ECHO world > tmp2
|
||||
$ZSTD tmp1 tmp2 -o "$INTOVOID"
|
||||
@@ -258,7 +263,7 @@ rm ./*.tmp ./*.zstd
|
||||
$ECHO "frame concatenation tests completed"
|
||||
|
||||
|
||||
if [ "$isWindows" = false ] && [ "$UNAME" != 'SunOS' ] ; then
|
||||
if [ "$isWindows" = false ] && [ "$UNAME" != 'SunOS' ] && [ "$UNAME" != "OpenBSD" ] ; then
|
||||
$ECHO "\n**** flush write error test **** "
|
||||
|
||||
$ECHO "$ECHO foo | $ZSTD > /dev/full"
|
||||
@@ -482,6 +487,12 @@ $ZSTD -bi0 --fast tmp1
|
||||
$ECHO "with recursive and quiet modes"
|
||||
$ZSTD -rqi1b1e2 tmp1
|
||||
|
||||
$ECHO "\n===> zstd compatibility tests "
|
||||
|
||||
./datagen > tmp
|
||||
rm -f tmp.zst
|
||||
$ZSTD --format=zstd -f tmp
|
||||
test -f tmp.zst
|
||||
|
||||
$ECHO "\n===> gzip compatibility tests "
|
||||
|
||||
@@ -519,6 +530,12 @@ else
|
||||
$ECHO "gzip mode not supported"
|
||||
fi
|
||||
|
||||
if [ $GZIPMODE -eq 1 ]; then
|
||||
./datagen > tmp
|
||||
rm -f tmp.zst
|
||||
$ZSTD --format=gzip --format=zstd -f tmp
|
||||
test -f tmp.zst
|
||||
fi
|
||||
|
||||
$ECHO "\n===> xz compatibility tests "
|
||||
|
||||
@@ -617,6 +634,23 @@ else
|
||||
$ECHO "lz4 mode not supported"
|
||||
fi
|
||||
|
||||
$ECHO "\n===> suffix list test"
|
||||
|
||||
! $ZSTD -d tmp.abc 2> tmplg
|
||||
|
||||
if [ $GZIPMODE -ne 1 ]; then
|
||||
grep ".gz" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
fi
|
||||
|
||||
if [ $LZMAMODE -ne 1 ]; then
|
||||
grep ".lzma" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
grep ".xz" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
fi
|
||||
|
||||
if [ $LZ4MODE -ne 1 ]; then
|
||||
grep ".lz4" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
fi
|
||||
|
||||
$ECHO "\n===> zstd round-trip tests "
|
||||
|
||||
roundTripTest
|
||||
@@ -650,6 +684,25 @@ then
|
||||
|
||||
$ECHO "\n===> zstdmt long distance matching round-trip tests "
|
||||
roundTripTest -g8M "3 --long=24 -T2"
|
||||
|
||||
$ECHO "\n===> ovLog tests "
|
||||
./datagen -g2MB > tmp
|
||||
refSize=$($ZSTD tmp -6 -c --zstd=wlog=18 | wc -c)
|
||||
ov9Size=$($ZSTD tmp -6 -c --zstd=wlog=18,ovlog=9 | wc -c)
|
||||
ov0Size=$($ZSTD tmp -6 -c --zstd=wlog=18,ovlog=0 | wc -c)
|
||||
if [ $refSize -eq $ov9Size ]; then
|
||||
echo ov9Size should be different from refSize
|
||||
exit 1
|
||||
fi
|
||||
if [ $refSize -eq $ov0Size ]; then
|
||||
echo ov0Size should be different from refSize
|
||||
exit 1
|
||||
fi
|
||||
if [ $ov9Size -ge $ov0Size ]; then
|
||||
echo ov9Size=$ov9Size should be smaller than ov0Size=$ov0Size
|
||||
exit 1
|
||||
fi
|
||||
|
||||
else
|
||||
$ECHO "\n===> no multithreading, skipping zstdmt tests "
|
||||
fi
|
||||
@@ -678,6 +731,9 @@ $ECHO "\n===> zstd --list/-l error detection tests "
|
||||
! $ZSTD -lv tmp1*
|
||||
! $ZSTD --list -v tmp2 tmp12.zst
|
||||
|
||||
$ECHO "\n===> zstd --list/-l exits 1 when stdin is piped in"
|
||||
! echo "piped STDIN" | $ZSTD --list
|
||||
|
||||
$ECHO "\n===> zstd --list/-l test with null files "
|
||||
./datagen -g0 > tmp5
|
||||
$ZSTD tmp5
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ASSERT_TRUE(p) \
|
||||
do { \
|
||||
if (!(p)) { \
|
||||
return 1; \
|
||||
} \
|
||||
#define ASSERT_TRUE(p) \
|
||||
do { \
|
||||
if (!(p)) { \
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
#define ASSERT_FALSE(p) ASSERT_TRUE(!(p))
|
||||
#define ASSERT_EQ(lhs, rhs) ASSERT_TRUE((lhs) == (rhs))
|
||||
@@ -32,10 +32,10 @@ struct data {
|
||||
|
||||
void fn(void *opaque) {
|
||||
struct data *data = (struct data *)opaque;
|
||||
pthread_mutex_lock(&data->mutex);
|
||||
ZSTD_pthread_mutex_lock(&data->mutex);
|
||||
data->data[data->i] = data->i;
|
||||
++data->i;
|
||||
pthread_mutex_unlock(&data->mutex);
|
||||
ZSTD_pthread_mutex_unlock(&data->mutex);
|
||||
}
|
||||
|
||||
int testOrder(size_t numThreads, size_t queueSize) {
|
||||
@@ -43,25 +43,26 @@ int testOrder(size_t numThreads, size_t queueSize) {
|
||||
POOL_ctx *ctx = POOL_create(numThreads, queueSize);
|
||||
ASSERT_TRUE(ctx);
|
||||
data.i = 0;
|
||||
pthread_mutex_init(&data.mutex, NULL);
|
||||
{
|
||||
size_t i;
|
||||
ZSTD_pthread_mutex_init(&data.mutex, NULL);
|
||||
{ size_t i;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
POOL_add(ctx, &fn, &data);
|
||||
}
|
||||
}
|
||||
POOL_free(ctx);
|
||||
ASSERT_EQ(16, data.i);
|
||||
{
|
||||
size_t i;
|
||||
{ size_t i;
|
||||
for (i = 0; i < data.i; ++i) {
|
||||
ASSERT_EQ(i, data.data[i]);
|
||||
}
|
||||
}
|
||||
pthread_mutex_destroy(&data.mutex);
|
||||
ZSTD_pthread_mutex_destroy(&data.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --- test deadlocks --- */
|
||||
|
||||
void waitFn(void *opaque) {
|
||||
(void)opaque;
|
||||
UTIL_sleepMilli(1);
|
||||
@@ -72,8 +73,7 @@ int testWait(size_t numThreads, size_t queueSize) {
|
||||
struct data data;
|
||||
POOL_ctx *ctx = POOL_create(numThreads, queueSize);
|
||||
ASSERT_TRUE(ctx);
|
||||
{
|
||||
size_t i;
|
||||
{ size_t i;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
POOL_add(ctx, &waitFn, &data);
|
||||
}
|
||||
@@ -82,25 +82,178 @@ int testWait(size_t numThreads, size_t queueSize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --- test POOL_resize() --- */
|
||||
|
||||
typedef struct {
|
||||
ZSTD_pthread_mutex_t mut;
|
||||
int val;
|
||||
int max;
|
||||
ZSTD_pthread_cond_t cond;
|
||||
} poolTest_t;
|
||||
|
||||
void waitLongFn(void *opaque) {
|
||||
poolTest_t* test = (poolTest_t*) opaque;
|
||||
UTIL_sleepMilli(10);
|
||||
ZSTD_pthread_mutex_lock(&test->mut);
|
||||
test->val = test->val + 1;
|
||||
if (test->val == test->max)
|
||||
ZSTD_pthread_cond_signal(&test->cond);
|
||||
ZSTD_pthread_mutex_unlock(&test->mut);
|
||||
}
|
||||
|
||||
static int testThreadReduction_internal(POOL_ctx* ctx, poolTest_t test)
|
||||
{
|
||||
int const nbWaits = 16;
|
||||
UTIL_time_t startTime;
|
||||
U64 time4threads, time2threads;
|
||||
|
||||
test.val = 0;
|
||||
test.max = nbWaits;
|
||||
|
||||
startTime = UTIL_getTime();
|
||||
{ int i;
|
||||
for (i=0; i<nbWaits; i++)
|
||||
POOL_add(ctx, &waitLongFn, &test);
|
||||
}
|
||||
ZSTD_pthread_mutex_lock(&test.mut);
|
||||
ZSTD_pthread_cond_wait(&test.cond, &test.mut);
|
||||
ASSERT_EQ(test.val, nbWaits);
|
||||
ZSTD_pthread_mutex_unlock(&test.mut);
|
||||
time4threads = UTIL_clockSpanNano(startTime);
|
||||
|
||||
ASSERT_EQ( POOL_resize(ctx, 2/*nbThreads*/) , 0 );
|
||||
test.val = 0;
|
||||
startTime = UTIL_getTime();
|
||||
{ int i;
|
||||
for (i=0; i<nbWaits; i++)
|
||||
POOL_add(ctx, &waitLongFn, &test);
|
||||
}
|
||||
ZSTD_pthread_mutex_lock(&test.mut);
|
||||
ZSTD_pthread_cond_wait(&test.cond, &test.mut);
|
||||
ASSERT_EQ(test.val, nbWaits);
|
||||
ZSTD_pthread_mutex_unlock(&test.mut);
|
||||
time2threads = UTIL_clockSpanNano(startTime);
|
||||
|
||||
if (time4threads >= time2threads) return 1; /* check 4 threads were effectively faster than 2 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int testThreadReduction(void) {
|
||||
int result;
|
||||
poolTest_t test;
|
||||
POOL_ctx* const ctx = POOL_create(4 /*nbThreads*/, 2 /*queueSize*/);
|
||||
|
||||
ASSERT_TRUE(ctx);
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
ASSERT_FALSE( ZSTD_pthread_mutex_init(&test.mut, NULL) );
|
||||
ASSERT_FALSE( ZSTD_pthread_cond_init(&test.cond, NULL) );
|
||||
|
||||
result = testThreadReduction_internal(ctx, test);
|
||||
|
||||
ZSTD_pthread_mutex_destroy(&test.mut);
|
||||
ZSTD_pthread_cond_destroy(&test.cond);
|
||||
POOL_free(ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* --- test abrupt ending --- */
|
||||
|
||||
typedef struct {
|
||||
ZSTD_pthread_mutex_t mut;
|
||||
int val;
|
||||
} abruptEndCanary_t;
|
||||
|
||||
void waitIncFn(void *opaque) {
|
||||
abruptEndCanary_t* test = (abruptEndCanary_t*) opaque;
|
||||
UTIL_sleepMilli(10);
|
||||
ZSTD_pthread_mutex_lock(&test->mut);
|
||||
test->val = test->val + 1;
|
||||
ZSTD_pthread_mutex_unlock(&test->mut);
|
||||
}
|
||||
|
||||
static int testAbruptEnding_internal(abruptEndCanary_t test)
|
||||
{
|
||||
int const nbWaits = 16;
|
||||
|
||||
POOL_ctx* const ctx = POOL_create(3 /*numThreads*/, nbWaits /*queueSize*/);
|
||||
ASSERT_TRUE(ctx);
|
||||
test.val = 0;
|
||||
|
||||
{ int i;
|
||||
for (i=0; i<nbWaits; i++)
|
||||
POOL_add(ctx, &waitIncFn, &test); /* all jobs pushed into queue */
|
||||
}
|
||||
ASSERT_EQ( POOL_resize(ctx, 1 /*numThreads*/) , 0 ); /* downsize numThreads, to try to break end condition */
|
||||
|
||||
POOL_free(ctx); /* must finish all jobs in queue before giving back control */
|
||||
ASSERT_EQ(test.val, nbWaits);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int testAbruptEnding(void) {
|
||||
int result;
|
||||
abruptEndCanary_t test;
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
ASSERT_FALSE( ZSTD_pthread_mutex_init(&test.mut, NULL) );
|
||||
|
||||
result = testAbruptEnding_internal(test);
|
||||
|
||||
ZSTD_pthread_mutex_destroy(&test.mut);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- test launcher --- */
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
size_t numThreads;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
if (POOL_create(0, 1)) { /* should not be possible */
|
||||
printf("FAIL: should not create POOL with 0 threads\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (numThreads = 1; numThreads <= 4; ++numThreads) {
|
||||
size_t queueSize;
|
||||
for (queueSize = 0; queueSize <= 2; ++queueSize) {
|
||||
printf("queueSize==%u, numThreads=%u \n",
|
||||
(unsigned)queueSize, (unsigned)numThreads);
|
||||
if (testOrder(numThreads, queueSize)) {
|
||||
printf("FAIL: testOrder\n");
|
||||
return 1;
|
||||
}
|
||||
printf("SUCCESS: testOrder\n");
|
||||
if (testWait(numThreads, queueSize)) {
|
||||
printf("FAIL: testWait\n");
|
||||
return 1;
|
||||
}
|
||||
printf("SUCCESS: testWait\n");
|
||||
}
|
||||
}
|
||||
printf("PASS: testOrder\n");
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return (POOL_create(0, 1)) ? printf("FAIL: testInvalid\n"), 1
|
||||
: printf("PASS: testInvalid\n"), 0;
|
||||
|
||||
if (testThreadReduction()) {
|
||||
printf("FAIL: thread reduction not effective \n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("SUCCESS: thread reduction effective (slower execution) \n");
|
||||
}
|
||||
|
||||
if (testAbruptEnding()) {
|
||||
printf("FAIL: jobs in queue not completed on early end \n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("SUCCESS: all jobs in queue completed on early end \n");
|
||||
}
|
||||
|
||||
printf("PASS: all POOL tests\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Compiler specific
|
||||
**************************************/
|
||||
* Compiler specific
|
||||
**************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define _CRT_SECURE_NO_WARNINGS /* fgets */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Includes
|
||||
**************************************/
|
||||
* Includes
|
||||
**************************************/
|
||||
#include <stdlib.h> /* free */
|
||||
#include <stdio.h> /* fgets, sscanf */
|
||||
#include <string.h> /* strcmp */
|
||||
@@ -40,8 +40,8 @@
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Constants
|
||||
**************************************/
|
||||
* Constants
|
||||
**************************************/
|
||||
#define KB *(1U<<10)
|
||||
#define MB *(1U<<20)
|
||||
#define GB *(1U<<30)
|
||||
@@ -54,8 +54,8 @@ static const U32 prime32 = 2654435761U;
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Display Macros
|
||||
**************************************/
|
||||
* Display Macros
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
@@ -74,8 +74,8 @@ static U64 g_clockTime = 0;
|
||||
|
||||
|
||||
/*-*******************************************************
|
||||
* Fuzzer functions
|
||||
*********************************************************/
|
||||
* Check macros
|
||||
*********************************************************/
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
@@ -110,10 +110,24 @@ unsigned int FUZ_rand(unsigned int* seedPtr)
|
||||
#f, ZSTD_getErrorName(err)); \
|
||||
}
|
||||
|
||||
#define CHECK_RET(ret, cond, ...) { \
|
||||
if (cond) { \
|
||||
DISPLAY("Error %llu => ", (unsigned long long)ret); \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
DISPLAY(" (line %u)\n", __LINE__); \
|
||||
return ret; \
|
||||
} }
|
||||
|
||||
#define CHECK_RET_Z(f) { \
|
||||
size_t const err = f; \
|
||||
CHECK_RET(err, ZSTD_isError(err), "%s : %s ", \
|
||||
#f, ZSTD_getErrorName(err)); \
|
||||
}
|
||||
|
||||
|
||||
/*======================================================
|
||||
* Basic Unit tests
|
||||
======================================================*/
|
||||
* Basic Unit tests
|
||||
*======================================================*/
|
||||
|
||||
typedef struct {
|
||||
void* start;
|
||||
@@ -207,6 +221,42 @@ static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t getCCtxParams(ZSTD_CCtx* zc, ZSTD_parameters* savedParams)
|
||||
{
|
||||
unsigned value;
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_windowLog, &savedParams->cParams.windowLog));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_hashLog, &savedParams->cParams.hashLog));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_chainLog, &savedParams->cParams.chainLog));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_searchLog, &savedParams->cParams.searchLog));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_minMatch, &savedParams->cParams.searchLength));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_targetLength, &savedParams->cParams.targetLength));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_compressionStrategy, &value));
|
||||
savedParams->cParams.strategy = value;
|
||||
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_checksumFlag, &savedParams->fParams.checksumFlag));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_contentSizeFlag, &savedParams->fParams.contentSizeFlag));
|
||||
CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_p_dictIDFlag, &value));
|
||||
savedParams->fParams.noDictIDFlag = !value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static U32 badParameters(ZSTD_CCtx* zc, ZSTD_parameters const savedParams)
|
||||
{
|
||||
ZSTD_parameters params;
|
||||
if (ZSTD_isError(getCCtxParams(zc, ¶ms))) return 10;
|
||||
CHECK_RET(1, params.cParams.windowLog != savedParams.cParams.windowLog, "windowLog");
|
||||
CHECK_RET(2, params.cParams.hashLog != savedParams.cParams.hashLog, "hashLog");
|
||||
CHECK_RET(3, params.cParams.chainLog != savedParams.cParams.chainLog, "chainLog");
|
||||
CHECK_RET(4, params.cParams.searchLog != savedParams.cParams.searchLog, "searchLog");
|
||||
CHECK_RET(5, params.cParams.searchLength != savedParams.cParams.searchLength, "searchLength");
|
||||
CHECK_RET(6, params.cParams.targetLength != savedParams.cParams.targetLength, "targetLength");
|
||||
|
||||
CHECK_RET(7, params.fParams.checksumFlag != savedParams.fParams.checksumFlag, "checksumFlag");
|
||||
CHECK_RET(8, params.fParams.contentSizeFlag != savedParams.fParams.contentSizeFlag, "contentSizeFlag");
|
||||
CHECK_RET(9, params.fParams.noDictIDFlag != savedParams.fParams.noDictIDFlag, "noDictIDFlag");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int basicUnitTests(U32 seed, double compressibility)
|
||||
{
|
||||
size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
|
||||
@@ -383,11 +433,12 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
inBuff.pos = 0;
|
||||
outBuff.pos = 0;
|
||||
while (r) { /* skippable frame */
|
||||
size_t const inSize = FUZ_rand(&coreSeed) & 15;
|
||||
size_t const outSize = FUZ_rand(&coreSeed) & 15;
|
||||
size_t const inSize = (FUZ_rand(&coreSeed) & 15) + 1;
|
||||
size_t const outSize = (FUZ_rand(&coreSeed) & 15) + 1;
|
||||
inBuff.size = inBuff.pos + inSize;
|
||||
outBuff.size = outBuff.pos + outSize;
|
||||
r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream on skippable frame error : %s \n", ZSTD_getErrorName(r));
|
||||
if (ZSTD_isError(r)) goto _output_error;
|
||||
}
|
||||
/* normal frame */
|
||||
@@ -395,14 +446,17 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
r=1;
|
||||
while (r) {
|
||||
size_t const inSize = FUZ_rand(&coreSeed) & 15;
|
||||
size_t const outSize = FUZ_rand(&coreSeed) & 15;
|
||||
size_t const outSize = (FUZ_rand(&coreSeed) & 15) + (!inSize); /* avoid having both sizes at 0 => would trigger a no_forward_progress error */
|
||||
inBuff.size = inBuff.pos + inSize;
|
||||
outBuff.size = outBuff.pos + outSize;
|
||||
r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(r));
|
||||
if (ZSTD_isError(r)) goto _output_error;
|
||||
}
|
||||
}
|
||||
if (outBuff.pos != CNBufferSize) DISPLAYLEVEL(4, "outBuff.pos != CNBufferSize : should have regenerated same amount ! \n");
|
||||
if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
|
||||
if (inBuff.pos != cSize) DISPLAYLEVEL(4, "inBuff.pos != cSize : should have real all input ! \n");
|
||||
if (inBuff.pos != cSize) goto _output_error; /* should have read the entire frame */
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
@@ -414,6 +468,30 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
} }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* Decompression forward progress */
|
||||
DISPLAYLEVEL(3, "test%3i : generate error when ZSTD_decompressStream() doesn't progress : ", testNb++);
|
||||
{ /* skippable frame */
|
||||
size_t r = 0;
|
||||
int decNb = 0;
|
||||
int const maxDec = 100;
|
||||
inBuff.src = compressedBuffer;
|
||||
inBuff.size = cSize;
|
||||
inBuff.pos = 0;
|
||||
|
||||
outBuff.dst = decodedBuffer;
|
||||
outBuff.pos = 0;
|
||||
outBuff.size = CNBufferSize-1; /* 1 byte missing */
|
||||
|
||||
for (decNb=0; decNb<maxDec; decNb++) {
|
||||
if (r==0) ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
|
||||
r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) break;
|
||||
}
|
||||
if (!ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream should have triggered a no_forward_progress error \n");
|
||||
if (!ZSTD_isError(r)) goto _output_error; /* should have triggered no_forward_progress error */
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* _srcSize compression test */
|
||||
DISPLAYLEVEL(3, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
|
||||
ZSTD_initCStream_srcSize(zc, 1, CNBufferSize);
|
||||
@@ -460,6 +538,21 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : wrong srcSize !contentSizeFlag : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
|
||||
{ ZSTD_parameters params = ZSTD_getParams(1, CNBufferSize, 0);
|
||||
params.fParams.contentSizeFlag = 0;
|
||||
CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, CNBufferSize - MIN(CNBufferSize, 200 KB)));
|
||||
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 */
|
||||
DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
|
||||
ZSTD_freeCStream(zc);
|
||||
@@ -591,6 +684,8 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
for (size = 512; size <= maxSize; size <<= 1) {
|
||||
U64 const crcOrig = XXH64(CNBuffer, size, 0);
|
||||
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
ZSTD_parameters savedParams;
|
||||
getCCtxParams(cctx, &savedParams);
|
||||
outBuff.dst = compressedBuffer;
|
||||
outBuff.size = compressedBufferSize;
|
||||
outBuff.pos = 0;
|
||||
@@ -599,6 +694,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
inBuff.pos = 0;
|
||||
CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
|
||||
CHECK_Z(ZSTD_compress_generic(cctx, &outBuff, &inBuff, ZSTD_e_end));
|
||||
CHECK(badParameters(cctx, savedParams), "Bad CCtx params");
|
||||
if (inBuff.pos != inBuff.size) goto _output_error;
|
||||
{ ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
|
||||
ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
|
||||
@@ -748,7 +844,12 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
/* Basic multithreading compression test */
|
||||
DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
|
||||
{ ZSTD_parameters const params = ZSTD_getParams(1, 0, 0);
|
||||
unsigned jobSize;
|
||||
CHECK_Z( ZSTDMT_getMTCtxParameter(mtctx, ZSTDMT_p_jobSize, &jobSize));
|
||||
CHECK(jobSize != 0, "job size non-zero");
|
||||
CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) );
|
||||
CHECK_Z( ZSTDMT_getMTCtxParameter(mtctx, ZSTDMT_p_jobSize, &jobSize));
|
||||
CHECK(jobSize != 0, "job size non-zero");
|
||||
}
|
||||
outBuff.dst = compressedBuffer;
|
||||
outBuff.size = compressedBufferSize;
|
||||
@@ -1216,8 +1317,9 @@ _output_error:
|
||||
}
|
||||
|
||||
|
||||
/* Multi-threading version of fuzzer Tests */
|
||||
static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests)
|
||||
/* fuzzing ZSTDMT_* interface */
|
||||
static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest,
|
||||
double compressibility, int bigTests)
|
||||
{
|
||||
const U32 maxSrcLog = bigTests ? 24 : 22;
|
||||
static const U32 maxSampleLog = 19;
|
||||
@@ -1491,7 +1593,7 @@ _output_error:
|
||||
* Otherwise, sets the param in zc. */
|
||||
static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
|
||||
ZSTD_cParameter param, unsigned value,
|
||||
U32 useOpaqueAPI)
|
||||
int useOpaqueAPI)
|
||||
{
|
||||
if (useOpaqueAPI) {
|
||||
return ZSTD_CCtxParam_setParameter(cctxParams, param, value);
|
||||
@@ -1501,7 +1603,8 @@ static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
|
||||
}
|
||||
|
||||
/* Tests for ZSTD_compress_generic() API */
|
||||
static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests, U32 const useOpaqueAPI)
|
||||
static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest,
|
||||
double compressibility, int bigTests)
|
||||
{
|
||||
U32 const maxSrcLog = bigTests ? 24 : 22;
|
||||
static const U32 maxSampleLog = 19;
|
||||
@@ -1554,12 +1657,14 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
/* test loop */
|
||||
for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
|
||||
U32 lseed;
|
||||
int opaqueAPI;
|
||||
const BYTE* srcBuffer;
|
||||
size_t totalTestSize, totalGenSize, cSize;
|
||||
XXH64_state_t xxhState;
|
||||
U64 crcOrig;
|
||||
U32 resetAllowed = 1;
|
||||
size_t maxTestSize;
|
||||
ZSTD_parameters savedParams;
|
||||
|
||||
/* init */
|
||||
if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
|
||||
@@ -1567,6 +1672,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
FUZ_rand(&coreSeed);
|
||||
lseed = coreSeed ^ prime32;
|
||||
DISPLAYLEVEL(5, " *** Test %u *** \n", testNb);
|
||||
opaqueAPI = FUZ_rand(&lseed) & 1;
|
||||
|
||||
/* states full reset (deliberately not synchronized) */
|
||||
/* some issues can only happen when reusing states */
|
||||
@@ -1574,13 +1680,13 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
DISPLAYLEVEL(5, "Creating new context \n");
|
||||
ZSTD_freeCCtx(zc);
|
||||
zc = ZSTD_createCCtx();
|
||||
CHECK(zc==NULL, "ZSTD_createCCtx allocation error");
|
||||
resetAllowed=0;
|
||||
CHECK(zc == NULL, "ZSTD_createCCtx allocation error");
|
||||
resetAllowed = 0;
|
||||
}
|
||||
if ((FUZ_rand(&lseed) & 0xFF) == 132) {
|
||||
ZSTD_freeDStream(zd);
|
||||
zd = ZSTD_createDStream();
|
||||
CHECK(zd==NULL, "ZSTD_createDStream allocation error");
|
||||
CHECK(zd == NULL, "ZSTD_createDStream allocation error");
|
||||
ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
|
||||
}
|
||||
|
||||
@@ -1602,11 +1708,14 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
/* compression init */
|
||||
CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) ); /* cancel previous dict /*/
|
||||
if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
|
||||
&& oldTestLog /* at least one test happened */ && resetAllowed) {
|
||||
&& oldTestLog /* at least one test happened */
|
||||
&& resetAllowed) {
|
||||
/* just set a compression level */
|
||||
maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
|
||||
if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
|
||||
{ int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
|
||||
CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_compressionLevel, compressionLevel, useOpaqueAPI) );
|
||||
DISPLAYLEVEL(5, "t%u : compression level : %i \n", testNb, compressionLevel);
|
||||
CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_compressionLevel, compressionLevel, opaqueAPI) );
|
||||
}
|
||||
} else {
|
||||
U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||
@@ -1629,6 +1738,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
{ U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
|
||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
|
||||
static const U32 windowLogMax = 24;
|
||||
if (dictSize)
|
||||
DISPLAYLEVEL(5, "t%u: with dictionary of size : %zu \n", testNb, dictSize);
|
||||
|
||||
/* mess with compression parameters */
|
||||
cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
|
||||
@@ -1638,43 +1749,43 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
|
||||
cParams.searchLength += (FUZ_rand(&lseed) & 3) - 1;
|
||||
cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
|
||||
cParams = ZSTD_adjustCParams(cParams, 0, 0);
|
||||
cParams = ZSTD_adjustCParams(cParams, pledgedSrcSize, dictSize);
|
||||
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, opaqueAPI) );
|
||||
assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */
|
||||
windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
|
||||
}
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, opaqueAPI) );
|
||||
}
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, opaqueAPI) );
|
||||
}
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, opaqueAPI) );
|
||||
|
||||
/* mess with long distance matching parameters */
|
||||
if (bigTests) {
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), opaqueAPI) );
|
||||
}
|
||||
|
||||
/* mess with frame parameters */
|
||||
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) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, checksumFlag, opaqueAPI) );
|
||||
}
|
||||
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_dictIDFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (U32)pledgedSrcSize);
|
||||
CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
|
||||
@@ -1685,19 +1796,19 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
|
||||
U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
|
||||
DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads);
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbWorkers, nbThreads, useOpaqueAPI) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbWorkers, nbThreads, opaqueAPI) );
|
||||
if (nbThreads > 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_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), useOpaqueAPI) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, opaqueAPI) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), opaqueAPI) );
|
||||
}
|
||||
}
|
||||
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1, opaqueAPI) );
|
||||
|
||||
/* Apply parameters */
|
||||
if (useOpaqueAPI) {
|
||||
DISPLAYLEVEL(6," t%u: applying CCtxParams \n", testNb);
|
||||
if (opaqueAPI) {
|
||||
DISPLAYLEVEL(5, "t%u: applying CCtxParams \n", testNb);
|
||||
CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
|
||||
}
|
||||
|
||||
@@ -1709,7 +1820,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
}
|
||||
if (dict && dictSize) {
|
||||
/* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */
|
||||
if (useOpaqueAPI) {
|
||||
if (opaqueAPI) {
|
||||
size_t const setError = ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams);
|
||||
CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParametersUsingCCtxParams should have failed");
|
||||
} else {
|
||||
@@ -1722,6 +1833,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
}
|
||||
} }
|
||||
|
||||
CHECK_Z(getCCtxParams(zc, &savedParams));
|
||||
|
||||
/* multi-segments compression test */
|
||||
XXH64_reset(&xxhState, 0);
|
||||
{ ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
|
||||
@@ -1761,15 +1874,18 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
} }
|
||||
crcOrig = XXH64_digest(&xxhState);
|
||||
cSize = outBuff.pos;
|
||||
DISPLAYLEVEL(5, "Frame completed : %u bytes \n", (U32)cSize);
|
||||
DISPLAYLEVEL(5, "Frame completed : %zu bytes \n", cSize);
|
||||
}
|
||||
|
||||
CHECK(badParameters(zc, savedParams), "CCtx params are wrong");
|
||||
|
||||
/* multi - fragments decompression test */
|
||||
if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
|
||||
DISPLAYLEVEL(5, "resetting DCtx (dict:%08X) \n", (U32)(size_t)dict);
|
||||
CHECK_Z( ZSTD_resetDStream(zd) );
|
||||
} else {
|
||||
DISPLAYLEVEL(5, "using dict of size %u \n", (U32)dictSize);
|
||||
if (dictSize)
|
||||
DISPLAYLEVEL(5, "using dictionary of size %zu \n", dictSize);
|
||||
CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
|
||||
}
|
||||
{ size_t decompressionResult = 1;
|
||||
@@ -1883,7 +1999,6 @@ int main(int argc, const char** argv)
|
||||
int bigTests = (sizeof(size_t) == 8);
|
||||
e_api selected_api = simple_api;
|
||||
const char* const programName = argv[0];
|
||||
U32 useOpaqueAPI = 0;
|
||||
int argNb;
|
||||
|
||||
/* Check command line */
|
||||
@@ -1896,7 +2011,6 @@ int main(int argc, const char** argv)
|
||||
|
||||
if (!strcmp(argument, "--mt")) { selected_api=mt_api; testNb += !testNb; continue; }
|
||||
if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
|
||||
if (!strcmp(argument, "--opaqueapi")) { selected_api=advanced_api; testNb += !testNb; useOpaqueAPI = 1; continue; }
|
||||
if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
|
||||
|
||||
argument++;
|
||||
@@ -2012,7 +2126,7 @@ int main(int argc, const char** argv)
|
||||
result = fuzzerTests_MT(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
|
||||
break;
|
||||
case advanced_api :
|
||||
result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests, useOpaqueAPI);
|
||||
result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
|
||||
break;
|
||||
default :
|
||||
assert(0); /* impossible */
|
||||
|
||||