Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
794ea1b0af | ||
|
|
78f732cfdd | ||
|
|
273d1279ca | ||
|
|
c6e5257240 | ||
|
|
dc1f7b560b | ||
|
|
6679d0ca7b | ||
|
|
76fbb5f3d4 | ||
|
|
1d3f664fce | ||
|
|
86caab507f | ||
|
|
731f4b70fc | ||
|
|
741b87bbe1 | ||
|
|
f62b2663b9 | ||
|
|
3487a60950 | ||
|
|
6a0052a409 | ||
|
|
6f1215b874 | ||
|
|
c5da438dc0 | ||
|
|
3d18d9a9ce | ||
|
|
902c7ec1fe | ||
|
|
5d82c2b57c | ||
|
|
f5728da365 | ||
|
|
42b02f5185 | ||
|
|
cd4dba74de | ||
|
|
7d970bd83c | ||
|
|
a595e5812a | ||
|
|
79cd0ff712 | ||
|
|
3008f74ee2 | ||
|
|
f79c1c476e | ||
|
|
9dca0602f4 | ||
|
|
88301b58c1 | ||
|
|
0fcdc62c2d | ||
|
|
dff5407cd0 | ||
|
|
351498b932 | ||
|
|
686e7e4b4b | ||
|
|
559762da12 | ||
|
|
9cc3304614 | ||
|
|
a0a9bc6c95 | ||
|
|
515c07a131 | ||
|
|
490163ac73 | ||
|
|
216099a73f | ||
|
|
04d91d5219 | ||
|
|
3613448fb8 | ||
|
|
86b8e39a84 | ||
|
|
2215101cad | ||
|
|
d6ee2d5d24 | ||
|
|
ff0afbad58 | ||
|
|
c8ab027227 | ||
|
|
7c2aa73a8e | ||
|
|
084b362775 | ||
|
|
c1e995321e | ||
|
|
94c102038b | ||
|
|
4bd911ae41 | ||
|
|
b20703f273 | ||
|
|
f65b9e27ce | ||
|
|
ff6713fd72 | ||
|
|
5473b72a05 | ||
|
|
92fbd42894 | ||
|
|
83ec3d0164 | ||
|
|
5a66afa051 | ||
|
|
37ff4f91eb | ||
|
|
e27e156d3c | ||
|
|
a6ff1194d8 | ||
|
|
0ae98ba215 | ||
|
|
db996d253e | ||
|
|
7a43609ffd | ||
|
|
3b573ba1f0 | ||
|
|
8688c6ed92 | ||
|
|
4eea5af595 | ||
|
|
ca0fc763e3 | ||
|
|
b39c76765b | ||
|
|
fe7c645a7e | ||
|
|
8ba5bc4729 | ||
|
|
ee6acaf26b | ||
|
|
e0872806df | ||
|
|
74e856a195 | ||
|
|
edab9eed66 | ||
|
|
f6039f3d5f | ||
|
|
a4db145900 | ||
|
|
f99a450ca4 | ||
|
|
1362699e87 | ||
|
|
fbd9e628ae | ||
|
|
c610a01d7d | ||
|
|
372fddf4e6 | ||
|
|
cb596b024f | ||
|
|
c1875a7386 | ||
|
|
eb5f7a7fa2 | ||
|
|
d2f56ba442 | ||
|
|
a9fb8d4c41 | ||
|
|
e127139ceb | ||
|
|
478e5fedf9 | ||
|
|
aed172a8fe | ||
|
|
ad590275b4 | ||
|
|
007cda88ca | ||
|
|
8689633fdf | ||
|
|
2abe8d63e0 | ||
|
|
4fb0a77314 | ||
|
|
b293d2ebc3 | ||
|
|
70df177615 | ||
|
|
e385c3dd46 | ||
|
|
bb774ae1eb | ||
|
|
61d89067c9 | ||
|
|
b125202440 | ||
|
|
bb4f85db42 | ||
|
|
063d9f24e2 | ||
|
|
b27d1634a5 | ||
|
|
dcd713ce06 | ||
|
|
a58b48ef0e | ||
|
|
34cf4c139e | ||
|
|
8d31e8ec42 | ||
|
|
d23b95d21d | ||
|
|
86db60752d | ||
|
|
ef82b214ad | ||
|
|
aa8592c532 | ||
|
|
e0412c2062 | ||
|
|
a412bedb3f | ||
|
|
1fafd0c4ae | ||
|
|
038a8a906b | ||
|
|
4d2bf7f0f2 | ||
|
|
5c5c1b0d90 | ||
|
|
f8372191f5 | ||
|
|
f77f634d41 | ||
|
|
4b51526412 | ||
|
|
6719794379 | ||
|
|
0591e7eea1 | ||
|
|
3b40100058 | ||
|
|
6b11fc436c | ||
|
|
cc4530924b | ||
|
|
68a232c591 | ||
|
|
621a263fb2 | ||
|
|
ce6cadc860 | ||
|
|
3c78b42210 | ||
|
|
4afe31ba7b | ||
|
|
0a68be83e7 | ||
|
|
7170f51dd2 | ||
|
|
9e711c9360 | ||
|
|
e62e15df19 | ||
|
|
b34517a440 | ||
|
|
588dfbcc97 | ||
|
|
c2d3570338 | ||
|
|
1e240af30a | ||
|
|
7a225c0c46 | ||
|
|
83598aa106 | ||
|
|
7003c9905e | ||
|
|
3dbd861b7d | ||
|
|
5a1bb4a4e0 | ||
|
|
40874d4aea | ||
|
|
1e046ce7fa | ||
|
|
889392dac8 | ||
|
|
e13d099bf8 | ||
|
|
b6805c54d6 | ||
|
|
927d079944 | ||
|
|
b921f1aad6 | ||
|
|
a3f1b2448c | ||
|
|
b0e8580dc7 | ||
|
|
695d154cac | ||
|
|
54107e263f | ||
|
|
3a64c69eba | ||
|
|
a844455095 | ||
|
|
22574d848d | ||
|
|
1f87c88ecf | ||
|
|
06b5b37b8d | ||
|
|
b88c593d8f | ||
|
|
887f5b62ae | ||
|
|
6c35fb2e8c | ||
|
|
641749fc09 | ||
|
|
5a08f58df2 | ||
|
|
0d9fb5dc33 | ||
|
|
9fed5ef108 | ||
|
|
fe2e2ad36d | ||
|
|
0ae21d8c31 | ||
|
|
5474edbe60 | ||
|
|
9ae3bf5ee2 | ||
|
|
e5af24c5fa | ||
|
|
8168a451e5 | ||
|
|
d31018e223 | ||
|
|
7afd9db8db | ||
|
|
04a6c8cbe2 | ||
|
|
79e9459efc | ||
|
|
0166b2ba80 | ||
|
|
81bfe3655e | ||
|
|
4683667785 | ||
|
|
de10f56be2 | ||
|
|
fd03971252 | ||
|
|
befcec1788 | ||
|
|
3ce4c6e046 | ||
|
|
a261375996 | ||
|
|
d0b7da30e2 | ||
|
|
a7b4dafa03 | ||
|
|
4a74eb8cfb | ||
|
|
c485b57bc7 | ||
|
|
163e9b6637 | ||
|
|
e1ef81a3ae | ||
|
|
60829445bf | ||
|
|
798034aeae | ||
|
|
2fc7248412 | ||
|
|
799b904628 | ||
|
|
c7611d6964 | ||
|
|
ee2efb634e | ||
|
|
1a860c8737 | ||
|
|
81f444f4f9 | ||
|
|
050fec5c37 | ||
|
|
e6f4b46493 | ||
|
|
d2ea3fb5ef | ||
|
|
572acb9c5d | ||
|
|
e2fe266279 | ||
|
|
3a2e302b2c | ||
|
|
dcf784a04b | ||
|
|
7971fd16f7 | ||
|
|
7f76d37044 | ||
|
|
17332454e5 | ||
|
|
e49d1ab6aa | ||
|
|
66269e74a0 | ||
|
|
923cf3dc92 | ||
|
|
ffde100b68 | ||
|
|
a07cae3976 | ||
|
|
a52d897d60 | ||
|
|
903bc264ad | ||
|
|
f06b18b3ff | ||
|
|
c6cabf9441 | ||
|
|
475da4fb2e | ||
|
|
7cf62bc274 | ||
|
|
377ecefce9 | ||
|
|
8052cd0131 | ||
|
|
e515327764 | ||
|
|
9a3b17c4d6 | ||
|
|
2ce0290e4d | ||
|
|
86ead9f4a4 | ||
|
|
20f8df6440 | ||
|
|
126ec2669c | ||
|
|
468bb17378 | ||
|
|
d151a4880b | ||
|
|
809c7eb6bf | ||
|
|
05059e5a48 | ||
|
|
dc84e35138 | ||
|
|
8193250615 | ||
|
|
6b3d12fe54 | ||
|
|
dd4de1dd7a | ||
|
|
5ab78c0418 | ||
|
|
c7269add7e | ||
|
|
e122fcbf58 | ||
|
|
c2d470581e | ||
|
|
a419265d30 | ||
|
|
59dcc47579 | ||
|
|
fcbf2fde9a | ||
|
|
3fd5f9f52d | ||
|
|
592b1acb18 | ||
|
|
e19fe535f4 | ||
|
|
83adaecf41 | ||
|
|
c5bf96fb74 | ||
|
|
52e41b9ac8 | ||
|
|
e61e3ff152 | ||
|
|
98d8ad27a2 | ||
|
|
c53d650d9a | ||
|
|
f013b1b504 | ||
|
|
1518570c62 | ||
|
|
4502ca5f42 | ||
|
|
fabce2a61c | ||
|
|
81fdca0012 | ||
|
|
324cce4996 | ||
|
|
b38d87b476 | ||
|
|
9446b1910c | ||
|
|
3c3845b9d8 | ||
|
|
af971cec65 | ||
|
|
7567769a7e | ||
|
|
24dabde507 | ||
|
|
d988e00a7f | ||
|
|
e590c8a0e3 | ||
|
|
69036dffe5 | ||
|
|
6bb1688c1a | ||
|
|
ea4027c003 | ||
|
|
c87ad5bdb5 | ||
|
|
e8ff7d18eb | ||
|
|
c692b8d12d | ||
|
|
2b31cb0698 | ||
|
|
19317239ec | ||
|
|
c1e588fcb4 | ||
|
|
4f77b81c8a | ||
|
|
0e2cfebb63 | ||
|
|
43118da8a7 | ||
|
|
3daed7017a | ||
|
|
2c17e05646 | ||
|
|
7b762364cb | ||
|
|
d5cbae7c50 | ||
|
|
585aaa0ed3 | ||
|
|
fe34776c20 | ||
|
|
cdceb0fce5 | ||
|
|
48b5a7bd8b | ||
|
|
1c007e64b8 | ||
|
|
3fc14e411b | ||
|
|
823b32ce43 | ||
|
|
607933a2ff | ||
|
|
f4dbfce79c | ||
|
|
feaa8ac50d | ||
|
|
4edfaa93b7 | ||
|
|
b69d06a810 | ||
|
|
1ec201c7b9 | ||
|
|
f2bc34d9b4 | ||
|
|
d55ebb5718 | ||
|
|
d8b25cbf68 | ||
|
|
e0e309f27c | ||
|
|
01dbbdf560 | ||
|
|
1de57bb271 | ||
|
|
839c7939e8 | ||
|
|
253873220f | ||
|
|
396ef5b434 | ||
|
|
c27fa39904 | ||
|
|
ecb86d8286 | ||
|
|
0fcb28c5d2 | ||
|
|
59af58762a | ||
|
|
bd02c9be6e | ||
|
|
9662fe1683 | ||
|
|
edb6e8f427 | ||
|
|
db0ae65436 | ||
|
|
a02d81f944 | ||
|
|
a07d7c4e29 | ||
|
|
3298a08076 | ||
|
|
9987d2f594 | ||
|
|
5f5bdc1e5d | ||
|
|
969e54f26e | ||
|
|
78dbba76b8 | ||
|
|
d857369028 | ||
|
|
e99d554903 | ||
|
|
eb9f881eb8 | ||
|
|
65dbb0b77b | ||
|
|
4d267f3d4f | ||
|
|
de6b46dfc8 | ||
|
|
55ff3e4e17 | ||
|
|
ef59cc39cd | ||
|
|
a1b9a5ad0e | ||
|
|
ccd494860a | ||
|
|
065ea9274f | ||
|
|
118200f7b9 | ||
|
|
25822342be | ||
|
|
68aa9a4ea3 | ||
|
|
8090c90491 | ||
|
|
52bbf1be54 | ||
|
|
2c97f5dbed | ||
|
|
1a6278c82d | ||
|
|
b1a30e2b4a | ||
|
|
e2cd353473 | ||
|
|
c6a888c073 | ||
|
|
f307493711 | ||
|
|
e4aeaebc20 | ||
|
|
c123e69ad0 | ||
|
|
c60dcedcc9 | ||
|
|
33fca19dd4 | ||
|
|
84e898a76c | ||
|
|
02134fad12 | ||
|
|
8b8b5f4d75 | ||
|
|
d9645327b3 | ||
|
|
74c901bbed | ||
|
|
ba50807029 | ||
|
|
bd00ec6804 | ||
|
|
b46236278a | ||
|
|
c8888d9bf4 | ||
|
|
6579f6c452 | ||
|
|
ba12054273 | ||
|
|
3732a08f5b | ||
|
|
3e815f5b3a | ||
|
|
8030342eea | ||
|
|
f60100dd5f | ||
|
|
1f83b7cfc4 | ||
|
|
7e09f07b32 | ||
|
|
94a2f2791f | ||
|
|
5108c9ac97 | ||
|
|
5059618295 | ||
|
|
d01a2c6929 | ||
|
|
23a0643ef1 | ||
|
|
1b994cbc57 | ||
|
|
ed6953772f | ||
|
|
1b65803fe7 | ||
|
|
59c7b2a492 | ||
|
|
5490c75dda | ||
|
|
cc1ffe0bd6 | ||
|
|
eb9227935e | ||
|
|
d09f195ceb | ||
|
|
b7add1dd67 | ||
|
|
f242f5be8f | ||
|
|
698af84fcf | ||
|
|
bae174960b | ||
|
|
39b7946b95 | ||
|
|
b12e8cb3e7 | ||
|
|
6761e1c949 | ||
|
|
16bbd7437c | ||
|
|
5a75956001 | ||
|
|
50cdf84f58 | ||
|
|
81b86a2024 | ||
|
|
cbf3e26316 | ||
|
|
7806d80338 | ||
|
|
2a5076d264 | ||
|
|
6ec18aed31 | ||
|
|
0525d1cec6 | ||
|
|
be489f78df | ||
|
|
e256e43274 | ||
|
|
4c25ea329b | ||
|
|
189653a9c1 | ||
|
|
504c4a1f36 | ||
|
|
0d6954b4cc | ||
|
|
61efb2a047 | ||
|
|
ed313342f1 | ||
|
|
0abf2baef9 | ||
|
|
05434fe9a5 | ||
|
|
a29b6ed251 | ||
|
|
7afe0b3bea | ||
|
|
803e65f935 | ||
|
|
0a794163f4 | ||
|
|
e72e13ac6c | ||
|
|
0f255ff4fa | ||
|
|
632baf62e3 | ||
|
|
d9582a0cb8 | ||
|
|
dc88f7b8a0 | ||
|
|
c28031df8f | ||
|
|
19105bf710 | ||
|
|
a4fff8e0e8 | ||
|
|
520843d8ff | ||
|
|
c42ae69eb4 | ||
|
|
d8197ad88d | ||
|
|
63779c7982 | ||
|
|
d4871d5e6e | ||
|
|
838f96a955 | ||
|
|
8eef3370a3 | ||
|
|
e4120c5513 | ||
|
|
d507e02940 | ||
|
|
2b71b79f98 | ||
|
|
fcaa422897 | ||
|
|
130c2640d0 | ||
|
|
2e29728797 | ||
|
|
da41d1d401 | ||
|
|
68a4a03453 | ||
|
|
73e19c4cf1 | ||
|
|
9b4833df2d | ||
|
|
9f58241dcc | ||
|
|
c45eddfa40 | ||
|
|
fcaf06ddb4 | ||
|
|
14d0cd5d69 | ||
|
|
7b828aaeb5 | ||
|
|
f33a4068b1 | ||
|
|
c1024af3e3 | ||
|
|
bb7fbd56a6 | ||
|
|
5bf1359e3b | ||
|
|
649a9c85c3 | ||
|
|
618bf84e0d | ||
|
|
0f77956bcc | ||
|
|
871f3a4026 | ||
|
|
262e553b23 | ||
|
|
b2ad17a658 | ||
|
|
b558190ac7 | ||
|
|
e6dccbf482 | ||
|
|
57e1b45920 | ||
|
|
a810e1eeb7 | ||
|
|
abb3585c3b | ||
|
|
93da0416e8 | ||
|
|
cbe0f0e435 | ||
|
|
c36d54f5ed | ||
|
|
7306832e8a | ||
|
|
1b8bddc41e | ||
|
|
167157dd74 | ||
|
|
191d22994f | ||
|
|
4cf9c7e098 | ||
|
|
35c0c2075e | ||
|
|
ca799f84ca | ||
|
|
408bd1e9fe | ||
|
|
979b047114 | ||
|
|
82cf6037ac | ||
|
|
3e0550ee52 | ||
|
|
a3c3a38b9b | ||
|
|
3b001a38fe | ||
|
|
29b8a3d8f2 | ||
|
|
e2208242ac | ||
|
|
fbd97f305a | ||
|
|
53bad103ce | ||
|
|
f4563d87b9 | ||
|
|
488e45f38b | ||
|
|
91f4c23e63 | ||
|
|
9420bce8a4 | ||
|
|
e2965edd10 | ||
|
|
a91e91d614 | ||
|
|
dd8cb5a0f1 | ||
|
|
33e39094e7 | ||
|
|
134d332b10 | ||
|
|
1df9f36c6c | ||
|
|
d55a6483d7 | ||
|
|
cd9486031d | ||
|
|
283c228abe | ||
|
|
e769da1645 | ||
|
|
6bedef8095 | ||
|
|
e0fc9fd90b | ||
|
|
c40c7378c6 | ||
|
|
1ec556238e | ||
|
|
957a0ae52d | ||
|
|
c4c3e11958 | ||
|
|
50e8f55e7d | ||
|
|
b7080f4c67 | ||
|
|
70850eb72b | ||
|
|
64e8511b26 | ||
|
|
07a2a33135 | ||
|
|
96e55c14f2 | ||
|
|
6313a58e45 | ||
|
|
988ce61a0c | ||
|
|
1e38e07b3d | ||
|
|
9efc14804e | ||
|
|
db79219f70 | ||
|
|
db7d7b6974 | ||
|
|
1be95291a8 | ||
|
|
bd86e24637 | ||
|
|
e1ab6913ad | ||
|
|
395a2c5462 | ||
|
|
4b9e3d11a6 | ||
|
|
832f559b0b | ||
|
|
547794ef40 | ||
|
|
4ebaf36582 | ||
|
|
8420502ef9 | ||
|
|
1c42844668 | ||
|
|
3c50854c05 | ||
|
|
345ed63976 | ||
|
|
d54ad3c234 | ||
|
|
d3d0b92e5e | ||
|
|
7da1c6ddbf | ||
|
|
2d8afd9ce1 | ||
|
|
6a86db11a4 | ||
|
|
727d03161f | ||
|
|
886de7bc04 | ||
|
|
8a189b1b29 | ||
|
|
30cb0a4f25 | ||
|
|
4373c5ab88 | ||
|
|
6894746eb1 | ||
|
|
c78f434aa4 | ||
|
|
a7de1d9f49 | ||
|
|
f8ae21680f | ||
|
|
5be3f19e1d | ||
|
|
43bc470fe0 | ||
|
|
f37b291bf5 | ||
|
|
97ab0e2ab6 | ||
|
|
183a18a45c | ||
|
|
db3e1de729 | ||
|
|
cc4e941745 | ||
|
|
610c8b9e33 | ||
|
|
f746c37d00 | ||
|
|
a5a2418df4 |
@@ -1,4 +1,4 @@
|
||||
FROM circleci/buildpack-deps:focal
|
||||
FROM circleci/buildpack-deps@sha256:f6f10c11b7b8ccfd4f4a5b830c3256803604ce61292b60cb22e26b12f62b0e8c
|
||||
|
||||
RUN sudo dpkg --add-architecture i386
|
||||
RUN sudo apt-get -y -qq update
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ task:
|
||||
name: FreeBSD (shortest)
|
||||
freebsd_instance:
|
||||
matrix:
|
||||
image_family: freebsd-13-0
|
||||
image_family: freebsd-12-2
|
||||
image_family: freebsd-14-0
|
||||
image_family: freebsd-13-2
|
||||
install_script: pkg install -y gmake coreutils
|
||||
script: |
|
||||
MOREFLAGS="-Werror" gmake -j all
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
name: facebook/zstd/commit
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
permissions: read-all
|
||||
jobs:
|
||||
short-tests-0:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
docker:
|
||||
image: fbopensource/zstd-circleci-primary:0.0.1
|
||||
options: --entrypoint /bin/bash
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libcurl4-gnutls-dev
|
||||
- name: Test
|
||||
run: |
|
||||
./tests/test-license.py
|
||||
cc -v
|
||||
CFLAGS="-O0 -Werror -pedantic" make allmost; make clean
|
||||
make c99build; make clean
|
||||
make c11build; make clean
|
||||
make -j regressiontest; make clean
|
||||
make shortest; make clean
|
||||
make cxxtest; make clean
|
||||
short-tests-1:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
docker:
|
||||
image: fbopensource/zstd-circleci-primary:0.0.1
|
||||
options: --entrypoint /bin/bash
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-powerpc-linux-gnu gcc-arm-linux-gnueabi gcc-aarch64-linux-gnu libc6-dev-ppc64-powerpc-cross libcurl4-gnutls-dev lib64gcc-11-dev-powerpc-cross
|
||||
- name: Test
|
||||
run: |-
|
||||
make gnu90build; make clean
|
||||
make gnu99build; make clean
|
||||
make ppc64build V=1; make clean
|
||||
make ppcbuild V=1; make clean
|
||||
make armbuild V=1; make clean
|
||||
make aarch64build V=1; make clean
|
||||
make -C tests test-legacy test-longmatch; make clean
|
||||
make -C lib libzstd-nomt; make clean
|
||||
regression-test:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
docker:
|
||||
image: fbopensource/zstd-circleci-primary:0.0.1
|
||||
options: --entrypoint /bin/bash
|
||||
env:
|
||||
CIRCLE_ARTIFACTS: "/tmp/circleci-artifacts"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: restore_cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: regression-cache-{{ checksum "tests/regression/data.c" }}-v0
|
||||
path: tests/regression/cache
|
||||
restore-keys: regression-cache-{{ checksum "tests/regression/data.c" }}-v0
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libcurl4-gnutls-dev
|
||||
- name: Regression Test
|
||||
run: |
|
||||
make -C programs zstd
|
||||
make -C tests/regression test
|
||||
mkdir -p $CIRCLE_ARTIFACTS
|
||||
./tests/regression/test \
|
||||
--cache tests/regression/cache \
|
||||
--output $CIRCLE_ARTIFACTS/results.csv \
|
||||
--zstd programs/zstd
|
||||
echo "NOTE: The new results.csv is uploaded as an artifact to this job"
|
||||
echo " If this fails, go to the Artifacts pane in CircleCI, "
|
||||
echo " download /tmp/circleci-artifacts/results.csv, and if they "
|
||||
echo " are still good, copy it into the repo and commit it."
|
||||
echo "> diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv"
|
||||
diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: "/tmp/circleci-artifacts"
|
||||
@@ -9,11 +9,13 @@ on:
|
||||
pull_request:
|
||||
branches: [ dev, release, actionsTest ]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
make-all:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make all
|
||||
run: make all
|
||||
|
||||
@@ -24,7 +26,7 @@ jobs:
|
||||
DEVNULLRIGHTS: 1
|
||||
READFROMBLOCKDEVICE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make test
|
||||
run: make test
|
||||
|
||||
@@ -32,36 +34,50 @@ jobs:
|
||||
make-test-osx:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: OS-X test
|
||||
run: make test # make -c lib all doesn't work because of the fact that it's not a tty
|
||||
|
||||
# lasts ~24mn
|
||||
make-test-32bit:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DEVNULLRIGHTS: 1
|
||||
READFROMBLOCKDEVICE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make test
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
make libc6install
|
||||
CFLAGS="-m32" make test
|
||||
|
||||
no-intrinsics-fuzztest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: no intrinsics fuzztest
|
||||
run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest
|
||||
|
||||
tsan-zstreamtest:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: thread sanitizer zstreamtest
|
||||
run: CC=clang ZSTREAM_TESTTIME=-T3mn make tsan-test-zstream
|
||||
|
||||
ubsan-zstreamtest:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: undefined behavior sanitizer zstreamtest
|
||||
run: CC=clang make uasan-test-zstream
|
||||
|
||||
# lasts ~15mn
|
||||
tsan-fuzztest:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: thread sanitizer fuzztest
|
||||
run: CC=clang make tsan-fuzztest
|
||||
|
||||
@@ -69,7 +85,7 @@ jobs:
|
||||
big-tests-zstreamtest32:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: zstream tests in 32bit mode, with big tests
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -78,9 +94,9 @@ jobs:
|
||||
|
||||
# lasts ~23mn
|
||||
gcc-8-asan-ubsan-testzstd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: gcc-8 + ASan + UBSan + Test Zstd
|
||||
# See https://askubuntu.com/a/1428822
|
||||
run: |
|
||||
@@ -90,16 +106,16 @@ jobs:
|
||||
CC=gcc-8 make -j uasan-test-zstd </dev/null V=1
|
||||
|
||||
clang-asan-ubsan-testzstd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: clang + ASan + UBSan + Test Zstd
|
||||
run: CC=clang make -j uasan-test-zstd </dev/null V=1
|
||||
|
||||
gcc-asan-ubsan-testzstd-32bit:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: ASan + UBSan + Test Zstd, 32bit mode
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -111,9 +127,9 @@ jobs:
|
||||
# so any data coming from these libraries is always considered "uninitialized"
|
||||
|
||||
gcc-8-asan-ubsan-fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: gcc-8 + ASan + UBSan + Fuzz Test
|
||||
# See https://askubuntu.com/a/1428822
|
||||
run: |
|
||||
@@ -123,16 +139,16 @@ jobs:
|
||||
CC=gcc-8 FUZZER_FLAGS="--long-tests" make clean uasan-fuzztest
|
||||
|
||||
clang-asan-ubsan-fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: clang + ASan + UBSan + Fuzz Test
|
||||
run: CC=clang FUZZER_FLAGS="--long-tests" make clean uasan-fuzztest
|
||||
|
||||
gcc-asan-ubsan-fuzz32:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: ASan + UBSan + Fuzz Test 32bit
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -140,9 +156,9 @@ jobs:
|
||||
CFLAGS="-O3 -m32" FUZZER_FLAGS="--long-tests" make uasan-fuzztest
|
||||
|
||||
clang-asan-ubsan-fuzz32:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: clang + ASan + UBSan + Fuzz Test 32bit
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -150,30 +166,40 @@ jobs:
|
||||
CC=clang CFLAGS="-O3 -m32" FUZZER_FLAGS="--long-tests" make uasan-fuzztest
|
||||
|
||||
asan-ubsan-regression:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: ASan + UBSan + Regression Test
|
||||
run: make -j uasanregressiontest
|
||||
|
||||
clang-ubsan-regression:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: clang + ASan + UBSan + Regression Test
|
||||
run: CC=clang make -j uasanregressiontest
|
||||
|
||||
msan-regression:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: MSan + Regression Test
|
||||
run: make -j msanregressiontest
|
||||
|
||||
clang-msan-fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
clang-msan-fuzz-unoptimized:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: clang + MSan + Fuzz Test
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
sudo apt-get install clang
|
||||
CC=clang MOREFLAGS="-O0" make clean msan-fuzztest
|
||||
|
||||
clang-msan-fuzz:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: clang + MSan + Fuzz Test
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -182,9 +208,9 @@ jobs:
|
||||
|
||||
# lasts ~24mn
|
||||
clang-msan-testzstd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: clang + MSan + Test Zstd
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -194,7 +220,7 @@ jobs:
|
||||
armfuzz:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Qemu ARM emulation + Fuzz Test
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -204,7 +230,7 @@ jobs:
|
||||
valgrind-fuzz-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: valgrind + fuzz test stack mode # ~ 7mn
|
||||
shell: 'script -q -e -c "bash {0}"'
|
||||
run: |
|
||||
@@ -220,8 +246,8 @@ jobs:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- uses: msys2/setup-msys2@cc11e9188b693c2b100158c3322424c4cc1dadea # tag=v2.22.0
|
||||
with:
|
||||
msystem: MINGW64
|
||||
install: make
|
||||
@@ -243,7 +269,7 @@ jobs:
|
||||
|
||||
# lasts ~20mn
|
||||
oss-fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -264,7 +290,7 @@ jobs:
|
||||
dry-run: false
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # tag=v3.1.2
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: ${{ matrix.sanitizer }}-artifacts
|
||||
|
||||
@@ -10,25 +10,27 @@ on:
|
||||
pull_request:
|
||||
branches: [ dev, release, actionsTest ]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
linux-kernel:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: linux kernel, library + build + test
|
||||
run: make -C contrib/linux-kernel test CFLAGS="-Werror -Wunused-const-variable -Wunused-but-set-variable"
|
||||
|
||||
benchmarking:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make benchmarking
|
||||
run: make benchmarking
|
||||
|
||||
check-32bit: # designed to catch https://github.com/facebook/zstd/issues/2428
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make check on 32-bit
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -36,9 +38,9 @@ jobs:
|
||||
CFLAGS="-m32 -O1 -fstack-protector" make check V=1
|
||||
|
||||
check-x32:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04 # ubuntu-latest == ubuntu-22.04 have issues currently with x32
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make check on x32 ABI # https://en.wikipedia.org/wiki/X32_ABI
|
||||
env:
|
||||
CHECK_CONSTRAINED_MEM: true
|
||||
@@ -50,16 +52,24 @@ jobs:
|
||||
build-c89:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: ensure zstd can be build with c89/c90 compilers (+ long long support + variadic macros)
|
||||
run: |
|
||||
make c89build V=1
|
||||
|
||||
build-zstd-dll:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: build zstd bin against a dynamic lib (debuglevel for more dependencies)
|
||||
run: |
|
||||
make -C lib lib-mt-release
|
||||
DEBUGLEVEL=2 make -C programs zstd-dll
|
||||
|
||||
gcc-7-libzstd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: gcc-7 + libzstdmt compilation
|
||||
# See https://askubuntu.com/a/1428822
|
||||
run: |
|
||||
@@ -70,24 +80,21 @@ jobs:
|
||||
make clean
|
||||
LDFLAGS=-Wl,--no-undefined make -C lib libzstd-mt
|
||||
|
||||
# candidate test (to check) : underlink test
|
||||
# candidate test (for discussion) : underlink test
|
||||
# LDFLAGS=-Wl,--no-undefined : will make the linker fail if dll is underlinked
|
||||
|
||||
cmake-build-and-test-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- name: cmake build and test check
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: cmake build and test
|
||||
run: |
|
||||
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild
|
||||
cp -r ./ "../zstd source"
|
||||
cd "../zstd source"
|
||||
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild
|
||||
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild V=1
|
||||
|
||||
cpp-gnu90-c99-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: C++, gnu90 and c99 compatibility
|
||||
run: |
|
||||
make cxxtest
|
||||
@@ -101,7 +108,7 @@ jobs:
|
||||
mingw-cross-compilation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: mingw cross-compilation
|
||||
run: |
|
||||
# sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix; (doesn't work)
|
||||
@@ -112,7 +119,7 @@ jobs:
|
||||
armbuild:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: ARM Build Test
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -122,7 +129,7 @@ jobs:
|
||||
bourne-shell:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Bourne shell compatibility (shellcheck)
|
||||
run: |
|
||||
wget https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.x86_64.tar.xz
|
||||
@@ -132,7 +139,7 @@ jobs:
|
||||
zlib-wrapper:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: zlib wrapper test
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -143,7 +150,7 @@ jobs:
|
||||
lz4-threadpool-libs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: LZ4, thread pool, and libs build testslib wrapper test
|
||||
run: |
|
||||
make lz4install
|
||||
@@ -157,7 +164,7 @@ jobs:
|
||||
gcc-make-tests-32bit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Make all, 32bit mode
|
||||
run: |
|
||||
sudo apt-get -qqq update
|
||||
@@ -167,7 +174,7 @@ jobs:
|
||||
gcc-8-make:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: gcc-8 build
|
||||
# See https://askubuntu.com/a/1428822
|
||||
run: |
|
||||
@@ -176,10 +183,29 @@ jobs:
|
||||
make gcc8install
|
||||
CC=gcc-8 CFLAGS="-Werror" make -j all
|
||||
|
||||
make-external-compressors:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: "no external compressors"
|
||||
flags: "HAVE_ZLIB=0 HAVE_LZ4=0 HAVE_LZMA=0"
|
||||
- name: "only zlib"
|
||||
flags: "HAVE_ZLIB=1 HAVE_LZ4=0 HAVE_LZMA=0"
|
||||
- name: "only lz4"
|
||||
flags: "HAVE_ZLIB=0 HAVE_LZ4=1 HAVE_LZMA=0"
|
||||
- name: "only lzma"
|
||||
flags: "HAVE_ZLIB=0 HAVE_LZ4=0 HAVE_LZMA=1"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Build with ${{matrix.name}}
|
||||
run: ${{matrix.flags}} make zstd
|
||||
|
||||
|
||||
implicit-fall-through:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: -Wimplicit-fallthrough build
|
||||
run: |
|
||||
make clean
|
||||
@@ -190,7 +216,7 @@ jobs:
|
||||
meson-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Install packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -214,17 +240,15 @@ jobs:
|
||||
meson-windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Install packages
|
||||
run: pip install --pre meson
|
||||
- name: Initialize the MSVC dev command prompt
|
||||
uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89
|
||||
- name: Configure with Meson
|
||||
run: |
|
||||
meson setup build/meson/ builddir -Dbin_tests=true -Dbin_programs=true -Dbin_contrib=true
|
||||
meson setup --vsenv build/meson/ builddir -Dbin_tests=true -Dbin_programs=true -Dbin_contrib=true
|
||||
- name: Build with Meson
|
||||
run: |
|
||||
ninja -C builddir/
|
||||
meson compile -C builddir/
|
||||
- name: Test with Meson
|
||||
run: |
|
||||
meson test -C builddir/ --print-errorlogs
|
||||
@@ -241,50 +265,64 @@ jobs:
|
||||
- generator: "Visual Studio 17 2022"
|
||||
flags: "-A Win32"
|
||||
- generator: "MinGW Makefiles"
|
||||
- generator: "Visual Studio 17 2022"
|
||||
flags: "-T ClangCL"
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.3
|
||||
- name: Build
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0
|
||||
- name: Build & Test
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
run: |
|
||||
cd build\cmake
|
||||
mkdir build
|
||||
cd build
|
||||
cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} ..
|
||||
cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZSTREAM_FLAGS=-T30s -DZSTD_FUZZER_FLAGS=-T30s -DZSTD_FULLBENCH_FLAGS=-i0 ..
|
||||
cmake.exe --build .
|
||||
ctest.exe -V -C Debug
|
||||
|
||||
msbuild-visual-studio:
|
||||
strategy:
|
||||
fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix failed.
|
||||
matrix:
|
||||
include: [
|
||||
{ name: "VS 2022 x64 Debug", platform: x64, configuration: Debug, toolset: v143, runner: "windows-2022"},
|
||||
{ name: "VS 2022 Win32 Debug", platform: Win32, configuration: Debug, toolset: v143, runner: "windows-2022"},
|
||||
{ name: "VS 2022 x64 Release", platform: x64, configuration: Release, toolset: v143, runner: "windows-2022"},
|
||||
{ name: "VS 2022 Win32 Release", platform: Win32, configuration: Release, toolset: v143, runner: "windows-2022"},
|
||||
{ name: "VS 2019 x64 Release", platform: Win32, configuration: Release, toolset: v142, runner: "windows-2019"},
|
||||
{ name: "VS 2019 Win32 Release", platform: x64, configuration: Release, toolset: v142, runner: "windows-2019"},
|
||||
{ name: "VS 2022 x64 Debug", platform: x64, configuration: Debug, toolset: v143, runner: "windows-2022", arch: "" },
|
||||
{ name: "VS 2022 Win32 Debug", platform: Win32, configuration: Debug, toolset: v143, runner: "windows-2022", arch: "" },
|
||||
{ name: "VS 2022 x64 Release", platform: x64, configuration: Release, toolset: v143, runner: "windows-2022", arch: ""},
|
||||
{ name: "VS 2022 Win32 Release", platform: Win32, configuration: Release, toolset: v143, runner: "windows-2022", arch: ""},
|
||||
{ name: "VS 2019 x64 Release", platform: Win32, configuration: Release, toolset: v142, runner: "windows-2019", arch: ""},
|
||||
{ name: "VS 2019 Win32 Release", platform: x64, configuration: Release, toolset: v142, runner: "windows-2019", arch: ""},
|
||||
{ name: "VS 2022 x64 Release AVX2", platform: x64, configuration: Release, toolset: v143, runner: "windows-2022", arch: "AdvancedVectorExtensions2" },
|
||||
]
|
||||
runs-on: ${{matrix.runner}}
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.3
|
||||
- name: Build
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0
|
||||
- name: Build ${{matrix.name}}
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
# See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
|
||||
if: ${{ matrix.arch == '' }}
|
||||
run: >
|
||||
msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=${{matrix.toolset}}
|
||||
/t:Clean,Build /p:Platform=${{matrix.platform}} /p:Configuration=${{matrix.configuration}}
|
||||
/t:Clean,Build /p:Platform=${{matrix.platform}} /p:Configuration=${{matrix.configuration}} /warnaserror
|
||||
- name: Build ${{matrix.name}}
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
# See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
|
||||
if: ${{ matrix.arch != '' }}
|
||||
run: >
|
||||
msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=${{matrix.toolset}}
|
||||
/t:Clean,Build /p:Platform=${{matrix.platform}} /p:Configuration=${{matrix.configuration}} /warnaserror
|
||||
/p:InstructionSet=${{matrix.arch}}
|
||||
|
||||
# This tests that we don't accidently grow the size too much.
|
||||
# This tests that we don't accidentally grow the size too much.
|
||||
# If the size grows intentionally, you can raise these numbers.
|
||||
# But we do need to think about binary size, since it is a concern.
|
||||
libzstd-size:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: libzstd size test
|
||||
run: |
|
||||
make clean && make -j -C lib libzstd && ./tests/check_size.py lib/libzstd.so 1100000
|
||||
@@ -295,7 +333,7 @@ jobs:
|
||||
minimal-decompressor-macros:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: minimal decompressor macros
|
||||
run: |
|
||||
make clean && make -j all ZSTD_LIB_MINIFY=1 MOREFLAGS="-Werror"
|
||||
@@ -306,11 +344,13 @@ jobs:
|
||||
make clean && make check MOREFLAGS="-Werror -DHUF_FORCE_DECOMPRESS_X2 -DZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG"
|
||||
make clean && make -j all MOREFLAGS="-Werror -DZSTD_NO_INLINE -DZSTD_STRIP_ERROR_STRINGS"
|
||||
make clean && make check MOREFLAGS="-Werror -DZSTD_NO_INLINE -DZSTD_STRIP_ERROR_STRINGS"
|
||||
make clean && make check ZSTD_LIB_EXCLUDE_COMPRESSORS_DFAST_AND_UP=1 MOREFLAGS="-Werror"
|
||||
make clean && make check ZSTD_LIB_EXCLUDE_COMPRESSORS_GREEDY_AND_UP=1 MOREFLAGS="-Werror"
|
||||
|
||||
dynamic-bmi2:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: dynamic bmi2 tests
|
||||
run: |
|
||||
make clean && make -j check MOREFLAGS="-O0 -Werror -mbmi2"
|
||||
@@ -322,13 +362,12 @@ jobs:
|
||||
test-variants:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make all variants & validate
|
||||
run: |
|
||||
make -j -C programs allVariants MOREFLAGS=-O0
|
||||
./tests/test-variants.sh
|
||||
|
||||
|
||||
qemu-consistency:
|
||||
name: QEMU ${{ matrix.name }}
|
||||
runs-on: ubuntu-20.04
|
||||
@@ -342,13 +381,15 @@ jobs:
|
||||
{ name: PPC64LE, xcc_pkg: gcc-powerpc64le-linux-gnu, xcc: powerpc64le-linux-gnu-gcc, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64le-static },
|
||||
{ name: S390X, xcc_pkg: gcc-s390x-linux-gnu, xcc: s390x-linux-gnu-gcc, xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static },
|
||||
{ name: MIPS, xcc_pkg: gcc-mips-linux-gnu, xcc: mips-linux-gnu-gcc, xemu_pkg: qemu-system-mips, xemu: qemu-mips-static },
|
||||
{ name: RISC-V, xcc_pkg: gcc-riscv64-linux-gnu, xcc: riscv64-linux-gnu-gcc, xemu_pkg: qemu-system-riscv64,xemu: qemu-riscv64-static },
|
||||
{ name: M68K, xcc_pkg: gcc-m68k-linux-gnu, xcc: m68k-linux-gnu-gcc, xemu_pkg: qemu-system-m68k, xemu: qemu-m68k-static },
|
||||
{ name: SPARC, xcc_pkg: gcc-sparc64-linux-gnu, xcc: sparc64-linux-gnu-gcc, xemu_pkg: qemu-system-sparc, xemu: qemu-sparc64-static },
|
||||
]
|
||||
env: # Set environment variables
|
||||
XCC: ${{ matrix.xcc }}
|
||||
XEMU: ${{ matrix.xemu }}
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: apt update & install
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -368,6 +409,7 @@ jobs:
|
||||
- name: ARM64
|
||||
if: ${{ matrix.name == 'ARM64' }}
|
||||
run: |
|
||||
LDFLAGS="-static -z force-bti" MOREFLAGS="-mbranch-protection=standard" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
- name: PPC
|
||||
if: ${{ matrix.name == 'PPC' }}
|
||||
@@ -385,10 +427,18 @@ jobs:
|
||||
if: ${{ matrix.name == 'MIPS' }}
|
||||
run: |
|
||||
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
- name: RISC-V
|
||||
if: ${{ matrix.name == 'RISC-V' }}
|
||||
run: |
|
||||
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
- name: M68K
|
||||
if: ${{ matrix.name == 'M68K' }}
|
||||
run: |
|
||||
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
- name: SPARC
|
||||
if: ${{ matrix.name == 'SPARC' }}
|
||||
run: |
|
||||
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
|
||||
mingw-short-test:
|
||||
runs-on: windows-latest
|
||||
@@ -404,8 +454,8 @@ jobs:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- uses: msys2/setup-msys2@cc11e9188b693c2b100158c3322424c4cc1dadea # tag=v2.22.0
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
install: make diffutils
|
||||
@@ -440,9 +490,9 @@ jobs:
|
||||
platform: [x64, Win32]
|
||||
configuration: [Release]
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.3
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0
|
||||
- name: Build and run tests
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
env:
|
||||
@@ -461,8 +511,8 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- run: git config --global core.autocrlf input
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: cygwin/cygwin-install-action@f5e0f048310c425e84bc789f493a828c6dc80a25 # tag=master
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- uses: cygwin/cygwin-install-action@006ad0b0946ca6d0a3ea2d4437677fa767392401 # tag=master
|
||||
with:
|
||||
platform: x86_64
|
||||
packages: >-
|
||||
@@ -483,31 +533,12 @@ jobs:
|
||||
make -C tests fuzzer &&
|
||||
./tests/fuzzer.exe -v -T1m
|
||||
|
||||
intel-cet-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- name: Build Zstd
|
||||
run: |
|
||||
make -j zstd V=1
|
||||
readelf -n zstd
|
||||
- name: Get Intel SDE
|
||||
run: |
|
||||
curl -LO https://downloadmirror.intel.com/684899/sde-external-9.0.0-2021-11-07-lin.tar.xz
|
||||
tar xJvf sde-external-9.0.0-2021-11-07-lin.tar.xz
|
||||
- name: Configure Permissions
|
||||
run: |
|
||||
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
|
||||
- name: Run Under SDE
|
||||
run: |
|
||||
sde-external-9.0.0-2021-11-07-lin/sde -cet -cet-raise 0 -cet-endbr-exe -cet-stderr -cet-abort -- ./zstd -b3
|
||||
|
||||
pkg-config:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: debian:testing
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt -y update
|
||||
@@ -522,7 +553,7 @@ jobs:
|
||||
versions-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Versions Compatibility Test
|
||||
run: |
|
||||
make -C tests versionsTest
|
||||
@@ -530,7 +561,7 @@ jobs:
|
||||
clangbuild:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: make clangbuild
|
||||
run: |
|
||||
make clangbuild
|
||||
@@ -538,7 +569,7 @@ jobs:
|
||||
clang-pgo:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Build PGO Zstd with Clang
|
||||
env:
|
||||
CC: clang-14
|
||||
@@ -550,7 +581,7 @@ jobs:
|
||||
gcc-pgo:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Build PGO Zstd with GCC
|
||||
env:
|
||||
CC: gcc
|
||||
@@ -558,10 +589,29 @@ jobs:
|
||||
make -C programs zstd-pgo
|
||||
./programs/zstd -b
|
||||
|
||||
intel-cet-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
- name: Build Zstd
|
||||
run: |
|
||||
make -j zstd V=1
|
||||
readelf -n zstd
|
||||
- name: Get Intel SDE
|
||||
run: |
|
||||
curl -LO https://downloadmirror.intel.com/813591/sde-external-9.33.0-2024-01-07-lin.tar.xz
|
||||
tar xJvf sde-external-9.33.0-2024-01-07-lin.tar.xz
|
||||
- name: Configure Permissions
|
||||
run: |
|
||||
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
|
||||
- name: Run Under SDE
|
||||
run: |
|
||||
sde-external-9.33.0-2024-01-07-lin/sde -cet -cet-raise 0 -cet-endbr-exe -cet-stderr -cet-abort -- ./zstd -b3
|
||||
|
||||
|
||||
# Failing tests, for reference
|
||||
|
||||
# For reference : icc tests
|
||||
# icc tests are currently failing on Github Actions, likely to issues during installation stage
|
||||
# To be fixed later
|
||||
#
|
||||
# icc:
|
||||
# name: icc-check
|
||||
@@ -577,7 +627,7 @@ jobs:
|
||||
# sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y intel-basekit intel-hpckit
|
||||
# - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
# - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
|
||||
# - name: make check
|
||||
# run: |
|
||||
# make CC=/opt/intel/oneapi/compiler/latest/linux/bin/intel64/icc check
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
name: facebook/zstd/nightly
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 0 * * *
|
||||
push:
|
||||
branches:
|
||||
- release
|
||||
- dev
|
||||
- master
|
||||
permissions: read-all
|
||||
jobs:
|
||||
regression-test:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
docker:
|
||||
image: fbopensource/zstd-circleci-primary:0.0.1
|
||||
options: --entrypoint /bin/bash
|
||||
env:
|
||||
CIRCLE_ARTIFACTS: "/tmp/circleci-artifacts"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
key: regression-cache-{{ checksum "tests/regression/data.c" }}-v0
|
||||
path: tests/regression/cache
|
||||
restore-keys: regression-cache-{{ checksum "tests/regression/data.c" }}-v0
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: "/tmp/circleci-artifacts"
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libcurl4-gnutls-dev
|
||||
- name: Regression Test
|
||||
run: |
|
||||
make -C programs zstd
|
||||
make -C tests/regression test
|
||||
mkdir -p $CIRCLE_ARTIFACTS
|
||||
./tests/regression/test \
|
||||
--cache tests/regression/cache \
|
||||
--output $CIRCLE_ARTIFACTS/results.csv \
|
||||
--zstd programs/zstd
|
||||
echo "NOTE: The new results.csv is uploaded as an artifact to this job"
|
||||
echo " If this fails, go to the Artifacts pane in CircleCI, "
|
||||
echo " download /tmp/circleci-artifacts/results.csv, and if they "
|
||||
echo " are still good, copy it into the repo and commit it."
|
||||
echo "> diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv"
|
||||
diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv
|
||||
|
||||
# Longer tests
|
||||
#- make -C tests test-zstd-nolegacy && make clean
|
||||
#- pyenv global 3.4.4; make -C tests versionsTest && make clean
|
||||
#- make zlibwrapper && make clean
|
||||
#- gcc -v; make -C tests test32 MOREFLAGS="-I/usr/include/x86_64-linux-gnu" && make clean
|
||||
#- make uasan && make clean
|
||||
#- make asan32 && make clean
|
||||
#- make -C tests test32 CC=clang MOREFLAGS="-g -fsanitize=address -I/usr/include/x86_64-linux-gnu"
|
||||
# Valgrind tests
|
||||
#- CFLAGS="-O1 -g" make -C zlibWrapper valgrindTest && make clean
|
||||
#- make -C tests valgrindTest && make clean
|
||||
# ARM, AArch64, PowerPC, PowerPC64 tests
|
||||
#- make ppctest && make clean
|
||||
#- make ppc64test && make clean
|
||||
#- make armtest && make clean
|
||||
#- make aarch64test && make clean
|
||||
@@ -5,21 +5,19 @@ on:
|
||||
types:
|
||||
- published
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
publish-release-artifacts:
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
actions: write # to attach binaries to release artifacts (skx/github-action-publish-binaries)
|
||||
contents: write # to fetch code and upload artifacts
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
|
||||
- name: Archive
|
||||
env:
|
||||
@@ -68,7 +66,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Publish
|
||||
uses: skx/github-action-publish-binaries@release-2.0
|
||||
uses: skx/github-action-publish-binaries@b9ca5643b2f1d7371a6cba7f35333f1461bbc703 # tag=release-2.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
||||
@@ -27,12 +27,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # tag=v2.1.2
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # tag=v2.3.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # tag=v3.1.2
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -59,6 +59,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@3ebbd71c74ef574dbc558c82f70e52732c8b44fe # tag=v2.2.1
|
||||
uses: github/codeql-action/upload-sarif@3ab4101902695724f9365a384f86c1074d94e18c # tag=v3.24.7
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
name: windows-artifacts
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ test_artifacts, win_artifacts ]
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
windows-artifacts:
|
||||
# see https://ariya.io/2020/07/on-github-actions-with-msys2
|
||||
runs-on: windows-latest
|
||||
# see https://github.com/msys2/setup-msys2
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- { msystem: mingw64, env: x86_64, ziparch: win64 }
|
||||
- { msystem: mingw32, env: i686, ziparch: win32 }
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- uses: msys2/setup-msys2@5beef6d11f48bba68b9eb503e3adc60b23c0cc36 # tag=v2
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
install: make zlib git p7zip mingw-w64-${{matrix.env}}-gcc
|
||||
update: true
|
||||
|
||||
- name: display versions
|
||||
run: |
|
||||
make -v
|
||||
cc -v
|
||||
|
||||
- name: Building zlib to static link
|
||||
run: |
|
||||
git clone --depth 1 --branch v1.2.11 https://github.com/madler/zlib
|
||||
make -C zlib -f win32/Makefile.gcc libz.a
|
||||
|
||||
- name: Building zstd programs
|
||||
run: |
|
||||
CPPFLAGS=-I../zlib LDFLAGS=../zlib/libz.a make -j allzstd MOREFLAGS=-static V=1
|
||||
|
||||
- name: Create artifacts
|
||||
run: |
|
||||
./lib/dll/example/build_package.bat
|
||||
mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/
|
||||
7z a -tzip -mx9 zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip zstd-${{ github.ref_name }}-${{matrix.ziparch}}/
|
||||
cd ..
|
||||
|
||||
- name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
|
||||
with:
|
||||
path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip
|
||||
name: zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip
|
||||
+7
-1
@@ -27,6 +27,8 @@ tmp*
|
||||
dictionary.
|
||||
dictionary
|
||||
NUL
|
||||
cmakebuild/
|
||||
install/
|
||||
|
||||
# Build artefacts
|
||||
contrib/linux-kernel/linux/
|
||||
@@ -37,11 +39,15 @@ buck-out/
|
||||
build-*
|
||||
*.gcda
|
||||
|
||||
# IDE
|
||||
.clang_complete
|
||||
compile_flags.txt
|
||||
.clang-format
|
||||
|
||||
# Other files
|
||||
.directory
|
||||
_codelite/
|
||||
_zstdbench/
|
||||
.clang_complete
|
||||
*.idea
|
||||
*.swp
|
||||
.DS_Store
|
||||
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
# Travis CI is used to test platforms that github-actions currently doesn't support
|
||||
# without either self-hosting or some finnicky work-around. Also, some tests
|
||||
# are troublesome to migrate since GH Actions runs tests not in a tty.
|
||||
language: c
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
branches:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- master
|
||||
- travisTest
|
||||
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
|
||||
env:
|
||||
global:
|
||||
- FUZZERTEST=-T1mn
|
||||
ZSTREAM_TESTTIME=-T1mn
|
||||
DECODECORPUS_TESTTIME=-T1mn
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- name: S390X (big endian) + Fuzz test
|
||||
dist: trusty
|
||||
arch: s390x
|
||||
script:
|
||||
- FUZZER_FLAGS=--no-big-tests make -C tests fuzztest
|
||||
|
||||
- name: S390X (big endian) + Fuzz test + no intrinsics
|
||||
dist: trusty
|
||||
arch: s390x
|
||||
script:
|
||||
- MOREFLAGS="-DZSTD_NO_INTRINSICS" FUZZER_FLAGS=--no-big-tests make -C tests fuzztest
|
||||
|
||||
- name: arm64 # ~2.5 mn
|
||||
os: linux
|
||||
arch: arm64
|
||||
script:
|
||||
- make check
|
||||
|
||||
- name: arm64fuzz
|
||||
os: linux
|
||||
arch: arm64
|
||||
script:
|
||||
- make -C tests fuzztest
|
||||
|
||||
# TODO: migrate to GH Actions once newest clang staticanalyze warnings are fixed
|
||||
- name: static analyzer scanbuild # ~8mn
|
||||
dist: trusty # note : it's important to pin down a version of static analyzer, since different versions report different false positives
|
||||
script:
|
||||
- make staticAnalyze
|
||||
|
||||
# GH actions can't run this command on OS-X, non-tty issues
|
||||
- name: OS-X make all lib
|
||||
os: osx
|
||||
script:
|
||||
- make -C lib all
|
||||
|
||||
# Introduced to check compat with old toolchains, to prevent e.g. #1872
|
||||
- name: ARM Build Test (on Trusty)
|
||||
dist: trusty
|
||||
script:
|
||||
- make arminstall
|
||||
- make armbuild
|
||||
|
||||
# check release number (release/new tag only)
|
||||
- name: Tag-Specific Test
|
||||
if: tag =~ ^v[0-9]\.[0-9]
|
||||
script:
|
||||
- make -C tests checkTag
|
||||
- tests/checkTag "$TRAVIS_BRANCH"
|
||||
|
||||
- name: PPC64LE + Fuzz test # ~13mn
|
||||
arch: ppc64le
|
||||
env:
|
||||
- FUZZER_FLAGS=--no-big-tests
|
||||
- MOREFLAGS="-static"
|
||||
script:
|
||||
- cat /proc/cpuinfo
|
||||
- make -C tests fuzztest
|
||||
|
||||
# This test currently fails on GA specifically, for no obvious reason
|
||||
# (it works fine on travisCI, and on local test platforms).
|
||||
- name: Versions Compatibility Test # ~6mn
|
||||
script:
|
||||
- make -C tests versionsTest
|
||||
|
||||
# meson dedicated test
|
||||
- name: Focal (Meson + clang) # ~15mn
|
||||
dist: focal
|
||||
language: cpp
|
||||
compiler: clang
|
||||
install:
|
||||
- sudo apt-get install -qq liblz4-dev valgrind tree
|
||||
- |
|
||||
travis_retry curl -o ~/ninja.zip -L 'https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-linux.zip' &&
|
||||
unzip ~/ninja.zip -d ~/.local/bin
|
||||
- |
|
||||
travis_retry curl -o ~/get-pip.py -L 'https://bootstrap.pypa.io/pip/3.6/get-pip.py' &&
|
||||
python3 ~/get-pip.py --user &&
|
||||
pip3 install --user meson
|
||||
script:
|
||||
- |
|
||||
meson setup \
|
||||
--buildtype=debugoptimized \
|
||||
-Db_lundef=false \
|
||||
-Dauto_features=enabled \
|
||||
-Dbin_programs=true \
|
||||
-Dbin_tests=true \
|
||||
-Dbin_contrib=true \
|
||||
-Ddefault_library=both \
|
||||
build/meson builddir
|
||||
- pushd builddir
|
||||
- ninja
|
||||
- meson test --verbose --no-rebuild
|
||||
- DESTDIR=./staging ninja install
|
||||
- tree ./staging
|
||||
after_failure:
|
||||
- cat "$TRAVIS_BUILD_DIR"/builddir/meson-logs/testlog.txt
|
||||
|
||||
allow_failures:
|
||||
- env: ALLOW_FAILURES=true
|
||||
@@ -1,3 +1,59 @@
|
||||
V1.5.6 (Mar 2024)
|
||||
api: Promote `ZSTD_c_targetCBlockSize` to Stable API by @felixhandte
|
||||
api: new `ZSTD_d_maxBlockSize` experimental parameter, to reduce streaming decompression memory, by @terrelln
|
||||
perf: improve performance of param `ZSTD_c_targetCBlockSize`, by @Cyan4973
|
||||
perf: improved compression of arrays of integers at high compression, by @Cyan4973
|
||||
lib: reduce binary size with selective built-time exclusion, by @felixhandte
|
||||
lib: improved huffman speed on small data and linux kernel, by @terrelln
|
||||
lib: accept dictionaries with partial literal tables, by @terrelln
|
||||
lib: fix CCtx size estimation with external sequence producer, by @embg
|
||||
lib: fix corner case decoder behaviors, by @Cyan4973 and @aimuz
|
||||
lib: fix zdict prototype mismatch in static_only mode, by @ldv-alt
|
||||
lib: fix several bugs in magicless-format decoding, by @embg
|
||||
cli: add common compressed file types to `--exclude-compressed`` by @daniellerozenblit
|
||||
cli: fix mixing `-c` and `-o` commands with `--rm`, by @Cyan4973
|
||||
cli: fix erroneous exclusion of hidden files with `--output-dir-mirror` by @felixhandte
|
||||
cli: improved time accuracy on BSD, by @felixhandte
|
||||
cli: better errors on argument parsing, by @KapJI
|
||||
tests: better compatibility with older versions of `grep`, by @Cyan4973
|
||||
tests: lorem ipsum generator as default backup content, by @Cyan4973
|
||||
build: cmake improvements by @terrelln, @sighingnow, @gjasny, @JohanMabille, @Saverio976, @gruenich, @teo-tsirpanis
|
||||
build: bazel support, by @jondo2010
|
||||
build: fix cross-compiling for AArch64 with lld by @jcelerier
|
||||
build: fix Apple platform compatibility, by @nidhijaju
|
||||
build: fix Visual 2012 and lower compatibility, by @Cyan4973
|
||||
build: improve win32 support, by @DimitriPapadopoulos
|
||||
build: better C90 compliance for zlibWrapper, by @emaste
|
||||
port: make: fat binaries on macos, by @mredig
|
||||
port: ARM64EC compatibility for Windows, by @dunhor
|
||||
port: QNX support by @klausholstjacobsen
|
||||
port: MSYS2 and Cygwin makefile installation and test support, by @QBos07
|
||||
port: risc-v support validation in CI, by @Cyan4973
|
||||
port: sparc64 support validation in CI, by @Cyan4973
|
||||
port: AIX compatibility, by @likema
|
||||
port: HP-UX compatibility, by @likema
|
||||
doc: Improved specification accuracy, by @elasota
|
||||
bug: Fix and deprecate ZSTD_generateSequences (#3981)
|
||||
|
||||
v1.5.5 (Apr 2023)
|
||||
fix: fix rare corruption bug affecting the high compression mode, reported by @danlark1 (#3517, @terrelln)
|
||||
perf: improve mid-level compression speed (#3529, #3533, #3543, @yoniko and #3552, @terrelln)
|
||||
lib: deprecated bufferless block-level API (#3534) by @terrelln
|
||||
cli: mmap large dictionaries to save memory, by @daniellerozenblit
|
||||
cli: improve speed of --patch-from mode (~+50%) (#3545) by @daniellerozenblit
|
||||
cli: improve i/o speed (~+10%) when processing lots of small files (#3479) by @felixhandte
|
||||
cli: zstd no longer crashes when requested to write into write-protected directory (#3541) by @felixhandte
|
||||
cli: fix decompression into block device using -o, reported by @georgmu (#3583)
|
||||
build: fix zstd CLI compiled with lzma support but not zlib support (#3494) by @Hello71
|
||||
build: fix cmake does no longer require 3.18 as minimum version (#3510) by @kou
|
||||
build: fix MSVC+ClangCL linking issue (#3569) by @tru
|
||||
build: fix zstd-dll, version of zstd CLI that links to the dynamic library (#3496) by @yoniko
|
||||
build: fix MSVC warnings (#3495) by @embg
|
||||
doc: updated zstd specification to clarify corner cases, by @Cyan4973
|
||||
doc: document how to create fat binaries for macos (#3568) by @rickmark
|
||||
misc: improve seekable format ingestion speed (~+100%) for very small chunk sizes (#3544) by @Cyan4973
|
||||
misc: tests/fullbench can benchmark multiple files (#3516) by @dloidolt
|
||||
|
||||
v1.5.4 (Feb 2023)
|
||||
perf: +20% faster huffman decompression for targets that can't compile x64 assembly (#3449, @terrelln)
|
||||
perf: up to +10% faster streaming compression at levels 1-2 (#3114, @embg)
|
||||
@@ -79,7 +135,7 @@ build: support for m68k (Motorola 68000's), by @cyan4973
|
||||
build: improved AIX support, by @Helflym
|
||||
build: improved meson unofficial build, by @eli-schwartz
|
||||
cli : custom memory limit when training dictionary (#2925), by @embg
|
||||
cli : report advanced parameters information when compressing in very verbose mode (``-vv`), by @Svetlitski-FB
|
||||
cli : report advanced parameters information when compressing in very verbose mode (`-vv`), by @Svetlitski-FB
|
||||
|
||||
v1.5.0 (May 11, 2021)
|
||||
api: Various functions promoted from experimental to stable API: (#2579-2581, @senhuang42)
|
||||
@@ -146,7 +202,7 @@ api: Add Function to Generate Skippable Frame (#2439, @senhuang42)
|
||||
perf: New Algorithms for the Long Distance Matcher (#2483, @mpu)
|
||||
perf: Performance Improvements for Long Distance Matcher (#2464, @mpu)
|
||||
perf: Don't Shrink Window Log when Streaming with a Dictionary (#2451, @terrelln)
|
||||
cli: Fix `--output-dir-mirror`'s Rejection of `..`-Containing Paths (#2512, @felixhandte)
|
||||
cli: Fix `--output-dir-mirror` rejection of `..` -containing paths (#2512, @felixhandte)
|
||||
cli: Allow Input From Console When `-f`/`--force` is Passed (#2466, @felixhandte)
|
||||
cli: Improve Help Message (#2500, @senhuang42)
|
||||
tests: Remove Flaky Tests (#2455, #2486, #2445, @Cyan4973)
|
||||
|
||||
+3
-3
@@ -171,8 +171,8 @@ who want earlier signal.
|
||||
| Cirrus CI | Used for testing on FreeBSD | https://github.com/marketplace/cirrus-ci/ | `.cirrus.yml` |
|
||||
| Circle CI | Historically was used to provide faster signal,<br/> but we may be able to migrate these to Github Actions | https://circleci.com/docs/2.0/getting-started/#setting-up-circleci <br> https://youtu.be/Js3hMUsSZ2c <br> https://circleci.com/docs/2.0/enable-checks/ | `.circleci/config.yml` |
|
||||
|
||||
Note: the instructions linked above mostly cover how to set up a repository with CI from scratch.
|
||||
The general idea should be the same for setting up CI on your fork of zstd, but you may have to
|
||||
Note: the instructions linked above mostly cover how to set up a repository with CI from scratch.
|
||||
The general idea should be the same for setting up CI on your fork of zstd, but you may have to
|
||||
follow slightly different steps. In particular, please ignore any instructions related to setting up
|
||||
config files (since zstd already has configs for each of these services).
|
||||
|
||||
@@ -216,7 +216,7 @@ will typically not be stable enough to obtain reliable benchmark results. If you
|
||||
hands on a desktop, this is usually a better scenario.
|
||||
|
||||
Of course, benchmarking can be done on non-hyper-stable machines as well. You will just have to
|
||||
do a little more work to ensure that you are in fact measuring the changes you've made not and
|
||||
do a little more work to ensure that you are in fact measuring the changes you've made and not
|
||||
noise. Here are some things you can do to make your benchmarks more stable:
|
||||
|
||||
1. The most simple thing you can do to drastically improve the stability of your benchmark is
|
||||
|
||||
@@ -145,13 +145,13 @@ clean:
|
||||
$(Q)$(MAKE) -C contrib/largeNbDicts $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C contrib/externalSequenceProducer $@ > $(VOID)
|
||||
$(Q)$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
|
||||
$(Q)$(RM) -r lz4
|
||||
$(Q)$(RM) -r lz4 cmakebuild install
|
||||
@echo Cleaning completed
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# make install is validated only for Linux, macOS, Hurd and some BSD targets
|
||||
#------------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly NetBSD MSYS_NT Haiku AIX))
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly NetBSD MSYS_NT CYGWIN_NT Haiku AIX))
|
||||
|
||||
HOST_OS = POSIX
|
||||
|
||||
@@ -197,18 +197,27 @@ uninstall:
|
||||
travis-install:
|
||||
$(MAKE) install PREFIX=~/install_test_dir
|
||||
|
||||
.PHONY: clangbuild-darwin-fat
|
||||
clangbuild-darwin-fat: clean
|
||||
clang -v
|
||||
CXX=clang++ CC=clang CFLAGS="-Werror -Wconversion -Wno-sign-conversion -Wdocumentation -arch arm64" $(MAKE) zstd-release
|
||||
mv programs/zstd programs/zstd_arm64
|
||||
CXX=clang++ CC=clang CFLAGS="-Werror -Wconversion -Wno-sign-conversion -Wdocumentation -arch x86_64" $(MAKE) zstd-release
|
||||
mv programs/zstd programs/zstd_x64
|
||||
lipo -create programs/zstd_x64 programs/zstd_arm64 -output programs/zstd
|
||||
|
||||
.PHONY: gcc5build gcc6build gcc7build clangbuild m32build armbuild aarch64build ppcbuild ppc64build
|
||||
gcc5build: clean
|
||||
gcc-5 -v
|
||||
CC=gcc-5 $(MAKE) all MOREFLAGS="-Werror"
|
||||
CC=gcc-5 $(MAKE) all MOREFLAGS="-Werror $(MOREFLAGS)"
|
||||
|
||||
gcc6build: clean
|
||||
gcc-6 -v
|
||||
CC=gcc-6 $(MAKE) all MOREFLAGS="-Werror"
|
||||
CC=gcc-6 $(MAKE) all MOREFLAGS="-Werror $(MOREFLAGS)"
|
||||
|
||||
gcc7build: clean
|
||||
gcc-7 -v
|
||||
CC=gcc-7 $(MAKE) all MOREFLAGS="-Werror"
|
||||
CC=gcc-7 $(MAKE) all MOREFLAGS="-Werror $(MOREFLAGS)"
|
||||
|
||||
clangbuild: clean
|
||||
clang -v
|
||||
@@ -232,17 +241,17 @@ ppc64build: clean
|
||||
|
||||
.PHONY: armfuzz aarch64fuzz ppcfuzz ppc64fuzz
|
||||
armfuzz: clean
|
||||
CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static MOREFLAGS="-static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest
|
||||
CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static MOREFLAGS="-static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(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
|
||||
CC=aarch64-linux-gnu-gcc QEMU_SYS=qemu-aarch64-static MOREFLAGS="-static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(MAKE) -C $(TESTDIR) fuzztest
|
||||
|
||||
ppcfuzz: clean
|
||||
CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static MOREFLAGS="-static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest
|
||||
CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static MOREFLAGS="-static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(MAKE) -C $(TESTDIR) fuzztest
|
||||
|
||||
ppc64fuzz: clean
|
||||
CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static MOREFLAGS="-m64 -static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest
|
||||
CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static MOREFLAGS="-m64 -static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(MAKE) -C $(TESTDIR) fuzztest
|
||||
|
||||
.PHONY: cxxtest gcc5test gcc6test armtest aarch64test ppctest ppc64test
|
||||
cxxtest: CXXFLAGS += -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror
|
||||
@@ -251,34 +260,34 @@ cxxtest: clean
|
||||
|
||||
gcc5test: clean
|
||||
gcc-5 -v
|
||||
$(MAKE) all CC=gcc-5 MOREFLAGS="-Werror"
|
||||
$(MAKE) all CC=gcc-5 MOREFLAGS="-Werror $(MOREFLAGS)"
|
||||
|
||||
gcc6test: clean
|
||||
gcc-6 -v
|
||||
$(MAKE) all CC=gcc-6 MOREFLAGS="-Werror"
|
||||
$(MAKE) all CC=gcc-6 MOREFLAGS="-Werror $(MOREFLAGS)"
|
||||
|
||||
armtest: clean
|
||||
$(MAKE) -C $(TESTDIR) datagen # use native, faster
|
||||
$(MAKE) -C $(TESTDIR) test CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static ZSTDRTTEST= MOREFLAGS="-Werror -static" FUZZER_FLAGS=--no-big-tests
|
||||
$(MAKE) -C $(TESTDIR) test CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static ZSTDRTTEST= MOREFLAGS="-Werror -static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)"
|
||||
|
||||
aarch64test:
|
||||
$(MAKE) -C $(TESTDIR) datagen # use native, faster
|
||||
$(MAKE) -C $(TESTDIR) test CC=aarch64-linux-gnu-gcc QEMU_SYS=qemu-aarch64-static ZSTDRTTEST= MOREFLAGS="-Werror -static" FUZZER_FLAGS=--no-big-tests
|
||||
$(MAKE) -C $(TESTDIR) test CC=aarch64-linux-gnu-gcc QEMU_SYS=qemu-aarch64-static ZSTDRTTEST= MOREFLAGS="-Werror -static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)"
|
||||
|
||||
ppctest: clean
|
||||
$(MAKE) -C $(TESTDIR) datagen # use native, faster
|
||||
$(MAKE) -C $(TESTDIR) test CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static ZSTDRTTEST= MOREFLAGS="-Werror -Wno-attributes -static" FUZZER_FLAGS=--no-big-tests
|
||||
$(MAKE) -C $(TESTDIR) test CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static ZSTDRTTEST= MOREFLAGS="-Werror -Wno-attributes -static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)"
|
||||
|
||||
ppc64test: clean
|
||||
$(MAKE) -C $(TESTDIR) datagen # use native, faster
|
||||
$(MAKE) -C $(TESTDIR) test CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static ZSTDRTTEST= MOREFLAGS="-m64 -static" FUZZER_FLAGS=--no-big-tests
|
||||
$(MAKE) -C $(TESTDIR) test CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static ZSTDRTTEST= MOREFLAGS="-m64 -static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)"
|
||||
|
||||
.PHONY: arm-ppc-compilation
|
||||
arm-ppc-compilation:
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static ZSTDRTTEST= MOREFLAGS="-Werror -static"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=aarch64-linux-gnu-gcc QEMU_SYS=qemu-aarch64-static ZSTDRTTEST= MOREFLAGS="-Werror -static"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static ZSTDRTTEST= MOREFLAGS="-Werror -Wno-attributes -static"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static ZSTDRTTEST= MOREFLAGS="-m64 -static"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static ZSTDRTTEST= MOREFLAGS="-Werror -static $(MOREFLAGS)"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=aarch64-linux-gnu-gcc QEMU_SYS=qemu-aarch64-static ZSTDRTTEST= MOREFLAGS="-Werror -static $(MOREFLAGS)"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static ZSTDRTTEST= MOREFLAGS="-Werror -Wno-attributes -static $(MOREFLAGS)"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static ZSTDRTTEST= MOREFLAGS="-m64 -static $(MOREFLAGS)"
|
||||
|
||||
regressiontest:
|
||||
$(MAKE) -C $(FUZZDIR) regressiontest
|
||||
@@ -308,31 +317,32 @@ update_regressionResults:
|
||||
# run UBsan with -fsanitize-recover=pointer-overflow
|
||||
# this only works with recent compilers such as gcc 8+
|
||||
usan: clean
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=pointer-overflow -fsanitize=undefined -Werror"
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=undefined -Werror $(MOREFLAGS)"
|
||||
|
||||
asan: clean
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=address -Werror"
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=address -Werror $(MOREFLAGS)"
|
||||
|
||||
asan-%: clean
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=address -Werror" $(MAKE) -C $(TESTDIR) $*
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=address -Werror $(MOREFLAGS)" $(MAKE) -C $(TESTDIR) $*
|
||||
|
||||
msan: clean
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=memory -fno-omit-frame-pointer -Werror" HAVE_LZMA=0 # datagen.c fails this test for no obvious reason
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=memory -fno-omit-frame-pointer -Werror $(MOREFLAGS)" HAVE_LZMA=0 # datagen.c fails this test for no obvious reason
|
||||
|
||||
msan-%: clean
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer -Werror" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) HAVE_LZMA=0 $*
|
||||
msan-%:
|
||||
$(MAKE) clean
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer -Werror $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(MAKE) -j -C $(TESTDIR) HAVE_LZMA=0 $*
|
||||
|
||||
asan32: clean
|
||||
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address"
|
||||
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address $(MOREFLAGS)"
|
||||
|
||||
uasan: clean
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=pointer-overflow -fsanitize=address,undefined -Werror"
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=address,undefined -Werror $(MOREFLAGS)"
|
||||
|
||||
uasan-%: clean
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=pointer-overflow -fsanitize=address,undefined -Werror" $(MAKE) -C $(TESTDIR) $*
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=address,undefined -Werror $(MOREFLAGS)" $(MAKE) -C $(TESTDIR) $*
|
||||
|
||||
tsan-%: clean
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=thread -Werror" $(MAKE) -C $(TESTDIR) $* FUZZER_FLAGS=--no-big-tests
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=thread -Werror $(MOREFLAGS)" $(MAKE) -C $(TESTDIR) $* FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)"
|
||||
|
||||
.PHONY: apt-install
|
||||
apt-install:
|
||||
@@ -380,28 +390,32 @@ lz4install:
|
||||
endif
|
||||
|
||||
|
||||
CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZLIB_SUPPORT:BOOL=ON -DZSTD_LZMA_SUPPORT:BOOL=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
ifneq (,$(filter MSYS%,$(shell uname)))
|
||||
HOST_OS = MSYS
|
||||
CMAKE_PARAMS = -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug -DZSTD_MULTITHREAD_SUPPORT:BOOL=OFF -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON
|
||||
endif
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# target specific tests
|
||||
#------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(HOST_OS),MSYS POSIX))
|
||||
.PHONY: cmakebuild c89build gnu90build c99build gnu99build c11build bmix64build bmix32build bmi32build staticAnalyze
|
||||
cmakebuild:
|
||||
cmake --version
|
||||
$(RM) -r $(BUILDIR)/cmake/build
|
||||
$(MKDIR) $(BUILDIR)/cmake/build
|
||||
cd $(BUILDIR)/cmake/build; cmake -DCMAKE_INSTALL_PREFIX:PATH=~/install_test_dir $(CMAKE_PARAMS) ..
|
||||
$(MAKE) -C $(BUILDIR)/cmake/build -j4;
|
||||
$(MAKE) -C $(BUILDIR)/cmake/build install;
|
||||
$(MAKE) -C $(BUILDIR)/cmake/build uninstall;
|
||||
cd $(BUILDIR)/cmake/build; ctest -V -L Medium
|
||||
|
||||
CMAKE ?= cmake
|
||||
CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZLIB_SUPPORT:BOOL=ON -DZSTD_LZMA_SUPPORT:BOOL=ON
|
||||
|
||||
ifneq (,$(filter MSYS%,$(shell uname)))
|
||||
CMAKE_PARAMS = -G"MSYS Makefiles" -DZSTD_MULTITHREAD_SUPPORT:BOOL=OFF -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON
|
||||
endif
|
||||
|
||||
.PHONY: cmakebuild
|
||||
cmakebuild:
|
||||
$(CMAKE) --version
|
||||
$(RM) -r cmakebuild install
|
||||
$(MKDIR) cmakebuild install
|
||||
cd cmakebuild; $(CMAKE) -Wdev -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS="-Werror -O0" -DCMAKE_INSTALL_PREFIX=install $(CMAKE_PARAMS) ../build/cmake
|
||||
$(CMAKE) --build cmakebuild --target install -- -j V=1
|
||||
cd cmakebuild; ctest -V -L Medium
|
||||
|
||||
.PHONY: c89build gnu90build c99build gnu99build c11build bmix64build bmix32build bmi32build staticAnalyze
|
||||
c89build: clean
|
||||
$(CC) -v
|
||||
CFLAGS="-std=c89 -Werror -Wno-attributes -Wpedantic -Wno-long-long -Wno-variadic-macros -O0" $(MAKE) lib zstd
|
||||
|
||||
@@ -5,7 +5,7 @@ targeting real-time compression scenarios at zlib-level and better compression r
|
||||
It's backed by a very fast entropy stage, provided by [Huff0 and FSE library](https://github.com/Cyan4973/FiniteStateEntropy).
|
||||
|
||||
Zstandard's format is stable and documented in [RFC8878](https://datatracker.ietf.org/doc/html/rfc8878). Multiple independent implementations are already available.
|
||||
This repository represents the reference implementation, provided as an open-source dual [BSD](LICENSE) and [GPLv2](COPYING) licensed **C** library,
|
||||
This repository represents the reference implementation, provided as an open-source dual [BSD](LICENSE) OR [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](https://facebook.github.io/zstd/#other-languages).
|
||||
@@ -13,15 +13,12 @@ a list of known ports and bindings is provided on [Zstandard homepage](https://f
|
||||
**Development branch status:**
|
||||
|
||||
[![Build Status][travisDevBadge]][travisLink]
|
||||
[![Build status][AppveyorDevBadge]][AppveyorLink]
|
||||
[![Build status][CircleDevBadge]][CircleLink]
|
||||
[![Build status][CirrusDevBadge]][CirrusLink]
|
||||
[![Fuzzing Status][OSSFuzzBadge]][OSSFuzzLink]
|
||||
|
||||
[travisDevBadge]: https://api.travis-ci.com/facebook/zstd.svg?branch=dev "Continuous Integration test suite"
|
||||
[travisLink]: https://travis-ci.com/facebook/zstd
|
||||
[AppveyorDevBadge]: https://ci.appveyor.com/api/projects/status/xt38wbdxjk5mrbem/branch/dev?svg=true "Windows test suite"
|
||||
[AppveyorLink]: https://ci.appveyor.com/project/YannCollet/zstd-p0yf0
|
||||
[CircleDevBadge]: https://circleci.com/gh/facebook/zstd/tree/dev.svg?style=shield "Short test suite"
|
||||
[CircleLink]: https://circleci.com/gh/facebook/zstd
|
||||
[CirrusDevBadge]: https://api.cirrus-ci.com/github/facebook/zstd.svg?branch=dev
|
||||
@@ -154,6 +151,18 @@ to create `zstd` binary, and `libzstd` dynamic and static libraries.
|
||||
|
||||
By default, `CMAKE_BUILD_TYPE` is set to `Release`.
|
||||
|
||||
#### Support for Fat (Universal2) Output
|
||||
|
||||
`zstd` can be built and installed with support for both Apple Silicon (M1/M2) as well as Intel by using CMake's Universal2 support.
|
||||
To perform a Fat/Universal2 build and install use the following commands:
|
||||
|
||||
```bash
|
||||
cmake -B build-cmake-debug -S build/cmake -G Ninja -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h;arm64"
|
||||
cd build-cmake-debug
|
||||
ninja
|
||||
sudo ninja install
|
||||
```
|
||||
|
||||
### Meson
|
||||
|
||||
A Meson project is provided within [`build/meson`](build/meson). Follow
|
||||
@@ -189,6 +198,10 @@ Going into `build` directory, you will find additional possibilities:
|
||||
You can build the zstd binary via buck by executing: `buck build programs:zstd` from the root of the repo.
|
||||
The output binary will be in `buck-out/gen/programs/`.
|
||||
|
||||
### Bazel
|
||||
|
||||
You easily can integrate zstd into your Bazel project by using the module hosted on the [Bazel Central Repository](https://registry.bazel.build/modules/zstd).
|
||||
|
||||
## Testing
|
||||
|
||||
You can run quick local smoke tests by running `make check`.
|
||||
@@ -204,7 +217,7 @@ Zstandard is considered safe for production environments.
|
||||
|
||||
## License
|
||||
|
||||
Zstandard is dual-licensed under [BSD](LICENSE) and [GPLv2](COPYING).
|
||||
Zstandard is dual-licensed under [BSD](LICENSE) OR [GPLv2](COPYING).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# Reporting and Fixing Security Issues
|
||||
|
||||
Please do not open GitHub issues or pull requests - this makes the problem immediately visible to everyone, including malicious actors. Security issues in this open source project can be safely reported via the Meta Bug Bounty program:
|
||||
|
||||
https://www.facebook.com/whitehat
|
||||
|
||||
Meta's security team will triage your report and determine whether or not is it eligible for a bounty under our program.
|
||||
|
||||
# Receiving Vulnerability Notifications
|
||||
|
||||
In the case that a significant security vulnerability is reported to us or discovered by us---without being publicly known---we will, at our discretion, notify high-profile, high-exposure users of Zstandard ahead of our public disclosure of the issue and associated fix.
|
||||
|
||||
If you believe your project would benefit from inclusion in this list, please reach out to one of the maintainers.
|
||||
|
||||
<!-- Note to maintainers: this list is kept [here](https://fburl.com/wiki/cgc1l62x). -->
|
||||
-205
@@ -1,205 +0,0 @@
|
||||
# Following tests are run _only_ on `release` branch
|
||||
# and on selected feature branch named `appveyorTest` or `visual*`
|
||||
|
||||
-
|
||||
version: 1.0.{build}
|
||||
branches:
|
||||
only:
|
||||
- release
|
||||
- master
|
||||
- /appveyor*/
|
||||
- /visual*/
|
||||
environment:
|
||||
matrix:
|
||||
- COMPILER: "gcc"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x64"
|
||||
SCRIPT: "make allzstd MOREFLAGS=-static"
|
||||
ARTIFACT: "true"
|
||||
BUILD: "true"
|
||||
- COMPILER: "gcc"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x86"
|
||||
SCRIPT: "make allzstd MOREFLAGS=-static"
|
||||
ARTIFACT: "true"
|
||||
BUILD: "true"
|
||||
|
||||
- COMPILER: "clang-cl"
|
||||
HOST: "cmake-visual"
|
||||
PLATFORM: "x64"
|
||||
CONFIGURATION: "Release"
|
||||
CMAKE_GENERATOR: "Visual Studio 15 2017"
|
||||
CMAKE_GENERATOR_PLATFORM: "x64"
|
||||
CMAKE_GENERATOR_TOOLSET: "LLVM"
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
|
||||
|
||||
install:
|
||||
- ECHO Installing %COMPILER% %PLATFORM% %CONFIGURATION%
|
||||
- SET PATH_ORIGINAL=%PATH%
|
||||
- if [%HOST%]==[mingw] (
|
||||
SET "PATH_MINGW32=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin" &&
|
||||
SET "PATH_MINGW64=C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin" &&
|
||||
COPY C:\msys64\usr\bin\make.exe C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin\make.exe &&
|
||||
COPY C:\msys64\usr\bin\make.exe C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin\make.exe
|
||||
)
|
||||
- IF [%HOST%]==[visual] IF [%PLATFORM%]==[x64] (
|
||||
SET ADDITIONALPARAM=/p:LibraryPath="C:\Program Files\Microsoft SDKs\Windows\v7.1\lib\x64;c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64;C:\Program Files (x86)\Microsoft Visual Studio 10.0\;C:\Program Files (x86)\Microsoft Visual Studio 10.0\lib\amd64;"
|
||||
)
|
||||
|
||||
build_script:
|
||||
- if [%HOST%]==[mingw] (
|
||||
( if [%PLATFORM%]==[x64] (
|
||||
SET "PATH=%PATH_MINGW64%;%PATH_ORIGINAL%"
|
||||
) else if [%PLATFORM%]==[x86] (
|
||||
SET "PATH=%PATH_MINGW32%;%PATH_ORIGINAL%"
|
||||
) )
|
||||
)
|
||||
- if [%HOST%]==[mingw] if [%BUILD%]==[true] (
|
||||
make -v &&
|
||||
sh -c "%COMPILER% -v" &&
|
||||
ECHO Building zlib to static link &&
|
||||
SET "CC=%COMPILER%" &&
|
||||
sh -c "cd .. && git clone --depth 1 --branch v1.2.11 https://github.com/madler/zlib" &&
|
||||
sh -c "cd ../zlib && make -f win32/Makefile.gcc libz.a"
|
||||
ECHO Building zstd &&
|
||||
SET "CPPFLAGS=-I../../zlib" &&
|
||||
SET "LDFLAGS=../../zlib/libz.a" &&
|
||||
sh -c "%SCRIPT%" &&
|
||||
( if [%COMPILER%]==[gcc] if [%ARTIFACT%]==[true]
|
||||
ECHO Creating artifacts &&
|
||||
ECHO %cd% &&
|
||||
lib\dll\example\build_package.bat &&
|
||||
make -C programs DEBUGFLAGS= clean zstd &&
|
||||
cd programs\ && 7z a -tzip -mx9 zstd-win-binary-%PLATFORM%.zip zstd.exe &&
|
||||
appveyor PushArtifact zstd-win-binary-%PLATFORM%.zip &&
|
||||
cp zstd.exe ..\bin\zstd.exe &&
|
||||
git clone --depth 1 --branch release https://github.com/facebook/zstd &&
|
||||
cd zstd &&
|
||||
git archive --format=tar release -o zstd-src.tar &&
|
||||
..\zstd -19 zstd-src.tar &&
|
||||
appveyor PushArtifact zstd-src.tar.zst &&
|
||||
certUtil -hashfile zstd-src.tar.zst SHA256 > zstd-src.tar.zst.sha256.sig &&
|
||||
appveyor PushArtifact zstd-src.tar.zst.sha256.sig &&
|
||||
cd ..\..\bin\ &&
|
||||
7z a -tzip -mx9 zstd-win-release-%PLATFORM%.zip * &&
|
||||
appveyor PushArtifact zstd-win-release-%PLATFORM%.zip
|
||||
)
|
||||
)
|
||||
- if [%HOST%]==[cmake-visual] (
|
||||
ECHO *** &&
|
||||
ECHO *** Building %CMAKE_GENERATOR% ^(%CMAKE_GENERATOR_TOOLSET%^) %PLATFORM%\%CONFIGURATION% &&
|
||||
PUSHD build\cmake &&
|
||||
cmake -DBUILD_TESTING=ON . &&
|
||||
cmake --build . --config %CONFIGURATION% -j4 &&
|
||||
POPD &&
|
||||
ECHO ***
|
||||
)
|
||||
|
||||
test_script:
|
||||
- ECHO Testing %COMPILER% %PLATFORM% %CONFIGURATION%
|
||||
- SET "CC=gcc"
|
||||
- SET "CXX=g++"
|
||||
- if [%TEST%]==[cmake] (
|
||||
mkdir build\cmake\build &&
|
||||
cd build\cmake\build &&
|
||||
SET FUZZERTEST=-T2mn &&
|
||||
SET ZSTREAM_TESTTIME=-T2mn &&
|
||||
cmake -G "Visual Studio 14 2015 Win64" .. &&
|
||||
cd ..\..\.. &&
|
||||
make clean
|
||||
)
|
||||
|
||||
|
||||
# The following tests are for regular pushes
|
||||
# into `dev` or some feature branch
|
||||
# There run less tests, for shorter feedback loop
|
||||
|
||||
-
|
||||
version: 1.0.{build}
|
||||
environment:
|
||||
matrix:
|
||||
- COMPILER: "visual"
|
||||
HOST: "visual"
|
||||
PLATFORM: "x64"
|
||||
CONFIGURATION: "Debug"
|
||||
- COMPILER: "visual"
|
||||
HOST: "visual"
|
||||
PLATFORM: "Win32"
|
||||
CONFIGURATION: "Debug"
|
||||
- COMPILER: "visual"
|
||||
HOST: "visual"
|
||||
PLATFORM: "x64"
|
||||
CONFIGURATION: "Release"
|
||||
- COMPILER: "visual"
|
||||
HOST: "visual"
|
||||
PLATFORM: "Win32"
|
||||
CONFIGURATION: "Release"
|
||||
|
||||
- COMPILER: "gcc"
|
||||
HOST: "cygwin"
|
||||
PLATFORM: "x64"
|
||||
|
||||
- COMPILER: "clang-cl"
|
||||
HOST: "cmake-visual"
|
||||
PLATFORM: "x64"
|
||||
CONFIGURATION: "Release"
|
||||
CMAKE_GENERATOR: "Visual Studio 15 2017"
|
||||
CMAKE_GENERATOR_PLATFORM: "x64"
|
||||
CMAKE_GENERATOR_TOOLSET: "LLVM"
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
|
||||
|
||||
install:
|
||||
- ECHO Installing %COMPILER% %PLATFORM% %CONFIGURATION%
|
||||
- SET PATH_ORIGINAL=%PATH%
|
||||
- if [%HOST%]==[cygwin] (
|
||||
ECHO Installing Cygwin Packages &&
|
||||
C:\cygwin64\setup-x86_64.exe -qnNdO -R "C:\cygwin64" -g -P ^
|
||||
gcc,^
|
||||
cmake,^
|
||||
make
|
||||
)
|
||||
- IF [%HOST%]==[visual] IF [%PLATFORM%]==[x64] (
|
||||
SET ADDITIONALPARAM=/p:LibraryPath="C:\Program Files\Microsoft SDKs\Windows\v7.1\lib\x64;c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64;C:\Program Files (x86)\Microsoft Visual Studio 10.0\;C:\Program Files (x86)\Microsoft Visual Studio 10.0\lib\amd64;"
|
||||
)
|
||||
|
||||
build_script:
|
||||
- ECHO Building %COMPILER% %PLATFORM% %CONFIGURATION%
|
||||
- if [%HOST%]==[cygwin] (
|
||||
set CHERE_INVOKING=yes &&
|
||||
set CC=%COMPILER% &&
|
||||
C:\cygwin64\bin\bash --login -c "
|
||||
set -e;
|
||||
cd build/cmake;
|
||||
CFLAGS='-Werror' cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Debug -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_FUZZER_FLAGS=-T20s -DZSTD_ZSTREAM_FLAGS=-T20s -DZSTD_FULLBENCH_FLAGS=-i0 .;
|
||||
make VERBOSE=1 -j;
|
||||
ctest -V -L Medium;
|
||||
"
|
||||
)
|
||||
- if [%HOST%]==[cmake-visual] (
|
||||
ECHO *** &&
|
||||
ECHO *** Building %CMAKE_GENERATOR% ^(%CMAKE_GENERATOR_TOOLSET%^) %PLATFORM%\%CONFIGURATION% &&
|
||||
PUSHD build\cmake &&
|
||||
cmake -DBUILD_TESTING=ON . &&
|
||||
cmake --build . --config %CONFIGURATION% -j4 &&
|
||||
POPD &&
|
||||
ECHO ***
|
||||
)
|
||||
- if [%HOST%]==[visual] (
|
||||
ECHO *** &&
|
||||
ECHO *** Building Visual Studio 2012 %PLATFORM%\%CONFIGURATION% &&
|
||||
ECHO *** &&
|
||||
msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v110 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\build\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" &&
|
||||
DIR build\VS2010\bin\%PLATFORM%_%CONFIGURATION%\*.exe &&
|
||||
msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v110 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" &&
|
||||
DIR build\VS2010\bin\%PLATFORM%_%CONFIGURATION%\*.exe
|
||||
)
|
||||
|
||||
|
||||
test_script:
|
||||
- ECHO Testing %COMPILER% %PLATFORM% %CONFIGURATION%
|
||||
- SET "FUZZERTEST=-T10s"
|
||||
- if [%HOST%]==[mingw] (
|
||||
set "CC=%COMPILER%" &&
|
||||
make clean &&
|
||||
make check
|
||||
)
|
||||
@@ -356,6 +356,10 @@
|
||||
RelativePath="..\..\..\programs\dibio.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\programs\lorem.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\dictBuilder\cover.c"
|
||||
>
|
||||
|
||||
@@ -157,6 +157,8 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\programs\util.c" />
|
||||
<ClCompile Include="..\..\..\programs\datagen.c" />
|
||||
<ClCompile Include="..\..\..\programs\lorem.c" />
|
||||
<ClCompile Include="..\..\..\tests\loremOut.c" />
|
||||
<ClCompile Include="..\..\..\tests\datagencli.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -169,7 +169,6 @@
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
|
||||
@@ -162,7 +162,6 @@
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<ClCompile Include="..\..\..\programs\dibio.c" />
|
||||
<ClCompile Include="..\..\..\programs\fileio.c" />
|
||||
<ClCompile Include="..\..\..\programs\fileio_asyncio.c" />
|
||||
<ClCompile Include="..\..\..\programs\lorem.c" />
|
||||
<ClCompile Include="..\..\..\programs\zstdcli.c" />
|
||||
<ClCompile Include="..\..\..\programs\zstdcli_trace.c" />
|
||||
</ItemGroup>
|
||||
@@ -114,6 +115,7 @@
|
||||
<RootNamespace>zstd</RootNamespace>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)bin\obj\$(RootNamespace)_$(Platform)_$(Configuration)\</IntDir>
|
||||
<InstructionSet>NotSet</InstructionSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
@@ -187,6 +189,7 @@
|
||||
<PreprocessorDefinitions>ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
<EnableEnhancedInstructionSet>$(InstructionSet)</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -203,6 +206,7 @@
|
||||
<PreprocessorDefinitions>ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
<EnableEnhancedInstructionSet>$(InstructionSet)</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -222,6 +226,7 @@
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
<TreatWarningAsError>false</TreatWarningAsError>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<EnableEnhancedInstructionSet>$(InstructionSet)</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -244,6 +249,7 @@
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalOptions>/DZSTD_MULTITHREAD %(AdditionalOptions)</AdditionalOptions>
|
||||
<EnableEnhancedInstructionSet>$(InstructionSet)</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
||||
+35
-31
@@ -7,16 +7,14 @@
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
# As of 2018-12-26 ZSTD has been validated to build with cmake version 3.13.2 new policies.
|
||||
# Set and use the newest cmake policies that are validated to work
|
||||
set(ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION "3")
|
||||
set(ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION "13") #Policies never changed at PATCH level
|
||||
if("${CMAKE_MAJOR_VERSION}" LESS 3)
|
||||
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
|
||||
elseif( "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND
|
||||
"${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}")
|
||||
if("${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND
|
||||
"${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}")
|
||||
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
|
||||
else()
|
||||
set(ZSTD_CMAKE_POLICY_VERSION "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}.${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}.0")
|
||||
@@ -32,24 +30,13 @@ set(LIBRARY_DIR ${ZSTD_SOURCE_DIR}/lib)
|
||||
include(GetZstdLibraryVersion)
|
||||
GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH)
|
||||
|
||||
if( CMAKE_MAJOR_VERSION LESS 3 )
|
||||
## Provide cmake 3+ behavior for older versions of cmake
|
||||
project(zstd)
|
||||
set(PROJECT_VERSION_MAJOR ${zstd_VERSION_MAJOR})
|
||||
set(PROJECT_VERSION_MINOR ${zstd_VERSION_MINOR})
|
||||
set(PROJECT_VERSION_PATCH ${zstd_VERSION_PATCH})
|
||||
set(PROJECT_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}")
|
||||
enable_language(C) # Main library is in C
|
||||
enable_language(ASM) # And ASM
|
||||
enable_language(CXX) # Testing contributed code also utilizes CXX
|
||||
else()
|
||||
project(zstd
|
||||
VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}"
|
||||
LANGUAGES C # Main library is in C
|
||||
ASM # And ASM
|
||||
CXX # Testing contributed code also utilizes CXX
|
||||
)
|
||||
endif()
|
||||
project(zstd
|
||||
VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}"
|
||||
LANGUAGES C # Main library is in C
|
||||
ASM # And ASM
|
||||
CXX # Testing contributed code also utilizes CXX
|
||||
)
|
||||
|
||||
message(STATUS "ZSTD VERSION: ${zstd_VERSION}")
|
||||
set(zstd_HOMEPAGE_URL "https://facebook.github.io/zstd")
|
||||
set(zstd_DESCRIPTION "Zstandard is a real-time compression algorithm, providing high compression ratios.")
|
||||
@@ -127,10 +114,26 @@ endif ()
|
||||
#-----------------------------------------------------------------------------
|
||||
# External dependencies
|
||||
#-----------------------------------------------------------------------------
|
||||
# Define a function to handle special thread settings for HP-UX
|
||||
# See https://github.com/facebook/zstd/pull/3862 for details.
|
||||
function(setup_hpux_threads)
|
||||
find_package(Threads)
|
||||
if (NOT Threads_FOUND)
|
||||
set(CMAKE_USE_PTHREADS_INIT 1 PARENT_SCOPE)
|
||||
set(CMAKE_THREAD_LIBS_INIT -lpthread PARENT_SCOPE)
|
||||
set(CMAKE_HAVE_THREADS_LIBRARY 1 PARENT_SCOPE)
|
||||
set(Threads_FOUND TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if (ZSTD_MULTITHREAD_SUPPORT AND UNIX)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
if(CMAKE_USE_PTHREADS_INIT)
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "HP-UX")
|
||||
setup_hpux_threads()
|
||||
else()
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(THREADS_LIBS "${CMAKE_THREAD_LIBS_INIT}")
|
||||
else()
|
||||
message(SEND_ERROR "ZSTD currently does not support thread libraries other than pthreads")
|
||||
@@ -193,10 +196,6 @@ export(EXPORT zstdExports
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/zstdTargets.cmake"
|
||||
NAMESPACE zstd::
|
||||
)
|
||||
configure_file(zstdConfig.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/zstdConfig.cmake"
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
# A Package Config file that works from the installation directory
|
||||
set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/zstd)
|
||||
@@ -205,8 +204,13 @@ install(EXPORT zstdExports
|
||||
NAMESPACE zstd::
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
configure_package_config_file(
|
||||
zstdConfig.cmake.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/zstdConfig.cmake"
|
||||
INSTALL_DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
install(FILES
|
||||
zstdConfig.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/zstdConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/zstdConfigVersion.cmake"
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckLinkerFlag)
|
||||
# VERSION_GREATER_EQUAL requires CMake 3.7 or later.
|
||||
# https://cmake.org/cmake/help/latest/command/if.html#version-greater-equal
|
||||
if (CMAKE_VERSION VERSION_LESS 3.18)
|
||||
set(ZSTD_HAVE_CHECK_LINKER_FLAG false)
|
||||
else ()
|
||||
set(ZSTD_HAVE_CHECK_LINKER_FLAG true)
|
||||
endif ()
|
||||
if (ZSTD_HAVE_CHECK_LINKER_FLAG)
|
||||
include(CheckLinkerFlag)
|
||||
endif()
|
||||
|
||||
function(EnableCompilerFlag _flag _C _CXX _LD)
|
||||
string(REGEX REPLACE "\\+" "PLUS" varname "${_flag}")
|
||||
@@ -20,7 +29,20 @@ function(EnableCompilerFlag _flag _C _CXX _LD)
|
||||
endif ()
|
||||
endif ()
|
||||
if (_LD)
|
||||
CHECK_LINKER_FLAG(C ${_flag} LD_FLAG_${varname})
|
||||
# We never add a linker flag with CMake < 3.18. We will
|
||||
# implement CHECK_LINKER_FLAG() like feature for CMake < 3.18
|
||||
# or require CMake >= 3.18 when we need to add a required
|
||||
# linker flag in future.
|
||||
#
|
||||
# We also skip linker flags check for MSVC compilers (which includes
|
||||
# clang-cl) since currently check_linker_flag() doesn't give correct
|
||||
# results for this configuration,
|
||||
# see: https://gitlab.kitware.com/cmake/cmake/-/issues/22023
|
||||
if (ZSTD_HAVE_CHECK_LINKER_FLAG AND NOT MSVC)
|
||||
CHECK_LINKER_FLAG(C ${_flag} LD_FLAG_${varname})
|
||||
else ()
|
||||
set(LD_FLAG_${varname} false)
|
||||
endif ()
|
||||
if (LD_FLAG_${varname})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${_flag}" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${_flag}" PARENT_SCOPE)
|
||||
|
||||
@@ -41,6 +41,38 @@ cmake -DZSTD_BUILD_TESTS=ON -DZSTD_LEGACY_SUPPORT=OFF ..
|
||||
make
|
||||
```
|
||||
|
||||
### how to use it with CMake FetchContent
|
||||
|
||||
For all options available, you can see it on <https://github.com/facebook/zstd/blob/dev/build/cmake/lib/CMakeLists.txt>
|
||||
```cmake
|
||||
include(FetchContent)
|
||||
|
||||
set(ZSTD_BUILD_STATIC ON)
|
||||
set(ZSTD_BUILD_SHARED OFF)
|
||||
|
||||
FetchContent_Declare(
|
||||
zstd
|
||||
URL "https://github.com/facebook/zstd/releases/download/v1.5.5/zstd-1.5.5.tar.gz"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
SOURCE_SUBDIR build/cmake
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(zstd)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE
|
||||
libzstd_static
|
||||
)
|
||||
|
||||
# On windows and macos this is needed
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${zstd_SOURCE_DIR}/lib
|
||||
)
|
||||
```
|
||||
|
||||
### referring
|
||||
[Looking for a 'cmake clean' command to clear up CMake output](https://stackoverflow.com/questions/9680420/looking-for-a-cmake-clean-command-to-clear-up-cmake-output)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ set(PZSTD_DIR ${ZSTD_SOURCE_DIR}/contrib/pzstd)
|
||||
include_directories(${PROGRAMS_DIR} ${LIBRARY_DIR} ${LIBRARY_DIR}/common ${PZSTD_DIR})
|
||||
|
||||
add_executable(pzstd ${PROGRAMS_DIR}/util.c ${PZSTD_DIR}/main.cpp ${PZSTD_DIR}/Options.cpp ${PZSTD_DIR}/Pzstd.cpp ${PZSTD_DIR}/SkippableFrame.cpp)
|
||||
target_compile_features(pzstd PRIVATE cxx_std_11)
|
||||
set_property(TARGET pzstd APPEND PROPERTY COMPILE_DEFINITIONS "NDEBUG")
|
||||
set_property(TARGET pzstd APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow")
|
||||
|
||||
|
||||
@@ -12,45 +12,70 @@ project(libzstd C ASM)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
|
||||
option(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON)
|
||||
option(ZSTD_BUILD_SHARED "BUILD SHARED LIBRARIES" ON)
|
||||
option(ZSTD_BUILD_COMPRESSION "BUILD COMPRESSION MODULE" ON)
|
||||
option(ZSTD_BUILD_DECOMPRESSION "BUILD DECOMPRESSION MODULE" ON)
|
||||
option(ZSTD_BUILD_DICTBUILDER "BUILD DICTBUILDER MODULE" ON)
|
||||
option(ZSTD_BUILD_DEPRECATED "BUILD DEPRECATED MODULE" OFF)
|
||||
|
||||
set(ZSTDLIB_VISIBLE "" CACHE STRING "Visibility for ZSTDLIB API")
|
||||
set(ZSTDERRORLIB_VISIBLE "" CACHE STRING "Visibility for ZSTDERRORLIB_VISIBLE API")
|
||||
set(ZDICTLIB_VISIBLE "" CACHE STRING "Visibility for ZDICTLIB_VISIBLE API")
|
||||
set(ZSTDLIB_STATIC_API "" CACHE STRING "Visibility for ZSTDLIB_STATIC_API API")
|
||||
set(ZDICTLIB_STATIC_API "" CACHE STRING "Visibility for ZDICTLIB_STATIC_API API")
|
||||
|
||||
set_property(CACHE ZSTDLIB_VISIBLE PROPERTY STRINGS "" "hidden" "default" "protected" "internal")
|
||||
set_property(CACHE ZSTDERRORLIB_VISIBLE PROPERTY STRINGS "" "hidden" "default" "protected" "internal")
|
||||
set_property(CACHE ZDICTLIB_VISIBLE PROPERTY STRINGS "" "hidden" "default" "protected" "internal")
|
||||
set_property(CACHE ZSTDLIB_STATIC_API PROPERTY STRINGS "" "hidden" "default" "protected" "internal")
|
||||
set_property(CACHE ZDICTLIB_STATIC_API PROPERTY STRINGS "" "hidden" "default" "protected" "internal")
|
||||
|
||||
if(NOT ZSTD_BUILD_SHARED AND NOT ZSTD_BUILD_STATIC)
|
||||
message(SEND_ERROR "You need to build at least one flavor of libzstd")
|
||||
endif()
|
||||
|
||||
# Define library directory, where sources and header files are located
|
||||
include_directories(${LIBRARY_DIR} ${LIBRARY_DIR}/common)
|
||||
|
||||
file(GLOB CommonSources ${LIBRARY_DIR}/common/*.c)
|
||||
file(GLOB CompressSources ${LIBRARY_DIR}/compress/*.c)
|
||||
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c)
|
||||
if (MSVC)
|
||||
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c)
|
||||
add_compile_options(-DZSTD_DISABLE_ASM)
|
||||
else ()
|
||||
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c ${LIBRARY_DIR}/decompress/*.S)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|AMD64.*|x86_64.*|X86_64.*")
|
||||
set(DecompressSources ${DecompressSources} ${LIBRARY_DIR}/decompress/huf_decompress_amd64.S)
|
||||
else()
|
||||
add_compile_options(-DZSTD_DISABLE_ASM)
|
||||
endif()
|
||||
endif ()
|
||||
file(GLOB DictBuilderSources ${LIBRARY_DIR}/dictBuilder/*.c)
|
||||
file(GLOB DeprecatedSources ${LIBRARY_DIR}/deprecated/*.c)
|
||||
|
||||
set(Sources
|
||||
${CommonSources}
|
||||
${CompressSources}
|
||||
${DecompressSources}
|
||||
${DictBuilderSources})
|
||||
|
||||
file(GLOB PublicHeaders ${LIBRARY_DIR}/*.h)
|
||||
file(GLOB CommonHeaders ${LIBRARY_DIR}/common/*.h)
|
||||
file(GLOB CompressHeaders ${LIBRARY_DIR}/compress/*.h)
|
||||
file(GLOB DecompressHeaders ${LIBRARY_DIR}/decompress/*.h)
|
||||
file(GLOB DictBuilderHeaders ${LIBRARY_DIR}/dictBuilder/*.h)
|
||||
file(GLOB DeprecatedHeaders ${LIBRARY_DIR}/deprecated/*.h)
|
||||
|
||||
set(Headers
|
||||
${LIBRARY_DIR}/zstd.h
|
||||
${CommonHeaders}
|
||||
${CompressHeaders}
|
||||
${DecompressHeaders}
|
||||
${DictBuilderHeaders})
|
||||
set(Sources ${CommonSources})
|
||||
set(Headers ${PublicHeaders} ${CommonHeaders})
|
||||
if (ZSTD_BUILD_COMPRESSION)
|
||||
set(Sources ${Sources} ${CompressSources})
|
||||
set(Headers ${Headers} ${CompressHeaders})
|
||||
endif()
|
||||
if (ZSTD_BUILD_DECOMPRESSION)
|
||||
set(Sources ${Sources} ${DecompressSources})
|
||||
set(Headers ${Headers} ${DecompressHeaders})
|
||||
endif()
|
||||
if (ZSTD_BUILD_DICTBUILDER)
|
||||
set(Sources ${Sources} ${DictBuilderSources})
|
||||
set(Headers ${Headers} ${DictBuilderHeaders})
|
||||
endif()
|
||||
if (ZSTD_BUILD_DEPRECATED)
|
||||
set(Sources ${Sources} ${DeprecatedSources})
|
||||
set(Headers ${Headers} ${DeprecatedHeaders})
|
||||
endif()
|
||||
|
||||
if (ZSTD_LEGACY_SUPPORT)
|
||||
set(LIBRARY_LEGACY_DIR ${LIBRARY_DIR}/legacy)
|
||||
include_directories(${LIBRARY_LEGACY_DIR})
|
||||
|
||||
set(Sources ${Sources}
|
||||
${LIBRARY_LEGACY_DIR}/zstd_v01.c
|
||||
@@ -81,22 +106,38 @@ endif ()
|
||||
# Our assembly expects to be compiled by a C compiler, and is only enabled for
|
||||
# __GNUC__ compatible compilers. Otherwise all the ASM code is disabled by
|
||||
# macros.
|
||||
set_source_files_properties(${Sources} PROPERTIES LANGUAGE C)
|
||||
if(NOT CMAKE_ASM_COMPILER STREQUAL CMAKE_C_COMPILER)
|
||||
set_source_files_properties(${Sources} PROPERTIES LANGUAGE C)
|
||||
endif()
|
||||
|
||||
macro (add_definition target var)
|
||||
if (NOT ("${${var}}" STREQUAL ""))
|
||||
set_property(TARGET ${target} APPEND PROPERTY COMPILE_DEFINITIONS "${var}=__attribute__((visibility(\"${${var}}\")))")
|
||||
endif ()
|
||||
endmacro ()
|
||||
|
||||
# Define directories containing the library's public headers
|
||||
set(PUBLIC_INCLUDE_DIRS ${LIBRARY_DIR})
|
||||
|
||||
# Split project to static and shared libraries build
|
||||
set(library_targets)
|
||||
if (ZSTD_BUILD_SHARED)
|
||||
add_library(libzstd_shared SHARED ${Sources} ${Headers} ${PlatformDependResources})
|
||||
target_include_directories(libzstd_shared INTERFACE $<BUILD_INTERFACE:${PUBLIC_INCLUDE_DIRS}>)
|
||||
list(APPEND library_targets libzstd_shared)
|
||||
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 ()
|
||||
add_definition(libzstd_shared ZSTDLIB_VISIBLE)
|
||||
add_definition(libzstd_shared ZSTDERRORLIB_VISIBLE)
|
||||
add_definition(libzstd_shared ZDICTLIB_VISIBLE)
|
||||
endif ()
|
||||
if (ZSTD_BUILD_STATIC)
|
||||
add_library(libzstd_static STATIC ${Sources} ${Headers})
|
||||
target_include_directories(libzstd_static INTERFACE $<BUILD_INTERFACE:${PUBLIC_INCLUDE_DIRS}>)
|
||||
list(APPEND library_targets libzstd_static)
|
||||
if (ZSTD_MULTITHREAD_SUPPORT)
|
||||
set_property(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
|
||||
@@ -104,6 +145,41 @@ if (ZSTD_BUILD_STATIC)
|
||||
target_link_libraries(libzstd_static ${THREADS_LIBS})
|
||||
endif ()
|
||||
endif ()
|
||||
add_definition(libzstd_static ZSTDLIB_VISIBLE)
|
||||
add_definition(libzstd_static ZSTDERRORLIB_VISIBLE)
|
||||
add_definition(libzstd_static ZDICTLIB_VISIBLE)
|
||||
add_definition(libzstd_static ZSTDLIB_STATIC_API)
|
||||
add_definition(libzstd_static ZDICTLIB_STATIC_API)
|
||||
endif ()
|
||||
if (ZSTD_BUILD_SHARED AND NOT ZSTD_BUILD_STATIC)
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
message(WARNING "BUILD_SHARED_LIBS is OFF, but ZSTD_BUILD_SHARED is ON and ZSTD_BUILD_STATIC is OFF, which takes precedence, so libzstd is a shared library")
|
||||
endif ()
|
||||
add_library(libzstd INTERFACE)
|
||||
target_link_libraries(libzstd INTERFACE libzstd_shared)
|
||||
list(APPEND library_targets libzstd)
|
||||
endif ()
|
||||
if (ZSTD_BUILD_STATIC AND NOT ZSTD_BUILD_SHARED)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
message(WARNING "BUILD_SHARED_LIBS is ON, but ZSTD_BUILD_SHARED is OFF and ZSTD_BUILD_STATIC is ON, which takes precedence, is set so libzstd is a static library")
|
||||
endif ()
|
||||
add_library(libzstd INTERFACE)
|
||||
target_link_libraries(libzstd INTERFACE libzstd_static)
|
||||
list(APPEND library_targets libzstd)
|
||||
endif ()
|
||||
if (ZSTD_BUILD_SHARED AND ZSTD_BUILD_STATIC)
|
||||
# If both ZSTD_BUILD_SHARED and ZSTD_BUILD_STATIC are set, which is the
|
||||
# default, fallback to using BUILD_SHARED_LIBS to determine whether to
|
||||
# set libzstd to static or shared.
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_library(libzstd INTERFACE)
|
||||
target_link_libraries(libzstd INTERFACE libzstd_shared)
|
||||
list(APPEND library_targets libzstd)
|
||||
else ()
|
||||
add_library(libzstd INTERFACE)
|
||||
target_link_libraries(libzstd INTERFACE libzstd_static)
|
||||
list(APPEND library_targets libzstd)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Add specific compile definitions for MSVC project
|
||||
@@ -154,11 +230,7 @@ configure_file("${LIBRARY_DIR}/libzstd.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libzs
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libzstd.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
|
||||
# install target
|
||||
install(FILES
|
||||
"${LIBRARY_DIR}/zstd.h"
|
||||
"${LIBRARY_DIR}/zdict.h"
|
||||
"${LIBRARY_DIR}/zstd_errors.h"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
install(FILES ${PublicHeaders} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
install(TARGETS ${library_targets}
|
||||
EXPORT zstdExports
|
||||
|
||||
@@ -32,7 +32,12 @@ if (MSVC)
|
||||
set(PlatformDependResources ${MSVC_RESOURCE_DIR}/zstd.rc)
|
||||
endif ()
|
||||
|
||||
add_executable(zstd ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/fileio_asyncio.c ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/dibio.c ${PROGRAMS_DIR}/zstdcli_trace.c ${PlatformDependResources})
|
||||
file(GLOB ZSTD_PROGRAM_SRCS "${PROGRAMS_DIR}/*.c")
|
||||
if (MSVC AND ZSTD_PROGRAMS_LINK_SHARED)
|
||||
list(APPEND ZSTD_PROGRAM_SRCS ${LIBRARY_DIR}/common/pool.c ${LIBRARY_DIR}/common/threading.c)
|
||||
endif ()
|
||||
|
||||
add_executable(zstd ${ZSTD_PROGRAM_SRCS})
|
||||
target_link_libraries(zstd ${PROGRAMS_ZSTD_LINK_TARGET})
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||
target_link_libraries(zstd rt)
|
||||
@@ -75,7 +80,9 @@ if (UNIX)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/zstdless.1
|
||||
DESTINATION "${MAN_INSTALL_DIR}")
|
||||
|
||||
add_executable(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/fileio_asyncio.c)
|
||||
add_executable(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c
|
||||
${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c
|
||||
${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/fileio_asyncio.c)
|
||||
target_link_libraries(zstd-frugal ${PROGRAMS_ZSTD_LINK_TARGET})
|
||||
set_property(TARGET zstd-frugal APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_NOBENCH;ZSTD_NODICT;ZSTD_NOTRACE")
|
||||
endif ()
|
||||
|
||||
@@ -50,18 +50,18 @@ set(PROGRAMS_DIR ${ZSTD_SOURCE_DIR}/programs)
|
||||
set(TESTS_DIR ${ZSTD_SOURCE_DIR}/tests)
|
||||
include_directories(${TESTS_DIR} ${PROGRAMS_DIR} ${LIBRARY_DIR} ${LIBRARY_DIR}/common ${LIBRARY_DIR}/compress ${LIBRARY_DIR}/dictBuilder)
|
||||
|
||||
add_executable(datagen ${PROGRAMS_DIR}/datagen.c ${TESTS_DIR}/datagencli.c)
|
||||
add_executable(datagen ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/lorem.c ${TESTS_DIR}/loremOut.c ${TESTS_DIR}/datagencli.c)
|
||||
target_link_libraries(datagen libzstd_static)
|
||||
|
||||
#
|
||||
# fullbench
|
||||
#
|
||||
add_executable(fullbench ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${TESTS_DIR}/fullbench.c)
|
||||
add_executable(fullbench ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/lorem.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${TESTS_DIR}/fullbench.c)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(fullbench PRIVATE "-Wno-deprecated-declarations")
|
||||
endif()
|
||||
target_link_libraries(fullbench libzstd_static)
|
||||
add_test(NAME fullbench COMMAND fullbench ${ZSTD_FULLBENCH_FLAGS})
|
||||
add_test(NAME fullbench COMMAND "$<TARGET_FILE:fullbench>" ${ZSTD_FULLBENCH_FLAGS})
|
||||
|
||||
#
|
||||
# fuzzer
|
||||
@@ -73,7 +73,7 @@ endif()
|
||||
target_link_libraries(fuzzer libzstd_static)
|
||||
AddTestFlagsOption(ZSTD_FUZZER_FLAGS "$ENV{FUZZERTEST} $ENV{FUZZER_FLAGS}"
|
||||
"Semicolon-separated list of flags to pass to the fuzzer test (see `fuzzer -h` for usage)")
|
||||
add_test(NAME fuzzer COMMAND fuzzer ${ZSTD_FUZZER_FLAGS})
|
||||
add_test(NAME fuzzer COMMAND "$<TARGET_FILE:fuzzer>" ${ZSTD_FUZZER_FLAGS})
|
||||
# Disable the timeout since the run time is too long for the default timeout of
|
||||
# 1500 seconds and varies considerably between low-end and high-end CPUs.
|
||||
# set_tests_properties(fuzzer PROPERTIES TIMEOUT 0)
|
||||
@@ -88,7 +88,7 @@ endif()
|
||||
target_link_libraries(zstreamtest libzstd_static)
|
||||
AddTestFlagsOption(ZSTD_ZSTREAM_FLAGS "$ENV{ZSTREAM_TESTTIME} $ENV{FUZZER_FLAGS}"
|
||||
"Semicolon-separated list of flags to pass to the zstreamtest test (see `zstreamtest -h` for usage)")
|
||||
add_test(NAME zstreamtest COMMAND zstreamtest ${ZSTD_ZSTREAM_FLAGS})
|
||||
add_test(NAME zstreamtest COMMAND "$<TARGET_FILE:zstreamtest>" ${ZSTD_ZSTREAM_FLAGS})
|
||||
|
||||
#
|
||||
# playTests.sh
|
||||
@@ -110,7 +110,7 @@ endif()
|
||||
# Label the "Medium" set of tests (see TESTING.md)
|
||||
set_property(TEST fuzzer zstreamtest playTests APPEND PROPERTY LABELS Medium)
|
||||
|
||||
add_executable(paramgrill ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${TESTS_DIR}/paramgrill.c)
|
||||
add_executable(paramgrill ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/lorem.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${TESTS_DIR}/paramgrill.c)
|
||||
if (UNIX)
|
||||
target_link_libraries(paramgrill libzstd_static m) #m is math library
|
||||
else()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/zstdTargets.cmake")
|
||||
@@ -0,0 +1,10 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
if(@ZSTD_MULTITHREAD_SUPPORT@ AND "@UNIX@")
|
||||
find_dependency(Threads)
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/zstdTargets.cmake")
|
||||
|
||||
check_required_components("zstd")
|
||||
@@ -132,7 +132,7 @@ endif
|
||||
|
||||
subdir('lib')
|
||||
|
||||
if bin_programs
|
||||
if bin_programs or bin_tests
|
||||
subdir('programs')
|
||||
endif
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ zstd_programs_sources = [join_paths(zstd_rootdir, 'programs/zstdcli.c'),
|
||||
join_paths(zstd_rootdir, 'programs/benchfn.c'),
|
||||
join_paths(zstd_rootdir, 'programs/benchzstd.c'),
|
||||
join_paths(zstd_rootdir, 'programs/datagen.c'),
|
||||
join_paths(zstd_rootdir, 'programs/lorem.c'),
|
||||
join_paths(zstd_rootdir, 'programs/dibio.c'),
|
||||
join_paths(zstd_rootdir, 'programs/zstdcli_trace.c')]
|
||||
|
||||
@@ -72,7 +73,14 @@ zstd = executable('zstd',
|
||||
c_args: zstd_c_args,
|
||||
dependencies: zstd_deps,
|
||||
export_dynamic: export_dynamic_on_windows, # Since Meson 0.45.0
|
||||
install: true)
|
||||
build_by_default: bin_programs,
|
||||
install: bin_programs)
|
||||
|
||||
if not bin_programs
|
||||
# we generate rules to build the programs, but don't install anything
|
||||
# so do not continue to installing scripts and manpages
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
zstd_frugal_sources = [join_paths(zstd_rootdir, 'programs/zstdcli.c'),
|
||||
join_paths(zstd_rootdir, 'programs/timefn.c'),
|
||||
|
||||
@@ -29,6 +29,7 @@ DECODECORPUS_TESTTIME = '-T30'
|
||||
test_includes = [ include_directories(join_paths(zstd_rootdir, 'programs')) ]
|
||||
|
||||
testcommon_sources = [join_paths(zstd_rootdir, 'programs/datagen.c'),
|
||||
join_paths(zstd_rootdir, 'programs/lorem.c'),
|
||||
join_paths(zstd_rootdir, 'programs/util.c'),
|
||||
join_paths(zstd_rootdir, 'programs/timefn.c'),
|
||||
join_paths(zstd_rootdir, 'programs/benchfn.c'),
|
||||
@@ -43,7 +44,8 @@ testcommon_dep = declare_dependency(link_with: testcommon,
|
||||
dependencies: libzstd_deps,
|
||||
include_directories: libzstd_includes)
|
||||
|
||||
datagen_sources = [join_paths(zstd_rootdir, 'tests/datagencli.c')]
|
||||
datagen_sources = [join_paths(zstd_rootdir, 'tests/datagencli.c'),
|
||||
join_paths(zstd_rootdir, 'tests/loremOut.c')]
|
||||
datagen = executable('datagen',
|
||||
datagen_sources,
|
||||
c_args: [ '-DNDEBUG' ],
|
||||
@@ -162,7 +164,7 @@ if host_machine_os != os_windows
|
||||
playTests_sh,
|
||||
args: opt,
|
||||
env: ['ZSTD_BIN=' + zstd.full_path(), 'DATAGEN_BIN=./datagen'],
|
||||
depends: [datagen],
|
||||
depends: [datagen, zstd],
|
||||
suite: suite,
|
||||
workdir: meson.current_build_dir(),
|
||||
timeout: 2800) # Timeout should work on HDD drive
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Dockerfile
|
||||
# First image to build the binary
|
||||
FROM alpine as builder
|
||||
FROM alpine@sha256:69665d02cb32192e52e07644d76bc6f25abeb5410edc1c7a81a10ba3f0efb90a as builder
|
||||
|
||||
RUN apk --no-cache add make gcc libc-dev
|
||||
COPY . /src
|
||||
RUN mkdir /pkg && cd /src && make && make DESTDIR=/pkg install
|
||||
|
||||
# Second minimal image to only keep the built binary
|
||||
FROM alpine
|
||||
FROM alpine@sha256:69665d02cb32192e52e07644d76bc6f25abeb5410edc1c7a81a10ba3f0efb90a
|
||||
|
||||
# Copy the built files
|
||||
COPY --from=builder /pkg /
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
/*-****************************************
|
||||
* Compiler specifics
|
||||
******************************************/
|
||||
#undef MEM_STATIC /* may be already defined from common/compiler.h */
|
||||
#define MEM_STATIC static inline
|
||||
|
||||
/*-**************************************************************
|
||||
|
||||
@@ -24,9 +24,6 @@ EXPORT_SYMBOL_GPL(HUF_readStats_wksp);
|
||||
EXPORT_SYMBOL_GPL(ZSTD_isError);
|
||||
EXPORT_SYMBOL_GPL(ZSTD_getErrorName);
|
||||
EXPORT_SYMBOL_GPL(ZSTD_getErrorCode);
|
||||
EXPORT_SYMBOL_GPL(ZSTD_customMalloc);
|
||||
EXPORT_SYMBOL_GPL(ZSTD_customCalloc);
|
||||
EXPORT_SYMBOL_GPL(ZSTD_customFree);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("Zstd Common");
|
||||
|
||||
@@ -77,7 +77,7 @@ EXPORT_SYMBOL(zstd_init_dstream);
|
||||
|
||||
size_t zstd_reset_dstream(zstd_dstream *dstream)
|
||||
{
|
||||
return ZSTD_resetDStream(dstream);
|
||||
return ZSTD_DCtx_reset(dstream, ZSTD_reset_session_only);
|
||||
}
|
||||
EXPORT_SYMBOL(zstd_reset_dstream);
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ static uint64_t ZSTD_div64(uint64_t dividend, uint32_t divisor) {
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define assert(x) WARN_ON((x))
|
||||
#define assert(x) WARN_ON(!(x))
|
||||
|
||||
#endif /* ZSTD_DEPS_ASSERT */
|
||||
#endif /* ZSTD_DEPS_NEED_ASSERT */
|
||||
@@ -115,11 +115,7 @@ static uint64_t ZSTD_div64(uint64_t dividend, uint32_t divisor) {
|
||||
#ifndef ZSTD_DEPS_STDINT
|
||||
#define ZSTD_DEPS_STDINT
|
||||
|
||||
/*
|
||||
* The Linux Kernel doesn't provide intptr_t, only uintptr_t, which
|
||||
* is an unsigned long.
|
||||
*/
|
||||
typedef long intptr_t;
|
||||
/* intptr_t already provided by ZSTD_DEPS_COMMON */
|
||||
|
||||
#endif /* ZSTD_DEPS_STDINT */
|
||||
#endif /* ZSTD_DEPS_NEED_STDINT */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Standard variables for installation
|
||||
DESTDIR ?=
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR := $(DESTDIR)$(PREFIX)/bin
|
||||
BINDIR := $(PREFIX)/bin
|
||||
|
||||
ZSTDDIR = ../../lib
|
||||
PROGDIR = ../../programs
|
||||
@@ -37,10 +37,13 @@ CFLAGS += -Wno-deprecated-declarations
|
||||
PZSTD_INC = -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(PROGDIR) -I.
|
||||
GTEST_INC = -isystem googletest/googletest/include
|
||||
|
||||
# Set the minimum required by gtest
|
||||
PZSTD_CXX_STD := -std=c++14
|
||||
|
||||
PZSTD_CPPFLAGS = $(PZSTD_INC)
|
||||
PZSTD_CCXXFLAGS =
|
||||
PZSTD_CFLAGS = $(PZSTD_CCXXFLAGS)
|
||||
PZSTD_CXXFLAGS = $(PZSTD_CCXXFLAGS) -std=c++11
|
||||
PZSTD_CXXFLAGS = $(PZSTD_CCXXFLAGS) $(PZSTD_CXX_STD)
|
||||
PZSTD_LDFLAGS =
|
||||
EXTRA_FLAGS =
|
||||
ALL_CFLAGS = $(EXTRA_FLAGS) $(CPPFLAGS) $(PZSTD_CPPFLAGS) $(CFLAGS) $(PZSTD_CFLAGS)
|
||||
@@ -106,12 +109,12 @@ check:
|
||||
.PHONY: install
|
||||
install: PZSTD_CPPFLAGS += -DNDEBUG
|
||||
install: pzstd$(EXT)
|
||||
install -d -m 755 $(BINDIR)/
|
||||
install -m 755 pzstd$(EXT) $(BINDIR)/pzstd$(EXT)
|
||||
install -d -m 755 $(DESTDIR)$(BINDIR)/
|
||||
install -m 755 pzstd$(EXT) $(DESTDIR)$(BINDIR)/pzstd$(EXT)
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
$(RM) $(BINDIR)/pzstd$(EXT)
|
||||
$(RM) $(DESTDIR)$(BINDIR)/pzstd$(EXT)
|
||||
|
||||
# Targets for many different builds
|
||||
.PHONY: all
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# Zstandard Seekable Format
|
||||
|
||||
The seekable format splits compressed data into a series of independent "frames",
|
||||
each compressed individually,
|
||||
so that decompression of a section in the middle of an archive
|
||||
only requires zstd to decompress at most a frame's worth of extra data,
|
||||
instead of the entire archive.
|
||||
|
||||
The frames are appended, so that the decompression of the entire payload
|
||||
still regenerates the original content, using any compliant zstd decoder.
|
||||
|
||||
On top of that, the seekable format generates a jump table,
|
||||
which makes it possible to jump directly to the position of the relevant frame
|
||||
when requesting only a segment of the data.
|
||||
The jump table is simply ignored by zstd decoders unaware of the seekable format.
|
||||
|
||||
The format is delivered with an API to create seekable archives
|
||||
and to retrieve arbitrary segments inside the archive.
|
||||
|
||||
### Maximum Frame Size parameter
|
||||
|
||||
When creating a seekable archive, the main parameter is the maximum frame size.
|
||||
|
||||
At compression time, user can manually select the boundaries between segments,
|
||||
but they don't have to: long segments will be automatically split
|
||||
when larger than selected maximum frame size.
|
||||
|
||||
Small frame sizes reduce decompression cost when requesting small segments,
|
||||
because the decoder will nonetheless have to decompress an entire frame
|
||||
to recover just a single byte from it.
|
||||
|
||||
A good rule of thumb is to select a maximum frame size roughly equivalent
|
||||
to the access pattern when it's known.
|
||||
For example, if the application tends to request 4KB blocks,
|
||||
then it's a good idea to set a maximum frame size in the vicinity of 4 KB.
|
||||
|
||||
But small frame sizes also reduce compression ratio,
|
||||
and increase the cost for the jump table,
|
||||
so there is a balance to find.
|
||||
|
||||
In general, try to avoid really tiny frame sizes (<1 KB),
|
||||
which would have a large negative impact on compression ratio.
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "pool.h" // use zstd thread pool for demo
|
||||
|
||||
#include "zstd_seekable.h"
|
||||
#include "../zstd_seekable.h"
|
||||
|
||||
static void* malloc_orDie(size_t size)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
#include <zstd.h> // presumes zstd library is installed
|
||||
#include <zstd_errors.h>
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
# define SLEEP(x) Sleep(x)
|
||||
#else
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "pool.h" // use zstd thread pool for demo
|
||||
|
||||
#include "zstd_seekable.h"
|
||||
#include "../zstd_seekable.h"
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
#include <zstd.h> // presumes zstd library is installed
|
||||
|
||||
#include "zstd_seekable.h"
|
||||
#include "../zstd_seekable.h"
|
||||
|
||||
static void* malloc_orDie(size_t size)
|
||||
{
|
||||
@@ -112,20 +112,23 @@ static char* createOutFilename_orDie(const char* filename)
|
||||
return (char*)outSpace;
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
#define CLEVEL_DEFAULT 5
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
const char* const exeName = argv[0];
|
||||
if (argc!=3) {
|
||||
printf("wrong arguments\n");
|
||||
printf("usage:\n");
|
||||
printf("%s FILE FRAME_SIZE\n", exeName);
|
||||
if (argc<3 || argc>4) {
|
||||
printf("wrong arguments \n");
|
||||
printf("usage: \n");
|
||||
printf("%s FILE FRAME_SIZE [LEVEL] \n", exeName);
|
||||
return 1;
|
||||
}
|
||||
|
||||
{ const char* const inFileName = argv[1];
|
||||
unsigned const frameSize = (unsigned)atoi(argv[2]);
|
||||
int const cLevel = (argc==4) ? atoi(argv[3]) : CLEVEL_DEFAULT;
|
||||
|
||||
char* const outFileName = createOutFilename_orDie(inFileName);
|
||||
compressFile_orDie(inFileName, outFileName, 5, frameSize);
|
||||
compressFile_orDie(inFileName, outFileName, cLevel, frameSize);
|
||||
free(outFileName);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <zstd.h> // presumes zstd library is installed
|
||||
#include <zstd_errors.h>
|
||||
|
||||
#include "zstd_seekable.h"
|
||||
#include "../zstd_seekable.h"
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
@@ -3,8 +3,55 @@
|
||||
#include <stdlib.h> // malloc
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "zstd_seekable.h"
|
||||
#include "../zstd_seekable.h"
|
||||
|
||||
|
||||
/* ZSTD_seekable_customFile implementation that reads/seeks a buffer while keeping track of total bytes read */
|
||||
typedef struct {
|
||||
const void *ptr;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
size_t totalRead;
|
||||
} buffWrapperWithTotal_t;
|
||||
|
||||
static int readBuffWithTotal(void* opaque, void* buffer, size_t n)
|
||||
{
|
||||
buffWrapperWithTotal_t* const buff = (buffWrapperWithTotal_t*)opaque;
|
||||
assert(buff != NULL);
|
||||
if (buff->pos + n > buff->size) return -1;
|
||||
memcpy(buffer, (const char*)buff->ptr + buff->pos, n);
|
||||
buff->pos += n;
|
||||
buff->totalRead += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int seekBuffWithTotal(void* opaque, long long offset, int origin)
|
||||
{
|
||||
buffWrapperWithTotal_t* const buff = (buffWrapperWithTotal_t*) opaque;
|
||||
unsigned long long newOffset;
|
||||
assert(buff != NULL);
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
assert(offset >= 0);
|
||||
newOffset = (unsigned long long)offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
newOffset = (unsigned long long)((long long)buff->pos + offset);
|
||||
break;
|
||||
case SEEK_END:
|
||||
newOffset = (unsigned long long)((long long)buff->size + offset);
|
||||
break;
|
||||
default:
|
||||
assert(0); /* not possible */
|
||||
}
|
||||
if (newOffset > buff->size) {
|
||||
return -1;
|
||||
}
|
||||
buff->pos = newOffset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Basic unit tests for zstd seekable format */
|
||||
int main(int argc, const char** argv)
|
||||
@@ -220,6 +267,92 @@ int main(int argc, const char** argv)
|
||||
}
|
||||
printf("Success!\n");
|
||||
|
||||
|
||||
printf("Test %u - multiple decompress calls: ", testNb++);
|
||||
{ char const inBuffer[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt";
|
||||
size_t const inSize = sizeof(inBuffer);
|
||||
|
||||
size_t const seekCapacity = 5000;
|
||||
void* const seekBuffer = malloc(seekCapacity);
|
||||
assert(seekBuffer != NULL);
|
||||
size_t seekSize;
|
||||
|
||||
size_t const outCapacity = inSize;
|
||||
char* const outBuffer = malloc(outCapacity);
|
||||
assert(outBuffer != NULL);
|
||||
|
||||
ZSTD_seekable_CStream* const zscs = ZSTD_seekable_createCStream();
|
||||
assert(zscs != NULL);
|
||||
|
||||
/* compress test data with a small frame size to ensure multiple frames in the output */
|
||||
unsigned const maxFrameSize = 40;
|
||||
{ size_t const initStatus = ZSTD_seekable_initCStream(zscs, 9, 0 /* checksumFlag */, maxFrameSize);
|
||||
assert(!ZSTD_isError(initStatus));
|
||||
}
|
||||
|
||||
{ ZSTD_outBuffer outb = { .dst=seekBuffer, .pos=0, .size=seekCapacity };
|
||||
ZSTD_inBuffer inb = { .src=inBuffer, .pos=0, .size=inSize };
|
||||
|
||||
while (inb.pos < inb.size) {
|
||||
size_t const cStatus = ZSTD_seekable_compressStream(zscs, &outb, &inb);
|
||||
assert(!ZSTD_isError(cStatus));
|
||||
}
|
||||
|
||||
size_t const endStatus = ZSTD_seekable_endStream(zscs, &outb);
|
||||
assert(!ZSTD_isError(endStatus));
|
||||
seekSize = outb.pos;
|
||||
}
|
||||
|
||||
ZSTD_seekable* const stream = ZSTD_seekable_create();
|
||||
assert(stream != NULL);
|
||||
buffWrapperWithTotal_t buffWrapper = {seekBuffer, seekSize, 0, 0};
|
||||
{ ZSTD_seekable_customFile srcFile = {&buffWrapper, &readBuffWithTotal, &seekBuffWithTotal};
|
||||
size_t const initStatus = ZSTD_seekable_initAdvanced(stream, srcFile);
|
||||
assert(!ZSTD_isError(initStatus)); }
|
||||
|
||||
/* Perform a series of small reads and seeks (repeatedly read 1 byte and skip 1 byte)
|
||||
and check that we didn't reread input data unnecessarily */
|
||||
size_t pos;
|
||||
for (pos = 0; pos < inSize; pos += 2) {
|
||||
size_t const decStatus = ZSTD_seekable_decompress(stream, outBuffer, 1, pos);
|
||||
if (decStatus != 1 || outBuffer[0] != inBuffer[pos]) {
|
||||
goto _test_error;
|
||||
}
|
||||
}
|
||||
if (buffWrapper.totalRead > seekSize) {
|
||||
/* We read more than the compressed size, meaning there were some rereads.
|
||||
This is unneeded because we only seeked forward. */
|
||||
printf("Too much data read: %zu read, with compressed size %zu\n", buffWrapper.totalRead, seekSize);
|
||||
goto _test_error;
|
||||
}
|
||||
|
||||
/* Perform some reads and seeks to ensure correctness */
|
||||
struct {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
} const tests[] = { /* Assume the frame size is 40 */
|
||||
{20, 40}, /* read partial data from two frames */
|
||||
{60, 10}, /* continue reading from the same offset */
|
||||
{50, 20}, /* seek backward within the same frame */
|
||||
{10, 10}, /* seek backward to a different frame */
|
||||
{25, 10}, /* seek forward within the same frame */
|
||||
{60, 10}, /* seek forward to a different frame */
|
||||
};
|
||||
size_t idx;
|
||||
for (idx = 0; idx < sizeof(tests) / sizeof(tests[0]); idx++) {
|
||||
size_t const decStatus = ZSTD_seekable_decompress(stream, outBuffer, tests[idx].size, tests[idx].offset);
|
||||
if (decStatus != tests[idx].size || memcmp(outBuffer, inBuffer + tests[idx].offset, tests[idx].size) != 0) {
|
||||
goto _test_error;
|
||||
}
|
||||
}
|
||||
|
||||
free(seekBuffer);
|
||||
free(outBuffer);
|
||||
ZSTD_seekable_freeCStream(zscs);
|
||||
ZSTD_seekable_free(stream);
|
||||
}
|
||||
printf("Success!\n");
|
||||
|
||||
/* TODO: Add more tests */
|
||||
printf("Finished tests\n");
|
||||
return 0;
|
||||
|
||||
@@ -15,8 +15,8 @@ extern "C" {
|
||||
|
||||
#define ZSTD_SEEKABLE_MAXFRAMES 0x8000000U
|
||||
|
||||
/* Limit the maximum size to avoid any potential issues storing the compressed size */
|
||||
#define ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE 0x80000000U
|
||||
/* Limit maximum size to avoid potential issues storing the compressed size */
|
||||
#define ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE 0x40000000U
|
||||
|
||||
/*-****************************************************************************
|
||||
* Seekable Format
|
||||
@@ -48,10 +48,19 @@ typedef struct ZSTD_seekTable_s ZSTD_seekTable;
|
||||
*
|
||||
* Use ZSTD_seekable_initCStream() to initialize a ZSTD_seekable_CStream object
|
||||
* for a new compression operation.
|
||||
* `maxFrameSize` indicates the size at which to automatically start a new
|
||||
* seekable frame. `maxFrameSize == 0` implies the default maximum size.
|
||||
* `checksumFlag` indicates whether or not the seek table should include frame
|
||||
* checksums on the uncompressed data for verification.
|
||||
* - `maxFrameSize` indicates the size at which to automatically start a new
|
||||
* seekable frame.
|
||||
* `maxFrameSize == 0` implies the default maximum size.
|
||||
* Smaller frame sizes allow faster decompression of small segments,
|
||||
* since retrieving a single byte requires decompression of
|
||||
* the full frame where the byte belongs.
|
||||
* In general, size the frames to roughly correspond to
|
||||
* the access granularity (when it's known).
|
||||
* But small sizes also reduce compression ratio.
|
||||
* Avoid really tiny frame sizes (< 1 KB),
|
||||
* that would hurt compression ratio considerably.
|
||||
* - `checksumFlag` indicates whether or not the seek table should include frame
|
||||
* checksums on the uncompressed data for verification.
|
||||
* @return : a size hint for input to provide for compression, or an error code
|
||||
* checkable with ZSTD_isError()
|
||||
*
|
||||
|
||||
@@ -230,6 +230,8 @@ size_t ZSTD_seekable_compressStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer*
|
||||
const BYTE* const inBase = (const BYTE*) input->src + input->pos;
|
||||
size_t inLen = input->size - input->pos;
|
||||
|
||||
assert(zcs->maxFrameSize < INT_MAX);
|
||||
ZSTD_CCtx_setParameter(zcs->cstream, ZSTD_c_srcSizeHint, (int)zcs->maxFrameSize);
|
||||
inLen = MIN(inLen, (size_t)(zcs->maxFrameSize - zcs->frameDSize));
|
||||
|
||||
/* if we haven't finished flushing the last frame, don't start writing a new one */
|
||||
|
||||
@@ -493,7 +493,7 @@ size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsign
|
||||
size_t srcBytesRead = 0;
|
||||
do {
|
||||
/* check if we can continue from a previous decompress job */
|
||||
if (targetFrame != zs->curFrame || offset != zs->decompressedOffset) {
|
||||
if (targetFrame != zs->curFrame || offset < zs->decompressedOffset) {
|
||||
zs->decompressedOffset = zs->seekTable.entries[targetFrame].dOffset;
|
||||
zs->curFrame = targetFrame;
|
||||
|
||||
|
||||
@@ -6,12 +6,53 @@ Each entry will contain:
|
||||
1. The last affected decompressor versions.
|
||||
2. The decompressor components affected.
|
||||
2. Whether the compressed frame could ever be produced by the reference compressor.
|
||||
3. An example frame.
|
||||
3. An example frame (hexadecimal string when it can be short enough, link to golden file otherwise)
|
||||
4. A description of the bug.
|
||||
|
||||
The document is in reverse chronological order, with the bugs that affect the most recent zstd decompressor versions listed first.
|
||||
|
||||
|
||||
No sequence using the 2-bytes format
|
||||
------------------------------------------------
|
||||
|
||||
**Last affected version**: v1.5.5
|
||||
|
||||
**Affected decompressor component(s)**: Library & CLI
|
||||
|
||||
**Produced by the reference compressor**: No
|
||||
|
||||
**Example Frame**: see zstd/tests/golden-decompression/zeroSeq_2B.zst
|
||||
|
||||
The zstd decoder incorrectly expects FSE tables when there are 0 sequences present in the block
|
||||
if the value 0 is encoded using the 2-bytes format.
|
||||
Instead, it should immediately end the sequence section, and move on to next block.
|
||||
|
||||
This situation was never generated by the reference compressor,
|
||||
because representing 0 sequences with the 2-bytes format is inefficient
|
||||
(the 1-byte format is always used in this case).
|
||||
|
||||
|
||||
Compressed block with a size of exactly 128 KB
|
||||
------------------------------------------------
|
||||
|
||||
**Last affected version**: v1.5.2
|
||||
|
||||
**Affected decompressor component(s)**: Library & CLI
|
||||
|
||||
**Produced by the reference compressor**: No
|
||||
|
||||
**Example Frame**: see zstd/tests/golden-decompression/block-128k.zst
|
||||
|
||||
The zstd decoder incorrectly rejected blocks of type `Compressed_Block` when their size was exactly 128 KB.
|
||||
Note that `128 KB - 1` was accepted, and `128 KB + 1` is forbidden by the spec.
|
||||
|
||||
This type of block was never generated by the reference compressor.
|
||||
|
||||
These blocks used to be disallowed by the spec up until spec version 0.3.2 when the restriction was lifted by [PR#1689](https://github.com/facebook/zstd/pull/1689).
|
||||
|
||||
> 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 block with 0 literals and 0 sequences
|
||||
------------------------------------------------
|
||||
|
||||
@@ -31,6 +72,7 @@ Additionally, these blocks were disallowed by the spec up until spec version 0.3
|
||||
|
||||
> 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).
|
||||
|
||||
|
||||
First block is RLE block
|
||||
------------------------
|
||||
|
||||
@@ -52,6 +94,7 @@ block.
|
||||
|
||||
https://github.com/facebook/zstd/blob/8814aa5bfa74f05a86e55e9d508da177a893ceeb/lib/compress/zstd_compress.c#L3527-L3535
|
||||
|
||||
|
||||
Tiny FSE Table & Block
|
||||
----------------------
|
||||
|
||||
@@ -82,3 +125,24 @@ The total `Block_Content` is `5` bytes, and `Last_Table_Offset` is `2`.
|
||||
See the compressor workaround code:
|
||||
|
||||
https://github.com/facebook/zstd/blob/8814aa5bfa74f05a86e55e9d508da177a893ceeb/lib/compress/zstd_compress.c#L2667-L2682
|
||||
|
||||
Magicless format
|
||||
----------------------
|
||||
|
||||
**Last affected version**: v1.5.5
|
||||
|
||||
**Affected decompressor component(s)**: Library
|
||||
|
||||
**Produced by the reference compressor**: Yes (example: https://gist.github.com/embg/9940726094f4cf2cef162cffe9319232)
|
||||
|
||||
**Example Frame**: `27 b5 2f fd 00 03 19 00 00 66 6f 6f 3f ba c4 59`
|
||||
|
||||
v1.5.6 fixes several bugs in which the magicless-format decoder rejects valid frames.
|
||||
These include but are not limited to:
|
||||
* Valid frames that happen to begin with a legacy magic number (little-endian)
|
||||
* Valid frames that happen to begin with a skippable magic number (little-endian)
|
||||
|
||||
If you are affected by this issue and cannot update to v1.5.6 or later, there is a
|
||||
workaround to recover affected data. Simply prepend the ZSTD magic number
|
||||
`0xFD2FB528` (little-endian) to your data and decompress using the standard-format
|
||||
decoder.
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
Decompressor Permissiveness to Invalid Data
|
||||
===========================================
|
||||
|
||||
This document describes the behavior of the reference decompressor in cases
|
||||
where it accepts formally invalid data instead of reporting an error.
|
||||
|
||||
While the reference decompressor *must* decode any compliant frame following
|
||||
the specification, its ability to detect erroneous data is on a best effort
|
||||
basis: the decoder may accept input data that would be formally invalid,
|
||||
when it causes no risk to the decoder, and which detection would cost too much
|
||||
complexity or speed regression.
|
||||
|
||||
In practice, the vast majority of invalid data are detected, if only because
|
||||
many corruption events are dangerous for the decoder process (such as
|
||||
requesting an out-of-bound memory access) and many more are easy to check.
|
||||
|
||||
This document lists a few known cases where invalid data was formerly accepted
|
||||
by the decoder, and what has changed since.
|
||||
|
||||
|
||||
Offset == 0
|
||||
-----------
|
||||
|
||||
**Last affected version**: v1.5.5
|
||||
|
||||
**Produced by the reference compressor**: No
|
||||
|
||||
**Example Frame**: `28b5 2ffd 0000 4500 0008 0002 002f 430b ae`
|
||||
|
||||
If a sequence is decoded with `literals_length = 0` and `offset_value = 3`
|
||||
while `Repeated_Offset_1 = 1`, the computed offset will be `0`, which is
|
||||
invalid.
|
||||
|
||||
The reference decompressor up to v1.5.5 processes this case as if the computed
|
||||
offset was `1`, including inserting `1` into the repeated offset list.
|
||||
This prevents the output buffer from remaining uninitialized, thus denying a
|
||||
potential attack vector from an untrusted source.
|
||||
However, in the rare case where this scenario would be the outcome of a
|
||||
transmission or storage error, the decoder relies on the checksum to detect
|
||||
the error.
|
||||
|
||||
In newer versions, this case is always detected and reported as a corruption error.
|
||||
|
||||
|
||||
Non-zeroes reserved bits
|
||||
------------------------
|
||||
|
||||
**Last affected version**: v1.5.5
|
||||
|
||||
**Produced by the reference compressor**: No
|
||||
|
||||
The Sequences section of each block has a header, and one of its elements is a
|
||||
byte, which describes the compression mode of each symbol.
|
||||
This byte contains 2 reserved bits which must be set to zero.
|
||||
|
||||
The reference decompressor up to v1.5.5 just ignores these 2 bits.
|
||||
This behavior has no consequence for the rest of the frame decoding process.
|
||||
|
||||
In newer versions, the 2 reserved bits are actively checked for value zero,
|
||||
and the decoder reports a corruption error if they are not.
|
||||
@@ -997,7 +997,8 @@ static void decompress_sequences(frame_context_t *const ctx,
|
||||
const size_t num_sequences);
|
||||
static sequence_command_t decode_sequence(sequence_states_t *const state,
|
||||
const u8 *const src,
|
||||
i64 *const offset);
|
||||
i64 *const offset,
|
||||
int lastSequence);
|
||||
static void decode_seq_table(FSE_dtable *const table, istream_t *const in,
|
||||
const seq_part_t type, const seq_mode_t mode);
|
||||
|
||||
@@ -1017,12 +1018,7 @@ static size_t decode_sequences(frame_context_t *const ctx, istream_t *in,
|
||||
// This is a variable size field using between 1 and 3 bytes. Let's call its
|
||||
// first byte byte0."
|
||||
u8 header = IO_read_bits(in, 8);
|
||||
if (header == 0) {
|
||||
// "There are no sequences. The sequence section stops there.
|
||||
// Regenerated content is defined entirely by literals section."
|
||||
*sequences = NULL;
|
||||
return 0;
|
||||
} else if (header < 128) {
|
||||
if (header < 128) {
|
||||
// "Number_of_Sequences = byte0 . Uses 1 byte."
|
||||
num_sequences = header;
|
||||
} else if (header < 255) {
|
||||
@@ -1033,6 +1029,12 @@ static size_t decode_sequences(frame_context_t *const ctx, istream_t *in,
|
||||
num_sequences = IO_read_bits(in, 16) + 0x7F00;
|
||||
}
|
||||
|
||||
if (num_sequences == 0) {
|
||||
// "There are no sequences. The sequence section stops there."
|
||||
*sequences = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sequences = malloc(num_sequences * sizeof(sequence_command_t));
|
||||
if (!*sequences) {
|
||||
BAD_ALLOC();
|
||||
@@ -1114,7 +1116,7 @@ static void decompress_sequences(frame_context_t *const ctx, istream_t *in,
|
||||
|
||||
for (size_t i = 0; i < num_sequences; i++) {
|
||||
// Decode sequences one by one
|
||||
sequences[i] = decode_sequence(&states, src, &bit_offset);
|
||||
sequences[i] = decode_sequence(&states, src, &bit_offset, i==num_sequences-1);
|
||||
}
|
||||
|
||||
if (bit_offset != 0) {
|
||||
@@ -1125,7 +1127,8 @@ static void decompress_sequences(frame_context_t *const ctx, istream_t *in,
|
||||
// Decode a single sequence and update the state
|
||||
static sequence_command_t decode_sequence(sequence_states_t *const states,
|
||||
const u8 *const src,
|
||||
i64 *const offset) {
|
||||
i64 *const offset,
|
||||
int lastSequence) {
|
||||
// "Each symbol is a code in its own context, which specifies Baseline and
|
||||
// Number_of_Bits to add. Codes are FSE compressed, and interleaved with raw
|
||||
// additional bits in the same bitstream."
|
||||
@@ -1160,7 +1163,7 @@ static sequence_command_t decode_sequence(sequence_states_t *const states,
|
||||
// Literals_Length_State is updated, followed by Match_Length_State, and
|
||||
// then Offset_State."
|
||||
// If the stream is complete don't read bits to update state
|
||||
if (*offset != 0) {
|
||||
if (!lastSequence) {
|
||||
FSE_update_state(&states->ll_table, &states->ll_state, src, offset);
|
||||
FSE_update_state(&states->ml_table, &states->ml_state, src, offset);
|
||||
FSE_update_state(&states->of_table, &states->of_state, src, offset);
|
||||
@@ -1210,7 +1213,7 @@ static void decode_seq_table(FSE_dtable *const table, istream_t *const in,
|
||||
break;
|
||||
}
|
||||
case seq_repeat:
|
||||
// "Repeat_Mode : re-use distribution table from previous compressed
|
||||
// "Repeat_Mode : reuse distribution table from previous compressed
|
||||
// block."
|
||||
// Nothing to do here, table will be unchanged
|
||||
if (!table->symbols) {
|
||||
@@ -1399,7 +1402,7 @@ size_t ZSTD_get_decompressed_size(const void *src, const size_t src_len) {
|
||||
/******* END OUTPUT SIZE COUNTING *********************************************/
|
||||
|
||||
/******* DICTIONARY PARSING ***************************************************/
|
||||
dictionary_t* create_dictionary() {
|
||||
dictionary_t* create_dictionary(void) {
|
||||
dictionary_t* const dict = calloc(1, sizeof(dictionary_t));
|
||||
if (!dict) {
|
||||
BAD_ALLOC();
|
||||
|
||||
@@ -16,7 +16,7 @@ Distribution of this document is unlimited.
|
||||
|
||||
### Version
|
||||
|
||||
0.3.7 (2020-12-09)
|
||||
0.4.0 (2023-06-05)
|
||||
|
||||
|
||||
Introduction
|
||||
@@ -470,6 +470,7 @@ This field uses 2 lowest bits of first byte, describing 4 different block types
|
||||
repeated `Regenerated_Size` times.
|
||||
- `Compressed_Literals_Block` - This is a standard Huffman-compressed block,
|
||||
starting with a Huffman tree description.
|
||||
In this mode, there are at least 2 different literals represented in the Huffman tree description.
|
||||
See details below.
|
||||
- `Treeless_Literals_Block` - This is a Huffman-compressed block,
|
||||
using Huffman tree _from previous Huffman-compressed literals block_.
|
||||
@@ -533,15 +534,20 @@ __`Size_Format` for `Compressed_Literals_Block` and `Treeless_Literals_Block`__
|
||||
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.
|
||||
Note 2: `Compressed_Size` can never be `==0`.
|
||||
Even in single-stream scenario, assuming an empty content, it must be `>=1`,
|
||||
since it contains at least the final end bit flag.
|
||||
In 4-streams scenario, a valid `Compressed_Size` is necessarily `>= 10`
|
||||
(6 bytes for the jump table, + 4x1 bytes for the 4 streams).
|
||||
|
||||
4 streams is superior to 1 stream in decompression speed,
|
||||
4 streams is faster than 1 stream in decompression speed,
|
||||
by exploiting instruction level parallelism.
|
||||
But it's also more expensive,
|
||||
costing on average ~7.3 bytes more than the 1 stream mode, mostly from the jump table.
|
||||
|
||||
In general, use the 4 streams mode when there are more literals to decode,
|
||||
to favor higher decompression speeds.
|
||||
Beyond 1KB, the 4 streams mode is compulsory anyway.
|
||||
Note that beyond >1KB of literals, the 4 streams mode is compulsory.
|
||||
|
||||
Note that a minimum of 6 bytes is required for the 4 streams mode.
|
||||
That's a technical minimum, but it's not recommended to employ the 4 streams mode
|
||||
@@ -566,6 +572,7 @@ or from a dictionary.
|
||||
|
||||
### `Huffman_Tree_Description`
|
||||
This section is only present when `Literals_Block_Type` type is `Compressed_Literals_Block` (`2`).
|
||||
The tree describes the weights of all literals symbols that can be present in the literals block, at least 2 and up to 256.
|
||||
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.
|
||||
@@ -575,10 +582,10 @@ it must be used to determine where streams begin.
|
||||
### 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.
|
||||
Reminder : Huffman compressed data consists of either 1 or 4 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
|
||||
remaining portion of the literals block, encoded as described in
|
||||
[Huffman-Coded Streams](#huffman-coded-streams).
|
||||
|
||||
If there are four streams, `Literals_Section_Header` only provided
|
||||
@@ -589,17 +596,18 @@ 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 in the Jump Table.
|
||||
Jump Table is 6 bytes long, and consist of three 2-byte __little-endian__ fields,
|
||||
Jump Table is 6 bytes long, and consists 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` is computed from `Total_Streams_Size` minus sizes of other streams:
|
||||
|
||||
`Stream4_Size = Total_Streams_Size - 6 - Stream1_Size - Stream2_Size - Stream3_Size`.
|
||||
|
||||
Note: if `Stream1_Size + Stream2_Size + Stream3_Size > Total_Streams_Size`,
|
||||
`Stream4_Size` is necessarily `>= 1`. Therefore,
|
||||
if `Total_Streams_Size < Stream1_Size + Stream2_Size + Stream3_Size + 6 + 1`,
|
||||
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)
|
||||
as described in [Huffman-Coded Streams](#huffman-coded-streams)
|
||||
|
||||
|
||||
Sequences Section
|
||||
@@ -642,13 +650,15 @@ __`Number_of_Sequences`__
|
||||
|
||||
This is a variable size field using between 1 and 3 bytes.
|
||||
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.
|
||||
- `if (byte0 < 255)` : `Number_of_Sequences = ((byte0 - 0x80) << 8) + byte1`. Uses 2 bytes.
|
||||
Note that the 2 bytes format fully overlaps the 1 byte format.
|
||||
- `if (byte0 == 255)`: `Number_of_Sequences = byte1 + (byte2<<8) + 0x7F00`. Uses 3 bytes.
|
||||
|
||||
`if (Number_of_Sequences == 0)` : there are no sequences.
|
||||
The sequence section stops immediately,
|
||||
FSE tables used in `Repeat_Mode` aren't updated.
|
||||
Block's decompressed content is defined solely by the Literals Section content.
|
||||
|
||||
__Symbol compression modes__
|
||||
|
||||
@@ -919,7 +929,10 @@ There is an exception though, when current sequence's `literals_length = 0`.
|
||||
In this case, repeated offsets are shifted by one,
|
||||
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`.
|
||||
and an `offset_value` of 3 means `Repeated_Offset1 - 1`.
|
||||
|
||||
In the final case, if `Repeated_Offset1 - 1` evaluates to 0, then the
|
||||
data is considered corrupted.
|
||||
|
||||
For the first block, the starting offset history is populated with following values :
|
||||
`Repeated_Offset1`=1, `Repeated_Offset2`=4, `Repeated_Offset3`=8,
|
||||
@@ -1073,7 +1086,8 @@ It depends on :
|
||||
Presuming an `Accuracy_Log` of 8,
|
||||
and presuming 100 probabilities points have already been distributed,
|
||||
the decoder may read any value from `0` to `256 - 100 + 1 == 157` (inclusive).
|
||||
Therefore, it must read `log2sup(157) == 8` bits.
|
||||
Therefore, it may read up to `log2sup(157) == 8` bits, where `log2sup(N)`
|
||||
is the smallest integer `T` that satisfies `(1 << T) > N`.
|
||||
|
||||
- Value decoded : small values use 1 less bit :
|
||||
__example__ :
|
||||
@@ -1113,6 +1127,9 @@ When last symbol reaches cumulated total of `1 << Accuracy_Log`,
|
||||
decoding is complete.
|
||||
If the last symbol makes cumulated total go above `1 << Accuracy_Log`,
|
||||
distribution is considered corrupted.
|
||||
If this process results in a non-zero probability for a value outside of the
|
||||
valid range of values that the FSE table is defined for, even if that value is
|
||||
not used, then the data is considered corrupted.
|
||||
|
||||
Then the decoder can tell how many bytes were used in this process,
|
||||
and how many symbols are present.
|
||||
@@ -1176,9 +1193,9 @@ Baseline is assigned starting from the higher states using fewer bits,
|
||||
increasing at each state, then resuming at the first state,
|
||||
each state takes its allocated width from Baseline.
|
||||
|
||||
| state value | 1 | 39 | 77 | 84 | 122 |
|
||||
| state order | 0 | 1 | 2 | 3 | 4 |
|
||||
| ---------------- | ----- | ----- | ------ | ---- | ------ |
|
||||
| state value | 1 | 39 | 77 | 84 | 122 |
|
||||
| width | 32 | 32 | 32 | 16 | 16 |
|
||||
| `Number_of_Bits` | 5 | 5 | 5 | 4 | 4 |
|
||||
| range number | 2 | 4 | 6 | 0 | 1 |
|
||||
@@ -1197,7 +1214,7 @@ Huffman Coding
|
||||
--------------
|
||||
Zstandard Huffman-coded streams are read backwards,
|
||||
similar to the FSE bitstreams.
|
||||
Therefore, to find the start of the bitstream, it is therefore to
|
||||
Therefore, to find the start of the bitstream, it is required to
|
||||
know the offset of the last byte of the Huffman-coded stream.
|
||||
|
||||
After writing the last bit containing information, the compressor
|
||||
@@ -1239,9 +1256,17 @@ Transformation from `Weight` to `Number_of_Bits` follows this formula :
|
||||
```
|
||||
Number_of_Bits = Weight ? (Max_Number_of_Bits + 1 - Weight) : 0
|
||||
```
|
||||
The last symbol's `Weight` is deduced from previously decoded ones,
|
||||
by completing to the nearest power of 2.
|
||||
This power of 2 gives `Max_Number_of_Bits`, the depth of the current tree.
|
||||
When a literal value is not present, it receives a `Weight` of 0.
|
||||
The least frequent symbol receives a `Weight` of 1.
|
||||
If no literal has a `Weight` of 1, then the data is considered corrupted.
|
||||
If there are not at least two literals with non-zero `Weight`, then the data
|
||||
is considered corrupted.
|
||||
The most frequent symbol receives a `Weight` anywhere between 1 and 11 (max).
|
||||
The last symbol's `Weight` is deduced from previously retrieved Weights,
|
||||
by completing to the nearest power of 2. It's necessarily non 0.
|
||||
If it's not possible to reach a clean power of 2 with a single `Weight` value,
|
||||
the Huffman Tree Description is considered invalid.
|
||||
This final power of 2 gives `Max_Number_of_Bits`, the depth of the current tree.
|
||||
`Max_Number_of_Bits` must be <= 11,
|
||||
otherwise the representation is considered corrupted.
|
||||
|
||||
@@ -1254,7 +1279,7 @@ Let's presume the following Huffman tree must be described :
|
||||
|
||||
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,
|
||||
Literal value `5` will not be listed, as it can be determined from previous values 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 :
|
||||
@@ -1274,7 +1299,7 @@ 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 larger power of 2 value is 16.
|
||||
Therefore, `Max_Number_of_Bits = 4` and `Weight[5] = 16-15 = 1`.
|
||||
Therefore, `Max_Number_of_Bits = 4` and `Weight[5] = log_2(16 - 15) + 1 = 1`.
|
||||
|
||||
#### Huffman Tree header
|
||||
|
||||
@@ -1336,6 +1361,9 @@ If updating state after decoding a symbol would require more bits than
|
||||
remain in the stream, it is assumed that extra bits are 0. Then,
|
||||
symbols for each of the final states are decoded and the process is complete.
|
||||
|
||||
If this process would produce more weights than the maximum number of decoded
|
||||
weights (255), then the data is considered corrupted.
|
||||
|
||||
#### Conversion from weights to Huffman prefix codes
|
||||
|
||||
All present symbols shall now have a `Weight` value.
|
||||
@@ -1683,6 +1711,9 @@ or at least provide a meaningful error code explaining for which reason it canno
|
||||
|
||||
Version changes
|
||||
---------------
|
||||
- 0.4.0 : fixed imprecise behavior for nbSeq==0, detected by Igor Pavlov
|
||||
- 0.3.9 : clarifications for Huffman-compressed literal sizes.
|
||||
- 0.3.8 : clarifications for Huffman Blocks and Huffman Tree descriptions.
|
||||
- 0.3.7 : clarifications for Repeat_Offsets, matching RFC8878
|
||||
- 0.3.6 : clarifications for Dictionary_ID
|
||||
- 0.3.5 : clarifications for Block_Maximum_Size
|
||||
|
||||
+210
-121
@@ -1,10 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>zstd 1.5.4 Manual</title>
|
||||
<title>zstd 1.5.6 Manual</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>zstd 1.5.4 Manual</h1>
|
||||
<h1>zstd 1.5.6 Manual</h1>
|
||||
<hr>
|
||||
<a name="Contents"></a><h2>Contents</h2>
|
||||
<ol>
|
||||
@@ -22,15 +22,15 @@
|
||||
<li><a href="#Chapter12">Dictionary helper functions</a></li>
|
||||
<li><a href="#Chapter13">Advanced dictionary and prefix API (Requires v1.4.0+)</a></li>
|
||||
<li><a href="#Chapter14">experimental API (static linking only)</a></li>
|
||||
<li><a href="#Chapter15">Frame size functions</a></li>
|
||||
<li><a href="#Chapter15">Frame header and size functions</a></li>
|
||||
<li><a href="#Chapter16">Memory management</a></li>
|
||||
<li><a href="#Chapter17">Advanced compression functions</a></li>
|
||||
<li><a href="#Chapter18">Advanced decompression functions</a></li>
|
||||
<li><a href="#Chapter19">Advanced streaming functions</a></li>
|
||||
<li><a href="#Chapter20">Buffer-less and synchronous inner streaming functions</a></li>
|
||||
<li><a href="#Chapter20">Buffer-less and synchronous inner streaming functions (DEPRECATED)</a></li>
|
||||
<li><a href="#Chapter21">Buffer-less streaming compression (synchronous mode)</a></li>
|
||||
<li><a href="#Chapter22">Buffer-less streaming decompression (synchronous mode)</a></li>
|
||||
<li><a href="#Chapter23">Block level API</a></li>
|
||||
<li><a href="#Chapter23">Block level API (DEPRECATED)</a></li>
|
||||
</ol>
|
||||
<hr>
|
||||
<a name="Chapter1"></a><h2>Introduction</h2><pre>
|
||||
@@ -80,7 +80,8 @@
|
||||
const void* src, size_t srcSize,
|
||||
int compressionLevel);
|
||||
</b><p> Compresses `src` content as a single zstd compressed frame into already allocated `dst`.
|
||||
Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`.
|
||||
NOTE: Providing `dstCapacity >= ZSTD_compressBound(srcSize)` guarantees that zstd will have
|
||||
enough space to successfully compress the data.
|
||||
@return : compressed size written into `dst` (<= `dstCapacity),
|
||||
or an error code if it fails (which can be tested using ZSTD_isError()).
|
||||
</p></pre><BR>
|
||||
@@ -155,7 +156,7 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
|
||||
* for example to size a static array on stack.
|
||||
* Will produce constant value 0 if srcSize too large.
|
||||
*/
|
||||
#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00LLU : 0xFF00FF00U)
|
||||
#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00ULL : 0xFF00FF00U)
|
||||
#define ZSTD_COMPRESSBOUND(srcSize) (((size_t)(srcSize) >= ZSTD_MAX_INPUT_SIZE) ? 0 : (srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) </b>/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */<b>
|
||||
size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case single-pass scenario */<b>
|
||||
</b>/* ZSTD_isError() :<b>
|
||||
@@ -173,7 +174,7 @@ int ZSTD_defaultCLevel(void); </b>/*!< default compression lev
|
||||
|
||||
<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.
|
||||
and reuse it for each successive compression operation.
|
||||
This will make workload friendlier for system's memory.
|
||||
Note : re-using context is just a speed / resource optimization.
|
||||
It doesn't change the compression ratio, which remains identical.
|
||||
@@ -189,9 +190,9 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); </b>/* accept NULL pointer */<b>
|
||||
const void* src, size_t srcSize,
|
||||
int compressionLevel);
|
||||
</b><p> Same as ZSTD_compress(), using an explicit ZSTD_CCtx.
|
||||
Important : in order to behave similarly to `ZSTD_compress()`,
|
||||
this function compresses at requested compression level,
|
||||
__ignoring any other parameter__ .
|
||||
Important : in order to mirror `ZSTD_compress()` behavior,
|
||||
this function compresses at the requested compression level,
|
||||
__ignoring any other advanced parameter__ .
|
||||
If any advanced parameter was set using the advanced API,
|
||||
they will all be reset. Only `compressionLevel` remains.
|
||||
|
||||
@@ -199,7 +200,7 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); </b>/* accept NULL pointer */<b>
|
||||
|
||||
<h3>Decompression context</h3><pre> When decompressing many times,
|
||||
it is recommended to allocate a context only once,
|
||||
and re-use it for each successive compression operation.
|
||||
and reuse it for each successive compression operation.
|
||||
This will make workload friendlier for system's memory.
|
||||
Use one context per thread for parallel execution.
|
||||
</pre><b><pre>typedef struct ZSTD_DCtx_s ZSTD_DCtx;
|
||||
@@ -211,7 +212,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
const void* src, size_t srcSize);
|
||||
</b><p> Same as ZSTD_decompress(),
|
||||
requires an allocated ZSTD_DCtx.
|
||||
Compatible with sticky parameters.
|
||||
Compatible with sticky parameters (see below).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
@@ -295,6 +296,19 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
* The higher the value of selected strategy, the more complex it is,
|
||||
* resulting in stronger and slower compression.
|
||||
* Special: value 0 means "use default strategy". */
|
||||
|
||||
ZSTD_c_targetCBlockSize=130, </b>/* v1.5.6+<b>
|
||||
* Attempts to fit compressed block size into approximatively targetCBlockSize.
|
||||
* Bound by ZSTD_TARGETCBLOCKSIZE_MIN and ZSTD_TARGETCBLOCKSIZE_MAX.
|
||||
* Note that it's not a guarantee, just a convergence target (default:0).
|
||||
* No target when targetCBlockSize == 0.
|
||||
* This is helpful in low bandwidth streaming environments to improve end-to-end latency,
|
||||
* when a client can make use of partial documents (a prominent example being Chrome).
|
||||
* Note: this parameter is stable since v1.5.6.
|
||||
* It was present as an experimental parameter in earlier versions,
|
||||
* but it's not recommended using it with earlier library versions
|
||||
* due to massive performance regressions.
|
||||
*/
|
||||
</b>/* LDM mode parameters */<b>
|
||||
ZSTD_c_enableLongDistanceMatching=160, </b>/* Enable long distance matching.<b>
|
||||
* This parameter is designed to improve compression ratio
|
||||
@@ -374,7 +388,6 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
* ZSTD_c_forceMaxWindow
|
||||
* ZSTD_c_forceAttachDict
|
||||
* ZSTD_c_literalCompressionMode
|
||||
* ZSTD_c_targetCBlockSize
|
||||
* ZSTD_c_srcSizeHint
|
||||
* ZSTD_c_enableDedicatedDictSearch
|
||||
* ZSTD_c_stableInBuffer
|
||||
@@ -395,7 +408,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
ZSTD_c_experimentalParam3=1000,
|
||||
ZSTD_c_experimentalParam4=1001,
|
||||
ZSTD_c_experimentalParam5=1002,
|
||||
ZSTD_c_experimentalParam6=1003,
|
||||
</b>/* was ZSTD_c_experimentalParam6=1003; is now ZSTD_c_targetCBlockSize */<b>
|
||||
ZSTD_c_experimentalParam7=1004,
|
||||
ZSTD_c_experimentalParam8=1005,
|
||||
ZSTD_c_experimentalParam9=1006,
|
||||
@@ -482,11 +495,13 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize);
|
||||
</b><p> Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API.
|
||||
(note that this entry point doesn't even expose a compression level parameter).
|
||||
ZSTD_compress2() always starts a new frame.
|
||||
Should cctx hold data from a previously unfinished frame, everything about it is forgotten.
|
||||
- Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
|
||||
- The function is always blocking, returns when compression is completed.
|
||||
Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`.
|
||||
NOTE: Providing `dstCapacity >= ZSTD_compressBound(srcSize)` guarantees that zstd will have
|
||||
enough space to successfully compress the data, though it is possible it fails for other reasons.
|
||||
@return : compressed size written into `dst` (<= `dstCapacity),
|
||||
or an error code if it fails (which can be tested using ZSTD_isError()).
|
||||
|
||||
@@ -511,6 +526,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
* ZSTD_d_forceIgnoreChecksum
|
||||
* ZSTD_d_refMultipleDDicts
|
||||
* ZSTD_d_disableHuffmanAssembly
|
||||
* ZSTD_d_maxBlockSize
|
||||
* Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
|
||||
* note : never ever use experimentalParam? names directly
|
||||
*/
|
||||
@@ -518,7 +534,8 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
ZSTD_d_experimentalParam2=1001,
|
||||
ZSTD_d_experimentalParam3=1002,
|
||||
ZSTD_d_experimentalParam4=1003,
|
||||
ZSTD_d_experimentalParam5=1004
|
||||
ZSTD_d_experimentalParam5=1004,
|
||||
ZSTD_d_experimentalParam6=1005
|
||||
|
||||
} ZSTD_dParameter;
|
||||
</b></pre><BR>
|
||||
@@ -566,14 +583,14 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
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.
|
||||
It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory.
|
||||
It is recommended to reuse ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory.
|
||||
|
||||
For parallel execution, use one separate ZSTD_CStream per thread.
|
||||
|
||||
note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing.
|
||||
|
||||
Parameters are sticky : when starting a new compression on the same context,
|
||||
it will re-use the same sticky parameters as previous compression session.
|
||||
it will reuse the same sticky parameters as previous compression session.
|
||||
When in doubt, it's recommended to fully initialize the context before usage.
|
||||
Use ZSTD_CCtx_reset() to reset the context and ZSTD_CCtx_setParameter(),
|
||||
ZSTD_CCtx_setPledgedSrcSize(), or ZSTD_CCtx_loadDictionary() and friends to
|
||||
@@ -664,6 +681,11 @@ size_t ZSTD_freeCStream(ZSTD_CStream* zcs); </b>/* accept NULL pointer */<b>
|
||||
only ZSTD_e_end or ZSTD_e_flush operations are allowed.
|
||||
Before starting a new compression job, or changing compression parameters,
|
||||
it is required to fully flush internal buffers.
|
||||
- note: if an operation ends with an error, it may leave @cctx in an undefined state.
|
||||
Therefore, it's UB to invoke ZSTD_compressStream2() of ZSTD_compressStream() on such a state.
|
||||
In order to be re-employed after an error, a state must be reset,
|
||||
which can be done explicitly (ZSTD_CCtx_reset()),
|
||||
or is sometimes implied by methods starting a new compression job (ZSTD_initCStream(), ZSTD_compressCCtx())
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
@@ -696,7 +718,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
|
||||
<a name="Chapter9"></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.
|
||||
ZSTD_DStream objects can be reused multiple times.
|
||||
|
||||
Use ZSTD_initDStream() to start a new decompression operation.
|
||||
@return : recommended first input size
|
||||
@@ -749,6 +771,12 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds); </b>/* accept NULL pointer */<b>
|
||||
@return : 0 when a frame is completely decoded and fully flushed,
|
||||
or an error code, which can be tested using ZSTD_isError(),
|
||||
or any other value > 0, which means there is some decoding or flushing to do to complete current frame.
|
||||
|
||||
Note: when an operation returns with an error code, the @zds state may be left in undefined state.
|
||||
It's UB to invoke `ZSTD_decompressStream()` on such a state.
|
||||
In order to re-use such a state, it must be first reset,
|
||||
which can be done explicitly (`ZSTD_DCtx_reset()`),
|
||||
or is implied for operations starting some new decompression job (`ZSTD_initDStream`, `ZSTD_decompressDCtx()`, `ZSTD_decompress_usingDict()`)
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
@@ -866,9 +894,11 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds); </b>/* accept NULL pointer */<b>
|
||||
|
||||
<a name="Chapter13"></a><h2>Advanced dictionary and prefix API (Requires v1.4.0+)</h2><pre>
|
||||
This API allows dictionaries to be used with ZSTD_compress2(),
|
||||
ZSTD_compressStream2(), and ZSTD_decompressDCtx(). Dictionaries are sticky, and
|
||||
only reset with the context is reset with ZSTD_reset_parameters or
|
||||
ZSTD_reset_session_and_parameters. Prefixes are single-use.
|
||||
ZSTD_compressStream2(), and ZSTD_decompressDCtx().
|
||||
Dictionaries are sticky, they remain valid when same context is reused,
|
||||
they only reset when the context is reset
|
||||
with ZSTD_reset_parameters or ZSTD_reset_session_and_parameters.
|
||||
In contrast, Prefixes are single-use.
|
||||
<BR></pre>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||
@@ -888,7 +918,11 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds); </b>/* accept NULL pointer */<b>
|
||||
Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead.
|
||||
In such a case, dictionary buffer must outlive its users.
|
||||
Note 4 : Use ZSTD_CCtx_loadDictionary_advanced()
|
||||
to precisely select how dictionary content must be interpreted.
|
||||
to precisely select how dictionary content must be interpreted.
|
||||
Note 5 : This method does not benefit from LDM (long distance mode).
|
||||
If you want to employ LDM on some large dictionary content,
|
||||
prefer employing ZSTD_CCtx_refPrefix() described below.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
||||
@@ -912,6 +946,7 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds); </b>/* accept NULL pointer */<b>
|
||||
Decompression will need same prefix to properly regenerate data.
|
||||
Compressing with a prefix is similar in outcome as performing a diff and compressing it,
|
||||
but performs much faster, especially during decompression (compression speed is tunable with compression level).
|
||||
This method is compatible with LDM (long distance mode).
|
||||
@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.
|
||||
@@ -1146,7 +1181,7 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
||||
ZSTD_ps_disable = 2 </b>/* Do not use the feature */<b>
|
||||
} ZSTD_paramSwitch_e;
|
||||
</b></pre><BR>
|
||||
<a name="Chapter15"></a><h2>Frame size functions</h2><pre></pre>
|
||||
<a name="Chapter15"></a><h2>Frame header and size functions</h2><pre></pre>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize);
|
||||
</b><p> `src` should point to the start of a series of ZSTD encoded and/or skippable frames
|
||||
@@ -1192,6 +1227,31 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
||||
or an error code (if srcSize is too small)
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
|
||||
</b></pre><BR>
|
||||
<pre><b>typedef struct {
|
||||
unsigned long long frameContentSize; </b>/* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */<b>
|
||||
unsigned long long windowSize; </b>/* can be very large, up to <= frameContentSize */<b>
|
||||
unsigned blockSizeMax;
|
||||
ZSTD_frameType_e frameType; </b>/* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */<b>
|
||||
unsigned headerSize;
|
||||
unsigned dictID;
|
||||
unsigned checksumFlag;
|
||||
unsigned _reserved1;
|
||||
unsigned _reserved2;
|
||||
} ZSTD_frameHeader;
|
||||
</b></pre><BR>
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); </b>/**< doesn't consume input */<b>
|
||||
</b>/*! ZSTD_getFrameHeader_advanced() :<b>
|
||||
* same as ZSTD_getFrameHeader(),
|
||||
* with added capability to select a format (like ZSTD_f_zstd1_magicless) */
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format);
|
||||
</b><p> 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()
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_decompressionMargin(const void* src, size_t srcSize);
|
||||
</b><p> Zstd supports in-place decompression, where the input and output buffers overlap.
|
||||
In this case, the output buffer must be at least (Margin + Output_Size) bytes large,
|
||||
@@ -1352,58 +1412,61 @@ ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize,
|
||||
|
||||
<a name="Chapter16"></a><h2>Memory management</h2><pre></pre>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int maxCompressionLevel);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void);
|
||||
</b><p> These functions make it possible to estimate memory usage
|
||||
of a future {D,C}Ctx, before its creation.
|
||||
This is useful in combination with ZSTD_initStatic(),
|
||||
which makes it possible to employ a static buffer for ZSTD_CCtx* state.
|
||||
|
||||
ZSTD_estimateCCtxSize() will provide a memory budget large enough
|
||||
for any compression level up to selected one.
|
||||
Note : Unlike ZSTD_estimateCStreamSize*(), this estimate
|
||||
does not include space for a window buffer.
|
||||
Therefore, the estimation is only guaranteed for single-shot compressions, not streaming.
|
||||
to compress data of any size using one-shot compression ZSTD_compressCCtx() or ZSTD_compress2()
|
||||
associated with any compression level up to max specified one.
|
||||
The estimate will assume the input may be arbitrarily large,
|
||||
which is the worst case.
|
||||
|
||||
Note that the size estimation is specific for one-shot compression,
|
||||
it is not valid for streaming (see ZSTD_estimateCStreamSize*())
|
||||
nor other potential ways of using a ZSTD_CCtx* state.
|
||||
|
||||
When srcSize can be bound by a known and rather "small" value,
|
||||
this fact can be used to provide a tighter estimation
|
||||
because the CCtx compression context will need less memory.
|
||||
This tighter estimation can be provided by more advanced functions
|
||||
this knowledge can be used to provide a tighter budget estimation
|
||||
because the ZSTD_CCtx* state will need less memory for small inputs.
|
||||
This tighter estimation can be provided by employing more advanced functions
|
||||
ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(),
|
||||
and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter().
|
||||
Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits.
|
||||
|
||||
Note : only single-threaded compression is supported.
|
||||
ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
|
||||
Note 2 : ZSTD_estimateCCtxSize* functions are not compatible with the Block-Level Sequence Producer API at this time.
|
||||
Size estimates assume that no external sequence producer is registered.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int maxCompressionLevel);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t maxWindowSize);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
||||
</b><p> ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
|
||||
It will also consider src size to be arbitrarily "large", which is worst case.
|
||||
</b><p> ZSTD_estimateCStreamSize() will provide a memory budget large enough for streaming compression
|
||||
using any compression level up to the max specified one.
|
||||
It will also consider src size to be arbitrarily "large", which is a worst case scenario.
|
||||
If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
||||
ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
Note : CStream size estimation is only correct for single-threaded compression.
|
||||
ZSTD_DStream memory budget depends on window Size.
|
||||
ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
Note 2 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time.
|
||||
Size estimates assume that no external sequence producer is registered.
|
||||
|
||||
ZSTD_DStream memory budget depends on frame's window Size.
|
||||
This information can be passed manually, using ZSTD_estimateDStreamSize,
|
||||
or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
|
||||
Any frame requesting a window size larger than max specified one will be rejected.
|
||||
Note : if streaming is init with function ZSTD_init?Stream_usingDict(),
|
||||
an internal ?Dict will be created, which additional size is not estimated here.
|
||||
In this case, get total size by adding ZSTD_estimate?DictSize
|
||||
Note 2 : only single-threaded compression is supported.
|
||||
ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
Note 3 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time.
|
||||
Size estimates assume that no external sequence producer is registered.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
@@ -1505,10 +1568,24 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPo
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams);
|
||||
</b><p> Set all parameters provided within @cparams into the working @cctx.
|
||||
</b><p> Set all parameters provided within @p cparams into the working @p cctx.
|
||||
Note : if modifying parameters during compression (MT mode only),
|
||||
note that changes to the .windowLog parameter will be ignored.
|
||||
@return 0 on success, or an error code (can be checked with ZSTD_isError())
|
||||
@return 0 on success, or an error code (can be checked with ZSTD_isError()).
|
||||
On failure, no parameters are updated.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams);
|
||||
</b><p> Set all parameters provided within @p fparams into the working @p cctx.
|
||||
@return 0 on success, or an error code (can be checked with ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params);
|
||||
</b><p> Set all parameters provided within @p params into the working @p cctx.
|
||||
@return 0 on success, or an error code (can be checked with ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTD_DEPRECATED("use ZSTD_compress2")
|
||||
@@ -1754,12 +1831,9 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_parameters params,
|
||||
unsigned long long pledgedSrcSize);
|
||||
</b><p> This function is DEPRECATED, and is approximately equivalent to:
|
||||
</b><p> This function is DEPRECATED, and is equivalent to:
|
||||
ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
|
||||
// Pseudocode: Set each zstd parameter and leave the rest as-is.
|
||||
for ((param, value) : params) {
|
||||
ZSTD_CCtx_setParameter(zcs, param, value);
|
||||
}
|
||||
ZSTD_CCtx_setParams(zcs, params);
|
||||
ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
|
||||
ZSTD_CCtx_loadDictionary(zcs, dict, dictSize);
|
||||
|
||||
@@ -1788,12 +1862,9 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_frameParameters fParams,
|
||||
unsigned long long pledgedSrcSize);
|
||||
</b><p> This function is DEPRECATED, and is approximately equivalent to:
|
||||
</b><p> This function is DEPRECATED, and is equivalent to:
|
||||
ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
|
||||
// Pseudocode: Set each zstd frame parameter and leave the rest as-is.
|
||||
for ((fParam, value) : fParams) {
|
||||
ZSTD_CCtx_setParameter(zcs, fParam, value);
|
||||
}
|
||||
ZSTD_CCtx_setFParams(zcs, fParams);
|
||||
ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
|
||||
ZSTD_CCtx_refCDict(zcs, cdict);
|
||||
|
||||
@@ -1815,7 +1886,7 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
|
||||
explicitly specified.
|
||||
|
||||
start a new frame, using same parameters from previous frame.
|
||||
This is typically useful to skip dictionary loading stage, since it will re-use it in-place.
|
||||
This is typically useful to skip dictionary loading stage, since it will reuse it in-place.
|
||||
Note that zcs must be init at least once before using ZSTD_resetCStream().
|
||||
If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
|
||||
If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
|
||||
@@ -1876,21 +1947,69 @@ ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
|
||||
</b><p>
|
||||
ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
|
||||
|
||||
re-use decompression parameters from previous init; saves dictionary loading
|
||||
reuse decompression parameters from previous init; saves dictionary loading
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter20"></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.
|
||||
<pre><b>ZSTDLIB_STATIC_API void
|
||||
ZSTD_registerSequenceProducer(
|
||||
ZSTD_CCtx* cctx,
|
||||
void* sequenceProducerState,
|
||||
ZSTD_sequenceProducer_F sequenceProducer
|
||||
);
|
||||
</b><p> Instruct zstd to use a block-level external sequence producer function.
|
||||
|
||||
The sequenceProducerState must be initialized by the caller, and the caller is
|
||||
responsible for managing its lifetime. This parameter is sticky across
|
||||
compressions. It will remain set until the user explicitly resets compression
|
||||
parameters.
|
||||
|
||||
Sequence producer registration is considered to be an "advanced parameter",
|
||||
part of the "advanced API". This means it will only have an effect on compression
|
||||
APIs which respect advanced parameters, such as compress2() and compressStream2().
|
||||
Older compression APIs such as compressCCtx(), which predate the introduction of
|
||||
"advanced parameters", will ignore any external sequence producer setting.
|
||||
|
||||
The sequence producer can be "cleared" by registering a NULL function pointer. This
|
||||
removes all limitations described above in the "LIMITATIONS" section of the API docs.
|
||||
|
||||
The user is strongly encouraged to read the full API documentation (above) before
|
||||
calling this function.
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API void
|
||||
ZSTD_CCtxParams_registerSequenceProducer(
|
||||
ZSTD_CCtx_params* params,
|
||||
void* sequenceProducerState,
|
||||
ZSTD_sequenceProducer_F sequenceProducer
|
||||
);
|
||||
</b><p> Same as ZSTD_registerSequenceProducer(), but operates on ZSTD_CCtx_params.
|
||||
This is used for accurate size estimation with ZSTD_estimateCCtxSize_usingCCtxParams(),
|
||||
which is needed when creating a ZSTD_CCtx with ZSTD_initStaticCCtx().
|
||||
|
||||
If you are using the external sequence producer API in a scenario where ZSTD_initStaticCCtx()
|
||||
is required, then this function is for you. Otherwise, you probably don't need it.
|
||||
|
||||
See tests/zstreamtest.c for example usage.
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter20"></a><h2>Buffer-less and synchronous inner streaming functions (DEPRECATED)</h2><pre>
|
||||
This API is deprecated, and will be removed in a future version.
|
||||
It allows streaming (de)compression with user allocated buffers.
|
||||
However, it is hard to use, and not as well tested as the rest of
|
||||
our API.
|
||||
|
||||
Please use the normal streaming API instead: ZSTD_compressStream2,
|
||||
and ZSTD_decompressStream.
|
||||
If there is functionality that you need, but it doesn't provide,
|
||||
please open an issue on our GitHub.
|
||||
|
||||
<BR></pre>
|
||||
|
||||
<a name="Chapter21"></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.
|
||||
ZSTD_CCtx object can be reused multiple times within successive compression operations.
|
||||
|
||||
Start by initializing a context.
|
||||
Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression.
|
||||
@@ -1911,11 +2030,14 @@ ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
|
||||
It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
|
||||
Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
|
||||
|
||||
`ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
|
||||
`ZSTD_CCtx` object can be reused (ZSTD_compressBegin()) to compress again.
|
||||
<BR></pre>
|
||||
|
||||
<h3>Buffer-less streaming compression functions</h3><pre></pre><b><pre>ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
|
||||
<h3>Buffer-less streaming compression functions</h3><pre></pre><b><pre>ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.")
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
|
||||
ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.")
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
|
||||
ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.")
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); </b>/**< note: fails if cdict==NULL */<b>
|
||||
</pre></b><BR>
|
||||
<pre><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>
|
||||
@@ -1925,7 +2047,7 @@ ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const Z
|
||||
<a name="Chapter22"></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.
|
||||
A ZSTD_DCtx object can be reused multiple times.
|
||||
|
||||
First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader().
|
||||
Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough.
|
||||
@@ -1993,36 +2115,25 @@ ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const Z
|
||||
For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content.
|
||||
<BR></pre>
|
||||
|
||||
<h3>Buffer-less streaming decompression functions</h3><pre></pre><b><pre>typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
|
||||
typedef struct {
|
||||
unsigned long long frameContentSize; </b>/* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */<b>
|
||||
unsigned long long windowSize; </b>/* can be very large, up to <= frameContentSize */<b>
|
||||
unsigned blockSizeMax;
|
||||
ZSTD_frameType_e frameType; </b>/* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */<b>
|
||||
unsigned headerSize;
|
||||
unsigned dictID;
|
||||
unsigned checksumFlag;
|
||||
unsigned _reserved1;
|
||||
unsigned _reserved2;
|
||||
} ZSTD_frameHeader;
|
||||
</pre></b><BR>
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); </b>/**< doesn't consume input */<b>
|
||||
</b>/*! ZSTD_getFrameHeader_advanced() :<b>
|
||||
* same as ZSTD_getFrameHeader(),
|
||||
* with added capability to select a format (like ZSTD_f_zstd1_magicless) */
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); </b>/**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */<b>
|
||||
</b><p> 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()
|
||||
</p></pre><BR>
|
||||
|
||||
<h3>Buffer-less streaming decompression functions</h3><pre></pre><b><pre></pre></b><BR>
|
||||
<pre><b>ZSTDLIB_STATIC_API 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>
|
||||
</b></pre><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="Chapter23"></a><h2>Block level API</h2><pre></pre>
|
||||
<a name="Chapter23"></a><h2>Block level API (DEPRECATED)</h2><pre></pre>
|
||||
|
||||
<pre><b></b><p> Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
||||
<pre><b></b><p> You can get the frame header down to 2 bytes by setting:
|
||||
- ZSTD_c_format = ZSTD_f_zstd1_magicless
|
||||
- ZSTD_c_contentSizeFlag = 0
|
||||
- ZSTD_c_checksumFlag = 0
|
||||
- ZSTD_c_dictIDFlag = 0
|
||||
|
||||
This API is not as well tested as our normal API, so we recommend not using it.
|
||||
We will be removing it in a future version. If the normal API doesn't provide
|
||||
the functionality you need, please open a GitHub issue.
|
||||
|
||||
Block functions produce and decode raw zstd blocks, without frame metadata.
|
||||
Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
||||
But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes.
|
||||
|
||||
A few rules to respect :
|
||||
@@ -2046,36 +2157,14 @@ ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowS
|
||||
Use ZSTD_insertBlock() for such a case.
|
||||
</p></pre><BR>
|
||||
|
||||
<h3>Raw zstd block functions</h3><pre></pre><b><pre>ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
|
||||
<h3>Raw zstd block functions</h3><pre></pre><b><pre>ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.")
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
|
||||
ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.")
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.")
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.")
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); </b>/**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */<b>
|
||||
</pre></b><BR>
|
||||
<pre><b>ZSTDLIB_STATIC_API void
|
||||
ZSTD_registerSequenceProducer(
|
||||
ZSTD_CCtx* cctx,
|
||||
void* sequenceProducerState,
|
||||
ZSTD_sequenceProducer_F* sequenceProducer
|
||||
);
|
||||
</b><p> Instruct zstd to use a block-level external sequence producer function.
|
||||
|
||||
The sequenceProducerState must be initialized by the caller, and the caller is
|
||||
responsible for managing its lifetime. This parameter is sticky across
|
||||
compressions. It will remain set until the user explicitly resets compression
|
||||
parameters.
|
||||
|
||||
Sequence producer registration is considered to be an "advanced parameter",
|
||||
part of the "advanced API". This means it will only have an effect on compression
|
||||
APIs which respect advanced parameters, such as compress2() and compressStream2().
|
||||
Older compression APIs such as compressCCtx(), which predate the introduction of
|
||||
"advanced parameters", will ignore any external sequence producer setting.
|
||||
|
||||
The sequence producer can be "cleared" by registering a NULL function pointer. This
|
||||
removes all limitations described above in the "LIMITATIONS" section of the API docs.
|
||||
|
||||
The user is strongly encouraged to read the full API documentation (above) before
|
||||
calling this function.
|
||||
</p></pre><BR>
|
||||
|
||||
</html>
|
||||
</body>
|
||||
|
||||
@@ -42,7 +42,13 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve
|
||||
*/
|
||||
CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel) );
|
||||
CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1) );
|
||||
ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, nbThreads);
|
||||
if (nbThreads > 1) {
|
||||
size_t const r = ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, nbThreads);
|
||||
if (ZSTD_isError(r)) {
|
||||
fprintf (stderr, "Note: the linked libzstd library doesn't support multithreading. "
|
||||
"Reverting to single-thread mode. \n");
|
||||
}
|
||||
}
|
||||
|
||||
/* This loop read from the input file, compresses that entire chunk,
|
||||
* and writes all output produced to the output file.
|
||||
@@ -117,7 +123,7 @@ int main(int argc, const char** argv)
|
||||
}
|
||||
|
||||
int cLevel = 1;
|
||||
int nbThreads = 4;
|
||||
int nbThreads = 1;
|
||||
|
||||
if (argc >= 3) {
|
||||
cLevel = atoi (argv[2]);
|
||||
|
||||
+40
-28
@@ -8,6 +8,9 @@
|
||||
# You may select, at your option, one of the above-listed licenses.
|
||||
# ################################################################
|
||||
|
||||
# default target (when running `make` with no argument)
|
||||
lib-release:
|
||||
|
||||
# Modules
|
||||
ZSTD_LIB_COMPRESSION ?= 1
|
||||
ZSTD_LIB_DECOMPRESSION ?= 1
|
||||
@@ -54,12 +57,11 @@ VERSION := $(ZSTD_VERSION)
|
||||
# Note: by default, the static library is built single-threaded and dynamic library is built
|
||||
# multi-threaded. It is possible to force multi or single threaded builds by appending
|
||||
# -mt or -nomt to the build target (like lib-mt for multi-threaded, lib-nomt for single-threaded).
|
||||
.PHONY: default
|
||||
default: lib-release
|
||||
|
||||
|
||||
CPPFLAGS_DYNLIB += -DZSTD_MULTITHREAD # dynamic library build defaults to multi-threaded
|
||||
LDFLAGS_DYNLIB += -pthread
|
||||
CPPFLAGS_STATLIB += # static library build defaults to single-threaded
|
||||
CPPFLAGS_STATICLIB += # static library build defaults to single-threaded
|
||||
|
||||
|
||||
ifeq ($(findstring GCC,$(CCVER)),GCC)
|
||||
@@ -91,7 +93,7 @@ all: lib
|
||||
|
||||
|
||||
.PHONY: libzstd.a # must be run every time
|
||||
libzstd.a: CPPFLAGS += $(CPPFLAGS_STATLIB)
|
||||
libzstd.a: CPPFLAGS += $(CPPFLAGS_STATICLIB)
|
||||
|
||||
SET_CACHE_DIRECTORY = \
|
||||
+$(MAKE) --no-print-directory $@ \
|
||||
@@ -109,19 +111,19 @@ libzstd.a:
|
||||
else
|
||||
# BUILD_DIR is defined
|
||||
|
||||
ZSTD_STATLIB_DIR := $(BUILD_DIR)/static
|
||||
ZSTD_STATLIB := $(ZSTD_STATLIB_DIR)/libzstd.a
|
||||
ZSTD_STATLIB_OBJ := $(addprefix $(ZSTD_STATLIB_DIR)/,$(ZSTD_LOCAL_OBJ))
|
||||
$(ZSTD_STATLIB): ARFLAGS = rcs
|
||||
$(ZSTD_STATLIB): | $(ZSTD_STATLIB_DIR)
|
||||
$(ZSTD_STATLIB): $(ZSTD_STATLIB_OBJ)
|
||||
ZSTD_STATICLIB_DIR := $(BUILD_DIR)/static
|
||||
ZSTD_STATICLIB := $(ZSTD_STATICLIB_DIR)/libzstd.a
|
||||
ZSTD_STATICLIB_OBJ := $(addprefix $(ZSTD_STATICLIB_DIR)/,$(ZSTD_LOCAL_OBJ))
|
||||
$(ZSTD_STATICLIB): ARFLAGS = rcs
|
||||
$(ZSTD_STATICLIB): | $(ZSTD_STATICLIB_DIR)
|
||||
$(ZSTD_STATICLIB): $(ZSTD_STATICLIB_OBJ)
|
||||
# Check for multithread flag at target execution time
|
||||
$(if $(filter -DZSTD_MULTITHREAD,$(CPPFLAGS)),\
|
||||
@echo compiling multi-threaded static library $(LIBVER),\
|
||||
@echo compiling single-threaded static library $(LIBVER))
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
libzstd.a: $(ZSTD_STATLIB)
|
||||
libzstd.a: $(ZSTD_STATICLIB)
|
||||
cp -f $< $@
|
||||
|
||||
endif
|
||||
@@ -182,14 +184,14 @@ lib : libzstd.a libzstd
|
||||
# make does not consider implicit pattern rule for .PHONY target
|
||||
|
||||
%-mt : CPPFLAGS_DYNLIB := -DZSTD_MULTITHREAD
|
||||
%-mt : CPPFLAGS_STATLIB := -DZSTD_MULTITHREAD
|
||||
%-mt : CPPFLAGS_STATICLIB := -DZSTD_MULTITHREAD
|
||||
%-mt : LDFLAGS_DYNLIB := -pthread
|
||||
%-mt : %
|
||||
@echo multi-threaded build completed
|
||||
|
||||
%-nomt : CPPFLAGS_DYNLIB :=
|
||||
%-nomt : LDFLAGS_DYNLIB :=
|
||||
%-nomt : CPPFLAGS_STATLIB :=
|
||||
%-nomt : CPPFLAGS_STATICLIB :=
|
||||
%-nomt : %
|
||||
@echo single-threaded build completed
|
||||
|
||||
@@ -200,42 +202,52 @@ lib : libzstd.a libzstd
|
||||
|
||||
# Generate .h dependencies automatically
|
||||
|
||||
DEPFLAGS = -MT $@ -MMD -MP -MF
|
||||
# -MMD: compiler generates dependency information as a side-effect of compilation, without system headers
|
||||
# -MP: adds phony target for each dependency other than main file.
|
||||
DEPFLAGS = -MMD -MP
|
||||
|
||||
$(ZSTD_DYNLIB_DIR)/%.o : %.c $(ZSTD_DYNLIB_DIR)/%.d | $(ZSTD_DYNLIB_DIR)
|
||||
# ensure that ZSTD_DYNLIB_DIR exists prior to generating %.o
|
||||
$(ZSTD_DYNLIB_DIR)/%.o : %.c | $(ZSTD_DYNLIB_DIR)
|
||||
@echo CC $@
|
||||
$(COMPILE.c) $(DEPFLAGS) $(ZSTD_DYNLIB_DIR)/$*.d $(OUTPUT_OPTION) $<
|
||||
$(COMPILE.c) $(DEPFLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(ZSTD_STATLIB_DIR)/%.o : %.c $(ZSTD_STATLIB_DIR)/%.d | $(ZSTD_STATLIB_DIR)
|
||||
$(ZSTD_STATICLIB_DIR)/%.o : %.c | $(ZSTD_STATICLIB_DIR)
|
||||
@echo CC $@
|
||||
$(COMPILE.c) $(DEPFLAGS) $(ZSTD_STATLIB_DIR)/$*.d $(OUTPUT_OPTION) $<
|
||||
$(COMPILE.c) $(DEPFLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(ZSTD_DYNLIB_DIR)/%.o : %.S | $(ZSTD_DYNLIB_DIR)
|
||||
@echo AS $@
|
||||
$(COMPILE.S) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(ZSTD_STATLIB_DIR)/%.o : %.S | $(ZSTD_STATLIB_DIR)
|
||||
$(ZSTD_STATICLIB_DIR)/%.o : %.S | $(ZSTD_STATICLIB_DIR)
|
||||
@echo AS $@
|
||||
$(COMPILE.S) $(OUTPUT_OPTION) $<
|
||||
|
||||
MKDIR ?= mkdir
|
||||
$(BUILD_DIR) $(ZSTD_DYNLIB_DIR) $(ZSTD_STATLIB_DIR):
|
||||
$(MKDIR) -p $@
|
||||
MKDIR ?= mkdir -p
|
||||
$(BUILD_DIR) $(ZSTD_DYNLIB_DIR) $(ZSTD_STATICLIB_DIR):
|
||||
$(MKDIR) $@
|
||||
|
||||
DEPFILES := $(ZSTD_DYNLIB_OBJ:.o=.d) $(ZSTD_STATLIB_OBJ:.o=.d)
|
||||
DEPFILES := $(ZSTD_DYNLIB_OBJ:.o=.d) $(ZSTD_STATICLIB_OBJ:.o=.d)
|
||||
$(DEPFILES):
|
||||
|
||||
include $(wildcard $(DEPFILES))
|
||||
# The leading '-' means: do not fail is include fails (ex: directory does not exist yet)
|
||||
-include $(wildcard $(DEPFILES))
|
||||
|
||||
|
||||
# Special case : building library in single-thread mode _and_ without zstdmt_compress.c
|
||||
ZSTDMT_FILES = compress/zstdmt_compress.c
|
||||
ZSTD_NOMT_FILES = $(filter-out $(ZSTDMT_FILES),$(ZSTD_FILES))
|
||||
# Special case : build library in single-thread mode _and_ without zstdmt_compress.c
|
||||
# Note : we still need threading.c and pool.c for the dictionary builder,
|
||||
# but they will correctly behave single-threaded.
|
||||
ZSTDMT_FILES = zstdmt_compress.c
|
||||
ZSTD_NOMT_FILES = $(filter-out $(ZSTDMT_FILES),$(notdir $(ZSTD_FILES)))
|
||||
libzstd-nomt: CFLAGS += -fPIC -fvisibility=hidden
|
||||
libzstd-nomt: LDFLAGS += -shared
|
||||
libzstd-nomt: $(ZSTD_NOMT_FILES)
|
||||
@echo compiling single-thread dynamic library $(LIBVER)
|
||||
@echo files : $(ZSTD_NOMT_FILES)
|
||||
@if echo "$(ZSTD_NOMT_FILES)" | tr ' ' '\n' | $(GREP) -q zstdmt; then \
|
||||
echo "Error: Found zstdmt in list."; \
|
||||
exit 1; \
|
||||
fi
|
||||
$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@
|
||||
|
||||
.PHONY: clean
|
||||
@@ -249,7 +261,7 @@ clean:
|
||||
#-----------------------------------------------------------------------------
|
||||
# make install is validated only for below listed environments
|
||||
#-----------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(UNAME),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku AIX))
|
||||
ifneq (,$(filter $(UNAME),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku AIX MSYS_NT CYGWIN_NT))
|
||||
|
||||
lib: libzstd.pc
|
||||
|
||||
|
||||
+14
-1
@@ -88,7 +88,7 @@ The file structure is designed to make this selection manually achievable for an
|
||||
For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` .
|
||||
|
||||
- While invoking `make libzstd`, it's possible to define build macros
|
||||
`ZSTD_LIB_COMPRESSION, ZSTD_LIB_DECOMPRESSION`, `ZSTD_LIB_DICTBUILDER`,
|
||||
`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 (e.g. `ZSTD_LIB_COMPRESSION=0` will also disable
|
||||
@@ -119,6 +119,15 @@ The file structure is designed to make this selection manually achievable for an
|
||||
binary is achieved by using `HUF_FORCE_DECOMPRESS_X1` and
|
||||
`ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT` (implied by `ZSTD_LIB_MINIFY`).
|
||||
|
||||
On the compressor side, Zstd's compression levels map to several internal
|
||||
strategies. In environments where the higher compression levels aren't used,
|
||||
it is possible to exclude all but the fastest strategy with
|
||||
`ZSTD_LIB_EXCLUDE_COMPRESSORS_DFAST_AND_UP=1`. (Note that this will change
|
||||
the behavior of the default compression level.) Or if you want to retain the
|
||||
default compressor as well, you can set
|
||||
`ZSTD_LIB_EXCLUDE_COMPRESSORS_GREEDY_AND_UP=1`, at the cost of an additional
|
||||
~20KB or so.
|
||||
|
||||
For squeezing the last ounce of size out, you can also define
|
||||
`ZSTD_NO_INLINE`, which disables inlining, and `ZSTD_STRIP_ERROR_STRINGS`,
|
||||
which removes the error messages that are otherwise returned by
|
||||
@@ -169,6 +178,10 @@ The file structure is designed to make this selection manually achievable for an
|
||||
`ZSTDERRORLIB_VSIBILITY`, and `ZDICTLIB_VISIBILITY` if unset, for backwards compatibility
|
||||
with the old macro names.
|
||||
|
||||
- The C compiler macro `HUF_DISABLE_FAST_DECODE` disables the newer Huffman fast C
|
||||
and assembly decoding loops. You may want to use this macro if these loops are
|
||||
slower on your platform.
|
||||
|
||||
#### Windows : using MinGW+MSYS to create DLL
|
||||
|
||||
DLL can be created using MinGW+MSYS with the `make libzstd` command.
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* This file provides custom allocation primitives
|
||||
*/
|
||||
|
||||
#define ZSTD_DEPS_NEED_MALLOC
|
||||
#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */
|
||||
|
||||
#include "compiler.h" /* MEM_STATIC */
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
#include "../zstd.h" /* ZSTD_customMem */
|
||||
|
||||
#ifndef ZSTD_ALLOCATIONS_H
|
||||
#define ZSTD_ALLOCATIONS_H
|
||||
|
||||
/* custom memory allocation functions */
|
||||
|
||||
MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem)
|
||||
{
|
||||
if (customMem.customAlloc)
|
||||
return customMem.customAlloc(customMem.opaque, size);
|
||||
return ZSTD_malloc(size);
|
||||
}
|
||||
|
||||
MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem)
|
||||
{
|
||||
if (customMem.customAlloc) {
|
||||
/* calloc implemented as malloc+memset;
|
||||
* not as efficient as calloc, but next best guess for custom malloc */
|
||||
void* const ptr = customMem.customAlloc(customMem.opaque, size);
|
||||
ZSTD_memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
return ZSTD_calloc(1, size);
|
||||
}
|
||||
|
||||
MEM_STATIC void ZSTD_customFree(void* ptr, ZSTD_customMem customMem)
|
||||
{
|
||||
if (ptr!=NULL) {
|
||||
if (customMem.customFree)
|
||||
customMem.customFree(customMem.opaque, ptr);
|
||||
else
|
||||
ZSTD_free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ZSTD_ALLOCATIONS_H */
|
||||
+30
-5
@@ -17,7 +17,7 @@ MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val)
|
||||
{
|
||||
assert(val != 0);
|
||||
{
|
||||
static const int DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3,
|
||||
static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3,
|
||||
30, 22, 20, 15, 25, 17, 4, 8,
|
||||
31, 27, 13, 23, 21, 19, 16, 7,
|
||||
26, 12, 18, 6, 11, 5, 10, 9};
|
||||
@@ -30,7 +30,7 @@ MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val)
|
||||
assert(val != 0);
|
||||
# if defined(_MSC_VER)
|
||||
# if STATIC_BMI2 == 1
|
||||
return _tzcnt_u32(val);
|
||||
return (unsigned)_tzcnt_u32(val);
|
||||
# else
|
||||
if (val != 0) {
|
||||
unsigned long r;
|
||||
@@ -69,7 +69,7 @@ MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val)
|
||||
assert(val != 0);
|
||||
# if defined(_MSC_VER)
|
||||
# if STATIC_BMI2 == 1
|
||||
return _lzcnt_u32(val);
|
||||
return (unsigned)_lzcnt_u32(val);
|
||||
# else
|
||||
if (val != 0) {
|
||||
unsigned long r;
|
||||
@@ -92,7 +92,7 @@ MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val)
|
||||
assert(val != 0);
|
||||
# if defined(_MSC_VER) && defined(_WIN64)
|
||||
# if STATIC_BMI2 == 1
|
||||
return _tzcnt_u64(val);
|
||||
return (unsigned)_tzcnt_u64(val);
|
||||
# else
|
||||
if (val != 0) {
|
||||
unsigned long r;
|
||||
@@ -123,7 +123,7 @@ MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val)
|
||||
assert(val != 0);
|
||||
# if defined(_MSC_VER) && defined(_WIN64)
|
||||
# if STATIC_BMI2 == 1
|
||||
return _lzcnt_u64(val);
|
||||
return (unsigned)_lzcnt_u64(val);
|
||||
# else
|
||||
if (val != 0) {
|
||||
unsigned long r;
|
||||
@@ -172,4 +172,29 @@ MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCo
|
||||
return 31 - ZSTD_countLeadingZeros32(val);
|
||||
}
|
||||
|
||||
/* ZSTD_rotateRight_*():
|
||||
* Rotates a bitfield to the right by "count" bits.
|
||||
* https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts
|
||||
*/
|
||||
MEM_STATIC
|
||||
U64 ZSTD_rotateRight_U64(U64 const value, U32 count) {
|
||||
assert(count < 64);
|
||||
count &= 0x3F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (U64)(value << ((0U - count) & 0x3F));
|
||||
}
|
||||
|
||||
MEM_STATIC
|
||||
U32 ZSTD_rotateRight_U32(U32 const value, U32 count) {
|
||||
assert(count < 32);
|
||||
count &= 0x1F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (U32)(value << ((0U - count) & 0x1F));
|
||||
}
|
||||
|
||||
MEM_STATIC
|
||||
U16 ZSTD_rotateRight_U16(U16 const value, U32 count) {
|
||||
assert(count < 16);
|
||||
count &= 0x0F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (U16)(value << ((0U - count) & 0x0F));
|
||||
}
|
||||
|
||||
#endif /* ZSTD_BITS_H */
|
||||
|
||||
+49
-29
@@ -90,19 +90,20 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
||||
/*-********************************************
|
||||
* bitStream decoding API (read backward)
|
||||
**********************************************/
|
||||
typedef size_t BitContainerType;
|
||||
typedef struct {
|
||||
size_t bitContainer;
|
||||
BitContainerType bitContainer;
|
||||
unsigned bitsConsumed;
|
||||
const char* ptr;
|
||||
const char* start;
|
||||
const char* limitPtr;
|
||||
} BIT_DStream_t;
|
||||
|
||||
typedef enum { BIT_DStream_unfinished = 0,
|
||||
BIT_DStream_endOfBuffer = 1,
|
||||
BIT_DStream_completed = 2,
|
||||
BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
|
||||
/* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
|
||||
typedef enum { BIT_DStream_unfinished = 0, /* fully refilled */
|
||||
BIT_DStream_endOfBuffer = 1, /* still some bits left in bitstream */
|
||||
BIT_DStream_completed = 2, /* bitstream entirely consumed, bit-exact */
|
||||
BIT_DStream_overflow = 3 /* user requested more bits than present in bitstream */
|
||||
} BIT_DStream_status; /* result of BIT_reloadDStream() */
|
||||
|
||||
MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
|
||||
MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
|
||||
@@ -112,7 +113,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
|
||||
|
||||
/* Start by invoking BIT_initDStream().
|
||||
* A chunk of the bitStream is then stored into a local register.
|
||||
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
|
||||
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (BitContainerType).
|
||||
* You can then retrieve bitFields stored into the local register, **in reverse order**.
|
||||
* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
|
||||
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
|
||||
@@ -162,7 +163,7 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
|
||||
return 0;
|
||||
}
|
||||
|
||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
|
||||
FORCE_INLINE_TEMPLATE size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
|
||||
{
|
||||
#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS)
|
||||
return _bzhi_u64(bitContainer, nbBits);
|
||||
@@ -267,22 +268,22 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
|
||||
bitD->bitContainer = *(const BYTE*)(bitD->start);
|
||||
switch(srcSize)
|
||||
{
|
||||
case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
|
||||
case 7: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
|
||||
ZSTD_FALLTHROUGH;
|
||||
|
||||
case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
|
||||
case 6: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
|
||||
ZSTD_FALLTHROUGH;
|
||||
|
||||
case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
|
||||
case 5: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
|
||||
ZSTD_FALLTHROUGH;
|
||||
|
||||
case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
|
||||
case 4: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[3]) << 24;
|
||||
ZSTD_FALLTHROUGH;
|
||||
|
||||
case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
|
||||
case 3: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[2]) << 16;
|
||||
ZSTD_FALLTHROUGH;
|
||||
|
||||
case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
|
||||
case 2: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[1]) << 8;
|
||||
ZSTD_FALLTHROUGH;
|
||||
|
||||
default: break;
|
||||
@@ -297,12 +298,12 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
|
||||
return srcSize;
|
||||
}
|
||||
|
||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
|
||||
FORCE_INLINE_TEMPLATE size_t BIT_getUpperBits(BitContainerType bitContainer, U32 const start)
|
||||
{
|
||||
return bitContainer >> start;
|
||||
}
|
||||
|
||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
|
||||
FORCE_INLINE_TEMPLATE size_t BIT_getMiddleBits(BitContainerType bitContainer, U32 const start, U32 const nbBits)
|
||||
{
|
||||
U32 const regMask = sizeof(bitContainer)*8 - 1;
|
||||
/* if start > regMask, bitstream is corrupted, and result is undefined */
|
||||
@@ -325,7 +326,7 @@ MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 c
|
||||
* On 32-bits, maxNbBits==24.
|
||||
* On 64-bits, maxNbBits==56.
|
||||
* @return : value extracted */
|
||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
|
||||
FORCE_INLINE_TEMPLATE size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
|
||||
{
|
||||
/* arbitrate between double-shift and shift+mask */
|
||||
#if 1
|
||||
@@ -348,7 +349,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
|
||||
return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
|
||||
}
|
||||
|
||||
MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||
FORCE_INLINE_TEMPLATE void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||
{
|
||||
bitD->bitsConsumed += nbBits;
|
||||
}
|
||||
@@ -357,7 +358,7 @@ MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||
* Read (consume) next n bits from local register and update.
|
||||
* Pay attention to not read more than nbBits contained into local register.
|
||||
* @return : extracted value. */
|
||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
|
||||
FORCE_INLINE_TEMPLATE size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
|
||||
{
|
||||
size_t const value = BIT_lookBits(bitD, nbBits);
|
||||
BIT_skipBits(bitD, nbBits);
|
||||
@@ -374,6 +375,21 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
|
||||
return value;
|
||||
}
|
||||
|
||||
/*! BIT_reloadDStream_internal() :
|
||||
* Simple variant of BIT_reloadDStream(), with two conditions:
|
||||
* 1. bitstream is valid : bitsConsumed <= sizeof(bitD->bitContainer)*8
|
||||
* 2. look window is valid after shifted down : bitD->ptr >= bitD->start
|
||||
*/
|
||||
MEM_STATIC BIT_DStream_status BIT_reloadDStream_internal(BIT_DStream_t* bitD)
|
||||
{
|
||||
assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
|
||||
bitD->ptr -= bitD->bitsConsumed >> 3;
|
||||
assert(bitD->ptr >= bitD->start);
|
||||
bitD->bitsConsumed &= 7;
|
||||
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||
return BIT_DStream_unfinished;
|
||||
}
|
||||
|
||||
/*! BIT_reloadDStreamFast() :
|
||||
* Similar to BIT_reloadDStream(), but with two differences:
|
||||
* 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
|
||||
@@ -384,31 +400,35 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
|
||||
{
|
||||
if (UNLIKELY(bitD->ptr < bitD->limitPtr))
|
||||
return BIT_DStream_overflow;
|
||||
assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
|
||||
bitD->ptr -= bitD->bitsConsumed >> 3;
|
||||
bitD->bitsConsumed &= 7;
|
||||
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||
return BIT_DStream_unfinished;
|
||||
return BIT_reloadDStream_internal(bitD);
|
||||
}
|
||||
|
||||
/*! BIT_reloadDStream() :
|
||||
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
||||
* This function is safe, it guarantees it will not read beyond src buffer.
|
||||
* This function is safe, it guarantees it will not never beyond src buffer.
|
||||
* @return : status of `BIT_DStream_t` internal register.
|
||||
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
|
||||
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
||||
FORCE_INLINE_TEMPLATE BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
||||
{
|
||||
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
|
||||
/* note : once in overflow mode, a bitstream remains in this mode until it's reset */
|
||||
if (UNLIKELY(bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))) {
|
||||
static const BitContainerType zeroFilled = 0;
|
||||
bitD->ptr = (const char*)&zeroFilled; /* aliasing is allowed for char */
|
||||
/* overflow detected, erroneous scenario or end of stream: no update */
|
||||
return BIT_DStream_overflow;
|
||||
}
|
||||
|
||||
assert(bitD->ptr >= bitD->start);
|
||||
|
||||
if (bitD->ptr >= bitD->limitPtr) {
|
||||
return BIT_reloadDStreamFast(bitD);
|
||||
return BIT_reloadDStream_internal(bitD);
|
||||
}
|
||||
if (bitD->ptr == bitD->start) {
|
||||
/* reached end of bitStream => no update */
|
||||
if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
|
||||
return BIT_DStream_completed;
|
||||
}
|
||||
/* start < ptr < limitPtr */
|
||||
/* start < ptr < limitPtr => cautious update */
|
||||
{ U32 nbBytes = bitD->bitsConsumed >> 3;
|
||||
BIT_DStream_status result = BIT_DStream_unfinished;
|
||||
if (bitD->ptr - nbBytes < bitD->start) {
|
||||
|
||||
+118
-22
@@ -11,6 +11,8 @@
|
||||
#ifndef ZSTD_COMPILER_H
|
||||
#define ZSTD_COMPILER_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "portability_macros.h"
|
||||
|
||||
/*-*******************************************************
|
||||
@@ -51,12 +53,19 @@
|
||||
# define WIN_CDECL
|
||||
#endif
|
||||
|
||||
/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
|
||||
#if defined(__GNUC__)
|
||||
# define UNUSED_ATTR __attribute__((unused))
|
||||
#else
|
||||
# define UNUSED_ATTR
|
||||
#endif
|
||||
|
||||
/**
|
||||
* FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
|
||||
* parameters. They must be inlined for the compiler to eliminate the constant
|
||||
* branches.
|
||||
*/
|
||||
#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
|
||||
#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR UNUSED_ATTR
|
||||
/**
|
||||
* HINT_INLINE is used to help the compiler generate better code. It is *not*
|
||||
* used for "templates", so it can be tweaked based on the compilers
|
||||
@@ -71,14 +80,28 @@
|
||||
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
|
||||
# define HINT_INLINE static INLINE_KEYWORD
|
||||
#else
|
||||
# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
|
||||
# define HINT_INLINE FORCE_INLINE_TEMPLATE
|
||||
#endif
|
||||
|
||||
/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
|
||||
/* "soft" inline :
|
||||
* The compiler is free to select if it's a good idea to inline or not.
|
||||
* The main objective is to silence compiler warnings
|
||||
* when a defined function in included but not used.
|
||||
*
|
||||
* Note : this macro is prefixed `MEM_` because it used to be provided by `mem.h` unit.
|
||||
* Updating the prefix is probably preferable, but requires a fairly large codemod,
|
||||
* since this name is used everywhere.
|
||||
*/
|
||||
#ifndef MEM_STATIC /* already defined in Linux Kernel mem.h */
|
||||
#if defined(__GNUC__)
|
||||
# define UNUSED_ATTR __attribute__((unused))
|
||||
# define MEM_STATIC static __inline UNUSED_ATTR
|
||||
#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# define MEM_STATIC static inline
|
||||
#elif defined(_MSC_VER)
|
||||
# define MEM_STATIC static __inline
|
||||
#else
|
||||
# define UNUSED_ATTR
|
||||
# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* force no inlining */
|
||||
@@ -109,10 +132,10 @@
|
||||
/* prefetch
|
||||
* can be disabled, by declaring NO_PREFETCH build macro */
|
||||
#if defined(NO_PREFETCH)
|
||||
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
#else
|
||||
# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */
|
||||
# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && !defined(_M_ARM64EC) /* _mm_prefetch() is not defined outside of x86/x64 */
|
||||
# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
|
||||
# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
|
||||
# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
|
||||
@@ -120,24 +143,25 @@
|
||||
# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
|
||||
# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
|
||||
# elif defined(__aarch64__)
|
||||
# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
|
||||
# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
|
||||
# define PREFETCH_L1(ptr) do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0)
|
||||
# define PREFETCH_L2(ptr) do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0)
|
||||
# else
|
||||
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
# endif
|
||||
#endif /* NO_PREFETCH */
|
||||
|
||||
#define CACHELINE_SIZE 64
|
||||
|
||||
#define PREFETCH_AREA(p, s) { \
|
||||
const char* const _ptr = (const char*)(p); \
|
||||
size_t const _size = (size_t)(s); \
|
||||
size_t _pos; \
|
||||
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
|
||||
PREFETCH_L2(_ptr + _pos); \
|
||||
} \
|
||||
}
|
||||
#define PREFETCH_AREA(p, s) \
|
||||
do { \
|
||||
const char* const _ptr = (const char*)(p); \
|
||||
size_t const _size = (size_t)(s); \
|
||||
size_t _pos; \
|
||||
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
|
||||
PREFETCH_L2(_ptr + _pos); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* vectorization
|
||||
* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
|
||||
@@ -166,9 +190,9 @@
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
|
||||
# define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); }
|
||||
# define ZSTD_UNREACHABLE do { assert(0), __builtin_unreachable(); } while (0)
|
||||
#else
|
||||
# define ZSTD_UNREACHABLE { assert(0); }
|
||||
# define ZSTD_UNREACHABLE do { assert(0); } while (0)
|
||||
#endif
|
||||
|
||||
/* disable warnings */
|
||||
@@ -281,6 +305,74 @@
|
||||
* Sanitizer
|
||||
*****************************************************************/
|
||||
|
||||
/**
|
||||
* Zstd relies on pointer overflow in its decompressor.
|
||||
* We add this attribute to functions that rely on pointer overflow.
|
||||
*/
|
||||
#ifndef ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
# if __has_attribute(no_sanitize)
|
||||
# if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 8
|
||||
/* gcc < 8 only has signed-integer-overlow which triggers on pointer overflow */
|
||||
# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("signed-integer-overflow")))
|
||||
# else
|
||||
/* older versions of clang [3.7, 5.0) will warn that pointer-overflow is ignored. */
|
||||
# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("pointer-overflow")))
|
||||
# endif
|
||||
# else
|
||||
# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper function to perform a wrapped pointer difference without trigging
|
||||
* UBSAN.
|
||||
*
|
||||
* @returns lhs - rhs with wrapping
|
||||
*/
|
||||
MEM_STATIC
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
ptrdiff_t ZSTD_wrappedPtrDiff(unsigned char const* lhs, unsigned char const* rhs)
|
||||
{
|
||||
return lhs - rhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to perform a wrapped pointer add without triggering UBSAN.
|
||||
*
|
||||
* @return ptr + add with wrapping
|
||||
*/
|
||||
MEM_STATIC
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add)
|
||||
{
|
||||
return ptr + add;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to perform a wrapped pointer subtraction without triggering
|
||||
* UBSAN.
|
||||
*
|
||||
* @return ptr - sub with wrapping
|
||||
*/
|
||||
MEM_STATIC
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub)
|
||||
{
|
||||
return ptr - sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to add to a pointer that works around C's undefined behavior
|
||||
* of adding 0 to NULL.
|
||||
*
|
||||
* @returns `ptr + add` except it defines `NULL + 0 == NULL`.
|
||||
*/
|
||||
MEM_STATIC
|
||||
unsigned char* ZSTD_maybeNullPtrAdd(unsigned char* ptr, ptrdiff_t add)
|
||||
{
|
||||
return add > 0 ? ptr + add : ptr;
|
||||
}
|
||||
|
||||
/* Issue #3240 reports an ASAN failure on an llvm-mingw build. Out of an
|
||||
* abundance of caution, disable our custom poisoning on mingw. */
|
||||
#ifdef __MINGW32__
|
||||
@@ -311,6 +403,10 @@ void __msan_poison(const volatile void *a, size_t size);
|
||||
/* Returns the offset of the first (at least partially) poisoned byte in the
|
||||
memory range, or -1 if the whole range is good. */
|
||||
intptr_t __msan_test_shadow(const volatile void *x, size_t size);
|
||||
|
||||
/* Print shadow and origin for the memory range to stderr in a human-readable
|
||||
format. */
|
||||
void __msan_print_shadow(const volatile void *x, size_t size);
|
||||
#endif
|
||||
|
||||
#if ZSTD_ADDRESS_SANITIZER && !defined(ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||
|
||||
@@ -35,6 +35,7 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
|
||||
U32 f7b = 0;
|
||||
U32 f7c = 0;
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
|
||||
#if !defined(__clang__)
|
||||
int reg[4];
|
||||
__cpuid((int*)reg, 0);
|
||||
{
|
||||
@@ -50,6 +51,41 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
|
||||
f7c = (U32)reg[2];
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in
|
||||
* which the `__cpuid` intrinsic does not save and restore `rbx` as it needs
|
||||
* to due to being a reserved register. So in that case, do the `cpuid`
|
||||
* ourselves. Clang supports inline assembly anyway.
|
||||
*/
|
||||
U32 n;
|
||||
__asm__(
|
||||
"pushq %%rbx\n\t"
|
||||
"cpuid\n\t"
|
||||
"popq %%rbx\n\t"
|
||||
: "=a"(n)
|
||||
: "a"(0)
|
||||
: "rcx", "rdx");
|
||||
if (n >= 1) {
|
||||
U32 f1a;
|
||||
__asm__(
|
||||
"pushq %%rbx\n\t"
|
||||
"cpuid\n\t"
|
||||
"popq %%rbx\n\t"
|
||||
: "=a"(f1a), "=c"(f1c), "=d"(f1d)
|
||||
: "a"(1)
|
||||
:);
|
||||
}
|
||||
if (n >= 7) {
|
||||
__asm__(
|
||||
"pushq %%rbx\n\t"
|
||||
"cpuid\n\t"
|
||||
"movq %%rbx, %%rax\n\t"
|
||||
"popq %%rbx"
|
||||
: "=a"(f7b), "=c"(f7c)
|
||||
: "a"(7), "c"(0)
|
||||
: "rdx");
|
||||
}
|
||||
#endif
|
||||
#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
|
||||
/* The following block like the normal cpuid branch below, but gcc
|
||||
* reserves ebx for use of its pic register so we must specially
|
||||
|
||||
@@ -21,4 +21,10 @@
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#if !defined(ZSTD_LINUX_KERNEL) || (DEBUGLEVEL>=2)
|
||||
/* We only use this when DEBUGLEVEL>=2, but we get -Werror=pedantic errors if a
|
||||
* translation unit is empty. So remove this from Linux kernel builds, but
|
||||
* otherwise just leave it in.
|
||||
*/
|
||||
int g_debuglevel = DEBUGLEVEL;
|
||||
#endif
|
||||
|
||||
+20
-11
@@ -85,18 +85,27 @@ extern int g_debuglevel; /* the variable is only declared,
|
||||
It's useful when enabling very verbose levels
|
||||
on selective conditions (such as position in src) */
|
||||
|
||||
# define RAWLOG(l, ...) { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
|
||||
} }
|
||||
# define DEBUGLOG(l, ...) { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
|
||||
ZSTD_DEBUG_PRINT(" \n"); \
|
||||
} }
|
||||
# define RAWLOG(l, ...) \
|
||||
do { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#define LINE_AS_STRING TOSTRING(__LINE__)
|
||||
|
||||
# define DEBUGLOG(l, ...) \
|
||||
do { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__FILE__ ":" LINE_AS_STRING ": " __VA_ARGS__); \
|
||||
ZSTD_DEBUG_PRINT(" \n"); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define RAWLOG(l, ...) {} /* disabled */
|
||||
# define DEBUGLOG(l, ...) {} /* disabled */
|
||||
# define RAWLOG(l, ...) do { } while (0) /* disabled */
|
||||
# define DEBUGLOG(l, ...) do { } while (0) /* disabled */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+45
-36
@@ -60,8 +60,13 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
|
||||
ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
|
||||
|
||||
/* check and forward error code */
|
||||
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
|
||||
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
|
||||
#define CHECK_V_F(e, f) \
|
||||
size_t const e = f; \
|
||||
do { \
|
||||
if (ERR_isError(e)) \
|
||||
return e; \
|
||||
} while (0)
|
||||
#define CHECK_F(f) do { CHECK_V_F(_var_err__, f); } while (0)
|
||||
|
||||
|
||||
/*-****************************************
|
||||
@@ -95,10 +100,12 @@ void _force_has_format_string(const char *format, ...) {
|
||||
* We want to force this function invocation to be syntactically correct, but
|
||||
* we don't want to force runtime evaluation of its arguments.
|
||||
*/
|
||||
#define _FORCE_HAS_FORMAT_STRING(...) \
|
||||
if (0) { \
|
||||
_force_has_format_string(__VA_ARGS__); \
|
||||
}
|
||||
#define _FORCE_HAS_FORMAT_STRING(...) \
|
||||
do { \
|
||||
if (0) { \
|
||||
_force_has_format_string(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ERR_QUOTE(str) #str
|
||||
|
||||
@@ -109,48 +116,50 @@ void _force_has_format_string(const char *format, ...) {
|
||||
* In order to do that (particularly, printing the conditional that failed),
|
||||
* this can't just wrap RETURN_ERROR().
|
||||
*/
|
||||
#define RETURN_ERROR_IF(cond, err, ...) \
|
||||
if (cond) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
}
|
||||
#define RETURN_ERROR_IF(cond, err, ...) \
|
||||
do { \
|
||||
if (cond) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Unconditionally return the specified error.
|
||||
*
|
||||
* In debug modes, prints additional information.
|
||||
*/
|
||||
#define RETURN_ERROR(err, ...) \
|
||||
do { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
} while(0);
|
||||
#define RETURN_ERROR(err, ...) \
|
||||
do { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* If the provided expression evaluates to an error code, returns that error code.
|
||||
*
|
||||
* In debug modes, prints additional information.
|
||||
*/
|
||||
#define FORWARD_IF_ERROR(err, ...) \
|
||||
do { \
|
||||
size_t const err_code = (err); \
|
||||
if (ERR_isError(err_code)) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0);
|
||||
#define FORWARD_IF_ERROR(err, ...) \
|
||||
do { \
|
||||
size_t const err_code = (err); \
|
||||
if (ERR_isError(err_code)) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
||||
+3
-2
@@ -229,6 +229,7 @@ If there is an error, the function will return an error code, which can be teste
|
||||
|
||||
#endif /* FSE_H */
|
||||
|
||||
|
||||
#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
|
||||
#define FSE_H_FSE_STATIC_LINKING_ONLY
|
||||
|
||||
@@ -464,13 +465,13 @@ MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, un
|
||||
FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
|
||||
const U16* const stateTable = (const U16*)(statePtr->stateTable);
|
||||
U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
|
||||
BIT_addBits(bitC, statePtr->value, nbBitsOut);
|
||||
BIT_addBits(bitC, (size_t)statePtr->value, nbBitsOut);
|
||||
statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
||||
}
|
||||
|
||||
MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
|
||||
{
|
||||
BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
|
||||
BIT_addBits(bitC, (size_t)statePtr->value, statePtr->stateLog);
|
||||
BIT_flushBits(bitC);
|
||||
}
|
||||
|
||||
|
||||
+19
-17
@@ -22,8 +22,7 @@
|
||||
#define FSE_STATIC_LINKING_ONLY
|
||||
#include "fse.h"
|
||||
#include "error_private.h"
|
||||
#define ZSTD_DEPS_NEED_MALLOC
|
||||
#include "zstd_deps.h"
|
||||
#include "zstd_deps.h" /* ZSTD_memcpy */
|
||||
#include "bits.h" /* ZSTD_highbit32 */
|
||||
|
||||
|
||||
@@ -84,7 +83,7 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo
|
||||
symbolNext[s] = 1;
|
||||
} else {
|
||||
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
||||
symbolNext[s] = normalizedCounter[s];
|
||||
symbolNext[s] = (U16)normalizedCounter[s];
|
||||
} } }
|
||||
ZSTD_memcpy(dt, &DTableH, sizeof(DTableH));
|
||||
}
|
||||
@@ -99,8 +98,7 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo
|
||||
* all symbols have counts <= 8. We ensure we have 8 bytes at the end of
|
||||
* our buffer to handle the over-write.
|
||||
*/
|
||||
{
|
||||
U64 const add = 0x0101010101010101ull;
|
||||
{ U64 const add = 0x0101010101010101ull;
|
||||
size_t pos = 0;
|
||||
U64 sv = 0;
|
||||
U32 s;
|
||||
@@ -111,9 +109,8 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo
|
||||
for (i = 8; i < n; i += 8) {
|
||||
MEM_write64(spread + pos + i, sv);
|
||||
}
|
||||
pos += n;
|
||||
}
|
||||
}
|
||||
pos += (size_t)n;
|
||||
} }
|
||||
/* Now we spread those positions across the table.
|
||||
* The benefit of doing it in two stages is that we avoid the
|
||||
* variable size inner loop, which caused lots of branch misses.
|
||||
@@ -232,12 +229,12 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
|
||||
break;
|
||||
} }
|
||||
|
||||
return op-ostart;
|
||||
assert(op >= ostart);
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
short ncount[FSE_MAX_SYMBOL_VALUE + 1];
|
||||
FSE_DTable dtable[1]; /* Dynamically sized */
|
||||
} FSE_DecompressWksp;
|
||||
|
||||
|
||||
@@ -252,13 +249,18 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
|
||||
unsigned tableLog;
|
||||
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
|
||||
FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace;
|
||||
size_t const dtablePos = sizeof(FSE_DecompressWksp) / sizeof(FSE_DTable);
|
||||
FSE_DTable* const dtable = (FSE_DTable*)workSpace + dtablePos;
|
||||
|
||||
DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
|
||||
FSE_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
|
||||
if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC);
|
||||
|
||||
/* correct offset to dtable depends on this property */
|
||||
FSE_STATIC_ASSERT(sizeof(FSE_DecompressWksp) % sizeof(FSE_DTable) == 0);
|
||||
|
||||
/* normal FSE decoding mode */
|
||||
{
|
||||
size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
|
||||
{ size_t const NCountLength =
|
||||
FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
|
||||
if (FSE_isError(NCountLength)) return NCountLength;
|
||||
if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
|
||||
assert(NCountLength <= cSrcSize);
|
||||
@@ -271,16 +273,16 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
|
||||
workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
|
||||
wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
|
||||
|
||||
CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
|
||||
CHECK_F( FSE_buildDTable_internal(dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
|
||||
|
||||
{
|
||||
const void* ptr = wksp->dtable;
|
||||
const void* ptr = dtable;
|
||||
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
|
||||
const U32 fastMode = DTableH->fastMode;
|
||||
|
||||
/* select fast mode (static) */
|
||||
if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1);
|
||||
return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0);
|
||||
if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 1);
|
||||
return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -197,9 +197,22 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
||||
|
||||
/** HUF_getNbBitsFromCTable() :
|
||||
* Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
|
||||
* Note 1 : is not inlined, as HUF_CElt definition is private */
|
||||
* Note 1 : If symbolValue > HUF_readCTableHeader(symbolTable).maxSymbolValue, returns 0
|
||||
* Note 2 : is not inlined, as HUF_CElt definition is private
|
||||
*/
|
||||
U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue);
|
||||
|
||||
typedef struct {
|
||||
BYTE tableLog;
|
||||
BYTE maxSymbolValue;
|
||||
BYTE unused[sizeof(size_t) - 2];
|
||||
} HUF_CTableHeader;
|
||||
|
||||
/** HUF_readCTableHeader() :
|
||||
* @returns The header from the CTable specifying the tableLog and the maxSymbolValue.
|
||||
*/
|
||||
HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable);
|
||||
|
||||
/*
|
||||
* HUF_decompress() does the following:
|
||||
* 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
|
||||
|
||||
@@ -31,15 +31,6 @@ extern "C" {
|
||||
# include <stdlib.h> /* _byteswap_ulong */
|
||||
# include <intrin.h> /* _byteswap_* */
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
# define MEM_STATIC static __inline __attribute__((unused))
|
||||
#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# define MEM_STATIC static inline
|
||||
#elif defined(_MSC_VER)
|
||||
# define MEM_STATIC static __inline
|
||||
#else
|
||||
# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
|
||||
#endif
|
||||
|
||||
/*-**************************************************************
|
||||
* Basic Types
|
||||
|
||||
+2
-2
@@ -10,9 +10,9 @@
|
||||
|
||||
|
||||
/* ====== Dependencies ======= */
|
||||
#include "../common/allocations.h" /* ZSTD_customCalloc, ZSTD_customFree */
|
||||
#include "zstd_deps.h" /* size_t */
|
||||
#include "debug.h" /* assert */
|
||||
#include "zstd_internal.h" /* ZSTD_customCalloc, ZSTD_customFree */
|
||||
#include "pool.h"
|
||||
|
||||
/* ====== Compiler specifics ====== */
|
||||
@@ -223,7 +223,7 @@ static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
|
||||
{ ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
|
||||
if (!threadPool) return 1;
|
||||
/* replace existing thread pool */
|
||||
ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
|
||||
ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(ZSTD_pthread_t));
|
||||
ZSTD_customFree(ctx->threads, ctx->customMem);
|
||||
ctx->threads = threadPool;
|
||||
/* Initialize additional threads */
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ void POOL_joinJobs(POOL_ctx* ctx);
|
||||
/*! POOL_resize() :
|
||||
* Expands or shrinks pool's number of threads.
|
||||
* This is more efficient than releasing + creating a new context,
|
||||
* since it tries to preserve and re-use existing threads.
|
||||
* since it tries to preserve and reuse existing threads.
|
||||
* `numThreads` must be at least 1.
|
||||
* @return : 0 when resize was successful,
|
||||
* !0 (typically 1) if there is an error.
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
/* Mark the internal assembly functions as hidden */
|
||||
#ifdef __ELF__
|
||||
# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func
|
||||
#elif defined(__APPLE__)
|
||||
# define ZSTD_HIDE_ASM_FUNCTION(func) .private_extern func
|
||||
#else
|
||||
# define ZSTD_HIDE_ASM_FUNCTION(func)
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,7 @@ static unsigned __stdcall worker(void *arg)
|
||||
void* (*start_routine)(void*);
|
||||
void* thread_arg;
|
||||
|
||||
/* Inialized thread_arg and start_routine and signal main thread that we don't need it
|
||||
/* Initialized thread_arg and start_routine and signal main thread that we don't need it
|
||||
* to wait any longer.
|
||||
*/
|
||||
{
|
||||
@@ -73,10 +73,12 @@ int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
|
||||
ZSTD_thread_params_t thread_param;
|
||||
(void)unused;
|
||||
|
||||
if (thread==NULL) return -1;
|
||||
*thread = NULL;
|
||||
|
||||
thread_param.start_routine = start_routine;
|
||||
thread_param.arg = arg;
|
||||
thread_param.initialized = 0;
|
||||
*thread = NULL;
|
||||
|
||||
/* Setup thread initialization synchronization */
|
||||
if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) {
|
||||
@@ -91,7 +93,7 @@ int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
|
||||
|
||||
/* Spawn thread */
|
||||
*thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL);
|
||||
if (!thread) {
|
||||
if (*thread==NULL) {
|
||||
ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex);
|
||||
ZSTD_pthread_cond_destroy(&thread_param.initialized_cond);
|
||||
return errno;
|
||||
@@ -137,6 +139,7 @@ int ZSTD_pthread_join(ZSTD_pthread_t thread)
|
||||
|
||||
int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr)
|
||||
{
|
||||
assert(mutex != NULL);
|
||||
*mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t));
|
||||
if (!*mutex)
|
||||
return 1;
|
||||
@@ -145,6 +148,7 @@ int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t con
|
||||
|
||||
int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex)
|
||||
{
|
||||
assert(mutex != NULL);
|
||||
if (!*mutex)
|
||||
return 0;
|
||||
{
|
||||
@@ -156,6 +160,7 @@ int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex)
|
||||
|
||||
int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
*cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t));
|
||||
if (!*cond)
|
||||
return 1;
|
||||
@@ -164,6 +169,7 @@ int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const*
|
||||
|
||||
int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond)
|
||||
{
|
||||
assert(cond != NULL);
|
||||
if (!*cond)
|
||||
return 0;
|
||||
{
|
||||
|
||||
+5
-11
@@ -1,24 +1,18 @@
|
||||
/*
|
||||
* xxHash - Fast Hash algorithm
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* You can contact the author at :
|
||||
* - xxHash homepage: https://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (c) Yann Collet - Meta Platforms, Inc
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* xxhash.c instantiates functions defined in xxhash.h
|
||||
*/
|
||||
|
||||
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
|
||||
#define XXH_IMPLEMENTATION /* access definitions */
|
||||
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
|
||||
#define XXH_IMPLEMENTATION /* access definitions */
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
+2327
-993
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,6 @@
|
||||
* Dependencies
|
||||
***************************************/
|
||||
#define ZSTD_DEPS_NEED_MALLOC
|
||||
#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */
|
||||
#include "error_private.h"
|
||||
#include "zstd_internal.h"
|
||||
|
||||
@@ -47,37 +46,3 @@ ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
|
||||
/*! ZSTD_getErrorString() :
|
||||
* provides error code string from enum */
|
||||
const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
|
||||
|
||||
|
||||
|
||||
/*=**************************************************************
|
||||
* Custom allocator
|
||||
****************************************************************/
|
||||
void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem)
|
||||
{
|
||||
if (customMem.customAlloc)
|
||||
return customMem.customAlloc(customMem.opaque, size);
|
||||
return ZSTD_malloc(size);
|
||||
}
|
||||
|
||||
void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem)
|
||||
{
|
||||
if (customMem.customAlloc) {
|
||||
/* calloc implemented as malloc+memset;
|
||||
* not as efficient as calloc, but next best guess for custom malloc */
|
||||
void* const ptr = customMem.customAlloc(customMem.opaque, size);
|
||||
ZSTD_memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
return ZSTD_calloc(1, size);
|
||||
}
|
||||
|
||||
void ZSTD_customFree(void* ptr, ZSTD_customMem customMem)
|
||||
{
|
||||
if (ptr!=NULL) {
|
||||
if (customMem.customFree)
|
||||
customMem.customFree(customMem.opaque, ptr);
|
||||
else
|
||||
ZSTD_free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ static void ZSTD_copy8(void* dst, const void* src) {
|
||||
ZSTD_memcpy(dst, src, 8);
|
||||
#endif
|
||||
}
|
||||
#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
|
||||
#define COPY8(d,s) do { ZSTD_copy8(d,s); d+=8; s+=8; } while (0)
|
||||
|
||||
/* Need to use memmove here since the literal buffer can now be located within
|
||||
the dst buffer. In circumstances where the op "catches up" to where the
|
||||
@@ -198,7 +198,7 @@ static void ZSTD_copy16(void* dst, const void* src) {
|
||||
ZSTD_memcpy(dst, copy16_buf, 16);
|
||||
#endif
|
||||
}
|
||||
#define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; }
|
||||
#define COPY16(d,s) do { ZSTD_copy16(d,s); d+=16; s+=16; } while (0)
|
||||
|
||||
#define WILDCOPY_OVERLENGTH 32
|
||||
#define WILDCOPY_VECLEN 16
|
||||
@@ -227,7 +227,7 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e
|
||||
if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
|
||||
/* Handle short offset copies. */
|
||||
do {
|
||||
COPY8(op, ip)
|
||||
COPY8(op, ip);
|
||||
} while (op < oend);
|
||||
} else {
|
||||
assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
|
||||
@@ -350,11 +350,6 @@ typedef struct {
|
||||
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
|
||||
int ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
|
||||
|
||||
/* custom memory allocation functions */
|
||||
void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem);
|
||||
void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem);
|
||||
void ZSTD_customFree(void* ptr, ZSTD_customMem customMem);
|
||||
|
||||
|
||||
/* ZSTD_invalidateRepCodes() :
|
||||
* ensures next compression will not use repcodes from previous block.
|
||||
@@ -371,13 +366,13 @@ typedef struct {
|
||||
|
||||
/*! ZSTD_getcBlockSize() :
|
||||
* Provides the size of compressed block from block header `src` */
|
||||
/* Used by: decompress, fullbench (does not get its definition from here) */
|
||||
/* Used by: decompress, fullbench */
|
||||
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
|
||||
blockProperties_t* bpPtr);
|
||||
|
||||
/*! ZSTD_decodeSeqHeaders() :
|
||||
* decode sequence header from src */
|
||||
/* Used by: decompress, fullbench (does not get its definition from here) */
|
||||
/* Used by: zstd_decompress_block, fullbench */
|
||||
size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "../common/error_private.h"
|
||||
#define ZSTD_DEPS_NEED_MALLOC
|
||||
#define ZSTD_DEPS_NEED_MATH64
|
||||
#include "../common/zstd_deps.h" /* ZSTD_malloc, ZSTD_free, ZSTD_memcpy, ZSTD_memset */
|
||||
#include "../common/zstd_deps.h" /* ZSTD_memset */
|
||||
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||
|
||||
|
||||
@@ -225,8 +225,8 @@ size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
|
||||
size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog
|
||||
+ 4 /* bitCount initialized at 4 */
|
||||
+ 2 /* first two symbols may use one additional bit each */) / 8)
|
||||
+ 1 /* round up to whole nb bytes */
|
||||
+ 2 /* additional two bytes for bitstream flush */;
|
||||
+ 1 /* round up to whole nb bytes */
|
||||
+ 2 /* additional two bytes for bitstream flush */;
|
||||
return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||
/* Init */
|
||||
remaining = tableSize+1; /* +1 for extra accuracy */
|
||||
threshold = tableSize;
|
||||
nbBits = tableLog+1;
|
||||
nbBits = (int)tableLog+1;
|
||||
|
||||
while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */
|
||||
if (previousIs0) {
|
||||
@@ -274,7 +274,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||
}
|
||||
while (symbol >= start+3) {
|
||||
start+=3;
|
||||
bitStream += 3 << bitCount;
|
||||
bitStream += 3U << bitCount;
|
||||
bitCount += 2;
|
||||
}
|
||||
bitStream += (symbol-start) << bitCount;
|
||||
@@ -294,7 +294,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||
count++; /* +1 for extra accuracy */
|
||||
if (count>=threshold)
|
||||
count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
|
||||
bitStream += count << bitCount;
|
||||
bitStream += (U32)count << bitCount;
|
||||
bitCount += nbBits;
|
||||
bitCount -= (count<max);
|
||||
previousIs0 = (count==1);
|
||||
@@ -322,7 +322,8 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||
out[1] = (BYTE)(bitStream>>8);
|
||||
out+= (bitCount+7) /8;
|
||||
|
||||
return (out-ostart);
|
||||
assert(out >= ostart);
|
||||
return (size_t)(out-ostart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+54
-25
@@ -220,6 +220,25 @@ static void HUF_setValue(HUF_CElt* elt, size_t value)
|
||||
}
|
||||
}
|
||||
|
||||
HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable)
|
||||
{
|
||||
HUF_CTableHeader header;
|
||||
ZSTD_memcpy(&header, ctable, sizeof(header));
|
||||
return header;
|
||||
}
|
||||
|
||||
static void HUF_writeCTableHeader(HUF_CElt* ctable, U32 tableLog, U32 maxSymbolValue)
|
||||
{
|
||||
HUF_CTableHeader header;
|
||||
HUF_STATIC_ASSERT(sizeof(ctable[0]) == sizeof(header));
|
||||
ZSTD_memset(&header, 0, sizeof(header));
|
||||
assert(tableLog < 256);
|
||||
header.tableLog = (BYTE)tableLog;
|
||||
assert(maxSymbolValue < 256);
|
||||
header.maxSymbolValue = (BYTE)maxSymbolValue;
|
||||
ZSTD_memcpy(ctable, &header, sizeof(header));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
HUF_CompressWeightsWksp wksp;
|
||||
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
|
||||
@@ -237,6 +256,9 @@ size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize,
|
||||
|
||||
HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE >= sizeof(HUF_WriteCTableWksp));
|
||||
|
||||
assert(HUF_readCTableHeader(CTable).maxSymbolValue == maxSymbolValue);
|
||||
assert(HUF_readCTableHeader(CTable).tableLog == huffLog);
|
||||
|
||||
/* check conditions */
|
||||
if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC);
|
||||
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
||||
@@ -283,7 +305,9 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
||||
if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||
if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
|
||||
|
||||
CTable[0] = tableLog;
|
||||
*maxSymbolValuePtr = nbSymbols - 1;
|
||||
|
||||
HUF_writeCTableHeader(CTable, tableLog, *maxSymbolValuePtr);
|
||||
|
||||
/* Prepare base value per rank */
|
||||
{ U32 n, nextRankStart = 0;
|
||||
@@ -315,7 +339,6 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
||||
{ U32 n; for (n=0; n<nbSymbols; n++) HUF_setValue(ct + n, valPerRank[HUF_getNbBits(ct[n])]++); }
|
||||
}
|
||||
|
||||
*maxSymbolValuePtr = nbSymbols - 1;
|
||||
return readSize;
|
||||
}
|
||||
|
||||
@@ -323,6 +346,8 @@ U32 HUF_getNbBitsFromCTable(HUF_CElt const* CTable, U32 symbolValue)
|
||||
{
|
||||
const HUF_CElt* const ct = CTable + 1;
|
||||
assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
|
||||
if (symbolValue > HUF_readCTableHeader(CTable).maxSymbolValue)
|
||||
return 0;
|
||||
return (U32)HUF_getNbBits(ct[symbolValue]);
|
||||
}
|
||||
|
||||
@@ -723,7 +748,8 @@ static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, i
|
||||
HUF_setNbBits(ct + huffNode[n].byte, huffNode[n].nbBits); /* push nbBits per symbol, symbol order */
|
||||
for (n=0; n<alphabetSize; n++)
|
||||
HUF_setValue(ct + n, valPerRank[HUF_getNbBits(ct[n])]++); /* assign value within rank, symbol order */
|
||||
CTable[0] = maxNbBits;
|
||||
|
||||
HUF_writeCTableHeader(CTable, maxNbBits, maxSymbolValue);
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -776,13 +802,20 @@ size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count,
|
||||
}
|
||||
|
||||
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
|
||||
HUF_CElt const* ct = CTable + 1;
|
||||
int bad = 0;
|
||||
int s;
|
||||
for (s = 0; s <= (int)maxSymbolValue; ++s) {
|
||||
bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0);
|
||||
}
|
||||
return !bad;
|
||||
HUF_CTableHeader header = HUF_readCTableHeader(CTable);
|
||||
HUF_CElt const* ct = CTable + 1;
|
||||
int bad = 0;
|
||||
int s;
|
||||
|
||||
assert(header.tableLog <= HUF_TABLELOG_ABSOLUTEMAX);
|
||||
|
||||
if (header.maxSymbolValue < maxSymbolValue)
|
||||
return 0;
|
||||
|
||||
for (s = 0; s <= (int)maxSymbolValue; ++s) {
|
||||
bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0);
|
||||
}
|
||||
return !bad;
|
||||
}
|
||||
|
||||
size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
|
||||
@@ -1024,17 +1057,17 @@ HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
|
||||
const void* src, size_t srcSize,
|
||||
const HUF_CElt* CTable)
|
||||
{
|
||||
U32 const tableLog = (U32)CTable[0];
|
||||
U32 const tableLog = HUF_readCTableHeader(CTable).tableLog;
|
||||
HUF_CElt const* ct = CTable + 1;
|
||||
const BYTE* ip = (const BYTE*) src;
|
||||
BYTE* const ostart = (BYTE*)dst;
|
||||
BYTE* const oend = ostart + dstSize;
|
||||
BYTE* op = ostart;
|
||||
HUF_CStream_t bitC;
|
||||
|
||||
/* init */
|
||||
if (dstSize < 8) return 0; /* not enough space to compress */
|
||||
{ size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op));
|
||||
{ BYTE* op = ostart;
|
||||
size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op));
|
||||
if (HUF_isError(initErr)) return 0; }
|
||||
|
||||
if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11)
|
||||
@@ -1255,7 +1288,7 @@ unsigned HUF_optimalTableLog(
|
||||
|
||||
{ BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp);
|
||||
size_t dstSize = wkspSize - sizeof(HUF_WriteCTableWksp);
|
||||
size_t maxBits, hSize, newSize;
|
||||
size_t hSize, newSize;
|
||||
const unsigned symbolCardinality = HUF_cardinality(count, maxSymbolValue);
|
||||
const unsigned minTableLog = HUF_minTableLog(symbolCardinality);
|
||||
size_t optSize = ((size_t) ~0) - 1;
|
||||
@@ -1266,12 +1299,14 @@ unsigned HUF_optimalTableLog(
|
||||
/* Search until size increases */
|
||||
for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) {
|
||||
DEBUGLOG(7, "checking for huffLog=%u", optLogGuess);
|
||||
maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize);
|
||||
if (ERR_isError(maxBits)) continue;
|
||||
|
||||
if (maxBits < optLogGuess && optLogGuess > minTableLog) break;
|
||||
{ size_t maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize);
|
||||
if (ERR_isError(maxBits)) continue;
|
||||
|
||||
hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize);
|
||||
if (maxBits < optLogGuess && optLogGuess > minTableLog) break;
|
||||
|
||||
hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize);
|
||||
}
|
||||
|
||||
if (ERR_isError(hSize)) continue;
|
||||
|
||||
@@ -1372,12 +1407,6 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
||||
huffLog = (U32)maxBits;
|
||||
DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1));
|
||||
}
|
||||
/* Zero unused symbols in CTable, so we can check it for validity */
|
||||
{
|
||||
size_t const ctableSize = HUF_CTABLE_SIZE_ST(maxSymbolValue);
|
||||
size_t const unusedSize = sizeof(table->CTable) - ctableSize * sizeof(HUF_CElt);
|
||||
ZSTD_memset(table->CTable + ctableSize, 0, unusedSize);
|
||||
}
|
||||
|
||||
/* Write table description header */
|
||||
{ CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog,
|
||||
@@ -1420,7 +1449,7 @@ size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
||||
/* HUF_compress4X_repeat():
|
||||
* compress input using 4 streams.
|
||||
* consider skipping quickly
|
||||
* re-use an existing huffman compression table */
|
||||
* reuse an existing huffman compression table */
|
||||
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
||||
const void* src, size_t srcSize,
|
||||
unsigned maxSymbolValue, unsigned huffLog,
|
||||
|
||||
+488
-262
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,7 @@ extern "C" {
|
||||
It's not a big deal though : candidate will just be sorted again.
|
||||
Additionally, 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 mishandled after table re-use with a different strategy.
|
||||
The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table reuse with a different strategy.
|
||||
This constant is required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
|
||||
|
||||
|
||||
@@ -159,23 +159,24 @@ typedef struct {
|
||||
UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0};
|
||||
|
||||
typedef struct {
|
||||
int price;
|
||||
U32 off;
|
||||
U32 mlen;
|
||||
U32 litlen;
|
||||
U32 rep[ZSTD_REP_NUM];
|
||||
int price; /* price from beginning of segment to this position */
|
||||
U32 off; /* offset of previous match */
|
||||
U32 mlen; /* length of previous match */
|
||||
U32 litlen; /* nb of literals since previous match */
|
||||
U32 rep[ZSTD_REP_NUM]; /* offset history after previous match */
|
||||
} ZSTD_optimal_t;
|
||||
|
||||
typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
|
||||
|
||||
#define ZSTD_OPT_SIZE (ZSTD_OPT_NUM+3)
|
||||
typedef struct {
|
||||
/* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
|
||||
unsigned* litFreq; /* table of literals statistics, of size 256 */
|
||||
unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
|
||||
unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
|
||||
unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
|
||||
ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
|
||||
ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
|
||||
ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_SIZE */
|
||||
ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_SIZE */
|
||||
|
||||
U32 litSum; /* nb of literals */
|
||||
U32 litLengthSum; /* nb of litLength codes */
|
||||
@@ -226,8 +227,10 @@ struct ZSTD_matchState_t {
|
||||
U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */
|
||||
|
||||
U32 rowHashLog; /* For row-based matchfinder: Hashlog based on nb of rows in the hashTable.*/
|
||||
U16* tagTable; /* For row-based matchFinder: A row-based table containing the hashes and head index. */
|
||||
BYTE* tagTable; /* For row-based matchFinder: A row-based table containing the hashes and head index. */
|
||||
U32 hashCache[ZSTD_ROW_HASH_CACHE_SIZE]; /* For row-based matchFinder: a cache of hashes to improve speed */
|
||||
U64 hashSalt; /* For row-based matchFinder: salts the hash for reuse of tag table */
|
||||
U32 hashSaltEntropy; /* For row-based matchFinder: collects entropy for salt generation */
|
||||
|
||||
U32* hashTable;
|
||||
U32* hashTable3;
|
||||
@@ -247,6 +250,13 @@ struct ZSTD_matchState_t {
|
||||
* This behavior is controlled from the cctx ms.
|
||||
* This parameter has no effect in the cdict ms. */
|
||||
int prefetchCDictTables;
|
||||
|
||||
/* When == 0, lazy match finders insert every position.
|
||||
* When != 0, lazy match finders only insert positions they search.
|
||||
* This allows them to skip much faster over incompressible data,
|
||||
* at a small cost to compression ratio.
|
||||
*/
|
||||
int lazySkipping;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -351,10 +361,11 @@ struct ZSTD_CCtx_params_s {
|
||||
* if the external matchfinder returns an error code. */
|
||||
int enableMatchFinderFallback;
|
||||
|
||||
/* Indicates whether an external matchfinder has been referenced.
|
||||
* Users can't set this externally.
|
||||
* It is set internally in ZSTD_registerSequenceProducer(). */
|
||||
int useSequenceProducer;
|
||||
/* Parameters for the external sequence producer API.
|
||||
* Users set these parameters through ZSTD_registerSequenceProducer().
|
||||
* It is not possible to set these parameters individually through the public API. */
|
||||
void* extSeqProdState;
|
||||
ZSTD_sequenceProducer_F extSeqProdFunc;
|
||||
|
||||
/* Adjust the max block size*/
|
||||
size_t maxBlockSize;
|
||||
@@ -392,14 +403,6 @@ typedef struct {
|
||||
ZSTD_entropyCTablesMetadata_t entropyMetadata;
|
||||
} ZSTD_blockSplitCtx;
|
||||
|
||||
/* Context for block-level external matchfinder API */
|
||||
typedef struct {
|
||||
void* mState;
|
||||
ZSTD_sequenceProducer_F* mFinder;
|
||||
ZSTD_Sequence* seqBuffer;
|
||||
size_t seqBufferCapacity;
|
||||
} ZSTD_externalMatchCtx;
|
||||
|
||||
struct ZSTD_CCtx_s {
|
||||
ZSTD_compressionStage_e stage;
|
||||
int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
|
||||
@@ -470,8 +473,9 @@ struct ZSTD_CCtx_s {
|
||||
/* Workspace for block splitter */
|
||||
ZSTD_blockSplitCtx blockSplitCtx;
|
||||
|
||||
/* Workspace for external matchfinder */
|
||||
ZSTD_externalMatchCtx externalMatchCtx;
|
||||
/* Buffer for output from external sequence producer */
|
||||
ZSTD_Sequence* extSeqBuf;
|
||||
size_t extSeqBufCapacity;
|
||||
};
|
||||
|
||||
typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
|
||||
@@ -787,28 +791,35 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
|
||||
* Hashes
|
||||
***************************************/
|
||||
static const U32 prime3bytes = 506832829U;
|
||||
static U32 ZSTD_hash3(U32 u, U32 h) { assert(h <= 32); return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
|
||||
MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
|
||||
static U32 ZSTD_hash3(U32 u, U32 h, U32 s) { assert(h <= 32); return (((u << (32-24)) * prime3bytes) ^ s) >> (32-h) ; }
|
||||
MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h, 0); } /* only in zstd_opt.h */
|
||||
MEM_STATIC size_t ZSTD_hash3PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash3(MEM_readLE32(ptr), h, s); }
|
||||
|
||||
static const U32 prime4bytes = 2654435761U;
|
||||
static U32 ZSTD_hash4(U32 u, U32 h) { assert(h <= 32); return (u * prime4bytes) >> (32-h) ; }
|
||||
static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_readLE32(ptr), h); }
|
||||
static U32 ZSTD_hash4(U32 u, U32 h, U32 s) { assert(h <= 32); return ((u * prime4bytes) ^ s) >> (32-h) ; }
|
||||
static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_readLE32(ptr), h, 0); }
|
||||
static size_t ZSTD_hash4PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash4(MEM_readLE32(ptr), h, s); }
|
||||
|
||||
static const U64 prime5bytes = 889523592379ULL;
|
||||
static size_t ZSTD_hash5(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
|
||||
static size_t ZSTD_hash5(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-40)) * prime5bytes) ^ s) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h, 0); }
|
||||
static size_t ZSTD_hash5PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash5(MEM_readLE64(p), h, s); }
|
||||
|
||||
static const U64 prime6bytes = 227718039650203ULL;
|
||||
static size_t ZSTD_hash6(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
|
||||
static size_t ZSTD_hash6(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-48)) * prime6bytes) ^ s) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h, 0); }
|
||||
static size_t ZSTD_hash6PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash6(MEM_readLE64(p), h, s); }
|
||||
|
||||
static const U64 prime7bytes = 58295818150454627ULL;
|
||||
static size_t ZSTD_hash7(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
|
||||
static size_t ZSTD_hash7(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-56)) * prime7bytes) ^ s) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h, 0); }
|
||||
static size_t ZSTD_hash7PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash7(MEM_readLE64(p), h, s); }
|
||||
|
||||
static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
|
||||
static size_t ZSTD_hash8(U64 u, U32 h) { assert(h <= 64); return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
|
||||
static size_t ZSTD_hash8(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u) * prime8bytes) ^ s) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h, 0); }
|
||||
static size_t ZSTD_hash8PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash8(MEM_readLE64(p), h, s); }
|
||||
|
||||
|
||||
MEM_STATIC FORCE_INLINE_ATTR
|
||||
size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
|
||||
@@ -828,6 +839,24 @@ size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
|
||||
}
|
||||
}
|
||||
|
||||
MEM_STATIC FORCE_INLINE_ATTR
|
||||
size_t ZSTD_hashPtrSalted(const void* p, U32 hBits, U32 mls, const U64 hashSalt) {
|
||||
/* Although some of these hashes do support hBits up to 64, some do not.
|
||||
* To be on the safe side, always avoid hBits > 32. */
|
||||
assert(hBits <= 32);
|
||||
|
||||
switch(mls)
|
||||
{
|
||||
default:
|
||||
case 4: return ZSTD_hash4PtrS(p, hBits, (U32)hashSalt);
|
||||
case 5: return ZSTD_hash5PtrS(p, hBits, hashSalt);
|
||||
case 6: return ZSTD_hash6PtrS(p, hBits, hashSalt);
|
||||
case 7: return ZSTD_hash7PtrS(p, hBits, hashSalt);
|
||||
case 8: return ZSTD_hash8PtrS(p, hBits, hashSalt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** ZSTD_ipow() :
|
||||
* Return base^exponent.
|
||||
*/
|
||||
@@ -1019,7 +1048,9 @@ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
|
||||
* The least significant cycleLog bits of the indices must remain the same,
|
||||
* which may be 0. Every index up to maxDist in the past must be valid.
|
||||
*/
|
||||
MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
|
||||
MEM_STATIC
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
|
||||
U32 maxDist, void const* src)
|
||||
{
|
||||
/* preemptive overflow correction:
|
||||
@@ -1212,7 +1243,9 @@ MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
|
||||
* forget about the extDict. Handles overlap of the prefix and extDict.
|
||||
* Returns non-zero if the segment is contiguous.
|
||||
*/
|
||||
MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||
MEM_STATIC
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||
void const* src, size_t srcSize,
|
||||
int forceNonContiguous)
|
||||
{
|
||||
@@ -1433,11 +1466,10 @@ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity);
|
||||
* This cannot be used when long range matching is enabled.
|
||||
* Zstd will use these sequences, and pass the literals to a secondary block
|
||||
* compressor.
|
||||
* @return : An error code on failure.
|
||||
* NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory
|
||||
* access and data corruption.
|
||||
*/
|
||||
size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq);
|
||||
void ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq);
|
||||
|
||||
/** ZSTD_cycleLog() :
|
||||
* condition for correct operation : hashLog > 1 */
|
||||
@@ -1475,4 +1507,28 @@ ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition*
|
||||
const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
|
||||
const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch);
|
||||
|
||||
/* Returns 1 if an external sequence producer is registered, otherwise returns 0. */
|
||||
MEM_STATIC int ZSTD_hasExtSeqProd(const ZSTD_CCtx_params* params) {
|
||||
return params->extSeqProdFunc != NULL;
|
||||
}
|
||||
|
||||
/* ===============================================================
|
||||
* Deprecated definitions that are still used internally to avoid
|
||||
* deprecation warnings. These functions are exactly equivalent to
|
||||
* their public variants, but avoid the deprecation warnings.
|
||||
* =============================================================== */
|
||||
|
||||
size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
||||
|
||||
size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
|
||||
|
||||
#endif /* ZSTD_COMPRESS_H */
|
||||
|
||||
@@ -76,8 +76,8 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||
}
|
||||
|
||||
{ int const flags = bmi2 ? HUF_flags_bmi2 : 0;
|
||||
const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable, flags)
|
||||
: HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable, flags);
|
||||
const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags)
|
||||
: HUF_compress4X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags);
|
||||
op += cSize;
|
||||
cLitSize += cSize;
|
||||
if (cSize == 0 || ERR_isError(cSize)) {
|
||||
@@ -102,7 +102,7 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||
switch(lhSize)
|
||||
{
|
||||
case 3: /* 2 - 2 - 10 - 10 */
|
||||
{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
|
||||
{ U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
|
||||
MEM_writeLE24(ostart, lhc);
|
||||
break;
|
||||
}
|
||||
@@ -122,30 +122,30 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||
}
|
||||
*entropyWritten = 1;
|
||||
DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));
|
||||
return op-ostart;
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
static size_t
|
||||
ZSTD_seqDecompressedSize(seqStore_t const* seqStore,
|
||||
const seqDef* sequences, size_t nbSeq,
|
||||
size_t litSize, int lastSequence)
|
||||
const seqDef* sequences, size_t nbSeqs,
|
||||
size_t litSize, int lastSubBlock)
|
||||
{
|
||||
const seqDef* const sstart = sequences;
|
||||
const seqDef* const send = sequences + nbSeq;
|
||||
const seqDef* sp = sstart;
|
||||
size_t matchLengthSum = 0;
|
||||
size_t litLengthSum = 0;
|
||||
(void)(litLengthSum); /* suppress unused variable warning on some environments */
|
||||
while (send-sp > 0) {
|
||||
ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);
|
||||
size_t n;
|
||||
for (n=0; n<nbSeqs; n++) {
|
||||
const ZSTD_sequenceLength seqLen = ZSTD_getSequenceLength(seqStore, sequences+n);
|
||||
litLengthSum += seqLen.litLength;
|
||||
matchLengthSum += seqLen.matchLength;
|
||||
sp++;
|
||||
}
|
||||
assert(litLengthSum <= litSize);
|
||||
if (!lastSequence) {
|
||||
DEBUGLOG(5, "ZSTD_seqDecompressedSize: %u sequences from %p: %u literals + %u matchlength",
|
||||
(unsigned)nbSeqs, (const void*)sequences,
|
||||
(unsigned)litLengthSum, (unsigned)matchLengthSum);
|
||||
if (!lastSubBlock)
|
||||
assert(litLengthSum == litSize);
|
||||
}
|
||||
else
|
||||
assert(litLengthSum <= litSize);
|
||||
(void)litLengthSum;
|
||||
return matchLengthSum + litSize;
|
||||
}
|
||||
|
||||
@@ -180,14 +180,14 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
||||
/* Sequences Header */
|
||||
RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
|
||||
dstSize_tooSmall, "");
|
||||
if (nbSeq < 0x7F)
|
||||
if (nbSeq < 128)
|
||||
*op++ = (BYTE)nbSeq;
|
||||
else if (nbSeq < LONGNBSEQ)
|
||||
op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
|
||||
else
|
||||
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
||||
if (nbSeq==0) {
|
||||
return op - ostart;
|
||||
return (size_t)(op - ostart);
|
||||
}
|
||||
|
||||
/* seqHead : flags for FSE encoding type */
|
||||
@@ -209,7 +209,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
||||
}
|
||||
|
||||
{ size_t const bitstreamSize = ZSTD_encodeSequences(
|
||||
op, oend - op,
|
||||
op, (size_t)(oend - op),
|
||||
fseTables->matchlengthCTable, mlCode,
|
||||
fseTables->offcodeCTable, ofCode,
|
||||
fseTables->litlengthCTable, llCode,
|
||||
@@ -253,7 +253,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
||||
#endif
|
||||
|
||||
*entropyWritten = 1;
|
||||
return op - ostart;
|
||||
return (size_t)(op - ostart);
|
||||
}
|
||||
|
||||
/** ZSTD_compressSubBlock() :
|
||||
@@ -279,7 +279,8 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
||||
litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);
|
||||
{ size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,
|
||||
&entropyMetadata->hufMetadata, literals, litSize,
|
||||
op, oend-op, bmi2, writeLitEntropy, litEntropyWritten);
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeLitEntropy, litEntropyWritten);
|
||||
FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");
|
||||
if (cLitSize == 0) return 0;
|
||||
op += cLitSize;
|
||||
@@ -289,18 +290,18 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
||||
sequences, nbSeq,
|
||||
llCode, mlCode, ofCode,
|
||||
cctxParams,
|
||||
op, oend-op,
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeSeqEntropy, seqEntropyWritten);
|
||||
FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");
|
||||
if (cSeqSize == 0) return 0;
|
||||
op += cSeqSize;
|
||||
}
|
||||
/* Write block header */
|
||||
{ size_t cSize = (op-ostart)-ZSTD_blockHeaderSize;
|
||||
{ size_t cSize = (size_t)(op-ostart) - ZSTD_blockHeaderSize;
|
||||
U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
|
||||
MEM_writeLE24(ostart, cBlockHeader24);
|
||||
}
|
||||
return op-ostart;
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,
|
||||
@@ -389,7 +390,11 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
|
||||
return cSeqSizeEstimate + sequencesSectionHeaderSize;
|
||||
}
|
||||
|
||||
static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||
typedef struct {
|
||||
size_t estLitSize;
|
||||
size_t estBlockSize;
|
||||
} EstimatedBlockSize;
|
||||
static EstimatedBlockSize ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||
const BYTE* ofCodeTable,
|
||||
const BYTE* llCodeTable,
|
||||
const BYTE* mlCodeTable,
|
||||
@@ -397,15 +402,17 @@ static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||
const ZSTD_entropyCTables_t* entropy,
|
||||
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
||||
void* workspace, size_t wkspSize,
|
||||
int writeLitEntropy, int writeSeqEntropy) {
|
||||
size_t cSizeEstimate = 0;
|
||||
cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize,
|
||||
&entropy->huf, &entropyMetadata->hufMetadata,
|
||||
workspace, wkspSize, writeLitEntropy);
|
||||
cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
|
||||
int writeLitEntropy, int writeSeqEntropy)
|
||||
{
|
||||
EstimatedBlockSize ebs;
|
||||
ebs.estLitSize = ZSTD_estimateSubBlockSize_literal(literals, litSize,
|
||||
&entropy->huf, &entropyMetadata->hufMetadata,
|
||||
workspace, wkspSize, writeLitEntropy);
|
||||
ebs.estBlockSize = ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
|
||||
nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
|
||||
workspace, wkspSize, writeSeqEntropy);
|
||||
return cSizeEstimate + ZSTD_blockHeaderSize;
|
||||
ebs.estBlockSize += ebs.estLitSize + ZSTD_blockHeaderSize;
|
||||
return ebs;
|
||||
}
|
||||
|
||||
static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)
|
||||
@@ -419,13 +426,56 @@ static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMe
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t countLiterals(seqStore_t const* seqStore, const seqDef* sp, size_t seqCount)
|
||||
{
|
||||
size_t n, total = 0;
|
||||
assert(sp != NULL);
|
||||
for (n=0; n<seqCount; n++) {
|
||||
total += ZSTD_getSequenceLength(seqStore, sp+n).litLength;
|
||||
}
|
||||
DEBUGLOG(6, "countLiterals for %zu sequences from %p => %zu bytes", seqCount, (const void*)sp, total);
|
||||
return total;
|
||||
}
|
||||
|
||||
#define BYTESCALE 256
|
||||
|
||||
static size_t sizeBlockSequences(const seqDef* sp, size_t nbSeqs,
|
||||
size_t targetBudget, size_t avgLitCost, size_t avgSeqCost,
|
||||
int firstSubBlock)
|
||||
{
|
||||
size_t n, budget = 0, inSize=0;
|
||||
/* entropy headers */
|
||||
size_t const headerSize = (size_t)firstSubBlock * 120 * BYTESCALE; /* generous estimate */
|
||||
assert(firstSubBlock==0 || firstSubBlock==1);
|
||||
budget += headerSize;
|
||||
|
||||
/* first sequence => at least one sequence*/
|
||||
budget += sp[0].litLength * avgLitCost + avgSeqCost;
|
||||
if (budget > targetBudget) return 1;
|
||||
inSize = sp[0].litLength + (sp[0].mlBase+MINMATCH);
|
||||
|
||||
/* loop over sequences */
|
||||
for (n=1; n<nbSeqs; n++) {
|
||||
size_t currentCost = sp[n].litLength * avgLitCost + avgSeqCost;
|
||||
budget += currentCost;
|
||||
inSize += sp[n].litLength + (sp[n].mlBase+MINMATCH);
|
||||
/* stop when sub-block budget is reached */
|
||||
if ( (budget > targetBudget)
|
||||
/* though continue to expand until the sub-block is deemed compressible */
|
||||
&& (budget < inSize * BYTESCALE) )
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/** ZSTD_compressSubBlock_multi() :
|
||||
* Breaks super-block into multiple sub-blocks and compresses them.
|
||||
* Entropy will be written to the first block.
|
||||
* The following blocks will use repeat mode to compress.
|
||||
* All sub-blocks are compressed blocks (no raw or rle blocks).
|
||||
* @return : compressed size of the super block (which is multiple ZSTD blocks)
|
||||
* Or 0 if it failed to compress. */
|
||||
* Entropy will be written into the first block.
|
||||
* The following blocks use repeat_mode to compress.
|
||||
* Sub-blocks are all compressed, except the last one when beneficial.
|
||||
* @return : compressed size of the super block (which features multiple ZSTD blocks)
|
||||
* or 0 if it failed to compress. */
|
||||
static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
const ZSTD_compressedBlockState_t* prevCBlock,
|
||||
ZSTD_compressedBlockState_t* nextCBlock,
|
||||
@@ -438,10 +488,12 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
{
|
||||
const seqDef* const sstart = seqStorePtr->sequencesStart;
|
||||
const seqDef* const send = seqStorePtr->sequences;
|
||||
const seqDef* sp = sstart;
|
||||
const seqDef* sp = sstart; /* tracks progresses within seqStorePtr->sequences */
|
||||
size_t const nbSeqs = (size_t)(send - sstart);
|
||||
const BYTE* const lstart = seqStorePtr->litStart;
|
||||
const BYTE* const lend = seqStorePtr->lit;
|
||||
const BYTE* lp = lstart;
|
||||
size_t const nbLiterals = (size_t)(lend - lstart);
|
||||
BYTE const* ip = (BYTE const*)src;
|
||||
BYTE const* const iend = ip + srcSize;
|
||||
BYTE* const ostart = (BYTE*)dst;
|
||||
@@ -450,96 +502,152 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
const BYTE* llCodePtr = seqStorePtr->llCode;
|
||||
const BYTE* mlCodePtr = seqStorePtr->mlCode;
|
||||
const BYTE* ofCodePtr = seqStorePtr->ofCode;
|
||||
size_t targetCBlockSize = cctxParams->targetCBlockSize;
|
||||
size_t litSize, seqCount;
|
||||
int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed;
|
||||
size_t const minTarget = ZSTD_TARGETCBLOCKSIZE_MIN; /* enforce minimum size, to reduce undesirable side effects */
|
||||
size_t const targetCBlockSize = MAX(minTarget, cctxParams->targetCBlockSize);
|
||||
int writeLitEntropy = (entropyMetadata->hufMetadata.hType == set_compressed);
|
||||
int writeSeqEntropy = 1;
|
||||
int lastSequence = 0;
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)",
|
||||
(unsigned)(lend-lp), (unsigned)(send-sstart));
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi (srcSize=%u, litSize=%u, nbSeq=%u)",
|
||||
(unsigned)srcSize, (unsigned)(lend-lstart), (unsigned)(send-sstart));
|
||||
|
||||
litSize = 0;
|
||||
seqCount = 0;
|
||||
do {
|
||||
size_t cBlockSizeEstimate = 0;
|
||||
if (sstart == send) {
|
||||
lastSequence = 1;
|
||||
} else {
|
||||
const seqDef* const sequence = sp + seqCount;
|
||||
lastSequence = sequence == send - 1;
|
||||
litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength;
|
||||
seqCount++;
|
||||
/* let's start by a general estimation for the full block */
|
||||
if (nbSeqs > 0) {
|
||||
EstimatedBlockSize const ebs =
|
||||
ZSTD_estimateSubBlockSize(lp, nbLiterals,
|
||||
ofCodePtr, llCodePtr, mlCodePtr, nbSeqs,
|
||||
&nextCBlock->entropy, entropyMetadata,
|
||||
workspace, wkspSize,
|
||||
writeLitEntropy, writeSeqEntropy);
|
||||
/* quick estimation */
|
||||
size_t const avgLitCost = nbLiterals ? (ebs.estLitSize * BYTESCALE) / nbLiterals : BYTESCALE;
|
||||
size_t const avgSeqCost = ((ebs.estBlockSize - ebs.estLitSize) * BYTESCALE) / nbSeqs;
|
||||
const size_t nbSubBlocks = MAX((ebs.estBlockSize + (targetCBlockSize/2)) / targetCBlockSize, 1);
|
||||
size_t n, avgBlockBudget, blockBudgetSupp=0;
|
||||
avgBlockBudget = (ebs.estBlockSize * BYTESCALE) / nbSubBlocks;
|
||||
DEBUGLOG(5, "estimated fullblock size=%u bytes ; avgLitCost=%.2f ; avgSeqCost=%.2f ; targetCBlockSize=%u, nbSubBlocks=%u ; avgBlockBudget=%.0f bytes",
|
||||
(unsigned)ebs.estBlockSize, (double)avgLitCost/BYTESCALE, (double)avgSeqCost/BYTESCALE,
|
||||
(unsigned)targetCBlockSize, (unsigned)nbSubBlocks, (double)avgBlockBudget/BYTESCALE);
|
||||
/* simplification: if estimates states that the full superblock doesn't compress, just bail out immediately
|
||||
* this will result in the production of a single uncompressed block covering @srcSize.*/
|
||||
if (ebs.estBlockSize > srcSize) return 0;
|
||||
|
||||
/* compress and write sub-blocks */
|
||||
assert(nbSubBlocks>0);
|
||||
for (n=0; n < nbSubBlocks-1; n++) {
|
||||
/* determine nb of sequences for current sub-block + nbLiterals from next sequence */
|
||||
size_t const seqCount = sizeBlockSequences(sp, (size_t)(send-sp),
|
||||
avgBlockBudget + blockBudgetSupp, avgLitCost, avgSeqCost, n==0);
|
||||
/* if reached last sequence : break to last sub-block (simplification) */
|
||||
assert(seqCount <= (size_t)(send-sp));
|
||||
if (sp + seqCount == send) break;
|
||||
assert(seqCount > 0);
|
||||
/* compress sub-block */
|
||||
{ int litEntropyWritten = 0;
|
||||
int seqEntropyWritten = 0;
|
||||
size_t litSize = countLiterals(seqStorePtr, sp, seqCount);
|
||||
const size_t decompressedSize =
|
||||
ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 0);
|
||||
size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||
sp, seqCount,
|
||||
lp, litSize,
|
||||
llCodePtr, mlCodePtr, ofCodePtr,
|
||||
cctxParams,
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||
&litEntropyWritten, &seqEntropyWritten,
|
||||
0);
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||
|
||||
/* check compressibility, update state components */
|
||||
if (cSize > 0 && cSize < decompressedSize) {
|
||||
DEBUGLOG(5, "Committed sub-block compressing %u bytes => %u bytes",
|
||||
(unsigned)decompressedSize, (unsigned)cSize);
|
||||
assert(ip + decompressedSize <= iend);
|
||||
ip += decompressedSize;
|
||||
lp += litSize;
|
||||
op += cSize;
|
||||
llCodePtr += seqCount;
|
||||
mlCodePtr += seqCount;
|
||||
ofCodePtr += seqCount;
|
||||
/* Entropy only needs to be written once */
|
||||
if (litEntropyWritten) {
|
||||
writeLitEntropy = 0;
|
||||
}
|
||||
if (seqEntropyWritten) {
|
||||
writeSeqEntropy = 0;
|
||||
}
|
||||
sp += seqCount;
|
||||
blockBudgetSupp = 0;
|
||||
} }
|
||||
/* otherwise : do not compress yet, coalesce current sub-block with following one */
|
||||
}
|
||||
if (lastSequence) {
|
||||
assert(lp <= lend);
|
||||
assert(litSize <= (size_t)(lend - lp));
|
||||
litSize = (size_t)(lend - lp);
|
||||
}
|
||||
/* I think there is an optimization opportunity here.
|
||||
* Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful
|
||||
* since it recalculates estimate from scratch.
|
||||
* For example, it would recount literal distribution and symbol codes every time.
|
||||
*/
|
||||
cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount,
|
||||
&nextCBlock->entropy, entropyMetadata,
|
||||
workspace, wkspSize, writeLitEntropy, writeSeqEntropy);
|
||||
if (cBlockSizeEstimate > targetCBlockSize || lastSequence) {
|
||||
int litEntropyWritten = 0;
|
||||
int seqEntropyWritten = 0;
|
||||
const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence);
|
||||
const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||
sp, seqCount,
|
||||
lp, litSize,
|
||||
llCodePtr, mlCodePtr, ofCodePtr,
|
||||
cctxParams,
|
||||
op, oend-op,
|
||||
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||
&litEntropyWritten, &seqEntropyWritten,
|
||||
lastBlock && lastSequence);
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||
if (cSize > 0 && cSize < decompressedSize) {
|
||||
DEBUGLOG(5, "Committed the sub-block");
|
||||
assert(ip + decompressedSize <= iend);
|
||||
ip += decompressedSize;
|
||||
sp += seqCount;
|
||||
lp += litSize;
|
||||
op += cSize;
|
||||
llCodePtr += seqCount;
|
||||
mlCodePtr += seqCount;
|
||||
ofCodePtr += seqCount;
|
||||
litSize = 0;
|
||||
seqCount = 0;
|
||||
/* Entropy only needs to be written once */
|
||||
if (litEntropyWritten) {
|
||||
writeLitEntropy = 0;
|
||||
}
|
||||
if (seqEntropyWritten) {
|
||||
writeSeqEntropy = 0;
|
||||
}
|
||||
} /* if (nbSeqs > 0) */
|
||||
|
||||
/* write last block */
|
||||
DEBUGLOG(5, "Generate last sub-block: %u sequences remaining", (unsigned)(send - sp));
|
||||
{ int litEntropyWritten = 0;
|
||||
int seqEntropyWritten = 0;
|
||||
size_t litSize = (size_t)(lend - lp);
|
||||
size_t seqCount = (size_t)(send - sp);
|
||||
const size_t decompressedSize =
|
||||
ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 1);
|
||||
size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||
sp, seqCount,
|
||||
lp, litSize,
|
||||
llCodePtr, mlCodePtr, ofCodePtr,
|
||||
cctxParams,
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||
&litEntropyWritten, &seqEntropyWritten,
|
||||
lastBlock);
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||
|
||||
/* update pointers, the nb of literals borrowed from next sequence must be preserved */
|
||||
if (cSize > 0 && cSize < decompressedSize) {
|
||||
DEBUGLOG(5, "Last sub-block compressed %u bytes => %u bytes",
|
||||
(unsigned)decompressedSize, (unsigned)cSize);
|
||||
assert(ip + decompressedSize <= iend);
|
||||
ip += decompressedSize;
|
||||
lp += litSize;
|
||||
op += cSize;
|
||||
llCodePtr += seqCount;
|
||||
mlCodePtr += seqCount;
|
||||
ofCodePtr += seqCount;
|
||||
/* Entropy only needs to be written once */
|
||||
if (litEntropyWritten) {
|
||||
writeLitEntropy = 0;
|
||||
}
|
||||
if (seqEntropyWritten) {
|
||||
writeSeqEntropy = 0;
|
||||
}
|
||||
sp += seqCount;
|
||||
}
|
||||
} while (!lastSequence);
|
||||
}
|
||||
|
||||
|
||||
if (writeLitEntropy) {
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");
|
||||
DEBUGLOG(5, "Literal entropy tables were never written");
|
||||
ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
|
||||
}
|
||||
if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
|
||||
/* If we haven't written our entropy tables, then we've violated our contract and
|
||||
* must emit an uncompressed block.
|
||||
*/
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten");
|
||||
DEBUGLOG(5, "Sequence entropy tables were never written => cancel, emit an uncompressed block");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ip < iend) {
|
||||
size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock);
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip));
|
||||
/* some data left : last part of the block sent uncompressed */
|
||||
size_t const rSize = (size_t)((iend - ip));
|
||||
size_t const cSize = ZSTD_noCompressBlock(op, (size_t)(oend - op), ip, rSize, lastBlock);
|
||||
DEBUGLOG(5, "Generate last uncompressed sub-block of %u bytes", (unsigned)(rSize));
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
|
||||
assert(cSize != 0);
|
||||
op += cSize;
|
||||
/* We have to regenerate the repcodes because we've skipped some sequences */
|
||||
if (sp < send) {
|
||||
seqDef const* seq;
|
||||
const seqDef* seq;
|
||||
repcodes_t rep;
|
||||
ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));
|
||||
for (seq = sstart; seq < sp; ++seq) {
|
||||
@@ -548,14 +656,17 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep));
|
||||
}
|
||||
}
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");
|
||||
return op-ostart;
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed all subBlocks: total compressed size = %u",
|
||||
(unsigned)(op-ostart));
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
|
||||
void* dst, size_t dstCapacity,
|
||||
void const* src, size_t srcSize,
|
||||
unsigned lastBlock) {
|
||||
const void* src, size_t srcSize,
|
||||
unsigned lastBlock)
|
||||
{
|
||||
ZSTD_entropyCTablesMetadata_t entropyMetadata;
|
||||
|
||||
FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,
|
||||
|
||||
+141
-71
@@ -14,7 +14,9 @@
|
||||
/*-*************************************
|
||||
* Dependencies
|
||||
***************************************/
|
||||
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */
|
||||
#include "../common/zstd_internal.h"
|
||||
#include "../common/portability_macros.h"
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
@@ -44,8 +46,9 @@ extern "C" {
|
||||
***************************************/
|
||||
typedef enum {
|
||||
ZSTD_cwksp_alloc_objects,
|
||||
ZSTD_cwksp_alloc_buffers,
|
||||
ZSTD_cwksp_alloc_aligned
|
||||
ZSTD_cwksp_alloc_aligned_init_once,
|
||||
ZSTD_cwksp_alloc_aligned,
|
||||
ZSTD_cwksp_alloc_buffers
|
||||
} ZSTD_cwksp_alloc_phase_e;
|
||||
|
||||
/**
|
||||
@@ -98,8 +101,8 @@ typedef enum {
|
||||
*
|
||||
* Workspace Layout:
|
||||
*
|
||||
* [ ... workspace ... ]
|
||||
* [objects][tables ... ->] free space [<- ... aligned][<- ... buffers]
|
||||
* [ ... workspace ... ]
|
||||
* [objects][tables ->] free space [<- buffers][<- aligned][<- init once]
|
||||
*
|
||||
* The various objects that live in the workspace are divided into the
|
||||
* following categories, and are allocated separately:
|
||||
@@ -123,9 +126,18 @@ typedef enum {
|
||||
* uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
|
||||
* Their sizes depend on the cparams. These tables are 64-byte aligned.
|
||||
*
|
||||
* - Aligned: these buffers are used for various purposes that require 4 byte
|
||||
* alignment, but don't require any initialization before they're used. These
|
||||
* buffers are each aligned to 64 bytes.
|
||||
* - Init once: these buffers require to be initialized at least once before
|
||||
* use. They should be used when we want to skip memory initialization
|
||||
* while not triggering memory checkers (like Valgrind) when reading from
|
||||
* from this memory without writing to it first.
|
||||
* These buffers should be used carefully as they might contain data
|
||||
* from previous compressions.
|
||||
* Buffers are aligned to 64 bytes.
|
||||
*
|
||||
* - Aligned: these buffers don't require any initialization before they're
|
||||
* used. The user of the buffer should make sure they write into a buffer
|
||||
* location before reading from it.
|
||||
* Buffers are aligned to 64 bytes.
|
||||
*
|
||||
* - Buffers: these buffers are used for various purposes that don't require
|
||||
* any alignment or initialization before they're used. This means they can
|
||||
@@ -137,8 +149,9 @@ typedef enum {
|
||||
* correctly packed into the workspace buffer. That order is:
|
||||
*
|
||||
* 1. Objects
|
||||
* 2. Buffers
|
||||
* 3. Aligned/Tables
|
||||
* 2. Init once / Tables
|
||||
* 3. Aligned / Tables
|
||||
* 4. Buffers / Tables
|
||||
*
|
||||
* Attempts to reserve objects of different types out of order will fail.
|
||||
*/
|
||||
@@ -150,6 +163,7 @@ typedef struct {
|
||||
void* tableEnd;
|
||||
void* tableValidEnd;
|
||||
void* allocStart;
|
||||
void* initOnceStart;
|
||||
|
||||
BYTE allocFailed;
|
||||
int workspaceOversizedDuration;
|
||||
@@ -162,6 +176,7 @@ typedef struct {
|
||||
***************************************/
|
||||
|
||||
MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws);
|
||||
MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws);
|
||||
|
||||
MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
|
||||
(void)ws;
|
||||
@@ -171,6 +186,21 @@ MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
|
||||
assert(ws->tableEnd <= ws->allocStart);
|
||||
assert(ws->tableValidEnd <= ws->allocStart);
|
||||
assert(ws->allocStart <= ws->workspaceEnd);
|
||||
assert(ws->initOnceStart <= ZSTD_cwksp_initialAllocStart(ws));
|
||||
assert(ws->workspace <= ws->initOnceStart);
|
||||
#if ZSTD_MEMORY_SANITIZER
|
||||
{
|
||||
intptr_t const offset = __msan_test_shadow(ws->initOnceStart,
|
||||
(U8*)ZSTD_cwksp_initialAllocStart(ws) - (U8*)ws->initOnceStart);
|
||||
(void)offset;
|
||||
#if defined(ZSTD_MSAN_PRINT)
|
||||
if(offset!=-1) {
|
||||
__msan_print_shadow((U8*)ws->initOnceStart + offset - 8, 32);
|
||||
}
|
||||
#endif
|
||||
assert(offset==-1);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,14 +247,10 @@ MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
|
||||
* for internal purposes (currently only alignment).
|
||||
*/
|
||||
MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
|
||||
/* For alignment, the wksp will always allocate an additional n_1=[1, 64] bytes
|
||||
* to align the beginning of tables section, as well as another n_2=[0, 63] bytes
|
||||
* to align the beginning of the aligned section.
|
||||
*
|
||||
* n_1 + n_2 == 64 bytes if the cwksp is freshly allocated, due to tables and
|
||||
* aligneds being sized in multiples of 64 bytes.
|
||||
/* For alignment, the wksp will always allocate an additional 2*ZSTD_CWKSP_ALIGNMENT_BYTES
|
||||
* bytes to align the beginning of tables section and end of buffers;
|
||||
*/
|
||||
size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES;
|
||||
size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2;
|
||||
return slackSpace;
|
||||
}
|
||||
|
||||
@@ -237,10 +263,18 @@ MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignByt
|
||||
size_t const alignBytesMask = alignBytes - 1;
|
||||
size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
|
||||
assert((alignBytes & alignBytesMask) == 0);
|
||||
assert(bytes != ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||
assert(bytes < alignBytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial value for allocStart which is used to determine the position from
|
||||
* which we can allocate from the end of the workspace.
|
||||
*/
|
||||
MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws) {
|
||||
return (void*)((size_t)ws->workspaceEnd & ~(ZSTD_CWKSP_ALIGNMENT_BYTES-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function. Do not use directly.
|
||||
* Reserves the given number of bytes within the aligned/buffer segment of the wksp,
|
||||
@@ -281,27 +315,16 @@ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase
|
||||
{
|
||||
assert(phase >= ws->phase);
|
||||
if (phase > ws->phase) {
|
||||
/* Going from allocating objects to allocating buffers */
|
||||
if (ws->phase < ZSTD_cwksp_alloc_buffers &&
|
||||
phase >= ZSTD_cwksp_alloc_buffers) {
|
||||
/* Going from allocating objects to allocating initOnce / tables */
|
||||
if (ws->phase < ZSTD_cwksp_alloc_aligned_init_once &&
|
||||
phase >= ZSTD_cwksp_alloc_aligned_init_once) {
|
||||
ws->tableValidEnd = ws->objectEnd;
|
||||
}
|
||||
ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
|
||||
|
||||
/* Going from allocating buffers to allocating aligneds/tables */
|
||||
if (ws->phase < ZSTD_cwksp_alloc_aligned &&
|
||||
phase >= ZSTD_cwksp_alloc_aligned) {
|
||||
{ /* Align the start of the "aligned" to 64 bytes. Use [1, 64] bytes. */
|
||||
size_t const bytesToAlign =
|
||||
ZSTD_CWKSP_ALIGNMENT_BYTES - ZSTD_cwksp_bytes_to_align_ptr(ws->allocStart, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||
DEBUGLOG(5, "reserving aligned alignment addtl space: %zu", bytesToAlign);
|
||||
ZSTD_STATIC_ASSERT((ZSTD_CWKSP_ALIGNMENT_BYTES & (ZSTD_CWKSP_ALIGNMENT_BYTES - 1)) == 0); /* power of 2 */
|
||||
RETURN_ERROR_IF(!ZSTD_cwksp_reserve_internal_buffer_space(ws, bytesToAlign),
|
||||
memory_allocation, "aligned phase - alignment initial allocation failed!");
|
||||
}
|
||||
{ /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
|
||||
void* const alloc = ws->objectEnd;
|
||||
void *const alloc = ws->objectEnd;
|
||||
size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||
void* const objectEnd = (BYTE*)alloc + bytesToAlign;
|
||||
void *const objectEnd = (BYTE *) alloc + bytesToAlign;
|
||||
DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
|
||||
RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation,
|
||||
"table phase - alignment initial allocation failed!");
|
||||
@@ -309,7 +332,9 @@ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase
|
||||
ws->tableEnd = objectEnd; /* table area starts being empty */
|
||||
if (ws->tableValidEnd < ws->tableEnd) {
|
||||
ws->tableValidEnd = ws->tableEnd;
|
||||
} } }
|
||||
}
|
||||
}
|
||||
}
|
||||
ws->phase = phase;
|
||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||
}
|
||||
@@ -321,7 +346,7 @@ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase
|
||||
*/
|
||||
MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr)
|
||||
{
|
||||
return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd);
|
||||
return (ptr != NULL) && (ws->workspace <= ptr) && (ptr < ws->workspaceEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,6 +391,36 @@ MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes)
|
||||
return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
|
||||
* This memory has been initialized at least once in the past.
|
||||
* This doesn't mean it has been initialized this time, and it might contain data from previous
|
||||
* operations.
|
||||
* The main usage is for algorithms that might need read access into uninitialized memory.
|
||||
* The algorithm must maintain safety under these conditions and must make sure it doesn't
|
||||
* leak any of the past data (directly or in side channels).
|
||||
*/
|
||||
MEM_STATIC void* ZSTD_cwksp_reserve_aligned_init_once(ZSTD_cwksp* ws, size_t bytes)
|
||||
{
|
||||
size_t const alignedBytes = ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||
void* ptr = ZSTD_cwksp_reserve_internal(ws, alignedBytes, ZSTD_cwksp_alloc_aligned_init_once);
|
||||
assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
|
||||
if(ptr && ptr < ws->initOnceStart) {
|
||||
/* We assume the memory following the current allocation is either:
|
||||
* 1. Not usable as initOnce memory (end of workspace)
|
||||
* 2. Another initOnce buffer that has been allocated before (and so was previously memset)
|
||||
* 3. An ASAN redzone, in which case we don't want to write on it
|
||||
* For these reasons it should be fine to not explicitly zero every byte up to ws->initOnceStart.
|
||||
* Note that we assume here that MSAN and ASAN cannot run in the same time. */
|
||||
ZSTD_memset(ptr, 0, MIN((size_t)((U8*)ws->initOnceStart - (U8*)ptr), alignedBytes));
|
||||
ws->initOnceStart = ptr;
|
||||
}
|
||||
#if ZSTD_MEMORY_SANITIZER
|
||||
assert(__msan_test_shadow(ptr, bytes) == -1);
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
|
||||
*/
|
||||
@@ -379,18 +434,22 @@ MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes)
|
||||
|
||||
/**
|
||||
* Aligned on 64 bytes. These buffers have the special property that
|
||||
* their values remain constrained, allowing us to re-use them without
|
||||
* their values remain constrained, allowing us to reuse them without
|
||||
* memset()-ing them.
|
||||
*/
|
||||
MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes)
|
||||
{
|
||||
const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
|
||||
const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned_init_once;
|
||||
void* alloc;
|
||||
void* end;
|
||||
void* top;
|
||||
|
||||
if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
|
||||
return NULL;
|
||||
/* We can only start allocating tables after we are done reserving space for objects at the
|
||||
* start of the workspace */
|
||||
if(ws->phase < phase) {
|
||||
if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
alloc = ws->tableEnd;
|
||||
end = (BYTE *)alloc + bytes;
|
||||
@@ -467,13 +526,21 @@ MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws)
|
||||
DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty");
|
||||
|
||||
#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
|
||||
/* To validate that the table re-use logic is sound, and that we don't
|
||||
/* To validate that the table reuse logic is sound, and that we don't
|
||||
* access table space that we haven't cleaned, we re-"poison" the table
|
||||
* space every time we mark it dirty. */
|
||||
* space every time we mark it dirty.
|
||||
* Since tableValidEnd space and initOnce space may overlap we don't poison
|
||||
* the initOnce portion as it break its promise. This means that this poisoning
|
||||
* check isn't always applied fully. */
|
||||
{
|
||||
size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
|
||||
assert(__msan_test_shadow(ws->objectEnd, size) == -1);
|
||||
__msan_poison(ws->objectEnd, size);
|
||||
if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) {
|
||||
__msan_poison(ws->objectEnd, size);
|
||||
} else {
|
||||
assert(ws->initOnceStart >= ws->objectEnd);
|
||||
__msan_poison(ws->objectEnd, (BYTE*)ws->initOnceStart - (BYTE*)ws->objectEnd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -536,13 +603,16 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
|
||||
DEBUGLOG(4, "cwksp: clearing!");
|
||||
|
||||
#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
|
||||
/* To validate that the context re-use logic is sound, and that we don't
|
||||
/* To validate that the context reuse logic is sound, and that we don't
|
||||
* access stuff that this compression hasn't initialized, we re-"poison"
|
||||
* the workspace (or at least the non-static, non-table parts of it)
|
||||
* every time we start a new compression. */
|
||||
* the workspace except for the areas in which we expect memory reuse
|
||||
* without initialization (objects, valid tables area and init once
|
||||
* memory). */
|
||||
{
|
||||
size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd;
|
||||
__msan_poison(ws->tableValidEnd, size);
|
||||
if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) {
|
||||
size_t size = (BYTE*)ws->initOnceStart - (BYTE*)ws->tableValidEnd;
|
||||
__msan_poison(ws->tableValidEnd, size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -558,14 +628,23 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
|
||||
#endif
|
||||
|
||||
ws->tableEnd = ws->objectEnd;
|
||||
ws->allocStart = ws->workspaceEnd;
|
||||
ws->allocStart = ZSTD_cwksp_initialAllocStart(ws);
|
||||
ws->allocFailed = 0;
|
||||
if (ws->phase > ZSTD_cwksp_alloc_buffers) {
|
||||
ws->phase = ZSTD_cwksp_alloc_buffers;
|
||||
if (ws->phase > ZSTD_cwksp_alloc_aligned_init_once) {
|
||||
ws->phase = ZSTD_cwksp_alloc_aligned_init_once;
|
||||
}
|
||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
|
||||
return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
|
||||
return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
|
||||
+ (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* The provided workspace takes ownership of the buffer [start, start+size).
|
||||
* Any existing values in the workspace are ignored (the previously managed
|
||||
@@ -578,6 +657,7 @@ MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_c
|
||||
ws->workspaceEnd = (BYTE*)start + size;
|
||||
ws->objectEnd = ws->workspace;
|
||||
ws->tableValidEnd = ws->objectEnd;
|
||||
ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
|
||||
ws->phase = ZSTD_cwksp_alloc_objects;
|
||||
ws->isStatic = isStatic;
|
||||
ZSTD_cwksp_clear(ws);
|
||||
@@ -596,6 +676,11 @@ MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem
|
||||
MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
|
||||
void *ptr = ws->workspace;
|
||||
DEBUGLOG(4, "cwksp: freeing workspace");
|
||||
#if ZSTD_MEMORY_SANITIZER && !defined(ZSTD_MSAN_DONT_POISON_WORKSPACE)
|
||||
if (ptr != NULL && customMem.customFree != NULL) {
|
||||
__msan_unpoison(ptr, ZSTD_cwksp_sizeof(ws));
|
||||
}
|
||||
#endif
|
||||
ZSTD_memset(ws, 0, sizeof(ZSTD_cwksp));
|
||||
ZSTD_customFree(ptr, customMem);
|
||||
}
|
||||
@@ -609,15 +694,6 @@ MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
|
||||
ZSTD_memset(src, 0, sizeof(ZSTD_cwksp));
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
|
||||
return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
|
||||
return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
|
||||
+ (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
|
||||
}
|
||||
|
||||
MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
||||
return ws->allocFailed;
|
||||
}
|
||||
@@ -630,17 +706,11 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
||||
* Returns if the estimated space needed for a wksp is within an acceptable limit of the
|
||||
* actual amount of space used.
|
||||
*/
|
||||
MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp* const ws,
|
||||
size_t const estimatedSpace, int resizedWorkspace) {
|
||||
if (resizedWorkspace) {
|
||||
/* Resized/newly allocated wksp should have exact bounds */
|
||||
return ZSTD_cwksp_used(ws) == estimatedSpace;
|
||||
} else {
|
||||
/* Due to alignment, when reusing a workspace, we can actually consume 63 fewer or more bytes
|
||||
* than estimatedSpace. See the comments in zstd_cwksp.h for details.
|
||||
*/
|
||||
return (ZSTD_cwksp_used(ws) >= estimatedSpace - 63) && (ZSTD_cwksp_used(ws) <= estimatedSpace + 63);
|
||||
}
|
||||
MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp *const ws, size_t const estimatedSpace) {
|
||||
/* We have an alignment space between objects and tables between tables and buffers, so we can have up to twice
|
||||
* the alignment bytes difference between estimation and actual usage */
|
||||
return (estimatedSpace - ZSTD_cwksp_slack_space_required()) <= ZSTD_cwksp_used(ws) &&
|
||||
ZSTD_cwksp_used(ws) <= estimatedSpace;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,11 @@
|
||||
#include "zstd_compress_internal.h"
|
||||
#include "zstd_double_fast.h"
|
||||
|
||||
static void ZSTD_fillDoubleHashTableForCDict(ZSTD_matchState_t* ms,
|
||||
#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
|
||||
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_fillDoubleHashTableForCDict(ZSTD_matchState_t* ms,
|
||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm)
|
||||
{
|
||||
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||
@@ -47,7 +51,9 @@ static void ZSTD_fillDoubleHashTableForCDict(ZSTD_matchState_t* ms,
|
||||
} }
|
||||
}
|
||||
|
||||
static void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms,
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms,
|
||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm)
|
||||
{
|
||||
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||
@@ -95,6 +101,7 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize, U32 const mls /* template */)
|
||||
@@ -305,6 +312,7 @@ _match_stored:
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize,
|
||||
@@ -348,8 +356,8 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||
if (ms->prefetchCDictTables) {
|
||||
size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32);
|
||||
size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32);
|
||||
PREFETCH_AREA(dictHashLong, hashTableBytes)
|
||||
PREFETCH_AREA(dictHashSmall, chainTableBytes)
|
||||
PREFETCH_AREA(dictHashLong, hashTableBytes);
|
||||
PREFETCH_AREA(dictHashSmall, chainTableBytes);
|
||||
}
|
||||
|
||||
/* init */
|
||||
@@ -589,7 +597,9 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState(
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize,
|
||||
U32 const mls /* template */)
|
||||
@@ -756,3 +766,5 @@ size_t ZSTD_compressBlock_doubleFast_extDict(
|
||||
return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */
|
||||
|
||||
@@ -18,9 +18,12 @@ extern "C" {
|
||||
#include "../common/mem.h" /* U32 */
|
||||
#include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
|
||||
|
||||
void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm,
|
||||
ZSTD_tableFillPurpose_e tfp);
|
||||
|
||||
size_t ZSTD_compressBlock_doubleFast(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
@@ -31,6 +34,14 @@ size_t ZSTD_compressBlock_doubleFast_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST ZSTD_compressBlock_doubleFast
|
||||
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE ZSTD_compressBlock_doubleFast_dictMatchState
|
||||
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT ZSTD_compressBlock_doubleFast_extDict
|
||||
#else
|
||||
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST NULL
|
||||
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE NULL
|
||||
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT NULL
|
||||
#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "zstd_compress_internal.h" /* ZSTD_hashPtr, ZSTD_count, ZSTD_storeSeq */
|
||||
#include "zstd_fast.h"
|
||||
|
||||
static void ZSTD_fillHashTableForCDict(ZSTD_matchState_t* ms,
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_fillHashTableForCDict(ZSTD_matchState_t* ms,
|
||||
const void* const end,
|
||||
ZSTD_dictTableLoadMethod_e dtlm)
|
||||
{
|
||||
@@ -46,7 +48,9 @@ static void ZSTD_fillHashTableForCDict(ZSTD_matchState_t* ms,
|
||||
} } } }
|
||||
}
|
||||
|
||||
static void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms,
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms,
|
||||
const void* const end,
|
||||
ZSTD_dictTableLoadMethod_e dtlm)
|
||||
{
|
||||
@@ -139,8 +143,9 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
|
||||
*
|
||||
* This is also the work we do at the beginning to enter the loop initially.
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
ZSTD_compressBlock_fast_noDict_generic(
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_fast_noDict_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize,
|
||||
U32 const mls, U32 const hasStep)
|
||||
@@ -456,6 +461,7 @@ size_t ZSTD_compressBlock_fast(
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_fast_dictMatchState_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize, U32 const mls, U32 const hasStep)
|
||||
@@ -502,7 +508,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
|
||||
|
||||
if (ms->prefetchCDictTables) {
|
||||
size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32);
|
||||
PREFETCH_AREA(dictHashTable, hashTableBytes)
|
||||
PREFETCH_AREA(dictHashTable, hashTableBytes);
|
||||
}
|
||||
|
||||
/* init */
|
||||
@@ -681,7 +687,9 @@ size_t ZSTD_compressBlock_fast_dictMatchState(
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize, U32 const mls, U32 const hasStep)
|
||||
{
|
||||
|
||||
+269
-197
@@ -12,13 +12,21 @@
|
||||
#include "zstd_lazy.h"
|
||||
#include "../common/bits.h" /* ZSTD_countTrailingZeros64 */
|
||||
|
||||
#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR)
|
||||
|
||||
#define kLazySkippingStep 8
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Binary Tree search
|
||||
***************************************/
|
||||
|
||||
static void
|
||||
ZSTD_updateDUBT(ZSTD_matchState_t* ms,
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_updateDUBT(ZSTD_matchState_t* ms,
|
||||
const BYTE* ip, const BYTE* iend,
|
||||
U32 mls)
|
||||
{
|
||||
@@ -61,8 +69,9 @@ ZSTD_updateDUBT(ZSTD_matchState_t* ms,
|
||||
* sort one already inserted but unsorted position
|
||||
* assumption : curr >= btlow == (curr - btmask)
|
||||
* doesn't fail */
|
||||
static void
|
||||
ZSTD_insertDUBT1(const ZSTD_matchState_t* ms,
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_insertDUBT1(const ZSTD_matchState_t* ms,
|
||||
U32 curr, const BYTE* inputEnd,
|
||||
U32 nbCompares, U32 btLow,
|
||||
const ZSTD_dictMode_e dictMode)
|
||||
@@ -150,8 +159,9 @@ ZSTD_insertDUBT1(const ZSTD_matchState_t* ms,
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ZSTD_DUBT_findBetterDictMatch (
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_DUBT_findBetterDictMatch (
|
||||
const ZSTD_matchState_t* ms,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
size_t* offsetPtr,
|
||||
@@ -228,8 +238,9 @@ ZSTD_DUBT_findBetterDictMatch (
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
size_t* offBasePtr,
|
||||
U32 const mls,
|
||||
@@ -379,8 +390,9 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
|
||||
|
||||
|
||||
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms,
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offBasePtr,
|
||||
const U32 mls /* template */,
|
||||
@@ -615,10 +627,12 @@ size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nb
|
||||
|
||||
/* Update chains up to ip (excluded)
|
||||
Assumption : always within prefix (i.e. not within extDict) */
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal(
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32 ZSTD_insertAndFindFirstIndex_internal(
|
||||
ZSTD_matchState_t* ms,
|
||||
const ZSTD_compressionParameters* const cParams,
|
||||
const BYTE* ip, U32 const mls)
|
||||
const BYTE* ip, U32 const mls, U32 const lazySkipping)
|
||||
{
|
||||
U32* const hashTable = ms->hashTable;
|
||||
const U32 hashLog = cParams->hashLog;
|
||||
@@ -633,6 +647,9 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal(
|
||||
NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
|
||||
hashTable[h] = idx;
|
||||
idx++;
|
||||
/* Stop inserting every position when in the lazy skipping mode. */
|
||||
if (lazySkipping)
|
||||
break;
|
||||
}
|
||||
|
||||
ms->nextToUpdate = target;
|
||||
@@ -641,11 +658,12 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal(
|
||||
|
||||
U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
|
||||
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||
return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
|
||||
return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch, /* lazySkipping*/ 0);
|
||||
}
|
||||
|
||||
/* inlining is important to hardwire a hot branch (template emulation) */
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_HcFindBestMatch(
|
||||
ZSTD_matchState_t* ms,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
@@ -685,7 +703,7 @@ size_t ZSTD_HcFindBestMatch(
|
||||
}
|
||||
|
||||
/* HC4 match finder */
|
||||
matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
|
||||
matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls, ms->lazySkipping);
|
||||
|
||||
for ( ; (matchIndex>=lowLimit) & (nbAttempts>0) ; nbAttempts--) {
|
||||
size_t currentMl=0;
|
||||
@@ -758,7 +776,6 @@ size_t ZSTD_HcFindBestMatch(
|
||||
* (SIMD) Row-based matchfinder
|
||||
***********************************/
|
||||
/* Constants for row-based hash */
|
||||
#define ZSTD_ROW_HASH_TAG_OFFSET 16 /* byte offset of hashes in the match state's tagTable from the beginning of a row */
|
||||
#define ZSTD_ROW_HASH_TAG_MASK ((1u << ZSTD_ROW_HASH_TAG_BITS) - 1)
|
||||
#define ZSTD_ROW_HASH_MAX_ENTRIES 64 /* absolute maximum number of entries per row, for all configurations */
|
||||
|
||||
@@ -774,39 +791,15 @@ MEM_STATIC U32 ZSTD_VecMask_next(ZSTD_VecMask val) {
|
||||
return ZSTD_countTrailingZeros64(val);
|
||||
}
|
||||
|
||||
/* ZSTD_rotateRight_*():
|
||||
* Rotates a bitfield to the right by "count" bits.
|
||||
* https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE
|
||||
U64 ZSTD_rotateRight_U64(U64 const value, U32 count) {
|
||||
assert(count < 64);
|
||||
count &= 0x3F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (U64)(value << ((0U - count) & 0x3F));
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
U32 ZSTD_rotateRight_U32(U32 const value, U32 count) {
|
||||
assert(count < 32);
|
||||
count &= 0x1F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (U32)(value << ((0U - count) & 0x1F));
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
U16 ZSTD_rotateRight_U16(U16 const value, U32 count) {
|
||||
assert(count < 16);
|
||||
count &= 0x0F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (U16)(value << ((0U - count) & 0x0F));
|
||||
}
|
||||
|
||||
/* ZSTD_row_nextIndex():
|
||||
* Returns the next index to insert at within a tagTable row, and updates the "head"
|
||||
* value to reflect the update. Essentially cycles backwards from [0, {entries per row})
|
||||
* value to reflect the update. Essentially cycles backwards from [1, {entries per row})
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextIndex(BYTE* const tagRow, U32 const rowMask) {
|
||||
U32 const next = (*tagRow - 1) & rowMask;
|
||||
*tagRow = (BYTE)next;
|
||||
return next;
|
||||
U32 next = (*tagRow-1) & rowMask;
|
||||
next += (next == 0) ? rowMask : 0; /* skip first position */
|
||||
*tagRow = (BYTE)next;
|
||||
return next;
|
||||
}
|
||||
|
||||
/* ZSTD_isAligned():
|
||||
@@ -820,7 +813,7 @@ MEM_STATIC int ZSTD_isAligned(void const* ptr, size_t align) {
|
||||
/* ZSTD_row_prefetch():
|
||||
* Performs prefetching for the hashTable and tagTable at a given row.
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, U16 const* tagTable, U32 const relRow, U32 const rowLog) {
|
||||
FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, BYTE const* tagTable, U32 const relRow, U32 const rowLog) {
|
||||
PREFETCH_L1(hashTable + relRow);
|
||||
if (rowLog >= 5) {
|
||||
PREFETCH_L1(hashTable + relRow + 16);
|
||||
@@ -839,18 +832,20 @@ FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, U16 const* ta
|
||||
* Fill up the hash cache starting at idx, prefetching up to ZSTD_ROW_HASH_CACHE_SIZE entries,
|
||||
* but not beyond iLimit.
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base,
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base,
|
||||
U32 const rowLog, U32 const mls,
|
||||
U32 idx, const BYTE* const iLimit)
|
||||
{
|
||||
U32 const* const hashTable = ms->hashTable;
|
||||
U16 const* const tagTable = ms->tagTable;
|
||||
BYTE const* const tagTable = ms->tagTable;
|
||||
U32 const hashLog = ms->rowHashLog;
|
||||
U32 const maxElemsToPrefetch = (base + idx) > iLimit ? 0 : (U32)(iLimit - (base + idx) + 1);
|
||||
U32 const lim = idx + MIN(ZSTD_ROW_HASH_CACHE_SIZE, maxElemsToPrefetch);
|
||||
|
||||
for (; idx < lim; ++idx) {
|
||||
U32 const hash = (U32)ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
|
||||
U32 const hash = (U32)ZSTD_hashPtrSalted(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt);
|
||||
U32 const row = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
|
||||
ZSTD_row_prefetch(hashTable, tagTable, row, rowLog);
|
||||
ms->hashCache[idx & ZSTD_ROW_HASH_CACHE_MASK] = hash;
|
||||
@@ -865,12 +860,15 @@ FORCE_INLINE_TEMPLATE void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const B
|
||||
* Returns the hash of base + idx, and replaces the hash in the hash cache with the byte at
|
||||
* base + idx + ZSTD_ROW_HASH_CACHE_SIZE. Also prefetches the appropriate rows from hashTable and tagTable.
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable,
|
||||
U16 const* tagTable, BYTE const* base,
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable,
|
||||
BYTE const* tagTable, BYTE const* base,
|
||||
U32 idx, U32 const hashLog,
|
||||
U32 const rowLog, U32 const mls)
|
||||
U32 const rowLog, U32 const mls,
|
||||
U64 const hashSalt)
|
||||
{
|
||||
U32 const newHash = (U32)ZSTD_hashPtr(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
|
||||
U32 const newHash = (U32)ZSTD_hashPtrSalted(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt);
|
||||
U32 const row = (newHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
|
||||
ZSTD_row_prefetch(hashTable, tagTable, row, rowLog);
|
||||
{ U32 const hash = cache[idx & ZSTD_ROW_HASH_CACHE_MASK];
|
||||
@@ -882,28 +880,29 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTab
|
||||
/* ZSTD_row_update_internalImpl():
|
||||
* Updates the hash table with positions starting from updateStartIdx until updateEndIdx.
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE void ZSTD_row_update_internalImpl(ZSTD_matchState_t* ms,
|
||||
U32 updateStartIdx, U32 const updateEndIdx,
|
||||
U32 const mls, U32 const rowLog,
|
||||
U32 const rowMask, U32 const useCache)
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_row_update_internalImpl(ZSTD_matchState_t* ms,
|
||||
U32 updateStartIdx, U32 const updateEndIdx,
|
||||
U32 const mls, U32 const rowLog,
|
||||
U32 const rowMask, U32 const useCache)
|
||||
{
|
||||
U32* const hashTable = ms->hashTable;
|
||||
U16* const tagTable = ms->tagTable;
|
||||
BYTE* const tagTable = ms->tagTable;
|
||||
U32 const hashLog = ms->rowHashLog;
|
||||
const BYTE* const base = ms->window.base;
|
||||
|
||||
DEBUGLOG(6, "ZSTD_row_update_internalImpl(): updateStartIdx=%u, updateEndIdx=%u", updateStartIdx, updateEndIdx);
|
||||
for (; updateStartIdx < updateEndIdx; ++updateStartIdx) {
|
||||
U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, updateStartIdx, hashLog, rowLog, mls)
|
||||
: (U32)ZSTD_hashPtr(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
|
||||
U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, updateStartIdx, hashLog, rowLog, mls, ms->hashSalt)
|
||||
: (U32)ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt);
|
||||
U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
|
||||
U32* const row = hashTable + relRow;
|
||||
BYTE* tagRow = (BYTE*)(tagTable + relRow); /* Though tagTable is laid out as a table of U16, each tag is only 1 byte.
|
||||
Explicit cast allows us to get exact desired position within each row */
|
||||
BYTE* tagRow = tagTable + relRow;
|
||||
U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask);
|
||||
|
||||
assert(hash == ZSTD_hashPtr(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls));
|
||||
((BYTE*)tagRow)[pos + ZSTD_ROW_HASH_TAG_OFFSET] = hash & ZSTD_ROW_HASH_TAG_MASK;
|
||||
assert(hash == ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt));
|
||||
tagRow[pos] = hash & ZSTD_ROW_HASH_TAG_MASK;
|
||||
row[pos] = updateStartIdx;
|
||||
}
|
||||
}
|
||||
@@ -912,9 +911,11 @@ FORCE_INLINE_TEMPLATE void ZSTD_row_update_internalImpl(ZSTD_matchState_t* ms,
|
||||
* Inserts the byte at ip into the appropriate position in the hash table, and updates ms->nextToUpdate.
|
||||
* Skips sections of long matches as is necessary.
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip,
|
||||
U32 const mls, U32 const rowLog,
|
||||
U32 const rowMask, U32 const useCache)
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip,
|
||||
U32 const mls, U32 const rowLog,
|
||||
U32 const rowMask, U32 const useCache)
|
||||
{
|
||||
U32 idx = ms->nextToUpdate;
|
||||
const BYTE* const base = ms->window.base;
|
||||
@@ -1059,7 +1060,7 @@ ZSTD_row_getNEONMask(const U32 rowEntries, const BYTE* const src, const BYTE tag
|
||||
FORCE_INLINE_TEMPLATE ZSTD_VecMask
|
||||
ZSTD_row_getMatchMask(const BYTE* const tagRow, const BYTE tag, const U32 headGrouped, const U32 rowEntries)
|
||||
{
|
||||
const BYTE* const src = tagRow + ZSTD_ROW_HASH_TAG_OFFSET;
|
||||
const BYTE* const src = tagRow;
|
||||
assert((rowEntries == 16) || (rowEntries == 32) || rowEntries == 64);
|
||||
assert(rowEntries <= ZSTD_ROW_HASH_MAX_ENTRIES);
|
||||
assert(ZSTD_row_matchMaskGroupWidth(rowEntries) * rowEntries <= sizeof(ZSTD_VecMask) * 8);
|
||||
@@ -1122,20 +1123,21 @@ ZSTD_row_getMatchMask(const BYTE* const tagRow, const BYTE tag, const U32 headGr
|
||||
|
||||
/* The high-level approach of the SIMD row based match finder is as follows:
|
||||
* - Figure out where to insert the new entry:
|
||||
* - Generate a hash from a byte along with an additional 1-byte "short hash". The additional byte is our "tag"
|
||||
* - The hashTable is effectively split into groups or "rows" of 16 or 32 entries of U32, and the hash determines
|
||||
* - Generate a hash for current input posistion and split it into a one byte of tag and `rowHashLog` bits of index.
|
||||
* - The hash is salted by a value that changes on every contex reset, so when the same table is used
|
||||
* we will avoid collisions that would otherwise slow us down by intorducing phantom matches.
|
||||
* - The hashTable is effectively split into groups or "rows" of 15 or 31 entries of U32, and the index determines
|
||||
* which row to insert into.
|
||||
* - Determine the correct position within the row to insert the entry into. Each row of 16 or 32 can
|
||||
* be considered as a circular buffer with a "head" index that resides in the tagTable.
|
||||
* - Also insert the "tag" into the equivalent row and position in the tagTable.
|
||||
* - Note: The tagTable has 17 or 33 1-byte entries per row, due to 16 or 32 tags, and 1 "head" entry.
|
||||
* The 17 or 33 entry rows are spaced out to occur every 32 or 64 bytes, respectively,
|
||||
* for alignment/performance reasons, leaving some bytes unused.
|
||||
* - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte "short hash" and
|
||||
* - Determine the correct position within the row to insert the entry into. Each row of 15 or 31 can
|
||||
* be considered as a circular buffer with a "head" index that resides in the tagTable (overall 16 or 32 bytes
|
||||
* per row).
|
||||
* - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte tag calculated for the position and
|
||||
* generate a bitfield that we can cycle through to check the collisions in the hash table.
|
||||
* - Pick the longest match.
|
||||
* - Insert the tag into the equivalent row and position in the tagTable.
|
||||
*/
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_RowFindBestMatch(
|
||||
ZSTD_matchState_t* ms,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
@@ -1144,7 +1146,7 @@ size_t ZSTD_RowFindBestMatch(
|
||||
const U32 rowLog)
|
||||
{
|
||||
U32* const hashTable = ms->hashTable;
|
||||
U16* const tagTable = ms->tagTable;
|
||||
BYTE* const tagTable = ms->tagTable;
|
||||
U32* const hashCache = ms->hashCache;
|
||||
const U32 hashLog = ms->rowHashLog;
|
||||
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||
@@ -1163,8 +1165,10 @@ size_t ZSTD_RowFindBestMatch(
|
||||
const U32 rowMask = rowEntries - 1;
|
||||
const U32 cappedSearchLog = MIN(cParams->searchLog, rowLog); /* nb of searches is capped at nb entries per row */
|
||||
const U32 groupWidth = ZSTD_row_matchMaskGroupWidth(rowEntries);
|
||||
const U64 hashSalt = ms->hashSalt;
|
||||
U32 nbAttempts = 1U << cappedSearchLog;
|
||||
size_t ml=4-1;
|
||||
U32 hash;
|
||||
|
||||
/* DMS/DDS variables that may be referenced laster */
|
||||
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
||||
@@ -1188,7 +1192,7 @@ size_t ZSTD_RowFindBestMatch(
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
/* Prefetch DMS rows */
|
||||
U32* const dmsHashTable = dms->hashTable;
|
||||
U16* const dmsTagTable = dms->tagTable;
|
||||
BYTE* const dmsTagTable = dms->tagTable;
|
||||
U32 const dmsHash = (U32)ZSTD_hashPtr(ip, dms->rowHashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
|
||||
U32 const dmsRelRow = (dmsHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
|
||||
dmsTag = dmsHash & ZSTD_ROW_HASH_TAG_MASK;
|
||||
@@ -1198,9 +1202,19 @@ size_t ZSTD_RowFindBestMatch(
|
||||
}
|
||||
|
||||
/* Update the hashTable and tagTable up to (but not including) ip */
|
||||
ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */);
|
||||
if (!ms->lazySkipping) {
|
||||
ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */);
|
||||
hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls, hashSalt);
|
||||
} else {
|
||||
/* Stop inserting every position when in the lazy skipping mode.
|
||||
* The hash cache is also not kept up to date in this mode.
|
||||
*/
|
||||
hash = (U32)ZSTD_hashPtrSalted(ip, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt);
|
||||
ms->nextToUpdate = curr;
|
||||
}
|
||||
ms->hashSaltEntropy += hash; /* collect salt entropy */
|
||||
|
||||
{ /* Get the hash for ip, compute the appropriate row */
|
||||
U32 const hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls);
|
||||
U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
|
||||
U32 const tag = hash & ZSTD_ROW_HASH_TAG_MASK;
|
||||
U32* const row = hashTable + relRow;
|
||||
@@ -1212,9 +1226,10 @@ size_t ZSTD_RowFindBestMatch(
|
||||
ZSTD_VecMask matches = ZSTD_row_getMatchMask(tagRow, (BYTE)tag, headGrouped, rowEntries);
|
||||
|
||||
/* Cycle through the matches and prefetch */
|
||||
for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) {
|
||||
for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) {
|
||||
U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask;
|
||||
U32 const matchIndex = row[matchPos];
|
||||
if(matchPos == 0) continue;
|
||||
assert(numMatches < rowEntries);
|
||||
if (matchIndex < lowLimit)
|
||||
break;
|
||||
@@ -1224,13 +1239,14 @@ size_t ZSTD_RowFindBestMatch(
|
||||
PREFETCH_L1(dictBase + matchIndex);
|
||||
}
|
||||
matchBuffer[numMatches++] = matchIndex;
|
||||
--nbAttempts;
|
||||
}
|
||||
|
||||
/* Speed opt: insert current byte into hashtable too. This allows us to avoid one iteration of the loop
|
||||
in ZSTD_row_update_internal() at the next search. */
|
||||
{
|
||||
U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask);
|
||||
tagRow[pos + ZSTD_ROW_HASH_TAG_OFFSET] = (BYTE)tag;
|
||||
tagRow[pos] = (BYTE)tag;
|
||||
row[pos] = ms->nextToUpdate++;
|
||||
}
|
||||
|
||||
@@ -1281,13 +1297,15 @@ size_t ZSTD_RowFindBestMatch(
|
||||
size_t currMatch = 0;
|
||||
ZSTD_VecMask matches = ZSTD_row_getMatchMask(dmsTagRow, (BYTE)dmsTag, headGrouped, rowEntries);
|
||||
|
||||
for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) {
|
||||
for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) {
|
||||
U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask;
|
||||
U32 const matchIndex = dmsRow[matchPos];
|
||||
if(matchPos == 0) continue;
|
||||
if (matchIndex < dmsLowestIndex)
|
||||
break;
|
||||
PREFETCH_L1(dmsBase + matchIndex);
|
||||
matchBuffer[numMatches++] = matchIndex;
|
||||
--nbAttempts;
|
||||
}
|
||||
|
||||
/* Return the longest match */
|
||||
@@ -1493,8 +1511,9 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_searchMax(
|
||||
* Common parser - lazy strategy
|
||||
*********************************/
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
ZSTD_compressBlock_lazy_generic(
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_lazy_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize,
|
||||
@@ -1544,10 +1563,11 @@ ZSTD_compressBlock_lazy_generic(
|
||||
assert(offset_2 <= dictAndPrefixLength);
|
||||
}
|
||||
|
||||
/* Reset the lazy skipping state */
|
||||
ms->lazySkipping = 0;
|
||||
|
||||
if (searchMethod == search_rowHash) {
|
||||
ZSTD_row_fillHashCache(ms, base, rowLog,
|
||||
MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */),
|
||||
ms->nextToUpdate, ilimit);
|
||||
ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit);
|
||||
}
|
||||
|
||||
/* Match Loop */
|
||||
@@ -1591,7 +1611,16 @@ ZSTD_compressBlock_lazy_generic(
|
||||
}
|
||||
|
||||
if (matchLength < 4) {
|
||||
ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
|
||||
size_t const step = ((size_t)(ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */;
|
||||
ip += step;
|
||||
/* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time.
|
||||
* In this mode we stop inserting every position into our tables, and only insert
|
||||
* positions that we search, which is one in step positions.
|
||||
* The exact cutoff is flexible, I've just chosen a number that is reasonably high,
|
||||
* so we minimize the compression ratio loss in "normal" scenarios. This mode gets
|
||||
* triggered once we've gone 2KB without finding any matches.
|
||||
*/
|
||||
ms->lazySkipping = step > kLazySkippingStep;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1695,6 +1724,13 @@ _storeSequence:
|
||||
ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength);
|
||||
anchor = ip = start + matchLength;
|
||||
}
|
||||
if (ms->lazySkipping) {
|
||||
/* We've found a match, disable lazy skipping mode, and refill the hash cache. */
|
||||
if (searchMethod == search_rowHash) {
|
||||
ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit);
|
||||
}
|
||||
ms->lazySkipping = 0;
|
||||
}
|
||||
|
||||
/* check immediate repcode */
|
||||
if (isDxS) {
|
||||
@@ -1741,29 +1777,10 @@ _storeSequence:
|
||||
/* Return the last literals size */
|
||||
return (size_t)(iend - anchor);
|
||||
}
|
||||
#endif /* build exclusions */
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_noDict);
|
||||
}
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_greedy(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
@@ -1771,27 +1788,6 @@ size_t ZSTD_compressBlock_greedy(
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
@@ -1799,21 +1795,6 @@ size_t ZSTD_compressBlock_greedy_dictMatchState(
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
@@ -1821,21 +1802,6 @@ size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
|
||||
/* Row-based matchfinder */
|
||||
size_t ZSTD_compressBlock_lazy2_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
@@ -1843,11 +1809,48 @@ size_t ZSTD_compressBlock_greedy_row(
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
|
||||
size_t ZSTD_compressBlock_greedy_dictMatchState_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_lazy(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState_row(
|
||||
@@ -1857,13 +1860,49 @@ size_t ZSTD_compressBlock_lazy_dictMatchState_row(
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_dictMatchState_row(
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_lazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
@@ -1871,22 +1910,30 @@ size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dedicatedDictSearch);
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
|
||||
#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btlazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
|
||||
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch);
|
||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR)
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
@@ -1912,12 +1959,13 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic (searchFunc=%u)", (U32)searchMethod);
|
||||
|
||||
/* Reset the lazy skipping state */
|
||||
ms->lazySkipping = 0;
|
||||
|
||||
/* init */
|
||||
ip += (ip == prefixStart);
|
||||
if (searchMethod == search_rowHash) {
|
||||
ZSTD_row_fillHashCache(ms, base, rowLog,
|
||||
MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */),
|
||||
ms->nextToUpdate, ilimit);
|
||||
ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit);
|
||||
}
|
||||
|
||||
/* Match Loop */
|
||||
@@ -1955,7 +2003,16 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
}
|
||||
|
||||
if (matchLength < 4) {
|
||||
ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
|
||||
size_t const step = ((size_t)(ip-anchor) >> kSearchStrength);
|
||||
ip += step + 1; /* jump faster over incompressible sections */
|
||||
/* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time.
|
||||
* In this mode we stop inserting every position into our tables, and only insert
|
||||
* positions that we search, which is one in step positions.
|
||||
* The exact cutoff is flexible, I've just chosen a number that is reasonably high,
|
||||
* so we minimize the compression ratio loss in "normal" scenarios. This mode gets
|
||||
* triggered once we've gone 2KB without finding any matches.
|
||||
*/
|
||||
ms->lazySkipping = step > kLazySkippingStep;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2041,6 +2098,13 @@ _storeSequence:
|
||||
ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength);
|
||||
anchor = ip = start + matchLength;
|
||||
}
|
||||
if (ms->lazySkipping) {
|
||||
/* We've found a match, disable lazy skipping mode, and refill the hash cache. */
|
||||
if (searchMethod == search_rowHash) {
|
||||
ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit);
|
||||
}
|
||||
ms->lazySkipping = 0;
|
||||
}
|
||||
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
@@ -2071,8 +2135,9 @@ _storeSequence:
|
||||
/* Return the last literals size */
|
||||
return (size_t)(iend - anchor);
|
||||
}
|
||||
#endif /* build exclusions */
|
||||
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_greedy_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
@@ -2080,6 +2145,15 @@ size_t ZSTD_compressBlock_greedy_extDict(
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_extDict_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_lazy_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
@@ -2088,29 +2162,6 @@ size_t ZSTD_compressBlock_lazy_extDict(
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_extDict_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_extDict_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
@@ -2118,6 +2169,16 @@ size_t ZSTD_compressBlock_lazy_extDict_row(
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_lazy2_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_extDict_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
@@ -2125,3 +2186,14 @@ size_t ZSTD_compressBlock_lazy2_extDict_row(
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btlazy2_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize)
|
||||
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
+126
-51
@@ -27,98 +27,173 @@ extern "C" {
|
||||
|
||||
#define ZSTD_ROW_HASH_TAG_BITS 8 /* nb bits to use for the tag */
|
||||
|
||||
#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR)
|
||||
U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
|
||||
void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip);
|
||||
|
||||
void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip);
|
||||
|
||||
void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */
|
||||
#endif
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_greedy(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_greedy_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_greedy_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_greedy_dictMatchState_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_greedy_extDict_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY ZSTD_compressBlock_greedy
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_ROW ZSTD_compressBlock_greedy_row
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE ZSTD_compressBlock_greedy_dictMatchState
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW ZSTD_compressBlock_greedy_dictMatchState_row
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH ZSTD_compressBlock_greedy_dedicatedDictSearch
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_greedy_dedicatedDictSearch_row
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT ZSTD_compressBlock_greedy_extDict
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW ZSTD_compressBlock_greedy_extDict_row
|
||||
#else
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY NULL
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE NULL
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH NULL
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT NULL
|
||||
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW NULL
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_lazy(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dictMatchState_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_extDict_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY ZSTD_compressBlock_lazy
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_ROW ZSTD_compressBlock_lazy_row
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE ZSTD_compressBlock_lazy_dictMatchState
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy_dictMatchState_row
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy_dedicatedDictSearch
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy_dedicatedDictSearch_row
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT ZSTD_compressBlock_lazy_extDict
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW ZSTD_compressBlock_lazy_extDict_row
|
||||
#else
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW NULL
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_lazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_extDict_row(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2 ZSTD_compressBlock_lazy2
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_ROW ZSTD_compressBlock_lazy2_row
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE ZSTD_compressBlock_lazy2_dictMatchState
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy2_dictMatchState_row
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy2_dedicatedDictSearch
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy2_dedicatedDictSearch_row
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT ZSTD_compressBlock_lazy2_extDict
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW ZSTD_compressBlock_lazy2_extDict_row
|
||||
#else
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2 NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT NULL
|
||||
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW NULL
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btlazy2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btlazy2_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
#define ZSTD_COMPRESSBLOCK_BTLAZY2 ZSTD_compressBlock_btlazy2
|
||||
#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE ZSTD_compressBlock_btlazy2_dictMatchState
|
||||
#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT ZSTD_compressBlock_btlazy2_extDict
|
||||
#else
|
||||
#define ZSTD_COMPRESSBLOCK_BTLAZY2 NULL
|
||||
#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE NULL
|
||||
#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT NULL
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
||||
@@ -246,7 +246,11 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
|
||||
break;
|
||||
|
||||
case ZSTD_dfast:
|
||||
#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
|
||||
ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx);
|
||||
#else
|
||||
assert(0); /* shouldn't be called: cparams should've been adjusted. */
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ZSTD_greedy:
|
||||
@@ -318,7 +322,9 @@ static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
|
||||
}
|
||||
}
|
||||
|
||||
static size_t ZSTD_ldm_generateSequences_internal(
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_ldm_generateSequences_internal(
|
||||
ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
|
||||
ldmParams_t const* params, void const* src, size_t srcSize)
|
||||
{
|
||||
@@ -689,7 +695,6 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||
/* maybeSplitSequence updates rawSeqStore->pos */
|
||||
rawSeq const sequence = maybeSplitSequence(rawSeqStore,
|
||||
(U32)(iend - ip), minMatch);
|
||||
int i;
|
||||
/* End signal */
|
||||
if (sequence.offset == 0)
|
||||
break;
|
||||
@@ -702,6 +707,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||
/* Run the block compressor */
|
||||
DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
|
||||
{
|
||||
int i;
|
||||
size_t const newLitLength =
|
||||
blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
|
||||
ip += sequence.litLength;
|
||||
|
||||
+219
-113
@@ -12,6 +12,9 @@
|
||||
#include "hist.h"
|
||||
#include "zstd_opt.h"
|
||||
|
||||
#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR)
|
||||
|
||||
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */
|
||||
#define ZSTD_MAX_PRICE (1<<30)
|
||||
@@ -264,6 +267,7 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
|
||||
const optState_t* const optPtr,
|
||||
int optLevel)
|
||||
{
|
||||
DEBUGLOG(8, "ZSTD_rawLiteralsCost (%u literals)", litLength);
|
||||
if (litLength == 0) return 0;
|
||||
|
||||
if (!ZSTD_compressedLiterals(optPtr))
|
||||
@@ -402,9 +406,11 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
|
||||
|
||||
/* Update hashTable3 up to ip (excluded)
|
||||
Assumption : always within prefix (i.e. not within extDict) */
|
||||
static U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms,
|
||||
U32* nextToUpdate3,
|
||||
const BYTE* const ip)
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms,
|
||||
U32* nextToUpdate3,
|
||||
const BYTE* const ip)
|
||||
{
|
||||
U32* const hashTable3 = ms->hashTable3;
|
||||
U32 const hashLog3 = ms->hashLog3;
|
||||
@@ -431,7 +437,9 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms,
|
||||
* @param ip assumed <= iend-8 .
|
||||
* @param target The target of ZSTD_updateTree_internal() - we are filling to this position
|
||||
* @return : nb of positions added */
|
||||
static U32 ZSTD_insertBt1(
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32 ZSTD_insertBt1(
|
||||
const ZSTD_matchState_t* ms,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
U32 const target,
|
||||
@@ -550,6 +558,7 @@ static U32 ZSTD_insertBt1(
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_updateTree_internal(
|
||||
ZSTD_matchState_t* ms,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
@@ -558,7 +567,7 @@ void ZSTD_updateTree_internal(
|
||||
const BYTE* const base = ms->window.base;
|
||||
U32 const target = (U32)(ip - base);
|
||||
U32 idx = ms->nextToUpdate;
|
||||
DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
|
||||
DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
|
||||
idx, target, dictMode);
|
||||
|
||||
while(idx < target) {
|
||||
@@ -575,7 +584,9 @@ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) {
|
||||
ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict);
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE U32
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32
|
||||
ZSTD_insertBtAndGetAllMatches (
|
||||
ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */
|
||||
ZSTD_matchState_t* ms,
|
||||
@@ -816,7 +827,9 @@ typedef U32 (*ZSTD_getAllMatchesFn)(
|
||||
U32 const ll0,
|
||||
U32 const lengthToBeat);
|
||||
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_btGetAllMatches_internal(
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
U32 ZSTD_btGetAllMatches_internal(
|
||||
ZSTD_match_t* matches,
|
||||
ZSTD_matchState_t* ms,
|
||||
U32* nextToUpdate3,
|
||||
@@ -1035,11 +1048,6 @@ ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm,
|
||||
* Optimal parser
|
||||
*********************************/
|
||||
|
||||
static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
|
||||
{
|
||||
return sol.litlen + sol.mlen;
|
||||
}
|
||||
|
||||
#if 0 /* debug */
|
||||
|
||||
static void
|
||||
@@ -1057,7 +1065,13 @@ listStats(const U32* table, int lastEltID)
|
||||
|
||||
#endif
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
#define LIT_PRICE(_p) (int)ZSTD_rawLiteralsCost(_p, 1, optStatePtr, optLevel)
|
||||
#define LL_PRICE(_l) (int)ZSTD_litLengthPrice(_l, optStatePtr, optLevel)
|
||||
#define LL_INCPRICE(_l) (LL_PRICE(_l) - LL_PRICE(_l-1))
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t
|
||||
ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
@@ -1083,9 +1097,11 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
|
||||
ZSTD_optimal_t* const opt = optStatePtr->priceTable;
|
||||
ZSTD_match_t* const matches = optStatePtr->matchTable;
|
||||
ZSTD_optimal_t lastSequence;
|
||||
ZSTD_optimal_t lastStretch;
|
||||
ZSTD_optLdm_t optLdm;
|
||||
|
||||
ZSTD_memset(&lastStretch, 0, sizeof(ZSTD_optimal_t));
|
||||
|
||||
optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore;
|
||||
optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0;
|
||||
ZSTD_opt_getNextMatchAndUpdateSeqStore(&optLdm, (U32)(ip-istart), (U32)(iend-ip));
|
||||
@@ -1106,19 +1122,31 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
U32 const ll0 = !litlen;
|
||||
U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch);
|
||||
ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches,
|
||||
(U32)(ip-istart), (U32)(iend - ip));
|
||||
if (!nbMatches) { ip++; continue; }
|
||||
(U32)(ip-istart), (U32)(iend-ip));
|
||||
if (!nbMatches) {
|
||||
DEBUGLOG(8, "no match found at cPos %u", (unsigned)(ip-istart));
|
||||
ip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Match found: let's store this solution, and eventually find more candidates.
|
||||
* During this forward pass, @opt is used to store stretches,
|
||||
* defined as "a match followed by N literals".
|
||||
* Note how this is different from a Sequence, which is "N literals followed by a match".
|
||||
* Storing stretches allows us to store different match predecessors
|
||||
* for each literal position part of a literals run. */
|
||||
|
||||
/* initialize opt[0] */
|
||||
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||
opt[0].mlen = 0; /* means is_a_literal */
|
||||
opt[0].mlen = 0; /* there are only literals so far */
|
||||
opt[0].litlen = litlen;
|
||||
/* We don't need to include the actual price of the literals because
|
||||
* it is static for the duration of the forward pass, and is included
|
||||
* in every price. We include the literal length to avoid negative
|
||||
* prices when we subtract the previous literal length.
|
||||
/* No need to include the actual price of the literals before the first match
|
||||
* because it is static for the duration of the forward pass, and is included
|
||||
* in every subsequent price. But, we include the literal length because
|
||||
* the cost variation of litlen depends on the value of litlen.
|
||||
*/
|
||||
opt[0].price = (int)ZSTD_litLengthPrice(litlen, optStatePtr, optLevel);
|
||||
opt[0].price = LL_PRICE(litlen);
|
||||
ZSTD_STATIC_ASSERT(sizeof(opt[0].rep[0]) == sizeof(rep[0]));
|
||||
ZSTD_memcpy(&opt[0].rep, rep, sizeof(opt[0].rep));
|
||||
|
||||
/* large match -> immediate encoding */
|
||||
{ U32 const maxML = matches[nbMatches-1].len;
|
||||
@@ -1127,82 +1155,106 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart));
|
||||
|
||||
if (maxML > sufficient_len) {
|
||||
lastSequence.litlen = litlen;
|
||||
lastSequence.mlen = maxML;
|
||||
lastSequence.off = maxOffBase;
|
||||
DEBUGLOG(6, "large match (%u>%u), immediate encoding",
|
||||
lastStretch.litlen = 0;
|
||||
lastStretch.mlen = maxML;
|
||||
lastStretch.off = maxOffBase;
|
||||
DEBUGLOG(6, "large match (%u>%u) => immediate encoding",
|
||||
maxML, sufficient_len);
|
||||
cur = 0;
|
||||
last_pos = ZSTD_totalLen(lastSequence);
|
||||
last_pos = maxML;
|
||||
goto _shortestPath;
|
||||
} }
|
||||
|
||||
/* set prices for first matches starting position == 0 */
|
||||
assert(opt[0].price >= 0);
|
||||
{ U32 const literalsPrice = (U32)opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
||||
U32 pos;
|
||||
{ U32 pos;
|
||||
U32 matchNb;
|
||||
for (pos = 1; pos < minMatch; pos++) {
|
||||
opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */
|
||||
opt[pos].price = ZSTD_MAX_PRICE;
|
||||
opt[pos].mlen = 0;
|
||||
opt[pos].litlen = litlen + pos;
|
||||
}
|
||||
for (matchNb = 0; matchNb < nbMatches; matchNb++) {
|
||||
U32 const offBase = matches[matchNb].off;
|
||||
U32 const end = matches[matchNb].len;
|
||||
for ( ; pos <= end ; pos++ ) {
|
||||
U32 const matchPrice = ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel);
|
||||
U32 const sequencePrice = literalsPrice + matchPrice;
|
||||
int const matchPrice = (int)ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel);
|
||||
int const sequencePrice = opt[0].price + matchPrice;
|
||||
DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
|
||||
pos, ZSTD_fCost((int)sequencePrice));
|
||||
pos, ZSTD_fCost(sequencePrice));
|
||||
opt[pos].mlen = pos;
|
||||
opt[pos].off = offBase;
|
||||
opt[pos].litlen = litlen;
|
||||
opt[pos].price = (int)sequencePrice;
|
||||
} }
|
||||
opt[pos].litlen = 0; /* end of match */
|
||||
opt[pos].price = sequencePrice + LL_PRICE(0);
|
||||
}
|
||||
}
|
||||
last_pos = pos-1;
|
||||
opt[pos].price = ZSTD_MAX_PRICE;
|
||||
}
|
||||
}
|
||||
|
||||
/* check further positions */
|
||||
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)
|
||||
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 == 0) ? opt[cur-1].litlen + 1 : 1;
|
||||
{ U32 const litlen = opt[cur-1].litlen + 1;
|
||||
int const price = opt[cur-1].price
|
||||
+ (int)ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
|
||||
+ (int)ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
|
||||
- (int)ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
|
||||
+ LIT_PRICE(ip+cur-1)
|
||||
+ LL_INCPRICE(litlen);
|
||||
assert(price < 1000000000); /* overflow check */
|
||||
if (price <= opt[cur].price) {
|
||||
ZSTD_optimal_t const prevMatch = opt[cur];
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
|
||||
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] = opt[cur-1];
|
||||
opt[cur].litlen = litlen;
|
||||
opt[cur].price = price;
|
||||
if ( (optLevel >= 1) /* additional check only for higher modes */
|
||||
&& (prevMatch.litlen == 0) /* replace a match */
|
||||
&& (LL_INCPRICE(1) < 0) /* ll1 is cheaper than ll0 */
|
||||
&& LIKELY(ip + cur < iend)
|
||||
) {
|
||||
/* check next position, in case it would be cheaper */
|
||||
int with1literal = prevMatch.price + LIT_PRICE(ip+cur) + LL_INCPRICE(1);
|
||||
int withMoreLiterals = price + LIT_PRICE(ip+cur) + LL_INCPRICE(litlen+1);
|
||||
DEBUGLOG(7, "then at next rPos %u : match+1lit %.2f vs %ulits %.2f",
|
||||
cur+1, ZSTD_fCost(with1literal), litlen+1, ZSTD_fCost(withMoreLiterals));
|
||||
if ( (with1literal < withMoreLiterals)
|
||||
&& (with1literal < opt[cur+1].price) ) {
|
||||
/* update offset history - before it disappears */
|
||||
U32 const prev = cur - prevMatch.mlen;
|
||||
repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, prevMatch.off, opt[prev].litlen==0);
|
||||
assert(cur >= prevMatch.mlen);
|
||||
DEBUGLOG(7, "==> match+1lit is cheaper (%.2f < %.2f) (hist:%u,%u,%u) !",
|
||||
ZSTD_fCost(with1literal), ZSTD_fCost(withMoreLiterals),
|
||||
newReps.rep[0], newReps.rep[1], newReps.rep[2] );
|
||||
opt[cur+1] = prevMatch; /* mlen & offbase */
|
||||
ZSTD_memcpy(opt[cur+1].rep, &newReps, sizeof(repcodes_t));
|
||||
opt[cur+1].litlen = 1;
|
||||
opt[cur+1].price = with1literal;
|
||||
if (last_pos < cur+1) last_pos = cur+1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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]);
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f)",
|
||||
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the repcodes of the current position. We must do it here
|
||||
* because we rely on the repcodes of the 2nd to last sequence being
|
||||
* correct to set the next chunks repcodes during the backward
|
||||
* traversal.
|
||||
/* Offset history is not updated during match comparison.
|
||||
* Do it here, now that the match is selected and confirmed.
|
||||
*/
|
||||
ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t));
|
||||
assert(cur >= opt[cur].mlen);
|
||||
if (opt[cur].mlen != 0) {
|
||||
if (opt[cur].litlen == 0) {
|
||||
/* just finished a match => alter offset history */
|
||||
U32 const prev = cur - opt[cur].mlen;
|
||||
repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0);
|
||||
repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[prev].litlen==0);
|
||||
ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t));
|
||||
} else {
|
||||
ZSTD_memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t));
|
||||
}
|
||||
|
||||
/* last match must start at a minimum distance of 8 from oend */
|
||||
@@ -1212,15 +1264,14 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
|
||||
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);
|
||||
DEBUGLOG(7, "skip current position : next rPos(%u) price is cheaper", cur+1);
|
||||
continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
|
||||
}
|
||||
|
||||
assert(opt[cur].price >= 0);
|
||||
{ U32 const ll0 = (opt[cur].mlen != 0);
|
||||
U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
|
||||
U32 const previousPrice = (U32)opt[cur].price;
|
||||
U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
||||
{ U32 const ll0 = (opt[cur].litlen == 0);
|
||||
int const previousPrice = opt[cur].price;
|
||||
int const basePrice = previousPrice + LL_PRICE(0);
|
||||
U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch);
|
||||
U32 matchNb;
|
||||
|
||||
@@ -1232,18 +1283,17 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
continue;
|
||||
}
|
||||
|
||||
{ U32 const maxML = matches[nbMatches-1].len;
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
|
||||
inr-istart, cur, nbMatches, maxML);
|
||||
{ U32 const longestML = matches[nbMatches-1].len;
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of longest ML=%u",
|
||||
inr-istart, cur, nbMatches, longestML);
|
||||
|
||||
if ( (maxML > sufficient_len)
|
||||
|| (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 */
|
||||
if ( (longestML > sufficient_len)
|
||||
|| (cur + longestML >= ZSTD_OPT_NUM)
|
||||
|| (ip + cur + longestML >= iend) ) {
|
||||
lastStretch.mlen = longestML;
|
||||
lastStretch.off = matches[nbMatches-1].off;
|
||||
lastStretch.litlen = 0;
|
||||
last_pos = cur + longestML;
|
||||
goto _shortestPath;
|
||||
} }
|
||||
|
||||
@@ -1255,19 +1305,24 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
U32 mlen;
|
||||
|
||||
DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u",
|
||||
matchNb, matches[matchNb].off, lastML, litlen);
|
||||
matchNb, matches[matchNb].off, lastML, opt[cur].litlen);
|
||||
|
||||
for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
|
||||
U32 const pos = cur + mlen;
|
||||
int const price = (int)basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
|
||||
int const price = basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
|
||||
|
||||
if ((pos > last_pos) || (price < opt[pos].price)) {
|
||||
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 */
|
||||
while (last_pos < pos) {
|
||||
/* fill empty positions, for future comparisons */
|
||||
last_pos++;
|
||||
opt[last_pos].price = ZSTD_MAX_PRICE;
|
||||
opt[last_pos].litlen = !0; /* just needs to be != 0, to mean "not an end of match" */
|
||||
}
|
||||
opt[pos].mlen = mlen;
|
||||
opt[pos].off = offset;
|
||||
opt[pos].litlen = litlen;
|
||||
opt[pos].litlen = 0;
|
||||
opt[pos].price = price;
|
||||
} else {
|
||||
DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
|
||||
@@ -1275,47 +1330,81 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
|
||||
}
|
||||
} } }
|
||||
opt[last_pos+1].price = ZSTD_MAX_PRICE;
|
||||
} /* for (cur = 1; cur <= last_pos; cur++) */
|
||||
|
||||
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*/
|
||||
lastStretch = opt[last_pos];
|
||||
assert(cur >= lastStretch.mlen);
|
||||
cur = last_pos - lastStretch.mlen;
|
||||
|
||||
_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
assert(opt[0].mlen == 0);
|
||||
assert(last_pos >= lastStretch.mlen);
|
||||
assert(cur == last_pos - lastStretch.mlen);
|
||||
|
||||
/* Set the next chunk's repcodes based on the repcodes of the beginning
|
||||
* of the last match, and the last sequence. This avoids us having to
|
||||
* update them while traversing the sequences.
|
||||
*/
|
||||
if (lastSequence.mlen != 0) {
|
||||
repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0);
|
||||
ZSTD_memcpy(rep, &reps, sizeof(reps));
|
||||
if (lastStretch.mlen==0) {
|
||||
/* no solution : all matches have been converted into literals */
|
||||
assert(lastStretch.litlen == (ip - anchor) + last_pos);
|
||||
ip += last_pos;
|
||||
continue;
|
||||
}
|
||||
assert(lastStretch.off > 0);
|
||||
|
||||
/* Update offset history */
|
||||
if (lastStretch.litlen == 0) {
|
||||
/* finishing on a match : update offset history */
|
||||
repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastStretch.off, opt[cur].litlen==0);
|
||||
ZSTD_memcpy(rep, &reps, sizeof(repcodes_t));
|
||||
} else {
|
||||
ZSTD_memcpy(rep, opt[cur].rep, sizeof(repcodes_t));
|
||||
ZSTD_memcpy(rep, lastStretch.rep, sizeof(repcodes_t));
|
||||
assert(cur >= lastStretch.litlen);
|
||||
cur -= lastStretch.litlen;
|
||||
}
|
||||
|
||||
{ U32 const storeEnd = cur + 1;
|
||||
/* Let's write the shortest path solution.
|
||||
* It is stored in @opt in reverse order,
|
||||
* starting from @storeEnd (==cur+2),
|
||||
* effectively partially @opt overwriting.
|
||||
* Content is changed too:
|
||||
* - So far, @opt stored stretches, aka a match followed by literals
|
||||
* - Now, it will store sequences, aka literals followed by a match
|
||||
*/
|
||||
{ U32 const storeEnd = cur + 2;
|
||||
U32 storeStart = storeEnd;
|
||||
U32 seqPos = cur;
|
||||
U32 stretchPos = cur;
|
||||
|
||||
DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
|
||||
last_pos, cur); (void)last_pos;
|
||||
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]);
|
||||
assert(storeEnd < ZSTD_OPT_SIZE);
|
||||
DEBUGLOG(6, "last stretch copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
||||
storeEnd, lastStretch.litlen, lastStretch.mlen, lastStretch.off);
|
||||
if (lastStretch.litlen > 0) {
|
||||
/* last "sequence" is unfinished: just a bunch of literals */
|
||||
opt[storeEnd].litlen = lastStretch.litlen;
|
||||
opt[storeEnd].mlen = 0;
|
||||
storeStart = storeEnd-1;
|
||||
opt[storeStart] = lastStretch;
|
||||
} {
|
||||
opt[storeEnd] = lastStretch; /* note: litlen will be fixed */
|
||||
storeStart = storeEnd;
|
||||
}
|
||||
while (1) {
|
||||
ZSTD_optimal_t nextStretch = opt[stretchPos];
|
||||
opt[storeStart].litlen = nextStretch.litlen;
|
||||
DEBUGLOG(6, "selected sequence (llen=%u,mlen=%u,ofc=%u)",
|
||||
opt[storeStart].litlen, opt[storeStart].mlen, opt[storeStart].off);
|
||||
if (nextStretch.mlen == 0) {
|
||||
/* reaching beginning of segment */
|
||||
break;
|
||||
}
|
||||
storeStart--;
|
||||
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;
|
||||
opt[storeStart] = nextStretch; /* note: litlen will be fixed */
|
||||
assert(nextStretch.litlen + nextStretch.mlen <= stretchPos);
|
||||
stretchPos -= nextStretch.litlen + nextStretch.mlen;
|
||||
}
|
||||
|
||||
/* save sequences */
|
||||
DEBUGLOG(6, "sending selected sequences into seqStore")
|
||||
DEBUGLOG(6, "sending selected sequences into seqStore");
|
||||
{ U32 storePos;
|
||||
for (storePos=storeStart; storePos <= storeEnd; storePos++) {
|
||||
U32 const llen = opt[storePos].litlen;
|
||||
@@ -1337,6 +1426,9 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
anchor += advance;
|
||||
ip = anchor;
|
||||
} }
|
||||
DEBUGLOG(7, "new offset history : %u, %u, %u", rep[0], rep[1], rep[2]);
|
||||
|
||||
/* update all costs */
|
||||
ZSTD_setBasePrices(optStatePtr, optLevel);
|
||||
}
|
||||
} /* while (ip < ilimit) */
|
||||
@@ -1344,21 +1436,27 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
/* Return the last literals size */
|
||||
return (size_t)(iend - anchor);
|
||||
}
|
||||
#endif /* build exclusions */
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
|
||||
static size_t ZSTD_compressBlock_opt0(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /* optLevel */, dictMode);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
|
||||
static size_t ZSTD_compressBlock_opt2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /* optLevel */, dictMode);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btopt(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize)
|
||||
@@ -1366,20 +1464,23 @@ size_t ZSTD_compressBlock_btopt(
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_btopt");
|
||||
return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_noDict);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
|
||||
/* ZSTD_initStats_ultra():
|
||||
* make a first compression pass, just to seed stats with more accurate starting values.
|
||||
* only works on first block, with no dictionary and no ldm.
|
||||
* this function cannot error out, its narrow contract must be respected.
|
||||
*/
|
||||
static void
|
||||
ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
|
||||
seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize)
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
void ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
|
||||
seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */
|
||||
ZSTD_memcpy(tmpRep, rep, sizeof(tmpRep));
|
||||
@@ -1423,7 +1524,7 @@ size_t ZSTD_compressBlock_btultra2(
|
||||
* Consequently, this can only work if no data has been previously loaded in tables,
|
||||
* aka, no dictionary, no prefix, no ldm preprocessing.
|
||||
* The compression ratio gain is generally small (~0.5% on first block),
|
||||
** the cost is 2x cpu time on first block. */
|
||||
* the cost is 2x cpu time on first block. */
|
||||
assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
|
||||
if ( (ms->opt.litLengthSum==0) /* first block */
|
||||
&& (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
|
||||
@@ -1436,7 +1537,9 @@ size_t ZSTD_compressBlock_btultra2(
|
||||
|
||||
return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btopt_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize)
|
||||
@@ -1444,19 +1547,21 @@ size_t ZSTD_compressBlock_btopt_dictMatchState(
|
||||
return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btopt_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_extDict);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btultra_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
@@ -1464,6 +1569,7 @@ size_t ZSTD_compressBlock_btultra_extDict(
|
||||
{
|
||||
return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_extDict);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* note : no btultra2 variant for extDict nor dictMatchState,
|
||||
* because btultra2 is not meant to work with dictionaries
|
||||
|
||||
+34
-10
@@ -17,28 +17,38 @@ extern "C" {
|
||||
|
||||
#include "zstd_compress_internal.h"
|
||||
|
||||
#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \
|
||||
|| !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR)
|
||||
/* used in ZSTD_loadDictionaryContent() */
|
||||
void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend);
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btopt(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btultra(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btultra2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_btopt_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
||||
size_t ZSTD_compressBlock_btopt_extDict(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
size_t ZSTD_compressBlock_btopt_extDict(
|
||||
#define ZSTD_COMPRESSBLOCK_BTOPT ZSTD_compressBlock_btopt
|
||||
#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE ZSTD_compressBlock_btopt_dictMatchState
|
||||
#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT ZSTD_compressBlock_btopt_extDict
|
||||
#else
|
||||
#define ZSTD_COMPRESSBLOCK_BTOPT NULL
|
||||
#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE NULL
|
||||
#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT NULL
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
|
||||
size_t ZSTD_compressBlock_btultra(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btultra_extDict(
|
||||
@@ -48,6 +58,20 @@ size_t ZSTD_compressBlock_btultra_extDict(
|
||||
/* note : no btultra2 variant for extDict nor dictMatchState,
|
||||
* because btultra2 is not meant to work with dictionaries
|
||||
* and is only specific for the first block (no prefix) */
|
||||
size_t ZSTD_compressBlock_btultra2(
|
||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||
void const* src, size_t srcSize);
|
||||
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA ZSTD_compressBlock_btultra
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE ZSTD_compressBlock_btultra_dictMatchState
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT ZSTD_compressBlock_btultra_extDict
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA2 ZSTD_compressBlock_btultra2
|
||||
#else
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA NULL
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE NULL
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT NULL
|
||||
#define ZSTD_COMPRESSBLOCK_BTULTRA2 NULL
|
||||
#endif
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
||||
@@ -15,16 +15,13 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* ====== Constants ====== */
|
||||
#define ZSTDMT_OVERLAPLOG_DEFAULT 0
|
||||
|
||||
|
||||
/* ====== Dependencies ====== */
|
||||
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */
|
||||
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset, INT_MAX, UINT_MAX */
|
||||
#include "../common/mem.h" /* MEM_STATIC */
|
||||
#include "../common/pool.h" /* threadpool */
|
||||
#include "../common/threading.h" /* mutex */
|
||||
#include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
|
||||
#include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
|
||||
#include "zstd_ldm.h"
|
||||
#include "zstdmt_compress.h"
|
||||
|
||||
@@ -43,12 +40,13 @@
|
||||
# include <unistd.h>
|
||||
# include <sys/times.h>
|
||||
|
||||
# define DEBUG_PRINTHEX(l,p,n) { \
|
||||
unsigned debug_u; \
|
||||
for (debug_u=0; debug_u<(n); debug_u++) \
|
||||
RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
|
||||
RAWLOG(l, " \n"); \
|
||||
}
|
||||
# define DEBUG_PRINTHEX(l,p,n) \
|
||||
do { \
|
||||
unsigned debug_u; \
|
||||
for (debug_u=0; debug_u<(n); debug_u++) \
|
||||
RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
|
||||
RAWLOG(l, " \n"); \
|
||||
} while (0)
|
||||
|
||||
static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
||||
{
|
||||
@@ -60,25 +58,28 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
||||
} }
|
||||
|
||||
#define MUTEX_WAIT_TIME_DLEVEL 6
|
||||
#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) { \
|
||||
if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
{ unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
|
||||
unsigned long long const elapsedTime = (afterTime-beforeTime); \
|
||||
if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \
|
||||
DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \
|
||||
elapsedTime, #mutex); \
|
||||
} } \
|
||||
} else { \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
} \
|
||||
}
|
||||
#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) \
|
||||
do { \
|
||||
if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
{ unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
|
||||
unsigned long long const elapsedTime = (afterTime-beforeTime); \
|
||||
if (elapsedTime > 1000) { \
|
||||
/* or whatever threshold you like; I'm using 1 millisecond here */ \
|
||||
DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, \
|
||||
"Thread took %llu microseconds to acquire mutex %s \n", \
|
||||
elapsedTime, #mutex); \
|
||||
} } \
|
||||
} else { \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m)
|
||||
# define DEBUG_PRINTHEX(l,p,n) {}
|
||||
# define DEBUG_PRINTHEX(l,p,n) do { } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -99,18 +100,39 @@ typedef struct ZSTDMT_bufferPool_s {
|
||||
unsigned totalBuffers;
|
||||
unsigned nbBuffers;
|
||||
ZSTD_customMem cMem;
|
||||
buffer_t bTable[1]; /* variable size */
|
||||
buffer_t* buffers;
|
||||
} ZSTDMT_bufferPool;
|
||||
|
||||
static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
|
||||
{
|
||||
DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool);
|
||||
if (!bufPool) return; /* compatibility with free on NULL */
|
||||
if (bufPool->buffers) {
|
||||
unsigned u;
|
||||
for (u=0; u<bufPool->totalBuffers; u++) {
|
||||
DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->buffers[u].start);
|
||||
ZSTD_customFree(bufPool->buffers[u].start, bufPool->cMem);
|
||||
}
|
||||
ZSTD_customFree(bufPool->buffers, bufPool->cMem);
|
||||
}
|
||||
ZSTD_pthread_mutex_destroy(&bufPool->poolMutex);
|
||||
ZSTD_customFree(bufPool, bufPool->cMem);
|
||||
}
|
||||
|
||||
static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned maxNbBuffers, ZSTD_customMem cMem)
|
||||
{
|
||||
ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_customCalloc(
|
||||
sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
|
||||
ZSTDMT_bufferPool* const bufPool =
|
||||
(ZSTDMT_bufferPool*)ZSTD_customCalloc(sizeof(ZSTDMT_bufferPool), cMem);
|
||||
if (bufPool==NULL) return NULL;
|
||||
if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) {
|
||||
ZSTD_customFree(bufPool, cMem);
|
||||
return NULL;
|
||||
}
|
||||
bufPool->buffers = (buffer_t*)ZSTD_customCalloc(maxNbBuffers * sizeof(buffer_t), cMem);
|
||||
if (bufPool->buffers==NULL) {
|
||||
ZSTDMT_freeBufferPool(bufPool);
|
||||
return NULL;
|
||||
}
|
||||
bufPool->bufferSize = 64 KB;
|
||||
bufPool->totalBuffers = maxNbBuffers;
|
||||
bufPool->nbBuffers = 0;
|
||||
@@ -118,32 +140,19 @@ static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned maxNbBuffers, ZSTD_cu
|
||||
return bufPool;
|
||||
}
|
||||
|
||||
static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
|
||||
{
|
||||
unsigned u;
|
||||
DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool);
|
||||
if (!bufPool) return; /* compatibility with free on NULL */
|
||||
for (u=0; u<bufPool->totalBuffers; u++) {
|
||||
DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start);
|
||||
ZSTD_customFree(bufPool->bTable[u].start, bufPool->cMem);
|
||||
}
|
||||
ZSTD_pthread_mutex_destroy(&bufPool->poolMutex);
|
||||
ZSTD_customFree(bufPool, bufPool->cMem);
|
||||
}
|
||||
|
||||
/* only works at initialization, not during compression */
|
||||
static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
|
||||
{
|
||||
size_t const poolSize = sizeof(*bufPool)
|
||||
+ (bufPool->totalBuffers - 1) * sizeof(buffer_t);
|
||||
size_t const poolSize = sizeof(*bufPool);
|
||||
size_t const arraySize = bufPool->totalBuffers * sizeof(buffer_t);
|
||||
unsigned u;
|
||||
size_t totalBufferSize = 0;
|
||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||
for (u=0; u<bufPool->totalBuffers; u++)
|
||||
totalBufferSize += bufPool->bTable[u].capacity;
|
||||
totalBufferSize += bufPool->buffers[u].capacity;
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
|
||||
return poolSize + totalBufferSize;
|
||||
return poolSize + arraySize + totalBufferSize;
|
||||
}
|
||||
|
||||
/* ZSTDMT_setBufferSize() :
|
||||
@@ -186,9 +195,9 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
|
||||
DEBUGLOG(5, "ZSTDMT_getBuffer: bSize = %u", (U32)bufPool->bufferSize);
|
||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||
if (bufPool->nbBuffers) { /* try to use an existing buffer */
|
||||
buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
|
||||
buffer_t const buf = bufPool->buffers[--(bufPool->nbBuffers)];
|
||||
size_t const availBufferSize = buf.capacity;
|
||||
bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
|
||||
bufPool->buffers[bufPool->nbBuffers] = g_nullBuffer;
|
||||
if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) {
|
||||
/* large enough, but not too much */
|
||||
DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u",
|
||||
@@ -249,14 +258,14 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
|
||||
if (buf.start == NULL) return; /* compatible with release on NULL */
|
||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||
if (bufPool->nbBuffers < bufPool->totalBuffers) {
|
||||
bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */
|
||||
bufPool->buffers[bufPool->nbBuffers++] = buf; /* stored for later use */
|
||||
DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u",
|
||||
(U32)buf.capacity, (U32)(bufPool->nbBuffers-1));
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
return;
|
||||
}
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
/* Reached bufferPool capacity (should not happen) */
|
||||
/* Reached bufferPool capacity (note: should not happen) */
|
||||
DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing ");
|
||||
ZSTD_customFree(buf.start, bufPool->cMem);
|
||||
}
|
||||
@@ -349,16 +358,20 @@ typedef struct {
|
||||
int totalCCtx;
|
||||
int availCCtx;
|
||||
ZSTD_customMem cMem;
|
||||
ZSTD_CCtx* cctx[1]; /* variable size */
|
||||
ZSTD_CCtx** cctxs;
|
||||
} ZSTDMT_CCtxPool;
|
||||
|
||||
/* note : all CCtx borrowed from the pool should be released back to the pool _before_ freeing the pool */
|
||||
/* note : all CCtx borrowed from the pool must be reverted back to the pool _before_ freeing the pool */
|
||||
static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
|
||||
{
|
||||
int cid;
|
||||
for (cid=0; cid<pool->totalCCtx; cid++)
|
||||
ZSTD_freeCCtx(pool->cctx[cid]); /* note : compatible with free on NULL */
|
||||
if (!pool) return;
|
||||
ZSTD_pthread_mutex_destroy(&pool->poolMutex);
|
||||
if (pool->cctxs) {
|
||||
int cid;
|
||||
for (cid=0; cid<pool->totalCCtx; cid++)
|
||||
ZSTD_freeCCtx(pool->cctxs[cid]); /* free compatible with NULL */
|
||||
ZSTD_customFree(pool->cctxs, pool->cMem);
|
||||
}
|
||||
ZSTD_customFree(pool, pool->cMem);
|
||||
}
|
||||
|
||||
@@ -367,19 +380,24 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
|
||||
static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers,
|
||||
ZSTD_customMem cMem)
|
||||
{
|
||||
ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_customCalloc(
|
||||
sizeof(ZSTDMT_CCtxPool) + (nbWorkers-1)*sizeof(ZSTD_CCtx*), cMem);
|
||||
ZSTDMT_CCtxPool* const cctxPool =
|
||||
(ZSTDMT_CCtxPool*) ZSTD_customCalloc(sizeof(ZSTDMT_CCtxPool), cMem);
|
||||
assert(nbWorkers > 0);
|
||||
if (!cctxPool) return NULL;
|
||||
if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
|
||||
ZSTD_customFree(cctxPool, cMem);
|
||||
return NULL;
|
||||
}
|
||||
cctxPool->cMem = cMem;
|
||||
cctxPool->totalCCtx = nbWorkers;
|
||||
cctxPool->cctxs = (ZSTD_CCtx**)ZSTD_customCalloc(nbWorkers * sizeof(ZSTD_CCtx*), cMem);
|
||||
if (!cctxPool->cctxs) {
|
||||
ZSTDMT_freeCCtxPool(cctxPool);
|
||||
return NULL;
|
||||
}
|
||||
cctxPool->cMem = cMem;
|
||||
cctxPool->cctxs[0] = ZSTD_createCCtx_advanced(cMem);
|
||||
if (!cctxPool->cctxs[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; }
|
||||
cctxPool->availCCtx = 1; /* at least one cctx for single-thread mode */
|
||||
cctxPool->cctx[0] = ZSTD_createCCtx_advanced(cMem);
|
||||
if (!cctxPool->cctx[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; }
|
||||
DEBUGLOG(3, "cctxPool created, with %u workers", nbWorkers);
|
||||
return cctxPool;
|
||||
}
|
||||
@@ -401,16 +419,16 @@ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
|
||||
{
|
||||
ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
|
||||
{ unsigned const nbWorkers = cctxPool->totalCCtx;
|
||||
size_t const poolSize = sizeof(*cctxPool)
|
||||
+ (nbWorkers-1) * sizeof(ZSTD_CCtx*);
|
||||
unsigned u;
|
||||
size_t const poolSize = sizeof(*cctxPool);
|
||||
size_t const arraySize = cctxPool->totalCCtx * sizeof(ZSTD_CCtx*);
|
||||
size_t totalCCtxSize = 0;
|
||||
unsigned u;
|
||||
for (u=0; u<nbWorkers; u++) {
|
||||
totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctx[u]);
|
||||
totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctxs[u]);
|
||||
}
|
||||
ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
assert(nbWorkers > 0);
|
||||
return poolSize + totalCCtxSize;
|
||||
return poolSize + arraySize + totalCCtxSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +438,7 @@ static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool)
|
||||
ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
|
||||
if (cctxPool->availCCtx) {
|
||||
cctxPool->availCCtx--;
|
||||
{ ZSTD_CCtx* const cctx = cctxPool->cctx[cctxPool->availCCtx];
|
||||
{ ZSTD_CCtx* const cctx = cctxPool->cctxs[cctxPool->availCCtx];
|
||||
ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
return cctx;
|
||||
} }
|
||||
@@ -434,7 +452,7 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
|
||||
if (cctx==NULL) return; /* compatibility with release on NULL */
|
||||
ZSTD_pthread_mutex_lock(&pool->poolMutex);
|
||||
if (pool->availCCtx < pool->totalCCtx)
|
||||
pool->cctx[pool->availCCtx++] = cctx;
|
||||
pool->cctxs[pool->availCCtx++] = cctx;
|
||||
else {
|
||||
/* pool overflow : should not happen, since totalCCtx==nbWorkers */
|
||||
DEBUGLOG(4, "CCtx pool overflow : free cctx");
|
||||
@@ -600,11 +618,8 @@ static void ZSTDMT_serialState_update(serialState_t* serialState,
|
||||
ZSTD_pthread_mutex_unlock(&serialState->mutex);
|
||||
|
||||
if (seqStore.size > 0) {
|
||||
size_t const err = ZSTD_referenceExternalSequences(
|
||||
jobCCtx, seqStore.seq, seqStore.size);
|
||||
ZSTD_referenceExternalSequences(jobCCtx, seqStore.seq, seqStore.size);
|
||||
assert(serialState->params.ldmParams.enableLdm == ZSTD_ps_enable);
|
||||
assert(!ZSTD_isError(err));
|
||||
(void)err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,12 +671,13 @@ typedef struct {
|
||||
unsigned frameChecksumNeeded; /* used only by mtctx */
|
||||
} ZSTDMT_jobDescription;
|
||||
|
||||
#define JOB_ERROR(e) { \
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \
|
||||
job->cSize = e; \
|
||||
ZSTD_pthread_mutex_unlock(&job->job_mutex); \
|
||||
goto _endJob; \
|
||||
}
|
||||
#define JOB_ERROR(e) \
|
||||
do { \
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \
|
||||
job->cSize = e; \
|
||||
ZSTD_pthread_mutex_unlock(&job->job_mutex); \
|
||||
goto _endJob; \
|
||||
} while (0)
|
||||
|
||||
/* ZSTDMT_compressionJob() is a POOL_function type */
|
||||
static void ZSTDMT_compressionJob(void* jobDescription)
|
||||
@@ -719,7 +735,7 @@ static void ZSTDMT_compressionJob(void* jobDescription)
|
||||
ZSTDMT_serialState_update(job->serial, cctx, rawSeqStore, job->src, job->jobID);
|
||||
|
||||
if (!job->firstJob) { /* flush and overwrite frame header when it's not first job */
|
||||
size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0);
|
||||
size_t const hSize = ZSTD_compressContinue_public(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0);
|
||||
if (ZSTD_isError(hSize)) JOB_ERROR(hSize);
|
||||
DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize);
|
||||
ZSTD_invalidateRepCodes(cctx);
|
||||
@@ -737,7 +753,7 @@ static void ZSTDMT_compressionJob(void* jobDescription)
|
||||
DEBUGLOG(5, "ZSTDMT_compressionJob: compress %u bytes in %i blocks", (U32)job->src.size, nbChunks);
|
||||
assert(job->cSize == 0);
|
||||
for (chunkNb = 1; chunkNb < nbChunks; chunkNb++) {
|
||||
size_t const cSize = ZSTD_compressContinue(cctx, op, oend-op, ip, chunkSize);
|
||||
size_t const cSize = ZSTD_compressContinue_public(cctx, op, oend-op, ip, chunkSize);
|
||||
if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
|
||||
ip += chunkSize;
|
||||
op += cSize; assert(op < oend);
|
||||
@@ -757,8 +773,8 @@ static void ZSTDMT_compressionJob(void* jobDescription)
|
||||
size_t const lastBlockSize1 = job->src.size & (chunkSize-1);
|
||||
size_t const lastBlockSize = ((lastBlockSize1==0) & (job->src.size>=chunkSize)) ? chunkSize : lastBlockSize1;
|
||||
size_t const cSize = (job->lastJob) ?
|
||||
ZSTD_compressEnd (cctx, op, oend-op, ip, lastBlockSize) :
|
||||
ZSTD_compressContinue(cctx, op, oend-op, ip, lastBlockSize);
|
||||
ZSTD_compressEnd_public(cctx, op, oend-op, ip, lastBlockSize) :
|
||||
ZSTD_compressContinue_public(cctx, op, oend-op, ip, lastBlockSize);
|
||||
if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
|
||||
lastCBlockSize = cSize;
|
||||
} }
|
||||
@@ -1090,7 +1106,7 @@ ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
|
||||
{ unsigned jobNb;
|
||||
unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1);
|
||||
DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)",
|
||||
mtctx->doneJobID, lastJobNb, mtctx->jobReady)
|
||||
mtctx->doneJobID, lastJobNb, mtctx->jobReady);
|
||||
for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) {
|
||||
unsigned const wJobID = jobNb & mtctx->jobIDMask;
|
||||
ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID];
|
||||
|
||||
+192
-130
@@ -34,6 +34,12 @@
|
||||
* Macros
|
||||
****************************************************************/
|
||||
|
||||
#ifdef HUF_DISABLE_FAST_DECODE
|
||||
# define HUF_ENABLE_FAST_DECODE 0
|
||||
#else
|
||||
# define HUF_ENABLE_FAST_DECODE 1
|
||||
#endif
|
||||
|
||||
/* These two optional macros force the use one way or another of the two
|
||||
* Huffman decompression implementations. You can't force in both directions
|
||||
* at the same time.
|
||||
@@ -158,17 +164,18 @@ static size_t HUF_initFastDStream(BYTE const* ip) {
|
||||
* op [in/out] - The output pointers, must be updated to reflect what is written.
|
||||
* bits [in/out] - The bitstream containers, must be updated to reflect the current state.
|
||||
* dt [in] - The decoding table.
|
||||
* ilimit [in] - The input limit, stop when any input pointer is below ilimit.
|
||||
* ilowest [in] - The beginning of the valid range of the input. Decoders may read
|
||||
* down to this pointer. It may be below iend[0].
|
||||
* oend [in] - The end of the output stream. op[3] must not cross oend.
|
||||
* iend [in] - The end of each input stream. ip[i] may cross iend[i],
|
||||
* as long as it is above ilimit, but that indicates corruption.
|
||||
* as long as it is above ilowest, but that indicates corruption.
|
||||
*/
|
||||
typedef struct {
|
||||
BYTE const* ip[4];
|
||||
BYTE* op[4];
|
||||
U64 bits[4];
|
||||
void const* dt;
|
||||
BYTE const* ilimit;
|
||||
BYTE const* ilowest;
|
||||
BYTE* oend;
|
||||
BYTE const* iend[4];
|
||||
} HUF_DecompressFastArgs;
|
||||
@@ -186,9 +193,9 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
void const* dt = DTable + 1;
|
||||
U32 const dtLog = HUF_getDTableDesc(DTable).tableLog;
|
||||
|
||||
const BYTE* const ilimit = (const BYTE*)src + 6 + 8;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
|
||||
BYTE* const oend = (BYTE*)dst + dstSize;
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
|
||||
|
||||
/* The fast decoding loop assumes 64-bit little-endian.
|
||||
* This condition is false on x32.
|
||||
@@ -196,6 +203,11 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
if (!MEM_isLittleEndian() || MEM_32bits())
|
||||
return 0;
|
||||
|
||||
/* Avoid nullptr addition */
|
||||
if (dstSize == 0)
|
||||
return 0;
|
||||
assert(dst != NULL);
|
||||
|
||||
/* strict minimum : jump table + 1 byte per stream */
|
||||
if (srcSize < 10)
|
||||
return ERROR(corruption_detected);
|
||||
@@ -209,7 +221,6 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
|
||||
/* Read the jump table. */
|
||||
{
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
size_t const length1 = MEM_readLE16(istart);
|
||||
size_t const length2 = MEM_readLE16(istart+2);
|
||||
size_t const length3 = MEM_readLE16(istart+4);
|
||||
@@ -221,10 +232,8 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
|
||||
/* HUF_initFastDStream() requires this, and this small of an input
|
||||
* won't benefit from the ASM loop anyways.
|
||||
* length1 must be >= 16 so that ip[0] >= ilimit before the loop
|
||||
* starts.
|
||||
*/
|
||||
if (length1 < 16 || length2 < 8 || length3 < 8 || length4 < 8)
|
||||
if (length1 < 8 || length2 < 8 || length3 < 8 || length4 < 8)
|
||||
return 0;
|
||||
if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */
|
||||
}
|
||||
@@ -256,11 +265,12 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
args->bits[2] = HUF_initFastDStream(args->ip[2]);
|
||||
args->bits[3] = HUF_initFastDStream(args->ip[3]);
|
||||
|
||||
/* If ip[] >= ilimit, it is guaranteed to be safe to
|
||||
* reload bits[]. It may be beyond its section, but is
|
||||
* guaranteed to be valid (>= istart).
|
||||
*/
|
||||
args->ilimit = ilimit;
|
||||
/* The decoders must be sure to never read beyond ilowest.
|
||||
* This is lower than iend[0], but allowing decoders to read
|
||||
* down to ilowest can allow an extra iteration or two in the
|
||||
* fast loop.
|
||||
*/
|
||||
args->ilowest = istart;
|
||||
|
||||
args->oend = oend;
|
||||
args->dt = dt;
|
||||
@@ -285,13 +295,31 @@ static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArg
|
||||
assert(sizeof(size_t) == 8);
|
||||
bit->bitContainer = MEM_readLEST(args->ip[stream]);
|
||||
bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]);
|
||||
bit->start = (const char*)args->iend[0];
|
||||
bit->start = (const char*)args->ilowest;
|
||||
bit->limitPtr = bit->start + sizeof(size_t);
|
||||
bit->ptr = (const char*)args->ip[stream];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calls X(N) for each stream 0, 1, 2, 3. */
|
||||
#define HUF_4X_FOR_EACH_STREAM(X) \
|
||||
do { \
|
||||
X(0); \
|
||||
X(1); \
|
||||
X(2); \
|
||||
X(3); \
|
||||
} while (0)
|
||||
|
||||
/* Calls X(N, var) for each stream 0, 1, 2, 3. */
|
||||
#define HUF_4X_FOR_EACH_STREAM_WITH_VAR(X, var) \
|
||||
do { \
|
||||
X(0, (var)); \
|
||||
X(1, (var)); \
|
||||
X(2, (var)); \
|
||||
X(3, (var)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||
|
||||
@@ -500,15 +528,19 @@ HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog
|
||||
}
|
||||
|
||||
#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \
|
||||
*ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog)
|
||||
do { *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog); } while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
|
||||
#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \
|
||||
} while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
|
||||
if (MEM_64bits()) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
|
||||
#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits()) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \
|
||||
} while (0)
|
||||
|
||||
HINT_INLINE size_t
|
||||
HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog)
|
||||
@@ -546,7 +578,7 @@ HUF_decompress1X1_usingDTable_internal_body(
|
||||
const HUF_DTable* DTable)
|
||||
{
|
||||
BYTE* op = (BYTE*)dst;
|
||||
BYTE* const oend = op + dstSize;
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd(op, dstSize);
|
||||
const void* dtPtr = DTable + 1;
|
||||
const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
|
||||
BIT_DStream_t bitD;
|
||||
@@ -574,6 +606,7 @@ HUF_decompress4X1_usingDTable_internal_body(
|
||||
{
|
||||
/* Check */
|
||||
if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
|
||||
if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */
|
||||
|
||||
{ const BYTE* const istart = (const BYTE*) cSrc;
|
||||
BYTE* const ostart = (BYTE*) dst;
|
||||
@@ -609,7 +642,7 @@ HUF_decompress4X1_usingDTable_internal_body(
|
||||
|
||||
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
||||
if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */
|
||||
if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */
|
||||
assert(dstSize >= 6); /* validated above */
|
||||
CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
|
||||
CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
|
||||
CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
|
||||
@@ -692,11 +725,11 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
BYTE* op[4];
|
||||
U16 const* const dtable = (U16 const*)args->dt;
|
||||
BYTE* const oend = args->oend;
|
||||
BYTE const* const ilimit = args->ilimit;
|
||||
BYTE const* const ilowest = args->ilowest;
|
||||
|
||||
/* Copy the arguments to local variables */
|
||||
ZSTD_memcpy(&bits, &args->bits, sizeof(bits));
|
||||
ZSTD_memcpy(&ip, &args->ip, sizeof(ip));
|
||||
ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip));
|
||||
ZSTD_memcpy(&op, &args->op, sizeof(op));
|
||||
|
||||
assert(MEM_isLittleEndian());
|
||||
@@ -705,13 +738,12 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
for (;;) {
|
||||
BYTE* olimit;
|
||||
int stream;
|
||||
int symbol;
|
||||
|
||||
/* Assert loop preconditions */
|
||||
#ifndef NDEBUG
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
assert(op[stream] <= (stream == 3 ? oend : op[stream + 1]));
|
||||
assert(ip[stream] >= ilimit);
|
||||
assert(ip[stream] >= ilowest);
|
||||
}
|
||||
#endif
|
||||
/* Compute olimit */
|
||||
@@ -721,7 +753,7 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
/* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes
|
||||
* per stream.
|
||||
*/
|
||||
size_t const iiters = (size_t)(ip[0] - ilimit) / 7;
|
||||
size_t const iiters = (size_t)(ip[0] - ilowest) / 7;
|
||||
/* We can safely run iters iterations before running bounds checks */
|
||||
size_t const iters = MIN(oiters, iiters);
|
||||
size_t const symbols = iters * 5;
|
||||
@@ -732,8 +764,8 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
*/
|
||||
olimit = op[3] + symbols;
|
||||
|
||||
/* Exit fast decoding loop once we get close to the end. */
|
||||
if (op[3] + 20 > olimit)
|
||||
/* Exit fast decoding loop once we reach the end. */
|
||||
if (op[3] == olimit)
|
||||
break;
|
||||
|
||||
/* Exit the decoding loop if any input pointer has crossed the
|
||||
@@ -752,34 +784,49 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HUF_4X1_DECODE_SYMBOL(_stream, _symbol) \
|
||||
do { \
|
||||
int const index = (int)(bits[(_stream)] >> 53); \
|
||||
int const entry = (int)dtable[index]; \
|
||||
bits[(_stream)] <<= (entry & 0x3F); \
|
||||
op[(_stream)][(_symbol)] = (BYTE)((entry >> 8) & 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#define HUF_4X1_RELOAD_STREAM(_stream) \
|
||||
do { \
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \
|
||||
int const nbBits = ctz & 7; \
|
||||
int const nbBytes = ctz >> 3; \
|
||||
op[(_stream)] += 5; \
|
||||
ip[(_stream)] -= nbBytes; \
|
||||
bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \
|
||||
bits[(_stream)] <<= nbBits; \
|
||||
} while (0)
|
||||
|
||||
/* Manually unroll the loop because compilers don't consistently
|
||||
* unroll the inner loops, which destroys performance.
|
||||
*/
|
||||
do {
|
||||
/* Decode 5 symbols in each of the 4 streams */
|
||||
for (symbol = 0; symbol < 5; ++symbol) {
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
int const index = (int)(bits[stream] >> 53);
|
||||
int const entry = (int)dtable[index];
|
||||
bits[stream] <<= (entry & 63);
|
||||
op[stream][symbol] = (BYTE)((entry >> 8) & 0xFF);
|
||||
}
|
||||
}
|
||||
/* Reload the bitstreams */
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[stream]);
|
||||
int const nbBits = ctz & 7;
|
||||
int const nbBytes = ctz >> 3;
|
||||
op[stream] += 5;
|
||||
ip[stream] -= nbBytes;
|
||||
bits[stream] = MEM_read64(ip[stream]) | 1;
|
||||
bits[stream] <<= nbBits;
|
||||
}
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 1);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 2);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 3);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 4);
|
||||
|
||||
/* Reload each of the 4 the bitstreams */
|
||||
HUF_4X_FOR_EACH_STREAM(HUF_4X1_RELOAD_STREAM);
|
||||
} while (op[3] < olimit);
|
||||
|
||||
#undef HUF_4X1_DECODE_SYMBOL
|
||||
#undef HUF_4X1_RELOAD_STREAM
|
||||
}
|
||||
|
||||
_out:
|
||||
|
||||
/* Save the final values of each of the state variables back to args. */
|
||||
ZSTD_memcpy(&args->bits, &bits, sizeof(bits));
|
||||
ZSTD_memcpy(&args->ip, &ip, sizeof(ip));
|
||||
ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip));
|
||||
ZSTD_memcpy(&args->op, &op, sizeof(op));
|
||||
}
|
||||
|
||||
@@ -797,8 +844,8 @@ HUF_decompress4X1_usingDTable_internal_fast(
|
||||
HUF_DecompressFastLoopFn loopFn)
|
||||
{
|
||||
void const* dt = DTable + 1;
|
||||
const BYTE* const iend = (const BYTE*)cSrc + 6;
|
||||
BYTE* const oend = (BYTE*)dst + dstSize;
|
||||
BYTE const* const ilowest = (BYTE const*)cSrc;
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
|
||||
HUF_DecompressFastArgs args;
|
||||
{ size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable);
|
||||
FORWARD_IF_ERROR(ret, "Failed to init fast loop args");
|
||||
@@ -806,18 +853,22 @@ HUF_decompress4X1_usingDTable_internal_fast(
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(args.ip[0] >= args.ilimit);
|
||||
assert(args.ip[0] >= args.ilowest);
|
||||
loopFn(&args);
|
||||
|
||||
/* Our loop guarantees that ip[] >= ilimit and that we haven't
|
||||
/* Our loop guarantees that ip[] >= ilowest and that we haven't
|
||||
* overwritten any op[].
|
||||
*/
|
||||
assert(args.ip[0] >= iend);
|
||||
assert(args.ip[1] >= iend);
|
||||
assert(args.ip[2] >= iend);
|
||||
assert(args.ip[3] >= iend);
|
||||
assert(args.ip[0] >= ilowest);
|
||||
assert(args.ip[0] >= ilowest);
|
||||
assert(args.ip[1] >= ilowest);
|
||||
assert(args.ip[2] >= ilowest);
|
||||
assert(args.ip[3] >= ilowest);
|
||||
assert(args.op[3] <= oend);
|
||||
(void)iend;
|
||||
|
||||
assert(ilowest == args.ilowest);
|
||||
assert(ilowest + 6 == args.iend[0]);
|
||||
(void)ilowest;
|
||||
|
||||
/* finish bit streams one by one. */
|
||||
{ size_t const segmentSize = (dstSize+3) / 4;
|
||||
@@ -868,7 +919,7 @@ static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(flags & HUF_flags_disableFast)) {
|
||||
if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) {
|
||||
size_t const ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
@@ -1239,15 +1290,19 @@ HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, c
|
||||
}
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
do { ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); } while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \
|
||||
} while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
||||
if (MEM_64bits()) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits()) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \
|
||||
} while (0)
|
||||
|
||||
HINT_INLINE size_t
|
||||
HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
|
||||
@@ -1307,7 +1362,7 @@ HUF_decompress1X2_usingDTable_internal_body(
|
||||
|
||||
/* decode */
|
||||
{ BYTE* const ostart = (BYTE*) dst;
|
||||
BYTE* const oend = ostart + dstSize;
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd(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);
|
||||
@@ -1332,6 +1387,7 @@ HUF_decompress4X2_usingDTable_internal_body(
|
||||
const HUF_DTable* DTable)
|
||||
{
|
||||
if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
|
||||
if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */
|
||||
|
||||
{ const BYTE* const istart = (const BYTE*) cSrc;
|
||||
BYTE* const ostart = (BYTE*) dst;
|
||||
@@ -1367,7 +1423,7 @@ HUF_decompress4X2_usingDTable_internal_body(
|
||||
|
||||
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
||||
if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */
|
||||
if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */
|
||||
assert(dstSize >= 6 /* validated above */);
|
||||
CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
|
||||
CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
|
||||
CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
|
||||
@@ -1472,11 +1528,11 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
BYTE* op[4];
|
||||
BYTE* oend[4];
|
||||
HUF_DEltX2 const* const dtable = (HUF_DEltX2 const*)args->dt;
|
||||
BYTE const* const ilimit = args->ilimit;
|
||||
BYTE const* const ilowest = args->ilowest;
|
||||
|
||||
/* Copy the arguments to local registers. */
|
||||
ZSTD_memcpy(&bits, &args->bits, sizeof(bits));
|
||||
ZSTD_memcpy(&ip, &args->ip, sizeof(ip));
|
||||
ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip));
|
||||
ZSTD_memcpy(&op, &args->op, sizeof(op));
|
||||
|
||||
oend[0] = op[1];
|
||||
@@ -1490,13 +1546,12 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
for (;;) {
|
||||
BYTE* olimit;
|
||||
int stream;
|
||||
int symbol;
|
||||
|
||||
/* Assert loop preconditions */
|
||||
#ifndef NDEBUG
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
assert(op[stream] <= oend[stream]);
|
||||
assert(ip[stream] >= ilimit);
|
||||
assert(ip[stream] >= ilowest);
|
||||
}
|
||||
#endif
|
||||
/* Compute olimit */
|
||||
@@ -1509,7 +1564,7 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
* We also know that each input pointer is >= ip[0]. So we can run
|
||||
* iters loops before running out of input.
|
||||
*/
|
||||
size_t iters = (size_t)(ip[0] - ilimit) / 7;
|
||||
size_t iters = (size_t)(ip[0] - ilowest) / 7;
|
||||
/* Each iteration can produce up to 10 bytes of output per stream.
|
||||
* Each output stream my advance at different rates. So take the
|
||||
* minimum number of safe iterations among all the output streams.
|
||||
@@ -1527,8 +1582,8 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
*/
|
||||
olimit = op[3] + (iters * 5);
|
||||
|
||||
/* Exit the fast decoding loop if we are too close to the end. */
|
||||
if (op[3] + 10 > olimit)
|
||||
/* Exit the fast decoding loop once we reach the end. */
|
||||
if (op[3] == olimit)
|
||||
break;
|
||||
|
||||
/* Exit the decoding loop if any input pointer has crossed the
|
||||
@@ -1547,59 +1602,63 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HUF_4X2_DECODE_SYMBOL(_stream, _decode3) \
|
||||
do { \
|
||||
if ((_decode3) || (_stream) != 3) { \
|
||||
int const index = (int)(bits[(_stream)] >> 53); \
|
||||
HUF_DEltX2 const entry = dtable[index]; \
|
||||
MEM_write16(op[(_stream)], entry.sequence); \
|
||||
bits[(_stream)] <<= (entry.nbBits) & 0x3F; \
|
||||
op[(_stream)] += (entry.length); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define HUF_4X2_RELOAD_STREAM(_stream) \
|
||||
do { \
|
||||
HUF_4X2_DECODE_SYMBOL(3, 1); \
|
||||
{ \
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \
|
||||
int const nbBits = ctz & 7; \
|
||||
int const nbBytes = ctz >> 3; \
|
||||
ip[(_stream)] -= nbBytes; \
|
||||
bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \
|
||||
bits[(_stream)] <<= nbBits; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Manually unroll the loop because compilers don't consistently
|
||||
* unroll the inner loops, which destroys performance.
|
||||
*/
|
||||
do {
|
||||
/* Do 5 table lookups for each of the first 3 streams */
|
||||
for (symbol = 0; symbol < 5; ++symbol) {
|
||||
for (stream = 0; stream < 3; ++stream) {
|
||||
int const index = (int)(bits[stream] >> 53);
|
||||
HUF_DEltX2 const entry = dtable[index];
|
||||
MEM_write16(op[stream], entry.sequence);
|
||||
bits[stream] <<= (entry.nbBits);
|
||||
op[stream] += (entry.length);
|
||||
}
|
||||
}
|
||||
/* Do 1 table lookup from the final stream */
|
||||
{
|
||||
int const index = (int)(bits[3] >> 53);
|
||||
HUF_DEltX2 const entry = dtable[index];
|
||||
MEM_write16(op[3], entry.sequence);
|
||||
bits[3] <<= (entry.nbBits);
|
||||
op[3] += (entry.length);
|
||||
}
|
||||
/* Do 4 table lookups from the final stream & reload bitstreams */
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
/* Do a table lookup from the final stream.
|
||||
* This is interleaved with the reloading to reduce register
|
||||
* pressure. This shouldn't be necessary, but compilers can
|
||||
* struggle with codegen with high register pressure.
|
||||
*/
|
||||
{
|
||||
int const index = (int)(bits[3] >> 53);
|
||||
HUF_DEltX2 const entry = dtable[index];
|
||||
MEM_write16(op[3], entry.sequence);
|
||||
bits[3] <<= (entry.nbBits);
|
||||
op[3] += (entry.length);
|
||||
}
|
||||
/* Reload the bistreams. The final bitstream must be reloaded
|
||||
* after the 5th symbol was decoded.
|
||||
*/
|
||||
{
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[stream]);
|
||||
int const nbBits = ctz & 7;
|
||||
int const nbBytes = ctz >> 3;
|
||||
ip[stream] -= nbBytes;
|
||||
bits[stream] = MEM_read64(ip[stream]) | 1;
|
||||
bits[stream] <<= nbBits;
|
||||
}
|
||||
}
|
||||
/* Decode 5 symbols from each of the first 3 streams.
|
||||
* The final stream will be decoded during the reload phase
|
||||
* to reduce register pressure.
|
||||
*/
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
|
||||
/* Decode one symbol from the final stream */
|
||||
HUF_4X2_DECODE_SYMBOL(3, 1);
|
||||
|
||||
/* Decode 4 symbols from the final stream & reload bitstreams.
|
||||
* The final stream is reloaded last, meaning that all 5 symbols
|
||||
* are decoded from the final stream before it is reloaded.
|
||||
*/
|
||||
HUF_4X_FOR_EACH_STREAM(HUF_4X2_RELOAD_STREAM);
|
||||
} while (op[3] < olimit);
|
||||
}
|
||||
|
||||
#undef HUF_4X2_DECODE_SYMBOL
|
||||
#undef HUF_4X2_RELOAD_STREAM
|
||||
|
||||
_out:
|
||||
|
||||
/* Save the final values of each of the state variables back to args. */
|
||||
ZSTD_memcpy(&args->bits, &bits, sizeof(bits));
|
||||
ZSTD_memcpy(&args->ip, &ip, sizeof(ip));
|
||||
ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip));
|
||||
ZSTD_memcpy(&args->op, &op, sizeof(op));
|
||||
}
|
||||
|
||||
@@ -1611,8 +1670,8 @@ HUF_decompress4X2_usingDTable_internal_fast(
|
||||
const HUF_DTable* DTable,
|
||||
HUF_DecompressFastLoopFn loopFn) {
|
||||
void const* dt = DTable + 1;
|
||||
const BYTE* const iend = (const BYTE*)cSrc + 6;
|
||||
BYTE* const oend = (BYTE*)dst + dstSize;
|
||||
const BYTE* const ilowest = (const BYTE*)cSrc;
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
|
||||
HUF_DecompressFastArgs args;
|
||||
{
|
||||
size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable);
|
||||
@@ -1621,16 +1680,19 @@ HUF_decompress4X2_usingDTable_internal_fast(
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(args.ip[0] >= args.ilimit);
|
||||
assert(args.ip[0] >= args.ilowest);
|
||||
loopFn(&args);
|
||||
|
||||
/* note : op4 already verified within main loop */
|
||||
assert(args.ip[0] >= iend);
|
||||
assert(args.ip[1] >= iend);
|
||||
assert(args.ip[2] >= iend);
|
||||
assert(args.ip[3] >= iend);
|
||||
assert(args.ip[0] >= ilowest);
|
||||
assert(args.ip[1] >= ilowest);
|
||||
assert(args.ip[2] >= ilowest);
|
||||
assert(args.ip[3] >= ilowest);
|
||||
assert(args.op[3] <= oend);
|
||||
(void)iend;
|
||||
|
||||
assert(ilowest == args.ilowest);
|
||||
assert(ilowest + 6 == args.iend[0]);
|
||||
(void)ilowest;
|
||||
|
||||
/* finish bitStreams one by one */
|
||||
{
|
||||
@@ -1679,7 +1741,7 @@ static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(flags & HUF_flags_disableFast)) {
|
||||
if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) {
|
||||
size_t const ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
@@ -10,11 +10,32 @@
|
||||
|
||||
#include "../common/portability_macros.h"
|
||||
|
||||
#if defined(__ELF__) && defined(__GNUC__)
|
||||
/* Stack marking
|
||||
* ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart
|
||||
*/
|
||||
#if defined(__ELF__) && defined(__GNUC__)
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
#if defined(__aarch64__)
|
||||
/* Mark that this assembly supports BTI & PAC, because it is empty for aarch64.
|
||||
* See: https://github.com/facebook/zstd/issues/3841
|
||||
* See: https://gcc.godbolt.org/z/sqr5T4ffK
|
||||
* See: https://lore.kernel.org/linux-arm-kernel/20200429211641.9279-8-broonie@kernel.org/
|
||||
* See: https://reviews.llvm.org/D62609
|
||||
*/
|
||||
.pushsection .note.gnu.property, "a"
|
||||
.p2align 3
|
||||
.long 4 /* size of the name - "GNU\0" */
|
||||
.long 0x10 /* size of descriptor */
|
||||
.long 0x5 /* NT_GNU_PROPERTY_TYPE_0 */
|
||||
.asciz "GNU"
|
||||
.long 0xc0000000 /* pr_type - GNU_PROPERTY_AARCH64_FEATURE_1_AND */
|
||||
.long 4 /* pr_datasz - 4 bytes */
|
||||
.long 3 /* pr_data - GNU_PROPERTY_AARCH64_FEATURE_1_BTI | GNU_PROPERTY_AARCH64_FEATURE_1_PAC */
|
||||
.p2align 3 /* pr_padding - bring everything to 8 byte alignment */
|
||||
.popsection
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if ZSTD_ENABLE_ASM_X86_64_BMI2
|
||||
@@ -131,7 +152,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
movq 88(%rax), %bits3
|
||||
movq 96(%rax), %dtable
|
||||
push %rax /* argument */
|
||||
push 104(%rax) /* ilimit */
|
||||
push 104(%rax) /* ilowest */
|
||||
push 112(%rax) /* oend */
|
||||
push %olimit /* olimit space */
|
||||
|
||||
@@ -156,11 +177,11 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
shrq $2, %r15
|
||||
|
||||
movq %ip0, %rax /* rax = ip0 */
|
||||
movq 40(%rsp), %rdx /* rdx = ilimit */
|
||||
subq %rdx, %rax /* rax = ip0 - ilimit */
|
||||
movq %rax, %rbx /* rbx = ip0 - ilimit */
|
||||
movq 40(%rsp), %rdx /* rdx = ilowest */
|
||||
subq %rdx, %rax /* rax = ip0 - ilowest */
|
||||
movq %rax, %rbx /* rbx = ip0 - ilowest */
|
||||
|
||||
/* rdx = (ip0 - ilimit) / 7 */
|
||||
/* rdx = (ip0 - ilowest) / 7 */
|
||||
movabsq $2635249153387078803, %rdx
|
||||
mulq %rdx
|
||||
subq %rdx, %rbx
|
||||
@@ -183,9 +204,8 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
|
||||
/* If (op3 + 20 > olimit) */
|
||||
movq %op3, %rax /* rax = op3 */
|
||||
addq $20, %rax /* rax = op3 + 20 */
|
||||
cmpq %rax, %olimit /* op3 + 20 > olimit */
|
||||
jb .L_4X1_exit
|
||||
cmpq %rax, %olimit /* op3 == olimit */
|
||||
je .L_4X1_exit
|
||||
|
||||
/* If (ip1 < ip0) go to exit */
|
||||
cmpq %ip0, %ip1
|
||||
@@ -316,7 +336,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
/* Restore stack (oend & olimit) */
|
||||
pop %rax /* olimit */
|
||||
pop %rax /* oend */
|
||||
pop %rax /* ilimit */
|
||||
pop %rax /* ilowest */
|
||||
pop %rax /* arg */
|
||||
|
||||
/* Save ip / op / bits */
|
||||
@@ -387,7 +407,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
movq 96(%rax), %dtable
|
||||
push %rax /* argument */
|
||||
push %rax /* olimit */
|
||||
push 104(%rax) /* ilimit */
|
||||
push 104(%rax) /* ilowest */
|
||||
|
||||
movq 112(%rax), %rax
|
||||
push %rax /* oend3 */
|
||||
@@ -414,9 +434,9 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
|
||||
/* We can consume up to 7 input bytes each iteration. */
|
||||
movq %ip0, %rax /* rax = ip0 */
|
||||
movq 40(%rsp), %rdx /* rdx = ilimit */
|
||||
subq %rdx, %rax /* rax = ip0 - ilimit */
|
||||
movq %rax, %r15 /* r15 = ip0 - ilimit */
|
||||
movq 40(%rsp), %rdx /* rdx = ilowest */
|
||||
subq %rdx, %rax /* rax = ip0 - ilowest */
|
||||
movq %rax, %r15 /* r15 = ip0 - ilowest */
|
||||
|
||||
/* rdx = rax / 7 */
|
||||
movabsq $2635249153387078803, %rdx
|
||||
@@ -426,7 +446,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
addq %r15, %rdx
|
||||
shrq $2, %rdx
|
||||
|
||||
/* r15 = (ip0 - ilimit) / 7 */
|
||||
/* r15 = (ip0 - ilowest) / 7 */
|
||||
movq %rdx, %r15
|
||||
|
||||
/* r15 = min(r15, min(oend0 - op0, oend1 - op1, oend2 - op2, oend3 - op3) / 10) */
|
||||
@@ -467,9 +487,8 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
|
||||
/* If (op3 + 10 > olimit) */
|
||||
movq %op3, %rax /* rax = op3 */
|
||||
addq $10, %rax /* rax = op3 + 10 */
|
||||
cmpq %rax, %olimit /* op3 + 10 > olimit */
|
||||
jb .L_4X2_exit
|
||||
cmpq %rax, %olimit /* op3 == olimit */
|
||||
je .L_4X2_exit
|
||||
|
||||
/* If (ip1 < ip0) go to exit */
|
||||
cmpq %ip0, %ip1
|
||||
@@ -537,7 +556,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
pop %rax /* oend1 */
|
||||
pop %rax /* oend2 */
|
||||
pop %rax /* oend3 */
|
||||
pop %rax /* ilimit */
|
||||
pop %rax /* ilowest */
|
||||
pop %rax /* olimit */
|
||||
pop %rax /* arg */
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
/*-*******************************************************
|
||||
* Dependencies
|
||||
*********************************************************/
|
||||
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */
|
||||
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
||||
#include "../common/cpu.h" /* bmi2 */
|
||||
#include "../common/mem.h" /* low level memory routines */
|
||||
|
||||
@@ -56,16 +56,18 @@
|
||||
* Dependencies
|
||||
*********************************************************/
|
||||
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
||||
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */
|
||||
#include "../common/error_private.h"
|
||||
#include "../common/zstd_internal.h" /* blockProperties_t */
|
||||
#include "../common/mem.h" /* low level memory routines */
|
||||
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||
#define FSE_STATIC_LINKING_ONLY
|
||||
#include "../common/fse.h"
|
||||
#include "../common/huf.h"
|
||||
#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */
|
||||
#include "../common/zstd_internal.h" /* blockProperties_t */
|
||||
#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
|
||||
#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
|
||||
#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
|
||||
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
|
||||
# include "../legacy/zstd_legacy.h"
|
||||
@@ -244,6 +246,7 @@ static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)
|
||||
dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
|
||||
dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;
|
||||
dctx->disableHufAsm = 0;
|
||||
dctx->maxBlockSizeParam = 0;
|
||||
}
|
||||
|
||||
static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||
@@ -264,6 +267,7 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||
#endif
|
||||
dctx->noForwardProgress = 0;
|
||||
dctx->oversizedDuration = 0;
|
||||
dctx->isFrameDecompression = 1;
|
||||
#if DYNAMIC_BMI2
|
||||
dctx->bmi2 = ZSTD_cpuSupportsBmi2();
|
||||
#endif
|
||||
@@ -588,49 +592,52 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize)
|
||||
sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
|
||||
RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
|
||||
frameParameter_unsupported, "");
|
||||
{
|
||||
size_t const skippableSize = skippableHeaderSize + sizeU32;
|
||||
{ size_t const skippableSize = skippableHeaderSize + sizeU32;
|
||||
RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
|
||||
return skippableSize;
|
||||
}
|
||||
}
|
||||
|
||||
/*! ZSTD_readSkippableFrame() :
|
||||
* Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer.
|
||||
* Retrieves content of a skippable frame, and writes it to dst buffer.
|
||||
*
|
||||
* The parameter magicVariant will receive the magicVariant that was supplied when the frame was written,
|
||||
* i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested
|
||||
* in the magicVariant.
|
||||
*
|
||||
* Returns an error if destination buffer is not large enough, or if the frame is not skippable.
|
||||
* Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame.
|
||||
*
|
||||
* @return : number of bytes written or a ZSTD error.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant,
|
||||
const void* src, size_t srcSize)
|
||||
size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity,
|
||||
unsigned* magicVariant, /* optional, can be NULL */
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
U32 const magicNumber = MEM_readLE32(src);
|
||||
size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);
|
||||
size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;
|
||||
RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");
|
||||
|
||||
/* check input validity */
|
||||
RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, "");
|
||||
RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, "");
|
||||
RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, "");
|
||||
{ U32 const magicNumber = MEM_readLE32(src);
|
||||
size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);
|
||||
size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;
|
||||
|
||||
/* deliver payload */
|
||||
if (skippableContentSize > 0 && dst != NULL)
|
||||
ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize);
|
||||
if (magicVariant != NULL)
|
||||
*magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;
|
||||
return skippableContentSize;
|
||||
/* check input validity */
|
||||
RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, "");
|
||||
RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, "");
|
||||
RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, "");
|
||||
|
||||
/* deliver payload */
|
||||
if (skippableContentSize > 0 && dst != NULL)
|
||||
ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize);
|
||||
if (magicVariant != NULL)
|
||||
*magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;
|
||||
return skippableContentSize;
|
||||
}
|
||||
}
|
||||
|
||||
/** ZSTD_findDecompressedSize() :
|
||||
* compatible with legacy mode
|
||||
* `srcSize` must be the exact length of some number of ZSTD compressed and/or
|
||||
* skippable frames
|
||||
* @return : decompressed size of the frames contained */
|
||||
* note: compatible with legacy mode
|
||||
* @return : decompressed size of the frames contained */
|
||||
unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||
{
|
||||
unsigned long long totalDstSize = 0;
|
||||
@@ -640,9 +647,7 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||
|
||||
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
|
||||
if (ZSTD_isError(skippableSize)) {
|
||||
return ZSTD_CONTENTSIZE_ERROR;
|
||||
}
|
||||
if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR;
|
||||
assert(skippableSize <= srcSize);
|
||||
|
||||
src = (const BYTE *)src + skippableSize;
|
||||
@@ -650,17 +655,17 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||
continue;
|
||||
}
|
||||
|
||||
{ unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
|
||||
if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
|
||||
{ unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize);
|
||||
if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs;
|
||||
|
||||
/* check for overflow */
|
||||
if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
|
||||
totalDstSize += ret;
|
||||
if (totalDstSize + fcs < totalDstSize)
|
||||
return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */
|
||||
totalDstSize += fcs;
|
||||
}
|
||||
/* skip to next frame */
|
||||
{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
|
||||
if (ZSTD_isError(frameSrcSize)) {
|
||||
return ZSTD_CONTENTSIZE_ERROR;
|
||||
}
|
||||
if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR;
|
||||
assert(frameSrcSize <= srcSize);
|
||||
|
||||
src = (const BYTE *)src + frameSrcSize;
|
||||
srcSize -= frameSrcSize;
|
||||
@@ -724,17 +729,17 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
|
||||
return frameSizeInfo;
|
||||
}
|
||||
|
||||
static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
|
||||
static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize, ZSTD_format_e format)
|
||||
{
|
||||
ZSTD_frameSizeInfo frameSizeInfo;
|
||||
ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
|
||||
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
if (ZSTD_isLegacy(src, srcSize))
|
||||
if (format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize))
|
||||
return ZSTD_findFrameSizeInfoLegacy(src, srcSize);
|
||||
#endif
|
||||
|
||||
if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
|
||||
if (format == ZSTD_f_zstd1 && (srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
|
||||
&& (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||
frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
|
||||
assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
|
||||
@@ -748,7 +753,7 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
|
||||
ZSTD_frameHeader zfh;
|
||||
|
||||
/* Extract Frame Header */
|
||||
{ size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
|
||||
{ size_t const ret = ZSTD_getFrameHeader_advanced(&zfh, src, srcSize, format);
|
||||
if (ZSTD_isError(ret))
|
||||
return ZSTD_errorFrameSizeInfo(ret);
|
||||
if (ret > 0)
|
||||
@@ -791,15 +796,17 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
|
||||
}
|
||||
}
|
||||
|
||||
static size_t ZSTD_findFrameCompressedSize_advanced(const void *src, size_t srcSize, ZSTD_format_e format) {
|
||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, format);
|
||||
return frameSizeInfo.compressedSize;
|
||||
}
|
||||
|
||||
/** ZSTD_findFrameCompressedSize() :
|
||||
* compatible with legacy mode
|
||||
* `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
|
||||
* `srcSize` must be at least as large as the frame contained
|
||||
* @return : the compressed size of the frame starting at `src` */
|
||||
* See docs in zstd.h
|
||||
* Note: compatible with legacy mode */
|
||||
size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
|
||||
{
|
||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
|
||||
return frameSizeInfo.compressedSize;
|
||||
return ZSTD_findFrameCompressedSize_advanced(src, srcSize, ZSTD_f_zstd1);
|
||||
}
|
||||
|
||||
/** ZSTD_decompressBound() :
|
||||
@@ -813,7 +820,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
|
||||
unsigned long long bound = 0;
|
||||
/* Iterate over each frame */
|
||||
while (srcSize > 0) {
|
||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
|
||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1);
|
||||
size_t const compressedSize = frameSizeInfo.compressedSize;
|
||||
unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
|
||||
if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
|
||||
@@ -833,7 +840,7 @@ size_t ZSTD_decompressionMargin(void const* src, size_t srcSize)
|
||||
|
||||
/* Iterate over each frame */
|
||||
while (srcSize > 0) {
|
||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
|
||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1);
|
||||
size_t const compressedSize = frameSizeInfo.compressedSize;
|
||||
unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
|
||||
ZSTD_frameHeader zfh;
|
||||
@@ -969,6 +976,10 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
|
||||
}
|
||||
|
||||
/* Shrink the blockSizeMax if enabled */
|
||||
if (dctx->maxBlockSizeParam != 0)
|
||||
dctx->fParams.blockSizeMax = MIN(dctx->fParams.blockSizeMax, (unsigned)dctx->maxBlockSizeParam);
|
||||
|
||||
/* Loop on each block */
|
||||
while (1) {
|
||||
BYTE* oBlockEnd = oend;
|
||||
@@ -1001,7 +1012,8 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
switch(blockProperties.blockType)
|
||||
{
|
||||
case bt_compressed:
|
||||
decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, /* frame */ 1, not_streaming);
|
||||
assert(dctx->isFrameDecompression == 1);
|
||||
decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, not_streaming);
|
||||
break;
|
||||
case bt_raw :
|
||||
/* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */
|
||||
@@ -1014,12 +1026,14 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
default:
|
||||
RETURN_ERROR(corruption_detected, "invalid block type");
|
||||
}
|
||||
|
||||
if (ZSTD_isError(decodedSize)) return decodedSize;
|
||||
if (dctx->validateChecksum)
|
||||
FORWARD_IF_ERROR(decodedSize, "Block decompression failure");
|
||||
DEBUGLOG(5, "Decompressed block of dSize = %u", (unsigned)decodedSize);
|
||||
if (dctx->validateChecksum) {
|
||||
XXH64_update(&dctx->xxhState, op, decodedSize);
|
||||
if (decodedSize != 0)
|
||||
}
|
||||
if (decodedSize) /* support dst = NULL,0 */ {
|
||||
op += decodedSize;
|
||||
}
|
||||
assert(ip != NULL);
|
||||
ip += cBlockSize;
|
||||
remainingSrcSize -= cBlockSize;
|
||||
@@ -1049,7 +1063,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
static
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict, size_t dictSize,
|
||||
@@ -1069,7 +1085,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
while (srcSize >= ZSTD_startingInputLength(dctx->format)) {
|
||||
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
if (ZSTD_isLegacy(src, srcSize)) {
|
||||
if (dctx->format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize)) {
|
||||
size_t decodedSize;
|
||||
size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
|
||||
if (ZSTD_isError(frameSize)) return frameSize;
|
||||
@@ -1079,6 +1095,15 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
|
||||
if (ZSTD_isError(decodedSize)) return decodedSize;
|
||||
|
||||
{
|
||||
unsigned long long const expectedSize = ZSTD_getFrameContentSize(src, srcSize);
|
||||
RETURN_ERROR_IF(expectedSize == ZSTD_CONTENTSIZE_ERROR, corruption_detected, "Corrupted frame header!");
|
||||
if (expectedSize != ZSTD_CONTENTSIZE_UNKNOWN) {
|
||||
RETURN_ERROR_IF(expectedSize != decodedSize, corruption_detected,
|
||||
"Frame header size does not match decoded size!");
|
||||
}
|
||||
}
|
||||
|
||||
assert(decodedSize <= dstCapacity);
|
||||
dst = (BYTE*)dst + decodedSize;
|
||||
dstCapacity -= decodedSize;
|
||||
@@ -1090,17 +1115,18 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
}
|
||||
#endif
|
||||
|
||||
{ U32 const magicNumber = MEM_readLE32(src);
|
||||
DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
|
||||
(unsigned)magicNumber, ZSTD_MAGICNUMBER);
|
||||
if (dctx->format == ZSTD_f_zstd1 && srcSize >= 4) {
|
||||
U32 const magicNumber = MEM_readLE32(src);
|
||||
DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber);
|
||||
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||
/* skippable frame detected : skip it */
|
||||
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
|
||||
FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");
|
||||
FORWARD_IF_ERROR(skippableSize, "invalid skippable frame");
|
||||
assert(skippableSize <= srcSize);
|
||||
|
||||
src = (const BYTE *)src + skippableSize;
|
||||
srcSize -= skippableSize;
|
||||
continue;
|
||||
continue; /* check next frame */
|
||||
} }
|
||||
|
||||
if (ddict) {
|
||||
@@ -1316,7 +1342,8 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
{
|
||||
case bt_compressed:
|
||||
DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
|
||||
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming);
|
||||
assert(dctx->isFrameDecompression == 1);
|
||||
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, is_streaming);
|
||||
dctx->expected = 0; /* Streaming not supported */
|
||||
break;
|
||||
case bt_raw :
|
||||
@@ -1385,6 +1412,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
case ZSTDds_decodeSkippableHeader:
|
||||
assert(src != NULL);
|
||||
assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
|
||||
assert(dctx->format != ZSTD_f_zstd1_magicless);
|
||||
ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
|
||||
dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
|
||||
dctx->stage = ZSTDds_skipFrame;
|
||||
@@ -1545,6 +1573,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
|
||||
dctx->litEntropy = dctx->fseEntropy = 0;
|
||||
dctx->dictID = 0;
|
||||
dctx->bType = bt_reserved;
|
||||
dctx->isFrameDecompression = 1;
|
||||
ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
|
||||
ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
|
||||
dctx->LLTptr = dctx->entropy.LLTable;
|
||||
@@ -1816,6 +1845,10 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
|
||||
bounds.lowerBound = 0;
|
||||
bounds.upperBound = 1;
|
||||
return bounds;
|
||||
case ZSTD_d_maxBlockSize:
|
||||
bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN;
|
||||
bounds.upperBound = ZSTD_BLOCKSIZE_MAX;
|
||||
return bounds;
|
||||
|
||||
default:;
|
||||
}
|
||||
@@ -1860,6 +1893,9 @@ size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value
|
||||
case ZSTD_d_disableHuffmanAssembly:
|
||||
*value = (int)dctx->disableHufAsm;
|
||||
return 0;
|
||||
case ZSTD_d_maxBlockSize:
|
||||
*value = dctx->maxBlockSizeParam;
|
||||
return 0;
|
||||
default:;
|
||||
}
|
||||
RETURN_ERROR(parameter_unsupported, "");
|
||||
@@ -1897,6 +1933,10 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value
|
||||
CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value);
|
||||
dctx->disableHufAsm = value != 0;
|
||||
return 0;
|
||||
case ZSTD_d_maxBlockSize:
|
||||
if (value != 0) CHECK_DBOUNDS(ZSTD_d_maxBlockSize, value);
|
||||
dctx->maxBlockSizeParam = value;
|
||||
return 0;
|
||||
default:;
|
||||
}
|
||||
RETURN_ERROR(parameter_unsupported, "");
|
||||
@@ -1908,6 +1948,7 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
|
||||
|| (reset == ZSTD_reset_session_and_parameters) ) {
|
||||
dctx->streamStage = zdss_init;
|
||||
dctx->noForwardProgress = 0;
|
||||
dctx->isFrameDecompression = 1;
|
||||
}
|
||||
if ( (reset == ZSTD_reset_parameters)
|
||||
|| (reset == ZSTD_reset_session_and_parameters) ) {
|
||||
@@ -1924,11 +1965,17 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
|
||||
return ZSTD_sizeof_DCtx(dctx);
|
||||
}
|
||||
|
||||
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
|
||||
static size_t ZSTD_decodingBufferSize_internal(unsigned long long windowSize, unsigned long long frameContentSize, size_t blockSizeMax)
|
||||
{
|
||||
size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
||||
/* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/
|
||||
unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2);
|
||||
size_t const blockSize = MIN((size_t)MIN(windowSize, ZSTD_BLOCKSIZE_MAX), blockSizeMax);
|
||||
/* We need blockSize + WILDCOPY_OVERLENGTH worth of buffer so that if a block
|
||||
* ends at windowSize + WILDCOPY_OVERLENGTH + 1 bytes, we can start writing
|
||||
* the block at the beginning of the output buffer, and maintain a full window.
|
||||
*
|
||||
* We need another blockSize worth of buffer so that we can store split
|
||||
* literals at the end of the block without overwriting the extDict window.
|
||||
*/
|
||||
unsigned long long const neededRBSize = windowSize + (blockSize * 2) + (WILDCOPY_OVERLENGTH * 2);
|
||||
unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
|
||||
size_t const minRBSize = (size_t) neededSize;
|
||||
RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
|
||||
@@ -1936,6 +1983,11 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
return minRBSize;
|
||||
}
|
||||
|
||||
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
|
||||
{
|
||||
return ZSTD_decodingBufferSize_internal(windowSize, frameContentSize, ZSTD_BLOCKSIZE_MAX);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateDStreamSize(size_t windowSize)
|
||||
{
|
||||
size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
||||
@@ -2131,12 +2183,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
|
||||
&& zds->fParams.frameType != ZSTD_skippableFrame
|
||||
&& (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
|
||||
size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart));
|
||||
size_t const cSize = ZSTD_findFrameCompressedSize_advanced(istart, (size_t)(iend-istart), zds->format);
|
||||
if (cSize <= (size_t)(iend-istart)) {
|
||||
/* shortcut : using single-pass mode */
|
||||
size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
|
||||
if (ZSTD_isError(decompressedSize)) return decompressedSize;
|
||||
DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
|
||||
DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()");
|
||||
assert(istart != NULL);
|
||||
ip = istart + cSize;
|
||||
op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */
|
||||
@@ -2158,7 +2210,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
DEBUGLOG(4, "Consume header");
|
||||
FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");
|
||||
|
||||
if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
|
||||
if (zds->format == ZSTD_f_zstd1
|
||||
&& (MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
|
||||
zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
|
||||
zds->stage = ZSTDds_skipFrame;
|
||||
} else {
|
||||
@@ -2174,11 +2227,13 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
|
||||
RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
|
||||
frameParameter_windowTooLarge, "");
|
||||
if (zds->maxBlockSizeParam != 0)
|
||||
zds->fParams.blockSizeMax = MIN(zds->fParams.blockSizeMax, (unsigned)zds->maxBlockSizeParam);
|
||||
|
||||
/* Adapt buffer sizes to frame header instructions */
|
||||
{ size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
|
||||
size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered
|
||||
? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)
|
||||
? ZSTD_decodingBufferSize_internal(zds->fParams.windowSize, zds->fParams.frameContentSize, zds->fParams.blockSizeMax)
|
||||
: 0;
|
||||
|
||||
ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ typedef enum {
|
||||
*/
|
||||
size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize, const int frame, const streaming_operation streaming);
|
||||
const void* src, size_t srcSize, const streaming_operation streaming);
|
||||
|
||||
/* ZSTD_buildFSETable() :
|
||||
* generate FSE decoding table for one symbol (ll, ml or off)
|
||||
@@ -64,5 +64,10 @@ void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
|
||||
unsigned tableLog, void* wksp, size_t wkspSize,
|
||||
int bmi2);
|
||||
|
||||
/* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */
|
||||
size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
|
||||
#endif /* ZSTD_DEC_BLOCK_H */
|
||||
|
||||
@@ -153,6 +153,7 @@ struct ZSTD_DCtx_s
|
||||
size_t litSize;
|
||||
size_t rleSize;
|
||||
size_t staticSize;
|
||||
int isFrameDecompression;
|
||||
#if DYNAMIC_BMI2 != 0
|
||||
int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
|
||||
#endif
|
||||
@@ -166,6 +167,7 @@ struct ZSTD_DCtx_s
|
||||
ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */
|
||||
ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */
|
||||
int disableHufAsm;
|
||||
int maxBlockSizeParam;
|
||||
|
||||
/* streaming */
|
||||
ZSTD_dStreamStage streamStage;
|
||||
|
||||
+16
-12
@@ -31,8 +31,8 @@
|
||||
#endif
|
||||
|
||||
#include "../common/mem.h" /* read */
|
||||
#include "../common/pool.h"
|
||||
#include "../common/threading.h"
|
||||
#include "../common/pool.h" /* POOL_ctx */
|
||||
#include "../common/threading.h" /* ZSTD_pthread_mutex_t */
|
||||
#include "../common/zstd_internal.h" /* includes zstd.h */
|
||||
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||
#include "../zdict.h"
|
||||
@@ -78,7 +78,7 @@ static clock_t g_time = 0;
|
||||
#undef LOCALDISPLAYUPDATE
|
||||
#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \
|
||||
if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \
|
||||
g_time = clock(); \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
} \
|
||||
@@ -301,9 +301,10 @@ static int WIN_CDECL COVER_strict_cmp8(const void *lp, const void *rp) {
|
||||
* Returns the first pointer in [first, last) whose element does not compare
|
||||
* less than value. If no such element exists it returns last.
|
||||
*/
|
||||
static const size_t *COVER_lower_bound(const size_t *first, const size_t *last,
|
||||
static const size_t *COVER_lower_bound(const size_t* first, const size_t* last,
|
||||
size_t value) {
|
||||
size_t count = last - first;
|
||||
size_t count = (size_t)(last - first);
|
||||
assert(last >= first);
|
||||
while (count != 0) {
|
||||
size_t step = count / 2;
|
||||
const size_t *ptr = first;
|
||||
@@ -549,7 +550,8 @@ static void COVER_ctx_destroy(COVER_ctx_t *ctx) {
|
||||
*/
|
||||
static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
|
||||
const size_t *samplesSizes, unsigned nbSamples,
|
||||
unsigned d, double splitPoint) {
|
||||
unsigned d, double splitPoint)
|
||||
{
|
||||
const BYTE *const samples = (const BYTE *)samplesBuffer;
|
||||
const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);
|
||||
/* Split samples into testing and training sets */
|
||||
@@ -733,7 +735,7 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
|
||||
return tail;
|
||||
}
|
||||
|
||||
ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
|
||||
ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover(
|
||||
void *dictBuffer, size_t dictBufferCapacity,
|
||||
const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
|
||||
ZDICT_cover_params_t parameters)
|
||||
@@ -907,8 +909,10 @@ void COVER_best_start(COVER_best_t *best) {
|
||||
* Decrements liveJobs and signals any waiting threads if liveJobs == 0.
|
||||
* If this dictionary is the best so far save it and its parameters.
|
||||
*/
|
||||
void COVER_best_finish(COVER_best_t *best, ZDICT_cover_params_t parameters,
|
||||
COVER_dictSelection_t selection) {
|
||||
void COVER_best_finish(COVER_best_t* best,
|
||||
ZDICT_cover_params_t parameters,
|
||||
COVER_dictSelection_t selection)
|
||||
{
|
||||
void* dict = selection.dictContent;
|
||||
size_t compressedSize = selection.totalCompressedSize;
|
||||
size_t dictSize = selection.dictSize;
|
||||
@@ -980,8 +984,8 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBuffe
|
||||
size_t largestCompressed = 0;
|
||||
BYTE* customDictContentEnd = customDictContent + dictContentSize;
|
||||
|
||||
BYTE * largestDictbuffer = (BYTE *)malloc(dictBufferCapacity);
|
||||
BYTE * candidateDictBuffer = (BYTE *)malloc(dictBufferCapacity);
|
||||
BYTE* largestDictbuffer = (BYTE*)malloc(dictBufferCapacity);
|
||||
BYTE* candidateDictBuffer = (BYTE*)malloc(dictBufferCapacity);
|
||||
double regressionTolerance = ((double)params.shrinkDictMaxRegression / 100.0) + 1.00;
|
||||
|
||||
if (!largestDictbuffer || !candidateDictBuffer) {
|
||||
@@ -1119,7 +1123,7 @@ _cleanup:
|
||||
free(freqs);
|
||||
}
|
||||
|
||||
ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
|
||||
ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover(
|
||||
void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer,
|
||||
const size_t* samplesSizes, unsigned nbSamples,
|
||||
ZDICT_cover_params_t* parameters)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user