Merge pull request #647 from terrelln/linux
Add linux kernel modules to contrib/
This commit is contained in:
commit
b5b79b3942
4
contrib/linux-kernel/.gitignore
vendored
Normal file
4
contrib/linux-kernel/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
!lib/zstd
|
||||||
|
!lib/zstd/*
|
||||||
|
*.o
|
||||||
|
*.a
|
26
contrib/linux-kernel/README.md
Normal file
26
contrib/linux-kernel/README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Linux Kernel Patch
|
||||||
|
|
||||||
|
There are two pieces, the `zstd_compress` and `zstd_decompress` kernel modules, and the BtrFS patch.
|
||||||
|
The patches are based off of the linux kernel version 4.9.
|
||||||
|
The BtrFS patch is not present in its entirety yet.
|
||||||
|
|
||||||
|
## Zstd Kernel modules
|
||||||
|
|
||||||
|
* The header is in `include/linux/zstd.h`.
|
||||||
|
* It is split up into `zstd_compress` and `zstd_decompress`, which can be loaded independently.
|
||||||
|
* Source files are in `lib/zstd/`.
|
||||||
|
* `lib/Kconfig` and `lib/Makefile` need to be modified by applying `lib/Kconfig.diff` and `lib/Makefile.diff` respectively.
|
||||||
|
* `test/UserlandTest.cpp` contains tests for the patch in userland by mocking the kernel headers.
|
||||||
|
It can be run with the following commands:
|
||||||
|
```
|
||||||
|
cd test
|
||||||
|
make googletest
|
||||||
|
make UserlandTest
|
||||||
|
./UserlandTest
|
||||||
|
```
|
||||||
|
|
||||||
|
## BtrFS
|
||||||
|
|
||||||
|
* `fs/btrfs/zstd.c` is provided.
|
||||||
|
* Some more glue is required to integrate it with BtrFS, but I haven't included the patches yet.
|
||||||
|
In the meantime see https://github.com/terrelln/linux/commit/1914f7d4ca6c539369c84853eafa4ac104883047 if you're interested.
|
414
contrib/linux-kernel/fs/btrfs/zstd.c
Normal file
414
contrib/linux-kernel/fs/btrfs/zstd.c
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/pagemap.h>
|
||||||
|
#include <linux/bio.h>
|
||||||
|
#include <linux/zstd.h>
|
||||||
|
#include "compression.h"
|
||||||
|
|
||||||
|
#define ZSTD_BTRFS_MAX_WINDOWLOG 17
|
||||||
|
#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
|
||||||
|
|
||||||
|
static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len)
|
||||||
|
{
|
||||||
|
ZSTD_parameters params = ZSTD_getParams(3, src_len, 0);
|
||||||
|
BUG_ON(src_len > ZSTD_BTRFS_MAX_INPUT);
|
||||||
|
BUG_ON(params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG);
|
||||||
|
params.fParams.checksumFlag = 1;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct workspace {
|
||||||
|
void *mem;
|
||||||
|
size_t size;
|
||||||
|
char *buf;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void zstd_free_workspace(struct list_head *ws)
|
||||||
|
{
|
||||||
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
|
|
||||||
|
vfree(workspace->mem);
|
||||||
|
kfree(workspace->buf);
|
||||||
|
kfree(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct list_head *zstd_alloc_workspace(void)
|
||||||
|
{
|
||||||
|
ZSTD_parameters params = zstd_get_btrfs_parameters(ZSTD_BTRFS_MAX_INPUT);
|
||||||
|
struct workspace *workspace;
|
||||||
|
|
||||||
|
workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
|
||||||
|
if (!workspace) return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
workspace->size = max_t(size_t, ZSTD_CStreamWorkspaceBound(params.cParams),
|
||||||
|
ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT));
|
||||||
|
workspace->mem = vmalloc(workspace->size);
|
||||||
|
workspace->buf = kmalloc(PAGE_SIZE, GFP_NOFS);
|
||||||
|
if (!workspace->mem || !workspace->buf) goto fail;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&workspace->list);
|
||||||
|
|
||||||
|
return &workspace->list;
|
||||||
|
fail:
|
||||||
|
zstd_free_workspace(&workspace->list);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zstd_compress_pages(struct list_head *ws,
|
||||||
|
struct address_space *mapping,
|
||||||
|
u64 start, unsigned long len,
|
||||||
|
struct page **pages,
|
||||||
|
unsigned long nr_dest_pages,
|
||||||
|
unsigned long *out_pages,
|
||||||
|
unsigned long *total_in,
|
||||||
|
unsigned long *total_out,
|
||||||
|
unsigned long max_out)
|
||||||
|
{
|
||||||
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
|
ZSTD_parameters params = zstd_get_btrfs_parameters(len);
|
||||||
|
ZSTD_CStream *stream;
|
||||||
|
int ret = 0;
|
||||||
|
int nr_pages = 0;
|
||||||
|
struct page *in_page = NULL; /* The current page to read */
|
||||||
|
struct page *out_page = NULL; /* The current page to write to */
|
||||||
|
ZSTD_inBuffer in_buf = { NULL, 0, 0 };
|
||||||
|
ZSTD_outBuffer out_buf = { NULL, 0, 0 };
|
||||||
|
unsigned long tot_in = 0;
|
||||||
|
unsigned long tot_out = 0;
|
||||||
|
|
||||||
|
*out_pages = 0;
|
||||||
|
*total_out = 0;
|
||||||
|
*total_in = 0;
|
||||||
|
|
||||||
|
/* Initialize the stream */
|
||||||
|
stream = ZSTD_createCStream(params, len, workspace->mem, workspace->size);
|
||||||
|
if (!stream) {
|
||||||
|
pr_warn("BTRFS: ZSTD_createStream failed\n");
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* map in the first page of input data */
|
||||||
|
in_page = find_get_page(mapping, start >> PAGE_SHIFT);
|
||||||
|
in_buf.src = kmap(in_page);
|
||||||
|
in_buf.pos = 0;
|
||||||
|
in_buf.size = min_t(size_t, len, PAGE_SIZE);
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate and map in the output buffer */
|
||||||
|
out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
||||||
|
if (out_page == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pages[nr_pages++] = out_page;
|
||||||
|
out_buf.dst = kmap(out_page);
|
||||||
|
out_buf.pos = 0;
|
||||||
|
out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
const size_t rc = ZSTD_compressStream(stream, &out_buf, &in_buf);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
pr_debug("BTRFS: ZSTD_compressStream returned %d\n",
|
||||||
|
ZSTD_getErrorCode(rc));
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check to see if we are making it bigger */
|
||||||
|
if (tot_in + in_buf.pos > 8192 &&
|
||||||
|
tot_in + in_buf.pos <
|
||||||
|
tot_out + out_buf.pos) {
|
||||||
|
ret = -E2BIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We've reached the end of our output range */
|
||||||
|
if (out_buf.pos >= max_out) {
|
||||||
|
tot_out += out_buf.pos;
|
||||||
|
ret = -E2BIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we need more output space */
|
||||||
|
if (out_buf.pos == out_buf.size) {
|
||||||
|
tot_out += PAGE_SIZE;
|
||||||
|
max_out -= PAGE_SIZE;
|
||||||
|
kunmap(out_page);
|
||||||
|
if (nr_pages == nr_dest_pages) {
|
||||||
|
out_page = NULL;
|
||||||
|
ret = -E2BIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
||||||
|
if (out_page == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pages[nr_pages++] = out_page;
|
||||||
|
out_buf.dst = kmap(out_page);
|
||||||
|
out_buf.pos = 0;
|
||||||
|
out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We've reached the end of the input */
|
||||||
|
if (in_buf.pos >= len) {
|
||||||
|
tot_in += in_buf.pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we need more input */
|
||||||
|
if (in_buf.pos == in_buf.size) {
|
||||||
|
tot_in += PAGE_SIZE;
|
||||||
|
kunmap(in_page);
|
||||||
|
put_page(in_page);
|
||||||
|
|
||||||
|
start += PAGE_SIZE;
|
||||||
|
len -= PAGE_SIZE;
|
||||||
|
in_page = find_get_page(mapping, start >> PAGE_SHIFT);
|
||||||
|
in_buf.src = kmap(in_page);
|
||||||
|
in_buf.pos = 0;
|
||||||
|
in_buf.size = min_t(size_t, len, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
const size_t rc = ZSTD_endStream(stream, &out_buf);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
pr_debug("BTRFS: ZSTD_endStream returned %d\n",
|
||||||
|
ZSTD_getErrorCode(rc));
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
tot_out += out_buf.pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (out_buf.pos >= max_out) {
|
||||||
|
tot_out += out_buf.pos;
|
||||||
|
ret = -E2BIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tot_out += PAGE_SIZE;
|
||||||
|
max_out -= PAGE_SIZE;
|
||||||
|
kunmap(out_page);
|
||||||
|
if (nr_pages == nr_dest_pages) {
|
||||||
|
out_page = NULL;
|
||||||
|
ret = -E2BIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
||||||
|
if (out_page == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pages[nr_pages++] = out_page;
|
||||||
|
out_buf.dst = kmap(out_page);
|
||||||
|
out_buf.pos = 0;
|
||||||
|
out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tot_out >= tot_in) {
|
||||||
|
ret = -E2BIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
*total_in = tot_in;
|
||||||
|
*total_out = tot_out;
|
||||||
|
out:
|
||||||
|
*out_pages = nr_pages;
|
||||||
|
/* Cleanup */
|
||||||
|
if (in_page) {
|
||||||
|
kunmap(in_page);
|
||||||
|
put_page(in_page);
|
||||||
|
}
|
||||||
|
if (out_page) { kunmap(out_page); }
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zstd_decompress_biovec(struct list_head *ws, struct page **pages_in,
|
||||||
|
u64 disk_start,
|
||||||
|
struct bio_vec *bvec,
|
||||||
|
int vcnt,
|
||||||
|
size_t srclen)
|
||||||
|
{
|
||||||
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
|
ZSTD_DStream *stream;
|
||||||
|
int ret = 0;
|
||||||
|
unsigned long page_in_index = 0;
|
||||||
|
unsigned long page_out_index = 0;
|
||||||
|
unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
|
||||||
|
unsigned long buf_start;
|
||||||
|
unsigned long pg_offset;
|
||||||
|
unsigned long total_out = 0;
|
||||||
|
ZSTD_inBuffer in_buf = { NULL, 0, 0 };
|
||||||
|
ZSTD_outBuffer out_buf = { NULL, 0, 0 };
|
||||||
|
|
||||||
|
stream = ZSTD_createDStream(
|
||||||
|
ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
|
||||||
|
if (!stream) {
|
||||||
|
pr_debug("BTRFS: ZSTD_createDStream failed\n");
|
||||||
|
ret = -EIO;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_buf.src = kmap(pages_in[page_in_index]);
|
||||||
|
in_buf.pos = 0;
|
||||||
|
in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
|
||||||
|
|
||||||
|
out_buf.dst = workspace->buf;
|
||||||
|
out_buf.pos = 0;
|
||||||
|
out_buf.size = PAGE_SIZE;
|
||||||
|
|
||||||
|
pg_offset = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
const size_t rc = ZSTD_decompressStream(stream, &out_buf, &in_buf);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
pr_debug("BTRFS: ZSTD_decompressStream returned %d\n",
|
||||||
|
ZSTD_getErrorCode(rc));
|
||||||
|
ret = -EIO;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
buf_start = total_out;
|
||||||
|
total_out += out_buf.pos;
|
||||||
|
out_buf.pos = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
int ret2 = btrfs_decompress_buf2page(out_buf.dst, buf_start,
|
||||||
|
total_out, disk_start, bvec, vcnt,
|
||||||
|
&page_out_index, &pg_offset);
|
||||||
|
if (ret2 == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_buf.pos >= srclen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we've hit the end of a frame */
|
||||||
|
if (rc == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_buf.pos == in_buf.size) {
|
||||||
|
kunmap(pages_in[page_in_index++]);
|
||||||
|
if (page_in_index >= total_pages_in) {
|
||||||
|
in_buf.src = NULL;
|
||||||
|
ret = -EIO;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
srclen -= PAGE_SIZE;
|
||||||
|
in_buf.src = kmap(pages_in[page_in_index]);
|
||||||
|
in_buf.pos = 0;
|
||||||
|
in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
|
||||||
|
ret = 0;
|
||||||
|
done:
|
||||||
|
if (in_buf.src) { kunmap(pages_in[page_in_index]); }
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zstd_decompress(struct list_head *ws, unsigned char *data_in,
|
||||||
|
struct page *dest_page,
|
||||||
|
unsigned long start_byte,
|
||||||
|
size_t srclen, size_t destlen)
|
||||||
|
{
|
||||||
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
|
ZSTD_DStream *stream;
|
||||||
|
int ret = 0;
|
||||||
|
ZSTD_inBuffer in_buf = { NULL, 0, 0 };
|
||||||
|
ZSTD_outBuffer out_buf = { NULL, 0, 0 };
|
||||||
|
unsigned long total_out = 0;
|
||||||
|
unsigned long pg_offset = 0;
|
||||||
|
char *kaddr;
|
||||||
|
|
||||||
|
stream = ZSTD_createDStream(
|
||||||
|
ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
|
||||||
|
if (!stream) {
|
||||||
|
pr_warn("BTRFS: ZSTD_createDStream failed\n");
|
||||||
|
ret = -EIO;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
destlen = min_t(size_t, destlen, PAGE_SIZE);
|
||||||
|
|
||||||
|
in_buf.src = data_in;
|
||||||
|
in_buf.pos = 0;
|
||||||
|
in_buf.size = srclen;
|
||||||
|
|
||||||
|
out_buf.dst = workspace->buf;
|
||||||
|
out_buf.pos = 0;
|
||||||
|
out_buf.size = PAGE_SIZE;
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
while (pg_offset < destlen && in_buf.pos < in_buf.size) {
|
||||||
|
unsigned long buf_start;
|
||||||
|
unsigned long buf_offset;
|
||||||
|
unsigned long bytes;
|
||||||
|
|
||||||
|
/* Check if the frame is over and we still need more input */
|
||||||
|
if (ret == 0) {
|
||||||
|
pr_debug("BTRFS: ZSTD_decompressStream frame ended to early\n");
|
||||||
|
ret = -EIO;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const size_t rc = ZSTD_decompressStream(stream, &out_buf, &in_buf);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
pr_debug("BTRFS: ZSTD_decompressStream returned %d\n",
|
||||||
|
ZSTD_getErrorCode(rc));
|
||||||
|
ret = -EIO;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
ret = rc > 0;
|
||||||
|
}
|
||||||
|
buf_start = total_out;
|
||||||
|
total_out += out_buf.pos;
|
||||||
|
out_buf.pos = 0;
|
||||||
|
|
||||||
|
if (total_out <= start_byte) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_out > start_byte && buf_start < start_byte) {
|
||||||
|
buf_offset = start_byte - buf_start;
|
||||||
|
} else {
|
||||||
|
buf_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = min_t(unsigned long, destlen - pg_offset,
|
||||||
|
out_buf.size - buf_offset);
|
||||||
|
|
||||||
|
kaddr = kmap_atomic(dest_page);
|
||||||
|
memcpy(kaddr + pg_offset, out_buf.dst + buf_offset, bytes);
|
||||||
|
kunmap_atomic(kaddr);
|
||||||
|
|
||||||
|
pg_offset += bytes;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
finish:
|
||||||
|
if (pg_offset < destlen) {
|
||||||
|
kaddr = kmap_atomic(dest_page);
|
||||||
|
memset(kaddr + pg_offset, 0, destlen - pg_offset);
|
||||||
|
kunmap_atomic(kaddr);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct btrfs_compress_op btrfs_zstd_compress = {
|
||||||
|
.alloc_workspace = zstd_alloc_workspace,
|
||||||
|
.free_workspace = zstd_free_workspace,
|
||||||
|
.compress_pages = zstd_compress_pages,
|
||||||
|
.decompress_biovec = zstd_decompress_biovec,
|
||||||
|
.decompress = zstd_decompress,
|
||||||
|
};
|
646
contrib/linux-kernel/include/linux/zstd.h
Normal file
646
contrib/linux-kernel/include/linux/zstd.h
Normal file
@ -0,0 +1,646 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_H_235446
|
||||||
|
#define ZSTD_H_235446
|
||||||
|
|
||||||
|
/* ====== Dependency ======*/
|
||||||
|
#include <linux/types.h> /* size_t */
|
||||||
|
|
||||||
|
|
||||||
|
/* ===== ZSTDLIB_API : control library symbols visibility ===== */
|
||||||
|
#define ZSTDLIB_API
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************************************
|
||||||
|
Introduction
|
||||||
|
|
||||||
|
zstd, short for Zstandard, is a fast lossless compression algorithm, targeting real-time compression scenarios
|
||||||
|
at zlib-level and better compression ratios. The zstd compression library provides in-memory compression and
|
||||||
|
decompression functions. The library supports compression levels from 1 up to ZSTD_maxCLevel() which is 22.
|
||||||
|
Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory.
|
||||||
|
Compression can be done in:
|
||||||
|
- a single step (described as Simple API)
|
||||||
|
- a single step, reusing a context (described as Explicit memory management)
|
||||||
|
- unbounded multiple steps (described as Streaming compression)
|
||||||
|
The compression ratio achievable on small data can be highly improved using compression with a dictionary in:
|
||||||
|
- a single step (described as Simple dictionary API)
|
||||||
|
- a single step, reusing a dictionary (described as Fast dictionary API)
|
||||||
|
*********************************************************************************************************/
|
||||||
|
|
||||||
|
/*------ Version ------*/
|
||||||
|
#define ZSTD_VERSION_MAJOR 1
|
||||||
|
#define ZSTD_VERSION_MINOR 1
|
||||||
|
#define ZSTD_VERSION_RELEASE 5
|
||||||
|
|
||||||
|
#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE
|
||||||
|
#define ZSTD_QUOTE(str) #str
|
||||||
|
#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)
|
||||||
|
#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)
|
||||||
|
|
||||||
|
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
|
||||||
|
|
||||||
|
|
||||||
|
/*====== Helper functions ======*/
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_error_no_error,
|
||||||
|
ZSTD_error_GENERIC,
|
||||||
|
ZSTD_error_prefix_unknown,
|
||||||
|
ZSTD_error_version_unsupported,
|
||||||
|
ZSTD_error_parameter_unknown,
|
||||||
|
ZSTD_error_frameParameter_unsupported,
|
||||||
|
ZSTD_error_frameParameter_unsupportedBy32bits,
|
||||||
|
ZSTD_error_frameParameter_windowTooLarge,
|
||||||
|
ZSTD_error_compressionParameter_unsupported,
|
||||||
|
ZSTD_error_init_missing,
|
||||||
|
ZSTD_error_memory_allocation,
|
||||||
|
ZSTD_error_stage_wrong,
|
||||||
|
ZSTD_error_dstSize_tooSmall,
|
||||||
|
ZSTD_error_srcSize_wrong,
|
||||||
|
ZSTD_error_corruption_detected,
|
||||||
|
ZSTD_error_checksum_wrong,
|
||||||
|
ZSTD_error_tableLog_tooLarge,
|
||||||
|
ZSTD_error_maxSymbolValue_tooLarge,
|
||||||
|
ZSTD_error_maxSymbolValue_tooSmall,
|
||||||
|
ZSTD_error_dictionary_corrupted,
|
||||||
|
ZSTD_error_dictionary_wrong,
|
||||||
|
ZSTD_error_dictionaryCreation_failed,
|
||||||
|
ZSTD_error_maxCode
|
||||||
|
} ZSTD_ErrorCode;
|
||||||
|
|
||||||
|
ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */
|
||||||
|
/*! ZSTD_isError() :
|
||||||
|
* tells if a `size_t` function result is an error code */
|
||||||
|
ZSTDLIB_API static __attribute__((unused)) unsigned ZSTD_isError(size_t code) {
|
||||||
|
return code > (size_t)-ZSTD_error_maxCode;
|
||||||
|
}
|
||||||
|
/*! ZSTD_getErrorCode() :
|
||||||
|
* convert a `size_t` function result into a proper ZSTD_errorCode enum */
|
||||||
|
ZSTDLIB_API static __attribute__((unused)) ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult) {
|
||||||
|
if (!ZSTD_isError(functionResult)) {
|
||||||
|
return (ZSTD_ErrorCode)0;
|
||||||
|
}
|
||||||
|
return (ZSTD_ErrorCode)(0 - functionResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Explicit memory management
|
||||||
|
***************************************/
|
||||||
|
|
||||||
|
typedef enum { ZSTD_fast, ZSTD_dfast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_btopt, ZSTD_btopt2 } ZSTD_strategy; /* from faster to stronger */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */
|
||||||
|
unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */
|
||||||
|
unsigned hashLog; /**< dispatch table : larger == faster, more memory */
|
||||||
|
unsigned searchLog; /**< nb of searches : larger == more compression, slower */
|
||||||
|
unsigned searchLength; /**< match length searched : larger == faster decompression, sometimes less compression */
|
||||||
|
unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */
|
||||||
|
ZSTD_strategy strategy;
|
||||||
|
} ZSTD_compressionParameters;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned contentSizeFlag; /**< 1: content size will be in frame header (when known) */
|
||||||
|
unsigned checksumFlag; /**< 1: generate a 32-bits checksum at end of frame, for error detection */
|
||||||
|
unsigned noDictIDFlag; /**< 1: no dictID will be saved into frame header (if dictionary compression) */
|
||||||
|
} ZSTD_frameParameters;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ZSTD_compressionParameters cParams;
|
||||||
|
ZSTD_frameParameters fParams;
|
||||||
|
} ZSTD_parameters;
|
||||||
|
|
||||||
|
/*! ZSTD_getCParams() :
|
||||||
|
* @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
|
||||||
|
* `estimatedSrcSize` value is optional, select 0 if not known */
|
||||||
|
ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
|
||||||
|
|
||||||
|
/*! ZSTD_getParams() :
|
||||||
|
* same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`.
|
||||||
|
* All fields of `ZSTD_frameParameters` are set to default (0) */
|
||||||
|
ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
|
||||||
|
|
||||||
|
|
||||||
|
/*! ZSTD_CCtxWorkspaceBound() :
|
||||||
|
* Returns the minimum amount of memory that needs to be passed to ZSTD_createCCtx() in order to compress with `params.cParams`
|
||||||
|
* or a `cdict` created with `params.cParams`. */
|
||||||
|
size_t ZSTD_CCtxWorkspaceBound(ZSTD_compressionParameters cParams);
|
||||||
|
|
||||||
|
/*= Compression context
|
||||||
|
* When compressing many times,
|
||||||
|
* it is recommended to allocate a context just once, and re-use it for each successive compression operation.
|
||||||
|
* The context pointer is placed in `workspace`, which must outlive the returned context.
|
||||||
|
* Use one context per thread for parallel execution in multi-threaded environments. */
|
||||||
|
typedef struct ZSTD_CCtx_s ZSTD_CCtx;
|
||||||
|
ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
/*! ZSTD_compressCCtx() :
|
||||||
|
* Same as ZSTD_compress(), requires an allocated ZSTD_CCtx (see ZSTD_createCCtx()).
|
||||||
|
* Note : The workspace passed to ZSTD_createCCtx() must have been at least ZSTD_CCtxWorkspaceBound(params.cParams) bytes. */
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, ZSTD_parameters params);
|
||||||
|
|
||||||
|
/*! ZSTD_compress_usingDict() :
|
||||||
|
* Compression using a predefined Dictionary (see dictBuilder/zdict.h).
|
||||||
|
* Note : The workspace passed to ZSTD_createCCtx() must have been at least ZSTD_CCtxWorkspaceBound(params.cParams) bytes.
|
||||||
|
* Note : This function loads the dictionary, resulting in significant startup delay.
|
||||||
|
* Note : When `dict == NULL || dictSize < 8` no dictionary is used. */
|
||||||
|
ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void *dict, size_t dictSize, ZSTD_parameters params);
|
||||||
|
|
||||||
|
/*! ZSTD_DCtxWorkspaceBound() :
|
||||||
|
* Returns the minimum amount of memory that needs to be passed to ZSTD_createDCtx(). */
|
||||||
|
size_t ZSTD_DCtxWorkspaceBound(void);
|
||||||
|
|
||||||
|
/*= Decompression context
|
||||||
|
* When decompressing many times,
|
||||||
|
* it is recommended to allocate a context just once, and re-use it for each successive compression operation.
|
||||||
|
* The context pointer is placed in `workspace`, which must outlive the returned context.
|
||||||
|
* `workspace` must be at least ZSTD_DCtxWorkspaceBound() bytes.
|
||||||
|
* Use one context per thread for parallel execution in multi-threaded environments. */
|
||||||
|
typedef struct ZSTD_DCtx_s ZSTD_DCtx;
|
||||||
|
ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
/*! ZSTD_decompressDCtx() :
|
||||||
|
* Same as ZSTD_decompress(), requires an allocated ZSTD_DCtx (see ZSTD_createDCtx()). */
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/*! ZSTD_decompress_usingDict() :
|
||||||
|
* Decompression using a predefined Dictionary (see dictBuilder/zdict.h).
|
||||||
|
* Dictionary must be identical to the one used during compression.
|
||||||
|
* Note : This function loads the dictionary, resulting in significant startup delay.
|
||||||
|
* Note : When `dict == NULL || dictSize < 8` no dictionary is used. */
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void *dict, size_t dictSize);
|
||||||
|
|
||||||
|
/****************************
|
||||||
|
* Fast dictionary API
|
||||||
|
****************************/
|
||||||
|
/*! ZSTD_CDictWorkspaceBound() :
|
||||||
|
* Returns the minimum amount of memory that needs to be passed to ZSTD_createCDict() when called with the given `params.cParams`. */
|
||||||
|
size_t ZSTD_CDictWorkspaceBound(ZSTD_compressionParameters cParams);
|
||||||
|
|
||||||
|
typedef struct ZSTD_CDict_s ZSTD_CDict;
|
||||||
|
|
||||||
|
/*! ZSTD_createCDict() :
|
||||||
|
* When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once.
|
||||||
|
* ZSTD_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.
|
||||||
|
* ZSTD_CDict can be created once and used by multiple threads concurrently, as its usage is read-only.
|
||||||
|
* `dictBuffer` content is referenced, and it must remain accessible throughout the lifetime of the CDict.
|
||||||
|
* The cdict pointer is placed in `workspace`, which must outlive the returned cdict.
|
||||||
|
* `workspace` must be at least ZSTD_CDictWorkspaceBound(params.cParams) bytes. */
|
||||||
|
ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize, ZSTD_parameters params, void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
/*! ZSTD_compress_usingCDict() :
|
||||||
|
* Compression using a digested Dictionary.
|
||||||
|
* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
|
||||||
|
* Note that compression level is decided during dictionary creation. */
|
||||||
|
ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const ZSTD_CDict* cdict);
|
||||||
|
|
||||||
|
|
||||||
|
/*! ZSTD_DDictWorkspaceBound() :
|
||||||
|
* Returns the minimum amount of memory that needs to be passed to ZSTD_createDDict(). */
|
||||||
|
size_t ZSTD_DDictWorkspaceBound(void);
|
||||||
|
|
||||||
|
typedef struct ZSTD_DDict_s ZSTD_DDict;
|
||||||
|
|
||||||
|
/*! ZSTD_createDDict() :
|
||||||
|
* Create a digested dictionary, ready to start decompression operation without startup delay.
|
||||||
|
* `dictBuffer` content is referenced, and it must remain accessible throughout the lifetime of the DDict.
|
||||||
|
* The ddict pointer is placed in `workspace`, which must outlive the returned ddict.
|
||||||
|
* `workspace` must be at least ZSTD_DDictWorkspaceBound() bytes. */
|
||||||
|
ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize, void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
/*! ZSTD_decompress_usingDDict() :
|
||||||
|
* Decompression using a digested Dictionary.
|
||||||
|
* Faster startup than ZSTD_decompress_usingDict(), recommended when same dictionary is used multiple times. */
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const ZSTD_DDict* ddict);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************
|
||||||
|
* Streaming
|
||||||
|
****************************/
|
||||||
|
|
||||||
|
typedef struct ZSTD_inBuffer_s {
|
||||||
|
const void* src; /**< start of input buffer */
|
||||||
|
size_t size; /**< size of input buffer */
|
||||||
|
size_t pos; /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */
|
||||||
|
} ZSTD_inBuffer;
|
||||||
|
|
||||||
|
typedef struct ZSTD_outBuffer_s {
|
||||||
|
void* dst; /**< start of output buffer */
|
||||||
|
size_t size; /**< size of output buffer */
|
||||||
|
size_t pos; /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */
|
||||||
|
} ZSTD_outBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-***********************************************************************
|
||||||
|
* Streaming compression - HowTo
|
||||||
|
*
|
||||||
|
* 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 in situations where many streaming operations will be achieved consecutively.
|
||||||
|
* Use one separate ZSTD_CStream per thread for parallel execution.
|
||||||
|
*
|
||||||
|
* Start a new compression by initializing ZSTD_CStream.
|
||||||
|
* Use ZSTD_initCStream() to start a new compression operation.
|
||||||
|
* Use ZSTD_initCStream_usingCDict() for a compression which requires a dictionary.
|
||||||
|
*
|
||||||
|
* Use ZSTD_compressStream() repetitively to consume input stream.
|
||||||
|
* The function will automatically update both `pos` fields.
|
||||||
|
* Note that it may not consume the entire input, in which case `pos < size`,
|
||||||
|
* and it's up to the caller to present again remaining data.
|
||||||
|
* @return : a size hint, preferred nb of bytes to use as input for next function call
|
||||||
|
* or an error code, which can be tested using ZSTD_isError().
|
||||||
|
* Note 1 : it's just a hint, to help latency a little, any other value will work fine.
|
||||||
|
* Note 2 : size hint is guaranteed to be <= ZSTD_CStreamInSize()
|
||||||
|
*
|
||||||
|
* At any moment, it's possible to flush whatever data remains within internal buffer, using ZSTD_flushStream().
|
||||||
|
* `output->pos` will be updated.
|
||||||
|
* Note that some content might still be left within internal buffer if `output->size` is too small.
|
||||||
|
* @return : nb of bytes still present within internal buffer (0 if it's empty)
|
||||||
|
* or an error code, which can be tested using ZSTD_isError().
|
||||||
|
*
|
||||||
|
* ZSTD_endStream() instructs to finish a frame.
|
||||||
|
* It will perform a flush and write frame epilogue.
|
||||||
|
* The epilogue is required for decoders to consider a frame completed.
|
||||||
|
* Similar to ZSTD_flushStream(), it may not be able to flush the full content if `output->size` is too small.
|
||||||
|
* In which case, call again ZSTD_endStream() to complete the flush.
|
||||||
|
* @return : nb of bytes still present within internal buffer (0 if it's empty, hence compression completed)
|
||||||
|
* or an error code, which can be tested using ZSTD_isError().
|
||||||
|
*
|
||||||
|
* *******************************************************************/
|
||||||
|
|
||||||
|
/*! ZSTD_CStreamWorkspaceBound() :
|
||||||
|
* Returns the minimum amount of memory that needs to be passed to ZSTD_createCStream() or ZSTD_createCStream_usingCDict()
|
||||||
|
* when called with the given `params.cParams` or `cdict` created with `params.cParams`. */
|
||||||
|
size_t ZSTD_CStreamWorkspaceBound(ZSTD_compressionParameters cParams);
|
||||||
|
|
||||||
|
typedef struct ZSTD_CStream_s ZSTD_CStream;
|
||||||
|
/*===== ZSTD_CStream management functions =====*/
|
||||||
|
/*! ZSTD_createCStream() :
|
||||||
|
* Creates a cstream using params.
|
||||||
|
* Callers may optionally provide the size of the source they intend to compress, or pass 0 if unknown.
|
||||||
|
* The stream is placed in `workspace`, which must outlive the returned stream.
|
||||||
|
* `workspace` must be at least ZSTD_CStreamWorkspaceBound(params.cParams) bytes. */
|
||||||
|
ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize, void* workspace, size_t workspaceSize);
|
||||||
|
/*! ZSTD_createCStream_usingCDict() :
|
||||||
|
* Similar to ZSTD_createCStream(), but use the given preprocessed dictionary.
|
||||||
|
*/
|
||||||
|
ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_usingCDict(const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize, void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
/*===== Streaming compression functions =====*/
|
||||||
|
ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); /**< re-use compression parameters from previous init; skip dictionary loading stage; zcs must be init at least once before. note: pledgedSrcSize must be correct, a size of 0 means unknown. for a frame size of 0 use initCStream_advanced */
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
|
||||||
|
ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
|
||||||
|
ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
|
||||||
|
|
||||||
|
ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */
|
||||||
|
ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block in all circumstances. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-***************************************************************************
|
||||||
|
* Streaming decompression - HowTo
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Use ZSTD_initDStream() to start a new decompression operation,
|
||||||
|
* or ZSTD_initDStream_usingDict() if decompression requires a dictionary.
|
||||||
|
* @return : recommended first input size
|
||||||
|
*
|
||||||
|
* Use ZSTD_decompressStream() repetitively to consume your input.
|
||||||
|
* The function will update both `pos` fields.
|
||||||
|
* If `input.pos < input.size`, some input has not been consumed.
|
||||||
|
* It's up to the caller to present again remaining data.
|
||||||
|
* If `output.pos < output.size`, decoder has flushed everything it could.
|
||||||
|
* @return : 0 when a frame is completely decoded and fully flushed,
|
||||||
|
* an error code, which can be tested using ZSTD_isError(),
|
||||||
|
* any other value > 0, which means there is still some decoding to do to complete current frame.
|
||||||
|
* The return value is a suggested next input size (a hint to improve latency) that will never load more than the current frame.
|
||||||
|
* *******************************************************************************/
|
||||||
|
|
||||||
|
/*! ZSTD_DStreamWorkspaceBound() :
|
||||||
|
* Returns the minimum amount of memory that needs to be passed to ZSTD_createDStream() to decompress frames with windowSize <= maxWindowSize. */
|
||||||
|
size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize);
|
||||||
|
|
||||||
|
typedef struct ZSTD_DStream_s ZSTD_DStream;
|
||||||
|
/*===== ZSTD_DStream management functions =====*/
|
||||||
|
/*! ZSTD_createDStream() :
|
||||||
|
* Creates a dstream that can decompress frames with windowSize up to maxWindowSize.
|
||||||
|
* The stream is placed in `workspace`, which must outlive the returned stream.
|
||||||
|
* `workspace` must be at least ZSTD_DStreamWorkspaceBound(maxWindowSize) bytes. */
|
||||||
|
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(size_t maxWindowSize, void* workspace, size_t workspaceSize);
|
||||||
|
/*! ZSTD_createDStream_usingDDict() :
|
||||||
|
* Similar to ZSTD_createCStream(), but use the given preprocessed dictionary. */
|
||||||
|
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_usingDDict(size_t maxWindowSize, const ZSTD_DDict* ddict, void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
/*===== Streaming decompression functions =====*/
|
||||||
|
ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
|
||||||
|
|
||||||
|
ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */
|
||||||
|
ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Constants ---*/
|
||||||
|
#define ZSTD_MAGICNUMBER 0xFD2FB528 /* >= v0.8.0 */
|
||||||
|
#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U
|
||||||
|
|
||||||
|
#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1)
|
||||||
|
#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2)
|
||||||
|
|
||||||
|
#define ZSTD_WINDOWLOG_MAX_32 27
|
||||||
|
#define ZSTD_WINDOWLOG_MAX_64 27
|
||||||
|
#define ZSTD_WINDOWLOG_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64))
|
||||||
|
#define ZSTD_WINDOWLOG_MIN 10
|
||||||
|
#define ZSTD_HASHLOG_MAX ZSTD_WINDOWLOG_MAX
|
||||||
|
#define ZSTD_HASHLOG_MIN 6
|
||||||
|
#define ZSTD_CHAINLOG_MAX (ZSTD_WINDOWLOG_MAX+1)
|
||||||
|
#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
|
||||||
|
#define ZSTD_HASHLOG3_MAX 17
|
||||||
|
#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
|
||||||
|
#define ZSTD_SEARCHLOG_MIN 1
|
||||||
|
#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
|
||||||
|
#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */
|
||||||
|
#define ZSTD_TARGETLENGTH_MIN 4
|
||||||
|
#define ZSTD_TARGETLENGTH_MAX 999
|
||||||
|
|
||||||
|
#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */
|
||||||
|
#define ZSTD_FRAMEHEADERSIZE_MIN 6
|
||||||
|
static const size_t ZSTD_frameHeaderSize_prefix = 5;
|
||||||
|
static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN;
|
||||||
|
static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
|
||||||
|
static const size_t ZSTD_skippableHeaderSize = 8; /* magic number + skippable frame length */
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Compressed size functions
|
||||||
|
***************************************/
|
||||||
|
|
||||||
|
/*! ZSTD_findFrameCompressedSize() :
|
||||||
|
* `src` should point to the start of a ZSTD encoded frame or skippable frame
|
||||||
|
* `srcSize` must be at least as large as the frame
|
||||||
|
* @return : the compressed size of the frame pointed to by `src`, suitable to pass to
|
||||||
|
* `ZSTD_decompress` or similar, or an error code if given invalid input. */
|
||||||
|
ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Decompressed size functions
|
||||||
|
***************************************/
|
||||||
|
/*! ZSTD_getFrameContentSize() :
|
||||||
|
* `src` should point to the start of a ZSTD encoded frame
|
||||||
|
* `srcSize` must be at least as large as the frame header. A value greater than or equal
|
||||||
|
* to `ZSTD_frameHeaderSize_max` is guaranteed to be large enough in all cases.
|
||||||
|
* @return : decompressed size of the frame pointed to be `src` if known, otherwise
|
||||||
|
* - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
|
||||||
|
* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
|
||||||
|
ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
|
||||||
|
|
||||||
|
/*! ZSTD_findDecompressedSize() :
|
||||||
|
* `src` should point the start of a series of ZSTD encoded and/or skippable frames
|
||||||
|
* `srcSize` must be the _exact_ size of this series
|
||||||
|
* (i.e. there should be a frame boundary exactly `srcSize` bytes after `src`)
|
||||||
|
* @return : the decompressed size of all data in the contained frames, as a 64-bit value _if known_
|
||||||
|
* - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN
|
||||||
|
* - if an error occurred: ZSTD_CONTENTSIZE_ERROR
|
||||||
|
*
|
||||||
|
* note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode.
|
||||||
|
* When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size.
|
||||||
|
* In which case, it's necessary to use streaming mode to decompress data.
|
||||||
|
* Optionally, application can still use ZSTD_decompress() while relying on implied limits.
|
||||||
|
* (For example, data may be necessarily cut into blocks <= 16 KB).
|
||||||
|
* note 2 : decompressed size is always present when compression is done with ZSTD_compress()
|
||||||
|
* note 3 : decompressed size can be very large (64-bits value),
|
||||||
|
* potentially larger than what local system can handle as a single memory segment.
|
||||||
|
* In which case, it's necessary to use streaming mode to decompress data.
|
||||||
|
* note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified.
|
||||||
|
* Always ensure result fits within application's authorized limits.
|
||||||
|
* Each application can set its own limits.
|
||||||
|
* note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to
|
||||||
|
* read each contained frame header. This is efficient as most of the data is skipped,
|
||||||
|
* however it does mean that all frame data must be present and valid. */
|
||||||
|
ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Advanced compression functions
|
||||||
|
***************************************/
|
||||||
|
/*! ZSTD_checkCParams() :
|
||||||
|
* Ensure param values remain within authorized range */
|
||||||
|
ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params);
|
||||||
|
|
||||||
|
/*! ZSTD_adjustCParams() :
|
||||||
|
* optimize params for a given `srcSize` and `dictSize`.
|
||||||
|
* both values are optional, select `0` if unknown. */
|
||||||
|
ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize);
|
||||||
|
|
||||||
|
/*--- Advanced decompression functions ---*/
|
||||||
|
|
||||||
|
/*! ZSTD_isFrame() :
|
||||||
|
* Tells if the content of `buffer` starts with a valid Frame Identifier.
|
||||||
|
* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
|
||||||
|
* Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
|
||||||
|
* Note 3 : Skippable Frame Identifiers are considered valid. */
|
||||||
|
ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);
|
||||||
|
|
||||||
|
/*! ZSTD_getDictID_fromDict() :
|
||||||
|
* Provides the dictID stored within dictionary.
|
||||||
|
* if @return == 0, the dictionary is not conformant with Zstandard specification.
|
||||||
|
* It can still be loaded, but as a content-only dictionary. */
|
||||||
|
ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
|
||||||
|
|
||||||
|
/*! ZSTD_getDictID_fromDDict() :
|
||||||
|
* Provides the dictID of the dictionary loaded into `ddict`.
|
||||||
|
* If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
|
||||||
|
* Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
|
||||||
|
ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);
|
||||||
|
|
||||||
|
/*! ZSTD_getDictID_fromFrame() :
|
||||||
|
* Provides the dictID required to decompressed the frame stored within `src`.
|
||||||
|
* If @return == 0, the dictID could not be decoded.
|
||||||
|
* This could for one of the following reasons :
|
||||||
|
* - The frame does not require a dictionary to be decoded (most common case).
|
||||||
|
* - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information.
|
||||||
|
* Note : this use case also happens when using a non-conformant dictionary.
|
||||||
|
* - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
|
||||||
|
* - This is not a Zstandard frame.
|
||||||
|
* When identifying the exact failure cause, it's possible to used ZSTD_getFrameParams(), which will provide a more precise error code. */
|
||||||
|
ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Buffer-less and synchronous inner streaming functions
|
||||||
|
*
|
||||||
|
* This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
|
||||||
|
* But it's also a complex one, with many restrictions (documented below).
|
||||||
|
* Prefer using normal streaming API for an easier experience
|
||||||
|
********************************************************************* */
|
||||||
|
|
||||||
|
/**
|
||||||
|
Buffer-less streaming compression (synchronous mode)
|
||||||
|
|
||||||
|
A ZSTD_CCtx object is required to track streaming operations.
|
||||||
|
Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
|
||||||
|
ZSTD_CCtx object can be re-used multiple times within successive compression operations.
|
||||||
|
|
||||||
|
Start by initializing a context.
|
||||||
|
Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression,
|
||||||
|
or ZSTD_compressBegin_advanced(), for finer parameter control.
|
||||||
|
It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx()
|
||||||
|
|
||||||
|
Then, consume your input using ZSTD_compressContinue().
|
||||||
|
There are some important considerations to keep in mind when using this advanced function :
|
||||||
|
- ZSTD_compressContinue() has no internal buffer. It uses externally provided buffer only.
|
||||||
|
- Interface is synchronous : input is consumed entirely and produce 1+ (or more) compressed blocks.
|
||||||
|
- Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
|
||||||
|
Worst case evaluation is provided by ZSTD_compressBound().
|
||||||
|
ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
|
||||||
|
- ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog).
|
||||||
|
It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks)
|
||||||
|
- ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps.
|
||||||
|
In which case, it will "discard" the relevant memory section from its history.
|
||||||
|
|
||||||
|
Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
|
||||||
|
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 will be considered unfinished (corrupted) by decoders.
|
||||||
|
|
||||||
|
`ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new frame.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*===== Buffer-less streaming compression functions =====*/
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */
|
||||||
|
ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize can be 0, indicating unknown size. if it is non-zero, it must be accurate. for 0 size frames, use compressBegin_advanced */
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize can be 0, indicating unknown size. if it is non-zero, it must be accurate. for 0 size frames, use compressBegin_advanced */
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-
|
||||||
|
Buffer-less streaming decompression (synchronous mode)
|
||||||
|
|
||||||
|
A ZSTD_DCtx object is required to track streaming operations.
|
||||||
|
Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
|
||||||
|
A ZSTD_DCtx object can be re-used multiple times.
|
||||||
|
|
||||||
|
First typical operation is to retrieve frame parameters, using ZSTD_getFrameParams().
|
||||||
|
It fills a ZSTD_frameParams structure which provide important information to correctly decode the frame,
|
||||||
|
such as the minimum rolling buffer size to allocate to decompress data (`windowSize`),
|
||||||
|
and the dictionary ID used.
|
||||||
|
(Note : content size is optional, it may not be present. 0 means : content size unknown).
|
||||||
|
Note that these values could be wrong, either because of data malformation, or because an attacker is spoofing deliberate false information.
|
||||||
|
As a consequence, check that values remain within valid application range, especially `windowSize`, before allocation.
|
||||||
|
Each application can set its own limit, depending on local restrictions. For extended interoperability, it is recommended to support at least 8 MB.
|
||||||
|
Frame parameters are extracted from the beginning of the compressed frame.
|
||||||
|
Data fragment must be large enough to ensure successful decoding, typically `ZSTD_frameHeaderSize_max` bytes.
|
||||||
|
@result : 0 : successful decoding, the `ZSTD_frameParams` structure is correctly filled.
|
||||||
|
>0 : `srcSize` is too small, please provide at least @result bytes on next attempt.
|
||||||
|
errorCode, which can be tested using ZSTD_isError().
|
||||||
|
|
||||||
|
Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict().
|
||||||
|
Alternatively, you can copy a prepared context, using ZSTD_copyDCtx().
|
||||||
|
|
||||||
|
Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
|
||||||
|
ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue().
|
||||||
|
ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail.
|
||||||
|
|
||||||
|
@result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
|
||||||
|
It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some metadata item.
|
||||||
|
It can also be an error code, which can be tested with ZSTD_isError().
|
||||||
|
|
||||||
|
ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize`.
|
||||||
|
They should preferably be located contiguously, prior to current block.
|
||||||
|
Alternatively, a round buffer of sufficient size is also possible. Sufficient size is determined by frame parameters.
|
||||||
|
ZSTD_decompressContinue() is very sensitive to contiguity,
|
||||||
|
if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
|
||||||
|
or that previous contiguous segment is large enough to properly handle maximum back-reference.
|
||||||
|
|
||||||
|
A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
|
||||||
|
Context can then be reset to start a new decompression.
|
||||||
|
|
||||||
|
Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType().
|
||||||
|
This information is not required to properly decode a frame.
|
||||||
|
|
||||||
|
== Special case : skippable frames ==
|
||||||
|
|
||||||
|
Skippable frames allow integration of user-defined data into a flow of concatenated frames.
|
||||||
|
Skippable frames will be ignored (skipped) by a decompressor. The format of skippable frames is as follows :
|
||||||
|
a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F
|
||||||
|
b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
|
||||||
|
c) Frame Content - any content (User Data) of length equal to Frame Size
|
||||||
|
For skippable frames ZSTD_decompressContinue() always returns 0.
|
||||||
|
For skippable frames ZSTD_getFrameParams() returns fparamsPtr->windowLog==0 what means that a frame is skippable.
|
||||||
|
Note : If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might actually be a Zstd encoded frame with no content.
|
||||||
|
For purposes of decompression, it is valid in both cases to skip the frame using
|
||||||
|
ZSTD_findFrameCompressedSize to find its size in bytes.
|
||||||
|
It also returns Frame Size as fparamsPtr->frameContentSize.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long long frameContentSize;
|
||||||
|
unsigned windowSize;
|
||||||
|
unsigned dictID;
|
||||||
|
unsigned checksumFlag;
|
||||||
|
} ZSTD_frameParams;
|
||||||
|
|
||||||
|
/*===== Buffer-less streaming decompression functions =====*/
|
||||||
|
ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input, see details below */
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
|
||||||
|
ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
|
||||||
|
ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx);
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
|
||||||
|
ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Block functions
|
||||||
|
|
||||||
|
Block functions produce and decode raw zstd blocks, without frame metadata.
|
||||||
|
Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
||||||
|
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
|
||||||
|
|
||||||
|
A few rules to respect :
|
||||||
|
- Compressing and decompressing require a context structure
|
||||||
|
+ Use ZSTD_createCCtx() and ZSTD_createDCtx()
|
||||||
|
- It is necessary to init context before starting
|
||||||
|
+ compression : ZSTD_compressBegin()
|
||||||
|
+ decompression : ZSTD_decompressBegin()
|
||||||
|
+ variants _usingDict() are also allowed
|
||||||
|
+ copyCCtx() and copyDCtx() work too
|
||||||
|
- Block size is limited, it must be <= ZSTD_getBlockSizeMax()
|
||||||
|
+ If you need to compress more, cut data into multiple blocks
|
||||||
|
+ Consider using the regular ZSTD_compress() instead, as frame metadata costs become negligible when source size is large.
|
||||||
|
- When a block is considered not compressible enough, ZSTD_compressBlock() result will be zero.
|
||||||
|
In which case, nothing is produced into `dst`.
|
||||||
|
+ User must test for such outcome and deal directly with uncompressed data
|
||||||
|
+ ZSTD_decompressBlock() doesn't accept uncompressed data as input !!!
|
||||||
|
+ In case of multiple successive blocks, decoder must be informed of uncompressed block existence to follow proper history.
|
||||||
|
Use ZSTD_insertBlock() in such a case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZSTD_BLOCKSIZE_ABSOLUTEMAX (128 * 1024) /* define, for static allocation */
|
||||||
|
/*===== Raw zstd block functions =====*/
|
||||||
|
ZSTDLIB_API size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx);
|
||||||
|
ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert block into `dctx` history. Useful for uncompressed blocks */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_H_235446 */
|
17
contrib/linux-kernel/lib/Kconfig.diff
Normal file
17
contrib/linux-kernel/lib/Kconfig.diff
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/lib/Kconfig b/lib/Kconfig
|
||||||
|
index 260a80e..39d9347 100644
|
||||||
|
--- a/lib/Kconfig
|
||||||
|
+++ b/lib/Kconfig
|
||||||
|
@@ -239,6 +239,12 @@ config LZ4HC_COMPRESS
|
||||||
|
config LZ4_DECOMPRESS
|
||||||
|
tristate
|
||||||
|
|
||||||
|
+config ZSTD_COMPRESS
|
||||||
|
+ tristate
|
||||||
|
+
|
||||||
|
+config ZSTD_DECOMPRESS
|
||||||
|
+ tristate
|
||||||
|
+
|
||||||
|
source "lib/xz/Kconfig"
|
||||||
|
|
||||||
|
#
|
13
contrib/linux-kernel/lib/Makefile.diff
Normal file
13
contrib/linux-kernel/lib/Makefile.diff
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/lib/Makefile b/lib/Makefile
|
||||||
|
index 50144a3..b30a998 100644
|
||||||
|
--- a/lib/Makefile
|
||||||
|
+++ b/lib/Makefile
|
||||||
|
@@ -106,6 +106,8 @@ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
|
||||||
|
obj-$(CONFIG_LZ4_COMPRESS) += lz4/
|
||||||
|
obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/
|
||||||
|
obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
|
||||||
|
+obj-$(CONFIG_ZSTD_COMPRESS) += zstd/
|
||||||
|
+obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/
|
||||||
|
obj-$(CONFIG_XZ_DEC) += xz/
|
||||||
|
obj-$(CONFIG_RAID6_PQ) += raid6/
|
||||||
|
|
9
contrib/linux-kernel/lib/zstd/Makefile
Normal file
9
contrib/linux-kernel/lib/zstd/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
obj-$(CONFIG_ZSTD_COMPRESS) += zstd_compress.o
|
||||||
|
obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd_decompress.o
|
||||||
|
|
||||||
|
ccflags-y += -O3
|
||||||
|
|
||||||
|
zstd_compress-y := entropy_common.o fse_decompress.o xxhash.o zstd_common.o \
|
||||||
|
fse_compress.o huf_compress.o compress.o
|
||||||
|
zstd_decompress-y := entropy_common.o fse_decompress.o xxhash.o zstd_common.o \
|
||||||
|
huf_decompress.o decompress.o
|
391
contrib/linux-kernel/lib/zstd/bitstream.h
Normal file
391
contrib/linux-kernel/lib/zstd/bitstream.h
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
/* ******************************************************************
|
||||||
|
bitstream
|
||||||
|
Part of FSE library
|
||||||
|
header file (to include)
|
||||||
|
Copyright (C) 2013-2016, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
****************************************************************** */
|
||||||
|
#ifndef BITSTREAM_H_MODULE
|
||||||
|
#define BITSTREAM_H_MODULE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This API consists of small unitary functions, which must be inlined for best performance.
|
||||||
|
* Since link-time-optimization is not available for all compilers,
|
||||||
|
* these functions are defined into a .h to be included.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include "mem.h" /* unaligned access routines */
|
||||||
|
#include "error_private.h" /* error codes and messages */
|
||||||
|
|
||||||
|
|
||||||
|
/*=========================================
|
||||||
|
* Target specific
|
||||||
|
=========================================*/
|
||||||
|
#define STREAM_ACCUMULATOR_MIN_32 25
|
||||||
|
#define STREAM_ACCUMULATOR_MIN_64 57
|
||||||
|
#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
|
||||||
|
|
||||||
|
/*-******************************************
|
||||||
|
* bitStream encoding API (write forward)
|
||||||
|
********************************************/
|
||||||
|
/* bitStream can mix input from multiple sources.
|
||||||
|
* A critical property of these streams is that they encode and decode in **reverse** direction.
|
||||||
|
* So the first bit sequence you add will be the last to be read, like a LIFO stack.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t bitContainer;
|
||||||
|
int bitPos;
|
||||||
|
char* startPtr;
|
||||||
|
char* ptr;
|
||||||
|
char* endPtr;
|
||||||
|
} BIT_CStream_t;
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
|
||||||
|
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
|
||||||
|
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
|
||||||
|
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
||||||
|
|
||||||
|
/* Start with initCStream, providing the size of buffer to write into.
|
||||||
|
* bitStream will never write outside of this buffer.
|
||||||
|
* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
|
||||||
|
*
|
||||||
|
* bits are first added to a local register.
|
||||||
|
* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
|
||||||
|
* Writing data into memory is an explicit operation, performed by the flushBits function.
|
||||||
|
* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
|
||||||
|
* After a flushBits, a maximum of 7 bits might still be stored into local register.
|
||||||
|
*
|
||||||
|
* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
|
||||||
|
*
|
||||||
|
* Last operation is to close the bitStream.
|
||||||
|
* The function returns the final size of CStream in bytes.
|
||||||
|
* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-********************************************
|
||||||
|
* bitStream decoding API (read backward)
|
||||||
|
**********************************************/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t bitContainer;
|
||||||
|
unsigned bitsConsumed;
|
||||||
|
const char* ptr;
|
||||||
|
const char* start;
|
||||||
|
} 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 ... :( */
|
||||||
|
|
||||||
|
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);
|
||||||
|
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
|
||||||
|
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).
|
||||||
|
* 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.
|
||||||
|
* Otherwise, it can be less than that, so proceed accordingly.
|
||||||
|
* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* unsafe API
|
||||||
|
******************************************/
|
||||||
|
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
|
||||||
|
/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
|
||||||
|
|
||||||
|
MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
|
||||||
|
/* unsafe version; does not check buffer overflow */
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
|
||||||
|
/* faster, but works only if nbBits >= 1 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Internal functions
|
||||||
|
****************************************************************/
|
||||||
|
MEM_STATIC unsigned BIT_highbit32 (register U32 val)
|
||||||
|
{
|
||||||
|
# if defined(_MSC_VER) /* Visual */
|
||||||
|
unsigned long r=0;
|
||||||
|
_BitScanReverse ( &r, val );
|
||||||
|
return (unsigned) r;
|
||||||
|
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
|
||||||
|
return 31 - __builtin_clz (val);
|
||||||
|
# else /* Software version */
|
||||||
|
static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
|
||||||
|
U32 v = val;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===== Local Constants =====*/
|
||||||
|
static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* bitStream encoding
|
||||||
|
****************************************************************/
|
||||||
|
/*! BIT_initCStream() :
|
||||||
|
* `dstCapacity` must be > sizeof(void*)
|
||||||
|
* @return : 0 if success,
|
||||||
|
otherwise an error code (can be tested using ERR_isError() ) */
|
||||||
|
MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* startPtr, size_t dstCapacity)
|
||||||
|
{
|
||||||
|
bitC->bitContainer = 0;
|
||||||
|
bitC->bitPos = 0;
|
||||||
|
bitC->startPtr = (char*)startPtr;
|
||||||
|
bitC->ptr = bitC->startPtr;
|
||||||
|
bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->ptr);
|
||||||
|
if (dstCapacity <= sizeof(bitC->ptr)) return ERROR(dstSize_tooSmall);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_addBits() :
|
||||||
|
can add up to 26 bits into `bitC`.
|
||||||
|
Does not check for register overflow ! */
|
||||||
|
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
|
||||||
|
{
|
||||||
|
bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
|
||||||
|
bitC->bitPos += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_addBitsFast() :
|
||||||
|
* works only if `value` is _clean_, meaning all high bits above nbBits are 0 */
|
||||||
|
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
|
||||||
|
{
|
||||||
|
bitC->bitContainer |= value << bitC->bitPos;
|
||||||
|
bitC->bitPos += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_flushBitsFast() :
|
||||||
|
* unsafe version; does not check buffer overflow */
|
||||||
|
MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
|
||||||
|
{
|
||||||
|
size_t const nbBytes = bitC->bitPos >> 3;
|
||||||
|
MEM_writeLEST(bitC->ptr, bitC->bitContainer);
|
||||||
|
bitC->ptr += nbBytes;
|
||||||
|
bitC->bitPos &= 7;
|
||||||
|
bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_flushBits() :
|
||||||
|
* safe version; check for buffer overflow, and prevents it.
|
||||||
|
* note : does not signal buffer overflow. This will be revealed later on using BIT_closeCStream() */
|
||||||
|
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
|
||||||
|
{
|
||||||
|
size_t const nbBytes = bitC->bitPos >> 3;
|
||||||
|
MEM_writeLEST(bitC->ptr, bitC->bitContainer);
|
||||||
|
bitC->ptr += nbBytes;
|
||||||
|
if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
|
||||||
|
bitC->bitPos &= 7;
|
||||||
|
bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_closeCStream() :
|
||||||
|
* @return : size of CStream, in bytes,
|
||||||
|
or 0 if it could not fit into dstBuffer */
|
||||||
|
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
|
||||||
|
{
|
||||||
|
BIT_addBitsFast(bitC, 1, 1); /* endMark */
|
||||||
|
BIT_flushBits(bitC);
|
||||||
|
|
||||||
|
if (bitC->ptr >= bitC->endPtr) return 0; /* doesn't fit within authorized budget : cancel */
|
||||||
|
|
||||||
|
return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-********************************************************
|
||||||
|
* bitStream decoding
|
||||||
|
**********************************************************/
|
||||||
|
/*! BIT_initDStream() :
|
||||||
|
* Initialize a BIT_DStream_t.
|
||||||
|
* `bitD` : a pointer to an already allocated BIT_DStream_t structure.
|
||||||
|
* `srcSize` must be the *exact* size of the bitStream, in bytes.
|
||||||
|
* @return : size of stream (== srcSize) or an errorCode if a problem is detected
|
||||||
|
*/
|
||||||
|
MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
|
||||||
|
{
|
||||||
|
if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
|
||||||
|
|
||||||
|
if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
|
||||||
|
bitD->start = (const char*)srcBuffer;
|
||||||
|
bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
|
||||||
|
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||||
|
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
||||||
|
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
|
||||||
|
if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
|
||||||
|
} else {
|
||||||
|
bitD->start = (const char*)srcBuffer;
|
||||||
|
bitD->ptr = bitD->start;
|
||||||
|
bitD->bitContainer = *(const BYTE*)(bitD->start);
|
||||||
|
switch(srcSize)
|
||||||
|
{
|
||||||
|
case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
|
||||||
|
case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
|
||||||
|
case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
|
||||||
|
case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
|
||||||
|
case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
|
||||||
|
case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
||||||
|
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
|
||||||
|
if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
|
||||||
|
bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return srcSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
|
||||||
|
{
|
||||||
|
return bitContainer >> start;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
|
||||||
|
{
|
||||||
|
return (bitContainer >> start) & BIT_mask[nbBits];
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
|
||||||
|
{
|
||||||
|
return bitContainer & BIT_mask[nbBits];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_lookBits() :
|
||||||
|
* Provides next n bits from local register.
|
||||||
|
* local register is not modified.
|
||||||
|
* On 32-bits, maxNbBits==24.
|
||||||
|
* On 64-bits, maxNbBits==56.
|
||||||
|
* @return : value extracted
|
||||||
|
*/
|
||||||
|
MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
|
||||||
|
return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_lookBitsFast() :
|
||||||
|
* unsafe version; only works only if nbBits >= 1 */
|
||||||
|
MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
|
||||||
|
return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
bitD->bitsConsumed += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_readBits() :
|
||||||
|
* Read (consume) next n bits from local register and update.
|
||||||
|
* Pay attention to not read more than nbBits contained into local register.
|
||||||
|
* @return : extracted value.
|
||||||
|
*/
|
||||||
|
MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
size_t const value = BIT_lookBits(bitD, nbBits);
|
||||||
|
BIT_skipBits(bitD, nbBits);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_readBitsFast() :
|
||||||
|
* unsafe version; only works only if nbBits >= 1 */
|
||||||
|
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
size_t const value = BIT_lookBitsFast(bitD, nbBits);
|
||||||
|
BIT_skipBits(bitD, nbBits);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_reloadDStream() :
|
||||||
|
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
||||||
|
* This function is safe, it guarantees it will not read beyond src buffer.
|
||||||
|
* @return : status of `BIT_DStream_t` internal register.
|
||||||
|
if status == BIT_DStream_unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
|
||||||
|
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should not happen => corruption detected */
|
||||||
|
return BIT_DStream_overflow;
|
||||||
|
|
||||||
|
if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
|
||||||
|
bitD->ptr -= bitD->bitsConsumed >> 3;
|
||||||
|
bitD->bitsConsumed &= 7;
|
||||||
|
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||||
|
return BIT_DStream_unfinished;
|
||||||
|
}
|
||||||
|
if (bitD->ptr == bitD->start) {
|
||||||
|
if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
|
||||||
|
return BIT_DStream_completed;
|
||||||
|
}
|
||||||
|
{ U32 nbBytes = bitD->bitsConsumed >> 3;
|
||||||
|
BIT_DStream_status result = BIT_DStream_unfinished;
|
||||||
|
if (bitD->ptr - nbBytes < bitD->start) {
|
||||||
|
nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
|
||||||
|
result = BIT_DStream_endOfBuffer;
|
||||||
|
}
|
||||||
|
bitD->ptr -= nbBytes;
|
||||||
|
bitD->bitsConsumed -= nbBytes*8;
|
||||||
|
bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_endOfDStream() :
|
||||||
|
* @return Tells if DStream has exactly reached its end (all bits consumed).
|
||||||
|
*/
|
||||||
|
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
|
||||||
|
{
|
||||||
|
return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BITSTREAM_H_MODULE */
|
3384
contrib/linux-kernel/lib/zstd/compress.c
Normal file
3384
contrib/linux-kernel/lib/zstd/compress.c
Normal file
File diff suppressed because it is too large
Load Diff
2377
contrib/linux-kernel/lib/zstd/decompress.c
Normal file
2377
contrib/linux-kernel/lib/zstd/decompress.c
Normal file
File diff suppressed because it is too large
Load Diff
217
contrib/linux-kernel/lib/zstd/entropy_common.c
Normal file
217
contrib/linux-kernel/lib/zstd/entropy_common.c
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
Common functions of New Generation Entropy library
|
||||||
|
Copyright (C) 2016, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||||
|
*************************************************************************** */
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#include "mem.h"
|
||||||
|
#include "error_private.h" /* ERR_*, ERROR */
|
||||||
|
#include "fse.h"
|
||||||
|
#include "huf.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*=== Version ===*/
|
||||||
|
unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
|
||||||
|
|
||||||
|
|
||||||
|
/*=== Error Management ===*/
|
||||||
|
unsigned FSE_isError(size_t code) { return ERR_isError(code); }
|
||||||
|
|
||||||
|
unsigned HUF_isError(size_t code) { return ERR_isError(code); }
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* FSE NCount encoding-decoding
|
||||||
|
****************************************************************/
|
||||||
|
size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
|
||||||
|
const void* headerBuffer, size_t hbSize)
|
||||||
|
{
|
||||||
|
const BYTE* const istart = (const BYTE*) headerBuffer;
|
||||||
|
const BYTE* const iend = istart + hbSize;
|
||||||
|
const BYTE* ip = istart;
|
||||||
|
int nbBits;
|
||||||
|
int remaining;
|
||||||
|
int threshold;
|
||||||
|
U32 bitStream;
|
||||||
|
int bitCount;
|
||||||
|
unsigned charnum = 0;
|
||||||
|
int previous0 = 0;
|
||||||
|
|
||||||
|
if (hbSize < 4) return ERROR(srcSize_wrong);
|
||||||
|
bitStream = MEM_readLE32(ip);
|
||||||
|
nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
|
||||||
|
if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
|
||||||
|
bitStream >>= 4;
|
||||||
|
bitCount = 4;
|
||||||
|
*tableLogPtr = nbBits;
|
||||||
|
remaining = (1<<nbBits)+1;
|
||||||
|
threshold = 1<<nbBits;
|
||||||
|
nbBits++;
|
||||||
|
|
||||||
|
while ((remaining>1) & (charnum<=*maxSVPtr)) {
|
||||||
|
if (previous0) {
|
||||||
|
unsigned n0 = charnum;
|
||||||
|
while ((bitStream & 0xFFFF) == 0xFFFF) {
|
||||||
|
n0 += 24;
|
||||||
|
if (ip < iend-5) {
|
||||||
|
ip += 2;
|
||||||
|
bitStream = MEM_readLE32(ip) >> bitCount;
|
||||||
|
} else {
|
||||||
|
bitStream >>= 16;
|
||||||
|
bitCount += 16;
|
||||||
|
} }
|
||||||
|
while ((bitStream & 3) == 3) {
|
||||||
|
n0 += 3;
|
||||||
|
bitStream >>= 2;
|
||||||
|
bitCount += 2;
|
||||||
|
}
|
||||||
|
n0 += bitStream & 3;
|
||||||
|
bitCount += 2;
|
||||||
|
if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
|
||||||
|
while (charnum < n0) normalizedCounter[charnum++] = 0;
|
||||||
|
if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
|
||||||
|
ip += bitCount>>3;
|
||||||
|
bitCount &= 7;
|
||||||
|
bitStream = MEM_readLE32(ip) >> bitCount;
|
||||||
|
} else {
|
||||||
|
bitStream >>= 2;
|
||||||
|
} }
|
||||||
|
{ int const max = (2*threshold-1) - remaining;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if ((bitStream & (threshold-1)) < (U32)max) {
|
||||||
|
count = bitStream & (threshold-1);
|
||||||
|
bitCount += nbBits-1;
|
||||||
|
} else {
|
||||||
|
count = bitStream & (2*threshold-1);
|
||||||
|
if (count >= threshold) count -= max;
|
||||||
|
bitCount += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
count--; /* extra accuracy */
|
||||||
|
remaining -= count < 0 ? -count : count; /* -1 means +1 */
|
||||||
|
normalizedCounter[charnum++] = (short)count;
|
||||||
|
previous0 = !count;
|
||||||
|
while (remaining < threshold) {
|
||||||
|
nbBits--;
|
||||||
|
threshold >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
|
||||||
|
ip += bitCount>>3;
|
||||||
|
bitCount &= 7;
|
||||||
|
} else {
|
||||||
|
bitCount -= (int)(8 * (iend - 4 - ip));
|
||||||
|
ip = iend - 4;
|
||||||
|
}
|
||||||
|
bitStream = MEM_readLE32(ip) >> (bitCount & 31);
|
||||||
|
} } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
|
||||||
|
if (remaining != 1) return ERROR(corruption_detected);
|
||||||
|
if (bitCount > 32) return ERROR(corruption_detected);
|
||||||
|
*maxSVPtr = charnum-1;
|
||||||
|
|
||||||
|
ip += (bitCount+7)>>3;
|
||||||
|
return ip-istart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! HUF_readStats() :
|
||||||
|
Read compact Huffman tree, saved by HUF_writeCTable().
|
||||||
|
`huffWeight` is destination buffer.
|
||||||
|
`rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
|
||||||
|
@return : size read from `src` , or an error Code .
|
||||||
|
Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
|
||||||
|
*/
|
||||||
|
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
U32 weightTotal;
|
||||||
|
const BYTE* ip = (const BYTE*) src;
|
||||||
|
size_t iSize;
|
||||||
|
size_t oSize;
|
||||||
|
|
||||||
|
if (!srcSize) return ERROR(srcSize_wrong);
|
||||||
|
iSize = ip[0];
|
||||||
|
/* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
|
||||||
|
|
||||||
|
if (iSize >= 128) { /* special header */
|
||||||
|
oSize = iSize - 127;
|
||||||
|
iSize = ((oSize+1)/2);
|
||||||
|
if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
|
||||||
|
if (oSize >= hwSize) return ERROR(corruption_detected);
|
||||||
|
ip += 1;
|
||||||
|
{ U32 n;
|
||||||
|
for (n=0; n<oSize; n+=2) {
|
||||||
|
huffWeight[n] = ip[n/2] >> 4;
|
||||||
|
huffWeight[n+1] = ip[n/2] & 15;
|
||||||
|
} } }
|
||||||
|
else { /* header compressed with FSE (normal case) */
|
||||||
|
FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
|
||||||
|
if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
|
||||||
|
oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */
|
||||||
|
if (FSE_isError(oSize)) return oSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* collect weight stats */
|
||||||
|
memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
|
||||||
|
weightTotal = 0;
|
||||||
|
{ U32 n; for (n=0; n<oSize; n++) {
|
||||||
|
if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
|
||||||
|
rankStats[huffWeight[n]]++;
|
||||||
|
weightTotal += (1 << huffWeight[n]) >> 1;
|
||||||
|
} }
|
||||||
|
if (weightTotal == 0) return ERROR(corruption_detected);
|
||||||
|
|
||||||
|
/* get last non-null symbol weight (implied, total must be 2^n) */
|
||||||
|
{ U32 const tableLog = BIT_highbit32(weightTotal) + 1;
|
||||||
|
if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
|
||||||
|
*tableLogPtr = tableLog;
|
||||||
|
/* determine last weight */
|
||||||
|
{ U32 const total = 1 << tableLog;
|
||||||
|
U32 const rest = total - weightTotal;
|
||||||
|
U32 const verif = 1 << BIT_highbit32(rest);
|
||||||
|
U32 const lastWeight = BIT_highbit32(rest) + 1;
|
||||||
|
if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
|
||||||
|
huffWeight[oSize] = (BYTE)lastWeight;
|
||||||
|
rankStats[lastWeight]++;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* check tree construction validity */
|
||||||
|
if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
|
||||||
|
|
||||||
|
/* results */
|
||||||
|
*nbSymbolsPtr = (U32)(oSize+1);
|
||||||
|
return iSize+1;
|
||||||
|
}
|
44
contrib/linux-kernel/lib/zstd/error_private.h
Normal file
44
contrib/linux-kernel/lib/zstd/error_private.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note : this module is expected to remain private, do not expose it */
|
||||||
|
|
||||||
|
#ifndef ERROR_H_MODULE
|
||||||
|
#define ERROR_H_MODULE
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include <linux/types.h> /* size_t */
|
||||||
|
#include <linux/zstd.h> /* enum list */
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Compiler-specific
|
||||||
|
******************************************/
|
||||||
|
#define ERR_STATIC static __attribute__((unused))
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Customization (error_public.h)
|
||||||
|
******************************************/
|
||||||
|
typedef ZSTD_ErrorCode ERR_enum;
|
||||||
|
#define PREFIX(name) ZSTD_error_##name
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Error codes handling
|
||||||
|
******************************************/
|
||||||
|
#define ERROR(name) ((size_t)-PREFIX(name))
|
||||||
|
|
||||||
|
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); }
|
||||||
|
|
||||||
|
#endif /* ERROR_H_MODULE */
|
606
contrib/linux-kernel/lib/zstd/fse.h
Normal file
606
contrib/linux-kernel/lib/zstd/fse.h
Normal file
@ -0,0 +1,606 @@
|
|||||||
|
/* ******************************************************************
|
||||||
|
FSE : Finite State Entropy codec
|
||||||
|
Public Prototypes declaration
|
||||||
|
Copyright (C) 2013-2016, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
****************************************************************** */
|
||||||
|
#ifndef FSE_H
|
||||||
|
#define FSE_H
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include <linux/types.h> /* size_t, ptrdiff_t */
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* FSE_PUBLIC_API : control library symbols visibility
|
||||||
|
******************************************/
|
||||||
|
#define FSE_PUBLIC_API
|
||||||
|
|
||||||
|
/*------ Version ------*/
|
||||||
|
#define FSE_VERSION_MAJOR 0
|
||||||
|
#define FSE_VERSION_MINOR 9
|
||||||
|
#define FSE_VERSION_RELEASE 0
|
||||||
|
|
||||||
|
#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
|
||||||
|
#define FSE_QUOTE(str) #str
|
||||||
|
#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
|
||||||
|
#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
|
||||||
|
|
||||||
|
#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
|
||||||
|
FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* Tool functions
|
||||||
|
******************************************/
|
||||||
|
FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
|
||||||
|
|
||||||
|
/* Error Management */
|
||||||
|
FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* FSE detailed API
|
||||||
|
******************************************/
|
||||||
|
/*!
|
||||||
|
FSE_compress() does the following:
|
||||||
|
1. count symbol occurrence from source[] into table count[]
|
||||||
|
2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
|
||||||
|
3. save normalized counters to memory buffer using writeNCount()
|
||||||
|
4. build encoding table 'CTable' from normalized counters
|
||||||
|
5. encode the data stream using encoding table 'CTable'
|
||||||
|
|
||||||
|
FSE_decompress() does the following:
|
||||||
|
1. read normalized counters with readNCount()
|
||||||
|
2. build decoding table 'DTable' from normalized counters
|
||||||
|
3. decode the data stream using decoding table 'DTable'
|
||||||
|
|
||||||
|
The following API allows targeting specific sub-functions for advanced tasks.
|
||||||
|
For example, it's possible to compress several blocks using the same 'CTable',
|
||||||
|
or to save and provide normalized distribution using external method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* *** COMPRESSION *** */
|
||||||
|
/*! FSE_optimalTableLog():
|
||||||
|
dynamically downsize 'tableLog' when conditions are met.
|
||||||
|
It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
|
||||||
|
@return : recommended tableLog (necessarily <= 'maxTableLog') */
|
||||||
|
FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
||||||
|
|
||||||
|
/*! FSE_normalizeCount():
|
||||||
|
normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
|
||||||
|
'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
|
||||||
|
@return : tableLog,
|
||||||
|
or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
|
||||||
|
|
||||||
|
/*! FSE_NCountWriteBound():
|
||||||
|
Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
|
||||||
|
Typically useful for allocation purpose. */
|
||||||
|
FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
/*! FSE_writeNCount():
|
||||||
|
Compactly save 'normalizedCounter' into 'buffer'.
|
||||||
|
@return : size of the compressed table,
|
||||||
|
or an errorCode, which can be tested using FSE_isError(). */
|
||||||
|
FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
|
||||||
|
/*! Constructor and Destructor of FSE_CTable.
|
||||||
|
Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
|
||||||
|
typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
|
||||||
|
|
||||||
|
/*! FSE_compress_usingCTable():
|
||||||
|
Compress `src` using `ct` into `dst` which must be already allocated.
|
||||||
|
@return : size of compressed data (<= `dstCapacity`),
|
||||||
|
or 0 if compressed data could not fit into `dst`,
|
||||||
|
or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tutorial :
|
||||||
|
----------
|
||||||
|
The first step is to count all symbols. FSE_count() does this job very fast.
|
||||||
|
Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
|
||||||
|
'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
|
||||||
|
maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
|
||||||
|
FSE_count() will return the number of occurrence of the most frequent symbol.
|
||||||
|
This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
|
||||||
|
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
|
||||||
|
The next step is to normalize the frequencies.
|
||||||
|
FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
|
||||||
|
It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
|
||||||
|
You can use 'tableLog'==0 to mean "use default tableLog value".
|
||||||
|
If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
|
||||||
|
which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
|
||||||
|
|
||||||
|
The result of FSE_normalizeCount() will be saved into a table,
|
||||||
|
called 'normalizedCounter', which is a table of signed short.
|
||||||
|
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
|
||||||
|
The return value is tableLog if everything proceeded as expected.
|
||||||
|
It is 0 if there is a single symbol within distribution.
|
||||||
|
If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
|
||||||
|
'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
|
||||||
|
'buffer' must be already allocated.
|
||||||
|
For guaranteed success, buffer size must be at least FSE_headerBound().
|
||||||
|
The result of the function is the number of bytes written into 'buffer'.
|
||||||
|
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
|
||||||
|
|
||||||
|
'normalizedCounter' can then be used to create the compression table 'CTable'.
|
||||||
|
The space required by 'CTable' must be already allocated, using FSE_createCTable().
|
||||||
|
You can then use FSE_buildCTable() to fill 'CTable'.
|
||||||
|
If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
|
||||||
|
'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
|
||||||
|
Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
|
||||||
|
The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
|
||||||
|
If it returns '0', compressed data could not fit into 'dst'.
|
||||||
|
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *** DECOMPRESSION *** */
|
||||||
|
|
||||||
|
/*! FSE_readNCount():
|
||||||
|
Read compactly saved 'normalizedCounter' from 'rBuffer'.
|
||||||
|
@return : size read from 'rBuffer',
|
||||||
|
or an errorCode, which can be tested using FSE_isError().
|
||||||
|
maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
|
||||||
|
FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize);
|
||||||
|
|
||||||
|
/*! Constructor and Destructor of FSE_DTable.
|
||||||
|
Note that its size depends on 'tableLog' */
|
||||||
|
typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
|
||||||
|
|
||||||
|
/*! FSE_buildDTable():
|
||||||
|
Builds 'dt', which must be already allocated, using FSE_createDTable().
|
||||||
|
return : 0, or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
/*! FSE_decompress_usingDTable():
|
||||||
|
Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
|
||||||
|
into `dst` which must be already allocated.
|
||||||
|
@return : size of regenerated data (necessarily <= `dstCapacity`),
|
||||||
|
or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tutorial :
|
||||||
|
----------
|
||||||
|
(Note : these functions only decompress FSE-compressed blocks.
|
||||||
|
If block is uncompressed, use memcpy() instead
|
||||||
|
If block is a single repeated byte, use memset() instead )
|
||||||
|
|
||||||
|
The first step is to obtain the normalized frequencies of symbols.
|
||||||
|
This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
|
||||||
|
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
|
||||||
|
In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
|
||||||
|
or size the table to handle worst case situations (typically 256).
|
||||||
|
FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
|
||||||
|
The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
|
||||||
|
Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
|
||||||
|
If there is an error, the function will return an error code, which can be tested using FSE_isError().
|
||||||
|
|
||||||
|
The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
|
||||||
|
This is performed by the function FSE_buildDTable().
|
||||||
|
The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
|
||||||
|
If there is an error, the function will return an error code, which can be tested using FSE_isError().
|
||||||
|
|
||||||
|
`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
|
||||||
|
`cSrcSize` must be strictly correct, otherwise decompression will fail.
|
||||||
|
FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
|
||||||
|
If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Dependency *** */
|
||||||
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* Static allocation
|
||||||
|
*******************************************/
|
||||||
|
/* FSE buffer bounds */
|
||||||
|
#define FSE_NCOUNTBOUND 512
|
||||||
|
#define FSE_BLOCKBOUND(size) (size + (size>>7))
|
||||||
|
#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
|
||||||
|
|
||||||
|
/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
|
||||||
|
#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
|
||||||
|
#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<maxTableLog))
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE advanced API
|
||||||
|
*******************************************/
|
||||||
|
/* FSE_count_wksp() :
|
||||||
|
* Same as FSE_count(), but using an externally provided scratch buffer.
|
||||||
|
* `workSpace` size must be table of >= `1024` unsigned
|
||||||
|
*/
|
||||||
|
size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
|
const void* source, size_t sourceSize, unsigned* workSpace);
|
||||||
|
|
||||||
|
/* FSE_countFast_wksp() :
|
||||||
|
* Same as FSE_countFast(), but using an externally provided scratch buffer.
|
||||||
|
* `workSpace` must be a table of minimum `1024` unsigned
|
||||||
|
*/
|
||||||
|
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* workSpace);
|
||||||
|
|
||||||
|
/*! FSE_count_simple
|
||||||
|
* Same as FSE_countFast(), but does not use any additional memory (not even on stack).
|
||||||
|
* This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
|
||||||
|
*/
|
||||||
|
size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
|
||||||
|
/**< same as FSE_optimalTableLog(), which used `minus==2` */
|
||||||
|
|
||||||
|
/* FSE_compress_wksp() :
|
||||||
|
* Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
|
||||||
|
* FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
|
||||||
|
*/
|
||||||
|
#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
|
||||||
|
size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
|
size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
|
||||||
|
/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
|
||||||
|
|
||||||
|
size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
|
||||||
|
/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
|
||||||
|
|
||||||
|
/* FSE_buildCTable_wksp() :
|
||||||
|
* Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
|
||||||
|
* `wkspSize` must be >= `(1<<tableLog)`.
|
||||||
|
*/
|
||||||
|
size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
|
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
|
||||||
|
/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
|
||||||
|
|
||||||
|
size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
|
||||||
|
/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
|
||||||
|
|
||||||
|
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog);
|
||||||
|
/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE symbol compression API
|
||||||
|
*******************************************/
|
||||||
|
/*!
|
||||||
|
This API consists of small unitary functions, which highly benefit from being inlined.
|
||||||
|
Hence their body are included in next section.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ptrdiff_t value;
|
||||||
|
const void* stateTable;
|
||||||
|
const void* symbolTT;
|
||||||
|
unsigned stateLog;
|
||||||
|
} FSE_CState_t;
|
||||||
|
|
||||||
|
static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
|
||||||
|
|
||||||
|
static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
|
||||||
|
|
||||||
|
static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
|
||||||
|
|
||||||
|
/**<
|
||||||
|
These functions are inner components of FSE_compress_usingCTable().
|
||||||
|
They allow the creation of custom streams, mixing multiple tables and bit sources.
|
||||||
|
|
||||||
|
A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
|
||||||
|
So the first symbol you will encode is the last you will decode, like a LIFO stack.
|
||||||
|
|
||||||
|
You will need a few variables to track your CStream. They are :
|
||||||
|
|
||||||
|
FSE_CTable ct; // Provided by FSE_buildCTable()
|
||||||
|
BIT_CStream_t bitStream; // bitStream tracking structure
|
||||||
|
FSE_CState_t state; // State tracking structure (can have several)
|
||||||
|
|
||||||
|
|
||||||
|
The first thing to do is to init bitStream and state.
|
||||||
|
size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
|
||||||
|
FSE_initCState(&state, ct);
|
||||||
|
|
||||||
|
Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
|
||||||
|
You can then encode your input data, byte after byte.
|
||||||
|
FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
|
||||||
|
Remember decoding will be done in reverse direction.
|
||||||
|
FSE_encodeByte(&bitStream, &state, symbol);
|
||||||
|
|
||||||
|
At any time, you can also add any bit sequence.
|
||||||
|
Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
|
||||||
|
BIT_addBits(&bitStream, bitField, nbBits);
|
||||||
|
|
||||||
|
The above methods don't commit data to memory, they just store it into local register, for speed.
|
||||||
|
Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
|
||||||
|
Writing data to memory is a manual operation, performed by the flushBits function.
|
||||||
|
BIT_flushBits(&bitStream);
|
||||||
|
|
||||||
|
Your last FSE encoding operation shall be to flush your last state value(s).
|
||||||
|
FSE_flushState(&bitStream, &state);
|
||||||
|
|
||||||
|
Finally, you must close the bitStream.
|
||||||
|
The function returns the size of CStream in bytes.
|
||||||
|
If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
|
||||||
|
If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
|
||||||
|
size_t size = BIT_closeCStream(&bitStream);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE symbol decompression API
|
||||||
|
*******************************************/
|
||||||
|
typedef struct {
|
||||||
|
size_t state;
|
||||||
|
const void* table; /* precise table may vary, depending on U16 */
|
||||||
|
} FSE_DState_t;
|
||||||
|
|
||||||
|
|
||||||
|
static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
|
||||||
|
|
||||||
|
static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
|
||||||
|
|
||||||
|
static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
|
||||||
|
|
||||||
|
/**<
|
||||||
|
Let's now decompose FSE_decompress_usingDTable() into its unitary components.
|
||||||
|
You will decode FSE-encoded symbols from the bitStream,
|
||||||
|
and also any other bitFields you put in, **in reverse order**.
|
||||||
|
|
||||||
|
You will need a few variables to track your bitStream. They are :
|
||||||
|
|
||||||
|
BIT_DStream_t DStream; // Stream context
|
||||||
|
FSE_DState_t DState; // State context. Multiple ones are possible
|
||||||
|
FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
|
||||||
|
|
||||||
|
The first thing to do is to init the bitStream.
|
||||||
|
errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
|
||||||
|
|
||||||
|
You should then retrieve your initial state(s)
|
||||||
|
(in reverse flushing order if you have several ones) :
|
||||||
|
errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
|
||||||
|
|
||||||
|
You can then decode your data, symbol after symbol.
|
||||||
|
For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
|
||||||
|
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
|
||||||
|
unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
|
||||||
|
|
||||||
|
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
|
||||||
|
Note : maximum allowed nbBits is 25, for 32-bits compatibility
|
||||||
|
size_t bitField = BIT_readBits(&DStream, nbBits);
|
||||||
|
|
||||||
|
All above operations only read from local register (which size depends on size_t).
|
||||||
|
Refueling the register from memory is manually performed by the reload method.
|
||||||
|
endSignal = FSE_reloadDStream(&DStream);
|
||||||
|
|
||||||
|
BIT_reloadDStream() result tells if there is still some more data to read from DStream.
|
||||||
|
BIT_DStream_unfinished : there is still some data left into the DStream.
|
||||||
|
BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
|
||||||
|
BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
|
||||||
|
BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
|
||||||
|
|
||||||
|
When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
|
||||||
|
to properly detect the exact end of stream.
|
||||||
|
After each decoded symbol, check if DStream is fully consumed using this simple test :
|
||||||
|
BIT_reloadDStream(&DStream) >= BIT_DStream_completed
|
||||||
|
|
||||||
|
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
|
||||||
|
Checking if DStream has reached its end is performed by :
|
||||||
|
BIT_endOfDStream(&DStream);
|
||||||
|
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
|
||||||
|
FSE_endOfDState(&DState);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE unsafe API
|
||||||
|
*******************************************/
|
||||||
|
static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
|
||||||
|
/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* Implementation of inlined functions
|
||||||
|
*******************************************/
|
||||||
|
typedef struct {
|
||||||
|
int deltaFindState;
|
||||||
|
U32 deltaNbBits;
|
||||||
|
} FSE_symbolCompressionTransform; /* total 8 bytes */
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
|
||||||
|
{
|
||||||
|
const void* ptr = ct;
|
||||||
|
const U16* u16ptr = (const U16*) ptr;
|
||||||
|
const U32 tableLog = MEM_read16(ptr);
|
||||||
|
statePtr->value = (ptrdiff_t)1<<tableLog;
|
||||||
|
statePtr->stateTable = u16ptr+2;
|
||||||
|
statePtr->symbolTT = ((const U32*)ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1));
|
||||||
|
statePtr->stateLog = tableLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! FSE_initCState2() :
|
||||||
|
* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
|
||||||
|
* uses the smallest state value possible, saving the cost of this symbol */
|
||||||
|
MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
|
||||||
|
{
|
||||||
|
FSE_initCState(statePtr, ct);
|
||||||
|
{ const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
|
||||||
|
const U16* stateTable = (const U16*)(statePtr->stateTable);
|
||||||
|
U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
|
||||||
|
statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
|
||||||
|
statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, U32 symbol)
|
||||||
|
{
|
||||||
|
const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
|
||||||
|
const U16* const stateTable = (const U16*)(statePtr->stateTable);
|
||||||
|
U32 nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
|
||||||
|
BIT_addBits(bitC, 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_flushBits(bitC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ====== Decompression ====== */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U16 tableLog;
|
||||||
|
U16 fastMode;
|
||||||
|
} FSE_DTableHeader; /* sizeof U32 */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned short newState;
|
||||||
|
unsigned char symbol;
|
||||||
|
unsigned char nbBits;
|
||||||
|
} FSE_decode_t; /* size == U32 */
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
|
||||||
|
{
|
||||||
|
const void* ptr = dt;
|
||||||
|
const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
|
||||||
|
DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
|
||||||
|
BIT_reloadDStream(bitD);
|
||||||
|
DStatePtr->table = dt + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
return DInfo.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
U32 const nbBits = DInfo.nbBits;
|
||||||
|
size_t const lowBits = BIT_readBits(bitD, nbBits);
|
||||||
|
DStatePtr->state = DInfo.newState + lowBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
U32 const nbBits = DInfo.nbBits;
|
||||||
|
BYTE const symbol = DInfo.symbol;
|
||||||
|
size_t const lowBits = BIT_readBits(bitD, nbBits);
|
||||||
|
|
||||||
|
DStatePtr->state = DInfo.newState + lowBits;
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! FSE_decodeSymbolFast() :
|
||||||
|
unsafe, only works if no symbol has a probability > 50% */
|
||||||
|
MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
U32 const nbBits = DInfo.nbBits;
|
||||||
|
BYTE const symbol = DInfo.symbol;
|
||||||
|
size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
|
||||||
|
|
||||||
|
DStatePtr->state = DInfo.newState + lowBits;
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
|
||||||
|
{
|
||||||
|
return DStatePtr->state == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FSE_COMMONDEFS_ONLY
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Tuning parameters
|
||||||
|
****************************************************************/
|
||||||
|
/*!MEMORY_USAGE :
|
||||||
|
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
|
||||||
|
* Increasing memory usage improves compression ratio
|
||||||
|
* Reduced memory usage can improve speed, due to cache effect
|
||||||
|
* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
|
||||||
|
#ifndef FSE_MAX_MEMORY_USAGE
|
||||||
|
# define FSE_MAX_MEMORY_USAGE 14
|
||||||
|
#endif
|
||||||
|
#ifndef FSE_DEFAULT_MEMORY_USAGE
|
||||||
|
# define FSE_DEFAULT_MEMORY_USAGE 13
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!FSE_MAX_SYMBOL_VALUE :
|
||||||
|
* Maximum symbol value authorized.
|
||||||
|
* Required for proper stack allocation */
|
||||||
|
#ifndef FSE_MAX_SYMBOL_VALUE
|
||||||
|
# define FSE_MAX_SYMBOL_VALUE 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* template functions type & suffix
|
||||||
|
****************************************************************/
|
||||||
|
#define FSE_FUNCTION_TYPE BYTE
|
||||||
|
#define FSE_FUNCTION_EXTENSION
|
||||||
|
#define FSE_DECODE_TYPE FSE_decode_t
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !FSE_COMMONDEFS_ONLY */
|
||||||
|
|
||||||
|
|
||||||
|
/* ***************************************************************
|
||||||
|
* Constants
|
||||||
|
*****************************************************************/
|
||||||
|
#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
|
||||||
|
#define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
|
||||||
|
#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
|
||||||
|
#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
|
||||||
|
#define FSE_MIN_TABLELOG 5
|
||||||
|
|
||||||
|
#define FSE_TABLELOG_ABSOLUTE_MAX 15
|
||||||
|
#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
|
||||||
|
# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSE_H */
|
788
contrib/linux-kernel/lib/zstd/fse_compress.c
Normal file
788
contrib/linux-kernel/lib/zstd/fse_compress.c
Normal file
@ -0,0 +1,788 @@
|
|||||||
|
/* ******************************************************************
|
||||||
|
FSE : Finite State Entropy encoder
|
||||||
|
Copyright (C) 2013-2015, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Compiler specifics
|
||||||
|
****************************************************************/
|
||||||
|
#define FORCE_INLINE static __always_inline
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Includes
|
||||||
|
****************************************************************/
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/string.h> /* memcpy, memset */
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "fse.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Error Management
|
||||||
|
****************************************************************/
|
||||||
|
#define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Templates
|
||||||
|
****************************************************************/
|
||||||
|
/*
|
||||||
|
designed to be included
|
||||||
|
for type-specific functions (template emulation in C)
|
||||||
|
Objective is to write these functions only once, for improved maintenance
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* safety checks */
|
||||||
|
#ifndef FSE_FUNCTION_EXTENSION
|
||||||
|
# error "FSE_FUNCTION_EXTENSION must be defined"
|
||||||
|
#endif
|
||||||
|
#ifndef FSE_FUNCTION_TYPE
|
||||||
|
# error "FSE_FUNCTION_TYPE must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function names */
|
||||||
|
#define FSE_CAT(X,Y) X##Y
|
||||||
|
#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
|
#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
|
|
||||||
|
|
||||||
|
/* Function templates */
|
||||||
|
|
||||||
|
/* FSE_buildCTable_wksp() :
|
||||||
|
* Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
|
||||||
|
* wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
|
||||||
|
* workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
|
||||||
|
*/
|
||||||
|
size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
U32 const tableSize = 1 << tableLog;
|
||||||
|
U32 const tableMask = tableSize - 1;
|
||||||
|
void* const ptr = ct;
|
||||||
|
U16* const tableU16 = ( (U16*) ptr) + 2;
|
||||||
|
void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
|
||||||
|
FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
|
||||||
|
U32 const step = FSE_TABLESTEP(tableSize);
|
||||||
|
U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
|
||||||
|
|
||||||
|
FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
|
||||||
|
U32 highThreshold = tableSize-1;
|
||||||
|
|
||||||
|
/* CTable header */
|
||||||
|
if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
|
||||||
|
tableU16[-2] = (U16) tableLog;
|
||||||
|
tableU16[-1] = (U16) maxSymbolValue;
|
||||||
|
|
||||||
|
/* For explanations on how to distribute symbol values over the table :
|
||||||
|
* http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
|
||||||
|
|
||||||
|
/* symbol start positions */
|
||||||
|
{ U32 u;
|
||||||
|
cumul[0] = 0;
|
||||||
|
for (u=1; u<=maxSymbolValue+1; u++) {
|
||||||
|
if (normalizedCounter[u-1]==-1) { /* Low proba symbol */
|
||||||
|
cumul[u] = cumul[u-1] + 1;
|
||||||
|
tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
|
||||||
|
} else {
|
||||||
|
cumul[u] = cumul[u-1] + normalizedCounter[u-1];
|
||||||
|
} }
|
||||||
|
cumul[maxSymbolValue+1] = tableSize+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spread symbols */
|
||||||
|
{ U32 position = 0;
|
||||||
|
U32 symbol;
|
||||||
|
for (symbol=0; symbol<=maxSymbolValue; symbol++) {
|
||||||
|
int nbOccurences;
|
||||||
|
for (nbOccurences=0; nbOccurences<normalizedCounter[symbol]; nbOccurences++) {
|
||||||
|
tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
|
||||||
|
position = (position + step) & tableMask;
|
||||||
|
while (position > highThreshold) position = (position + step) & tableMask; /* Low proba area */
|
||||||
|
} }
|
||||||
|
|
||||||
|
if (position!=0) return ERROR(GENERIC); /* Must have gone through all positions */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build table */
|
||||||
|
{ U32 u; for (u=0; u<tableSize; u++) {
|
||||||
|
FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */
|
||||||
|
tableU16[cumul[s]++] = (U16) (tableSize+u); /* TableU16 : sorted by symbol order; gives next state value */
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* Build Symbol Transformation Table */
|
||||||
|
{ unsigned total = 0;
|
||||||
|
unsigned s;
|
||||||
|
for (s=0; s<=maxSymbolValue; s++) {
|
||||||
|
switch (normalizedCounter[s])
|
||||||
|
{
|
||||||
|
case 0: break;
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
case 1:
|
||||||
|
symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);
|
||||||
|
symbolTT[s].deltaFindState = total - 1;
|
||||||
|
total ++;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
{
|
||||||
|
U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);
|
||||||
|
U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
|
||||||
|
symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
|
||||||
|
symbolTT[s].deltaFindState = total - normalizedCounter[s];
|
||||||
|
total += normalizedCounter[s];
|
||||||
|
} } } }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FSE_COMMONDEFS_ONLY
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* FSE NCount encoding-decoding
|
||||||
|
****************************************************************/
|
||||||
|
size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
|
||||||
|
{
|
||||||
|
size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
|
||||||
|
return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||||
|
const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
|
||||||
|
unsigned writeIsSafe)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE*) header;
|
||||||
|
BYTE* out = ostart;
|
||||||
|
BYTE* const oend = ostart + headerBufferSize;
|
||||||
|
int nbBits;
|
||||||
|
const int tableSize = 1 << tableLog;
|
||||||
|
int remaining;
|
||||||
|
int threshold;
|
||||||
|
U32 bitStream;
|
||||||
|
int bitCount;
|
||||||
|
unsigned charnum = 0;
|
||||||
|
int previous0 = 0;
|
||||||
|
|
||||||
|
bitStream = 0;
|
||||||
|
bitCount = 0;
|
||||||
|
/* Table Size */
|
||||||
|
bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
|
||||||
|
bitCount += 4;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
remaining = tableSize+1; /* +1 for extra accuracy */
|
||||||
|
threshold = tableSize;
|
||||||
|
nbBits = tableLog+1;
|
||||||
|
|
||||||
|
while (remaining>1) { /* stops at 1 */
|
||||||
|
if (previous0) {
|
||||||
|
unsigned start = charnum;
|
||||||
|
while (!normalizedCounter[charnum]) charnum++;
|
||||||
|
while (charnum >= start+24) {
|
||||||
|
start+=24;
|
||||||
|
bitStream += 0xFFFFU << bitCount;
|
||||||
|
if ((!writeIsSafe) && (out > oend-2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
|
||||||
|
out[0] = (BYTE) bitStream;
|
||||||
|
out[1] = (BYTE)(bitStream>>8);
|
||||||
|
out+=2;
|
||||||
|
bitStream>>=16;
|
||||||
|
}
|
||||||
|
while (charnum >= start+3) {
|
||||||
|
start+=3;
|
||||||
|
bitStream += 3 << bitCount;
|
||||||
|
bitCount += 2;
|
||||||
|
}
|
||||||
|
bitStream += (charnum-start) << bitCount;
|
||||||
|
bitCount += 2;
|
||||||
|
if (bitCount>16) {
|
||||||
|
if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
|
||||||
|
out[0] = (BYTE)bitStream;
|
||||||
|
out[1] = (BYTE)(bitStream>>8);
|
||||||
|
out += 2;
|
||||||
|
bitStream >>= 16;
|
||||||
|
bitCount -= 16;
|
||||||
|
} }
|
||||||
|
{ int count = normalizedCounter[charnum++];
|
||||||
|
int const max = (2*threshold-1)-remaining;
|
||||||
|
remaining -= count < 0 ? -count : count;
|
||||||
|
count++; /* +1 for extra accuracy */
|
||||||
|
if (count>=threshold) count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
|
||||||
|
bitStream += count << bitCount;
|
||||||
|
bitCount += nbBits;
|
||||||
|
bitCount -= (count<max);
|
||||||
|
previous0 = (count==1);
|
||||||
|
if (remaining<1) return ERROR(GENERIC);
|
||||||
|
while (remaining<threshold) nbBits--, threshold>>=1;
|
||||||
|
}
|
||||||
|
if (bitCount>16) {
|
||||||
|
if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
|
||||||
|
out[0] = (BYTE)bitStream;
|
||||||
|
out[1] = (BYTE)(bitStream>>8);
|
||||||
|
out += 2;
|
||||||
|
bitStream >>= 16;
|
||||||
|
bitCount -= 16;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* flush remaining bitStream */
|
||||||
|
if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
|
||||||
|
out[0] = (BYTE)bitStream;
|
||||||
|
out[1] = (BYTE)(bitStream>>8);
|
||||||
|
out+= (bitCount+7) /8;
|
||||||
|
|
||||||
|
if (charnum > maxSymbolValue + 1) return ERROR(GENERIC);
|
||||||
|
|
||||||
|
return (out-ostart);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
|
||||||
|
{
|
||||||
|
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported */
|
||||||
|
if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */
|
||||||
|
|
||||||
|
if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
|
||||||
|
return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
|
||||||
|
|
||||||
|
return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Counting histogram
|
||||||
|
****************************************************************/
|
||||||
|
/*! FSE_count_simple
|
||||||
|
This function counts byte values within `src`, and store the histogram into table `count`.
|
||||||
|
It doesn't use any additional memory.
|
||||||
|
But this function is unsafe : it doesn't check that all values within `src` can fit into `count`.
|
||||||
|
For this reason, prefer using a table `count` with 256 elements.
|
||||||
|
@return : count of most numerous element
|
||||||
|
*/
|
||||||
|
size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
|
const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*)src;
|
||||||
|
const BYTE* const end = ip + srcSize;
|
||||||
|
unsigned maxSymbolValue = *maxSymbolValuePtr;
|
||||||
|
unsigned max=0;
|
||||||
|
|
||||||
|
memset(count, 0, (maxSymbolValue+1)*sizeof(*count));
|
||||||
|
if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
|
||||||
|
|
||||||
|
while (ip<end) count[*ip++]++;
|
||||||
|
|
||||||
|
while (!count[maxSymbolValue]) maxSymbolValue--;
|
||||||
|
*maxSymbolValuePtr = maxSymbolValue;
|
||||||
|
|
||||||
|
{ U32 s; for (s=0; s<=maxSymbolValue; s++) if (count[s] > max) max = count[s]; }
|
||||||
|
|
||||||
|
return (size_t)max;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* FSE_count_parallel_wksp() :
|
||||||
|
* Same as FSE_count_parallel(), but using an externally provided scratch buffer.
|
||||||
|
* `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`` */
|
||||||
|
static size_t FSE_count_parallel_wksp(
|
||||||
|
unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
|
const void* source, size_t sourceSize,
|
||||||
|
unsigned checkMax, unsigned* const workSpace)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*)source;
|
||||||
|
const BYTE* const iend = ip+sourceSize;
|
||||||
|
unsigned maxSymbolValue = *maxSymbolValuePtr;
|
||||||
|
unsigned max=0;
|
||||||
|
U32* const Counting1 = workSpace;
|
||||||
|
U32* const Counting2 = Counting1 + 256;
|
||||||
|
U32* const Counting3 = Counting2 + 256;
|
||||||
|
U32* const Counting4 = Counting3 + 256;
|
||||||
|
|
||||||
|
memset(Counting1, 0, 4*256*sizeof(unsigned));
|
||||||
|
|
||||||
|
/* safety checks */
|
||||||
|
if (!sourceSize) {
|
||||||
|
memset(count, 0, maxSymbolValue + 1);
|
||||||
|
*maxSymbolValuePtr = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
|
||||||
|
|
||||||
|
/* by stripes of 16 bytes */
|
||||||
|
{ U32 cached = MEM_read32(ip); ip += 4;
|
||||||
|
while (ip < iend-15) {
|
||||||
|
U32 c = cached; cached = MEM_read32(ip); ip += 4;
|
||||||
|
Counting1[(BYTE) c ]++;
|
||||||
|
Counting2[(BYTE)(c>>8) ]++;
|
||||||
|
Counting3[(BYTE)(c>>16)]++;
|
||||||
|
Counting4[ c>>24 ]++;
|
||||||
|
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||||
|
Counting1[(BYTE) c ]++;
|
||||||
|
Counting2[(BYTE)(c>>8) ]++;
|
||||||
|
Counting3[(BYTE)(c>>16)]++;
|
||||||
|
Counting4[ c>>24 ]++;
|
||||||
|
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||||
|
Counting1[(BYTE) c ]++;
|
||||||
|
Counting2[(BYTE)(c>>8) ]++;
|
||||||
|
Counting3[(BYTE)(c>>16)]++;
|
||||||
|
Counting4[ c>>24 ]++;
|
||||||
|
c = cached; cached = MEM_read32(ip); ip += 4;
|
||||||
|
Counting1[(BYTE) c ]++;
|
||||||
|
Counting2[(BYTE)(c>>8) ]++;
|
||||||
|
Counting3[(BYTE)(c>>16)]++;
|
||||||
|
Counting4[ c>>24 ]++;
|
||||||
|
}
|
||||||
|
ip-=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finish last symbols */
|
||||||
|
while (ip<iend) Counting1[*ip++]++;
|
||||||
|
|
||||||
|
if (checkMax) { /* verify stats will fit into destination table */
|
||||||
|
U32 s; for (s=255; s>maxSymbolValue; s--) {
|
||||||
|
Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
|
||||||
|
if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
|
||||||
|
} }
|
||||||
|
|
||||||
|
{ U32 s; for (s=0; s<=maxSymbolValue; s++) {
|
||||||
|
count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
|
||||||
|
if (count[s] > max) max = count[s];
|
||||||
|
} }
|
||||||
|
|
||||||
|
while (!count[maxSymbolValue]) maxSymbolValue--;
|
||||||
|
*maxSymbolValuePtr = maxSymbolValue;
|
||||||
|
return (size_t)max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FSE_countFast_wksp() :
|
||||||
|
* Same as FSE_countFast(), but using an externally provided scratch buffer.
|
||||||
|
* `workSpace` size must be table of >= `1024` unsigned */
|
||||||
|
size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
|
const void* source, size_t sourceSize, unsigned* workSpace)
|
||||||
|
{
|
||||||
|
if (sourceSize < 1500) return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
|
||||||
|
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FSE_count_wksp() :
|
||||||
|
* Same as FSE_count(), but using an externally provided scratch buffer.
|
||||||
|
* `workSpace` size must be table of >= `1024` unsigned */
|
||||||
|
size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
|
const void* source, size_t sourceSize, unsigned* workSpace)
|
||||||
|
{
|
||||||
|
if (*maxSymbolValuePtr < 255)
|
||||||
|
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace);
|
||||||
|
*maxSymbolValuePtr = 255;
|
||||||
|
return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* FSE Compression Code
|
||||||
|
****************************************************************/
|
||||||
|
/*! FSE_sizeof_CTable() :
|
||||||
|
FSE_CTable is a variable size structure which contains :
|
||||||
|
`U16 tableLog;`
|
||||||
|
`U16 maxSymbolValue;`
|
||||||
|
`U16 nextStateNumber[1 << tableLog];` // This size is variable
|
||||||
|
`FSE_symbolCompressionTransform symbolTT[maxSymbolValue+1];` // This size is variable
|
||||||
|
Allocation is manual (C standard does not support variable-size structures).
|
||||||
|
*/
|
||||||
|
size_t FSE_sizeof_CTable (unsigned maxSymbolValue, unsigned tableLog)
|
||||||
|
{
|
||||||
|
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
|
||||||
|
return FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* provides the minimum logSize to safely represent a distribution */
|
||||||
|
static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
|
||||||
|
{
|
||||||
|
U32 minBitsSrc = BIT_highbit32((U32)(srcSize - 1)) + 1;
|
||||||
|
U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
|
||||||
|
U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
|
||||||
|
return minBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
|
||||||
|
{
|
||||||
|
U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
|
||||||
|
U32 tableLog = maxTableLog;
|
||||||
|
U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
|
||||||
|
if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
|
||||||
|
if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */
|
||||||
|
if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */
|
||||||
|
if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
|
||||||
|
if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
|
||||||
|
return tableLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
|
||||||
|
{
|
||||||
|
return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Secondary normalization method.
|
||||||
|
To be used when primary method fails. */
|
||||||
|
|
||||||
|
static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
|
||||||
|
{
|
||||||
|
short const NOT_YET_ASSIGNED = -2;
|
||||||
|
U32 s;
|
||||||
|
U32 distributed = 0;
|
||||||
|
U32 ToDistribute;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
U32 const lowThreshold = (U32)(total >> tableLog);
|
||||||
|
U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
|
||||||
|
|
||||||
|
for (s=0; s<=maxSymbolValue; s++) {
|
||||||
|
if (count[s] == 0) {
|
||||||
|
norm[s]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (count[s] <= lowThreshold) {
|
||||||
|
norm[s] = -1;
|
||||||
|
distributed++;
|
||||||
|
total -= count[s];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (count[s] <= lowOne) {
|
||||||
|
norm[s] = 1;
|
||||||
|
distributed++;
|
||||||
|
total -= count[s];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
norm[s]=NOT_YET_ASSIGNED;
|
||||||
|
}
|
||||||
|
ToDistribute = (1 << tableLog) - distributed;
|
||||||
|
|
||||||
|
if ((total / ToDistribute) > lowOne) {
|
||||||
|
/* risk of rounding to zero */
|
||||||
|
lowOne = (U32)((total * 3) / (ToDistribute * 2));
|
||||||
|
for (s=0; s<=maxSymbolValue; s++) {
|
||||||
|
if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
|
||||||
|
norm[s] = 1;
|
||||||
|
distributed++;
|
||||||
|
total -= count[s];
|
||||||
|
continue;
|
||||||
|
} }
|
||||||
|
ToDistribute = (1 << tableLog) - distributed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distributed == maxSymbolValue+1) {
|
||||||
|
/* all values are pretty poor;
|
||||||
|
probably incompressible data (should have already been detected);
|
||||||
|
find max, then give all remaining points to max */
|
||||||
|
U32 maxV = 0, maxC = 0;
|
||||||
|
for (s=0; s<=maxSymbolValue; s++)
|
||||||
|
if (count[s] > maxC) maxV=s, maxC=count[s];
|
||||||
|
norm[maxV] += (short)ToDistribute;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total == 0) {
|
||||||
|
/* all of the symbols were low enough for the lowOne or lowThreshold */
|
||||||
|
for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
|
||||||
|
if (norm[s] > 0) ToDistribute--, norm[s]++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ U64 const vStepLog = 62 - tableLog;
|
||||||
|
U64 const mid = (1ULL << (vStepLog-1)) - 1;
|
||||||
|
U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total; /* scale on remaining */
|
||||||
|
U64 tmpTotal = mid;
|
||||||
|
for (s=0; s<=maxSymbolValue; s++) {
|
||||||
|
if (norm[s]==NOT_YET_ASSIGNED) {
|
||||||
|
U64 const end = tmpTotal + (count[s] * rStep);
|
||||||
|
U32 const sStart = (U32)(tmpTotal >> vStepLog);
|
||||||
|
U32 const sEnd = (U32)(end >> vStepLog);
|
||||||
|
U32 const weight = sEnd - sStart;
|
||||||
|
if (weight < 1)
|
||||||
|
return ERROR(GENERIC);
|
||||||
|
norm[s] = (short)weight;
|
||||||
|
tmpTotal = end;
|
||||||
|
} } }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
|
||||||
|
const unsigned* count, size_t total,
|
||||||
|
unsigned maxSymbolValue)
|
||||||
|
{
|
||||||
|
/* Sanity checks */
|
||||||
|
if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
|
||||||
|
if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */
|
||||||
|
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */
|
||||||
|
if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
|
||||||
|
|
||||||
|
{ U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
|
||||||
|
U64 const scale = 62 - tableLog;
|
||||||
|
U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */
|
||||||
|
U64 const vStep = 1ULL<<(scale-20);
|
||||||
|
int stillToDistribute = 1<<tableLog;
|
||||||
|
unsigned s;
|
||||||
|
unsigned largest=0;
|
||||||
|
short largestP=0;
|
||||||
|
U32 lowThreshold = (U32)(total >> tableLog);
|
||||||
|
|
||||||
|
for (s=0; s<=maxSymbolValue; s++) {
|
||||||
|
if (count[s] == total) return 0; /* rle special case */
|
||||||
|
if (count[s] == 0) { normalizedCounter[s]=0; continue; }
|
||||||
|
if (count[s] <= lowThreshold) {
|
||||||
|
normalizedCounter[s] = -1;
|
||||||
|
stillToDistribute--;
|
||||||
|
} else {
|
||||||
|
short proba = (short)((count[s]*step) >> scale);
|
||||||
|
if (proba<8) {
|
||||||
|
U64 restToBeat = vStep * rtbTable[proba];
|
||||||
|
proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
|
||||||
|
}
|
||||||
|
if (proba > largestP) largestP=proba, largest=s;
|
||||||
|
normalizedCounter[s] = proba;
|
||||||
|
stillToDistribute -= proba;
|
||||||
|
} }
|
||||||
|
if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
|
||||||
|
/* corner case, need another normalization method */
|
||||||
|
size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
|
||||||
|
if (FSE_isError(errorCode)) return errorCode;
|
||||||
|
}
|
||||||
|
else normalizedCounter[largest] += (short)stillToDistribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{ /* Print Table (debug) */
|
||||||
|
U32 s;
|
||||||
|
U32 nTotal = 0;
|
||||||
|
for (s=0; s<=maxSymbolValue; s++)
|
||||||
|
printf("%3i: %4i \n", s, normalizedCounter[s]);
|
||||||
|
for (s=0; s<=maxSymbolValue; s++)
|
||||||
|
nTotal += abs(normalizedCounter[s]);
|
||||||
|
if (nTotal != (1U<<tableLog))
|
||||||
|
printf("Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
|
||||||
|
getchar();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return tableLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* fake FSE_CTable, for raw (uncompressed) input */
|
||||||
|
size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)
|
||||||
|
{
|
||||||
|
const unsigned tableSize = 1 << nbBits;
|
||||||
|
const unsigned tableMask = tableSize - 1;
|
||||||
|
const unsigned maxSymbolValue = tableMask;
|
||||||
|
void* const ptr = ct;
|
||||||
|
U16* const tableU16 = ( (U16*) ptr) + 2;
|
||||||
|
void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */
|
||||||
|
FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
|
||||||
|
unsigned s;
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
if (nbBits < 1) return ERROR(GENERIC); /* min size */
|
||||||
|
|
||||||
|
/* header */
|
||||||
|
tableU16[-2] = (U16) nbBits;
|
||||||
|
tableU16[-1] = (U16) maxSymbolValue;
|
||||||
|
|
||||||
|
/* Build table */
|
||||||
|
for (s=0; s<tableSize; s++)
|
||||||
|
tableU16[s] = (U16)(tableSize + s);
|
||||||
|
|
||||||
|
/* Build Symbol Transformation Table */
|
||||||
|
{ const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
|
||||||
|
for (s=0; s<=maxSymbolValue; s++) {
|
||||||
|
symbolTT[s].deltaNbBits = deltaNbBits;
|
||||||
|
symbolTT[s].deltaFindState = s-1;
|
||||||
|
} }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fake FSE_CTable, for rle input (always same symbol) */
|
||||||
|
size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
|
||||||
|
{
|
||||||
|
void* ptr = ct;
|
||||||
|
U16* tableU16 = ( (U16*) ptr) + 2;
|
||||||
|
void* FSCTptr = (U32*)ptr + 2;
|
||||||
|
FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;
|
||||||
|
|
||||||
|
/* header */
|
||||||
|
tableU16[-2] = (U16) 0;
|
||||||
|
tableU16[-1] = (U16) symbolValue;
|
||||||
|
|
||||||
|
/* Build table */
|
||||||
|
tableU16[0] = 0;
|
||||||
|
tableU16[1] = 0; /* just in case */
|
||||||
|
|
||||||
|
/* Build Symbol Transformation Table */
|
||||||
|
symbolTT[symbolValue].deltaNbBits = 0;
|
||||||
|
symbolTT[symbolValue].deltaFindState = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const FSE_CTable* ct, const unsigned fast)
|
||||||
|
{
|
||||||
|
const BYTE* const istart = (const BYTE*) src;
|
||||||
|
const BYTE* const iend = istart + srcSize;
|
||||||
|
const BYTE* ip=iend;
|
||||||
|
|
||||||
|
BIT_CStream_t bitC;
|
||||||
|
FSE_CState_t CState1, CState2;
|
||||||
|
|
||||||
|
/* init */
|
||||||
|
if (srcSize <= 2) return 0;
|
||||||
|
{ size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
|
||||||
|
if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }
|
||||||
|
|
||||||
|
#define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
|
||||||
|
|
||||||
|
if (srcSize & 1) {
|
||||||
|
FSE_initCState2(&CState1, ct, *--ip);
|
||||||
|
FSE_initCState2(&CState2, ct, *--ip);
|
||||||
|
FSE_encodeSymbol(&bitC, &CState1, *--ip);
|
||||||
|
FSE_FLUSHBITS(&bitC);
|
||||||
|
} else {
|
||||||
|
FSE_initCState2(&CState2, ct, *--ip);
|
||||||
|
FSE_initCState2(&CState1, ct, *--ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* join to mod 4 */
|
||||||
|
srcSize -= 2;
|
||||||
|
if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */
|
||||||
|
FSE_encodeSymbol(&bitC, &CState2, *--ip);
|
||||||
|
FSE_encodeSymbol(&bitC, &CState1, *--ip);
|
||||||
|
FSE_FLUSHBITS(&bitC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2 or 4 encoding per loop */
|
||||||
|
while ( ip>istart ) {
|
||||||
|
|
||||||
|
FSE_encodeSymbol(&bitC, &CState2, *--ip);
|
||||||
|
|
||||||
|
if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */
|
||||||
|
FSE_FLUSHBITS(&bitC);
|
||||||
|
|
||||||
|
FSE_encodeSymbol(&bitC, &CState1, *--ip);
|
||||||
|
|
||||||
|
if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */
|
||||||
|
FSE_encodeSymbol(&bitC, &CState2, *--ip);
|
||||||
|
FSE_encodeSymbol(&bitC, &CState1, *--ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
FSE_FLUSHBITS(&bitC);
|
||||||
|
}
|
||||||
|
|
||||||
|
FSE_flushCState(&bitC, &CState2);
|
||||||
|
FSE_flushCState(&bitC, &CState1);
|
||||||
|
return BIT_closeCStream(&bitC);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
const FSE_CTable* ct)
|
||||||
|
{
|
||||||
|
unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
|
||||||
|
|
||||||
|
if (fast)
|
||||||
|
return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
|
||||||
|
else
|
||||||
|
return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
|
||||||
|
|
||||||
|
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return f
|
||||||
|
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
|
||||||
|
|
||||||
|
/* FSE_compress_wksp() :
|
||||||
|
* Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
|
||||||
|
* `wkspSize` size must be `(1<<tableLog)`.
|
||||||
|
*/
|
||||||
|
size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
|
||||||
|
U32 count[FSE_MAX_SYMBOL_VALUE+1];
|
||||||
|
S16 norm[FSE_MAX_SYMBOL_VALUE+1];
|
||||||
|
FSE_CTable* CTable = (FSE_CTable*)workSpace;
|
||||||
|
size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);
|
||||||
|
void* scratchBuffer = (void*)(CTable + CTableSize);
|
||||||
|
size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
|
||||||
|
|
||||||
|
/* init conditions */
|
||||||
|
if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
|
||||||
|
if (srcSize <= 1) return 0; /* Not compressible */
|
||||||
|
if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
|
||||||
|
if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
|
||||||
|
|
||||||
|
/* Scan input and build symbol stats */
|
||||||
|
{ CHECK_V_F(maxCount, FSE_count_wksp(count, &maxSymbolValue, src, srcSize, (unsigned*)scratchBuffer) );
|
||||||
|
if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */
|
||||||
|
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
||||||
|
if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
|
||||||
|
}
|
||||||
|
|
||||||
|
tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
|
||||||
|
CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
|
||||||
|
|
||||||
|
/* Write table description header */
|
||||||
|
{ CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
|
||||||
|
op += nc_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compress */
|
||||||
|
CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
|
||||||
|
{ CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
|
||||||
|
if (cSize == 0) return 0; /* not enough space for compressed data */
|
||||||
|
op += cSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check compressibility */
|
||||||
|
if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
|
||||||
|
|
||||||
|
return op-ostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSE_COMMONDEFS_ONLY */
|
292
contrib/linux-kernel/lib/zstd/fse_decompress.c
Normal file
292
contrib/linux-kernel/lib/zstd/fse_decompress.c
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
/* ******************************************************************
|
||||||
|
FSE : Finite State Entropy decoder
|
||||||
|
Copyright (C) 2013-2015, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Compiler specifics
|
||||||
|
****************************************************************/
|
||||||
|
#define FORCE_INLINE static __always_inline
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Includes
|
||||||
|
****************************************************************/
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/string.h> /* memcpy, memset */
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "fse.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Error Management
|
||||||
|
****************************************************************/
|
||||||
|
#define FSE_isError ERR_isError
|
||||||
|
#define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||||
|
|
||||||
|
/* check and forward error code */
|
||||||
|
#define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; }
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Templates
|
||||||
|
****************************************************************/
|
||||||
|
/*
|
||||||
|
designed to be included
|
||||||
|
for type-specific functions (template emulation in C)
|
||||||
|
Objective is to write these functions only once, for improved maintenance
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* safety checks */
|
||||||
|
#ifndef FSE_FUNCTION_EXTENSION
|
||||||
|
# error "FSE_FUNCTION_EXTENSION must be defined"
|
||||||
|
#endif
|
||||||
|
#ifndef FSE_FUNCTION_TYPE
|
||||||
|
# error "FSE_FUNCTION_TYPE must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function names */
|
||||||
|
#define FSE_CAT(X,Y) X##Y
|
||||||
|
#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
|
#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
|
|
||||||
|
|
||||||
|
/* Function templates */
|
||||||
|
|
||||||
|
size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
|
||||||
|
{
|
||||||
|
void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
|
||||||
|
FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
|
||||||
|
U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
|
||||||
|
|
||||||
|
U32 const maxSV1 = maxSymbolValue + 1;
|
||||||
|
U32 const tableSize = 1 << tableLog;
|
||||||
|
U32 highThreshold = tableSize-1;
|
||||||
|
|
||||||
|
/* Sanity Checks */
|
||||||
|
if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
|
||||||
|
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
|
||||||
|
|
||||||
|
/* Init, lay down lowprob symbols */
|
||||||
|
{ FSE_DTableHeader DTableH;
|
||||||
|
DTableH.tableLog = (U16)tableLog;
|
||||||
|
DTableH.fastMode = 1;
|
||||||
|
{ S16 const largeLimit= (S16)(1 << (tableLog-1));
|
||||||
|
U32 s;
|
||||||
|
for (s=0; s<maxSV1; s++) {
|
||||||
|
if (normalizedCounter[s]==-1) {
|
||||||
|
tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
|
||||||
|
symbolNext[s] = 1;
|
||||||
|
} else {
|
||||||
|
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
||||||
|
symbolNext[s] = normalizedCounter[s];
|
||||||
|
} } }
|
||||||
|
memcpy(dt, &DTableH, sizeof(DTableH));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spread symbols */
|
||||||
|
{ U32 const tableMask = tableSize-1;
|
||||||
|
U32 const step = FSE_TABLESTEP(tableSize);
|
||||||
|
U32 s, position = 0;
|
||||||
|
for (s=0; s<maxSV1; s++) {
|
||||||
|
int i;
|
||||||
|
for (i=0; i<normalizedCounter[s]; i++) {
|
||||||
|
tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
|
||||||
|
position = (position + step) & tableMask;
|
||||||
|
while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
|
||||||
|
} }
|
||||||
|
if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build Decoding table */
|
||||||
|
{ U32 u;
|
||||||
|
for (u=0; u<tableSize; u++) {
|
||||||
|
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
|
||||||
|
U16 nextState = symbolNext[symbol]++;
|
||||||
|
tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32 ((U32)nextState) );
|
||||||
|
tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
|
||||||
|
} }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FSE_COMMONDEFS_ONLY
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Decompression (Byte symbols)
|
||||||
|
*********************************************************/
|
||||||
|
size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
|
||||||
|
{
|
||||||
|
void* ptr = dt;
|
||||||
|
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
|
||||||
|
void* dPtr = dt + 1;
|
||||||
|
FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
|
||||||
|
|
||||||
|
DTableH->tableLog = 0;
|
||||||
|
DTableH->fastMode = 0;
|
||||||
|
|
||||||
|
cell->newState = 0;
|
||||||
|
cell->symbol = symbolValue;
|
||||||
|
cell->nbBits = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
|
||||||
|
{
|
||||||
|
void* ptr = dt;
|
||||||
|
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
|
||||||
|
void* dPtr = dt + 1;
|
||||||
|
FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
|
||||||
|
const unsigned tableSize = 1 << nbBits;
|
||||||
|
const unsigned tableMask = tableSize - 1;
|
||||||
|
const unsigned maxSV1 = tableMask+1;
|
||||||
|
unsigned s;
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
if (nbBits < 1) return ERROR(GENERIC); /* min size */
|
||||||
|
|
||||||
|
/* Build Decoding Table */
|
||||||
|
DTableH->tableLog = (U16)nbBits;
|
||||||
|
DTableH->fastMode = 1;
|
||||||
|
for (s=0; s<maxSV1; s++) {
|
||||||
|
dinfo[s].newState = 0;
|
||||||
|
dinfo[s].symbol = (BYTE)s;
|
||||||
|
dinfo[s].nbBits = (BYTE)nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE size_t FSE_decompress_usingDTable_generic(
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const FSE_DTable* dt, const unsigned fast)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
BYTE* const omax = op + maxDstSize;
|
||||||
|
BYTE* const olimit = omax-3;
|
||||||
|
|
||||||
|
BIT_DStream_t bitD;
|
||||||
|
FSE_DState_t state1;
|
||||||
|
FSE_DState_t state2;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
|
||||||
|
|
||||||
|
FSE_initDState(&state1, &bitD, dt);
|
||||||
|
FSE_initDState(&state2, &bitD, dt);
|
||||||
|
|
||||||
|
#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
|
||||||
|
|
||||||
|
/* 4 symbols per loop */
|
||||||
|
for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
|
||||||
|
op[0] = FSE_GETSYMBOL(&state1);
|
||||||
|
|
||||||
|
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
|
||||||
|
BIT_reloadDStream(&bitD);
|
||||||
|
|
||||||
|
op[1] = FSE_GETSYMBOL(&state2);
|
||||||
|
|
||||||
|
if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
|
||||||
|
{ if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
|
||||||
|
|
||||||
|
op[2] = FSE_GETSYMBOL(&state1);
|
||||||
|
|
||||||
|
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
|
||||||
|
BIT_reloadDStream(&bitD);
|
||||||
|
|
||||||
|
op[3] = FSE_GETSYMBOL(&state2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tail */
|
||||||
|
/* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
|
||||||
|
while (1) {
|
||||||
|
if (op>(omax-2)) return ERROR(dstSize_tooSmall);
|
||||||
|
*op++ = FSE_GETSYMBOL(&state1);
|
||||||
|
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
|
||||||
|
*op++ = FSE_GETSYMBOL(&state2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op>(omax-2)) return ERROR(dstSize_tooSmall);
|
||||||
|
*op++ = FSE_GETSYMBOL(&state2);
|
||||||
|
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
|
||||||
|
*op++ = FSE_GETSYMBOL(&state1);
|
||||||
|
break;
|
||||||
|
} }
|
||||||
|
|
||||||
|
return op-ostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const FSE_DTable* dt)
|
||||||
|
{
|
||||||
|
const void* ptr = dt;
|
||||||
|
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, originalSize, cSrc, cSrcSize, dt, 1);
|
||||||
|
return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
|
||||||
|
{
|
||||||
|
const BYTE* const istart = (const BYTE*)cSrc;
|
||||||
|
const BYTE* ip = istart;
|
||||||
|
short counting[FSE_MAX_SYMBOL_VALUE+1];
|
||||||
|
unsigned tableLog;
|
||||||
|
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
|
||||||
|
|
||||||
|
/* normal FSE decoding mode */
|
||||||
|
size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
|
||||||
|
if (FSE_isError(NCountLength)) return NCountLength;
|
||||||
|
//if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
|
||||||
|
if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
|
||||||
|
ip += NCountLength;
|
||||||
|
cSrcSize -= NCountLength;
|
||||||
|
|
||||||
|
CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
|
||||||
|
|
||||||
|
return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSE_COMMONDEFS_ONLY */
|
203
contrib/linux-kernel/lib/zstd/huf.h
Normal file
203
contrib/linux-kernel/lib/zstd/huf.h
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/* ******************************************************************
|
||||||
|
Huffman coder, part of New Generation Entropy library
|
||||||
|
header file
|
||||||
|
Copyright (C) 2013-2016, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
****************************************************************** */
|
||||||
|
#ifndef HUF_H_298734234
|
||||||
|
#define HUF_H_298734234
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Dependencies *** */
|
||||||
|
#include <linux/types.h> /* size_t */
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Tool functions *** */
|
||||||
|
#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
|
||||||
|
size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
|
||||||
|
|
||||||
|
/* Error Management */
|
||||||
|
unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Advanced function *** */
|
||||||
|
|
||||||
|
/** HUF_compress4X_wksp() :
|
||||||
|
* Same as HUF_compress2(), but uses externally allocated `workSpace`, which must be a table of >= 1024 unsigned */
|
||||||
|
size_t HUF_compress4X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Dependencies *** */
|
||||||
|
#include "mem.h" /* U32 */
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Constants *** */
|
||||||
|
#define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
|
||||||
|
#define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
|
||||||
|
#define HUF_SYMBOLVALUE_MAX 255
|
||||||
|
|
||||||
|
#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
|
||||||
|
#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
|
||||||
|
# error "HUF_TABLELOG_MAX is too large !"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Static allocation
|
||||||
|
******************************************/
|
||||||
|
/* HUF buffer bounds */
|
||||||
|
#define HUF_CTABLEBOUND 129
|
||||||
|
#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true if incompressible pre-filtered with fast heuristic */
|
||||||
|
#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
|
||||||
|
|
||||||
|
/* static allocation of HUF's Compression Table */
|
||||||
|
#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
|
||||||
|
U32 name##hb[maxSymbolValue+1]; \
|
||||||
|
void* name##hv = &(name##hb); \
|
||||||
|
HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */
|
||||||
|
|
||||||
|
/* static allocation of HUF's DTable */
|
||||||
|
typedef U32 HUF_DTable;
|
||||||
|
#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
|
||||||
|
#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
|
||||||
|
HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
|
||||||
|
#define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) \
|
||||||
|
HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
|
||||||
|
|
||||||
|
/* The workspace must have alignment at least 4 and be at least this large */
|
||||||
|
#define HUF_WORKSPACE_SIZE (6 << 10)
|
||||||
|
#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Advanced decompression functions
|
||||||
|
******************************************/
|
||||||
|
size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
|
||||||
|
size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
|
||||||
|
size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||||
|
size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* HUF detailed API
|
||||||
|
******************************************/
|
||||||
|
/*!
|
||||||
|
HUF_compress() does the following:
|
||||||
|
1. count symbol occurrence from source[] into table count[] using FSE_count()
|
||||||
|
2. (optional) refine tableLog using HUF_optimalTableLog()
|
||||||
|
3. build Huffman table from count using HUF_buildCTable()
|
||||||
|
4. save Huffman table to memory buffer using HUF_writeCTable()
|
||||||
|
5. encode the data stream using HUF_compress4X_usingCTable()
|
||||||
|
|
||||||
|
The following API allows targeting specific sub-functions for advanced tasks.
|
||||||
|
For example, it's possible to compress several blocks using the same 'CTable',
|
||||||
|
or to save and regenerate 'CTable' using external methods.
|
||||||
|
*/
|
||||||
|
/* FSE_count() : find it within "fse.h" */
|
||||||
|
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
||||||
|
typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
|
||||||
|
size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
|
||||||
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HUF_repeat_none, /**< Cannot use the previous table */
|
||||||
|
HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
|
||||||
|
HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */
|
||||||
|
} HUF_repeat;
|
||||||
|
/** HUF_compress4X_repeat() :
|
||||||
|
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
||||||
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
|
* If preferRepeat then the old table will always be used if valid. */
|
||||||
|
size_t HUF_compress4X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
||||||
|
|
||||||
|
/** HUF_buildCTable_wksp() :
|
||||||
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
|
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
|
||||||
|
*/
|
||||||
|
size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
|
/*! HUF_readStats() :
|
||||||
|
Read compact Huffman tree, saved by HUF_writeCTable().
|
||||||
|
`huffWeight` is destination buffer.
|
||||||
|
@return : size read from `src` , or an error Code .
|
||||||
|
Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
|
||||||
|
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/** HUF_readCTable() :
|
||||||
|
* Loading a CTable saved with HUF_writeCTable() */
|
||||||
|
size_t HUF_readCTable (HUF_CElt* CTable, unsigned maxSymbolValue, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
HUF_decompress() does the following:
|
||||||
|
1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
|
||||||
|
2. build Huffman table from save, using HUF_readDTableXn()
|
||||||
|
3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** HUF_selectDecoder() :
|
||||||
|
* Tells which decoder is likely to decode faster,
|
||||||
|
* based on a set of pre-determined metrics.
|
||||||
|
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
||||||
|
* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
|
||||||
|
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
|
||||||
|
|
||||||
|
size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||||
|
size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
|
||||||
|
|
||||||
|
/* single stream variants */
|
||||||
|
|
||||||
|
size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
||||||
|
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
||||||
|
/** HUF_compress1X_repeat() :
|
||||||
|
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
||||||
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
|
* If preferRepeat then the old table will always be used if valid. */
|
||||||
|
size_t HUF_compress1X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
|
||||||
|
|
||||||
|
size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
|
||||||
|
size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
|
||||||
|
size_t HUF_decompress1X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
|
||||||
|
|
||||||
|
size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
|
||||||
|
size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
|
||||||
|
#endif /* HUF_H_298734234 */
|
644
contrib/linux-kernel/lib/zstd/huf_compress.c
Normal file
644
contrib/linux-kernel/lib/zstd/huf_compress.c
Normal file
@ -0,0 +1,644 @@
|
|||||||
|
/* ******************************************************************
|
||||||
|
Huffman encoder, part of New Generation Entropy library
|
||||||
|
Copyright (C) 2013-2016, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Includes
|
||||||
|
****************************************************************/
|
||||||
|
#include <linux/string.h> /* memcpy, memset */
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "fse.h" /* header compression */
|
||||||
|
#include "huf.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Error Management
|
||||||
|
****************************************************************/
|
||||||
|
#define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||||
|
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return f
|
||||||
|
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Utils
|
||||||
|
****************************************************************/
|
||||||
|
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
|
||||||
|
{
|
||||||
|
return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* *******************************************************
|
||||||
|
* HUF : Huffman block compression
|
||||||
|
*********************************************************/
|
||||||
|
/* HUF_compressWeights() :
|
||||||
|
* Same as FSE_compress(), but dedicated to huff0's weights compression.
|
||||||
|
* The use case needs much less stack memory.
|
||||||
|
* Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
|
||||||
|
*/
|
||||||
|
#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
|
||||||
|
size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
|
||||||
|
U32 maxSymbolValue = HUF_TABLELOG_MAX;
|
||||||
|
U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
|
||||||
|
|
||||||
|
FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
|
||||||
|
BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];
|
||||||
|
|
||||||
|
U32 count[HUF_TABLELOG_MAX+1];
|
||||||
|
S16 norm[HUF_TABLELOG_MAX+1];
|
||||||
|
|
||||||
|
/* init conditions */
|
||||||
|
if (wtSize <= 1) return 0; /* Not compressible */
|
||||||
|
|
||||||
|
/* Scan input and build symbol stats */
|
||||||
|
{ CHECK_V_F(maxCount, FSE_count_simple(count, &maxSymbolValue, weightTable, wtSize) );
|
||||||
|
if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
|
||||||
|
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
||||||
|
}
|
||||||
|
|
||||||
|
tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
|
||||||
|
CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
|
||||||
|
|
||||||
|
/* Write table description header */
|
||||||
|
{ CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
|
||||||
|
op += hSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compress */
|
||||||
|
CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
|
||||||
|
{ CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) );
|
||||||
|
if (cSize == 0) return 0; /* not enough space for compressed data */
|
||||||
|
op += cSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return op-ostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct HUF_CElt_s {
|
||||||
|
U16 val;
|
||||||
|
BYTE nbBits;
|
||||||
|
}; /* typedef'd to HUF_CElt within "huf.h" */
|
||||||
|
|
||||||
|
/*! HUF_writeCTable() :
|
||||||
|
`CTable` : Huffman tree to save, using huf representation.
|
||||||
|
@return : size of saved CTable */
|
||||||
|
size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
||||||
|
const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog)
|
||||||
|
{
|
||||||
|
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
|
||||||
|
BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
|
||||||
|
BYTE* op = (BYTE*)dst;
|
||||||
|
U32 n;
|
||||||
|
|
||||||
|
/* check conditions */
|
||||||
|
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
||||||
|
|
||||||
|
/* convert to weight */
|
||||||
|
bitsToWeight[0] = 0;
|
||||||
|
for (n=1; n<huffLog+1; n++)
|
||||||
|
bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
|
||||||
|
for (n=0; n<maxSymbolValue; n++)
|
||||||
|
huffWeight[n] = bitsToWeight[CTable[n].nbBits];
|
||||||
|
|
||||||
|
/* attempt weights compression by FSE */
|
||||||
|
{ CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
|
||||||
|
if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
|
||||||
|
op[0] = (BYTE)hSize;
|
||||||
|
return hSize+1;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* write raw values as 4-bits (max : 15) */
|
||||||
|
if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
|
||||||
|
if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
|
||||||
|
op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
|
||||||
|
huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
|
||||||
|
for (n=0; n<maxSymbolValue; n+=2)
|
||||||
|
op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
|
||||||
|
return ((maxSymbolValue+1)/2) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */
|
||||||
|
U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
|
||||||
|
U32 tableLog = 0;
|
||||||
|
U32 nbSymbols = 0;
|
||||||
|
|
||||||
|
/* get symbol weights */
|
||||||
|
CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
|
||||||
|
|
||||||
|
/* check result */
|
||||||
|
if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||||
|
if (nbSymbols > maxSymbolValue+1) return ERROR(maxSymbolValue_tooSmall);
|
||||||
|
|
||||||
|
/* Prepare base value per rank */
|
||||||
|
{ U32 n, nextRankStart = 0;
|
||||||
|
for (n=1; n<=tableLog; n++) {
|
||||||
|
U32 current = nextRankStart;
|
||||||
|
nextRankStart += (rankVal[n] << (n-1));
|
||||||
|
rankVal[n] = current;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* fill nbBits */
|
||||||
|
{ U32 n; for (n=0; n<nbSymbols; n++) {
|
||||||
|
const U32 w = huffWeight[n];
|
||||||
|
CTable[n].nbBits = (BYTE)(tableLog + 1 - w);
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* fill val */
|
||||||
|
{ U16 nbPerRank[HUF_TABLELOG_MAX+2] = {0}; /* support w=0=>n=tableLog+1 */
|
||||||
|
U16 valPerRank[HUF_TABLELOG_MAX+2] = {0};
|
||||||
|
{ U32 n; for (n=0; n<nbSymbols; n++) nbPerRank[CTable[n].nbBits]++; }
|
||||||
|
/* determine stating value per rank */
|
||||||
|
valPerRank[tableLog+1] = 0; /* for w==0 */
|
||||||
|
{ U16 min = 0;
|
||||||
|
U32 n; for (n=tableLog; n>0; n--) { /* start at n=tablelog <-> w=1 */
|
||||||
|
valPerRank[n] = min; /* get starting value within each rank */
|
||||||
|
min += nbPerRank[n];
|
||||||
|
min >>= 1;
|
||||||
|
} }
|
||||||
|
/* assign value within rank, symbol order */
|
||||||
|
{ U32 n; for (n=0; n<=maxSymbolValue; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return readSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct nodeElt_s {
|
||||||
|
U32 count;
|
||||||
|
U16 parent;
|
||||||
|
BYTE byte;
|
||||||
|
BYTE nbBits;
|
||||||
|
} nodeElt;
|
||||||
|
|
||||||
|
static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
|
||||||
|
{
|
||||||
|
const U32 largestBits = huffNode[lastNonNull].nbBits;
|
||||||
|
if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */
|
||||||
|
|
||||||
|
/* there are several too large elements (at least >= 2) */
|
||||||
|
{ int totalCost = 0;
|
||||||
|
const U32 baseCost = 1 << (largestBits - maxNbBits);
|
||||||
|
U32 n = lastNonNull;
|
||||||
|
|
||||||
|
while (huffNode[n].nbBits > maxNbBits) {
|
||||||
|
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
|
||||||
|
huffNode[n].nbBits = (BYTE)maxNbBits;
|
||||||
|
n --;
|
||||||
|
} /* n stops at huffNode[n].nbBits <= maxNbBits */
|
||||||
|
while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */
|
||||||
|
|
||||||
|
/* renorm totalCost */
|
||||||
|
totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
|
||||||
|
|
||||||
|
/* repay normalized cost */
|
||||||
|
{ U32 const noSymbol = 0xF0F0F0F0;
|
||||||
|
U32 rankLast[HUF_TABLELOG_MAX+2];
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
/* Get pos of last (smallest) symbol per rank */
|
||||||
|
memset(rankLast, 0xF0, sizeof(rankLast));
|
||||||
|
{ U32 currentNbBits = maxNbBits;
|
||||||
|
for (pos=n ; pos >= 0; pos--) {
|
||||||
|
if (huffNode[pos].nbBits >= currentNbBits) continue;
|
||||||
|
currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */
|
||||||
|
rankLast[maxNbBits-currentNbBits] = pos;
|
||||||
|
} }
|
||||||
|
|
||||||
|
while (totalCost > 0) {
|
||||||
|
U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1;
|
||||||
|
for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
|
||||||
|
U32 highPos = rankLast[nBitsToDecrease];
|
||||||
|
U32 lowPos = rankLast[nBitsToDecrease-1];
|
||||||
|
if (highPos == noSymbol) continue;
|
||||||
|
if (lowPos == noSymbol) break;
|
||||||
|
{ U32 const highTotal = huffNode[highPos].count;
|
||||||
|
U32 const lowTotal = 2 * huffNode[lowPos].count;
|
||||||
|
if (highTotal <= lowTotal) break;
|
||||||
|
} }
|
||||||
|
/* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
|
||||||
|
while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
|
||||||
|
nBitsToDecrease ++;
|
||||||
|
totalCost -= 1 << (nBitsToDecrease-1);
|
||||||
|
if (rankLast[nBitsToDecrease-1] == noSymbol)
|
||||||
|
rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
|
||||||
|
huffNode[rankLast[nBitsToDecrease]].nbBits ++;
|
||||||
|
if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
|
||||||
|
rankLast[nBitsToDecrease] = noSymbol;
|
||||||
|
else {
|
||||||
|
rankLast[nBitsToDecrease]--;
|
||||||
|
if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
|
||||||
|
rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
|
||||||
|
} } /* while (totalCost > 0) */
|
||||||
|
|
||||||
|
while (totalCost < 0) { /* Sometimes, cost correction overshoot */
|
||||||
|
if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
|
||||||
|
while (huffNode[n].nbBits == maxNbBits) n--;
|
||||||
|
huffNode[n+1].nbBits--;
|
||||||
|
rankLast[1] = n+1;
|
||||||
|
totalCost++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
huffNode[ rankLast[1] + 1 ].nbBits--;
|
||||||
|
rankLast[1]++;
|
||||||
|
totalCost ++;
|
||||||
|
} } } /* there are several too large elements (at least >= 2) */
|
||||||
|
|
||||||
|
return maxNbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 base;
|
||||||
|
U32 current;
|
||||||
|
} rankPos;
|
||||||
|
|
||||||
|
static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue)
|
||||||
|
{
|
||||||
|
rankPos rank[32];
|
||||||
|
U32 n;
|
||||||
|
|
||||||
|
memset(rank, 0, sizeof(rank));
|
||||||
|
for (n=0; n<=maxSymbolValue; n++) {
|
||||||
|
U32 r = BIT_highbit32(count[n] + 1);
|
||||||
|
rank[r].base ++;
|
||||||
|
}
|
||||||
|
for (n=30; n>0; n--) rank[n-1].base += rank[n].base;
|
||||||
|
for (n=0; n<32; n++) rank[n].current = rank[n].base;
|
||||||
|
for (n=0; n<=maxSymbolValue; n++) {
|
||||||
|
U32 const c = count[n];
|
||||||
|
U32 const r = BIT_highbit32(c+1) + 1;
|
||||||
|
U32 pos = rank[r].current++;
|
||||||
|
while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) huffNode[pos]=huffNode[pos-1], pos--;
|
||||||
|
huffNode[pos].count = c;
|
||||||
|
huffNode[pos].byte = (BYTE)n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** HUF_buildCTable_wksp() :
|
||||||
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
|
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
|
||||||
|
*/
|
||||||
|
#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
|
||||||
|
typedef nodeElt huffNodeTable[2*HUF_SYMBOLVALUE_MAX+1 +1];
|
||||||
|
size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
nodeElt* const huffNode0 = (nodeElt*)workSpace;
|
||||||
|
nodeElt* const huffNode = huffNode0+1;
|
||||||
|
U32 n, nonNullRank;
|
||||||
|
int lowS, lowN;
|
||||||
|
U16 nodeNb = STARTNODE;
|
||||||
|
U32 nodeRoot;
|
||||||
|
|
||||||
|
/* safety checks */
|
||||||
|
if (wkspSize < sizeof(huffNodeTable)) return ERROR(GENERIC); /* workSpace is not large enough */
|
||||||
|
if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
|
||||||
|
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(GENERIC);
|
||||||
|
memset(huffNode0, 0, sizeof(huffNodeTable));
|
||||||
|
|
||||||
|
/* sort, decreasing order */
|
||||||
|
HUF_sort(huffNode, count, maxSymbolValue);
|
||||||
|
|
||||||
|
/* init for parents */
|
||||||
|
nonNullRank = maxSymbolValue;
|
||||||
|
while(huffNode[nonNullRank].count == 0) nonNullRank--;
|
||||||
|
lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb;
|
||||||
|
huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count;
|
||||||
|
huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb;
|
||||||
|
nodeNb++; lowS-=2;
|
||||||
|
for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30);
|
||||||
|
huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */
|
||||||
|
|
||||||
|
/* create parents */
|
||||||
|
while (nodeNb <= nodeRoot) {
|
||||||
|
U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
|
||||||
|
U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
|
||||||
|
huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count;
|
||||||
|
huffNode[n1].parent = huffNode[n2].parent = nodeNb;
|
||||||
|
nodeNb++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* distribute weights (unlimited tree height) */
|
||||||
|
huffNode[nodeRoot].nbBits = 0;
|
||||||
|
for (n=nodeRoot-1; n>=STARTNODE; n--)
|
||||||
|
huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
|
||||||
|
for (n=0; n<=nonNullRank; n++)
|
||||||
|
huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
|
||||||
|
|
||||||
|
/* enforce maxTableLog */
|
||||||
|
maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits);
|
||||||
|
|
||||||
|
/* fill result into tree (val, nbBits) */
|
||||||
|
{ U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
|
||||||
|
U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
|
||||||
|
if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
|
||||||
|
for (n=0; n<=nonNullRank; n++)
|
||||||
|
nbPerRank[huffNode[n].nbBits]++;
|
||||||
|
/* determine stating value per rank */
|
||||||
|
{ U16 min = 0;
|
||||||
|
for (n=maxNbBits; n>0; n--) {
|
||||||
|
valPerRank[n] = min; /* get starting value within each rank */
|
||||||
|
min += nbPerRank[n];
|
||||||
|
min >>= 1;
|
||||||
|
} }
|
||||||
|
for (n=0; n<=maxSymbolValue; n++)
|
||||||
|
tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
|
||||||
|
for (n=0; n<=maxSymbolValue; n++)
|
||||||
|
tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxNbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue)
|
||||||
|
{
|
||||||
|
size_t nbBits = 0;
|
||||||
|
int s;
|
||||||
|
for (s = 0; s <= (int)maxSymbolValue; ++s) {
|
||||||
|
nbBits += CTable[s].nbBits * count[s];
|
||||||
|
}
|
||||||
|
return nbBits >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
|
||||||
|
int bad = 0;
|
||||||
|
int s;
|
||||||
|
for (s = 0; s <= (int)maxSymbolValue; ++s) {
|
||||||
|
bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
|
||||||
|
}
|
||||||
|
return !bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
|
||||||
|
|
||||||
|
#define HUF_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
|
||||||
|
|
||||||
|
#define HUF_FLUSHBITS_1(stream) \
|
||||||
|
if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)
|
||||||
|
|
||||||
|
#define HUF_FLUSHBITS_2(stream) \
|
||||||
|
if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
|
||||||
|
|
||||||
|
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*) src;
|
||||||
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
size_t n;
|
||||||
|
const unsigned fast = (dstSize >= HUF_BLOCKBOUND(srcSize));
|
||||||
|
BIT_CStream_t bitC;
|
||||||
|
|
||||||
|
/* init */
|
||||||
|
if (dstSize < 8) return 0; /* not enough space to compress */
|
||||||
|
{ size_t const initErr = BIT_initCStream(&bitC, op, oend-op);
|
||||||
|
if (HUF_isError(initErr)) return 0; }
|
||||||
|
|
||||||
|
n = srcSize & ~3; /* join to mod 4 */
|
||||||
|
switch (srcSize & 3)
|
||||||
|
{
|
||||||
|
case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);
|
||||||
|
HUF_FLUSHBITS_2(&bitC);
|
||||||
|
case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);
|
||||||
|
HUF_FLUSHBITS_1(&bitC);
|
||||||
|
case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);
|
||||||
|
HUF_FLUSHBITS(&bitC);
|
||||||
|
case 0 :
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; n>0; n-=4) { /* note : n&3==0 at this stage */
|
||||||
|
HUF_encodeSymbol(&bitC, ip[n- 1], CTable);
|
||||||
|
HUF_FLUSHBITS_1(&bitC);
|
||||||
|
HUF_encodeSymbol(&bitC, ip[n- 2], CTable);
|
||||||
|
HUF_FLUSHBITS_2(&bitC);
|
||||||
|
HUF_encodeSymbol(&bitC, ip[n- 3], CTable);
|
||||||
|
HUF_FLUSHBITS_1(&bitC);
|
||||||
|
HUF_encodeSymbol(&bitC, ip[n- 4], CTable);
|
||||||
|
HUF_FLUSHBITS(&bitC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BIT_closeCStream(&bitC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
|
||||||
|
const BYTE* ip = (const BYTE*) src;
|
||||||
|
const BYTE* const iend = ip + srcSize;
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
|
||||||
|
if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */
|
||||||
|
if (srcSize < 12) return 0; /* no saving possible : too small input */
|
||||||
|
op += 6; /* jumpTable */
|
||||||
|
|
||||||
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
|
||||||
|
if (cSize==0) return 0;
|
||||||
|
MEM_writeLE16(ostart, (U16)cSize);
|
||||||
|
op += cSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip += segmentSize;
|
||||||
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
|
||||||
|
if (cSize==0) return 0;
|
||||||
|
MEM_writeLE16(ostart+2, (U16)cSize);
|
||||||
|
op += cSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip += segmentSize;
|
||||||
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
|
||||||
|
if (cSize==0) return 0;
|
||||||
|
MEM_writeLE16(ostart+4, (U16)cSize);
|
||||||
|
op += cSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip += segmentSize;
|
||||||
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, iend-ip, CTable) );
|
||||||
|
if (cSize==0) return 0;
|
||||||
|
op += cSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return op-ostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t HUF_compressCTable_internal(
|
||||||
|
BYTE* const ostart, BYTE* op, BYTE* const oend,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned singleStream, const HUF_CElt* CTable)
|
||||||
|
{
|
||||||
|
size_t const cSize = singleStream ?
|
||||||
|
HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable) :
|
||||||
|
HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable);
|
||||||
|
if (HUF_isError(cSize)) { return cSize; }
|
||||||
|
if (cSize==0) { return 0; } /* uncompressible */
|
||||||
|
op += cSize;
|
||||||
|
/* check compressibility */
|
||||||
|
if ((size_t)(op-ostart) >= srcSize-1) { return 0; }
|
||||||
|
return op-ostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* `workSpace` must a table of at least 1024 unsigned */
|
||||||
|
static size_t HUF_compress_internal (
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
|
unsigned singleStream,
|
||||||
|
void* workSpace, size_t wkspSize,
|
||||||
|
HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
|
||||||
|
U32* count;
|
||||||
|
size_t const countSize = sizeof(U32) * (HUF_SYMBOLVALUE_MAX + 1);
|
||||||
|
HUF_CElt* CTable;
|
||||||
|
size_t const CTableSize = sizeof(HUF_CElt) * (HUF_SYMBOLVALUE_MAX + 1);
|
||||||
|
|
||||||
|
/* checks & inits */
|
||||||
|
if (wkspSize < sizeof(huffNodeTable) + countSize + CTableSize) return ERROR(GENERIC);
|
||||||
|
if (!srcSize) return 0; /* Uncompressed (note : 1 means rle, so first byte must be correct) */
|
||||||
|
if (!dstSize) return 0; /* cannot fit within dst budget */
|
||||||
|
if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
|
||||||
|
if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||||
|
if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
|
||||||
|
if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
|
||||||
|
|
||||||
|
count = (U32*)workSpace;
|
||||||
|
workSpace = (BYTE*)workSpace + countSize;
|
||||||
|
wkspSize -= countSize;
|
||||||
|
CTable = (HUF_CElt*)workSpace;
|
||||||
|
workSpace = (BYTE*)workSpace + CTableSize;
|
||||||
|
wkspSize -= CTableSize;
|
||||||
|
|
||||||
|
/* Heuristic : If we don't need to check the validity of the old table use the old table for small inputs */
|
||||||
|
if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
|
||||||
|
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan input and build symbol stats */
|
||||||
|
{ CHECK_V_F(largest, FSE_count_wksp (count, &maxSymbolValue, (const BYTE*)src, srcSize, (U32*)workSpace) );
|
||||||
|
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
|
||||||
|
if (largest <= (srcSize >> 7)+1) return 0; /* Fast heuristic : not compressible enough */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check validity of previous table */
|
||||||
|
if (repeat && *repeat == HUF_repeat_check && !HUF_validateCTable(oldHufTable, count, maxSymbolValue)) {
|
||||||
|
*repeat = HUF_repeat_none;
|
||||||
|
}
|
||||||
|
/* Heuristic : use existing table for small inputs */
|
||||||
|
if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
|
||||||
|
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build Huffman Tree */
|
||||||
|
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
||||||
|
{ CHECK_V_F(maxBits, HUF_buildCTable_wksp (CTable, count, maxSymbolValue, huffLog, workSpace, wkspSize) );
|
||||||
|
huffLog = (U32)maxBits;
|
||||||
|
/* Zero the unused symbols so we can check it for validity */
|
||||||
|
memset(CTable + maxSymbolValue + 1, 0, CTableSize - (maxSymbolValue + 1) * sizeof(HUF_CElt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write table description header */
|
||||||
|
{ CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, CTable, maxSymbolValue, huffLog) );
|
||||||
|
/* Check if using the previous table will be beneficial */
|
||||||
|
if (repeat && *repeat != HUF_repeat_none) {
|
||||||
|
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, count, maxSymbolValue);
|
||||||
|
size_t const newSize = HUF_estimateCompressedSize(CTable, count, maxSymbolValue);
|
||||||
|
if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
|
||||||
|
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Use the new table */
|
||||||
|
if (hSize + 12ul >= srcSize) { return 0; }
|
||||||
|
op += hSize;
|
||||||
|
if (repeat) { *repeat = HUF_repeat_none; }
|
||||||
|
if (oldHufTable) { memcpy(oldHufTable, CTable, CTableSize); } /* Save the new table */
|
||||||
|
}
|
||||||
|
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, CTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
|
void* workSpace, size_t wkspSize,
|
||||||
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat)
|
||||||
|
{
|
||||||
|
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, hufTable, repeat, preferRepeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
|
void* workSpace, size_t wkspSize,
|
||||||
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat)
|
||||||
|
{
|
||||||
|
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, hufTable, repeat, preferRepeat);
|
||||||
|
}
|
835
contrib/linux-kernel/lib/zstd/huf_decompress.c
Normal file
835
contrib/linux-kernel/lib/zstd/huf_decompress.c
Normal file
@ -0,0 +1,835 @@
|
|||||||
|
/* ******************************************************************
|
||||||
|
Huffman decoder, part of New Generation Entropy library
|
||||||
|
Copyright (C) 2013-2016, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
- Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Compiler specifics
|
||||||
|
****************************************************************/
|
||||||
|
#define FORCE_INLINE static __always_inline
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Dependencies
|
||||||
|
****************************************************************/
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/string.h> /* memcpy, memset */
|
||||||
|
#include "bitstream.h" /* BIT_* */
|
||||||
|
#include "fse.h" /* header compression */
|
||||||
|
#include "huf.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Error Management
|
||||||
|
****************************************************************/
|
||||||
|
#define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||||
|
|
||||||
|
|
||||||
|
/*-***************************/
|
||||||
|
/* generic DTableDesc */
|
||||||
|
/*-***************************/
|
||||||
|
|
||||||
|
typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
|
||||||
|
|
||||||
|
static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
|
||||||
|
{
|
||||||
|
DTableDesc dtd;
|
||||||
|
memcpy(&dtd, table, sizeof(dtd));
|
||||||
|
return dtd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-***************************/
|
||||||
|
/* single-symbol decoding */
|
||||||
|
/*-***************************/
|
||||||
|
|
||||||
|
typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */
|
||||||
|
|
||||||
|
size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1];
|
||||||
|
U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
|
||||||
|
U32 tableLog = 0;
|
||||||
|
U32 nbSymbols = 0;
|
||||||
|
size_t iSize;
|
||||||
|
void* const dtPtr = DTable + 1;
|
||||||
|
HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
|
||||||
|
|
||||||
|
HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
|
||||||
|
/* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
|
||||||
|
|
||||||
|
iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
|
||||||
|
if (HUF_isError(iSize)) return iSize;
|
||||||
|
|
||||||
|
/* Table header */
|
||||||
|
{ DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
|
if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
|
||||||
|
dtd.tableType = 0;
|
||||||
|
dtd.tableLog = (BYTE)tableLog;
|
||||||
|
memcpy(DTable, &dtd, sizeof(dtd));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate starting value for each rank */
|
||||||
|
{ U32 n, nextRankStart = 0;
|
||||||
|
for (n=1; n<tableLog+1; n++) {
|
||||||
|
U32 const current = nextRankStart;
|
||||||
|
nextRankStart += (rankVal[n] << (n-1));
|
||||||
|
rankVal[n] = current;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* fill DTable */
|
||||||
|
{ U32 n;
|
||||||
|
for (n=0; n<nbSymbols; n++) {
|
||||||
|
U32 const w = huffWeight[n];
|
||||||
|
U32 const length = (1 << w) >> 1;
|
||||||
|
U32 u;
|
||||||
|
HUF_DEltX2 D;
|
||||||
|
D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
|
||||||
|
for (u = rankVal[w]; u < rankVal[w] + length; u++)
|
||||||
|
dt[u] = D;
|
||||||
|
rankVal[w] += length;
|
||||||
|
} }
|
||||||
|
|
||||||
|
return iSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
|
||||||
|
BYTE const c = dt[val].byte;
|
||||||
|
BIT_skipBits(Dstream, dt[val].nbBits);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
|
||||||
|
*ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
||||||
|
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||||
|
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
||||||
|
if (MEM_64bits()) \
|
||||||
|
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
||||||
|
|
||||||
|
FORCE_INLINE size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX2* const dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
BYTE* const pStart = p;
|
||||||
|
|
||||||
|
/* up to 4 symbols at a time */
|
||||||
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-4)) {
|
||||||
|
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* closer to the end */
|
||||||
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd))
|
||||||
|
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||||
|
|
||||||
|
/* no more data to retrieve from bitstream, hence no need to reload */
|
||||||
|
while (p < pEnd)
|
||||||
|
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
||||||
|
|
||||||
|
return pEnd-pStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t HUF_decompress1X2_usingDTable_internal(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
BYTE* op = (BYTE*)dst;
|
||||||
|
BYTE* const oend = op + dstSize;
|
||||||
|
const void* dtPtr = DTable + 1;
|
||||||
|
const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
|
||||||
|
BIT_DStream_t bitD;
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
U32 const dtLog = dtd.tableLog;
|
||||||
|
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
|
||||||
|
HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
|
||||||
|
|
||||||
|
/* check */
|
||||||
|
if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
|
||||||
|
|
||||||
|
return dstSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X2_usingDTable(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
|
if (dtd.tableType != 0) return ERROR(GENERIC);
|
||||||
|
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X2_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
|
size_t const hSize = HUF_readDTableX2 (DCtx, cSrc, cSrcSize);
|
||||||
|
if (HUF_isError(hSize)) return hSize;
|
||||||
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
|
return HUF_decompress1X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t HUF_decompress4X2_usingDTable_internal(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
/* Check */
|
||||||
|
if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
|
||||||
|
|
||||||
|
{ const BYTE* const istart = (const BYTE*) cSrc;
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
const void* const dtPtr = DTable + 1;
|
||||||
|
const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
BIT_DStream_t bitD1;
|
||||||
|
BIT_DStream_t bitD2;
|
||||||
|
BIT_DStream_t bitD3;
|
||||||
|
BIT_DStream_t bitD4;
|
||||||
|
size_t const length1 = MEM_readLE16(istart);
|
||||||
|
size_t const length2 = MEM_readLE16(istart+2);
|
||||||
|
size_t const length3 = MEM_readLE16(istart+4);
|
||||||
|
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
|
||||||
|
const BYTE* const istart1 = istart + 6; /* jumpTable */
|
||||||
|
const BYTE* const istart2 = istart1 + length1;
|
||||||
|
const BYTE* const istart3 = istart2 + length2;
|
||||||
|
const BYTE* const istart4 = istart3 + length3;
|
||||||
|
const size_t segmentSize = (dstSize+3) / 4;
|
||||||
|
BYTE* const opStart2 = ostart + segmentSize;
|
||||||
|
BYTE* const opStart3 = opStart2 + segmentSize;
|
||||||
|
BYTE* const opStart4 = opStart3 + segmentSize;
|
||||||
|
BYTE* op1 = ostart;
|
||||||
|
BYTE* op2 = opStart2;
|
||||||
|
BYTE* op3 = opStart3;
|
||||||
|
BYTE* op4 = opStart4;
|
||||||
|
U32 endSignal;
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
U32 const dtLog = dtd.tableLog;
|
||||||
|
|
||||||
|
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
|
||||||
|
/* 16-32 symbols per loop (4-8 symbols per stream) */
|
||||||
|
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||||
|
for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) {
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
|
||||||
|
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check corruption */
|
||||||
|
if (op1 > opStart2) return ERROR(corruption_detected);
|
||||||
|
if (op2 > opStart3) return ERROR(corruption_detected);
|
||||||
|
if (op3 > opStart4) return ERROR(corruption_detected);
|
||||||
|
/* note : op4 supposed already verified within main loop */
|
||||||
|
|
||||||
|
/* finish bitStreams one by one */
|
||||||
|
HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
|
||||||
|
HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
|
||||||
|
HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
|
||||||
|
HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
|
||||||
|
|
||||||
|
/* check */
|
||||||
|
endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
||||||
|
if (!endSignal) return ERROR(corruption_detected);
|
||||||
|
|
||||||
|
/* decoded size */
|
||||||
|
return dstSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_decompress4X2_usingDTable(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
|
if (dtd.tableType != 0) return ERROR(GENERIC);
|
||||||
|
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_decompress4X2_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
|
size_t const hSize = HUF_readDTableX2 (dctx, cSrc, cSrcSize);
|
||||||
|
if (HUF_isError(hSize)) return hSize;
|
||||||
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
|
return HUF_decompress4X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, dctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************/
|
||||||
|
/* double-symbols decoding */
|
||||||
|
/* *************************/
|
||||||
|
typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* double-symbols decoding */
|
||||||
|
|
||||||
|
typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
|
||||||
|
|
||||||
|
/* HUF_fillDTableX4Level2() :
|
||||||
|
* `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
|
||||||
|
static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 consumed,
|
||||||
|
const U32* rankValOrigin, const int minWeight,
|
||||||
|
const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
|
||||||
|
U32 nbBitsBaseline, U16 baseSeq)
|
||||||
|
{
|
||||||
|
HUF_DEltX4 DElt;
|
||||||
|
U32 rankVal[HUF_TABLELOG_MAX + 1];
|
||||||
|
|
||||||
|
/* get pre-calculated rankVal */
|
||||||
|
memcpy(rankVal, rankValOrigin, sizeof(rankVal));
|
||||||
|
|
||||||
|
/* fill skipped values */
|
||||||
|
if (minWeight>1) {
|
||||||
|
U32 i, skipSize = rankVal[minWeight];
|
||||||
|
MEM_writeLE16(&(DElt.sequence), baseSeq);
|
||||||
|
DElt.nbBits = (BYTE)(consumed);
|
||||||
|
DElt.length = 1;
|
||||||
|
for (i = 0; i < skipSize; i++)
|
||||||
|
DTable[i] = DElt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill DTable */
|
||||||
|
{ U32 s; for (s=0; s<sortedListSize; s++) { /* note : sortedSymbols already skipped */
|
||||||
|
const U32 symbol = sortedSymbols[s].symbol;
|
||||||
|
const U32 weight = sortedSymbols[s].weight;
|
||||||
|
const U32 nbBits = nbBitsBaseline - weight;
|
||||||
|
const U32 length = 1 << (sizeLog-nbBits);
|
||||||
|
const U32 start = rankVal[weight];
|
||||||
|
U32 i = start;
|
||||||
|
const U32 end = start + length;
|
||||||
|
|
||||||
|
MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
|
||||||
|
DElt.nbBits = (BYTE)(nbBits + consumed);
|
||||||
|
DElt.length = 2;
|
||||||
|
do { DTable[i++] = DElt; } while (i<end); /* since length >= 1 */
|
||||||
|
|
||||||
|
rankVal[weight] += length;
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1];
|
||||||
|
|
||||||
|
static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog,
|
||||||
|
const sortedSymbol_t* sortedList, const U32 sortedListSize,
|
||||||
|
const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
|
||||||
|
const U32 nbBitsBaseline)
|
||||||
|
{
|
||||||
|
U32 rankVal[HUF_TABLELOG_MAX + 1];
|
||||||
|
const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
|
||||||
|
const U32 minBits = nbBitsBaseline - maxWeight;
|
||||||
|
U32 s;
|
||||||
|
|
||||||
|
memcpy(rankVal, rankValOrigin, sizeof(rankVal));
|
||||||
|
|
||||||
|
/* fill DTable */
|
||||||
|
for (s=0; s<sortedListSize; s++) {
|
||||||
|
const U16 symbol = sortedList[s].symbol;
|
||||||
|
const U32 weight = sortedList[s].weight;
|
||||||
|
const U32 nbBits = nbBitsBaseline - weight;
|
||||||
|
const U32 start = rankVal[weight];
|
||||||
|
const U32 length = 1 << (targetLog-nbBits);
|
||||||
|
|
||||||
|
if (targetLog-nbBits >= minBits) { /* enough room for a second symbol */
|
||||||
|
U32 sortedRank;
|
||||||
|
int minWeight = nbBits + scaleLog;
|
||||||
|
if (minWeight < 1) minWeight = 1;
|
||||||
|
sortedRank = rankStart[minWeight];
|
||||||
|
HUF_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits,
|
||||||
|
rankValOrigin[nbBits], minWeight,
|
||||||
|
sortedList+sortedRank, sortedListSize-sortedRank,
|
||||||
|
nbBitsBaseline, symbol);
|
||||||
|
} else {
|
||||||
|
HUF_DEltX4 DElt;
|
||||||
|
MEM_writeLE16(&(DElt.sequence), symbol);
|
||||||
|
DElt.nbBits = (BYTE)(nbBits);
|
||||||
|
DElt.length = 1;
|
||||||
|
{ U32 const end = start + length;
|
||||||
|
U32 u;
|
||||||
|
for (u = start; u < end; u++) DTable[u] = DElt;
|
||||||
|
} }
|
||||||
|
rankVal[weight] += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
BYTE weightList[HUF_SYMBOLVALUE_MAX + 1];
|
||||||
|
sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1];
|
||||||
|
U32 rankStats[HUF_TABLELOG_MAX + 1] = { 0 };
|
||||||
|
U32 rankStart0[HUF_TABLELOG_MAX + 2] = { 0 };
|
||||||
|
U32* const rankStart = rankStart0+1;
|
||||||
|
rankVal_t rankVal;
|
||||||
|
U32 tableLog, maxW, sizeOfSort, nbSymbols;
|
||||||
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
|
U32 const maxTableLog = dtd.maxTableLog;
|
||||||
|
size_t iSize;
|
||||||
|
void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */
|
||||||
|
HUF_DEltX4* const dt = (HUF_DEltX4*)dtPtr;
|
||||||
|
|
||||||
|
HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
|
||||||
|
if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||||
|
/* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
|
||||||
|
|
||||||
|
iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
|
||||||
|
if (HUF_isError(iSize)) return iSize;
|
||||||
|
|
||||||
|
/* check result */
|
||||||
|
if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
|
||||||
|
|
||||||
|
/* find maxWeight */
|
||||||
|
for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */
|
||||||
|
|
||||||
|
/* Get start index of each weight */
|
||||||
|
{ U32 w, nextRankStart = 0;
|
||||||
|
for (w=1; w<maxW+1; w++) {
|
||||||
|
U32 current = nextRankStart;
|
||||||
|
nextRankStart += rankStats[w];
|
||||||
|
rankStart[w] = current;
|
||||||
|
}
|
||||||
|
rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/
|
||||||
|
sizeOfSort = nextRankStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort symbols by weight */
|
||||||
|
{ U32 s;
|
||||||
|
for (s=0; s<nbSymbols; s++) {
|
||||||
|
U32 const w = weightList[s];
|
||||||
|
U32 const r = rankStart[w]++;
|
||||||
|
sortedSymbol[r].symbol = (BYTE)s;
|
||||||
|
sortedSymbol[r].weight = (BYTE)w;
|
||||||
|
}
|
||||||
|
rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build rankVal */
|
||||||
|
{ U32* const rankVal0 = rankVal[0];
|
||||||
|
{ int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */
|
||||||
|
U32 nextRankVal = 0;
|
||||||
|
U32 w;
|
||||||
|
for (w=1; w<maxW+1; w++) {
|
||||||
|
U32 current = nextRankVal;
|
||||||
|
nextRankVal += rankStats[w] << (w+rescale);
|
||||||
|
rankVal0[w] = current;
|
||||||
|
} }
|
||||||
|
{ U32 const minBits = tableLog+1 - maxW;
|
||||||
|
U32 consumed;
|
||||||
|
for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
|
||||||
|
U32* const rankValPtr = rankVal[consumed];
|
||||||
|
U32 w;
|
||||||
|
for (w = 1; w < maxW+1; w++) {
|
||||||
|
rankValPtr[w] = rankVal0[w] >> consumed;
|
||||||
|
} } } }
|
||||||
|
|
||||||
|
HUF_fillDTableX4(dt, maxTableLog,
|
||||||
|
sortedSymbol, sizeOfSort,
|
||||||
|
rankStart0, rankVal, maxW,
|
||||||
|
tableLog+1);
|
||||||
|
|
||||||
|
dtd.tableLog = (BYTE)maxTableLog;
|
||||||
|
dtd.tableType = 1;
|
||||||
|
memcpy(DTable, &dtd, sizeof(dtd));
|
||||||
|
return iSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static U32 HUF_decodeSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
||||||
|
memcpy(op, dt+val, 2);
|
||||||
|
BIT_skipBits(DStream, dt[val].nbBits);
|
||||||
|
return dt[val].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32 HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
||||||
|
memcpy(op, dt+val, 1);
|
||||||
|
if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
|
||||||
|
else {
|
||||||
|
if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
|
||||||
|
BIT_skipBits(DStream, dt[val].nbBits);
|
||||||
|
if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
|
||||||
|
DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
|
||||||
|
} }
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \
|
||||||
|
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
|
||||||
|
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||||
|
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
||||||
|
|
||||||
|
#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
|
||||||
|
if (MEM_64bits()) \
|
||||||
|
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
||||||
|
|
||||||
|
FORCE_INLINE size_t HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, const HUF_DEltX4* const dt, const U32 dtLog)
|
||||||
|
{
|
||||||
|
BYTE* const pStart = p;
|
||||||
|
|
||||||
|
/* up to 8 symbols at a time */
|
||||||
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
|
||||||
|
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* closer to end : up to 2 symbols at a time */
|
||||||
|
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
|
||||||
|
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
||||||
|
|
||||||
|
while (p <= pEnd-2)
|
||||||
|
HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
|
||||||
|
|
||||||
|
if (p < pEnd)
|
||||||
|
p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
|
||||||
|
|
||||||
|
return p-pStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t HUF_decompress1X4_usingDTable_internal(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
BIT_DStream_t bitD;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode */
|
||||||
|
{ BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */
|
||||||
|
const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check */
|
||||||
|
if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
|
||||||
|
|
||||||
|
/* decoded size */
|
||||||
|
return dstSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X4_usingDTable(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
|
if (dtd.tableType != 1) return ERROR(GENERIC);
|
||||||
|
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X4_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
|
size_t const hSize = HUF_readDTableX4 (DCtx, cSrc, cSrcSize);
|
||||||
|
if (HUF_isError(hSize)) return hSize;
|
||||||
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
|
return HUF_decompress1X4_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t HUF_decompress4X4_usingDTable_internal(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
|
||||||
|
|
||||||
|
{ const BYTE* const istart = (const BYTE*) cSrc;
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* const oend = ostart + dstSize;
|
||||||
|
const void* const dtPtr = DTable+1;
|
||||||
|
const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
BIT_DStream_t bitD1;
|
||||||
|
BIT_DStream_t bitD2;
|
||||||
|
BIT_DStream_t bitD3;
|
||||||
|
BIT_DStream_t bitD4;
|
||||||
|
size_t const length1 = MEM_readLE16(istart);
|
||||||
|
size_t const length2 = MEM_readLE16(istart+2);
|
||||||
|
size_t const length3 = MEM_readLE16(istart+4);
|
||||||
|
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
|
||||||
|
const BYTE* const istart1 = istart + 6; /* jumpTable */
|
||||||
|
const BYTE* const istart2 = istart1 + length1;
|
||||||
|
const BYTE* const istart3 = istart2 + length2;
|
||||||
|
const BYTE* const istart4 = istart3 + length3;
|
||||||
|
size_t const segmentSize = (dstSize+3) / 4;
|
||||||
|
BYTE* const opStart2 = ostart + segmentSize;
|
||||||
|
BYTE* const opStart3 = opStart2 + segmentSize;
|
||||||
|
BYTE* const opStart4 = opStart3 + segmentSize;
|
||||||
|
BYTE* op1 = ostart;
|
||||||
|
BYTE* op2 = opStart2;
|
||||||
|
BYTE* op3 = opStart3;
|
||||||
|
BYTE* op4 = opStart4;
|
||||||
|
U32 endSignal;
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
U32 const dtLog = dtd.tableLog;
|
||||||
|
|
||||||
|
if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
{ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
|
||||||
|
if (HUF_isError(errorCode)) return errorCode; }
|
||||||
|
|
||||||
|
/* 16-32 symbols per loop (4-8 symbols per stream) */
|
||||||
|
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||||
|
for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) {
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
|
||||||
|
HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
|
||||||
|
|
||||||
|
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check corruption */
|
||||||
|
if (op1 > opStart2) return ERROR(corruption_detected);
|
||||||
|
if (op2 > opStart3) return ERROR(corruption_detected);
|
||||||
|
if (op3 > opStart4) return ERROR(corruption_detected);
|
||||||
|
/* note : op4 already verified within main loop */
|
||||||
|
|
||||||
|
/* finish bitStreams one by one */
|
||||||
|
HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
|
||||||
|
HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
|
||||||
|
HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
|
||||||
|
HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
|
||||||
|
|
||||||
|
/* check */
|
||||||
|
{ U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
||||||
|
if (!endCheck) return ERROR(corruption_detected); }
|
||||||
|
|
||||||
|
/* decoded size */
|
||||||
|
return dstSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_decompress4X4_usingDTable(
|
||||||
|
void* dst, size_t dstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
||||||
|
if (dtd.tableType != 1) return ERROR(GENERIC);
|
||||||
|
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t HUF_decompress4X4_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*) cSrc;
|
||||||
|
|
||||||
|
size_t hSize = HUF_readDTableX4 (dctx, cSrc, cSrcSize);
|
||||||
|
if (HUF_isError(hSize)) return hSize;
|
||||||
|
if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
|
||||||
|
ip += hSize; cSrcSize -= hSize;
|
||||||
|
|
||||||
|
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ********************************/
|
||||||
|
/* Generic decompression selector */
|
||||||
|
/* ********************************/
|
||||||
|
|
||||||
|
size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
|
||||||
|
HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const HUF_DTable* DTable)
|
||||||
|
{
|
||||||
|
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
||||||
|
return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
|
||||||
|
HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
|
||||||
|
static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
|
||||||
|
{
|
||||||
|
/* single, double, quad */
|
||||||
|
{{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */
|
||||||
|
{{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */
|
||||||
|
{{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */
|
||||||
|
{{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */
|
||||||
|
{{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */
|
||||||
|
{{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */
|
||||||
|
{{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */
|
||||||
|
{{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */
|
||||||
|
{{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */
|
||||||
|
{{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */
|
||||||
|
{{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */
|
||||||
|
{{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */
|
||||||
|
{{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */
|
||||||
|
{{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */
|
||||||
|
{{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */
|
||||||
|
{{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** HUF_selectDecoder() :
|
||||||
|
* Tells which decoder is likely to decode faster,
|
||||||
|
* based on a set of pre-determined metrics.
|
||||||
|
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
||||||
|
* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
|
||||||
|
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
/* decoder timing evaluation */
|
||||||
|
U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */
|
||||||
|
U32 const D256 = (U32)(dstSize >> 8);
|
||||||
|
U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
|
||||||
|
U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
|
||||||
|
DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */
|
||||||
|
|
||||||
|
return DTime1 < DTime0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
/* validation checks */
|
||||||
|
if (dstSize == 0) return ERROR(dstSize_tooSmall);
|
||||||
|
if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
|
||||||
|
if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
|
||||||
|
if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
|
||||||
|
|
||||||
|
{ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
||||||
|
return algoNb ? HUF_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
|
||||||
|
HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_hufOnly (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
/* validation checks */
|
||||||
|
if (dstSize == 0) return ERROR(dstSize_tooSmall);
|
||||||
|
if ((cSrcSize >= dstSize) || (cSrcSize <= 1)) return ERROR(corruption_detected); /* invalid */
|
||||||
|
|
||||||
|
{ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
||||||
|
return algoNb ? HUF_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
|
||||||
|
HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
|
||||||
|
{
|
||||||
|
/* validation checks */
|
||||||
|
if (dstSize == 0) return ERROR(dstSize_tooSmall);
|
||||||
|
if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
|
||||||
|
if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
|
||||||
|
if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
|
||||||
|
|
||||||
|
{ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
||||||
|
return algoNb ? HUF_decompress1X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
|
||||||
|
HUF_decompress1X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
|
||||||
|
}
|
||||||
|
}
|
209
contrib/linux-kernel/lib/zstd/mem.h
Normal file
209
contrib/linux-kernel/lib/zstd/mem.h
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEM_H_MODULE
|
||||||
|
#define MEM_H_MODULE
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
#include <linux/types.h> /* size_t, ptrdiff_t */
|
||||||
|
#include <linux/string.h> /* memcpy */
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Compiler specifics
|
||||||
|
******************************************/
|
||||||
|
#define MEM_STATIC static __inline __attribute__((unused))
|
||||||
|
|
||||||
|
/* code only tested on 32 and 64 bits systems */
|
||||||
|
#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
|
||||||
|
MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Basic Types
|
||||||
|
*****************************************************************/
|
||||||
|
typedef uint8_t BYTE;
|
||||||
|
typedef uint16_t U16;
|
||||||
|
typedef int16_t S16;
|
||||||
|
typedef uint32_t U32;
|
||||||
|
typedef int32_t S32;
|
||||||
|
typedef uint64_t U64;
|
||||||
|
typedef int64_t S64;
|
||||||
|
typedef ptrdiff_t iPtrDiff;
|
||||||
|
typedef uintptr_t uPtrDiff;
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Memory I/O
|
||||||
|
*****************************************************************/
|
||||||
|
MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
|
||||||
|
MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
|
||||||
|
|
||||||
|
#if defined(__LITTLE_ENDIAN)
|
||||||
|
# define MEM_LITTLE_ENDIAN 1
|
||||||
|
#else
|
||||||
|
# define MEM_LITTLE_ENDIAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MEM_STATIC unsigned MEM_isLittleEndian(void)
|
||||||
|
{
|
||||||
|
return MEM_LITTLE_ENDIAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U16 MEM_read16(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const U16*)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_read32(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const U32*)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U64 MEM_read64(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const U64*)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t MEM_readST(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const size_t*)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_write16(void* memPtr, U16 value)
|
||||||
|
{
|
||||||
|
put_unaligned(value, (U16*)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_write32(void* memPtr, U32 value)
|
||||||
|
{
|
||||||
|
put_unaligned(value, (U32*)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_write64(void* memPtr, U64 value)
|
||||||
|
{
|
||||||
|
put_unaligned(value, (U64*)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=== Little endian r/w ===*/
|
||||||
|
|
||||||
|
MEM_STATIC U16 MEM_readLE16(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_le16(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
|
||||||
|
{
|
||||||
|
put_unaligned_le16(val, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_readLE24(const void* memPtr)
|
||||||
|
{
|
||||||
|
return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
|
||||||
|
{
|
||||||
|
MEM_writeLE16(memPtr, (U16)val);
|
||||||
|
((BYTE*)memPtr)[2] = (BYTE)(val>>16);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_readLE32(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_le32(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
|
||||||
|
{
|
||||||
|
put_unaligned_le32(val32, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U64 MEM_readLE64(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_le64(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
|
||||||
|
{
|
||||||
|
put_unaligned_le64(val64, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t MEM_readLEST(const void* memPtr)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
return (size_t)MEM_readLE32(memPtr);
|
||||||
|
else
|
||||||
|
return (size_t)MEM_readLE64(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
MEM_writeLE32(memPtr, (U32)val);
|
||||||
|
else
|
||||||
|
MEM_writeLE64(memPtr, (U64)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=== Big endian r/w ===*/
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_readBE32(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_be32(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
|
||||||
|
{
|
||||||
|
put_unaligned_be32(val32, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U64 MEM_readBE64(const void* memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_be64(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
|
||||||
|
{
|
||||||
|
put_unaligned_be64(val64, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t MEM_readBEST(const void* memPtr)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
return (size_t)MEM_readBE32(memPtr);
|
||||||
|
else
|
||||||
|
return (size_t)MEM_readBE64(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
MEM_writeBE32(memPtr, (U32)val);
|
||||||
|
else
|
||||||
|
MEM_writeBE64(memPtr, (U64)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* function safe only for comparisons */
|
||||||
|
MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)
|
||||||
|
{
|
||||||
|
switch (length)
|
||||||
|
{
|
||||||
|
default :
|
||||||
|
case 4 : return MEM_read32(memPtr);
|
||||||
|
case 3 : if (MEM_isLittleEndian())
|
||||||
|
return MEM_read32(memPtr)<<8;
|
||||||
|
else
|
||||||
|
return MEM_read32(memPtr)>>8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MEM_H_MODULE */
|
700
contrib/linux-kernel/lib/zstd/xxhash.c
Normal file
700
contrib/linux-kernel/lib/zstd/xxhash.c
Normal file
@ -0,0 +1,700 @@
|
|||||||
|
/*
|
||||||
|
* xxHash - Fast Hash algorithm
|
||||||
|
* Copyright (C) 2012-2016, Yann Collet
|
||||||
|
*
|
||||||
|
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - xxHash homepage: http://www.xxhash.com
|
||||||
|
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Tuning parameters
|
||||||
|
***************************************/
|
||||||
|
/*!XXH_ACCEPT_NULL_INPUT_POINTER :
|
||||||
|
* If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
|
||||||
|
* When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
|
||||||
|
* By default, this option is disabled. To enable it, uncomment below define :
|
||||||
|
*/
|
||||||
|
/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
|
||||||
|
|
||||||
|
/*!XXH_FORCE_NATIVE_FORMAT :
|
||||||
|
* By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
|
||||||
|
* Results are therefore identical for little-endian and big-endian CPU.
|
||||||
|
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
|
||||||
|
* Should endian-independance be of no importance for your application, you may set the #define below to 1,
|
||||||
|
* to improve speed for Big-endian CPU.
|
||||||
|
* This option has no impact on Little_Endian CPU.
|
||||||
|
*/
|
||||||
|
#define XXH_FORCE_NATIVE_FORMAT 0
|
||||||
|
|
||||||
|
/*!XXH_FORCE_ALIGN_CHECK :
|
||||||
|
* This is a minor performance trick, only useful with lots of very small keys.
|
||||||
|
* It means : check for aligned/unaligned input.
|
||||||
|
* The check costs one initial branch per hash; set to 0 when the input data
|
||||||
|
* is guaranteed to be aligned.
|
||||||
|
*/
|
||||||
|
#define XXH_FORCE_ALIGN_CHECK 0
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Includes & Memory related functions
|
||||||
|
***************************************/
|
||||||
|
/* Modify the local functions below should you wish to use some other memory routines */
|
||||||
|
/* for memcpy() */
|
||||||
|
#include <linux/string.h>
|
||||||
|
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
|
||||||
|
|
||||||
|
#include "xxhash.h"
|
||||||
|
#include "mem.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Compiler Specific Options
|
||||||
|
***************************************/
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#define FORCE_INLINE static __always_inline
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Compiler-specific Functions and Macros
|
||||||
|
******************************************/
|
||||||
|
#define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||||
|
#define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Architecture Macros
|
||||||
|
***************************************/
|
||||||
|
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
|
||||||
|
|
||||||
|
/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
|
||||||
|
#ifndef XXH_CPU_LITTLE_ENDIAN
|
||||||
|
# define XXH_CPU_LITTLE_ENDIAN MEM_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ***************************
|
||||||
|
* Memory reads
|
||||||
|
*****************************/
|
||||||
|
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
|
||||||
|
|
||||||
|
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||||
|
{
|
||||||
|
(void)endian;
|
||||||
|
(void)align;
|
||||||
|
return MEM_readLE32(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
|
||||||
|
{
|
||||||
|
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32 XXH_readBE32(const void* ptr)
|
||||||
|
{
|
||||||
|
return MEM_readBE32(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||||
|
{
|
||||||
|
(void)endian;
|
||||||
|
(void)align;
|
||||||
|
return MEM_readLE64(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
|
||||||
|
{
|
||||||
|
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64 XXH_readBE64(const void* ptr)
|
||||||
|
{
|
||||||
|
return MEM_readBE64(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Macros
|
||||||
|
***************************************/
|
||||||
|
#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Constants
|
||||||
|
***************************************/
|
||||||
|
static const U32 PRIME32_1 = 2654435761U;
|
||||||
|
static const U32 PRIME32_2 = 2246822519U;
|
||||||
|
static const U32 PRIME32_3 = 3266489917U;
|
||||||
|
static const U32 PRIME32_4 = 668265263U;
|
||||||
|
static const U32 PRIME32_5 = 374761393U;
|
||||||
|
|
||||||
|
static const U64 PRIME64_1 = 11400714785074694791ULL;
|
||||||
|
static const U64 PRIME64_2 = 14029467366897019727ULL;
|
||||||
|
static const U64 PRIME64_3 = 1609587929392839161ULL;
|
||||||
|
static const U64 PRIME64_4 = 9650029242287828579ULL;
|
||||||
|
static const U64 PRIME64_5 = 2870177450012600261ULL;
|
||||||
|
|
||||||
|
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************
|
||||||
|
* Utils
|
||||||
|
****************************/
|
||||||
|
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
|
||||||
|
{
|
||||||
|
memcpy(dstState, srcState, sizeof(*dstState));
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
|
||||||
|
{
|
||||||
|
memcpy(dstState, srcState, sizeof(*dstState));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ***************************
|
||||||
|
* Simple Hash Functions
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
static U32 XXH32_round(U32 seed, U32 input)
|
||||||
|
{
|
||||||
|
seed += input * PRIME32_2;
|
||||||
|
seed = XXH_rotl32(seed, 13);
|
||||||
|
seed *= PRIME32_1;
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
|
||||||
|
{
|
||||||
|
const BYTE* p = (const BYTE*)input;
|
||||||
|
const BYTE* bEnd = p + len;
|
||||||
|
U32 h32;
|
||||||
|
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
|
||||||
|
|
||||||
|
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||||
|
if (p==NULL) {
|
||||||
|
len=0;
|
||||||
|
bEnd=p=(const BYTE*)(size_t)16;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (len>=16) {
|
||||||
|
const BYTE* const limit = bEnd - 16;
|
||||||
|
U32 v1 = seed + PRIME32_1 + PRIME32_2;
|
||||||
|
U32 v2 = seed + PRIME32_2;
|
||||||
|
U32 v3 = seed + 0;
|
||||||
|
U32 v4 = seed - PRIME32_1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
|
||||||
|
v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
|
||||||
|
v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
|
||||||
|
v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
|
||||||
|
} while (p<=limit);
|
||||||
|
|
||||||
|
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
|
||||||
|
} else {
|
||||||
|
h32 = seed + PRIME32_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 += (U32) len;
|
||||||
|
|
||||||
|
while (p+4<=bEnd) {
|
||||||
|
h32 += XXH_get32bits(p) * PRIME32_3;
|
||||||
|
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
|
||||||
|
p+=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p<bEnd) {
|
||||||
|
h32 += (*p) * PRIME32_5;
|
||||||
|
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 ^= h32 >> 15;
|
||||||
|
h32 *= PRIME32_2;
|
||||||
|
h32 ^= h32 >> 13;
|
||||||
|
h32 *= PRIME32_3;
|
||||||
|
h32 ^= h32 >> 16;
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||||
|
XXH32_CREATESTATE_STATIC(state);
|
||||||
|
XXH32_reset(state, seed);
|
||||||
|
XXH32_update(state, input, len);
|
||||||
|
return XXH32_digest(state);
|
||||||
|
#else
|
||||||
|
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||||
|
|
||||||
|
if (XXH_FORCE_ALIGN_CHECK) {
|
||||||
|
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||||
|
else
|
||||||
|
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||||
|
} }
|
||||||
|
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||||
|
else
|
||||||
|
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static U64 XXH64_round(U64 acc, U64 input)
|
||||||
|
{
|
||||||
|
acc += input * PRIME64_2;
|
||||||
|
acc = XXH_rotl64(acc, 31);
|
||||||
|
acc *= PRIME64_1;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64 XXH64_mergeRound(U64 acc, U64 val)
|
||||||
|
{
|
||||||
|
val = XXH64_round(0, val);
|
||||||
|
acc ^= val;
|
||||||
|
acc = acc * PRIME64_1 + PRIME64_4;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
|
||||||
|
{
|
||||||
|
const BYTE* p = (const BYTE*)input;
|
||||||
|
const BYTE* const bEnd = p + len;
|
||||||
|
U64 h64;
|
||||||
|
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
|
||||||
|
|
||||||
|
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||||
|
if (p==NULL) {
|
||||||
|
len=0;
|
||||||
|
bEnd=p=(const BYTE*)(size_t)32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (len>=32) {
|
||||||
|
const BYTE* const limit = bEnd - 32;
|
||||||
|
U64 v1 = seed + PRIME64_1 + PRIME64_2;
|
||||||
|
U64 v2 = seed + PRIME64_2;
|
||||||
|
U64 v3 = seed + 0;
|
||||||
|
U64 v4 = seed - PRIME64_1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
|
||||||
|
v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
|
||||||
|
v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
|
||||||
|
v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
|
||||||
|
} while (p<=limit);
|
||||||
|
|
||||||
|
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||||
|
h64 = XXH64_mergeRound(h64, v1);
|
||||||
|
h64 = XXH64_mergeRound(h64, v2);
|
||||||
|
h64 = XXH64_mergeRound(h64, v3);
|
||||||
|
h64 = XXH64_mergeRound(h64, v4);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
h64 = seed + PRIME64_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h64 += (U64) len;
|
||||||
|
|
||||||
|
while (p+8<=bEnd) {
|
||||||
|
U64 const k1 = XXH64_round(0, XXH_get64bits(p));
|
||||||
|
h64 ^= k1;
|
||||||
|
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||||
|
p+=8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p+4<=bEnd) {
|
||||||
|
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
|
||||||
|
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||||
|
p+=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p<bEnd) {
|
||||||
|
h64 ^= (*p) * PRIME64_5;
|
||||||
|
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
h64 ^= h64 >> 33;
|
||||||
|
h64 *= PRIME64_2;
|
||||||
|
h64 ^= h64 >> 29;
|
||||||
|
h64 *= PRIME64_3;
|
||||||
|
h64 ^= h64 >> 32;
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||||
|
XXH64_CREATESTATE_STATIC(state);
|
||||||
|
XXH64_reset(state, seed);
|
||||||
|
XXH64_update(state, input, len);
|
||||||
|
return XXH64_digest(state);
|
||||||
|
#else
|
||||||
|
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||||
|
|
||||||
|
if (XXH_FORCE_ALIGN_CHECK) {
|
||||||
|
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||||
|
else
|
||||||
|
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||||
|
} }
|
||||||
|
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||||
|
else
|
||||||
|
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************
|
||||||
|
* Advanced Hash Functions
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/*** Hash feed ***/
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
|
||||||
|
{
|
||||||
|
XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||||
|
memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
|
||||||
|
state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||||
|
state.v2 = seed + PRIME32_2;
|
||||||
|
state.v3 = seed + 0;
|
||||||
|
state.v4 = seed - PRIME32_1;
|
||||||
|
memcpy(statePtr, &state, sizeof(state));
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
|
||||||
|
{
|
||||||
|
XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||||
|
memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
|
||||||
|
state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||||
|
state.v2 = seed + PRIME64_2;
|
||||||
|
state.v3 = seed + 0;
|
||||||
|
state.v4 = seed - PRIME64_1;
|
||||||
|
memcpy(statePtr, &state, sizeof(state));
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||||
|
{
|
||||||
|
const BYTE* p = (const BYTE*)input;
|
||||||
|
const BYTE* const bEnd = p + len;
|
||||||
|
|
||||||
|
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||||
|
if (input==NULL) return XXH_ERROR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
state->total_len_32 += (unsigned)len;
|
||||||
|
state->large_len |= (len>=16) | (state->total_len_32>=16);
|
||||||
|
|
||||||
|
if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||||
|
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
|
||||||
|
state->memsize += (unsigned)len;
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->memsize) { /* some data left from previous update */
|
||||||
|
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
|
||||||
|
{ const U32* p32 = state->mem32;
|
||||||
|
state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
|
||||||
|
state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
|
||||||
|
state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
|
||||||
|
state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
|
||||||
|
}
|
||||||
|
p += 16-state->memsize;
|
||||||
|
state->memsize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p <= bEnd-16) {
|
||||||
|
const BYTE* const limit = bEnd - 16;
|
||||||
|
U32 v1 = state->v1;
|
||||||
|
U32 v2 = state->v2;
|
||||||
|
U32 v3 = state->v3;
|
||||||
|
U32 v4 = state->v4;
|
||||||
|
|
||||||
|
do {
|
||||||
|
v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
|
||||||
|
v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
|
||||||
|
v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
|
||||||
|
v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
|
||||||
|
} while (p<=limit);
|
||||||
|
|
||||||
|
state->v1 = v1;
|
||||||
|
state->v2 = v2;
|
||||||
|
state->v3 = v3;
|
||||||
|
state->v4 = v4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p < bEnd) {
|
||||||
|
XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
|
||||||
|
state->memsize = (unsigned)(bEnd-p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
|
||||||
|
{
|
||||||
|
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||||
|
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
|
||||||
|
else
|
||||||
|
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
|
||||||
|
{
|
||||||
|
const BYTE * p = (const BYTE*)state->mem32;
|
||||||
|
const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
|
||||||
|
U32 h32;
|
||||||
|
|
||||||
|
if (state->large_len) {
|
||||||
|
h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
|
||||||
|
} else {
|
||||||
|
h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 += state->total_len_32;
|
||||||
|
|
||||||
|
while (p+4<=bEnd) {
|
||||||
|
h32 += XXH_readLE32(p, endian) * PRIME32_3;
|
||||||
|
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
|
||||||
|
p+=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p<bEnd) {
|
||||||
|
h32 += (*p) * PRIME32_5;
|
||||||
|
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
h32 ^= h32 >> 15;
|
||||||
|
h32 *= PRIME32_2;
|
||||||
|
h32 ^= h32 >> 13;
|
||||||
|
h32 *= PRIME32_3;
|
||||||
|
h32 ^= h32 >> 16;
|
||||||
|
|
||||||
|
return h32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
|
||||||
|
{
|
||||||
|
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||||
|
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH32_digest_endian(state_in, XXH_littleEndian);
|
||||||
|
else
|
||||||
|
return XXH32_digest_endian(state_in, XXH_bigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* **** XXH64 **** */
|
||||||
|
|
||||||
|
FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||||
|
{
|
||||||
|
const BYTE* p = (const BYTE*)input;
|
||||||
|
const BYTE* const bEnd = p + len;
|
||||||
|
|
||||||
|
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||||
|
if (input==NULL) return XXH_ERROR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
state->total_len += len;
|
||||||
|
|
||||||
|
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||||
|
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||||
|
state->memsize += (U32)len;
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->memsize) { /* tmp buffer is full */
|
||||||
|
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
|
||||||
|
state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
|
||||||
|
state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
|
||||||
|
state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
|
||||||
|
state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
|
||||||
|
p += 32-state->memsize;
|
||||||
|
state->memsize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p+32 <= bEnd) {
|
||||||
|
const BYTE* const limit = bEnd - 32;
|
||||||
|
U64 v1 = state->v1;
|
||||||
|
U64 v2 = state->v2;
|
||||||
|
U64 v3 = state->v3;
|
||||||
|
U64 v4 = state->v4;
|
||||||
|
|
||||||
|
do {
|
||||||
|
v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
|
||||||
|
v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
|
||||||
|
v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
|
||||||
|
v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
|
||||||
|
} while (p<=limit);
|
||||||
|
|
||||||
|
state->v1 = v1;
|
||||||
|
state->v2 = v2;
|
||||||
|
state->v3 = v3;
|
||||||
|
state->v4 = v4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p < bEnd) {
|
||||||
|
XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
|
||||||
|
state->memsize = (unsigned)(bEnd-p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
|
||||||
|
{
|
||||||
|
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||||
|
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
|
||||||
|
else
|
||||||
|
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
|
||||||
|
{
|
||||||
|
const BYTE * p = (const BYTE*)state->mem64;
|
||||||
|
const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
|
||||||
|
U64 h64;
|
||||||
|
|
||||||
|
if (state->total_len >= 32) {
|
||||||
|
U64 const v1 = state->v1;
|
||||||
|
U64 const v2 = state->v2;
|
||||||
|
U64 const v3 = state->v3;
|
||||||
|
U64 const v4 = state->v4;
|
||||||
|
|
||||||
|
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||||
|
h64 = XXH64_mergeRound(h64, v1);
|
||||||
|
h64 = XXH64_mergeRound(h64, v2);
|
||||||
|
h64 = XXH64_mergeRound(h64, v3);
|
||||||
|
h64 = XXH64_mergeRound(h64, v4);
|
||||||
|
} else {
|
||||||
|
h64 = state->v3 + PRIME64_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h64 += (U64) state->total_len;
|
||||||
|
|
||||||
|
while (p+8<=bEnd) {
|
||||||
|
U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
|
||||||
|
h64 ^= k1;
|
||||||
|
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||||
|
p+=8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p+4<=bEnd) {
|
||||||
|
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
|
||||||
|
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||||
|
p+=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p<bEnd) {
|
||||||
|
h64 ^= (*p) * PRIME64_5;
|
||||||
|
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
h64 ^= h64 >> 33;
|
||||||
|
h64 *= PRIME64_2;
|
||||||
|
h64 ^= h64 >> 29;
|
||||||
|
h64 *= PRIME64_3;
|
||||||
|
h64 ^= h64 >> 32;
|
||||||
|
|
||||||
|
return h64;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
|
||||||
|
{
|
||||||
|
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||||
|
|
||||||
|
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||||
|
return XXH64_digest_endian(state_in, XXH_littleEndian);
|
||||||
|
else
|
||||||
|
return XXH64_digest_endian(state_in, XXH_bigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************
|
||||||
|
* Canonical representation
|
||||||
|
****************************/
|
||||||
|
|
||||||
|
/*! Default XXH result types are basic unsigned 32 and 64 bits.
|
||||||
|
* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
|
||||||
|
* These functions allow transformation of hash result into and from its canonical format.
|
||||||
|
* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
|
||||||
|
{
|
||||||
|
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
|
||||||
|
MEM_writeBE32(dst, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
|
||||||
|
{
|
||||||
|
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
|
||||||
|
MEM_writeBE64(dst, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
|
||||||
|
{
|
||||||
|
return XXH_readBE32(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
|
||||||
|
{
|
||||||
|
return XXH_readBE64(src);
|
||||||
|
}
|
235
contrib/linux-kernel/lib/zstd/xxhash.h
Normal file
235
contrib/linux-kernel/lib/zstd/xxhash.h
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
xxHash - Extremely Fast Hash algorithm
|
||||||
|
Header File
|
||||||
|
Copyright (C) 2012-2016, Yann Collet.
|
||||||
|
|
||||||
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
You can contact the author at :
|
||||||
|
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Notice extracted from xxHash homepage :
|
||||||
|
|
||||||
|
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||||
|
It also successfully passes all tests from the SMHasher suite.
|
||||||
|
|
||||||
|
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||||
|
|
||||||
|
Name Speed Q.Score Author
|
||||||
|
xxHash 5.4 GB/s 10
|
||||||
|
CrapWow 3.2 GB/s 2 Andrew
|
||||||
|
MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||||
|
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||||
|
SBox 1.4 GB/s 9 Bret Mulvey
|
||||||
|
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||||
|
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||||
|
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||||
|
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||||
|
CRC32 0.43 GB/s 9
|
||||||
|
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||||
|
SHA1-32 0.28 GB/s 10
|
||||||
|
|
||||||
|
Q.Score is a measure of quality of the hash function.
|
||||||
|
It depends on successfully passing SMHasher test set.
|
||||||
|
10 is a perfect score.
|
||||||
|
|
||||||
|
A 64-bits version, named XXH64, is available since r35.
|
||||||
|
It offers much better speed, but for 64-bits applications only.
|
||||||
|
Name Speed on 64 bits Speed on 32 bits
|
||||||
|
XXH64 13.8 GB/s 1.9 GB/s
|
||||||
|
XXH32 6.8 GB/s 6.0 GB/s
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XXHASH_H_5627135585666179
|
||||||
|
#define XXHASH_H_5627135585666179 1
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************
|
||||||
|
* Definitions
|
||||||
|
******************************/
|
||||||
|
#include <linux/types.h> /* size_t */
|
||||||
|
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************
|
||||||
|
* API modifier
|
||||||
|
******************************/
|
||||||
|
/** XXH_PRIVATE_API
|
||||||
|
* This is useful if you want to include xxhash functions in `static` mode
|
||||||
|
* in order to inline them, and remove their symbol from the public list.
|
||||||
|
* Methodology :
|
||||||
|
* #define XXH_PRIVATE_API
|
||||||
|
* #include "xxhash.h"
|
||||||
|
* `xxhash.c` is automatically included.
|
||||||
|
* It's not useful to compile and link it as a separate module anymore.
|
||||||
|
*/
|
||||||
|
#define XXH_PUBLIC_API /* do nothing */
|
||||||
|
|
||||||
|
/*!XXH_NAMESPACE, aka Namespace Emulation :
|
||||||
|
|
||||||
|
If you want to include _and expose_ xxHash functions from within your own library,
|
||||||
|
but also want to avoid symbol collisions with another library which also includes xxHash,
|
||||||
|
|
||||||
|
you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
|
||||||
|
with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).
|
||||||
|
|
||||||
|
Note that no change is required within the calling program as long as it includes `xxhash.h` :
|
||||||
|
regular symbol name will be automatically translated by this header.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Version
|
||||||
|
***************************************/
|
||||||
|
#define XXH_VERSION_MAJOR 0
|
||||||
|
#define XXH_VERSION_MINOR 6
|
||||||
|
#define XXH_VERSION_RELEASE 2
|
||||||
|
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||||
|
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************
|
||||||
|
* Simple Hash Functions
|
||||||
|
******************************/
|
||||||
|
typedef unsigned int XXH32_hash_t;
|
||||||
|
typedef unsigned long long XXH64_hash_t;
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
XXH32() :
|
||||||
|
Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
|
||||||
|
The memory between input & input+length must be valid (allocated and read-accessible).
|
||||||
|
"seed" can be used to alter the result predictably.
|
||||||
|
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||||
|
XXH64() :
|
||||||
|
Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
|
||||||
|
"seed" can be used to alter the result predictably.
|
||||||
|
This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************
|
||||||
|
* Streaming Hash Functions
|
||||||
|
******************************/
|
||||||
|
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
|
||||||
|
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
|
||||||
|
|
||||||
|
|
||||||
|
/* hash streaming */
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||||
|
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
These functions generate the xxHash of an input provided in multiple segments.
|
||||||
|
Note that, for small input, they are slower than single-call functions, due to state management.
|
||||||
|
For small input, prefer `XXH32()` and `XXH64()` .
|
||||||
|
|
||||||
|
XXH state must first be allocated, using XXH*_createState() .
|
||||||
|
|
||||||
|
Start a new hash by initializing state with a seed, using XXH*_reset().
|
||||||
|
|
||||||
|
Then, feed the hash state by calling XXH*_update() as many times as necessary.
|
||||||
|
Obviously, input must be allocated and read accessible.
|
||||||
|
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
||||||
|
|
||||||
|
Finally, a hash value can be produced anytime, by using XXH*_digest().
|
||||||
|
This function returns the nn-bits hash as an int or long long.
|
||||||
|
|
||||||
|
It's still possible to continue inserting input into the hash state after a digest,
|
||||||
|
and generate some new hashes later on, by calling again XXH*_digest().
|
||||||
|
|
||||||
|
When done, free XXH state space if it was allocated dynamically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************
|
||||||
|
* Utils
|
||||||
|
****************************/
|
||||||
|
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
|
||||||
|
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************
|
||||||
|
* Canonical representation
|
||||||
|
****************************/
|
||||||
|
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
|
||||||
|
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
|
||||||
|
* These functions allow transformation of hash result into and from its canonical format.
|
||||||
|
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
|
||||||
|
*/
|
||||||
|
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
|
||||||
|
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
|
||||||
|
|
||||||
|
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
|
||||||
|
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
|
||||||
|
|
||||||
|
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================================================================
|
||||||
|
This section contains definitions which are not guaranteed to remain stable.
|
||||||
|
They may change in future versions, becoming incompatible with a different version of the library.
|
||||||
|
They shall only be used with static linking.
|
||||||
|
Never use these definitions in association with dynamic linking !
|
||||||
|
=================================================================================================== */
|
||||||
|
/* These definitions are only meant to allow allocation of XXH state
|
||||||
|
statically, on stack, or in a struct for example.
|
||||||
|
Do not use members directly. */
|
||||||
|
|
||||||
|
struct XXH32_state_s {
|
||||||
|
unsigned total_len_32;
|
||||||
|
unsigned large_len;
|
||||||
|
unsigned v1;
|
||||||
|
unsigned v2;
|
||||||
|
unsigned v3;
|
||||||
|
unsigned v4;
|
||||||
|
unsigned mem32[4]; /* buffer defined as U32 for alignment */
|
||||||
|
unsigned memsize;
|
||||||
|
unsigned reserved; /* never read nor write, will be removed in a future version */
|
||||||
|
}; /* typedef'd to XXH32_state_t */
|
||||||
|
|
||||||
|
struct XXH64_state_s {
|
||||||
|
unsigned long long total_len;
|
||||||
|
unsigned long long v1;
|
||||||
|
unsigned long long v2;
|
||||||
|
unsigned long long v3;
|
||||||
|
unsigned long long v4;
|
||||||
|
unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
|
||||||
|
unsigned memsize;
|
||||||
|
unsigned reserved[2]; /* never read nor write, will be removed in a future version */
|
||||||
|
}; /* typedef'd to XXH64_state_t */
|
||||||
|
|
||||||
|
#endif /* XXHASH_H_5627135585666179 */
|
69
contrib/linux-kernel/lib/zstd/zstd_common.c
Normal file
69
contrib/linux-kernel/lib/zstd/zstd_common.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#include "error_private.h"
|
||||||
|
#include "zstd_internal.h" /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*=**************************************************************
|
||||||
|
* Custom allocator
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
#define stack_push(stack, size) ({ \
|
||||||
|
void* const ptr = ZSTD_PTR_ALIGN((stack)->ptr); \
|
||||||
|
(stack)->ptr = (char*)ptr + (size); \
|
||||||
|
(stack)->ptr <= (stack)->end ? ptr : NULL; \
|
||||||
|
})
|
||||||
|
|
||||||
|
ZSTD_customMem ZSTD_initStack(void* workspace, size_t workspaceSize) {
|
||||||
|
ZSTD_customMem stackMem = { ZSTD_stackAlloc, ZSTD_stackFree, workspace };
|
||||||
|
ZSTD_stack* stack = (ZSTD_stack*) workspace;
|
||||||
|
/* Verify preconditions */
|
||||||
|
if (!workspace || workspaceSize < sizeof(ZSTD_stack) || workspace != ZSTD_PTR_ALIGN(workspace)) {
|
||||||
|
ZSTD_customMem error = {NULL, NULL, NULL};
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
/* Initialize the stack */
|
||||||
|
stack->ptr = workspace;
|
||||||
|
stack->end = (char*)workspace + workspaceSize;
|
||||||
|
stack_push(stack, sizeof(ZSTD_stack));
|
||||||
|
return stackMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ZSTD_stackAllocAll(void* opaque, size_t* size) {
|
||||||
|
ZSTD_stack* stack = (ZSTD_stack*)opaque;
|
||||||
|
*size = stack->end - ZSTD_PTR_ALIGN(stack->ptr);
|
||||||
|
return stack_push(stack, *size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ZSTD_stackAlloc(void* opaque, size_t size) {
|
||||||
|
ZSTD_stack* stack = (ZSTD_stack*)opaque;
|
||||||
|
return stack_push(stack, size);
|
||||||
|
}
|
||||||
|
void ZSTD_stackFree(void* opaque, void* address) {
|
||||||
|
(void)opaque;
|
||||||
|
(void)address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
return customMem.customAlloc(customMem.opaque, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSTD_free(void* ptr, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if (ptr!=NULL)
|
||||||
|
customMem.customFree(customMem.opaque, ptr);
|
||||||
|
}
|
274
contrib/linux-kernel/lib/zstd/zstd_internal.h
Normal file
274
contrib/linux-kernel/lib/zstd/zstd_internal.h
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_CCOMMON_H_MODULE
|
||||||
|
#define ZSTD_CCOMMON_H_MODULE
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Compiler specifics
|
||||||
|
*********************************************************/
|
||||||
|
#define FORCE_INLINE static __always_inline
|
||||||
|
#define FORCE_NOINLINE static noinline
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/zstd.h>
|
||||||
|
#include "mem.h"
|
||||||
|
#include "error_private.h"
|
||||||
|
#include "xxhash.h" /* XXH_reset, update, digest */
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* shared macros
|
||||||
|
***************************************/
|
||||||
|
#define MIN(a,b) ((a)<(b) ? (a) : (b))
|
||||||
|
#define MAX(a,b) ((a)>(b) ? (a) : (b))
|
||||||
|
#define CHECK_F(f) { size_t const errcod = f; if (ERR_isError(errcod)) return errcod; } /* check and Forward error code */
|
||||||
|
#define CHECK_E(f, e) { size_t const errcod = f; if (ERR_isError(errcod)) return ERROR(e); } /* check and send Error code */
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Common constants
|
||||||
|
***************************************/
|
||||||
|
#define ZSTD_OPT_NUM (1<<12)
|
||||||
|
#define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */
|
||||||
|
|
||||||
|
#define ZSTD_REP_NUM 3 /* number of repcodes */
|
||||||
|
#define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */
|
||||||
|
#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1)
|
||||||
|
#define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)
|
||||||
|
static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
|
||||||
|
|
||||||
|
#define KB *(1 <<10)
|
||||||
|
#define MB *(1 <<20)
|
||||||
|
#define GB *(1U<<30)
|
||||||
|
|
||||||
|
#define BIT7 128
|
||||||
|
#define BIT6 64
|
||||||
|
#define BIT5 32
|
||||||
|
#define BIT4 16
|
||||||
|
#define BIT1 2
|
||||||
|
#define BIT0 1
|
||||||
|
|
||||||
|
#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
|
||||||
|
static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
|
||||||
|
static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
|
||||||
|
|
||||||
|
#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
|
||||||
|
static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
|
||||||
|
typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
|
||||||
|
|
||||||
|
#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
|
||||||
|
#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
|
||||||
|
|
||||||
|
#define HufLog 12
|
||||||
|
typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
|
||||||
|
|
||||||
|
#define LONGNBSEQ 0x7F00
|
||||||
|
|
||||||
|
#define MINMATCH 3
|
||||||
|
#define EQUAL_READ32 4
|
||||||
|
|
||||||
|
#define Litbits 8
|
||||||
|
#define MaxLit ((1<<Litbits) - 1)
|
||||||
|
#define MaxML 52
|
||||||
|
#define MaxLL 35
|
||||||
|
#define MaxOff 28
|
||||||
|
#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
|
||||||
|
#define MLFSELog 9
|
||||||
|
#define LLFSELog 9
|
||||||
|
#define OffFSELog 8
|
||||||
|
|
||||||
|
static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9,10,11,12,
|
||||||
|
13,14,15,16 };
|
||||||
|
static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
|
||||||
|
-1,-1,-1,-1 };
|
||||||
|
#define LL_DEFAULTNORMLOG 6 /* for static allocation */
|
||||||
|
static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
|
||||||
|
|
||||||
|
static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9,10,11,
|
||||||
|
12,13,14,15,16 };
|
||||||
|
static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,
|
||||||
|
-1,-1,-1,-1,-1 };
|
||||||
|
#define ML_DEFAULTNORMLOG 6 /* for static allocation */
|
||||||
|
static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
|
||||||
|
|
||||||
|
static const S16 OF_defaultNorm[MaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 };
|
||||||
|
#define OF_DEFAULTNORMLOG 5 /* for static allocation */
|
||||||
|
static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************
|
||||||
|
* Shared functions to include for inlining
|
||||||
|
*********************************************/
|
||||||
|
static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
|
||||||
|
#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
|
||||||
|
|
||||||
|
/*! ZSTD_wildcopy() :
|
||||||
|
* custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
|
||||||
|
#define WILDCOPY_OVERLENGTH 8
|
||||||
|
MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*)src;
|
||||||
|
BYTE* op = (BYTE*)dst;
|
||||||
|
BYTE* const oend = op + length;
|
||||||
|
do
|
||||||
|
COPY8(op, ip)
|
||||||
|
while (op < oend);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void ZSTD_wildcopy_e(void* dst, const void* src, void* dstEnd) /* should be faster for decoding, but strangely, not verified on all platform */
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*)src;
|
||||||
|
BYTE* op = (BYTE*)dst;
|
||||||
|
BYTE* const oend = (BYTE*)dstEnd;
|
||||||
|
do
|
||||||
|
COPY8(op, ip)
|
||||||
|
while (op < oend);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************
|
||||||
|
* Private interfaces
|
||||||
|
*********************************************/
|
||||||
|
typedef struct ZSTD_stats_s ZSTD_stats_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 off;
|
||||||
|
U32 len;
|
||||||
|
} ZSTD_match_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 price;
|
||||||
|
U32 off;
|
||||||
|
U32 mlen;
|
||||||
|
U32 litlen;
|
||||||
|
U32 rep[ZSTD_REP_NUM];
|
||||||
|
} ZSTD_optimal_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct seqDef_s {
|
||||||
|
U32 offset;
|
||||||
|
U16 litLength;
|
||||||
|
U16 matchLength;
|
||||||
|
} seqDef;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
seqDef* sequencesStart;
|
||||||
|
seqDef* sequences;
|
||||||
|
BYTE* litStart;
|
||||||
|
BYTE* lit;
|
||||||
|
BYTE* llCode;
|
||||||
|
BYTE* mlCode;
|
||||||
|
BYTE* ofCode;
|
||||||
|
U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
|
||||||
|
U32 longLengthPos;
|
||||||
|
/* opt */
|
||||||
|
ZSTD_optimal_t* priceTable;
|
||||||
|
ZSTD_match_t* matchTable;
|
||||||
|
U32* matchLengthFreq;
|
||||||
|
U32* litLengthFreq;
|
||||||
|
U32* litFreq;
|
||||||
|
U32* offCodeFreq;
|
||||||
|
U32 matchLengthSum;
|
||||||
|
U32 matchSum;
|
||||||
|
U32 litLengthSum;
|
||||||
|
U32 litSum;
|
||||||
|
U32 offCodeSum;
|
||||||
|
U32 log2matchLengthSum;
|
||||||
|
U32 log2matchSum;
|
||||||
|
U32 log2litLengthSum;
|
||||||
|
U32 log2litSum;
|
||||||
|
U32 log2offCodeSum;
|
||||||
|
U32 factor;
|
||||||
|
U32 staticPrices;
|
||||||
|
U32 cachedPrice;
|
||||||
|
U32 cachedLitLength;
|
||||||
|
const BYTE* cachedLiterals;
|
||||||
|
} seqStore_t;
|
||||||
|
|
||||||
|
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx);
|
||||||
|
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr);
|
||||||
|
int ZSTD_isSkipFrame(ZSTD_DCtx* dctx);
|
||||||
|
|
||||||
|
/*= Custom memory allocation functions */
|
||||||
|
typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
|
||||||
|
typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
|
||||||
|
typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
|
||||||
|
|
||||||
|
void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
|
||||||
|
void ZSTD_free(void* ptr, ZSTD_customMem customMem);
|
||||||
|
|
||||||
|
/*====== stack allocation ======*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void* ptr;
|
||||||
|
const void* end;
|
||||||
|
} ZSTD_stack;
|
||||||
|
|
||||||
|
#define ZSTD_ALIGN(x) ALIGN(x, sizeof(size_t))
|
||||||
|
#define ZSTD_PTR_ALIGN(p) PTR_ALIGN(p, sizeof(size_t))
|
||||||
|
|
||||||
|
ZSTD_customMem ZSTD_initStack(void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
void* ZSTD_stackAllocAll(void* opaque, size_t* size);
|
||||||
|
void* ZSTD_stackAlloc(void* opaque, size_t size);
|
||||||
|
void ZSTD_stackFree(void* opaque, void* address);
|
||||||
|
|
||||||
|
|
||||||
|
/*====== common function ======*/
|
||||||
|
|
||||||
|
MEM_STATIC U32 ZSTD_highbit32(U32 val)
|
||||||
|
{
|
||||||
|
# if defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
|
||||||
|
return 31 - __builtin_clz(val);
|
||||||
|
# else /* Software version */
|
||||||
|
static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
|
||||||
|
U32 v = val;
|
||||||
|
int r;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
|
||||||
|
return r;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* hidden functions */
|
||||||
|
|
||||||
|
/* ZSTD_invalidateRepCodes() :
|
||||||
|
* ensures next compression will not use repcodes from previous block.
|
||||||
|
* Note : only works with regular variant;
|
||||||
|
* do not use with extDict variant ! */
|
||||||
|
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx);
|
||||||
|
|
||||||
|
size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx);
|
||||||
|
size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
|
||||||
|
size_t ZSTD_freeCDict(ZSTD_CDict* cdict);
|
||||||
|
size_t ZSTD_freeDDict(ZSTD_DDict* cdict);
|
||||||
|
size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
|
||||||
|
size_t ZSTD_freeDStream(ZSTD_DStream* zds);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_CCOMMON_H_MODULE */
|
921
contrib/linux-kernel/lib/zstd/zstd_opt.h
Normal file
921
contrib/linux-kernel/lib/zstd/zstd_opt.h
Normal file
@ -0,0 +1,921 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Note : this file is intended to be included within zstd_compress.c */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ZSTD_OPT_H_91842398743
|
||||||
|
#define ZSTD_OPT_H_91842398743
|
||||||
|
|
||||||
|
|
||||||
|
#define ZSTD_LITFREQ_ADD 2
|
||||||
|
#define ZSTD_FREQ_DIV 4
|
||||||
|
#define ZSTD_MAX_PRICE (1<<30)
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Price functions for optimal parser
|
||||||
|
***************************************/
|
||||||
|
FORCE_INLINE void ZSTD_setLog2Prices(seqStore_t* ssPtr)
|
||||||
|
{
|
||||||
|
ssPtr->log2matchLengthSum = ZSTD_highbit32(ssPtr->matchLengthSum+1);
|
||||||
|
ssPtr->log2litLengthSum = ZSTD_highbit32(ssPtr->litLengthSum+1);
|
||||||
|
ssPtr->log2litSum = ZSTD_highbit32(ssPtr->litSum+1);
|
||||||
|
ssPtr->log2offCodeSum = ZSTD_highbit32(ssPtr->offCodeSum+1);
|
||||||
|
ssPtr->factor = 1 + ((ssPtr->litSum>>5) / ssPtr->litLengthSum) + ((ssPtr->litSum<<1) / (ssPtr->litSum + ssPtr->matchSum));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MEM_STATIC void ZSTD_rescaleFreqs(seqStore_t* ssPtr, const BYTE* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
unsigned u;
|
||||||
|
|
||||||
|
ssPtr->cachedLiterals = NULL;
|
||||||
|
ssPtr->cachedPrice = ssPtr->cachedLitLength = 0;
|
||||||
|
ssPtr->staticPrices = 0;
|
||||||
|
|
||||||
|
if (ssPtr->litLengthSum == 0) {
|
||||||
|
if (srcSize <= 1024) ssPtr->staticPrices = 1;
|
||||||
|
|
||||||
|
for (u=0; u<=MaxLit; u++)
|
||||||
|
ssPtr->litFreq[u] = 0;
|
||||||
|
for (u=0; u<srcSize; u++)
|
||||||
|
ssPtr->litFreq[src[u]]++;
|
||||||
|
|
||||||
|
ssPtr->litSum = 0;
|
||||||
|
ssPtr->litLengthSum = MaxLL+1;
|
||||||
|
ssPtr->matchLengthSum = MaxML+1;
|
||||||
|
ssPtr->offCodeSum = (MaxOff+1);
|
||||||
|
ssPtr->matchSum = (ZSTD_LITFREQ_ADD<<Litbits);
|
||||||
|
|
||||||
|
for (u=0; u<=MaxLit; u++) {
|
||||||
|
ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u]>>ZSTD_FREQ_DIV);
|
||||||
|
ssPtr->litSum += ssPtr->litFreq[u];
|
||||||
|
}
|
||||||
|
for (u=0; u<=MaxLL; u++)
|
||||||
|
ssPtr->litLengthFreq[u] = 1;
|
||||||
|
for (u=0; u<=MaxML; u++)
|
||||||
|
ssPtr->matchLengthFreq[u] = 1;
|
||||||
|
for (u=0; u<=MaxOff; u++)
|
||||||
|
ssPtr->offCodeFreq[u] = 1;
|
||||||
|
} else {
|
||||||
|
ssPtr->matchLengthSum = 0;
|
||||||
|
ssPtr->litLengthSum = 0;
|
||||||
|
ssPtr->offCodeSum = 0;
|
||||||
|
ssPtr->matchSum = 0;
|
||||||
|
ssPtr->litSum = 0;
|
||||||
|
|
||||||
|
for (u=0; u<=MaxLit; u++) {
|
||||||
|
ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
|
||||||
|
ssPtr->litSum += ssPtr->litFreq[u];
|
||||||
|
}
|
||||||
|
for (u=0; u<=MaxLL; u++) {
|
||||||
|
ssPtr->litLengthFreq[u] = 1 + (ssPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
|
||||||
|
ssPtr->litLengthSum += ssPtr->litLengthFreq[u];
|
||||||
|
}
|
||||||
|
for (u=0; u<=MaxML; u++) {
|
||||||
|
ssPtr->matchLengthFreq[u] = 1 + (ssPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
|
||||||
|
ssPtr->matchLengthSum += ssPtr->matchLengthFreq[u];
|
||||||
|
ssPtr->matchSum += ssPtr->matchLengthFreq[u] * (u + 3);
|
||||||
|
}
|
||||||
|
ssPtr->matchSum *= ZSTD_LITFREQ_ADD;
|
||||||
|
for (u=0; u<=MaxOff; u++) {
|
||||||
|
ssPtr->offCodeFreq[u] = 1 + (ssPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
|
||||||
|
ssPtr->offCodeSum += ssPtr->offCodeFreq[u];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_setLog2Prices(ssPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* ssPtr, U32 litLength, const BYTE* literals)
|
||||||
|
{
|
||||||
|
U32 price, u;
|
||||||
|
|
||||||
|
if (ssPtr->staticPrices)
|
||||||
|
return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
|
||||||
|
|
||||||
|
if (litLength == 0)
|
||||||
|
return ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[0]+1);
|
||||||
|
|
||||||
|
/* literals */
|
||||||
|
if (ssPtr->cachedLiterals == literals) {
|
||||||
|
U32 const additional = litLength - ssPtr->cachedLitLength;
|
||||||
|
const BYTE* literals2 = ssPtr->cachedLiterals + ssPtr->cachedLitLength;
|
||||||
|
price = ssPtr->cachedPrice + additional * ssPtr->log2litSum;
|
||||||
|
for (u=0; u < additional; u++)
|
||||||
|
price -= ZSTD_highbit32(ssPtr->litFreq[literals2[u]]+1);
|
||||||
|
ssPtr->cachedPrice = price;
|
||||||
|
ssPtr->cachedLitLength = litLength;
|
||||||
|
} else {
|
||||||
|
price = litLength * ssPtr->log2litSum;
|
||||||
|
for (u=0; u < litLength; u++)
|
||||||
|
price -= ZSTD_highbit32(ssPtr->litFreq[literals[u]]+1);
|
||||||
|
|
||||||
|
if (litLength >= 12) {
|
||||||
|
ssPtr->cachedLiterals = literals;
|
||||||
|
ssPtr->cachedPrice = price;
|
||||||
|
ssPtr->cachedLitLength = litLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* literal Length */
|
||||||
|
{ const BYTE LL_deltaCode = 19;
|
||||||
|
const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
|
||||||
|
price += LL_bits[llCode] + ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[llCode]+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
|
||||||
|
{
|
||||||
|
/* offset */
|
||||||
|
U32 price;
|
||||||
|
BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
|
||||||
|
|
||||||
|
if (seqStorePtr->staticPrices)
|
||||||
|
return ZSTD_getLiteralPrice(seqStorePtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
|
||||||
|
|
||||||
|
price = offCode + seqStorePtr->log2offCodeSum - ZSTD_highbit32(seqStorePtr->offCodeFreq[offCode]+1);
|
||||||
|
if (!ultra && offCode >= 20) price += (offCode-19)*2;
|
||||||
|
|
||||||
|
/* match Length */
|
||||||
|
{ const BYTE ML_deltaCode = 36;
|
||||||
|
const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
|
||||||
|
price += ML_bits[mlCode] + seqStorePtr->log2matchLengthSum - ZSTD_highbit32(seqStorePtr->matchLengthFreq[mlCode]+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return price + ZSTD_getLiteralPrice(seqStorePtr, litLength, literals) + seqStorePtr->factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
|
||||||
|
{
|
||||||
|
U32 u;
|
||||||
|
|
||||||
|
/* literals */
|
||||||
|
seqStorePtr->litSum += litLength*ZSTD_LITFREQ_ADD;
|
||||||
|
for (u=0; u < litLength; u++)
|
||||||
|
seqStorePtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
|
||||||
|
|
||||||
|
/* literal Length */
|
||||||
|
{ const BYTE LL_deltaCode = 19;
|
||||||
|
const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
|
||||||
|
seqStorePtr->litLengthFreq[llCode]++;
|
||||||
|
seqStorePtr->litLengthSum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* match offset */
|
||||||
|
{ BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
|
||||||
|
seqStorePtr->offCodeSum++;
|
||||||
|
seqStorePtr->offCodeFreq[offCode]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* match Length */
|
||||||
|
{ const BYTE ML_deltaCode = 36;
|
||||||
|
const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
|
||||||
|
seqStorePtr->matchLengthFreq[mlCode]++;
|
||||||
|
seqStorePtr->matchLengthSum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_setLog2Prices(seqStorePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \
|
||||||
|
{ \
|
||||||
|
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
|
||||||
|
opt[pos].mlen = mlen_; \
|
||||||
|
opt[pos].off = offset_; \
|
||||||
|
opt[pos].litlen = litlen_; \
|
||||||
|
opt[pos].price = price_; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Update hashTable3 up to ip (excluded)
|
||||||
|
Assumption : always within prefix (i.e. not within extDict) */
|
||||||
|
FORCE_INLINE
|
||||||
|
U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
|
||||||
|
{
|
||||||
|
U32* const hashTable3 = zc->hashTable3;
|
||||||
|
U32 const hashLog3 = zc->hashLog3;
|
||||||
|
const BYTE* const base = zc->base;
|
||||||
|
U32 idx = zc->nextToUpdate3;
|
||||||
|
const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
|
||||||
|
const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
|
||||||
|
|
||||||
|
while(idx < target) {
|
||||||
|
hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashTable3[hash3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Binary Tree search
|
||||||
|
***************************************/
|
||||||
|
static U32 ZSTD_insertBtAndGetAllMatches (
|
||||||
|
ZSTD_CCtx* zc,
|
||||||
|
const BYTE* const ip, const BYTE* const iLimit,
|
||||||
|
U32 nbCompares, const U32 mls,
|
||||||
|
U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||||
|
{
|
||||||
|
const BYTE* const base = zc->base;
|
||||||
|
const U32 current = (U32)(ip-base);
|
||||||
|
const U32 hashLog = zc->params.cParams.hashLog;
|
||||||
|
const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||||
|
U32* const hashTable = zc->hashTable;
|
||||||
|
U32 matchIndex = hashTable[h];
|
||||||
|
U32* const bt = zc->chainTable;
|
||||||
|
const U32 btLog = zc->params.cParams.chainLog - 1;
|
||||||
|
const U32 btMask= (1U << btLog) - 1;
|
||||||
|
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||||
|
const BYTE* const dictBase = zc->dictBase;
|
||||||
|
const U32 dictLimit = zc->dictLimit;
|
||||||
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
|
const BYTE* const prefixStart = base + dictLimit;
|
||||||
|
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
||||||
|
const U32 windowLow = zc->lowLimit;
|
||||||
|
U32* smallerPtr = bt + 2*(current&btMask);
|
||||||
|
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||||
|
U32 matchEndIdx = current+8;
|
||||||
|
U32 dummy32; /* to be nullified at the end */
|
||||||
|
U32 mnum = 0;
|
||||||
|
|
||||||
|
const U32 minMatch = (mls == 3) ? 3 : 4;
|
||||||
|
size_t bestLength = minMatchLen-1;
|
||||||
|
|
||||||
|
if (minMatch == 3) { /* HC3 match finder */
|
||||||
|
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
|
||||||
|
if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
|
||||||
|
const BYTE* match;
|
||||||
|
size_t currentMl=0;
|
||||||
|
if ((!extDict) || matchIndex3 >= dictLimit) {
|
||||||
|
match = base + matchIndex3;
|
||||||
|
if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
|
||||||
|
} else {
|
||||||
|
match = dictBase + matchIndex3;
|
||||||
|
if (MEM_readMINMATCH(match, MINMATCH) == MEM_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
|
||||||
|
currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save best solution */
|
||||||
|
if (currentMl > bestLength) {
|
||||||
|
bestLength = currentMl;
|
||||||
|
matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
|
||||||
|
matches[mnum].len = (U32)currentMl;
|
||||||
|
mnum++;
|
||||||
|
if (currentMl > ZSTD_OPT_NUM) goto update;
|
||||||
|
if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashTable[h] = current; /* Update Hash Table */
|
||||||
|
|
||||||
|
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||||
|
U32* nextPtr = bt + 2*(matchIndex & btMask);
|
||||||
|
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||||
|
const BYTE* match;
|
||||||
|
|
||||||
|
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||||
|
match = base + matchIndex;
|
||||||
|
if (match[matchLength] == ip[matchLength]) {
|
||||||
|
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match = dictBase + matchIndex;
|
||||||
|
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
|
||||||
|
if (matchIndex+matchLength >= dictLimit)
|
||||||
|
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchLength > bestLength) {
|
||||||
|
if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
|
||||||
|
bestLength = matchLength;
|
||||||
|
matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
|
||||||
|
matches[mnum].len = (U32)matchLength;
|
||||||
|
mnum++;
|
||||||
|
if (matchLength > ZSTD_OPT_NUM) break;
|
||||||
|
if (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */
|
||||||
|
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match[matchLength] < ip[matchLength]) {
|
||||||
|
/* match is smaller than current */
|
||||||
|
*smallerPtr = matchIndex; /* update smaller idx */
|
||||||
|
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||||
|
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||||
|
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||||
|
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||||
|
} else {
|
||||||
|
/* match is larger than current */
|
||||||
|
*largerPtr = matchIndex;
|
||||||
|
commonLengthLarger = matchLength;
|
||||||
|
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||||
|
largerPtr = nextPtr;
|
||||||
|
matchIndex = nextPtr[0];
|
||||||
|
} }
|
||||||
|
|
||||||
|
*smallerPtr = *largerPtr = 0;
|
||||||
|
|
||||||
|
update:
|
||||||
|
zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
|
||||||
|
return mnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Tree updater, providing best match */
|
||||||
|
static U32 ZSTD_BtGetAllMatches (
|
||||||
|
ZSTD_CCtx* zc,
|
||||||
|
const BYTE* const ip, const BYTE* const iLimit,
|
||||||
|
const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||||
|
{
|
||||||
|
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||||
|
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
|
||||||
|
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static U32 ZSTD_BtGetAllMatches_selectMLS (
|
||||||
|
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||||
|
const BYTE* ip, const BYTE* const iHighLimit,
|
||||||
|
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||||
|
{
|
||||||
|
switch(matchLengthSearch)
|
||||||
|
{
|
||||||
|
case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
|
||||||
|
default :
|
||||||
|
case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
|
||||||
|
case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
|
||||||
|
case 7 :
|
||||||
|
case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tree updater, providing best match */
|
||||||
|
static U32 ZSTD_BtGetAllMatches_extDict (
|
||||||
|
ZSTD_CCtx* zc,
|
||||||
|
const BYTE* const ip, const BYTE* const iLimit,
|
||||||
|
const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||||
|
{
|
||||||
|
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||||
|
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
|
||||||
|
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
|
||||||
|
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||||
|
const BYTE* ip, const BYTE* const iHighLimit,
|
||||||
|
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||||
|
{
|
||||||
|
switch(matchLengthSearch)
|
||||||
|
{
|
||||||
|
case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
|
||||||
|
default :
|
||||||
|
case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
|
||||||
|
case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
|
||||||
|
case 7 :
|
||||||
|
case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************
|
||||||
|
* Optimal parser
|
||||||
|
*********************************/
|
||||||
|
FORCE_INLINE
|
||||||
|
void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
||||||
|
const void* src, size_t srcSize, const int ultra)
|
||||||
|
{
|
||||||
|
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||||
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
|
const BYTE* ip = istart;
|
||||||
|
const BYTE* anchor = istart;
|
||||||
|
const BYTE* const iend = istart + srcSize;
|
||||||
|
const BYTE* const ilimit = iend - 8;
|
||||||
|
const BYTE* const base = ctx->base;
|
||||||
|
const BYTE* const prefixStart = base + ctx->dictLimit;
|
||||||
|
|
||||||
|
const U32 maxSearches = 1U << ctx->params.cParams.searchLog;
|
||||||
|
const U32 sufficient_len = ctx->params.cParams.targetLength;
|
||||||
|
const U32 mls = ctx->params.cParams.searchLength;
|
||||||
|
const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4;
|
||||||
|
|
||||||
|
ZSTD_optimal_t* opt = seqStorePtr->priceTable;
|
||||||
|
ZSTD_match_t* matches = seqStorePtr->matchTable;
|
||||||
|
const BYTE* inr;
|
||||||
|
U32 offset, rep[ZSTD_REP_NUM];
|
||||||
|
|
||||||
|
/* init */
|
||||||
|
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||||
|
ZSTD_rescaleFreqs(seqStorePtr, (const BYTE*)src, srcSize);
|
||||||
|
ip += (ip==prefixStart);
|
||||||
|
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=ctx->rep[i]; }
|
||||||
|
|
||||||
|
/* Match Loop */
|
||||||
|
while (ip < ilimit) {
|
||||||
|
U32 cur, match_num, last_pos, litlen, price;
|
||||||
|
U32 u, mlen, best_mlen, best_off, litLength;
|
||||||
|
memset(opt, 0, sizeof(ZSTD_optimal_t));
|
||||||
|
last_pos = 0;
|
||||||
|
litlen = (U32)(ip - anchor);
|
||||||
|
|
||||||
|
/* check repCode */
|
||||||
|
{ U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
|
||||||
|
for (i=(ip == anchor); i<last_i; i++) {
|
||||||
|
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
|
||||||
|
if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart))
|
||||||
|
&& (MEM_readMINMATCH(ip, minMatch) == MEM_readMINMATCH(ip - repCur, minMatch))) {
|
||||||
|
mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
|
||||||
|
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
|
||||||
|
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
best_off = i - (ip == anchor);
|
||||||
|
do {
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||||
|
if (mlen > last_pos || price < opt[mlen].price)
|
||||||
|
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
|
||||||
|
mlen--;
|
||||||
|
} while (mlen >= minMatch);
|
||||||
|
} } }
|
||||||
|
|
||||||
|
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
|
||||||
|
|
||||||
|
if (!last_pos && !match_num) { ip++; continue; }
|
||||||
|
|
||||||
|
if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||||
|
best_mlen = matches[match_num-1].len;
|
||||||
|
best_off = matches[match_num-1].off;
|
||||||
|
cur = 0;
|
||||||
|
last_pos = 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set prices using matches at position = 0 */
|
||||||
|
best_mlen = (last_pos) ? last_pos : minMatch;
|
||||||
|
for (u = 0; u < match_num; u++) {
|
||||||
|
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||||
|
best_mlen = matches[u].len;
|
||||||
|
while (mlen <= best_mlen) {
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
if (mlen > last_pos || price < opt[mlen].price)
|
||||||
|
SET_PRICE(mlen, mlen, matches[u].off, litlen, price); /* note : macro modifies last_pos */
|
||||||
|
mlen++;
|
||||||
|
} }
|
||||||
|
|
||||||
|
if (last_pos < minMatch) { ip++; continue; }
|
||||||
|
|
||||||
|
/* initialize opt[0] */
|
||||||
|
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||||
|
opt[0].mlen = 1;
|
||||||
|
opt[0].litlen = litlen;
|
||||||
|
|
||||||
|
/* check further positions */
|
||||||
|
for (cur = 1; cur <= last_pos; cur++) {
|
||||||
|
inr = ip + cur;
|
||||||
|
|
||||||
|
if (opt[cur-1].mlen == 1) {
|
||||||
|
litlen = opt[cur-1].litlen + 1;
|
||||||
|
if (cur > litlen) {
|
||||||
|
price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen);
|
||||||
|
} else
|
||||||
|
price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor);
|
||||||
|
} else {
|
||||||
|
litlen = 1;
|
||||||
|
price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur > last_pos || price <= opt[cur].price)
|
||||||
|
SET_PRICE(cur, 1, 0, litlen, price);
|
||||||
|
|
||||||
|
if (cur == last_pos) break;
|
||||||
|
|
||||||
|
if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mlen = opt[cur].mlen;
|
||||||
|
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
|
||||||
|
opt[cur].rep[2] = opt[cur-mlen].rep[1];
|
||||||
|
opt[cur].rep[1] = opt[cur-mlen].rep[0];
|
||||||
|
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
|
||||||
|
} else {
|
||||||
|
opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
|
||||||
|
opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
|
||||||
|
opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
|
||||||
|
}
|
||||||
|
|
||||||
|
best_mlen = minMatch;
|
||||||
|
{ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
|
||||||
|
for (i=(opt[cur].mlen != 1); i<last_i; i++) { /* check rep */
|
||||||
|
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
|
||||||
|
if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart))
|
||||||
|
&& (MEM_readMINMATCH(inr, minMatch) == MEM_readMINMATCH(inr - repCur, minMatch))) {
|
||||||
|
mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
|
||||||
|
|
||||||
|
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
|
||||||
|
best_mlen = mlen; best_off = i; last_pos = cur + 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_off = i - (opt[cur].mlen != 1);
|
||||||
|
if (mlen > best_mlen) best_mlen = mlen;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (opt[cur].mlen == 1) {
|
||||||
|
litlen = opt[cur].litlen;
|
||||||
|
if (cur > litlen) {
|
||||||
|
price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
|
||||||
|
} else
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||||
|
} else {
|
||||||
|
litlen = 0;
|
||||||
|
price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
|
||||||
|
SET_PRICE(cur + mlen, mlen, i, litlen, price);
|
||||||
|
mlen--;
|
||||||
|
} while (mlen >= minMatch);
|
||||||
|
} } }
|
||||||
|
|
||||||
|
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
|
||||||
|
|
||||||
|
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||||
|
best_mlen = matches[match_num-1].len;
|
||||||
|
best_off = matches[match_num-1].off;
|
||||||
|
last_pos = cur + 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set prices using matches at position = cur */
|
||||||
|
for (u = 0; u < match_num; u++) {
|
||||||
|
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||||
|
best_mlen = matches[u].len;
|
||||||
|
|
||||||
|
while (mlen <= best_mlen) {
|
||||||
|
if (opt[cur].mlen == 1) {
|
||||||
|
litlen = opt[cur].litlen;
|
||||||
|
if (cur > litlen)
|
||||||
|
price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
else
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
} else {
|
||||||
|
litlen = 0;
|
||||||
|
price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
|
||||||
|
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
|
||||||
|
|
||||||
|
mlen++;
|
||||||
|
} } }
|
||||||
|
|
||||||
|
best_mlen = opt[last_pos].mlen;
|
||||||
|
best_off = opt[last_pos].off;
|
||||||
|
cur = last_pos - best_mlen;
|
||||||
|
|
||||||
|
/* store sequence */
|
||||||
|
_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||||
|
opt[0].mlen = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
mlen = opt[cur].mlen;
|
||||||
|
offset = opt[cur].off;
|
||||||
|
opt[cur].mlen = best_mlen;
|
||||||
|
opt[cur].off = best_off;
|
||||||
|
best_mlen = mlen;
|
||||||
|
best_off = offset;
|
||||||
|
if (mlen > cur) break;
|
||||||
|
cur -= mlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u = 0; u <= last_pos;) {
|
||||||
|
u += opt[u].mlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cur=0; cur < last_pos; ) {
|
||||||
|
mlen = opt[cur].mlen;
|
||||||
|
if (mlen == 1) { ip++; cur++; continue; }
|
||||||
|
offset = opt[cur].off;
|
||||||
|
cur += mlen;
|
||||||
|
litLength = (U32)(ip - anchor);
|
||||||
|
|
||||||
|
if (offset > ZSTD_REP_MOVE_OPT) {
|
||||||
|
rep[2] = rep[1];
|
||||||
|
rep[1] = rep[0];
|
||||||
|
rep[0] = offset - ZSTD_REP_MOVE_OPT;
|
||||||
|
offset--;
|
||||||
|
} else {
|
||||||
|
if (offset != 0) {
|
||||||
|
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
|
||||||
|
if (offset != 1) rep[2] = rep[1];
|
||||||
|
rep[1] = rep[0];
|
||||||
|
rep[0] = best_off;
|
||||||
|
}
|
||||||
|
if (litLength==0) offset--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||||
|
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||||
|
anchor = ip = ip + mlen;
|
||||||
|
} } /* for (cur=0; cur < last_pos; ) */
|
||||||
|
|
||||||
|
/* Save reps for next block */
|
||||||
|
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) ctx->repToConfirm[i] = rep[i]; }
|
||||||
|
|
||||||
|
/* Last Literals */
|
||||||
|
{ size_t const lastLLSize = iend - anchor;
|
||||||
|
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||||
|
seqStorePtr->lit += lastLLSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE
|
||||||
|
void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
|
||||||
|
const void* src, size_t srcSize, const int ultra)
|
||||||
|
{
|
||||||
|
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||||
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
|
const BYTE* ip = istart;
|
||||||
|
const BYTE* anchor = istart;
|
||||||
|
const BYTE* const iend = istart + srcSize;
|
||||||
|
const BYTE* const ilimit = iend - 8;
|
||||||
|
const BYTE* const base = ctx->base;
|
||||||
|
const U32 lowestIndex = ctx->lowLimit;
|
||||||
|
const U32 dictLimit = ctx->dictLimit;
|
||||||
|
const BYTE* const prefixStart = base + dictLimit;
|
||||||
|
const BYTE* const dictBase = ctx->dictBase;
|
||||||
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
|
|
||||||
|
const U32 maxSearches = 1U << ctx->params.cParams.searchLog;
|
||||||
|
const U32 sufficient_len = ctx->params.cParams.targetLength;
|
||||||
|
const U32 mls = ctx->params.cParams.searchLength;
|
||||||
|
const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4;
|
||||||
|
|
||||||
|
ZSTD_optimal_t* opt = seqStorePtr->priceTable;
|
||||||
|
ZSTD_match_t* matches = seqStorePtr->matchTable;
|
||||||
|
const BYTE* inr;
|
||||||
|
|
||||||
|
/* init */
|
||||||
|
U32 offset, rep[ZSTD_REP_NUM];
|
||||||
|
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=ctx->rep[i]; }
|
||||||
|
|
||||||
|
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||||
|
ZSTD_rescaleFreqs(seqStorePtr, (const BYTE*)src, srcSize);
|
||||||
|
ip += (ip==prefixStart);
|
||||||
|
|
||||||
|
/* Match Loop */
|
||||||
|
while (ip < ilimit) {
|
||||||
|
U32 cur, match_num, last_pos, litlen, price;
|
||||||
|
U32 u, mlen, best_mlen, best_off, litLength;
|
||||||
|
U32 current = (U32)(ip-base);
|
||||||
|
memset(opt, 0, sizeof(ZSTD_optimal_t));
|
||||||
|
last_pos = 0;
|
||||||
|
opt[0].litlen = (U32)(ip - anchor);
|
||||||
|
|
||||||
|
/* check repCode */
|
||||||
|
{ U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
|
||||||
|
for (i = (ip==anchor); i<last_i; i++) {
|
||||||
|
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
|
||||||
|
const U32 repIndex = (U32)(current - repCur);
|
||||||
|
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||||
|
const BYTE* const repMatch = repBase + repIndex;
|
||||||
|
if ( (repCur > 0 && repCur <= (S32)current)
|
||||||
|
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
|
||||||
|
&& (MEM_readMINMATCH(ip, minMatch) == MEM_readMINMATCH(repMatch, minMatch)) ) {
|
||||||
|
/* repcode detected we should take it */
|
||||||
|
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||||
|
mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
|
||||||
|
|
||||||
|
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
|
||||||
|
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_off = i - (ip==anchor);
|
||||||
|
litlen = opt[0].litlen;
|
||||||
|
do {
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||||
|
if (mlen > last_pos || price < opt[mlen].price)
|
||||||
|
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
|
||||||
|
mlen--;
|
||||||
|
} while (mlen >= minMatch);
|
||||||
|
} } }
|
||||||
|
|
||||||
|
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch); /* first search (depth 0) */
|
||||||
|
|
||||||
|
if (!last_pos && !match_num) { ip++; continue; }
|
||||||
|
|
||||||
|
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||||
|
opt[0].mlen = 1;
|
||||||
|
|
||||||
|
if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||||
|
best_mlen = matches[match_num-1].len;
|
||||||
|
best_off = matches[match_num-1].off;
|
||||||
|
cur = 0;
|
||||||
|
last_pos = 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_mlen = (last_pos) ? last_pos : minMatch;
|
||||||
|
|
||||||
|
/* set prices using matches at position = 0 */
|
||||||
|
for (u = 0; u < match_num; u++) {
|
||||||
|
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||||
|
best_mlen = matches[u].len;
|
||||||
|
litlen = opt[0].litlen;
|
||||||
|
while (mlen <= best_mlen) {
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
if (mlen > last_pos || price < opt[mlen].price)
|
||||||
|
SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
|
||||||
|
mlen++;
|
||||||
|
} }
|
||||||
|
|
||||||
|
if (last_pos < minMatch) {
|
||||||
|
ip++; continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check further positions */
|
||||||
|
for (cur = 1; cur <= last_pos; cur++) {
|
||||||
|
inr = ip + cur;
|
||||||
|
|
||||||
|
if (opt[cur-1].mlen == 1) {
|
||||||
|
litlen = opt[cur-1].litlen + 1;
|
||||||
|
if (cur > litlen) {
|
||||||
|
price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen);
|
||||||
|
} else
|
||||||
|
price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor);
|
||||||
|
} else {
|
||||||
|
litlen = 1;
|
||||||
|
price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur > last_pos || price <= opt[cur].price)
|
||||||
|
SET_PRICE(cur, 1, 0, litlen, price);
|
||||||
|
|
||||||
|
if (cur == last_pos) break;
|
||||||
|
|
||||||
|
if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mlen = opt[cur].mlen;
|
||||||
|
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
|
||||||
|
opt[cur].rep[2] = opt[cur-mlen].rep[1];
|
||||||
|
opt[cur].rep[1] = opt[cur-mlen].rep[0];
|
||||||
|
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
|
||||||
|
} else {
|
||||||
|
opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
|
||||||
|
opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
|
||||||
|
opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
|
||||||
|
}
|
||||||
|
|
||||||
|
best_mlen = minMatch;
|
||||||
|
{ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
|
||||||
|
for (i = (mlen != 1); i<last_i; i++) {
|
||||||
|
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
|
||||||
|
const U32 repIndex = (U32)(current+cur - repCur);
|
||||||
|
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||||
|
const BYTE* const repMatch = repBase + repIndex;
|
||||||
|
if ( (repCur > 0 && repCur <= (S32)(current+cur))
|
||||||
|
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
|
||||||
|
&& (MEM_readMINMATCH(inr, minMatch) == MEM_readMINMATCH(repMatch, minMatch)) ) {
|
||||||
|
/* repcode detected */
|
||||||
|
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||||
|
mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
|
||||||
|
|
||||||
|
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
|
||||||
|
best_mlen = mlen; best_off = i; last_pos = cur + 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_off = i - (opt[cur].mlen != 1);
|
||||||
|
if (mlen > best_mlen) best_mlen = mlen;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (opt[cur].mlen == 1) {
|
||||||
|
litlen = opt[cur].litlen;
|
||||||
|
if (cur > litlen) {
|
||||||
|
price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
|
||||||
|
} else
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||||
|
} else {
|
||||||
|
litlen = 0;
|
||||||
|
price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
|
||||||
|
SET_PRICE(cur + mlen, mlen, i, litlen, price);
|
||||||
|
mlen--;
|
||||||
|
} while (mlen >= minMatch);
|
||||||
|
} } }
|
||||||
|
|
||||||
|
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
|
||||||
|
|
||||||
|
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||||
|
best_mlen = matches[match_num-1].len;
|
||||||
|
best_off = matches[match_num-1].off;
|
||||||
|
last_pos = cur + 1;
|
||||||
|
goto _storeSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set prices using matches at position = cur */
|
||||||
|
for (u = 0; u < match_num; u++) {
|
||||||
|
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||||
|
best_mlen = matches[u].len;
|
||||||
|
|
||||||
|
while (mlen <= best_mlen) {
|
||||||
|
if (opt[cur].mlen == 1) {
|
||||||
|
litlen = opt[cur].litlen;
|
||||||
|
if (cur > litlen)
|
||||||
|
price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
else
|
||||||
|
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
} else {
|
||||||
|
litlen = 0;
|
||||||
|
price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
|
||||||
|
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
|
||||||
|
|
||||||
|
mlen++;
|
||||||
|
} } } /* for (cur = 1; cur <= last_pos; cur++) */
|
||||||
|
|
||||||
|
best_mlen = opt[last_pos].mlen;
|
||||||
|
best_off = opt[last_pos].off;
|
||||||
|
cur = last_pos - best_mlen;
|
||||||
|
|
||||||
|
/* store sequence */
|
||||||
|
_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||||
|
opt[0].mlen = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
mlen = opt[cur].mlen;
|
||||||
|
offset = opt[cur].off;
|
||||||
|
opt[cur].mlen = best_mlen;
|
||||||
|
opt[cur].off = best_off;
|
||||||
|
best_mlen = mlen;
|
||||||
|
best_off = offset;
|
||||||
|
if (mlen > cur) break;
|
||||||
|
cur -= mlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u = 0; u <= last_pos; ) {
|
||||||
|
u += opt[u].mlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cur=0; cur < last_pos; ) {
|
||||||
|
mlen = opt[cur].mlen;
|
||||||
|
if (mlen == 1) { ip++; cur++; continue; }
|
||||||
|
offset = opt[cur].off;
|
||||||
|
cur += mlen;
|
||||||
|
litLength = (U32)(ip - anchor);
|
||||||
|
|
||||||
|
if (offset > ZSTD_REP_MOVE_OPT) {
|
||||||
|
rep[2] = rep[1];
|
||||||
|
rep[1] = rep[0];
|
||||||
|
rep[0] = offset - ZSTD_REP_MOVE_OPT;
|
||||||
|
offset--;
|
||||||
|
} else {
|
||||||
|
if (offset != 0) {
|
||||||
|
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
|
||||||
|
if (offset != 1) rep[2] = rep[1];
|
||||||
|
rep[1] = rep[0];
|
||||||
|
rep[0] = best_off;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (litLength==0) offset--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||||
|
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||||
|
anchor = ip = ip + mlen;
|
||||||
|
} } /* for (cur=0; cur < last_pos; ) */
|
||||||
|
|
||||||
|
/* Save reps for next block */
|
||||||
|
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) ctx->repToConfirm[i] = rep[i]; }
|
||||||
|
|
||||||
|
/* Last Literals */
|
||||||
|
{ size_t lastLLSize = iend - anchor;
|
||||||
|
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||||
|
seqStorePtr->lit += lastLLSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZSTD_OPT_H_91842398743 */
|
28
contrib/linux-kernel/spaces_to_tabs.sh
Executable file
28
contrib/linux-kernel/spaces_to_tabs.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
INCLUDE='include/'
|
||||||
|
LIB='lib/'
|
||||||
|
SPACES=' '
|
||||||
|
TAB=$'\t'
|
||||||
|
TMP="replacements.tmp"
|
||||||
|
|
||||||
|
echo "Files: " $INCLUDE* $LIB*
|
||||||
|
|
||||||
|
# Check files for existing tabs
|
||||||
|
grep "$TAB" $INCLUDE* $LIB* && exit 1 || true
|
||||||
|
# Replace the first tab on every line
|
||||||
|
sed -i '' "s/^$SPACES/$TAB/" $INCLUDE* $LIB*
|
||||||
|
|
||||||
|
# Execute once and then execute as long as replacements are happening
|
||||||
|
more_work="yes"
|
||||||
|
while [ ! -z "$more_work" ]
|
||||||
|
do
|
||||||
|
rm -f $TMP
|
||||||
|
# Replaces $SPACES that directly follow a $TAB with a $TAB.
|
||||||
|
# $TMP will be non-empty if any replacements took place.
|
||||||
|
sed -i '' "s/$TAB$SPACES/$TAB$TAB/w $TMP" $INCLUDE* $LIB*
|
||||||
|
more_work=$(cat "$TMP")
|
||||||
|
done
|
||||||
|
rm -f $TMP
|
1
contrib/linux-kernel/test/.gitignore
vendored
Normal file
1
contrib/linux-kernel/test/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*Test
|
27
contrib/linux-kernel/test/Makefile
Normal file
27
contrib/linux-kernel/test/Makefile
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
IFLAGS := -isystem include/ -I ../include/ -I ../lib/zstd/ -isystem googletest/googletest/include
|
||||||
|
|
||||||
|
SOURCES := $(wildcard ../lib/zstd/*.c)
|
||||||
|
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
|
||||||
|
|
||||||
|
ARFLAGS := rcs
|
||||||
|
CXXFLAGS += -std=c++11
|
||||||
|
CFLAGS += -g -O0
|
||||||
|
CPPFLAGS += $(IFLAGS)
|
||||||
|
|
||||||
|
../lib/zstd/libzstd.a: $(OBJECTS)
|
||||||
|
$(AR) $(ARFLAGS) $@ $^
|
||||||
|
|
||||||
|
UserlandTest: UserlandTest.cpp ../lib/zstd/libzstd.a
|
||||||
|
$(CXX) $(CXXFLAGS) $(CFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
|
||||||
|
|
||||||
|
# Install googletest
|
||||||
|
.PHONY: googletest
|
||||||
|
googletest:
|
||||||
|
@$(RM) -rf googletest
|
||||||
|
@git clone https://github.com/google/googletest
|
||||||
|
@mkdir -p googletest/build
|
||||||
|
@cd googletest/build && cmake .. && $(MAKE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f *.{o,a} ../lib/zstd/*.{o,a}
|
554
contrib/linux-kernel/test/UserlandTest.cpp
Normal file
554
contrib/linux-kernel/test/UserlandTest.cpp
Normal file
@ -0,0 +1,554 @@
|
|||||||
|
extern "C" {
|
||||||
|
#include <linux/zstd.h>
|
||||||
|
}
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct WorkspaceDeleter {
|
||||||
|
void *memory;
|
||||||
|
|
||||||
|
template <typename T> void operator()(T const *) { free(memory); }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
|
||||||
|
createCCtx(ZSTD_compressionParameters cParams) {
|
||||||
|
size_t const workspaceSize = ZSTD_CCtxWorkspaceBound(cParams);
|
||||||
|
void *workspace = malloc(workspaceSize);
|
||||||
|
std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter> cctx{
|
||||||
|
ZSTD_createCCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
|
||||||
|
if (!cctx) {
|
||||||
|
throw std::runtime_error{"Bad cctx"};
|
||||||
|
}
|
||||||
|
return cctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
|
||||||
|
createCCtx(int level, unsigned long long estimatedSrcSize = 0,
|
||||||
|
size_t dictSize = 0) {
|
||||||
|
auto const cParams = ZSTD_getCParams(level, estimatedSrcSize, dictSize);
|
||||||
|
return createCCtx(cParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter>
|
||||||
|
createDCtx() {
|
||||||
|
size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
|
||||||
|
void *workspace = malloc(workspaceSize);
|
||||||
|
std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter> dctx{
|
||||||
|
ZSTD_createDCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
|
||||||
|
if (!dctx) {
|
||||||
|
throw std::runtime_error{"Bad dctx"};
|
||||||
|
}
|
||||||
|
return dctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
|
||||||
|
createCDict(std::string const& dict, ZSTD_parameters params) {
|
||||||
|
size_t const workspaceSize = ZSTD_CDictWorkspaceBound(params.cParams);
|
||||||
|
void *workspace = malloc(workspaceSize);
|
||||||
|
std::unique_ptr<ZSTD_CDict, WorkspaceDeleter> cdict{
|
||||||
|
ZSTD_createCDict(dict.data(), dict.size(), params, workspace,
|
||||||
|
workspaceSize),
|
||||||
|
WorkspaceDeleter{workspace}};
|
||||||
|
if (!cdict) {
|
||||||
|
throw std::runtime_error{"Bad cdict"};
|
||||||
|
}
|
||||||
|
return cdict;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
|
||||||
|
createCDict(std::string const& dict, int level) {
|
||||||
|
auto const params = ZSTD_getParams(level, 0, dict.size());
|
||||||
|
return createCDict(dict, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_DDict, WorkspaceDeleter>
|
||||||
|
createDDict(std::string const& dict) {
|
||||||
|
size_t const workspaceSize = ZSTD_DDictWorkspaceBound();
|
||||||
|
void *workspace = malloc(workspaceSize);
|
||||||
|
std::unique_ptr<ZSTD_DDict, WorkspaceDeleter> ddict{
|
||||||
|
ZSTD_createDDict(dict.data(), dict.size(), workspace, workspaceSize),
|
||||||
|
WorkspaceDeleter{workspace}};
|
||||||
|
if (!ddict) {
|
||||||
|
throw std::runtime_error{"Bad ddict"};
|
||||||
|
}
|
||||||
|
return ddict;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
|
||||||
|
createCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize = 0) {
|
||||||
|
size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(params.cParams);
|
||||||
|
void *workspace = malloc(workspaceSize);
|
||||||
|
std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
|
||||||
|
ZSTD_createCStream(params, pledgedSrcSize, workspace, workspaceSize)};
|
||||||
|
if (!zcs) {
|
||||||
|
throw std::runtime_error{"bad cstream"};
|
||||||
|
}
|
||||||
|
return zcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
|
||||||
|
createCStream(ZSTD_compressionParameters cParams, ZSTD_CDict const &cdict,
|
||||||
|
unsigned long long pledgedSrcSize = 0) {
|
||||||
|
size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(cParams);
|
||||||
|
void *workspace = malloc(workspaceSize);
|
||||||
|
std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
|
||||||
|
ZSTD_createCStream_usingCDict(&cdict, pledgedSrcSize, workspace,
|
||||||
|
workspaceSize)};
|
||||||
|
if (!zcs) {
|
||||||
|
throw std::runtime_error{"bad cstream"};
|
||||||
|
}
|
||||||
|
return zcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
|
||||||
|
createCStream(int level, unsigned long long pledgedSrcSize = 0) {
|
||||||
|
auto const params = ZSTD_getParams(level, pledgedSrcSize, 0);
|
||||||
|
return createCStream(params, pledgedSrcSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ZSTD_DStream, WorkspaceDeleter>
|
||||||
|
createDStream(size_t maxWindowSize = (1ULL << ZSTD_WINDOWLOG_MAX),
|
||||||
|
ZSTD_DDict const *ddict = nullptr) {
|
||||||
|
size_t const workspaceSize = ZSTD_DStreamWorkspaceBound(maxWindowSize);
|
||||||
|
void *workspace = malloc(workspaceSize);
|
||||||
|
std::unique_ptr<ZSTD_DStream, WorkspaceDeleter> zds{
|
||||||
|
ddict == nullptr
|
||||||
|
? ZSTD_createDStream(maxWindowSize, workspace, workspaceSize)
|
||||||
|
: ZSTD_createDStream_usingDDict(maxWindowSize, ddict, workspace,
|
||||||
|
workspaceSize)};
|
||||||
|
if (!zds) {
|
||||||
|
throw std::runtime_error{"bad dstream"};
|
||||||
|
}
|
||||||
|
return zds;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string compress(ZSTD_CCtx &cctx, std::string const &data,
|
||||||
|
ZSTD_parameters params, std::string const &dict = "") {
|
||||||
|
std::string compressed;
|
||||||
|
compressed.resize(ZSTD_compressBound(data.size()));
|
||||||
|
size_t const rc =
|
||||||
|
dict.empty()
|
||||||
|
? ZSTD_compressCCtx(&cctx, &compressed[0], compressed.size(),
|
||||||
|
data.data(), data.size(), params)
|
||||||
|
: ZSTD_compress_usingDict(&cctx, &compressed[0], compressed.size(),
|
||||||
|
data.data(), data.size(), dict.data(),
|
||||||
|
dict.size(), params);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"compression error"};
|
||||||
|
}
|
||||||
|
compressed.resize(rc);
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string compress(ZSTD_CCtx& cctx, std::string const& data, int level, std::string const& dict = "") {
|
||||||
|
auto const params = ZSTD_getParams(level, 0, dict.size());
|
||||||
|
return compress(cctx, data, params, dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, std::string const& dict = "") {
|
||||||
|
std::string decompressed;
|
||||||
|
decompressed.resize(decompressedSize);
|
||||||
|
size_t const rc =
|
||||||
|
dict.empty()
|
||||||
|
? ZSTD_decompressDCtx(&dctx, &decompressed[0], decompressed.size(),
|
||||||
|
compressed.data(), compressed.size())
|
||||||
|
: ZSTD_decompress_usingDict(
|
||||||
|
&dctx, &decompressed[0], decompressed.size(), compressed.data(),
|
||||||
|
compressed.size(), dict.data(), dict.size());
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"decompression error"};
|
||||||
|
}
|
||||||
|
decompressed.resize(rc);
|
||||||
|
return decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string compress(ZSTD_CCtx& cctx, std::string const& data, ZSTD_CDict& cdict) {
|
||||||
|
std::string compressed;
|
||||||
|
compressed.resize(ZSTD_compressBound(data.size()));
|
||||||
|
size_t const rc =
|
||||||
|
ZSTD_compress_usingCDict(&cctx, &compressed[0], compressed.size(),
|
||||||
|
data.data(), data.size(), &cdict);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"compression error"};
|
||||||
|
}
|
||||||
|
compressed.resize(rc);
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, ZSTD_DDict& ddict) {
|
||||||
|
std::string decompressed;
|
||||||
|
decompressed.resize(decompressedSize);
|
||||||
|
size_t const rc =
|
||||||
|
ZSTD_decompress_usingDDict(&dctx, &decompressed[0], decompressed.size(),
|
||||||
|
compressed.data(), compressed.size(), &ddict);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"decompression error"};
|
||||||
|
}
|
||||||
|
decompressed.resize(rc);
|
||||||
|
return decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string compress(ZSTD_CStream& zcs, std::string const& data) {
|
||||||
|
std::string compressed;
|
||||||
|
compressed.resize(ZSTD_compressBound(data.size()));
|
||||||
|
ZSTD_inBuffer in = {data.data(), data.size(), 0};
|
||||||
|
ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
|
||||||
|
while (in.pos != in.size) {
|
||||||
|
size_t const rc = ZSTD_compressStream(&zcs, &out, &in);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"compress stream failed"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t const rc = ZSTD_endStream(&zcs, &out);
|
||||||
|
if (rc != 0) {
|
||||||
|
throw std::runtime_error{"compress end failed"};
|
||||||
|
}
|
||||||
|
compressed.resize(out.pos);
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string decompress(ZSTD_DStream &zds, std::string const &compressed,
|
||||||
|
size_t decompressedSize) {
|
||||||
|
std::string decompressed;
|
||||||
|
decompressed.resize(decompressedSize);
|
||||||
|
ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
|
||||||
|
ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
|
||||||
|
while (in.pos != in.size) {
|
||||||
|
size_t const rc = ZSTD_decompressStream(&zds, &out, &in);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"decompress stream failed"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decompressed.resize(out.pos);
|
||||||
|
return decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string makeData(size_t size) {
|
||||||
|
std::string result;
|
||||||
|
result.reserve(size + 20);
|
||||||
|
while (result.size() < size) {
|
||||||
|
result += "Hello world";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const kData = "Hello world";
|
||||||
|
std::string const kPlainDict = makeData(10000);
|
||||||
|
std::string const kZstdDict{
|
||||||
|
"\x37\xA4\x30\xEC\x99\x69\x58\x1C\x21\x10\xD8\x4A\x84\x01\xCC\xF3"
|
||||||
|
"\x3C\xCF\x9B\x25\xBB\xC9\x6E\xB2\x9B\xEC\x26\xAD\xCF\xDF\x4E\xCD"
|
||||||
|
"\xF3\x2C\x3A\x21\x84\x10\x42\x08\x21\x01\x33\xF1\x78\x3C\x1E\x8F"
|
||||||
|
"\xC7\xE3\xF1\x78\x3C\xCF\xF3\xBC\xF7\xD4\x42\x41\x41\x41\x41\x41"
|
||||||
|
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
|
||||||
|
"\x41\x41\x41\x41\xA1\x50\x28\x14\x0A\x85\x42\xA1\x50\x28\x14\x0A"
|
||||||
|
"\x85\xA2\x28\x8A\xA2\x28\x4A\x29\x7D\x74\xE1\xE1\xE1\xE1\xE1\xE1"
|
||||||
|
"\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xF1\x78\x3C"
|
||||||
|
"\x1E\x8F\xC7\xE3\xF1\x78\x9E\xE7\x79\xEF\x01\x01\x00\x00\x00\x04"
|
||||||
|
"\x00\x00\x00\x08\x00\x00\x00"
|
||||||
|
"0123456789",
|
||||||
|
161};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, CCtx) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const compressed = compress(*cctx, kData, 1);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
auto const decompressed = decompress(*dctx, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, NoContentSize) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const c = compress(*cctx, kData, 1);
|
||||||
|
auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
|
||||||
|
EXPECT_EQ(ZSTD_CONTENTSIZE_UNKNOWN, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, ContentSize) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto params = ZSTD_getParams(1, 0, 0);
|
||||||
|
params.fParams.contentSizeFlag = 1;
|
||||||
|
auto const c = compress(*cctx, kData, params);
|
||||||
|
auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
|
||||||
|
EXPECT_EQ(kData.size(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, CCtxLevelIncrease) {
|
||||||
|
std::string c;
|
||||||
|
auto cctx = createCCtx(6);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
for (int level = 1; level <= 6; ++level) {
|
||||||
|
auto compressed = compress(*cctx, kData, level);
|
||||||
|
auto const decompressed = decompress(*dctx, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, PlainDict) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const compressed = compress(*cctx, kData, 1, kPlainDict);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
|
||||||
|
auto const decompressed =
|
||||||
|
decompress(*dctx, compressed, kData.size(), kPlainDict);
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, ZstdDict) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const compressed = compress(*cctx, kData, 1, kZstdDict);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
|
||||||
|
auto const decompressed =
|
||||||
|
decompress(*dctx, compressed, kData.size(), kZstdDict);
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, PreprocessedPlainDict) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const cdict = createCDict(kPlainDict, 1);
|
||||||
|
auto const compressed = compress(*cctx, kData, *cdict);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
auto const ddict = createDDict(kPlainDict);
|
||||||
|
EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
|
||||||
|
auto const decompressed =
|
||||||
|
decompress(*dctx, compressed, kData.size(), *ddict);
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, PreprocessedZstdDict) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const cdict = createCDict(kZstdDict, 1);
|
||||||
|
auto const compressed = compress(*cctx, kData, *cdict);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
auto const ddict = createDDict(kZstdDict);
|
||||||
|
EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
|
||||||
|
auto const decompressed =
|
||||||
|
decompress(*dctx, compressed, kData.size(), *ddict);
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, RecreateCCtx) {
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
{
|
||||||
|
auto const compressed = compress(*cctx, kData, 1);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
auto const decompressed = decompress(*dctx, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
// Create the cctx with the same memory
|
||||||
|
auto d = cctx.get_deleter();
|
||||||
|
auto raw = cctx.release();
|
||||||
|
auto params = ZSTD_getParams(1, 0, 0);
|
||||||
|
cctx.reset(
|
||||||
|
ZSTD_createCCtx(d.memory, ZSTD_CCtxWorkspaceBound(params.cParams)));
|
||||||
|
// Repeat
|
||||||
|
{
|
||||||
|
auto const compressed = compress(*cctx, kData, 1);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
auto const decompressed = decompress(*dctx, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Block, RecreateDCtx) {
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
{
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const compressed = compress(*cctx, kData, 1);
|
||||||
|
auto const decompressed = decompress(*dctx, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
// Create the cctx with the same memory
|
||||||
|
auto d = dctx.get_deleter();
|
||||||
|
auto raw = dctx.release();
|
||||||
|
dctx.reset(ZSTD_createDCtx(d.memory, ZSTD_DCtxWorkspaceBound()));
|
||||||
|
// Repeat
|
||||||
|
{
|
||||||
|
auto cctx = createCCtx(1);
|
||||||
|
auto const compressed = compress(*cctx, kData, 1);
|
||||||
|
auto dctx = createDCtx();
|
||||||
|
auto const decompressed = decompress(*dctx, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Stream, Basic) {
|
||||||
|
auto zcs = createCStream(1);
|
||||||
|
auto const compressed = compress(*zcs, kData);
|
||||||
|
auto zds = createDStream();
|
||||||
|
auto const decompressed = decompress(*zds, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Stream, PlainDict) {
|
||||||
|
auto params = ZSTD_getParams(1, kData.size(), kPlainDict.size());
|
||||||
|
params.cParams.windowLog = 17;
|
||||||
|
auto cdict = createCDict(kPlainDict, params);
|
||||||
|
auto zcs = createCStream(params.cParams, *cdict, kData.size());
|
||||||
|
auto const compressed = compress(*zcs, kData);
|
||||||
|
auto const contentSize =
|
||||||
|
ZSTD_findDecompressedSize(compressed.data(), compressed.size());
|
||||||
|
EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
|
||||||
|
auto ddict = createDDict(kPlainDict);
|
||||||
|
auto zds = createDStream(1 << 17, ddict.get());
|
||||||
|
auto const decompressed = decompress(*zds, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Stream, ZstdDict) {
|
||||||
|
auto params = ZSTD_getParams(1, 0, 0);
|
||||||
|
params.cParams.windowLog = 17;
|
||||||
|
auto cdict = createCDict(kZstdDict, 1);
|
||||||
|
auto zcs = createCStream(params.cParams, *cdict);
|
||||||
|
auto const compressed = compress(*zcs, kData);
|
||||||
|
EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
|
||||||
|
auto ddict = createDDict(kZstdDict);
|
||||||
|
auto zds = createDStream(1 << 17, ddict.get());
|
||||||
|
auto const decompressed = decompress(*zds, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Stream, ResetCStream) {
|
||||||
|
auto zcs = createCStream(1);
|
||||||
|
auto zds = createDStream();
|
||||||
|
{
|
||||||
|
auto const compressed = compress(*zcs, kData);
|
||||||
|
auto const decompressed = decompress(*zds, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ZSTD_resetCStream(zcs.get(), 0);
|
||||||
|
auto const compressed = compress(*zcs, kData);
|
||||||
|
auto const decompressed = decompress(*zds, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Stream, ResetDStream) {
|
||||||
|
auto zcs = createCStream(1);
|
||||||
|
auto zds = createDStream();
|
||||||
|
auto const compressed = compress(*zcs, kData);
|
||||||
|
EXPECT_ANY_THROW(decompress(*zds, kData, kData.size()));
|
||||||
|
EXPECT_ANY_THROW(decompress(*zds, compressed, kData.size()));
|
||||||
|
ZSTD_resetDStream(zds.get());
|
||||||
|
auto const decompressed = decompress(*zds, compressed, kData.size());
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Stream, Flush) {
|
||||||
|
auto zcs = createCStream(1);
|
||||||
|
auto zds = createDStream();
|
||||||
|
std::string compressed;
|
||||||
|
{
|
||||||
|
compressed.resize(ZSTD_compressBound(kData.size()));
|
||||||
|
ZSTD_inBuffer in = {kData.data(), kData.size(), 0};
|
||||||
|
ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
|
||||||
|
while (in.pos != in.size) {
|
||||||
|
size_t const rc = ZSTD_compressStream(zcs.get(), &out, &in);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"compress stream failed"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ(0, out.pos);
|
||||||
|
size_t const rc = ZSTD_flushStream(zcs.get(), &out);
|
||||||
|
if (rc != 0) {
|
||||||
|
throw std::runtime_error{"compress end failed"};
|
||||||
|
}
|
||||||
|
compressed.resize(out.pos);
|
||||||
|
EXPECT_LT(0, out.pos);
|
||||||
|
}
|
||||||
|
std::string decompressed;
|
||||||
|
{
|
||||||
|
decompressed.resize(kData.size());
|
||||||
|
ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
|
||||||
|
ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
|
||||||
|
while (in.pos != in.size) {
|
||||||
|
size_t const rc = ZSTD_decompressStream(zds.get(), &out, &in);
|
||||||
|
if (ZSTD_isError(rc)) {
|
||||||
|
throw std::runtime_error{"decompress stream failed"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ(kData, decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_SYMBOL(symbol) \
|
||||||
|
do { \
|
||||||
|
extern void *__##symbol; \
|
||||||
|
EXPECT_NE((void *)0, __##symbol); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
TEST(API, Symbols) {
|
||||||
|
TEST_SYMBOL(ZSTD_CCtxWorkspaceBound);
|
||||||
|
TEST_SYMBOL(ZSTD_createCCtx);
|
||||||
|
TEST_SYMBOL(ZSTD_compressCCtx);
|
||||||
|
TEST_SYMBOL(ZSTD_compress_usingDict);
|
||||||
|
TEST_SYMBOL(ZSTD_DCtxWorkspaceBound);
|
||||||
|
TEST_SYMBOL(ZSTD_createDCtx);
|
||||||
|
TEST_SYMBOL(ZSTD_decompressDCtx);
|
||||||
|
TEST_SYMBOL(ZSTD_decompress_usingDict);
|
||||||
|
|
||||||
|
TEST_SYMBOL(ZSTD_CDictWorkspaceBound);
|
||||||
|
TEST_SYMBOL(ZSTD_createCDict);
|
||||||
|
TEST_SYMBOL(ZSTD_compress_usingCDict);
|
||||||
|
TEST_SYMBOL(ZSTD_DDictWorkspaceBound);
|
||||||
|
TEST_SYMBOL(ZSTD_createDDict);
|
||||||
|
TEST_SYMBOL(ZSTD_decompress_usingDDict);
|
||||||
|
|
||||||
|
TEST_SYMBOL(ZSTD_CStreamWorkspaceBound);
|
||||||
|
TEST_SYMBOL(ZSTD_createCStream);
|
||||||
|
TEST_SYMBOL(ZSTD_createCStream_usingCDict);
|
||||||
|
TEST_SYMBOL(ZSTD_resetCStream);
|
||||||
|
TEST_SYMBOL(ZSTD_compressStream);
|
||||||
|
TEST_SYMBOL(ZSTD_flushStream);
|
||||||
|
TEST_SYMBOL(ZSTD_endStream);
|
||||||
|
TEST_SYMBOL(ZSTD_CStreamInSize);
|
||||||
|
TEST_SYMBOL(ZSTD_CStreamOutSize);
|
||||||
|
TEST_SYMBOL(ZSTD_DStreamWorkspaceBound);
|
||||||
|
TEST_SYMBOL(ZSTD_createDStream);
|
||||||
|
TEST_SYMBOL(ZSTD_createDStream_usingDDict);
|
||||||
|
TEST_SYMBOL(ZSTD_resetDStream);
|
||||||
|
TEST_SYMBOL(ZSTD_decompressStream);
|
||||||
|
TEST_SYMBOL(ZSTD_DStreamInSize);
|
||||||
|
TEST_SYMBOL(ZSTD_DStreamOutSize);
|
||||||
|
|
||||||
|
TEST_SYMBOL(ZSTD_findFrameCompressedSize);
|
||||||
|
TEST_SYMBOL(ZSTD_getFrameContentSize);
|
||||||
|
TEST_SYMBOL(ZSTD_findDecompressedSize);
|
||||||
|
|
||||||
|
TEST_SYMBOL(ZSTD_getCParams);
|
||||||
|
TEST_SYMBOL(ZSTD_getParams);
|
||||||
|
TEST_SYMBOL(ZSTD_checkCParams);
|
||||||
|
TEST_SYMBOL(ZSTD_adjustCParams);
|
||||||
|
|
||||||
|
TEST_SYMBOL(ZSTD_isFrame);
|
||||||
|
TEST_SYMBOL(ZSTD_getDictID_fromDict);
|
||||||
|
TEST_SYMBOL(ZSTD_getDictID_fromDDict);
|
||||||
|
TEST_SYMBOL(ZSTD_getDictID_fromFrame);
|
||||||
|
|
||||||
|
TEST_SYMBOL(ZSTD_compressBegin);
|
||||||
|
TEST_SYMBOL(ZSTD_compressBegin_usingDict);
|
||||||
|
TEST_SYMBOL(ZSTD_compressBegin_advanced);
|
||||||
|
TEST_SYMBOL(ZSTD_copyCCtx);
|
||||||
|
TEST_SYMBOL(ZSTD_compressBegin_usingCDict);
|
||||||
|
TEST_SYMBOL(ZSTD_compressContinue);
|
||||||
|
TEST_SYMBOL(ZSTD_compressEnd);
|
||||||
|
TEST_SYMBOL(ZSTD_getFrameParams);
|
||||||
|
TEST_SYMBOL(ZSTD_decompressBegin);
|
||||||
|
TEST_SYMBOL(ZSTD_decompressBegin_usingDict);
|
||||||
|
TEST_SYMBOL(ZSTD_copyDCtx);
|
||||||
|
TEST_SYMBOL(ZSTD_nextSrcSizeToDecompress);
|
||||||
|
TEST_SYMBOL(ZSTD_decompressContinue);
|
||||||
|
TEST_SYMBOL(ZSTD_nextInputType);
|
||||||
|
|
||||||
|
TEST_SYMBOL(ZSTD_getBlockSizeMax);
|
||||||
|
TEST_SYMBOL(ZSTD_compressBlock);
|
||||||
|
TEST_SYMBOL(ZSTD_decompressBlock);
|
||||||
|
TEST_SYMBOL(ZSTD_insertBlock);
|
||||||
|
}
|
177
contrib/linux-kernel/test/include/asm/unaligned.h
Normal file
177
contrib/linux-kernel/test/include/asm/unaligned.h
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
#ifndef ASM_UNALIGNED_H
|
||||||
|
#define ASM_UNALIGNED_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define _LITTLE_ENDIAN 1
|
||||||
|
|
||||||
|
static unsigned _isLittleEndian(void)
|
||||||
|
{
|
||||||
|
const union { uint32_t u; uint8_t c[4]; } one = { 1 };
|
||||||
|
assert(_LITTLE_ENDIAN == one.c[0]);
|
||||||
|
return _LITTLE_ENDIAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t _swap16(uint16_t in)
|
||||||
|
{
|
||||||
|
return ((in & 0xF) << 8) + ((in & 0xF0) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t _swap32(uint32_t in)
|
||||||
|
{
|
||||||
|
return __builtin_bswap32(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t _swap64(uint64_t in)
|
||||||
|
{
|
||||||
|
return __builtin_bswap64(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Little endian */
|
||||||
|
static uint16_t get_unaligned_le16(const void* memPtr)
|
||||||
|
{
|
||||||
|
uint16_t val;
|
||||||
|
memcpy(&val, memPtr, sizeof(val));
|
||||||
|
if (!_isLittleEndian()) _swap16(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t get_unaligned_le32(const void* memPtr)
|
||||||
|
{
|
||||||
|
uint32_t val;
|
||||||
|
memcpy(&val, memPtr, sizeof(val));
|
||||||
|
if (!_isLittleEndian()) _swap32(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t get_unaligned_le64(const void* memPtr)
|
||||||
|
{
|
||||||
|
uint64_t val;
|
||||||
|
memcpy(&val, memPtr, sizeof(val));
|
||||||
|
if (!_isLittleEndian()) _swap64(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_unaligned_le16(uint16_t value, void* memPtr)
|
||||||
|
{
|
||||||
|
if (!_isLittleEndian()) value = _swap16(value);
|
||||||
|
memcpy(memPtr, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_unaligned_le32(uint32_t value, void* memPtr)
|
||||||
|
{
|
||||||
|
if (!_isLittleEndian()) value = _swap32(value);
|
||||||
|
memcpy(memPtr, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_unaligned_le64(uint64_t value, void* memPtr)
|
||||||
|
{
|
||||||
|
if (!_isLittleEndian()) value = _swap64(value);
|
||||||
|
memcpy(memPtr, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* big endian */
|
||||||
|
static uint32_t get_unaligned_be32(const void* memPtr)
|
||||||
|
{
|
||||||
|
uint32_t val;
|
||||||
|
memcpy(&val, memPtr, sizeof(val));
|
||||||
|
if (_isLittleEndian()) _swap32(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t get_unaligned_be64(const void* memPtr)
|
||||||
|
{
|
||||||
|
uint64_t val;
|
||||||
|
memcpy(&val, memPtr, sizeof(val));
|
||||||
|
if (_isLittleEndian()) _swap64(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_unaligned_be32(uint32_t value, void* memPtr)
|
||||||
|
{
|
||||||
|
if (_isLittleEndian()) value = _swap32(value);
|
||||||
|
memcpy(memPtr, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_unaligned_be64(uint64_t value, void* memPtr)
|
||||||
|
{
|
||||||
|
if (_isLittleEndian()) value = _swap64(value);
|
||||||
|
memcpy(memPtr, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generic */
|
||||||
|
extern void __bad_unaligned_access_size(void);
|
||||||
|
|
||||||
|
#define __get_unaligned_le(ptr) ((typeof(*(ptr)))({ \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \
|
||||||
|
__bad_unaligned_access_size())))); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __get_unaligned_be(ptr) ((typeof(*(ptr)))({ \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \
|
||||||
|
__builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \
|
||||||
|
__bad_unaligned_access_size())))); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __put_unaligned_le(val, ptr) \
|
||||||
|
({ \
|
||||||
|
void *__gu_p = (ptr); \
|
||||||
|
switch (sizeof(*(ptr))) { \
|
||||||
|
case 1: \
|
||||||
|
*(uint8_t *)__gu_p = (uint8_t)(val); \
|
||||||
|
break; \
|
||||||
|
case 2: \
|
||||||
|
put_unaligned_le16((uint16_t)(val), __gu_p); \
|
||||||
|
break; \
|
||||||
|
case 4: \
|
||||||
|
put_unaligned_le32((uint32_t)(val), __gu_p); \
|
||||||
|
break; \
|
||||||
|
case 8: \
|
||||||
|
put_unaligned_le64((uint64_t)(val), __gu_p); \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
__bad_unaligned_access_size(); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
(void)0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define __put_unaligned_be(val, ptr) \
|
||||||
|
({ \
|
||||||
|
void *__gu_p = (ptr); \
|
||||||
|
switch (sizeof(*(ptr))) { \
|
||||||
|
case 1: \
|
||||||
|
*(uint8_t *)__gu_p = (uint8_t)(val); \
|
||||||
|
break; \
|
||||||
|
case 2: \
|
||||||
|
put_unaligned_be16((uint16_t)(val), __gu_p); \
|
||||||
|
break; \
|
||||||
|
case 4: \
|
||||||
|
put_unaligned_be32((uint32_t)(val), __gu_p); \
|
||||||
|
break; \
|
||||||
|
case 8: \
|
||||||
|
put_unaligned_be64((uint64_t)(val), __gu_p); \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
__bad_unaligned_access_size(); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
(void)0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#if _LITTLE_ENDIAN
|
||||||
|
# define get_unaligned __get_unaligned_le
|
||||||
|
# define put_unaligned __put_unaligned_le
|
||||||
|
#else
|
||||||
|
# define get_unaligned __get_unaligned_be
|
||||||
|
# define put_unaligned __put_unaligned_be
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ASM_UNALIGNED_H
|
12
contrib/linux-kernel/test/include/linux/compiler.h
Normal file
12
contrib/linux-kernel/test/include/linux/compiler.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef LINUX_COMIPLER_H_
|
||||||
|
#define LINUX_COMIPLER_H_
|
||||||
|
|
||||||
|
#ifndef __always_inline
|
||||||
|
# define __always_inline inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef noinline
|
||||||
|
# define noinline __attribute__((__noinline__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // LINUX_COMIPLER_H_
|
14
contrib/linux-kernel/test/include/linux/kernel.h
Normal file
14
contrib/linux-kernel/test/include/linux/kernel.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef LINUX_KERNEL_H_
|
||||||
|
#define LINUX_KERNEL_H_
|
||||||
|
|
||||||
|
#define ALIGN(x, a) ({ \
|
||||||
|
typeof(x) const __xe = (x); \
|
||||||
|
typeof(a) const __ae = (a); \
|
||||||
|
typeof(a) const __m = __ae - 1; \
|
||||||
|
typeof(x) const __r = __xe & __m; \
|
||||||
|
__xe + (__r ? (__ae - __r) : 0); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define PTR_ALIGN(p, a) (typeof(p))ALIGN((unsigned long long)(p), (a))
|
||||||
|
|
||||||
|
#endif // LINUX_KERNEL_H_
|
10
contrib/linux-kernel/test/include/linux/module.h
Normal file
10
contrib/linux-kernel/test/include/linux/module.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef LINUX_MODULE_H_
|
||||||
|
#define LINUX_MODULE_H_
|
||||||
|
|
||||||
|
#define EXPORT_SYMBOL(symbol) \
|
||||||
|
void* __##symbol = symbol
|
||||||
|
#define MODULE_LICENSE(license) static char const *const LICENSE = license
|
||||||
|
#define MODULE_DESCRIPTION(description) \
|
||||||
|
static char const *const DESCRIPTION = description
|
||||||
|
|
||||||
|
#endif // LINUX_MODULE_H_
|
1
contrib/linux-kernel/test/include/linux/string.h
Normal file
1
contrib/linux-kernel/test/include/linux/string.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include <string.h>
|
2
contrib/linux-kernel/test/include/linux/types.h
Normal file
2
contrib/linux-kernel/test/include/linux/types.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
Loading…
Reference in New Issue
Block a user