Update zstd to the latest upstream release v1.5.7. Imported cleanly from the
upstream tag v1.5.7-kernel, which is signed by upstream's signing key EF8FE99528B52FFD. Link: https://github.com/facebook/zstd/releases/tag/v1.5.7 Link: https://github.com/facebook/zstd/releases/tag/v1.5.7-kernel Link: https://keyserver.ubuntu.com/pks/lookup?search=EF8FE99528B52FFD&fingerprint=on&op=index Signed-off-by: Nick Terrell <terrelln@fb.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEmIwAqlFIzbQodPwyuzRpqaNEqPUFAmfjI5oACgkQuzRpqaNE qPUZJA//foLgy1etgBSTaUbCCIFxOLguFjmH2qfs/0yGX1ekhlv5jXobyUmKhYVM q0WR3G4lS1MNC40T9zNoKR0GfmZGyrCjOlGkwMEwdNYc+4y5sWujbckE+Xl/mgld Gz1NEEentFNIeC5htnBX797PJldqawHl6OYax/+6gVZyeLPYfbNYtTGy30fQIvcz vdIR/KCR2XzHn8+xah1zga5Ey/8LAXpgoYY9Pu3J3HWFRTV35laUe0nZ8EQ1mW3q nGritp0453RFJgD1wHewp1CgJx9lAixPAMPZ5BCOqOxsCxyalbvefWc6u/cS3zJM KEeKChyF6k5VqaW4A9jVeKq+HoGfngYjFJmELeKG4vK1d2UwMeDZRJ2IfkKej7xK 0awM0E0LO95H0mWEPhI3bmNbcfOLiJ4TIdWcr/sztF8Vv7fxKkK67Bwk4NTYmyPv sgFZMEyw0eFYNf8/0j9FCATu7AgmbF3yes4vExuAy0cgZaiNxOxaAspRM2A8Tmdf WWiAIsS6ZYwp6L1Gm6Rva+GRB15I3wevxOuEJ4kTsVVgvzgLQ+N6Fn5H5g2zgb1Q hgRlJx6ivyRpoaJhbBB7tqNsK38lQ53i0DHQ21jkBHEPFmRzLnvC+D205Dz3tQK5 kwPAGOCbxoiQbqzhY4NOm75ZPxzy8OW7ygjow0HaX6fgv9Y9n9s= =+maf -----END PGP SIGNATURE----- Merge tag 'zstd-linus-v6.15-rc1' of https://github.com/terrelln/linux Pull zstd updates from Nick Terrell: "Update zstd to the latest upstream release v1.5.7. The two major motivations for updating Zstandard are to keep the code up to date, and to expose API's needed by Intel for the QAT compression accelerator. Imported cleanly from the upstream tag v1.5.7-kernel, which is signed by upstream's signing key EF8FE99528B52FFD" Link: https://github.com/facebook/zstd/releases/tag/v1.5.7 Link: https://github.com/facebook/zstd/releases/tag/v1.5.7-kernel Link: https://keyserver.ubuntu.com/pks/lookup?search=EF8FE99528B52FFD&fingerprint=on&op=index * tag 'zstd-linus-v6.15-rc1' of https://github.com/terrelln/linux: zstd: Import upstream v1.5.7pull/1188/head
commit
e61f33273c
|
|
@ -1,6 +1,6 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -160,7 +160,6 @@ typedef ZSTD_parameters zstd_parameters;
|
||||||
zstd_parameters zstd_get_params(int level,
|
zstd_parameters zstd_get_params(int level,
|
||||||
unsigned long long estimated_src_size);
|
unsigned long long estimated_src_size);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zstd_get_cparams() - returns zstd_compression_parameters for selected level
|
* zstd_get_cparams() - returns zstd_compression_parameters for selected level
|
||||||
* @level: The compression level
|
* @level: The compression level
|
||||||
|
|
@ -173,9 +172,20 @@ zstd_parameters zstd_get_params(int level,
|
||||||
zstd_compression_parameters zstd_get_cparams(int level,
|
zstd_compression_parameters zstd_get_cparams(int level,
|
||||||
unsigned long long estimated_src_size, size_t dict_size);
|
unsigned long long estimated_src_size, size_t dict_size);
|
||||||
|
|
||||||
/* ====== Single-pass Compression ====== */
|
|
||||||
|
|
||||||
typedef ZSTD_CCtx zstd_cctx;
|
typedef ZSTD_CCtx zstd_cctx;
|
||||||
|
typedef ZSTD_cParameter zstd_cparameter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zstd_cctx_set_param() - sets a compression parameter
|
||||||
|
* @cctx: The context. Must have been initialized with zstd_init_cctx().
|
||||||
|
* @param: The parameter to set.
|
||||||
|
* @value: The value to set the parameter to.
|
||||||
|
*
|
||||||
|
* Return: Zero or an error, which can be checked using zstd_is_error().
|
||||||
|
*/
|
||||||
|
size_t zstd_cctx_set_param(zstd_cctx *cctx, zstd_cparameter param, int value);
|
||||||
|
|
||||||
|
/* ====== Single-pass Compression ====== */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zstd_cctx_workspace_bound() - max memory needed to initialize a zstd_cctx
|
* zstd_cctx_workspace_bound() - max memory needed to initialize a zstd_cctx
|
||||||
|
|
@ -190,6 +200,20 @@ typedef ZSTD_CCtx zstd_cctx;
|
||||||
*/
|
*/
|
||||||
size_t zstd_cctx_workspace_bound(const zstd_compression_parameters *parameters);
|
size_t zstd_cctx_workspace_bound(const zstd_compression_parameters *parameters);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zstd_cctx_workspace_bound_with_ext_seq_prod() - max memory needed to
|
||||||
|
* initialize a zstd_cctx when using the block-level external sequence
|
||||||
|
* producer API.
|
||||||
|
* @parameters: The compression parameters to be used.
|
||||||
|
*
|
||||||
|
* If multiple compression parameters might be used, the caller must call
|
||||||
|
* this function for each set of parameters and use the maximum size.
|
||||||
|
*
|
||||||
|
* Return: A lower bound on the size of the workspace that is passed to
|
||||||
|
* zstd_init_cctx().
|
||||||
|
*/
|
||||||
|
size_t zstd_cctx_workspace_bound_with_ext_seq_prod(const zstd_compression_parameters *parameters);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zstd_init_cctx() - initialize a zstd compression context
|
* zstd_init_cctx() - initialize a zstd compression context
|
||||||
* @workspace: The workspace to emplace the context into. It must outlive
|
* @workspace: The workspace to emplace the context into. It must outlive
|
||||||
|
|
@ -424,6 +448,16 @@ typedef ZSTD_CStream zstd_cstream;
|
||||||
*/
|
*/
|
||||||
size_t zstd_cstream_workspace_bound(const zstd_compression_parameters *cparams);
|
size_t zstd_cstream_workspace_bound(const zstd_compression_parameters *cparams);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zstd_cstream_workspace_bound_with_ext_seq_prod() - memory needed to initialize
|
||||||
|
* a zstd_cstream when using the block-level external sequence producer API.
|
||||||
|
* @cparams: The compression parameters to be used for compression.
|
||||||
|
*
|
||||||
|
* Return: A lower bound on the size of the workspace that is passed to
|
||||||
|
* zstd_init_cstream().
|
||||||
|
*/
|
||||||
|
size_t zstd_cstream_workspace_bound_with_ext_seq_prod(const zstd_compression_parameters *cparams);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zstd_init_cstream() - initialize a zstd streaming compression context
|
* zstd_init_cstream() - initialize a zstd streaming compression context
|
||||||
* @parameters The zstd parameters to use for compression.
|
* @parameters The zstd parameters to use for compression.
|
||||||
|
|
@ -583,6 +617,18 @@ size_t zstd_decompress_stream(zstd_dstream *dstream, zstd_out_buffer *output,
|
||||||
*/
|
*/
|
||||||
size_t zstd_find_frame_compressed_size(const void *src, size_t src_size);
|
size_t zstd_find_frame_compressed_size(const void *src, size_t src_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zstd_register_sequence_producer() - exposes the zstd library function
|
||||||
|
* ZSTD_registerSequenceProducer(). This is used for the block-level external
|
||||||
|
* sequence producer API. See upstream zstd.h for detailed documentation.
|
||||||
|
*/
|
||||||
|
typedef ZSTD_sequenceProducer_F zstd_sequence_producer_f;
|
||||||
|
void zstd_register_sequence_producer(
|
||||||
|
zstd_cctx *cctx,
|
||||||
|
void* sequence_producer_state,
|
||||||
|
zstd_sequence_producer_f sequence_producer
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct zstd_frame_params - zstd frame parameters stored in the frame header
|
* struct zstd_frame_params - zstd frame parameters stored in the frame header
|
||||||
* @frameContentSize: The frame content size, or ZSTD_CONTENTSIZE_UNKNOWN if not
|
* @frameContentSize: The frame content size, or ZSTD_CONTENTSIZE_UNKNOWN if not
|
||||||
|
|
@ -596,7 +642,7 @@ size_t zstd_find_frame_compressed_size(const void *src, size_t src_size);
|
||||||
*
|
*
|
||||||
* See zstd_lib.h.
|
* See zstd_lib.h.
|
||||||
*/
|
*/
|
||||||
typedef ZSTD_frameHeader zstd_frame_header;
|
typedef ZSTD_FrameHeader zstd_frame_header;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zstd_get_frame_header() - extracts parameters from a zstd or skippable frame
|
* zstd_get_frame_header() - extracts parameters from a zstd or skippable frame
|
||||||
|
|
@ -611,4 +657,35 @@ typedef ZSTD_frameHeader zstd_frame_header;
|
||||||
size_t zstd_get_frame_header(zstd_frame_header *params, const void *src,
|
size_t zstd_get_frame_header(zstd_frame_header *params, const void *src,
|
||||||
size_t src_size);
|
size_t src_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct zstd_sequence - a sequence of literals or a match
|
||||||
|
*
|
||||||
|
* @offset: The offset of the match
|
||||||
|
* @litLength: The literal length of the sequence
|
||||||
|
* @matchLength: The match length of the sequence
|
||||||
|
* @rep: Represents which repeat offset is used
|
||||||
|
*/
|
||||||
|
typedef ZSTD_Sequence zstd_sequence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zstd_compress_sequences_and_literals() - compress an array of zstd_sequence and literals
|
||||||
|
*
|
||||||
|
* @cctx: The zstd compression context.
|
||||||
|
* @dst: The buffer to compress the data into.
|
||||||
|
* @dst_capacity: The size of the destination buffer.
|
||||||
|
* @in_seqs: The array of zstd_sequence to compress.
|
||||||
|
* @in_seqs_size: The number of sequences in in_seqs.
|
||||||
|
* @literals: The literals associated to the sequences to be compressed.
|
||||||
|
* @lit_size: The size of the literals in the literals buffer.
|
||||||
|
* @lit_capacity: The size of the literals buffer.
|
||||||
|
* @decompressed_size: The size of the input data
|
||||||
|
*
|
||||||
|
* Return: The compressed size or an error, which can be checked using
|
||||||
|
* zstd_is_error().
|
||||||
|
*/
|
||||||
|
size_t zstd_compress_sequences_and_literals(zstd_cctx *cctx, void* dst, size_t dst_capacity,
|
||||||
|
const zstd_sequence *in_seqs, size_t in_seqs_size,
|
||||||
|
const void* literals, size_t lit_size, size_t lit_capacity,
|
||||||
|
size_t decompressed_size);
|
||||||
|
|
||||||
#endif /* LINUX_ZSTD_H */
|
#endif /* LINUX_ZSTD_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -12,13 +13,18 @@
|
||||||
#define ZSTD_ERRORS_H_398273423
|
#define ZSTD_ERRORS_H_398273423
|
||||||
|
|
||||||
|
|
||||||
/*===== dependency =====*/
|
|
||||||
#include <linux/types.h> /* size_t */
|
|
||||||
|
|
||||||
|
|
||||||
/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */
|
/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */
|
||||||
#define ZSTDERRORLIB_VISIBILITY
|
#define ZSTDERRORLIB_VISIBLE
|
||||||
#define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY
|
|
||||||
|
#ifndef ZSTDERRORLIB_HIDDEN
|
||||||
|
# if (__GNUC__ >= 4) && !defined(__MINGW32__)
|
||||||
|
# define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden")))
|
||||||
|
# else
|
||||||
|
# define ZSTDERRORLIB_HIDDEN
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE
|
||||||
|
|
||||||
/*-*********************************************
|
/*-*********************************************
|
||||||
* Error codes list
|
* Error codes list
|
||||||
|
|
@ -43,14 +49,18 @@ typedef enum {
|
||||||
ZSTD_error_frameParameter_windowTooLarge = 16,
|
ZSTD_error_frameParameter_windowTooLarge = 16,
|
||||||
ZSTD_error_corruption_detected = 20,
|
ZSTD_error_corruption_detected = 20,
|
||||||
ZSTD_error_checksum_wrong = 22,
|
ZSTD_error_checksum_wrong = 22,
|
||||||
|
ZSTD_error_literals_headerWrong = 24,
|
||||||
ZSTD_error_dictionary_corrupted = 30,
|
ZSTD_error_dictionary_corrupted = 30,
|
||||||
ZSTD_error_dictionary_wrong = 32,
|
ZSTD_error_dictionary_wrong = 32,
|
||||||
ZSTD_error_dictionaryCreation_failed = 34,
|
ZSTD_error_dictionaryCreation_failed = 34,
|
||||||
ZSTD_error_parameter_unsupported = 40,
|
ZSTD_error_parameter_unsupported = 40,
|
||||||
|
ZSTD_error_parameter_combination_unsupported = 41,
|
||||||
ZSTD_error_parameter_outOfBound = 42,
|
ZSTD_error_parameter_outOfBound = 42,
|
||||||
ZSTD_error_tableLog_tooLarge = 44,
|
ZSTD_error_tableLog_tooLarge = 44,
|
||||||
ZSTD_error_maxSymbolValue_tooLarge = 46,
|
ZSTD_error_maxSymbolValue_tooLarge = 46,
|
||||||
ZSTD_error_maxSymbolValue_tooSmall = 48,
|
ZSTD_error_maxSymbolValue_tooSmall = 48,
|
||||||
|
ZSTD_error_cannotProduce_uncompressedBlock = 49,
|
||||||
|
ZSTD_error_stabilityCondition_notRespected = 50,
|
||||||
ZSTD_error_stage_wrong = 60,
|
ZSTD_error_stage_wrong = 60,
|
||||||
ZSTD_error_init_missing = 62,
|
ZSTD_error_init_missing = 62,
|
||||||
ZSTD_error_memory_allocation = 64,
|
ZSTD_error_memory_allocation = 64,
|
||||||
|
|
@ -58,18 +68,18 @@ typedef enum {
|
||||||
ZSTD_error_dstSize_tooSmall = 70,
|
ZSTD_error_dstSize_tooSmall = 70,
|
||||||
ZSTD_error_srcSize_wrong = 72,
|
ZSTD_error_srcSize_wrong = 72,
|
||||||
ZSTD_error_dstBuffer_null = 74,
|
ZSTD_error_dstBuffer_null = 74,
|
||||||
|
ZSTD_error_noForwardProgress_destFull = 80,
|
||||||
|
ZSTD_error_noForwardProgress_inputEmpty = 82,
|
||||||
/* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
|
/* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
|
||||||
ZSTD_error_frameIndex_tooLarge = 100,
|
ZSTD_error_frameIndex_tooLarge = 100,
|
||||||
ZSTD_error_seekableIO = 102,
|
ZSTD_error_seekableIO = 102,
|
||||||
ZSTD_error_dstBuffer_wrong = 104,
|
ZSTD_error_dstBuffer_wrong = 104,
|
||||||
ZSTD_error_srcBuffer_wrong = 105,
|
ZSTD_error_srcBuffer_wrong = 105,
|
||||||
|
ZSTD_error_sequenceProducer_failed = 106,
|
||||||
|
ZSTD_error_externalSequences_invalid = 107,
|
||||||
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
||||||
} ZSTD_ErrorCode;
|
} ZSTD_ErrorCode;
|
||||||
|
|
||||||
/*! ZSTD_getErrorCode() :
|
|
||||||
convert a `size_t` function result into a `ZSTD_ErrorCode` enum type,
|
|
||||||
which can be used to compare with enum list published above */
|
|
||||||
ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult);
|
|
||||||
ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /*< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
|
ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /*< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,6 +1,6 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
# ################################################################
|
# ################################################################
|
||||||
# Copyright (c) Facebook, Inc.
|
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# This source code is licensed under both the BSD-style license (found in the
|
# This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -26,6 +26,7 @@ zstd_compress-y := \
|
||||||
compress/zstd_lazy.o \
|
compress/zstd_lazy.o \
|
||||||
compress/zstd_ldm.o \
|
compress/zstd_ldm.o \
|
||||||
compress/zstd_opt.o \
|
compress/zstd_opt.o \
|
||||||
|
compress/zstd_preSplit.o \
|
||||||
|
|
||||||
zstd_decompress-y := \
|
zstd_decompress-y := \
|
||||||
zstd_decompress_module.o \
|
zstd_decompress_module.o \
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This file provides custom allocation primitives
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZSTD_DEPS_NEED_MALLOC
|
||||||
|
#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */
|
||||||
|
|
||||||
|
#include "compiler.h" /* MEM_STATIC */
|
||||||
|
#define ZSTD_STATIC_LINKING_ONLY
|
||||||
|
#include <linux/zstd.h> /* ZSTD_customMem */
|
||||||
|
|
||||||
|
#ifndef ZSTD_ALLOCATIONS_H
|
||||||
|
#define ZSTD_ALLOCATIONS_H
|
||||||
|
|
||||||
|
/* custom memory allocation functions */
|
||||||
|
|
||||||
|
MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if (customMem.customAlloc)
|
||||||
|
return customMem.customAlloc(customMem.opaque, size);
|
||||||
|
return ZSTD_malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if (customMem.customAlloc) {
|
||||||
|
/* calloc implemented as malloc+memset;
|
||||||
|
* not as efficient as calloc, but next best guess for custom malloc */
|
||||||
|
void* const ptr = customMem.customAlloc(customMem.opaque, size);
|
||||||
|
ZSTD_memset(ptr, 0, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
return ZSTD_calloc(1, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void ZSTD_customFree(void* ptr, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if (ptr!=NULL) {
|
||||||
|
if (customMem.customFree)
|
||||||
|
customMem.customFree(customMem.opaque, ptr);
|
||||||
|
else
|
||||||
|
ZSTD_free(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZSTD_ALLOCATIONS_H */
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_BITS_H
|
||||||
|
#define ZSTD_BITS_H
|
||||||
|
|
||||||
|
#include "mem.h"
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
{
|
||||||
|
static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3,
|
||||||
|
30, 22, 20, 15, 25, 17, 4, 8,
|
||||||
|
31, 27, 13, 23, 21, 19, 16, 7,
|
||||||
|
26, 12, 18, 6, 11, 5, 10, 9};
|
||||||
|
return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
#if (__GNUC__ >= 4)
|
||||||
|
return (unsigned)__builtin_ctz(val);
|
||||||
|
#else
|
||||||
|
return ZSTD_countTrailingZeros32_fallback(val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
{
|
||||||
|
static const U32 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};
|
||||||
|
val |= val >> 1;
|
||||||
|
val |= val >> 2;
|
||||||
|
val |= val >> 4;
|
||||||
|
val |= val >> 8;
|
||||||
|
val |= val >> 16;
|
||||||
|
return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
#if (__GNUC__ >= 4)
|
||||||
|
return (unsigned)__builtin_clz(val);
|
||||||
|
#else
|
||||||
|
return ZSTD_countLeadingZeros32_fallback(val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
#if (__GNUC__ >= 4) && defined(__LP64__)
|
||||||
|
return (unsigned)__builtin_ctzll(val);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
U32 mostSignificantWord = (U32)(val >> 32);
|
||||||
|
U32 leastSignificantWord = (U32)val;
|
||||||
|
if (leastSignificantWord == 0) {
|
||||||
|
return 32 + ZSTD_countTrailingZeros32(mostSignificantWord);
|
||||||
|
} else {
|
||||||
|
return ZSTD_countTrailingZeros32(leastSignificantWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
#if (__GNUC__ >= 4)
|
||||||
|
return (unsigned)(__builtin_clzll(val));
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
U32 mostSignificantWord = (U32)(val >> 32);
|
||||||
|
U32 leastSignificantWord = (U32)val;
|
||||||
|
if (mostSignificantWord == 0) {
|
||||||
|
return 32 + ZSTD_countLeadingZeros32(leastSignificantWord);
|
||||||
|
} else {
|
||||||
|
return ZSTD_countLeadingZeros32(mostSignificantWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val)
|
||||||
|
{
|
||||||
|
if (MEM_isLittleEndian()) {
|
||||||
|
if (MEM_64bits()) {
|
||||||
|
return ZSTD_countTrailingZeros64((U64)val) >> 3;
|
||||||
|
} else {
|
||||||
|
return ZSTD_countTrailingZeros32((U32)val) >> 3;
|
||||||
|
}
|
||||||
|
} else { /* Big Endian CPU */
|
||||||
|
if (MEM_64bits()) {
|
||||||
|
return ZSTD_countLeadingZeros64((U64)val) >> 3;
|
||||||
|
} else {
|
||||||
|
return ZSTD_countLeadingZeros32((U32)val) >> 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
return 31 - ZSTD_countLeadingZeros32(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTD_rotateRight_*():
|
||||||
|
* Rotates a bitfield to the right by "count" bits.
|
||||||
|
* https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts
|
||||||
|
*/
|
||||||
|
MEM_STATIC
|
||||||
|
U64 ZSTD_rotateRight_U64(U64 const value, U32 count) {
|
||||||
|
assert(count < 64);
|
||||||
|
count &= 0x3F; /* for fickle pattern recognition */
|
||||||
|
return (value >> count) | (U64)(value << ((0U - count) & 0x3F));
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC
|
||||||
|
U32 ZSTD_rotateRight_U32(U32 const value, U32 count) {
|
||||||
|
assert(count < 32);
|
||||||
|
count &= 0x1F; /* for fickle pattern recognition */
|
||||||
|
return (value >> count) | (U32)(value << ((0U - count) & 0x1F));
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC
|
||||||
|
U16 ZSTD_rotateRight_U16(U16 const value, U32 count) {
|
||||||
|
assert(count < 16);
|
||||||
|
count &= 0x0F; /* for fickle pattern recognition */
|
||||||
|
return (value >> count) | (U16)(value << ((0U - count) & 0x0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZSTD_BITS_H */
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* bitstream
|
* bitstream
|
||||||
* Part of FSE library
|
* Part of FSE library
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -27,7 +28,7 @@
|
||||||
#include "compiler.h" /* UNLIKELY() */
|
#include "compiler.h" /* UNLIKELY() */
|
||||||
#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
|
#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
|
||||||
#include "error_private.h" /* error codes and messages */
|
#include "error_private.h" /* error codes and messages */
|
||||||
|
#include "bits.h" /* ZSTD_highbit32 */
|
||||||
|
|
||||||
/*=========================================
|
/*=========================================
|
||||||
* Target specific
|
* Target specific
|
||||||
|
|
@ -41,12 +42,13 @@
|
||||||
/*-******************************************
|
/*-******************************************
|
||||||
* bitStream encoding API (write forward)
|
* bitStream encoding API (write forward)
|
||||||
********************************************/
|
********************************************/
|
||||||
|
typedef size_t BitContainerType;
|
||||||
/* bitStream can mix input from multiple sources.
|
/* bitStream can mix input from multiple sources.
|
||||||
* A critical property of these streams is that they encode and decode in **reverse** direction.
|
* 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.
|
* So the first bit sequence you add will be the last to be read, like a LIFO stack.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t bitContainer;
|
BitContainerType bitContainer;
|
||||||
unsigned bitPos;
|
unsigned bitPos;
|
||||||
char* startPtr;
|
char* startPtr;
|
||||||
char* ptr;
|
char* ptr;
|
||||||
|
|
@ -54,7 +56,7 @@ typedef struct {
|
||||||
} BIT_CStream_t;
|
} BIT_CStream_t;
|
||||||
|
|
||||||
MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
|
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_addBits(BIT_CStream_t* bitC, BitContainerType value, unsigned nbBits);
|
||||||
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
|
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
|
||||||
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
||||||
|
|
||||||
|
|
@ -63,7 +65,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
||||||
* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
|
* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
|
||||||
*
|
*
|
||||||
* bits are first added to a local register.
|
* 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.
|
* Local register is BitContainerType, 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.
|
* 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.
|
* 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.
|
* After a flushBits, a maximum of 7 bits might still be stored into local register.
|
||||||
|
|
@ -80,28 +82,28 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
||||||
* bitStream decoding API (read backward)
|
* bitStream decoding API (read backward)
|
||||||
**********************************************/
|
**********************************************/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t bitContainer;
|
BitContainerType bitContainer;
|
||||||
unsigned bitsConsumed;
|
unsigned bitsConsumed;
|
||||||
const char* ptr;
|
const char* ptr;
|
||||||
const char* start;
|
const char* start;
|
||||||
const char* limitPtr;
|
const char* limitPtr;
|
||||||
} BIT_DStream_t;
|
} BIT_DStream_t;
|
||||||
|
|
||||||
typedef enum { BIT_DStream_unfinished = 0,
|
typedef enum { BIT_DStream_unfinished = 0, /* fully refilled */
|
||||||
BIT_DStream_endOfBuffer = 1,
|
BIT_DStream_endOfBuffer = 1, /* still some bits left in bitstream */
|
||||||
BIT_DStream_completed = 2,
|
BIT_DStream_completed = 2, /* bitstream entirely consumed, bit-exact */
|
||||||
BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
|
BIT_DStream_overflow = 3 /* user requested more bits than present in bitstream */
|
||||||
/* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
|
} BIT_DStream_status; /* result of BIT_reloadDStream() */
|
||||||
|
|
||||||
MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
|
MEM_STATIC size_t BIT_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 BitContainerType BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
|
||||||
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
|
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
|
||||||
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
|
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
|
||||||
|
|
||||||
|
|
||||||
/* Start by invoking BIT_initDStream().
|
/* Start by invoking BIT_initDStream().
|
||||||
* A chunk of the bitStream is then stored into a local register.
|
* A chunk of the bitStream is then stored into a local register.
|
||||||
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
|
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (BitContainerType).
|
||||||
* You can then retrieve bitFields stored into the local register, **in reverse order**.
|
* 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.
|
* 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.
|
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
|
||||||
|
|
@ -113,7 +115,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
|
||||||
/*-****************************************
|
/*-****************************************
|
||||||
* unsafe API
|
* unsafe API
|
||||||
******************************************/
|
******************************************/
|
||||||
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
|
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, BitContainerType value, unsigned nbBits);
|
||||||
/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
|
/* 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);
|
MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
|
||||||
|
|
@ -122,33 +124,6 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
|
||||||
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
|
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
|
||||||
/* faster, but works only if nbBits >= 1 */
|
/* faster, but works only if nbBits >= 1 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-**************************************************************
|
|
||||||
* Internal functions
|
|
||||||
****************************************************************/
|
|
||||||
MEM_STATIC unsigned BIT_highbit32 (U32 val)
|
|
||||||
{
|
|
||||||
assert(val != 0);
|
|
||||||
{
|
|
||||||
# if (__GNUC__ >= 3) /* Use GCC Intrinsic */
|
|
||||||
return __builtin_clz (val) ^ 31;
|
|
||||||
# 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 =====*/
|
/*===== Local Constants =====*/
|
||||||
static const unsigned BIT_mask[] = {
|
static const unsigned BIT_mask[] = {
|
||||||
0, 1, 3, 7, 0xF, 0x1F,
|
0, 1, 3, 7, 0xF, 0x1F,
|
||||||
|
|
@ -178,16 +153,22 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE BitContainerType BIT_getLowerBits(BitContainerType bitContainer, U32 const nbBits)
|
||||||
|
{
|
||||||
|
assert(nbBits < BIT_MASK_SIZE);
|
||||||
|
return bitContainer & BIT_mask[nbBits];
|
||||||
|
}
|
||||||
|
|
||||||
/*! BIT_addBits() :
|
/*! BIT_addBits() :
|
||||||
* can add up to 31 bits into `bitC`.
|
* can add up to 31 bits into `bitC`.
|
||||||
* Note : does not check for register overflow ! */
|
* Note : does not check for register overflow ! */
|
||||||
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
|
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
|
||||||
size_t value, unsigned nbBits)
|
BitContainerType value, unsigned nbBits)
|
||||||
{
|
{
|
||||||
DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32);
|
DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32);
|
||||||
assert(nbBits < BIT_MASK_SIZE);
|
assert(nbBits < BIT_MASK_SIZE);
|
||||||
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
||||||
bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
|
bitC->bitContainer |= BIT_getLowerBits(value, nbBits) << bitC->bitPos;
|
||||||
bitC->bitPos += nbBits;
|
bitC->bitPos += nbBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +176,7 @@ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
|
||||||
* works only if `value` is _clean_,
|
* works only if `value` is _clean_,
|
||||||
* meaning all high bits above nbBits are 0 */
|
* meaning all high bits above nbBits are 0 */
|
||||||
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
|
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
|
||||||
size_t value, unsigned nbBits)
|
BitContainerType value, unsigned nbBits)
|
||||||
{
|
{
|
||||||
assert((value>>nbBits) == 0);
|
assert((value>>nbBits) == 0);
|
||||||
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
||||||
|
|
@ -242,7 +223,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
|
||||||
BIT_addBitsFast(bitC, 1, 1); /* endMark */
|
BIT_addBitsFast(bitC, 1, 1); /* endMark */
|
||||||
BIT_flushBits(bitC);
|
BIT_flushBits(bitC);
|
||||||
if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
|
if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
|
||||||
return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
|
return (size_t)(bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -266,35 +247,35 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
|
||||||
bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
|
bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
|
||||||
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||||
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
||||||
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
|
bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
|
||||||
if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
|
if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
|
||||||
} else {
|
} else {
|
||||||
bitD->ptr = bitD->start;
|
bitD->ptr = bitD->start;
|
||||||
bitD->bitContainer = *(const BYTE*)(bitD->start);
|
bitD->bitContainer = *(const BYTE*)(bitD->start);
|
||||||
switch(srcSize)
|
switch(srcSize)
|
||||||
{
|
{
|
||||||
case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
|
case 7: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
|
||||||
ZSTD_FALLTHROUGH;
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
|
case 6: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
|
||||||
ZSTD_FALLTHROUGH;
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
|
case 5: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
|
||||||
ZSTD_FALLTHROUGH;
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
|
case 4: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[3]) << 24;
|
||||||
ZSTD_FALLTHROUGH;
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
|
case 3: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[2]) << 16;
|
||||||
ZSTD_FALLTHROUGH;
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
|
case 2: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[1]) << 8;
|
||||||
ZSTD_FALLTHROUGH;
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
||||||
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
|
bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0;
|
||||||
if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
|
if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
|
||||||
}
|
}
|
||||||
bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
|
bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
|
||||||
|
|
@ -303,12 +284,12 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
|
||||||
return srcSize;
|
return srcSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
|
FORCE_INLINE_TEMPLATE BitContainerType BIT_getUpperBits(BitContainerType bitContainer, U32 const start)
|
||||||
{
|
{
|
||||||
return bitContainer >> start;
|
return bitContainer >> start;
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
|
FORCE_INLINE_TEMPLATE BitContainerType BIT_getMiddleBits(BitContainerType bitContainer, U32 const start, U32 const nbBits)
|
||||||
{
|
{
|
||||||
U32 const regMask = sizeof(bitContainer)*8 - 1;
|
U32 const regMask = sizeof(bitContainer)*8 - 1;
|
||||||
/* if start > regMask, bitstream is corrupted, and result is undefined */
|
/* if start > regMask, bitstream is corrupted, and result is undefined */
|
||||||
|
|
@ -318,26 +299,20 @@ MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 c
|
||||||
* such cpus old (pre-Haswell, 2013) and their performance is not of that
|
* such cpus old (pre-Haswell, 2013) and their performance is not of that
|
||||||
* importance.
|
* importance.
|
||||||
*/
|
*/
|
||||||
#if defined(__x86_64__) || defined(_M_X86)
|
#if defined(__x86_64__) || defined(_M_X64)
|
||||||
return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1);
|
return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1);
|
||||||
#else
|
#else
|
||||||
return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
|
return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
|
|
||||||
{
|
|
||||||
assert(nbBits < BIT_MASK_SIZE);
|
|
||||||
return bitContainer & BIT_mask[nbBits];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_lookBits() :
|
/*! BIT_lookBits() :
|
||||||
* Provides next n bits from local register.
|
* Provides next n bits from local register.
|
||||||
* local register is not modified.
|
* local register is not modified.
|
||||||
* On 32-bits, maxNbBits==24.
|
* On 32-bits, maxNbBits==24.
|
||||||
* On 64-bits, maxNbBits==56.
|
* On 64-bits, maxNbBits==56.
|
||||||
* @return : value extracted */
|
* @return : value extracted */
|
||||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
|
FORCE_INLINE_TEMPLATE BitContainerType BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
|
||||||
{
|
{
|
||||||
/* arbitrate between double-shift and shift+mask */
|
/* arbitrate between double-shift and shift+mask */
|
||||||
#if 1
|
#if 1
|
||||||
|
|
@ -353,14 +328,14 @@ MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U3
|
||||||
|
|
||||||
/*! BIT_lookBitsFast() :
|
/*! BIT_lookBitsFast() :
|
||||||
* unsafe version; only works if nbBits >= 1 */
|
* unsafe version; only works if nbBits >= 1 */
|
||||||
MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
|
MEM_STATIC BitContainerType BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
|
||||||
{
|
{
|
||||||
U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
|
U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
|
||||||
assert(nbBits >= 1);
|
assert(nbBits >= 1);
|
||||||
return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
|
return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
FORCE_INLINE_TEMPLATE void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||||
{
|
{
|
||||||
bitD->bitsConsumed += nbBits;
|
bitD->bitsConsumed += nbBits;
|
||||||
}
|
}
|
||||||
|
|
@ -369,23 +344,38 @@ MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||||
* Read (consume) next n bits from local register and update.
|
* Read (consume) next n bits from local register and update.
|
||||||
* Pay attention to not read more than nbBits contained into local register.
|
* Pay attention to not read more than nbBits contained into local register.
|
||||||
* @return : extracted value. */
|
* @return : extracted value. */
|
||||||
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
|
FORCE_INLINE_TEMPLATE BitContainerType BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
|
||||||
{
|
{
|
||||||
size_t const value = BIT_lookBits(bitD, nbBits);
|
BitContainerType const value = BIT_lookBits(bitD, nbBits);
|
||||||
BIT_skipBits(bitD, nbBits);
|
BIT_skipBits(bitD, nbBits);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! BIT_readBitsFast() :
|
/*! BIT_readBitsFast() :
|
||||||
* unsafe version; only works only if nbBits >= 1 */
|
* unsafe version; only works if nbBits >= 1 */
|
||||||
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
|
MEM_STATIC BitContainerType BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
|
||||||
{
|
{
|
||||||
size_t const value = BIT_lookBitsFast(bitD, nbBits);
|
BitContainerType const value = BIT_lookBitsFast(bitD, nbBits);
|
||||||
assert(nbBits >= 1);
|
assert(nbBits >= 1);
|
||||||
BIT_skipBits(bitD, nbBits);
|
BIT_skipBits(bitD, nbBits);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! BIT_reloadDStream_internal() :
|
||||||
|
* Simple variant of BIT_reloadDStream(), with two conditions:
|
||||||
|
* 1. bitstream is valid : bitsConsumed <= sizeof(bitD->bitContainer)*8
|
||||||
|
* 2. look window is valid after shifted down : bitD->ptr >= bitD->start
|
||||||
|
*/
|
||||||
|
MEM_STATIC BIT_DStream_status BIT_reloadDStream_internal(BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
|
||||||
|
bitD->ptr -= bitD->bitsConsumed >> 3;
|
||||||
|
assert(bitD->ptr >= bitD->start);
|
||||||
|
bitD->bitsConsumed &= 7;
|
||||||
|
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||||
|
return BIT_DStream_unfinished;
|
||||||
|
}
|
||||||
|
|
||||||
/*! BIT_reloadDStreamFast() :
|
/*! BIT_reloadDStreamFast() :
|
||||||
* Similar to BIT_reloadDStream(), but with two differences:
|
* Similar to BIT_reloadDStream(), but with two differences:
|
||||||
* 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
|
* 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
|
||||||
|
|
@ -396,31 +386,35 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
|
||||||
{
|
{
|
||||||
if (UNLIKELY(bitD->ptr < bitD->limitPtr))
|
if (UNLIKELY(bitD->ptr < bitD->limitPtr))
|
||||||
return BIT_DStream_overflow;
|
return BIT_DStream_overflow;
|
||||||
assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
|
return BIT_reloadDStream_internal(bitD);
|
||||||
bitD->ptr -= bitD->bitsConsumed >> 3;
|
|
||||||
bitD->bitsConsumed &= 7;
|
|
||||||
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
|
||||||
return BIT_DStream_unfinished;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! BIT_reloadDStream() :
|
/*! BIT_reloadDStream() :
|
||||||
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
||||||
* This function is safe, it guarantees it will not read beyond src buffer.
|
* This function is safe, it guarantees it will not never beyond src buffer.
|
||||||
* @return : status of `BIT_DStream_t` internal register.
|
* @return : status of `BIT_DStream_t` internal register.
|
||||||
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
|
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
|
||||||
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
FORCE_INLINE_TEMPLATE BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
||||||
{
|
{
|
||||||
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
|
/* note : once in overflow mode, a bitstream remains in this mode until it's reset */
|
||||||
|
if (UNLIKELY(bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))) {
|
||||||
|
static const BitContainerType zeroFilled = 0;
|
||||||
|
bitD->ptr = (const char*)&zeroFilled; /* aliasing is allowed for char */
|
||||||
|
/* overflow detected, erroneous scenario or end of stream: no update */
|
||||||
return BIT_DStream_overflow;
|
return BIT_DStream_overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(bitD->ptr >= bitD->start);
|
||||||
|
|
||||||
if (bitD->ptr >= bitD->limitPtr) {
|
if (bitD->ptr >= bitD->limitPtr) {
|
||||||
return BIT_reloadDStreamFast(bitD);
|
return BIT_reloadDStream_internal(bitD);
|
||||||
}
|
}
|
||||||
if (bitD->ptr == bitD->start) {
|
if (bitD->ptr == bitD->start) {
|
||||||
|
/* reached end of bitStream => no update */
|
||||||
if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
|
if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
|
||||||
return BIT_DStream_completed;
|
return BIT_DStream_completed;
|
||||||
}
|
}
|
||||||
/* start < ptr < limitPtr */
|
/* start < ptr < limitPtr => cautious update */
|
||||||
{ U32 nbBytes = bitD->bitsConsumed >> 3;
|
{ U32 nbBytes = bitD->bitsConsumed >> 3;
|
||||||
BIT_DStream_status result = BIT_DStream_unfinished;
|
BIT_DStream_status result = BIT_DStream_unfinished;
|
||||||
if (bitD->ptr - nbBytes < bitD->start) {
|
if (bitD->ptr - nbBytes < bitD->start) {
|
||||||
|
|
@ -442,5 +436,4 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
|
||||||
return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
|
return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* BITSTREAM_H_MODULE */
|
#endif /* BITSTREAM_H_MODULE */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,6 +12,8 @@
|
||||||
#ifndef ZSTD_COMPILER_H
|
#ifndef ZSTD_COMPILER_H
|
||||||
#define ZSTD_COMPILER_H
|
#define ZSTD_COMPILER_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include "portability_macros.h"
|
#include "portability_macros.h"
|
||||||
|
|
||||||
/*-*******************************************************
|
/*-*******************************************************
|
||||||
|
|
@ -41,12 +44,15 @@
|
||||||
*/
|
*/
|
||||||
#define WIN_CDECL
|
#define WIN_CDECL
|
||||||
|
|
||||||
|
/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
|
||||||
|
#define UNUSED_ATTR __attribute__((unused))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
|
* FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
|
||||||
* parameters. They must be inlined for the compiler to eliminate the constant
|
* parameters. They must be inlined for the compiler to eliminate the constant
|
||||||
* branches.
|
* branches.
|
||||||
*/
|
*/
|
||||||
#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
|
#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR UNUSED_ATTR
|
||||||
/*
|
/*
|
||||||
* HINT_INLINE is used to help the compiler generate better code. It is *not*
|
* HINT_INLINE is used to help the compiler generate better code. It is *not*
|
||||||
* used for "templates", so it can be tweaked based on the compilers
|
* used for "templates", so it can be tweaked based on the compilers
|
||||||
|
|
@ -61,11 +67,21 @@
|
||||||
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
|
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
|
||||||
# define HINT_INLINE static INLINE_KEYWORD
|
# define HINT_INLINE static INLINE_KEYWORD
|
||||||
#else
|
#else
|
||||||
# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
|
# define HINT_INLINE FORCE_INLINE_TEMPLATE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
|
/* "soft" inline :
|
||||||
#define UNUSED_ATTR __attribute__((unused))
|
* The compiler is free to select if it's a good idea to inline or not.
|
||||||
|
* The main objective is to silence compiler warnings
|
||||||
|
* when a defined function in included but not used.
|
||||||
|
*
|
||||||
|
* Note : this macro is prefixed `MEM_` because it used to be provided by `mem.h` unit.
|
||||||
|
* Updating the prefix is probably preferable, but requires a fairly large codemod,
|
||||||
|
* since this name is used everywhere.
|
||||||
|
*/
|
||||||
|
#ifndef MEM_STATIC /* already defined in Linux Kernel mem.h */
|
||||||
|
#define MEM_STATIC static __inline UNUSED_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
/* force no inlining */
|
/* force no inlining */
|
||||||
#define FORCE_NOINLINE static __attribute__((__noinline__))
|
#define FORCE_NOINLINE static __attribute__((__noinline__))
|
||||||
|
|
@ -86,23 +102,24 @@
|
||||||
# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
|
# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
|
||||||
# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
|
# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
|
# define PREFETCH_L1(ptr) do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0)
|
||||||
# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
|
# define PREFETCH_L2(ptr) do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0)
|
||||||
#else
|
#else
|
||||||
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
|
# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||||
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
|
# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||||
#endif /* NO_PREFETCH */
|
#endif /* NO_PREFETCH */
|
||||||
|
|
||||||
#define CACHELINE_SIZE 64
|
#define CACHELINE_SIZE 64
|
||||||
|
|
||||||
#define PREFETCH_AREA(p, s) { \
|
#define PREFETCH_AREA(p, s) \
|
||||||
|
do { \
|
||||||
const char* const _ptr = (const char*)(p); \
|
const char* const _ptr = (const char*)(p); \
|
||||||
size_t const _size = (size_t)(s); \
|
size_t const _size = (size_t)(s); \
|
||||||
size_t _pos; \
|
size_t _pos; \
|
||||||
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
|
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
|
||||||
PREFETCH_L2(_ptr + _pos); \
|
PREFETCH_L2(_ptr + _pos); \
|
||||||
} \
|
} \
|
||||||
}
|
} while (0)
|
||||||
|
|
||||||
/* vectorization
|
/* vectorization
|
||||||
* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
|
* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
|
||||||
|
|
@ -126,16 +143,13 @@
|
||||||
#define UNLIKELY(x) (__builtin_expect((x), 0))
|
#define UNLIKELY(x) (__builtin_expect((x), 0))
|
||||||
|
|
||||||
#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
|
#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
|
||||||
# define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); }
|
# define ZSTD_UNREACHABLE do { assert(0), __builtin_unreachable(); } while (0)
|
||||||
#else
|
#else
|
||||||
# define ZSTD_UNREACHABLE { assert(0); }
|
# define ZSTD_UNREACHABLE do { assert(0); } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* disable warnings */
|
/* disable warnings */
|
||||||
|
|
||||||
/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/
|
|
||||||
|
|
||||||
|
|
||||||
/* compile time determination of SIMD support */
|
/* compile time determination of SIMD support */
|
||||||
|
|
||||||
/* C-language Attributes are added in C23. */
|
/* C-language Attributes are added in C23. */
|
||||||
|
|
@ -158,9 +172,15 @@
|
||||||
#define ZSTD_FALLTHROUGH fallthrough
|
#define ZSTD_FALLTHROUGH fallthrough
|
||||||
|
|
||||||
/*-**************************************************************
|
/*-**************************************************************
|
||||||
* Alignment check
|
* Alignment
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
|
|
||||||
|
/* @return 1 if @u is a 2^n value, 0 otherwise
|
||||||
|
* useful to check a value is valid for alignment restrictions */
|
||||||
|
MEM_STATIC int ZSTD_isPower2(size_t u) {
|
||||||
|
return (u & (u-1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* this test was initially positioned in mem.h,
|
/* this test was initially positioned in mem.h,
|
||||||
* but this file is removed (or replaced) for linux kernel
|
* but this file is removed (or replaced) for linux kernel
|
||||||
* so it's now hosted in compiler.h,
|
* so it's now hosted in compiler.h,
|
||||||
|
|
@ -175,10 +195,95 @@
|
||||||
|
|
||||||
#endif /* ZSTD_ALIGNOF */
|
#endif /* ZSTD_ALIGNOF */
|
||||||
|
|
||||||
|
#ifndef ZSTD_ALIGNED
|
||||||
|
/* C90-compatible alignment macro (GCC/Clang). Adjust for other compilers if needed. */
|
||||||
|
#define ZSTD_ALIGNED(a) __attribute__((aligned(a)))
|
||||||
|
#endif /* ZSTD_ALIGNED */
|
||||||
|
|
||||||
|
|
||||||
/*-**************************************************************
|
/*-**************************************************************
|
||||||
* Sanitizer
|
* Sanitizer
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Zstd relies on pointer overflow in its decompressor.
|
||||||
|
* We add this attribute to functions that rely on pointer overflow.
|
||||||
|
*/
|
||||||
|
#ifndef ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
# if __has_attribute(no_sanitize)
|
||||||
|
# if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 8
|
||||||
|
/* gcc < 8 only has signed-integer-overlow which triggers on pointer overflow */
|
||||||
|
# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("signed-integer-overflow")))
|
||||||
|
# else
|
||||||
|
/* older versions of clang [3.7, 5.0) will warn that pointer-overflow is ignored. */
|
||||||
|
# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("pointer-overflow")))
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to perform a wrapped pointer difference without triggering
|
||||||
|
* UBSAN.
|
||||||
|
*
|
||||||
|
* @returns lhs - rhs with wrapping
|
||||||
|
*/
|
||||||
|
MEM_STATIC
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
ptrdiff_t ZSTD_wrappedPtrDiff(unsigned char const* lhs, unsigned char const* rhs)
|
||||||
|
{
|
||||||
|
return lhs - rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to perform a wrapped pointer add without triggering UBSAN.
|
||||||
|
*
|
||||||
|
* @return ptr + add with wrapping
|
||||||
|
*/
|
||||||
|
MEM_STATIC
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add)
|
||||||
|
{
|
||||||
|
return ptr + add;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to perform a wrapped pointer subtraction without triggering
|
||||||
|
* UBSAN.
|
||||||
|
*
|
||||||
|
* @return ptr - sub with wrapping
|
||||||
|
*/
|
||||||
|
MEM_STATIC
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub)
|
||||||
|
{
|
||||||
|
return ptr - sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to add to a pointer that works around C's undefined behavior
|
||||||
|
* of adding 0 to NULL.
|
||||||
|
*
|
||||||
|
* @returns `ptr + add` except it defines `NULL + 0 == NULL`.
|
||||||
|
*/
|
||||||
|
MEM_STATIC
|
||||||
|
unsigned char* ZSTD_maybeNullPtrAdd(unsigned char* ptr, ptrdiff_t add)
|
||||||
|
{
|
||||||
|
return add > 0 ? ptr + add : ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Issue #3240 reports an ASAN failure on an llvm-mingw build. Out of an
|
||||||
|
* abundance of caution, disable our custom poisoning on mingw. */
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#ifndef ZSTD_ASAN_DONT_POISON_WORKSPACE
|
||||||
|
#define ZSTD_ASAN_DONT_POISON_WORKSPACE 1
|
||||||
|
#endif
|
||||||
|
#ifndef ZSTD_MSAN_DONT_POISON_WORKSPACE
|
||||||
|
#define ZSTD_MSAN_DONT_POISON_WORKSPACE 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ZSTD_COMPILER_H */
|
#endif /* ZSTD_COMPILER_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* debug
|
* debug
|
||||||
* Part of FSE library
|
* Part of FSE library
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -21,4 +22,10 @@
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
#if (DEBUGLEVEL>=2)
|
||||||
|
/* We only use this when DEBUGLEVEL>=2, but we get -Werror=pedantic errors if a
|
||||||
|
* translation unit is empty. So remove this from Linux kernel builds, but
|
||||||
|
* otherwise just leave it in.
|
||||||
|
*/
|
||||||
int g_debuglevel = DEBUGLEVEL;
|
int g_debuglevel = DEBUGLEVEL;
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* debug
|
* debug
|
||||||
* Part of FSE library
|
* Part of FSE library
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -33,7 +34,6 @@
|
||||||
#define DEBUG_H_12987983217
|
#define DEBUG_H_12987983217
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* static assert is triggered at compile time, leaving no runtime artefact.
|
/* static assert is triggered at compile time, leaving no runtime artefact.
|
||||||
* static assert only works with compile-time constants.
|
* static assert only works with compile-time constants.
|
||||||
* Also, this variant can only be used inside a function. */
|
* Also, this variant can only be used inside a function. */
|
||||||
|
|
@ -82,20 +82,27 @@ extern int g_debuglevel; /* the variable is only declared,
|
||||||
It's useful when enabling very verbose levels
|
It's useful when enabling very verbose levels
|
||||||
on selective conditions (such as position in src) */
|
on selective conditions (such as position in src) */
|
||||||
|
|
||||||
# define RAWLOG(l, ...) { \
|
# define RAWLOG(l, ...) \
|
||||||
|
do { \
|
||||||
if (l<=g_debuglevel) { \
|
if (l<=g_debuglevel) { \
|
||||||
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
|
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
|
||||||
} }
|
} \
|
||||||
# define DEBUGLOG(l, ...) { \
|
} while (0)
|
||||||
|
|
||||||
|
#define STRINGIFY(x) #x
|
||||||
|
#define TOSTRING(x) STRINGIFY(x)
|
||||||
|
#define LINE_AS_STRING TOSTRING(__LINE__)
|
||||||
|
|
||||||
|
# define DEBUGLOG(l, ...) \
|
||||||
|
do { \
|
||||||
if (l<=g_debuglevel) { \
|
if (l<=g_debuglevel) { \
|
||||||
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
|
ZSTD_DEBUG_PRINT(__FILE__ ":" LINE_AS_STRING ": " __VA_ARGS__); \
|
||||||
ZSTD_DEBUG_PRINT(" \n"); \
|
ZSTD_DEBUG_PRINT(" \n"); \
|
||||||
} }
|
} \
|
||||||
|
} while (0)
|
||||||
#else
|
#else
|
||||||
# define RAWLOG(l, ...) {} /* disabled */
|
# define RAWLOG(l, ...) do { } while (0) /* disabled */
|
||||||
# define DEBUGLOG(l, ...) {} /* disabled */
|
# define DEBUGLOG(l, ...) do { } while (0) /* disabled */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* DEBUG_H_12987983217 */
|
#endif /* DEBUG_H_12987983217 */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* Common functions of New Generation Entropy library
|
* Common functions of New Generation Entropy library
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -19,8 +20,8 @@
|
||||||
#include "error_private.h" /* ERR_*, ERROR */
|
#include "error_private.h" /* ERR_*, ERROR */
|
||||||
#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
|
#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
|
||||||
#include "fse.h"
|
#include "fse.h"
|
||||||
#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */
|
|
||||||
#include "huf.h"
|
#include "huf.h"
|
||||||
|
#include "bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */
|
||||||
|
|
||||||
|
|
||||||
/*=== Version ===*/
|
/*=== Version ===*/
|
||||||
|
|
@ -38,23 +39,6 @@ const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
|
||||||
/*-**************************************************************
|
/*-**************************************************************
|
||||||
* FSE NCount encoding-decoding
|
* FSE NCount encoding-decoding
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
static U32 FSE_ctz(U32 val)
|
|
||||||
{
|
|
||||||
assert(val != 0);
|
|
||||||
{
|
|
||||||
# if (__GNUC__ >= 3) /* GCC Intrinsic */
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
# else /* Software version */
|
|
||||||
U32 count = 0;
|
|
||||||
while ((val & 1) == 0) {
|
|
||||||
val >>= 1;
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
|
size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
|
||||||
const void* headerBuffer, size_t hbSize)
|
const void* headerBuffer, size_t hbSize)
|
||||||
|
|
@ -102,7 +86,7 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne
|
||||||
* repeat.
|
* repeat.
|
||||||
* Avoid UB by setting the high bit to 1.
|
* Avoid UB by setting the high bit to 1.
|
||||||
*/
|
*/
|
||||||
int repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
|
int repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1;
|
||||||
while (repeats >= 12) {
|
while (repeats >= 12) {
|
||||||
charnum += 3 * 12;
|
charnum += 3 * 12;
|
||||||
if (LIKELY(ip <= iend-7)) {
|
if (LIKELY(ip <= iend-7)) {
|
||||||
|
|
@ -113,7 +97,7 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne
|
||||||
ip = iend - 4;
|
ip = iend - 4;
|
||||||
}
|
}
|
||||||
bitStream = MEM_readLE32(ip) >> bitCount;
|
bitStream = MEM_readLE32(ip) >> bitCount;
|
||||||
repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
|
repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1;
|
||||||
}
|
}
|
||||||
charnum += 3 * repeats;
|
charnum += 3 * repeats;
|
||||||
bitStream >>= 2 * repeats;
|
bitStream >>= 2 * repeats;
|
||||||
|
|
@ -178,7 +162,7 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne
|
||||||
* know that threshold > 1.
|
* know that threshold > 1.
|
||||||
*/
|
*/
|
||||||
if (remaining <= 1) break;
|
if (remaining <= 1) break;
|
||||||
nbBits = BIT_highbit32(remaining) + 1;
|
nbBits = ZSTD_highbit32(remaining) + 1;
|
||||||
threshold = 1 << (nbBits - 1);
|
threshold = 1 << (nbBits - 1);
|
||||||
}
|
}
|
||||||
if (charnum >= maxSV1) break;
|
if (charnum >= maxSV1) break;
|
||||||
|
|
@ -253,7 +237,7 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
const void* src, size_t srcSize)
|
const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
|
U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
|
||||||
return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0);
|
return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* flags */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE size_t
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
|
@ -301,14 +285,14 @@ HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
if (weightTotal == 0) return ERROR(corruption_detected);
|
if (weightTotal == 0) return ERROR(corruption_detected);
|
||||||
|
|
||||||
/* get last non-null symbol weight (implied, total must be 2^n) */
|
/* get last non-null symbol weight (implied, total must be 2^n) */
|
||||||
{ U32 const tableLog = BIT_highbit32(weightTotal) + 1;
|
{ U32 const tableLog = ZSTD_highbit32(weightTotal) + 1;
|
||||||
if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
|
if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
|
||||||
*tableLogPtr = tableLog;
|
*tableLogPtr = tableLog;
|
||||||
/* determine last weight */
|
/* determine last weight */
|
||||||
{ U32 const total = 1 << tableLog;
|
{ U32 const total = 1 << tableLog;
|
||||||
U32 const rest = total - weightTotal;
|
U32 const rest = total - weightTotal;
|
||||||
U32 const verif = 1 << BIT_highbit32(rest);
|
U32 const verif = 1 << ZSTD_highbit32(rest);
|
||||||
U32 const lastWeight = BIT_highbit32(rest) + 1;
|
U32 const lastWeight = ZSTD_highbit32(rest) + 1;
|
||||||
if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
|
if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
|
||||||
huffWeight[oSize] = (BYTE)lastWeight;
|
huffWeight[oSize] = (BYTE)lastWeight;
|
||||||
rankStats[lastWeight]++;
|
rankStats[lastWeight]++;
|
||||||
|
|
@ -345,13 +329,13 @@ size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
U32* nbSymbolsPtr, U32* tableLogPtr,
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
int bmi2)
|
int flags)
|
||||||
{
|
{
|
||||||
#if DYNAMIC_BMI2
|
#if DYNAMIC_BMI2
|
||||||
if (bmi2) {
|
if (flags & HUF_flags_bmi2) {
|
||||||
return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
|
return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
(void)bmi2;
|
(void)flags;
|
||||||
return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
|
return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -27,9 +28,11 @@ const char* ERR_getErrorString(ERR_enum code)
|
||||||
case PREFIX(version_unsupported): return "Version not supported";
|
case PREFIX(version_unsupported): return "Version not supported";
|
||||||
case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
|
case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
|
||||||
case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
|
case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
|
||||||
case PREFIX(corruption_detected): return "Corrupted block detected";
|
case PREFIX(corruption_detected): return "Data corruption detected";
|
||||||
case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
|
case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
|
||||||
|
case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification";
|
||||||
case PREFIX(parameter_unsupported): return "Unsupported parameter";
|
case PREFIX(parameter_unsupported): return "Unsupported parameter";
|
||||||
|
case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters";
|
||||||
case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
|
case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
|
||||||
case PREFIX(init_missing): return "Context should be init first";
|
case PREFIX(init_missing): return "Context should be init first";
|
||||||
case PREFIX(memory_allocation): return "Allocation error : not enough memory";
|
case PREFIX(memory_allocation): return "Allocation error : not enough memory";
|
||||||
|
|
@ -38,17 +41,23 @@ const char* ERR_getErrorString(ERR_enum code)
|
||||||
case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
|
case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
|
||||||
case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
|
case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
|
||||||
case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
|
case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
|
||||||
|
case PREFIX(cannotProduce_uncompressedBlock): return "This mode cannot generate an uncompressed block";
|
||||||
|
case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected";
|
||||||
case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
|
case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
|
||||||
case PREFIX(dictionary_wrong): return "Dictionary mismatch";
|
case PREFIX(dictionary_wrong): return "Dictionary mismatch";
|
||||||
case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
|
case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
|
||||||
case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
|
case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
|
||||||
case PREFIX(srcSize_wrong): return "Src size is incorrect";
|
case PREFIX(srcSize_wrong): return "Src size is incorrect";
|
||||||
case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
|
case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
|
||||||
|
case PREFIX(noForwardProgress_destFull): return "Operation made no progress over multiple calls, due to output buffer being full";
|
||||||
|
case PREFIX(noForwardProgress_inputEmpty): return "Operation made no progress over multiple calls, due to input being empty";
|
||||||
/* following error codes are not stable and may be removed or changed in a future version */
|
/* following error codes are not stable and may be removed or changed in a future version */
|
||||||
case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
|
case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
|
||||||
case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
|
case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
|
||||||
case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
|
case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
|
||||||
case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
|
case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
|
||||||
|
case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code";
|
||||||
|
case PREFIX(externalSequences_invalid): return "External sequences are not valid";
|
||||||
case PREFIX(maxCode):
|
case PREFIX(maxCode):
|
||||||
default: return notErrorCode;
|
default: return notErrorCode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -13,8 +14,6 @@
|
||||||
#ifndef ERROR_H_MODULE
|
#ifndef ERROR_H_MODULE
|
||||||
#define ERROR_H_MODULE
|
#define ERROR_H_MODULE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ****************************************
|
/* ****************************************
|
||||||
* Dependencies
|
* Dependencies
|
||||||
******************************************/
|
******************************************/
|
||||||
|
|
@ -23,7 +22,6 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "zstd_deps.h" /* size_t */
|
#include "zstd_deps.h" /* size_t */
|
||||||
|
|
||||||
|
|
||||||
/* ****************************************
|
/* ****************************************
|
||||||
* Compiler-specific
|
* Compiler-specific
|
||||||
******************************************/
|
******************************************/
|
||||||
|
|
@ -49,8 +47,13 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
|
||||||
ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
|
ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
|
||||||
|
|
||||||
/* check and forward error code */
|
/* check and forward error code */
|
||||||
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
|
#define CHECK_V_F(e, f) \
|
||||||
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
|
size_t const e = f; \
|
||||||
|
do { \
|
||||||
|
if (ERR_isError(e)) \
|
||||||
|
return e; \
|
||||||
|
} while (0)
|
||||||
|
#define CHECK_F(f) do { CHECK_V_F(_var_err__, f); } while (0)
|
||||||
|
|
||||||
|
|
||||||
/*-****************************************
|
/*-****************************************
|
||||||
|
|
@ -85,9 +88,11 @@ void _force_has_format_string(const char *format, ...) {
|
||||||
* we don't want to force runtime evaluation of its arguments.
|
* we don't want to force runtime evaluation of its arguments.
|
||||||
*/
|
*/
|
||||||
#define _FORCE_HAS_FORMAT_STRING(...) \
|
#define _FORCE_HAS_FORMAT_STRING(...) \
|
||||||
|
do { \
|
||||||
if (0) { \
|
if (0) { \
|
||||||
_force_has_format_string(__VA_ARGS__); \
|
_force_has_format_string(__VA_ARGS__); \
|
||||||
}
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define ERR_QUOTE(str) #str
|
#define ERR_QUOTE(str) #str
|
||||||
|
|
||||||
|
|
@ -99,6 +104,7 @@ void _force_has_format_string(const char *format, ...) {
|
||||||
* this can't just wrap RETURN_ERROR().
|
* this can't just wrap RETURN_ERROR().
|
||||||
*/
|
*/
|
||||||
#define RETURN_ERROR_IF(cond, err, ...) \
|
#define RETURN_ERROR_IF(cond, err, ...) \
|
||||||
|
do { \
|
||||||
if (cond) { \
|
if (cond) { \
|
||||||
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
|
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
|
||||||
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
|
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
|
||||||
|
|
@ -106,7 +112,8 @@ void _force_has_format_string(const char *format, ...) {
|
||||||
RAWLOG(3, ": " __VA_ARGS__); \
|
RAWLOG(3, ": " __VA_ARGS__); \
|
||||||
RAWLOG(3, "\n"); \
|
RAWLOG(3, "\n"); \
|
||||||
return ERROR(err); \
|
return ERROR(err); \
|
||||||
}
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unconditionally return the specified error.
|
* Unconditionally return the specified error.
|
||||||
|
|
@ -121,7 +128,7 @@ void _force_has_format_string(const char *format, ...) {
|
||||||
RAWLOG(3, ": " __VA_ARGS__); \
|
RAWLOG(3, ": " __VA_ARGS__); \
|
||||||
RAWLOG(3, "\n"); \
|
RAWLOG(3, "\n"); \
|
||||||
return ERROR(err); \
|
return ERROR(err); \
|
||||||
} while(0);
|
} while(0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the provided expression evaluates to an error code, returns that error code.
|
* If the provided expression evaluates to an error code, returns that error code.
|
||||||
|
|
@ -139,7 +146,6 @@ void _force_has_format_string(const char *format, ...) {
|
||||||
RAWLOG(3, "\n"); \
|
RAWLOG(3, "\n"); \
|
||||||
return err_code; \
|
return err_code; \
|
||||||
} \
|
} \
|
||||||
} while(0);
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
#endif /* ERROR_H_MODULE */
|
#endif /* ERROR_H_MODULE */
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* FSE : Finite State Entropy codec
|
* FSE : Finite State Entropy codec
|
||||||
* Public Prototypes declaration
|
* Public Prototypes declaration
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -11,8 +12,6 @@
|
||||||
* in the COPYING file in the root directory of this source tree).
|
* in the COPYING file in the root directory of this source tree).
|
||||||
* You may select, at your option, one of the above-listed licenses.
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
****************************************************************** */
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
#ifndef FSE_H
|
#ifndef FSE_H
|
||||||
#define FSE_H
|
#define FSE_H
|
||||||
|
|
||||||
|
|
@ -22,7 +21,6 @@
|
||||||
******************************************/
|
******************************************/
|
||||||
#include "zstd_deps.h" /* size_t, ptrdiff_t */
|
#include "zstd_deps.h" /* size_t, ptrdiff_t */
|
||||||
|
|
||||||
|
|
||||||
/*-*****************************************
|
/*-*****************************************
|
||||||
* FSE_PUBLIC_API : control library symbols visibility
|
* FSE_PUBLIC_API : control library symbols visibility
|
||||||
******************************************/
|
******************************************/
|
||||||
|
|
@ -50,34 +48,6 @@
|
||||||
FSE_PUBLIC_API unsigned FSE_versionNumber(void); /*< library version number; to be used when checking dll version */
|
FSE_PUBLIC_API unsigned FSE_versionNumber(void); /*< library version number; to be used when checking dll version */
|
||||||
|
|
||||||
|
|
||||||
/*-****************************************
|
|
||||||
* FSE simple functions
|
|
||||||
******************************************/
|
|
||||||
/*! FSE_compress() :
|
|
||||||
Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
|
|
||||||
'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
|
|
||||||
@return : size of compressed data (<= dstCapacity).
|
|
||||||
Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
|
|
||||||
if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
|
|
||||||
if FSE_isError(return), compression failed (more details using FSE_getErrorName())
|
|
||||||
*/
|
|
||||||
FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
|
|
||||||
const void* src, size_t srcSize);
|
|
||||||
|
|
||||||
/*! FSE_decompress():
|
|
||||||
Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
|
|
||||||
into already allocated destination buffer 'dst', of size 'dstCapacity'.
|
|
||||||
@return : size of regenerated data (<= maxDstSize),
|
|
||||||
or an error code, which can be tested using FSE_isError() .
|
|
||||||
|
|
||||||
** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
|
|
||||||
Why ? : making this distinction requires a header.
|
|
||||||
Header management is intentionally delegated to the user layer, which can better manage special cases.
|
|
||||||
*/
|
|
||||||
FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity,
|
|
||||||
const void* cSrc, size_t cSrcSize);
|
|
||||||
|
|
||||||
|
|
||||||
/*-*****************************************
|
/*-*****************************************
|
||||||
* Tool functions
|
* Tool functions
|
||||||
******************************************/
|
******************************************/
|
||||||
|
|
@ -88,20 +58,6 @@ FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return
|
||||||
FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
|
FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
|
||||||
|
|
||||||
|
|
||||||
/*-*****************************************
|
|
||||||
* FSE advanced functions
|
|
||||||
******************************************/
|
|
||||||
/*! FSE_compress2() :
|
|
||||||
Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
|
|
||||||
Both parameters can be defined as '0' to mean : use default value
|
|
||||||
@return : size of compressed data
|
|
||||||
Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
|
|
||||||
if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
|
|
||||||
if FSE_isError(return), it's an error code.
|
|
||||||
*/
|
|
||||||
FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
|
|
||||||
|
|
||||||
|
|
||||||
/*-*****************************************
|
/*-*****************************************
|
||||||
* FSE detailed API
|
* FSE detailed API
|
||||||
******************************************/
|
******************************************/
|
||||||
|
|
@ -161,8 +117,6 @@ FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
|
||||||
/*! Constructor and Destructor of FSE_CTable.
|
/*! Constructor and Destructor of FSE_CTable.
|
||||||
Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
|
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* */
|
typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
|
||||||
FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
|
|
||||||
FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
|
|
||||||
|
|
||||||
/*! FSE_buildCTable():
|
/*! FSE_buildCTable():
|
||||||
Builds `ct`, which must be already allocated, using FSE_createCTable().
|
Builds `ct`, which must be already allocated, using FSE_createCTable().
|
||||||
|
|
@ -238,23 +192,7 @@ FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter,
|
||||||
unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
|
unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
|
||||||
const void* rBuffer, size_t rBuffSize, int bmi2);
|
const void* rBuffer, size_t rBuffSize, int bmi2);
|
||||||
|
|
||||||
/*! 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* */
|
typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
|
||||||
FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
|
|
||||||
FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt);
|
|
||||||
|
|
||||||
/*! 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 :
|
Tutorial :
|
||||||
|
|
@ -286,13 +224,11 @@ If there is an error, the function will return an error code, which can be teste
|
||||||
|
|
||||||
#endif /* FSE_H */
|
#endif /* FSE_H */
|
||||||
|
|
||||||
|
|
||||||
#if !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
|
#if !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
|
||||||
#define FSE_H_FSE_STATIC_LINKING_ONLY
|
#define FSE_H_FSE_STATIC_LINKING_ONLY
|
||||||
|
|
||||||
/* *** Dependency *** */
|
|
||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
|
||||||
/* *****************************************
|
/* *****************************************
|
||||||
* Static allocation
|
* Static allocation
|
||||||
*******************************************/
|
*******************************************/
|
||||||
|
|
@ -317,16 +253,6 @@ If there is an error, the function will return an error code, which can be teste
|
||||||
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
|
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
|
||||||
/*< same as FSE_optimalTableLog(), which used `minus==2` */
|
/*< same as FSE_optimalTableLog(), which used `minus==2` */
|
||||||
|
|
||||||
/* FSE_compress_wksp() :
|
|
||||||
* Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
|
|
||||||
* FSE_COMPRESS_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
|
|
||||||
*/
|
|
||||||
#define FSE_COMPRESS_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);
|
size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
|
||||||
/*< build a fake FSE_CTable, designed to compress always the same symbolValue */
|
/*< build a fake FSE_CTable, designed to compress always the same symbolValue */
|
||||||
|
|
||||||
|
|
@ -344,19 +270,11 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsi
|
||||||
FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
||||||
/*< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */
|
/*< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */
|
||||||
|
|
||||||
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
|
#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + 1 + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1)
|
||||||
/*< 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 */
|
|
||||||
|
|
||||||
#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1)
|
|
||||||
#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned))
|
#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned))
|
||||||
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize);
|
|
||||||
/*< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */
|
|
||||||
|
|
||||||
size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2);
|
size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
/*< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */
|
/*< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)`.
|
||||||
|
* Set bmi2 to 1 if your CPU supports BMI2 or 0 if it doesn't */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FSE_repeat_none, /*< Cannot use the previous table */
|
FSE_repeat_none, /*< Cannot use the previous table */
|
||||||
|
|
@ -539,20 +457,20 @@ MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, un
|
||||||
FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
|
FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
|
||||||
const U16* const stateTable = (const U16*)(statePtr->stateTable);
|
const U16* const stateTable = (const U16*)(statePtr->stateTable);
|
||||||
U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
|
U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
|
||||||
BIT_addBits(bitC, statePtr->value, nbBitsOut);
|
BIT_addBits(bitC, (BitContainerType)statePtr->value, nbBitsOut);
|
||||||
statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
|
MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
|
||||||
{
|
{
|
||||||
BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
|
BIT_addBits(bitC, (BitContainerType)statePtr->value, statePtr->stateLog);
|
||||||
BIT_flushBits(bitC);
|
BIT_flushBits(bitC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* FSE_getMaxNbBits() :
|
/* FSE_getMaxNbBits() :
|
||||||
* Approximate maximum cost of a symbol, in bits.
|
* Approximate maximum cost of a symbol, in bits.
|
||||||
* Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
|
* Fractional get rounded up (i.e. a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
|
||||||
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
|
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
|
||||||
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
|
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
|
||||||
MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
|
MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
|
||||||
|
|
@ -705,7 +623,4 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
|
||||||
|
|
||||||
#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3)
|
#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3)
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSE_STATIC_LINKING_ONLY */
|
#endif /* FSE_STATIC_LINKING_ONLY */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* FSE : Finite State Entropy decoder
|
* FSE : Finite State Entropy decoder
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -22,8 +23,8 @@
|
||||||
#define FSE_STATIC_LINKING_ONLY
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
#include "fse.h"
|
#include "fse.h"
|
||||||
#include "error_private.h"
|
#include "error_private.h"
|
||||||
#define ZSTD_DEPS_NEED_MALLOC
|
#include "zstd_deps.h" /* ZSTD_memcpy */
|
||||||
#include "zstd_deps.h"
|
#include "bits.h" /* ZSTD_highbit32 */
|
||||||
|
|
||||||
|
|
||||||
/* **************************************************************
|
/* **************************************************************
|
||||||
|
|
@ -55,19 +56,6 @@
|
||||||
#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
|
#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
|
#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
|
|
||||||
|
|
||||||
/* Function templates */
|
|
||||||
FSE_DTable* FSE_createDTable (unsigned tableLog)
|
|
||||||
{
|
|
||||||
if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
|
|
||||||
return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void FSE_freeDTable (FSE_DTable* dt)
|
|
||||||
{
|
|
||||||
ZSTD_free(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
|
static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
|
||||||
{
|
{
|
||||||
void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
|
void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
|
||||||
|
|
@ -96,7 +84,7 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo
|
||||||
symbolNext[s] = 1;
|
symbolNext[s] = 1;
|
||||||
} else {
|
} else {
|
||||||
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
||||||
symbolNext[s] = normalizedCounter[s];
|
symbolNext[s] = (U16)normalizedCounter[s];
|
||||||
} } }
|
} } }
|
||||||
ZSTD_memcpy(dt, &DTableH, sizeof(DTableH));
|
ZSTD_memcpy(dt, &DTableH, sizeof(DTableH));
|
||||||
}
|
}
|
||||||
|
|
@ -111,8 +99,7 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo
|
||||||
* all symbols have counts <= 8. We ensure we have 8 bytes at the end of
|
* all symbols have counts <= 8. We ensure we have 8 bytes at the end of
|
||||||
* our buffer to handle the over-write.
|
* our buffer to handle the over-write.
|
||||||
*/
|
*/
|
||||||
{
|
{ U64 const add = 0x0101010101010101ull;
|
||||||
U64 const add = 0x0101010101010101ull;
|
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
U64 sv = 0;
|
U64 sv = 0;
|
||||||
U32 s;
|
U32 s;
|
||||||
|
|
@ -123,14 +110,13 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo
|
||||||
for (i = 8; i < n; i += 8) {
|
for (i = 8; i < n; i += 8) {
|
||||||
MEM_write64(spread + pos + i, sv);
|
MEM_write64(spread + pos + i, sv);
|
||||||
}
|
}
|
||||||
pos += n;
|
pos += (size_t)n;
|
||||||
}
|
} }
|
||||||
}
|
|
||||||
/* Now we spread those positions across the table.
|
/* Now we spread those positions across the table.
|
||||||
* The benefit of doing it in two stages is that we avoid the the
|
* The benefit of doing it in two stages is that we avoid the
|
||||||
* variable size inner loop, which caused lots of branch misses.
|
* variable size inner loop, which caused lots of branch misses.
|
||||||
* Now we can run through all the positions without any branch misses.
|
* Now we can run through all the positions without any branch misses.
|
||||||
* We unroll the loop twice, since that is what emperically worked best.
|
* We unroll the loop twice, since that is what empirically worked best.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
size_t position = 0;
|
size_t position = 0;
|
||||||
|
|
@ -166,7 +152,7 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo
|
||||||
for (u=0; u<tableSize; u++) {
|
for (u=0; u<tableSize; u++) {
|
||||||
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
|
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
|
||||||
U32 const nextState = symbolNext[symbol]++;
|
U32 const nextState = symbolNext[symbol]++;
|
||||||
tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
|
tableDecode[u].nbBits = (BYTE) (tableLog - ZSTD_highbit32(nextState) );
|
||||||
tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
|
tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
@ -184,49 +170,6 @@ size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsi
|
||||||
/*-*******************************************************
|
/*-*******************************************************
|
||||||
* Decompression (Byte symbols)
|
* 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_TEMPLATE size_t FSE_decompress_usingDTable_generic(
|
FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
|
||||||
void* dst, size_t maxDstSize,
|
void* dst, size_t maxDstSize,
|
||||||
|
|
@ -248,6 +191,8 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
|
||||||
FSE_initDState(&state1, &bitD, dt);
|
FSE_initDState(&state1, &bitD, dt);
|
||||||
FSE_initDState(&state2, &bitD, dt);
|
FSE_initDState(&state2, &bitD, dt);
|
||||||
|
|
||||||
|
RETURN_ERROR_IF(BIT_reloadDStream(&bitD)==BIT_DStream_overflow, corruption_detected, "");
|
||||||
|
|
||||||
#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
|
#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
|
||||||
|
|
||||||
/* 4 symbols per loop */
|
/* 4 symbols per loop */
|
||||||
|
|
@ -287,32 +232,12 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
|
||||||
break;
|
break;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
return op-ostart;
|
assert(op >= ostart);
|
||||||
}
|
return (size_t)(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, unsigned maxLog, void* workSpace, size_t wkspSize)
|
|
||||||
{
|
|
||||||
return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
short ncount[FSE_MAX_SYMBOL_VALUE + 1];
|
short ncount[FSE_MAX_SYMBOL_VALUE + 1];
|
||||||
FSE_DTable dtable[]; /* Dynamically sized */
|
|
||||||
} FSE_DecompressWksp;
|
} FSE_DecompressWksp;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -327,13 +252,18 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
|
||||||
unsigned tableLog;
|
unsigned tableLog;
|
||||||
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
|
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
|
||||||
FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace;
|
FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace;
|
||||||
|
size_t const dtablePos = sizeof(FSE_DecompressWksp) / sizeof(FSE_DTable);
|
||||||
|
FSE_DTable* const dtable = (FSE_DTable*)workSpace + dtablePos;
|
||||||
|
|
||||||
DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
|
FSE_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
|
||||||
if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC);
|
if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC);
|
||||||
|
|
||||||
|
/* correct offset to dtable depends on this property */
|
||||||
|
FSE_STATIC_ASSERT(sizeof(FSE_DecompressWksp) % sizeof(FSE_DTable) == 0);
|
||||||
|
|
||||||
/* normal FSE decoding mode */
|
/* normal FSE decoding mode */
|
||||||
{
|
{ size_t const NCountLength =
|
||||||
size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
|
FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
|
||||||
if (FSE_isError(NCountLength)) return NCountLength;
|
if (FSE_isError(NCountLength)) return NCountLength;
|
||||||
if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
|
if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
|
||||||
assert(NCountLength <= cSrcSize);
|
assert(NCountLength <= cSrcSize);
|
||||||
|
|
@ -342,19 +272,20 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge);
|
if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge);
|
||||||
workSpace = wksp->dtable + FSE_DTABLE_SIZE_U32(tableLog);
|
assert(sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog) <= wkspSize);
|
||||||
|
workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
|
||||||
wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
|
wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
|
||||||
|
|
||||||
CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
|
CHECK_F( FSE_buildDTable_internal(dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
|
||||||
|
|
||||||
{
|
{
|
||||||
const void* ptr = wksp->dtable;
|
const void* ptr = dtable;
|
||||||
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
|
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
|
||||||
const U32 fastMode = DTableH->fastMode;
|
const U32 fastMode = DTableH->fastMode;
|
||||||
|
|
||||||
/* select fast mode (static) */
|
/* select fast mode (static) */
|
||||||
if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1);
|
if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 1);
|
||||||
return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0);
|
return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,9 +313,4 @@ size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc,
|
||||||
return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
|
return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSE_COMMONDEFS_ONLY */
|
#endif /* FSE_COMMONDEFS_ONLY */
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* huff0 huffman codec,
|
* huff0 huffman codec,
|
||||||
* part of Finite State Entropy library
|
* part of Finite State Entropy library
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -12,105 +13,26 @@
|
||||||
* You may select, at your option, one of the above-listed licenses.
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
****************************************************************** */
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
#ifndef HUF_H_298734234
|
#ifndef HUF_H_298734234
|
||||||
#define HUF_H_298734234
|
#define HUF_H_298734234
|
||||||
|
|
||||||
/* *** Dependencies *** */
|
/* *** Dependencies *** */
|
||||||
#include "zstd_deps.h" /* size_t */
|
#include "zstd_deps.h" /* size_t */
|
||||||
|
|
||||||
|
|
||||||
/* *** library symbols visibility *** */
|
|
||||||
/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual,
|
|
||||||
* HUF symbols remain "private" (internal symbols for library only).
|
|
||||||
* Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */
|
|
||||||
#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
|
|
||||||
# define HUF_PUBLIC_API __attribute__ ((visibility ("default")))
|
|
||||||
#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
|
|
||||||
# define HUF_PUBLIC_API __declspec(dllexport)
|
|
||||||
#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
|
|
||||||
# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */
|
|
||||||
#else
|
|
||||||
# define HUF_PUBLIC_API
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* ========================== */
|
|
||||||
/* *** simple functions *** */
|
|
||||||
/* ========================== */
|
|
||||||
|
|
||||||
/* HUF_compress() :
|
|
||||||
* Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
|
|
||||||
* 'dst' buffer must be already allocated.
|
|
||||||
* Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
|
|
||||||
* `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
|
|
||||||
* @return : size of compressed data (<= `dstCapacity`).
|
|
||||||
* Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
|
|
||||||
* if HUF_isError(return), compression failed (more details using HUF_getErrorName())
|
|
||||||
*/
|
|
||||||
HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
|
|
||||||
const void* src, size_t srcSize);
|
|
||||||
|
|
||||||
/* HUF_decompress() :
|
|
||||||
* Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
|
|
||||||
* into already allocated buffer 'dst', of minimum size 'dstSize'.
|
|
||||||
* `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
|
|
||||||
* Note : in contrast with FSE, HUF_decompress can regenerate
|
|
||||||
* RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
|
|
||||||
* because it knows size to regenerate (originalSize).
|
|
||||||
* @return : size of regenerated data (== originalSize),
|
|
||||||
* or an error code, which can be tested using HUF_isError()
|
|
||||||
*/
|
|
||||||
HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
|
|
||||||
const void* cSrc, size_t cSrcSize);
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Tool functions *** */
|
|
||||||
#define HUF_BLOCKSIZE_MAX (128 * 1024) /*< maximum input size for a single block compressed with HUF_compress */
|
|
||||||
HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /*< maximum compressed size (worst case) */
|
|
||||||
|
|
||||||
/* Error Management */
|
|
||||||
HUF_PUBLIC_API unsigned HUF_isError(size_t code); /*< tells if a return value is an error code */
|
|
||||||
HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /*< provides error code string (useful for debugging) */
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Advanced function *** */
|
|
||||||
|
|
||||||
/* HUF_compress2() :
|
|
||||||
* Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
|
|
||||||
* `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
|
|
||||||
* `tableLog` must be `<= HUF_TABLELOG_MAX` . */
|
|
||||||
HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
|
|
||||||
const void* src, size_t srcSize,
|
|
||||||
unsigned maxSymbolValue, unsigned tableLog);
|
|
||||||
|
|
||||||
/* HUF_compress4X_wksp() :
|
|
||||||
* Same as HUF_compress2(), but uses externally allocated `workSpace`.
|
|
||||||
* `workspace` must be at least as large as HUF_WORKSPACE_SIZE */
|
|
||||||
#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */)
|
|
||||||
#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64))
|
|
||||||
HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
|
|
||||||
const void* src, size_t srcSize,
|
|
||||||
unsigned maxSymbolValue, unsigned tableLog,
|
|
||||||
void* workSpace, size_t wkspSize);
|
|
||||||
|
|
||||||
#endif /* HUF_H_298734234 */
|
|
||||||
|
|
||||||
/* ******************************************************************
|
|
||||||
* WARNING !!
|
|
||||||
* The following section contains advanced and experimental definitions
|
|
||||||
* which shall never be used in the context of a dynamic library,
|
|
||||||
* because they are not guaranteed to remain stable in the future.
|
|
||||||
* Only consider them in association with static linking.
|
|
||||||
* *****************************************************************/
|
|
||||||
#if !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
|
|
||||||
#define HUF_H_HUF_STATIC_LINKING_ONLY
|
|
||||||
|
|
||||||
/* *** Dependencies *** */
|
|
||||||
#include "mem.h" /* U32 */
|
#include "mem.h" /* U32 */
|
||||||
#define FSE_STATIC_LINKING_ONLY
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
#include "fse.h"
|
#include "fse.h"
|
||||||
|
|
||||||
|
/* *** 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 */
|
||||||
|
const char* HUF_getErrorName(size_t code); /*< provides error code string (useful for debugging) */
|
||||||
|
|
||||||
|
|
||||||
|
#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */)
|
||||||
|
#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64))
|
||||||
|
|
||||||
/* *** Constants *** */
|
/* *** Constants *** */
|
||||||
#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */
|
#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */
|
||||||
|
|
@ -151,25 +73,49 @@ typedef U32 HUF_DTable;
|
||||||
/* ****************************************
|
/* ****************************************
|
||||||
* Advanced decompression functions
|
* Advanced decompression functions
|
||||||
******************************************/
|
******************************************/
|
||||||
size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< single-symbol decoder */
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
|
||||||
size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< double-symbols decoder */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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 */
|
* Huffman flags bitset.
|
||||||
size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< considers RLE and uncompressed as errors */
|
* For all flags, 0 is the default value.
|
||||||
size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< single-symbol decoder */
|
*/
|
||||||
size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< single-symbol decoder */
|
typedef enum {
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
/*
|
||||||
size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< double-symbols decoder */
|
* If compiled with DYNAMIC_BMI2: Set flag only if the CPU supports BMI2 at runtime.
|
||||||
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< double-symbols decoder */
|
* Otherwise: Ignored.
|
||||||
#endif
|
*/
|
||||||
|
HUF_flags_bmi2 = (1 << 0),
|
||||||
|
/*
|
||||||
|
* If set: Test possible table depths to find the one that produces the smallest header + encoded size.
|
||||||
|
* If unset: Use heuristic to find the table depth.
|
||||||
|
*/
|
||||||
|
HUF_flags_optimalDepth = (1 << 1),
|
||||||
|
/*
|
||||||
|
* If set: If the previous table can encode the input, always reuse the previous table.
|
||||||
|
* If unset: If the previous table can encode the input, reuse the previous table if it results in a smaller output.
|
||||||
|
*/
|
||||||
|
HUF_flags_preferRepeat = (1 << 2),
|
||||||
|
/*
|
||||||
|
* If set: Sample the input and check if the sample is uncompressible, if it is then don't attempt to compress.
|
||||||
|
* If unset: Always histogram the entire input.
|
||||||
|
*/
|
||||||
|
HUF_flags_suspectUncompressible = (1 << 3),
|
||||||
|
/*
|
||||||
|
* If set: Don't use assembly implementations
|
||||||
|
* If unset: Allow using assembly implementations
|
||||||
|
*/
|
||||||
|
HUF_flags_disableAsm = (1 << 4),
|
||||||
|
/*
|
||||||
|
* If set: Don't use the fast decoding loop, always use the fallback decoding loop.
|
||||||
|
* If unset: Use the fast decoding loop when possible.
|
||||||
|
*/
|
||||||
|
HUF_flags_disableFast = (1 << 5)
|
||||||
|
} HUF_flags_e;
|
||||||
|
|
||||||
|
|
||||||
/* ****************************************
|
/* ****************************************
|
||||||
* HUF detailed API
|
* HUF detailed API
|
||||||
* ****************************************/
|
* ****************************************/
|
||||||
|
#define HUF_OPTIMAL_DEPTH_THRESHOLD ZSTD_btultra
|
||||||
|
|
||||||
/*! HUF_compress() does the following:
|
/*! HUF_compress() does the following:
|
||||||
* 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
|
* 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
|
||||||
|
|
@ -182,12 +128,12 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
||||||
* For example, it's possible to compress several blocks using the same 'CTable',
|
* For example, it's possible to compress several blocks using the same 'CTable',
|
||||||
* or to save and regenerate 'CTable' using external methods.
|
* or to save and regenerate 'CTable' using external methods.
|
||||||
*/
|
*/
|
||||||
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
unsigned HUF_minTableLog(unsigned symbolCardinality);
|
||||||
size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
|
unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue);
|
||||||
size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
|
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, void* workSpace,
|
||||||
|
size_t wkspSize, HUF_CElt* table, const unsigned* count, int flags); /* table is used as scratch space for building and testing tables, not a return value */
|
||||||
size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize);
|
size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize);
|
||||||
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags);
|
||||||
size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2);
|
|
||||||
size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
||||||
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
||||||
|
|
||||||
|
|
@ -196,6 +142,7 @@ typedef enum {
|
||||||
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_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 assumed to be valid */
|
HUF_repeat_valid /*< Can use the previous table and it is assumed to be valid */
|
||||||
} HUF_repeat;
|
} HUF_repeat;
|
||||||
|
|
||||||
/* HUF_compress4X_repeat() :
|
/* HUF_compress4X_repeat() :
|
||||||
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
* 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 uses hufTable it does not modify hufTable or repeat.
|
||||||
|
|
@ -206,13 +153,13 @@ size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned tableLog,
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
void* workSpace, size_t wkspSize, /*< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
void* workSpace, size_t wkspSize, /*< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
|
HUF_CElt* hufTable, HUF_repeat* repeat, int flags);
|
||||||
|
|
||||||
/* HUF_buildCTable_wksp() :
|
/* HUF_buildCTable_wksp() :
|
||||||
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
* `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
|
* `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
|
||||||
*/
|
*/
|
||||||
#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
|
#define HUF_CTABLE_WORKSPACE_SIZE_U32 ((4 * (HUF_SYMBOLVALUE_MAX + 1)) + 192)
|
||||||
#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
|
#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
|
||||||
size_t HUF_buildCTable_wksp (HUF_CElt* tree,
|
size_t HUF_buildCTable_wksp (HUF_CElt* tree,
|
||||||
const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
|
const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
|
||||||
|
|
@ -238,7 +185,7 @@ size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize,
|
||||||
U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
|
U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
void* workspace, size_t wkspSize,
|
void* workspace, size_t wkspSize,
|
||||||
int bmi2);
|
int flags);
|
||||||
|
|
||||||
/* HUF_readCTable() :
|
/* HUF_readCTable() :
|
||||||
* Loading a CTable saved with HUF_writeCTable() */
|
* Loading a CTable saved with HUF_writeCTable() */
|
||||||
|
|
@ -246,9 +193,22 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
||||||
|
|
||||||
/* HUF_getNbBitsFromCTable() :
|
/* HUF_getNbBitsFromCTable() :
|
||||||
* Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
|
* Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
|
||||||
* Note 1 : is not inlined, as HUF_CElt definition is private */
|
* Note 1 : If symbolValue > HUF_readCTableHeader(symbolTable).maxSymbolValue, returns 0
|
||||||
|
* Note 2 : is not inlined, as HUF_CElt definition is private
|
||||||
|
*/
|
||||||
U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue);
|
U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE tableLog;
|
||||||
|
BYTE maxSymbolValue;
|
||||||
|
BYTE unused[sizeof(size_t) - 2];
|
||||||
|
} HUF_CTableHeader;
|
||||||
|
|
||||||
|
/* HUF_readCTableHeader() :
|
||||||
|
* @returns The header from the CTable specifying the tableLog and the maxSymbolValue.
|
||||||
|
*/
|
||||||
|
HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HUF_decompress() does the following:
|
* HUF_decompress() does the following:
|
||||||
* 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
|
* 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
|
||||||
|
|
@ -276,32 +236,12 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
|
||||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9))
|
#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9))
|
||||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
||||||
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
|
||||||
size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
|
||||||
size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
|
||||||
#endif
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
|
||||||
size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
|
||||||
size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
|
||||||
size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
|
||||||
#endif
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
|
||||||
size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* ====================== */
|
/* ====================== */
|
||||||
/* single stream variants */
|
/* single stream variants */
|
||||||
/* ====================== */
|
/* ====================== */
|
||||||
|
|
||||||
size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
|
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags);
|
||||||
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_U64 U64 */
|
|
||||||
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
|
||||||
size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2);
|
|
||||||
/* HUF_compress1X_repeat() :
|
/* HUF_compress1X_repeat() :
|
||||||
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
* 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 uses hufTable it does not modify hufTable or repeat.
|
||||||
|
|
@ -312,47 +252,27 @@ size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned tableLog,
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
void* workSpace, size_t wkspSize, /*< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
void* workSpace, size_t wkspSize, /*< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
|
HUF_CElt* hufTable, HUF_repeat* repeat, int flags);
|
||||||
|
|
||||||
size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
|
size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags);
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
|
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); /*< double-symbols decoder */
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
|
|
||||||
size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
|
||||||
size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< single-symbol decoder */
|
|
||||||
size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< single-symbol decoder */
|
|
||||||
#endif
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
|
||||||
size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< double-symbols decoder */
|
|
||||||
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< double-symbols decoder */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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 */
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
|
||||||
size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
|
||||||
#endif
|
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
|
||||||
size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* BMI2 variants.
|
/* BMI2 variants.
|
||||||
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
|
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
|
||||||
*/
|
*/
|
||||||
size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
|
size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags);
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
|
size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags);
|
||||||
#endif
|
#endif
|
||||||
size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
|
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags);
|
||||||
size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
|
size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags);
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2);
|
size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags);
|
||||||
#endif
|
#endif
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2);
|
size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* HUF_STATIC_LINKING_ONLY */
|
#endif /* HUF_H_298734234 */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
/*-****************************************
|
/*-****************************************
|
||||||
* Compiler specifics
|
* Compiler specifics
|
||||||
******************************************/
|
******************************************/
|
||||||
|
#undef MEM_STATIC /* may be already defined from common/compiler.h */
|
||||||
#define MEM_STATIC static inline
|
#define MEM_STATIC static inline
|
||||||
|
|
||||||
/*-**************************************************************
|
/*-**************************************************************
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -12,7 +13,7 @@
|
||||||
#define ZSTD_PORTABILITY_MACROS_H
|
#define ZSTD_PORTABILITY_MACROS_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This header file contains macro defintions to support portability.
|
* This header file contains macro definitions to support portability.
|
||||||
* This header is shared between C and ASM code, so it MUST only
|
* This header is shared between C and ASM code, so it MUST only
|
||||||
* contain macro definitions. It MUST not contain any C code.
|
* contain macro definitions. It MUST not contain any C code.
|
||||||
*
|
*
|
||||||
|
|
@ -45,30 +46,35 @@
|
||||||
/* Mark the internal assembly functions as hidden */
|
/* Mark the internal assembly functions as hidden */
|
||||||
#ifdef __ELF__
|
#ifdef __ELF__
|
||||||
# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func
|
# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# define ZSTD_HIDE_ASM_FUNCTION(func) .private_extern func
|
||||||
#else
|
#else
|
||||||
# define ZSTD_HIDE_ASM_FUNCTION(func)
|
# define ZSTD_HIDE_ASM_FUNCTION(func)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Compile time determination of BMI2 support */
|
||||||
|
|
||||||
|
|
||||||
/* Enable runtime BMI2 dispatch based on the CPU.
|
/* Enable runtime BMI2 dispatch based on the CPU.
|
||||||
* Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
|
* Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
|
||||||
*/
|
*/
|
||||||
#ifndef DYNAMIC_BMI2
|
#ifndef DYNAMIC_BMI2
|
||||||
#if ((defined(__clang__) && __has_attribute(__target__)) \
|
# if ((defined(__clang__) && __has_attribute(__target__)) \
|
||||||
|| (defined(__GNUC__) \
|
|| (defined(__GNUC__) \
|
||||||
&& (__GNUC__ >= 11))) \
|
&& (__GNUC__ >= 11))) \
|
||||||
&& (defined(__x86_64__) || defined(_M_X64)) \
|
&& (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)) \
|
||||||
&& !defined(__BMI2__)
|
&& !defined(__BMI2__)
|
||||||
# define DYNAMIC_BMI2 1
|
# define DYNAMIC_BMI2 1
|
||||||
#else
|
# else
|
||||||
# define DYNAMIC_BMI2 0
|
# define DYNAMIC_BMI2 0
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only enable assembly for GNUC comptabile compilers,
|
* Only enable assembly for GNU C compatible compilers,
|
||||||
* because other platforms may not support GAS assembly syntax.
|
* because other platforms may not support GAS assembly syntax.
|
||||||
*
|
*
|
||||||
* Only enable assembly for Linux / MacOS, other platforms may
|
* Only enable assembly for Linux / MacOS / Win32, other platforms may
|
||||||
* work, but they haven't been tested. This could likely be
|
* work, but they haven't been tested. This could likely be
|
||||||
* extended to BSD systems.
|
* extended to BSD systems.
|
||||||
*
|
*
|
||||||
|
|
@ -90,4 +96,23 @@
|
||||||
*/
|
*/
|
||||||
#define ZSTD_ENABLE_ASM_X86_64_BMI2 0
|
#define ZSTD_ENABLE_ASM_X86_64_BMI2 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For x86 ELF targets, add .note.gnu.property section for Intel CET in
|
||||||
|
* assembly sources when CET is enabled.
|
||||||
|
*
|
||||||
|
* Additionally, any function that may be called indirectly must begin
|
||||||
|
* with ZSTD_CET_ENDBRANCH.
|
||||||
|
*/
|
||||||
|
#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \
|
||||||
|
&& defined(__has_include)
|
||||||
|
# if __has_include(<cet.h>)
|
||||||
|
# include <cet.h>
|
||||||
|
# define ZSTD_CET_ENDBRANCH _CET_ENDBR
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZSTD_CET_ENDBRANCH
|
||||||
|
# define ZSTD_CET_ENDBRANCH
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* ZSTD_PORTABILITY_MACROS_H */
|
#endif /* ZSTD_PORTABILITY_MACROS_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -14,7 +15,6 @@
|
||||||
* Dependencies
|
* Dependencies
|
||||||
***************************************/
|
***************************************/
|
||||||
#define ZSTD_DEPS_NEED_MALLOC
|
#define ZSTD_DEPS_NEED_MALLOC
|
||||||
#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */
|
|
||||||
#include "error_private.h"
|
#include "error_private.h"
|
||||||
#include "zstd_internal.h"
|
#include "zstd_internal.h"
|
||||||
|
|
||||||
|
|
@ -47,37 +47,3 @@ ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
|
||||||
/*! ZSTD_getErrorString() :
|
/*! ZSTD_getErrorString() :
|
||||||
* provides error code string from enum */
|
* provides error code string from enum */
|
||||||
const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
|
const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=**************************************************************
|
|
||||||
* Custom allocator
|
|
||||||
****************************************************************/
|
|
||||||
void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem)
|
|
||||||
{
|
|
||||||
if (customMem.customAlloc)
|
|
||||||
return customMem.customAlloc(customMem.opaque, size);
|
|
||||||
return ZSTD_malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem)
|
|
||||||
{
|
|
||||||
if (customMem.customAlloc) {
|
|
||||||
/* calloc implemented as malloc+memset;
|
|
||||||
* not as efficient as calloc, but next best guess for custom malloc */
|
|
||||||
void* const ptr = customMem.customAlloc(customMem.opaque, size);
|
|
||||||
ZSTD_memset(ptr, 0, size);
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
return ZSTD_calloc(1, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZSTD_customFree(void* ptr, ZSTD_customMem customMem)
|
|
||||||
{
|
|
||||||
if (ptr!=NULL) {
|
|
||||||
if (customMem.customFree)
|
|
||||||
customMem.customFree(customMem.opaque, ptr);
|
|
||||||
else
|
|
||||||
ZSTD_free(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -105,3 +105,17 @@ static uint64_t ZSTD_div64(uint64_t dividend, uint32_t divisor) {
|
||||||
|
|
||||||
#endif /* ZSTD_DEPS_IO */
|
#endif /* ZSTD_DEPS_IO */
|
||||||
#endif /* ZSTD_DEPS_NEED_IO */
|
#endif /* ZSTD_DEPS_NEED_IO */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only requested when MSAN is enabled.
|
||||||
|
* Need:
|
||||||
|
* intptr_t
|
||||||
|
*/
|
||||||
|
#ifdef ZSTD_DEPS_NEED_STDINT
|
||||||
|
#ifndef ZSTD_DEPS_STDINT
|
||||||
|
#define ZSTD_DEPS_STDINT
|
||||||
|
|
||||||
|
/* intptr_t already provided by ZSTD_DEPS_COMMON */
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEPS_STDINT */
|
||||||
|
#endif /* ZSTD_DEPS_NEED_STDINT */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -28,12 +29,10 @@
|
||||||
#include <linux/zstd.h>
|
#include <linux/zstd.h>
|
||||||
#define FSE_STATIC_LINKING_ONLY
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
#include "fse.h"
|
#include "fse.h"
|
||||||
#define HUF_STATIC_LINKING_ONLY
|
|
||||||
#include "huf.h"
|
#include "huf.h"
|
||||||
#include <linux/xxhash.h> /* XXH_reset, update, digest */
|
#include <linux/xxhash.h> /* XXH_reset, update, digest */
|
||||||
#define ZSTD_TRACE 0
|
#define ZSTD_TRACE 0
|
||||||
|
|
||||||
|
|
||||||
/* ---- static assert (debug) --- */
|
/* ---- static assert (debug) --- */
|
||||||
#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
|
#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
|
||||||
#define ZSTD_isError ERR_isError /* for inlining */
|
#define ZSTD_isError ERR_isError /* for inlining */
|
||||||
|
|
@ -83,16 +82,17 @@ typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
|
||||||
#define ZSTD_FRAMECHECKSUMSIZE 4
|
#define ZSTD_FRAMECHECKSUMSIZE 4
|
||||||
|
|
||||||
#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
|
#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 MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */) /* for a non-null block */
|
||||||
|
#define MIN_LITERALS_FOR_4_STREAMS 6
|
||||||
|
|
||||||
#define HufLog 12
|
typedef enum { set_basic, set_rle, set_compressed, set_repeat } SymbolEncodingType_e;
|
||||||
typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
|
|
||||||
|
|
||||||
#define LONGNBSEQ 0x7F00
|
#define LONGNBSEQ 0x7F00
|
||||||
|
|
||||||
#define MINMATCH 3
|
#define MINMATCH 3
|
||||||
|
|
||||||
#define Litbits 8
|
#define Litbits 8
|
||||||
|
#define LitHufLog 11
|
||||||
#define MaxLit ((1<<Litbits) - 1)
|
#define MaxLit ((1<<Litbits) - 1)
|
||||||
#define MaxML 52
|
#define MaxML 52
|
||||||
#define MaxLL 35
|
#define MaxLL 35
|
||||||
|
|
@ -103,6 +103,8 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy
|
||||||
#define LLFSELog 9
|
#define LLFSELog 9
|
||||||
#define OffFSELog 8
|
#define OffFSELog 8
|
||||||
#define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
|
#define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
|
||||||
|
#define MaxMLBits 16
|
||||||
|
#define MaxLLBits 16
|
||||||
|
|
||||||
#define ZSTD_MAX_HUF_HEADER_SIZE 128 /* header + <= 127 byte tree description */
|
#define ZSTD_MAX_HUF_HEADER_SIZE 128 /* header + <= 127 byte tree description */
|
||||||
/* Each table cannot take more than #symbols * FSELog bits */
|
/* Each table cannot take more than #symbols * FSELog bits */
|
||||||
|
|
@ -166,7 +168,7 @@ static void ZSTD_copy8(void* dst, const void* src) {
|
||||||
ZSTD_memcpy(dst, src, 8);
|
ZSTD_memcpy(dst, src, 8);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
|
#define COPY8(d,s) do { ZSTD_copy8(d,s); d+=8; s+=8; } while (0)
|
||||||
|
|
||||||
/* Need to use memmove here since the literal buffer can now be located within
|
/* Need to use memmove here since the literal buffer can now be located within
|
||||||
the dst buffer. In circumstances where the op "catches up" to where the
|
the dst buffer. In circumstances where the op "catches up" to where the
|
||||||
|
|
@ -186,7 +188,7 @@ static void ZSTD_copy16(void* dst, const void* src) {
|
||||||
ZSTD_memcpy(dst, copy16_buf, 16);
|
ZSTD_memcpy(dst, copy16_buf, 16);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; }
|
#define COPY16(d,s) do { ZSTD_copy16(d,s); d+=16; s+=16; } while (0)
|
||||||
|
|
||||||
#define WILDCOPY_OVERLENGTH 32
|
#define WILDCOPY_OVERLENGTH 32
|
||||||
#define WILDCOPY_VECLEN 16
|
#define WILDCOPY_VECLEN 16
|
||||||
|
|
@ -215,7 +217,7 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e
|
||||||
if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
|
if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
|
||||||
/* Handle short offset copies. */
|
/* Handle short offset copies. */
|
||||||
do {
|
do {
|
||||||
COPY8(op, ip)
|
COPY8(op, ip);
|
||||||
} while (op < oend);
|
} while (op < oend);
|
||||||
} else {
|
} else {
|
||||||
assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
|
assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
|
||||||
|
|
@ -225,12 +227,6 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e
|
||||||
* one COPY16() in the first call. Then, do two calls per loop since
|
* one COPY16() in the first call. Then, do two calls per loop since
|
||||||
* at that point it is more likely to have a high trip count.
|
* at that point it is more likely to have a high trip count.
|
||||||
*/
|
*/
|
||||||
#ifdef __aarch64__
|
|
||||||
do {
|
|
||||||
COPY16(op, ip);
|
|
||||||
}
|
|
||||||
while (op < oend);
|
|
||||||
#else
|
|
||||||
ZSTD_copy16(op, ip);
|
ZSTD_copy16(op, ip);
|
||||||
if (16 >= length) return;
|
if (16 >= length) return;
|
||||||
op += 16;
|
op += 16;
|
||||||
|
|
@ -240,7 +236,6 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e
|
||||||
COPY16(op, ip);
|
COPY16(op, ip);
|
||||||
}
|
}
|
||||||
while (op < oend);
|
while (op < oend);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,62 +268,6 @@ typedef enum {
|
||||||
/*-*******************************************
|
/*-*******************************************
|
||||||
* Private declarations
|
* Private declarations
|
||||||
*********************************************/
|
*********************************************/
|
||||||
typedef struct seqDef_s {
|
|
||||||
U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */
|
|
||||||
U16 litLength;
|
|
||||||
U16 mlBase; /* mlBase == matchLength - MINMATCH */
|
|
||||||
} seqDef;
|
|
||||||
|
|
||||||
/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */
|
|
||||||
typedef enum {
|
|
||||||
ZSTD_llt_none = 0, /* no longLengthType */
|
|
||||||
ZSTD_llt_literalLength = 1, /* represents a long literal */
|
|
||||||
ZSTD_llt_matchLength = 2 /* represents a long match */
|
|
||||||
} ZSTD_longLengthType_e;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
seqDef* sequencesStart;
|
|
||||||
seqDef* sequences; /* ptr to end of sequences */
|
|
||||||
BYTE* litStart;
|
|
||||||
BYTE* lit; /* ptr to end of literals */
|
|
||||||
BYTE* llCode;
|
|
||||||
BYTE* mlCode;
|
|
||||||
BYTE* ofCode;
|
|
||||||
size_t maxNbSeq;
|
|
||||||
size_t maxNbLit;
|
|
||||||
|
|
||||||
/* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength
|
|
||||||
* in the seqStore that has a value larger than U16 (if it exists). To do so, we increment
|
|
||||||
* the existing value of the litLength or matchLength by 0x10000.
|
|
||||||
*/
|
|
||||||
ZSTD_longLengthType_e longLengthType;
|
|
||||||
U32 longLengthPos; /* Index of the sequence to apply long length modification to */
|
|
||||||
} seqStore_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
U32 litLength;
|
|
||||||
U32 matchLength;
|
|
||||||
} ZSTD_sequenceLength;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences
|
|
||||||
* indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength.
|
|
||||||
*/
|
|
||||||
MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq)
|
|
||||||
{
|
|
||||||
ZSTD_sequenceLength seqLen;
|
|
||||||
seqLen.litLength = seq->litLength;
|
|
||||||
seqLen.matchLength = seq->mlBase + MINMATCH;
|
|
||||||
if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) {
|
|
||||||
if (seqStore->longLengthType == ZSTD_llt_literalLength) {
|
|
||||||
seqLen.litLength += 0xFFFF;
|
|
||||||
}
|
|
||||||
if (seqStore->longLengthType == ZSTD_llt_matchLength) {
|
|
||||||
seqLen.matchLength += 0xFFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return seqLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Contains the compressed frame size and an upper-bound for the decompressed frame size.
|
* Contains the compressed frame size and an upper-bound for the decompressed frame size.
|
||||||
|
|
@ -337,74 +276,11 @@ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore
|
||||||
* `decompressedBound != ZSTD_CONTENTSIZE_ERROR`
|
* `decompressedBound != ZSTD_CONTENTSIZE_ERROR`
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
size_t nbBlocks;
|
||||||
size_t compressedSize;
|
size_t compressedSize;
|
||||||
unsigned long long decompressedBound;
|
unsigned long long decompressedBound;
|
||||||
} ZSTD_frameSizeInfo; /* decompress & legacy */
|
} ZSTD_frameSizeInfo; /* decompress & legacy */
|
||||||
|
|
||||||
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
|
|
||||||
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
|
|
||||||
|
|
||||||
/* custom memory allocation functions */
|
|
||||||
void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem);
|
|
||||||
void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem);
|
|
||||||
void ZSTD_customFree(void* ptr, ZSTD_customMem customMem);
|
|
||||||
|
|
||||||
|
|
||||||
MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */
|
|
||||||
{
|
|
||||||
assert(val != 0);
|
|
||||||
{
|
|
||||||
# if (__GNUC__ >= 3) /* GCC Intrinsic */
|
|
||||||
return __builtin_clz (val) ^ 31;
|
|
||||||
# else /* Software version */
|
|
||||||
static const U32 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[(v * 0x07C4ACDDU) >> 27];
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Counts the number of trailing zeros of a `size_t`.
|
|
||||||
* Most compilers should support CTZ as a builtin. A backup
|
|
||||||
* implementation is provided if the builtin isn't supported, but
|
|
||||||
* it may not be terribly efficient.
|
|
||||||
*/
|
|
||||||
MEM_STATIC unsigned ZSTD_countTrailingZeros(size_t val)
|
|
||||||
{
|
|
||||||
if (MEM_64bits()) {
|
|
||||||
# if (__GNUC__ >= 4)
|
|
||||||
return __builtin_ctzll((U64)val);
|
|
||||||
# else
|
|
||||||
static const int DeBruijnBytePos[64] = { 0, 1, 2, 7, 3, 13, 8, 19,
|
|
||||||
4, 25, 14, 28, 9, 34, 20, 56,
|
|
||||||
5, 17, 26, 54, 15, 41, 29, 43,
|
|
||||||
10, 31, 38, 35, 21, 45, 49, 57,
|
|
||||||
63, 6, 12, 18, 24, 27, 33, 55,
|
|
||||||
16, 53, 40, 42, 30, 37, 44, 48,
|
|
||||||
62, 11, 23, 32, 52, 39, 36, 47,
|
|
||||||
61, 22, 51, 46, 60, 50, 59, 58 };
|
|
||||||
return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
|
|
||||||
# endif
|
|
||||||
} else { /* 32 bits */
|
|
||||||
# if (__GNUC__ >= 3)
|
|
||||||
return __builtin_ctz((U32)val);
|
|
||||||
# else
|
|
||||||
static const int DeBruijnBytePos[32] = { 0, 1, 28, 2, 29, 14, 24, 3,
|
|
||||||
30, 22, 20, 15, 25, 17, 4, 8,
|
|
||||||
31, 27, 13, 23, 21, 19, 16, 7,
|
|
||||||
26, 12, 18, 6, 11, 5, 10, 9 };
|
|
||||||
return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ZSTD_invalidateRepCodes() :
|
/* ZSTD_invalidateRepCodes() :
|
||||||
* ensures next compression will not use repcodes from previous block.
|
* ensures next compression will not use repcodes from previous block.
|
||||||
* Note : only works with regular variant;
|
* Note : only works with regular variant;
|
||||||
|
|
@ -420,13 +296,13 @@ typedef struct {
|
||||||
|
|
||||||
/*! ZSTD_getcBlockSize() :
|
/*! ZSTD_getcBlockSize() :
|
||||||
* Provides the size of compressed block from block header `src` */
|
* Provides the size of compressed block from block header `src` */
|
||||||
/* Used by: decompress, fullbench (does not get its definition from here) */
|
/* Used by: decompress, fullbench */
|
||||||
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
|
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
|
||||||
blockProperties_t* bpPtr);
|
blockProperties_t* bpPtr);
|
||||||
|
|
||||||
/*! ZSTD_decodeSeqHeaders() :
|
/*! ZSTD_decodeSeqHeaders() :
|
||||||
* decode sequence header from src */
|
* decode sequence header from src */
|
||||||
/* Used by: decompress, fullbench (does not get its definition from here) */
|
/* Used by: zstd_decompress_block, fullbench */
|
||||||
size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
|
size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
|
||||||
const void* src, size_t srcSize);
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
@ -439,5 +315,4 @@ MEM_STATIC int ZSTD_cpuSupportsBmi2(void)
|
||||||
return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid);
|
return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* ZSTD_CCOMMON_H_MODULE */
|
#endif /* ZSTD_CCOMMON_H_MODULE */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* FSE : Finite State Entropy encoder
|
* FSE : Finite State Entropy encoder
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -25,7 +26,8 @@
|
||||||
#include "../common/error_private.h"
|
#include "../common/error_private.h"
|
||||||
#define ZSTD_DEPS_NEED_MALLOC
|
#define ZSTD_DEPS_NEED_MALLOC
|
||||||
#define ZSTD_DEPS_NEED_MATH64
|
#define ZSTD_DEPS_NEED_MATH64
|
||||||
#include "../common/zstd_deps.h" /* ZSTD_malloc, ZSTD_free, ZSTD_memcpy, ZSTD_memset */
|
#include "../common/zstd_deps.h" /* ZSTD_memset */
|
||||||
|
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||||
|
|
||||||
|
|
||||||
/* **************************************************************
|
/* **************************************************************
|
||||||
|
|
@ -90,7 +92,7 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct,
|
||||||
assert(tableLog < 16); /* required for threshold strategy to work */
|
assert(tableLog < 16); /* required for threshold strategy to work */
|
||||||
|
|
||||||
/* For explanations on how to distribute symbol values over the table :
|
/* For explanations on how to distribute symbol values over the table :
|
||||||
* http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
|
* https://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
|
||||||
|
|
||||||
#ifdef __clang_analyzer__
|
#ifdef __clang_analyzer__
|
||||||
ZSTD_memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */
|
ZSTD_memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */
|
||||||
|
|
@ -191,7 +193,7 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct,
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
assert(normalizedCounter[s] > 1);
|
assert(normalizedCounter[s] > 1);
|
||||||
{ U32 const maxBitsOut = tableLog - BIT_highbit32 ((U32)normalizedCounter[s]-1);
|
{ U32 const maxBitsOut = tableLog - ZSTD_highbit32 ((U32)normalizedCounter[s]-1);
|
||||||
U32 const minStatePlus = (U32)normalizedCounter[s] << maxBitsOut;
|
U32 const minStatePlus = (U32)normalizedCounter[s] << maxBitsOut;
|
||||||
symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
|
symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
|
||||||
symbolTT[s].deltaFindState = (int)(total - (unsigned)normalizedCounter[s]);
|
symbolTT[s].deltaFindState = (int)(total - (unsigned)normalizedCounter[s]);
|
||||||
|
|
@ -254,7 +256,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||||
/* Init */
|
/* Init */
|
||||||
remaining = tableSize+1; /* +1 for extra accuracy */
|
remaining = tableSize+1; /* +1 for extra accuracy */
|
||||||
threshold = tableSize;
|
threshold = tableSize;
|
||||||
nbBits = tableLog+1;
|
nbBits = (int)tableLog+1;
|
||||||
|
|
||||||
while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */
|
while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */
|
||||||
if (previousIs0) {
|
if (previousIs0) {
|
||||||
|
|
@ -273,7 +275,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||||
}
|
}
|
||||||
while (symbol >= start+3) {
|
while (symbol >= start+3) {
|
||||||
start+=3;
|
start+=3;
|
||||||
bitStream += 3 << bitCount;
|
bitStream += 3U << bitCount;
|
||||||
bitCount += 2;
|
bitCount += 2;
|
||||||
}
|
}
|
||||||
bitStream += (symbol-start) << bitCount;
|
bitStream += (symbol-start) << bitCount;
|
||||||
|
|
@ -293,7 +295,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||||
count++; /* +1 for extra accuracy */
|
count++; /* +1 for extra accuracy */
|
||||||
if (count>=threshold)
|
if (count>=threshold)
|
||||||
count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
|
count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
|
||||||
bitStream += count << bitCount;
|
bitStream += (U32)count << bitCount;
|
||||||
bitCount += nbBits;
|
bitCount += nbBits;
|
||||||
bitCount -= (count<max);
|
bitCount -= (count<max);
|
||||||
previousIs0 = (count==1);
|
previousIs0 = (count==1);
|
||||||
|
|
@ -321,7 +323,8 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize,
|
||||||
out[1] = (BYTE)(bitStream>>8);
|
out[1] = (BYTE)(bitStream>>8);
|
||||||
out+= (bitCount+7) /8;
|
out+= (bitCount+7) /8;
|
||||||
|
|
||||||
return (out-ostart);
|
assert(out >= ostart);
|
||||||
|
return (size_t)(out-ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -342,21 +345,11 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize,
|
||||||
* FSE Compression Code
|
* FSE Compression Code
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
|
|
||||||
{
|
|
||||||
size_t size;
|
|
||||||
if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
|
|
||||||
size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
|
|
||||||
return (FSE_CTable*)ZSTD_malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FSE_freeCTable (FSE_CTable* ct) { ZSTD_free(ct); }
|
|
||||||
|
|
||||||
/* provides the minimum logSize to safely represent a distribution */
|
/* provides the minimum logSize to safely represent a distribution */
|
||||||
static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
|
static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
|
||||||
{
|
{
|
||||||
U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1;
|
U32 minBitsSrc = ZSTD_highbit32((U32)(srcSize)) + 1;
|
||||||
U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
|
U32 minBitsSymbols = ZSTD_highbit32(maxSymbolValue) + 2;
|
||||||
U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
|
U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
|
||||||
assert(srcSize > 1); /* Not supported, RLE should be used instead */
|
assert(srcSize > 1); /* Not supported, RLE should be used instead */
|
||||||
return minBits;
|
return minBits;
|
||||||
|
|
@ -364,7 +357,7 @@ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
|
||||||
|
|
||||||
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
|
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
|
||||||
{
|
{
|
||||||
U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
|
U32 maxBitsSrc = ZSTD_highbit32((U32)(srcSize - 1)) - minus;
|
||||||
U32 tableLog = maxTableLog;
|
U32 tableLog = maxTableLog;
|
||||||
U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
|
U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
|
||||||
assert(srcSize > 1); /* Not supported, RLE should be used instead */
|
assert(srcSize > 1); /* Not supported, RLE should be used instead */
|
||||||
|
|
@ -532,40 +525,6 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
|
||||||
return tableLog;
|
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) */
|
/* fake FSE_CTable, for rle input (always same symbol) */
|
||||||
size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
|
size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
|
||||||
{
|
{
|
||||||
|
|
@ -664,5 +623,4 @@ size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
|
||||||
|
|
||||||
size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
|
size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSE_COMMONDEFS_ONLY */
|
#endif /* FSE_COMMONDEFS_ONLY */
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* hist : Histogram functions
|
* hist : Histogram functions
|
||||||
* part of Finite State Entropy project
|
* part of Finite State Entropy project
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -26,6 +27,16 @@ unsigned HIST_isError(size_t code) { return ERR_isError(code); }
|
||||||
/*-**************************************************************
|
/*-**************************************************************
|
||||||
* Histogram functions
|
* Histogram functions
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
void HIST_add(unsigned* count, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
const BYTE* ip = (const BYTE*)src;
|
||||||
|
const BYTE* const end = ip + srcSize;
|
||||||
|
|
||||||
|
while (ip<end) {
|
||||||
|
count[*ip++]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
const void* src, size_t srcSize)
|
const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* hist : Histogram functions
|
* hist : Histogram functions
|
||||||
* part of Finite State Entropy project
|
* part of Finite State Entropy project
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -73,3 +74,10 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
*/
|
*/
|
||||||
unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
|
||||||
const void* src, size_t srcSize);
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/*! HIST_add() :
|
||||||
|
* Lowest level: just add nb of occurrences of characters from @src into @count.
|
||||||
|
* @count is not reset. @count array is presumed large enough (i.e. 1 KB).
|
||||||
|
@ This function does not need any additional stack memory.
|
||||||
|
*/
|
||||||
|
void HIST_add(unsigned* count, const void* src, size_t srcSize);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/* ******************************************************************
|
/* ******************************************************************
|
||||||
* Huffman encoder, part of New Generation Entropy library
|
* Huffman encoder, part of New Generation Entropy library
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* You can contact the author at :
|
* You can contact the author at :
|
||||||
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
|
@ -26,9 +27,9 @@
|
||||||
#include "hist.h"
|
#include "hist.h"
|
||||||
#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
|
#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
|
||||||
#include "../common/fse.h" /* header compression */
|
#include "../common/fse.h" /* header compression */
|
||||||
#define HUF_STATIC_LINKING_ONLY
|
|
||||||
#include "../common/huf.h"
|
#include "../common/huf.h"
|
||||||
#include "../common/error_private.h"
|
#include "../common/error_private.h"
|
||||||
|
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||||
|
|
||||||
|
|
||||||
/* **************************************************************
|
/* **************************************************************
|
||||||
|
|
@ -39,13 +40,67 @@
|
||||||
|
|
||||||
|
|
||||||
/* **************************************************************
|
/* **************************************************************
|
||||||
* Utils
|
* Required declarations
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
|
typedef struct nodeElt_s {
|
||||||
|
U32 count;
|
||||||
|
U16 parent;
|
||||||
|
BYTE byte;
|
||||||
|
BYTE nbBits;
|
||||||
|
} nodeElt;
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Debug Traces
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
#if DEBUGLEVEL >= 2
|
||||||
|
|
||||||
|
static size_t showU32(const U32* arr, size_t size)
|
||||||
{
|
{
|
||||||
return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
|
size_t u;
|
||||||
|
for (u=0; u<size; u++) {
|
||||||
|
RAWLOG(6, " %u", arr[u]); (void)arr;
|
||||||
|
}
|
||||||
|
RAWLOG(6, " \n");
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t HUF_getNbBits(HUF_CElt elt);
|
||||||
|
|
||||||
|
static size_t showCTableBits(const HUF_CElt* ctable, size_t size)
|
||||||
|
{
|
||||||
|
size_t u;
|
||||||
|
for (u=0; u<size; u++) {
|
||||||
|
RAWLOG(6, " %zu", HUF_getNbBits(ctable[u])); (void)ctable;
|
||||||
|
}
|
||||||
|
RAWLOG(6, " \n");
|
||||||
|
return size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t showHNodeSymbols(const nodeElt* hnode, size_t size)
|
||||||
|
{
|
||||||
|
size_t u;
|
||||||
|
for (u=0; u<size; u++) {
|
||||||
|
RAWLOG(6, " %u", hnode[u].byte); (void)hnode;
|
||||||
|
}
|
||||||
|
RAWLOG(6, " \n");
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t showHNodeBits(const nodeElt* hnode, size_t size)
|
||||||
|
{
|
||||||
|
size_t u;
|
||||||
|
for (u=0; u<size; u++) {
|
||||||
|
RAWLOG(6, " %u", hnode[u].nbBits); (void)hnode;
|
||||||
|
}
|
||||||
|
RAWLOG(6, " \n");
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* *******************************************************
|
/* *******************************************************
|
||||||
* HUF : Huffman block compression
|
* HUF : Huffman block compression
|
||||||
|
|
@ -86,7 +141,10 @@ typedef struct {
|
||||||
S16 norm[HUF_TABLELOG_MAX+1];
|
S16 norm[HUF_TABLELOG_MAX+1];
|
||||||
} HUF_CompressWeightsWksp;
|
} HUF_CompressWeightsWksp;
|
||||||
|
|
||||||
static size_t HUF_compressWeights(void* dst, size_t dstSize, const void* weightTable, size_t wtSize, void* workspace, size_t workspaceSize)
|
static size_t
|
||||||
|
HUF_compressWeights(void* dst, size_t dstSize,
|
||||||
|
const void* weightTable, size_t wtSize,
|
||||||
|
void* workspace, size_t workspaceSize)
|
||||||
{
|
{
|
||||||
BYTE* const ostart = (BYTE*) dst;
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
BYTE* op = ostart;
|
BYTE* op = ostart;
|
||||||
|
|
@ -137,7 +195,7 @@ static size_t HUF_getNbBitsFast(HUF_CElt elt)
|
||||||
|
|
||||||
static size_t HUF_getValue(HUF_CElt elt)
|
static size_t HUF_getValue(HUF_CElt elt)
|
||||||
{
|
{
|
||||||
return elt & ~0xFF;
|
return elt & ~(size_t)0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t HUF_getValueFast(HUF_CElt elt)
|
static size_t HUF_getValueFast(HUF_CElt elt)
|
||||||
|
|
@ -160,6 +218,25 @@ static void HUF_setValue(HUF_CElt* elt, size_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable)
|
||||||
|
{
|
||||||
|
HUF_CTableHeader header;
|
||||||
|
ZSTD_memcpy(&header, ctable, sizeof(header));
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HUF_writeCTableHeader(HUF_CElt* ctable, U32 tableLog, U32 maxSymbolValue)
|
||||||
|
{
|
||||||
|
HUF_CTableHeader header;
|
||||||
|
HUF_STATIC_ASSERT(sizeof(ctable[0]) == sizeof(header));
|
||||||
|
ZSTD_memset(&header, 0, sizeof(header));
|
||||||
|
assert(tableLog < 256);
|
||||||
|
header.tableLog = (BYTE)tableLog;
|
||||||
|
assert(maxSymbolValue < 256);
|
||||||
|
header.maxSymbolValue = (BYTE)maxSymbolValue;
|
||||||
|
ZSTD_memcpy(ctable, &header, sizeof(header));
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HUF_CompressWeightsWksp wksp;
|
HUF_CompressWeightsWksp wksp;
|
||||||
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
|
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
|
||||||
|
|
@ -175,6 +252,11 @@ size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize,
|
||||||
U32 n;
|
U32 n;
|
||||||
HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32));
|
HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32));
|
||||||
|
|
||||||
|
HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE >= sizeof(HUF_WriteCTableWksp));
|
||||||
|
|
||||||
|
assert(HUF_readCTableHeader(CTable).maxSymbolValue == maxSymbolValue);
|
||||||
|
assert(HUF_readCTableHeader(CTable).tableLog == huffLog);
|
||||||
|
|
||||||
/* check conditions */
|
/* check conditions */
|
||||||
if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC);
|
if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC);
|
||||||
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
||||||
|
|
@ -204,16 +286,6 @@ size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize,
|
||||||
return ((maxSymbolValue+1)/2) + 1;
|
return ((maxSymbolValue+1)/2) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! 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, unsigned maxSymbolValue, unsigned huffLog)
|
|
||||||
{
|
|
||||||
HUF_WriteCTableWksp wksp;
|
|
||||||
return HUF_writeCTable_wksp(dst, maxDstSize, CTable, maxSymbolValue, huffLog, &wksp, sizeof(wksp));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
|
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
|
||||||
{
|
{
|
||||||
|
|
@ -231,7 +303,9 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
||||||
if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||||
if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
|
if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
|
||||||
|
|
||||||
CTable[0] = tableLog;
|
*maxSymbolValuePtr = nbSymbols - 1;
|
||||||
|
|
||||||
|
HUF_writeCTableHeader(CTable, tableLog, *maxSymbolValuePtr);
|
||||||
|
|
||||||
/* Prepare base value per rank */
|
/* Prepare base value per rank */
|
||||||
{ U32 n, nextRankStart = 0;
|
{ U32 n, nextRankStart = 0;
|
||||||
|
|
@ -263,74 +337,71 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
|
||||||
{ U32 n; for (n=0; n<nbSymbols; n++) HUF_setValue(ct + n, valPerRank[HUF_getNbBits(ct[n])]++); }
|
{ U32 n; for (n=0; n<nbSymbols; n++) HUF_setValue(ct + n, valPerRank[HUF_getNbBits(ct[n])]++); }
|
||||||
}
|
}
|
||||||
|
|
||||||
*maxSymbolValuePtr = nbSymbols - 1;
|
|
||||||
return readSize;
|
return readSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 HUF_getNbBitsFromCTable(HUF_CElt const* CTable, U32 symbolValue)
|
U32 HUF_getNbBitsFromCTable(HUF_CElt const* CTable, U32 symbolValue)
|
||||||
{
|
{
|
||||||
const HUF_CElt* ct = CTable + 1;
|
const HUF_CElt* const ct = CTable + 1;
|
||||||
assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
|
assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
|
||||||
|
if (symbolValue > HUF_readCTableHeader(CTable).maxSymbolValue)
|
||||||
|
return 0;
|
||||||
return (U32)HUF_getNbBits(ct[symbolValue]);
|
return (U32)HUF_getNbBits(ct[symbolValue]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct nodeElt_s {
|
|
||||||
U32 count;
|
|
||||||
U16 parent;
|
|
||||||
BYTE byte;
|
|
||||||
BYTE nbBits;
|
|
||||||
} nodeElt;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HUF_setMaxHeight():
|
* HUF_setMaxHeight():
|
||||||
* Enforces maxNbBits on the Huffman tree described in huffNode.
|
* Try to enforce @targetNbBits on the Huffman tree described in @huffNode.
|
||||||
*
|
*
|
||||||
* It sets all nodes with nbBits > maxNbBits to be maxNbBits. Then it adjusts
|
* It attempts to convert all nodes with nbBits > @targetNbBits
|
||||||
* the tree to so that it is a valid canonical Huffman tree.
|
* to employ @targetNbBits instead. Then it adjusts the tree
|
||||||
|
* so that it remains a valid canonical Huffman tree.
|
||||||
*
|
*
|
||||||
* @pre The sum of the ranks of each symbol == 2^largestBits,
|
* @pre The sum of the ranks of each symbol == 2^largestBits,
|
||||||
* where largestBits == huffNode[lastNonNull].nbBits.
|
* where largestBits == huffNode[lastNonNull].nbBits.
|
||||||
* @post The sum of the ranks of each symbol == 2^largestBits,
|
* @post The sum of the ranks of each symbol == 2^largestBits,
|
||||||
* where largestBits is the return value <= maxNbBits.
|
* where largestBits is the return value (expected <= targetNbBits).
|
||||||
*
|
*
|
||||||
* @param huffNode The Huffman tree modified in place to enforce maxNbBits.
|
* @param huffNode The Huffman tree modified in place to enforce targetNbBits.
|
||||||
|
* It's presumed sorted, from most frequent to rarest symbol.
|
||||||
* @param lastNonNull The symbol with the lowest count in the Huffman tree.
|
* @param lastNonNull The symbol with the lowest count in the Huffman tree.
|
||||||
* @param maxNbBits The maximum allowed number of bits, which the Huffman tree
|
* @param targetNbBits The allowed number of bits, which the Huffman tree
|
||||||
* may not respect. After this function the Huffman tree will
|
* may not respect. After this function the Huffman tree will
|
||||||
* respect maxNbBits.
|
* respect targetNbBits.
|
||||||
* @return The maximum number of bits of the Huffman tree after adjustment,
|
* @return The maximum number of bits of the Huffman tree after adjustment.
|
||||||
* necessarily no more than maxNbBits.
|
|
||||||
*/
|
*/
|
||||||
static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
|
static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits)
|
||||||
{
|
{
|
||||||
const U32 largestBits = huffNode[lastNonNull].nbBits;
|
const U32 largestBits = huffNode[lastNonNull].nbBits;
|
||||||
/* early exit : no elt > maxNbBits, so the tree is already valid. */
|
/* early exit : no elt > targetNbBits, so the tree is already valid. */
|
||||||
if (largestBits <= maxNbBits) return largestBits;
|
if (largestBits <= targetNbBits) return largestBits;
|
||||||
|
|
||||||
|
DEBUGLOG(5, "HUF_setMaxHeight (targetNbBits = %u)", targetNbBits);
|
||||||
|
|
||||||
/* there are several too large elements (at least >= 2) */
|
/* there are several too large elements (at least >= 2) */
|
||||||
{ int totalCost = 0;
|
{ int totalCost = 0;
|
||||||
const U32 baseCost = 1 << (largestBits - maxNbBits);
|
const U32 baseCost = 1 << (largestBits - targetNbBits);
|
||||||
int n = (int)lastNonNull;
|
int n = (int)lastNonNull;
|
||||||
|
|
||||||
/* Adjust any ranks > maxNbBits to maxNbBits.
|
/* Adjust any ranks > targetNbBits to targetNbBits.
|
||||||
* Compute totalCost, which is how far the sum of the ranks is
|
* Compute totalCost, which is how far the sum of the ranks is
|
||||||
* we are over 2^largestBits after adjust the offending ranks.
|
* we are over 2^largestBits after adjust the offending ranks.
|
||||||
*/
|
*/
|
||||||
while (huffNode[n].nbBits > maxNbBits) {
|
while (huffNode[n].nbBits > targetNbBits) {
|
||||||
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
|
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
|
||||||
huffNode[n].nbBits = (BYTE)maxNbBits;
|
huffNode[n].nbBits = (BYTE)targetNbBits;
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
/* n stops at huffNode[n].nbBits <= maxNbBits */
|
/* n stops at huffNode[n].nbBits <= targetNbBits */
|
||||||
assert(huffNode[n].nbBits <= maxNbBits);
|
assert(huffNode[n].nbBits <= targetNbBits);
|
||||||
/* n end at index of smallest symbol using < maxNbBits */
|
/* n end at index of smallest symbol using < targetNbBits */
|
||||||
while (huffNode[n].nbBits == maxNbBits) --n;
|
while (huffNode[n].nbBits == targetNbBits) --n;
|
||||||
|
|
||||||
/* renorm totalCost from 2^largestBits to 2^maxNbBits
|
/* renorm totalCost from 2^largestBits to 2^targetNbBits
|
||||||
* note : totalCost is necessarily a multiple of baseCost */
|
* note : totalCost is necessarily a multiple of baseCost */
|
||||||
assert((totalCost & (baseCost - 1)) == 0);
|
assert(((U32)totalCost & (baseCost - 1)) == 0);
|
||||||
totalCost >>= (largestBits - maxNbBits);
|
totalCost >>= (largestBits - targetNbBits);
|
||||||
assert(totalCost > 0);
|
assert(totalCost > 0);
|
||||||
|
|
||||||
/* repay normalized cost */
|
/* repay normalized cost */
|
||||||
|
|
@ -339,19 +410,19 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
|
||||||
|
|
||||||
/* Get pos of last (smallest = lowest cum. count) symbol per rank */
|
/* Get pos of last (smallest = lowest cum. count) symbol per rank */
|
||||||
ZSTD_memset(rankLast, 0xF0, sizeof(rankLast));
|
ZSTD_memset(rankLast, 0xF0, sizeof(rankLast));
|
||||||
{ U32 currentNbBits = maxNbBits;
|
{ U32 currentNbBits = targetNbBits;
|
||||||
int pos;
|
int pos;
|
||||||
for (pos=n ; pos >= 0; pos--) {
|
for (pos=n ; pos >= 0; pos--) {
|
||||||
if (huffNode[pos].nbBits >= currentNbBits) continue;
|
if (huffNode[pos].nbBits >= currentNbBits) continue;
|
||||||
currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */
|
currentNbBits = huffNode[pos].nbBits; /* < targetNbBits */
|
||||||
rankLast[maxNbBits-currentNbBits] = (U32)pos;
|
rankLast[targetNbBits-currentNbBits] = (U32)pos;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
while (totalCost > 0) {
|
while (totalCost > 0) {
|
||||||
/* Try to reduce the next power of 2 above totalCost because we
|
/* Try to reduce the next power of 2 above totalCost because we
|
||||||
* gain back half the rank.
|
* gain back half the rank.
|
||||||
*/
|
*/
|
||||||
U32 nBitsToDecrease = BIT_highbit32((U32)totalCost) + 1;
|
U32 nBitsToDecrease = ZSTD_highbit32((U32)totalCost) + 1;
|
||||||
for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
|
for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
|
||||||
U32 const highPos = rankLast[nBitsToDecrease];
|
U32 const highPos = rankLast[nBitsToDecrease];
|
||||||
U32 const lowPos = rankLast[nBitsToDecrease-1];
|
U32 const lowPos = rankLast[nBitsToDecrease-1];
|
||||||
|
|
@ -391,7 +462,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
|
||||||
rankLast[nBitsToDecrease] = noSymbol;
|
rankLast[nBitsToDecrease] = noSymbol;
|
||||||
else {
|
else {
|
||||||
rankLast[nBitsToDecrease]--;
|
rankLast[nBitsToDecrease]--;
|
||||||
if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
|
if (huffNode[rankLast[nBitsToDecrease]].nbBits != targetNbBits-nBitsToDecrease)
|
||||||
rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
|
rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
|
||||||
}
|
}
|
||||||
} /* while (totalCost > 0) */
|
} /* while (totalCost > 0) */
|
||||||
|
|
@ -403,11 +474,11 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
|
||||||
* TODO.
|
* TODO.
|
||||||
*/
|
*/
|
||||||
while (totalCost < 0) { /* Sometimes, cost correction overshoot */
|
while (totalCost < 0) { /* Sometimes, cost correction overshoot */
|
||||||
/* special case : no rank 1 symbol (using maxNbBits-1);
|
/* special case : no rank 1 symbol (using targetNbBits-1);
|
||||||
* let's create one from largest rank 0 (using maxNbBits).
|
* let's create one from largest rank 0 (using targetNbBits).
|
||||||
*/
|
*/
|
||||||
if (rankLast[1] == noSymbol) {
|
if (rankLast[1] == noSymbol) {
|
||||||
while (huffNode[n].nbBits == maxNbBits) n--;
|
while (huffNode[n].nbBits == targetNbBits) n--;
|
||||||
huffNode[n+1].nbBits--;
|
huffNode[n+1].nbBits--;
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
rankLast[1] = (U32)(n+1);
|
rankLast[1] = (U32)(n+1);
|
||||||
|
|
@ -421,7 +492,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
|
||||||
} /* repay normalized cost */
|
} /* repay normalized cost */
|
||||||
} /* there are several too large elements (at least >= 2) */
|
} /* there are several too large elements (at least >= 2) */
|
||||||
|
|
||||||
return maxNbBits;
|
return targetNbBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -429,7 +500,7 @@ typedef struct {
|
||||||
U16 curr;
|
U16 curr;
|
||||||
} rankPos;
|
} rankPos;
|
||||||
|
|
||||||
typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32];
|
typedef nodeElt huffNodeTable[2 * (HUF_SYMBOLVALUE_MAX + 1)];
|
||||||
|
|
||||||
/* Number of buckets available for HUF_sort() */
|
/* Number of buckets available for HUF_sort() */
|
||||||
#define RANK_POSITION_TABLE_SIZE 192
|
#define RANK_POSITION_TABLE_SIZE 192
|
||||||
|
|
@ -448,8 +519,8 @@ typedef struct {
|
||||||
* Let buckets 166 to 192 represent all remaining counts up to RANK_POSITION_MAX_COUNT_LOG using log2 bucketing.
|
* Let buckets 166 to 192 represent all remaining counts up to RANK_POSITION_MAX_COUNT_LOG using log2 bucketing.
|
||||||
*/
|
*/
|
||||||
#define RANK_POSITION_MAX_COUNT_LOG 32
|
#define RANK_POSITION_MAX_COUNT_LOG 32
|
||||||
#define RANK_POSITION_LOG_BUCKETS_BEGIN (RANK_POSITION_TABLE_SIZE - 1) - RANK_POSITION_MAX_COUNT_LOG - 1 /* == 158 */
|
#define RANK_POSITION_LOG_BUCKETS_BEGIN ((RANK_POSITION_TABLE_SIZE - 1) - RANK_POSITION_MAX_COUNT_LOG - 1 /* == 158 */)
|
||||||
#define RANK_POSITION_DISTINCT_COUNT_CUTOFF RANK_POSITION_LOG_BUCKETS_BEGIN + BIT_highbit32(RANK_POSITION_LOG_BUCKETS_BEGIN) /* == 166 */
|
#define RANK_POSITION_DISTINCT_COUNT_CUTOFF (RANK_POSITION_LOG_BUCKETS_BEGIN + ZSTD_highbit32(RANK_POSITION_LOG_BUCKETS_BEGIN) /* == 166 */)
|
||||||
|
|
||||||
/* Return the appropriate bucket index for a given count. See definition of
|
/* Return the appropriate bucket index for a given count. See definition of
|
||||||
* RANK_POSITION_DISTINCT_COUNT_CUTOFF for explanation of bucketing strategy.
|
* RANK_POSITION_DISTINCT_COUNT_CUTOFF for explanation of bucketing strategy.
|
||||||
|
|
@ -457,7 +528,7 @@ typedef struct {
|
||||||
static U32 HUF_getIndex(U32 const count) {
|
static U32 HUF_getIndex(U32 const count) {
|
||||||
return (count < RANK_POSITION_DISTINCT_COUNT_CUTOFF)
|
return (count < RANK_POSITION_DISTINCT_COUNT_CUTOFF)
|
||||||
? count
|
? count
|
||||||
: BIT_highbit32(count) + RANK_POSITION_LOG_BUCKETS_BEGIN;
|
: ZSTD_highbit32(count) + RANK_POSITION_LOG_BUCKETS_BEGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper swap function for HUF_quickSortPartition() */
|
/* Helper swap function for HUF_quickSortPartition() */
|
||||||
|
|
@ -580,7 +651,7 @@ static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSy
|
||||||
|
|
||||||
/* Sort each bucket. */
|
/* Sort each bucket. */
|
||||||
for (n = RANK_POSITION_DISTINCT_COUNT_CUTOFF; n < RANK_POSITION_TABLE_SIZE - 1; ++n) {
|
for (n = RANK_POSITION_DISTINCT_COUNT_CUTOFF; n < RANK_POSITION_TABLE_SIZE - 1; ++n) {
|
||||||
U32 const bucketSize = rankPosition[n].curr-rankPosition[n].base;
|
int const bucketSize = rankPosition[n].curr - rankPosition[n].base;
|
||||||
U32 const bucketStartIdx = rankPosition[n].base;
|
U32 const bucketStartIdx = rankPosition[n].base;
|
||||||
if (bucketSize > 1) {
|
if (bucketSize > 1) {
|
||||||
assert(bucketStartIdx < maxSymbolValue1);
|
assert(bucketStartIdx < maxSymbolValue1);
|
||||||
|
|
@ -591,6 +662,7 @@ static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSy
|
||||||
assert(HUF_isSorted(huffNode, maxSymbolValue1));
|
assert(HUF_isSorted(huffNode, maxSymbolValue1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* HUF_buildCTable_wksp() :
|
/* HUF_buildCTable_wksp() :
|
||||||
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as sizeof(HUF_buildCTable_wksp_tables).
|
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as sizeof(HUF_buildCTable_wksp_tables).
|
||||||
|
|
@ -611,6 +683,7 @@ static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue)
|
||||||
int lowS, lowN;
|
int lowS, lowN;
|
||||||
int nodeNb = STARTNODE;
|
int nodeNb = STARTNODE;
|
||||||
int n, nodeRoot;
|
int n, nodeRoot;
|
||||||
|
DEBUGLOG(5, "HUF_buildTree (alphabet size = %u)", maxSymbolValue + 1);
|
||||||
/* init for parents */
|
/* init for parents */
|
||||||
nonNullRank = (int)maxSymbolValue;
|
nonNullRank = (int)maxSymbolValue;
|
||||||
while(huffNode[nonNullRank].count == 0) nonNullRank--;
|
while(huffNode[nonNullRank].count == 0) nonNullRank--;
|
||||||
|
|
@ -637,6 +710,8 @@ static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue)
|
||||||
for (n=0; n<=nonNullRank; n++)
|
for (n=0; n<=nonNullRank; n++)
|
||||||
huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
|
huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
|
||||||
|
|
||||||
|
DEBUGLOG(6, "Initial distribution of bits completed (%zu sorted symbols)", showHNodeBits(huffNode, maxSymbolValue+1));
|
||||||
|
|
||||||
return nonNullRank;
|
return nonNullRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -671,16 +746,24 @@ static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, i
|
||||||
HUF_setNbBits(ct + huffNode[n].byte, huffNode[n].nbBits); /* push nbBits per symbol, symbol order */
|
HUF_setNbBits(ct + huffNode[n].byte, huffNode[n].nbBits); /* push nbBits per symbol, symbol order */
|
||||||
for (n=0; n<alphabetSize; n++)
|
for (n=0; n<alphabetSize; n++)
|
||||||
HUF_setValue(ct + n, valPerRank[HUF_getNbBits(ct[n])]++); /* assign value within rank, symbol order */
|
HUF_setValue(ct + n, valPerRank[HUF_getNbBits(ct[n])]++); /* assign value within rank, symbol order */
|
||||||
CTable[0] = maxNbBits;
|
|
||||||
|
HUF_writeCTableHeader(CTable, maxNbBits, maxSymbolValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_buildCTable_wksp (HUF_CElt* CTable, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
|
size_t
|
||||||
|
HUF_buildCTable_wksp(HUF_CElt* CTable, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
{
|
{
|
||||||
HUF_buildCTable_wksp_tables* const wksp_tables = (HUF_buildCTable_wksp_tables*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(U32));
|
HUF_buildCTable_wksp_tables* const wksp_tables =
|
||||||
|
(HUF_buildCTable_wksp_tables*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(U32));
|
||||||
nodeElt* const huffNode0 = wksp_tables->huffNodeTbl;
|
nodeElt* const huffNode0 = wksp_tables->huffNodeTbl;
|
||||||
nodeElt* const huffNode = huffNode0+1;
|
nodeElt* const huffNode = huffNode0+1;
|
||||||
int nonNullRank;
|
int nonNullRank;
|
||||||
|
|
||||||
|
HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE == sizeof(HUF_buildCTable_wksp_tables));
|
||||||
|
|
||||||
|
DEBUGLOG(5, "HUF_buildCTable_wksp (alphabet size = %u)", maxSymbolValue+1);
|
||||||
|
|
||||||
/* safety checks */
|
/* safety checks */
|
||||||
if (wkspSize < sizeof(HUF_buildCTable_wksp_tables))
|
if (wkspSize < sizeof(HUF_buildCTable_wksp_tables))
|
||||||
return ERROR(workSpace_tooSmall);
|
return ERROR(workSpace_tooSmall);
|
||||||
|
|
@ -691,11 +774,12 @@ size_t HUF_buildCTable_wksp (HUF_CElt* CTable, const unsigned* count, U32 maxSym
|
||||||
|
|
||||||
/* sort, decreasing order */
|
/* sort, decreasing order */
|
||||||
HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition);
|
HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition);
|
||||||
|
DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1));
|
||||||
|
|
||||||
/* build tree */
|
/* build tree */
|
||||||
nonNullRank = HUF_buildTree(huffNode, maxSymbolValue);
|
nonNullRank = HUF_buildTree(huffNode, maxSymbolValue);
|
||||||
|
|
||||||
/* enforce maxTableLog */
|
/* determine and enforce maxTableLog */
|
||||||
maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits);
|
maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits);
|
||||||
if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
|
if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
|
||||||
|
|
||||||
|
|
@ -716,9 +800,16 @@ size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count,
|
||||||
}
|
}
|
||||||
|
|
||||||
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
|
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
|
||||||
|
HUF_CTableHeader header = HUF_readCTableHeader(CTable);
|
||||||
HUF_CElt const* ct = CTable + 1;
|
HUF_CElt const* ct = CTable + 1;
|
||||||
int bad = 0;
|
int bad = 0;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
|
assert(header.tableLog <= HUF_TABLELOG_ABSOLUTEMAX);
|
||||||
|
|
||||||
|
if (header.maxSymbolValue < maxSymbolValue)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (s = 0; s <= (int)maxSymbolValue; ++s) {
|
for (s = 0; s <= (int)maxSymbolValue; ++s) {
|
||||||
bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0);
|
bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0);
|
||||||
}
|
}
|
||||||
|
|
@ -804,7 +895,7 @@ FORCE_INLINE_TEMPLATE void HUF_addBits(HUF_CStream_t* bitC, HUF_CElt elt, int id
|
||||||
#if DEBUGLEVEL >= 1
|
#if DEBUGLEVEL >= 1
|
||||||
{
|
{
|
||||||
size_t const nbBits = HUF_getNbBits(elt);
|
size_t const nbBits = HUF_getNbBits(elt);
|
||||||
size_t const dirtyBits = nbBits == 0 ? 0 : BIT_highbit32((U32)nbBits) + 1;
|
size_t const dirtyBits = nbBits == 0 ? 0 : ZSTD_highbit32((U32)nbBits) + 1;
|
||||||
(void)dirtyBits;
|
(void)dirtyBits;
|
||||||
/* Middle bits are 0. */
|
/* Middle bits are 0. */
|
||||||
assert(((elt >> dirtyBits) << (dirtyBits + nbBits)) == 0);
|
assert(((elt >> dirtyBits) << (dirtyBits + nbBits)) == 0);
|
||||||
|
|
@ -884,7 +975,7 @@ static size_t HUF_closeCStream(HUF_CStream_t* bitC)
|
||||||
{
|
{
|
||||||
size_t const nbBits = bitC->bitPos[0] & 0xFF;
|
size_t const nbBits = bitC->bitPos[0] & 0xFF;
|
||||||
if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
|
if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
|
||||||
return (bitC->ptr - bitC->startPtr) + (nbBits > 0);
|
return (size_t)(bitC->ptr - bitC->startPtr) + (nbBits > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -964,17 +1055,17 @@ HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const HUF_CElt* CTable)
|
const HUF_CElt* CTable)
|
||||||
{
|
{
|
||||||
U32 const tableLog = (U32)CTable[0];
|
U32 const tableLog = HUF_readCTableHeader(CTable).tableLog;
|
||||||
HUF_CElt const* ct = CTable + 1;
|
HUF_CElt const* ct = CTable + 1;
|
||||||
const BYTE* ip = (const BYTE*) src;
|
const BYTE* ip = (const BYTE*) src;
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
BYTE* const oend = ostart + dstSize;
|
BYTE* const oend = ostart + dstSize;
|
||||||
BYTE* op = ostart;
|
|
||||||
HUF_CStream_t bitC;
|
HUF_CStream_t bitC;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
if (dstSize < 8) return 0; /* not enough space to compress */
|
if (dstSize < 8) return 0; /* not enough space to compress */
|
||||||
{ size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op));
|
{ BYTE* op = ostart;
|
||||||
|
size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op));
|
||||||
if (HUF_isError(initErr)) return 0; }
|
if (HUF_isError(initErr)) return 0; }
|
||||||
|
|
||||||
if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11)
|
if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11)
|
||||||
|
|
@ -1045,9 +1136,9 @@ HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize,
|
||||||
static size_t
|
static size_t
|
||||||
HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
|
HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const HUF_CElt* CTable, const int bmi2)
|
const HUF_CElt* CTable, const int flags)
|
||||||
{
|
{
|
||||||
if (bmi2) {
|
if (flags & HUF_flags_bmi2) {
|
||||||
return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable);
|
return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable);
|
||||||
}
|
}
|
||||||
return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable);
|
return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable);
|
||||||
|
|
@ -1058,28 +1149,23 @@ HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
static size_t
|
static size_t
|
||||||
HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
|
HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const HUF_CElt* CTable, const int bmi2)
|
const HUF_CElt* CTable, const int flags)
|
||||||
{
|
{
|
||||||
(void)bmi2;
|
(void)flags;
|
||||||
return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
|
return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags)
|
||||||
{
|
{
|
||||||
return HUF_compress1X_usingCTable_bmi2(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
|
return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags);
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2)
|
|
||||||
{
|
|
||||||
return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, bmi2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const HUF_CElt* CTable, int bmi2)
|
const HUF_CElt* CTable, int flags)
|
||||||
{
|
{
|
||||||
size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
|
size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
|
||||||
const BYTE* ip = (const BYTE*) src;
|
const BYTE* ip = (const BYTE*) src;
|
||||||
|
|
@ -1093,7 +1179,7 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
op += 6; /* jumpTable */
|
op += 6; /* jumpTable */
|
||||||
|
|
||||||
assert(op <= oend);
|
assert(op <= oend);
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) );
|
||||||
if (cSize == 0 || cSize > 65535) return 0;
|
if (cSize == 0 || cSize > 65535) return 0;
|
||||||
MEM_writeLE16(ostart, (U16)cSize);
|
MEM_writeLE16(ostart, (U16)cSize);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
|
|
@ -1101,7 +1187,7 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
|
|
||||||
ip += segmentSize;
|
ip += segmentSize;
|
||||||
assert(op <= oend);
|
assert(op <= oend);
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) );
|
||||||
if (cSize == 0 || cSize > 65535) return 0;
|
if (cSize == 0 || cSize > 65535) return 0;
|
||||||
MEM_writeLE16(ostart+2, (U16)cSize);
|
MEM_writeLE16(ostart+2, (U16)cSize);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
|
|
@ -1109,7 +1195,7 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
|
|
||||||
ip += segmentSize;
|
ip += segmentSize;
|
||||||
assert(op <= oend);
|
assert(op <= oend);
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) );
|
||||||
if (cSize == 0 || cSize > 65535) return 0;
|
if (cSize == 0 || cSize > 65535) return 0;
|
||||||
MEM_writeLE16(ostart+4, (U16)cSize);
|
MEM_writeLE16(ostart+4, (U16)cSize);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
|
|
@ -1118,7 +1204,7 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
ip += segmentSize;
|
ip += segmentSize;
|
||||||
assert(op <= oend);
|
assert(op <= oend);
|
||||||
assert(ip <= iend);
|
assert(ip <= iend);
|
||||||
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, bmi2) );
|
{ CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, flags) );
|
||||||
if (cSize == 0 || cSize > 65535) return 0;
|
if (cSize == 0 || cSize > 65535) return 0;
|
||||||
op += cSize;
|
op += cSize;
|
||||||
}
|
}
|
||||||
|
|
@ -1126,14 +1212,9 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
|
||||||
return (size_t)(op-ostart);
|
return (size_t)(op-ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags)
|
||||||
{
|
{
|
||||||
return HUF_compress4X_usingCTable_bmi2(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
|
return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags);
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2)
|
|
||||||
{
|
|
||||||
return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, bmi2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e;
|
typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e;
|
||||||
|
|
@ -1141,11 +1222,11 @@ typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e;
|
||||||
static size_t HUF_compressCTable_internal(
|
static size_t HUF_compressCTable_internal(
|
||||||
BYTE* const ostart, BYTE* op, BYTE* const oend,
|
BYTE* const ostart, BYTE* op, BYTE* const oend,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2)
|
HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int flags)
|
||||||
{
|
{
|
||||||
size_t const cSize = (nbStreams==HUF_singleStream) ?
|
size_t const cSize = (nbStreams==HUF_singleStream) ?
|
||||||
HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2) :
|
HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags) :
|
||||||
HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2);
|
HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags);
|
||||||
if (HUF_isError(cSize)) { return cSize; }
|
if (HUF_isError(cSize)) { return cSize; }
|
||||||
if (cSize==0) { return 0; } /* uncompressible */
|
if (cSize==0) { return 0; } /* uncompressible */
|
||||||
op += cSize;
|
op += cSize;
|
||||||
|
|
@ -1168,6 +1249,81 @@ typedef struct {
|
||||||
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096
|
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096
|
||||||
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */
|
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */
|
||||||
|
|
||||||
|
unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue)
|
||||||
|
{
|
||||||
|
unsigned cardinality = 0;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < maxSymbolValue + 1; i++) {
|
||||||
|
if (count[i] != 0) cardinality += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cardinality;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned HUF_minTableLog(unsigned symbolCardinality)
|
||||||
|
{
|
||||||
|
U32 minBitsSymbols = ZSTD_highbit32(symbolCardinality) + 1;
|
||||||
|
return minBitsSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned HUF_optimalTableLog(
|
||||||
|
unsigned maxTableLog,
|
||||||
|
size_t srcSize,
|
||||||
|
unsigned maxSymbolValue,
|
||||||
|
void* workSpace, size_t wkspSize,
|
||||||
|
HUF_CElt* table,
|
||||||
|
const unsigned* count,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
assert(srcSize > 1); /* Not supported, RLE should be used instead */
|
||||||
|
assert(wkspSize >= sizeof(HUF_buildCTable_wksp_tables));
|
||||||
|
|
||||||
|
if (!(flags & HUF_flags_optimalDepth)) {
|
||||||
|
/* cheap evaluation, based on FSE */
|
||||||
|
return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp);
|
||||||
|
size_t dstSize = wkspSize - sizeof(HUF_WriteCTableWksp);
|
||||||
|
size_t hSize, newSize;
|
||||||
|
const unsigned symbolCardinality = HUF_cardinality(count, maxSymbolValue);
|
||||||
|
const unsigned minTableLog = HUF_minTableLog(symbolCardinality);
|
||||||
|
size_t optSize = ((size_t) ~0) - 1;
|
||||||
|
unsigned optLog = maxTableLog, optLogGuess;
|
||||||
|
|
||||||
|
DEBUGLOG(6, "HUF_optimalTableLog: probing huf depth (srcSize=%zu)", srcSize);
|
||||||
|
|
||||||
|
/* Search until size increases */
|
||||||
|
for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) {
|
||||||
|
DEBUGLOG(7, "checking for huffLog=%u", optLogGuess);
|
||||||
|
|
||||||
|
{ size_t maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize);
|
||||||
|
if (ERR_isError(maxBits)) continue;
|
||||||
|
|
||||||
|
if (maxBits < optLogGuess && optLogGuess > minTableLog) break;
|
||||||
|
|
||||||
|
hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ERR_isError(hSize)) continue;
|
||||||
|
|
||||||
|
newSize = HUF_estimateCompressedSize(table, count, maxSymbolValue) + hSize;
|
||||||
|
|
||||||
|
if (newSize > optSize + 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSize < optSize) {
|
||||||
|
optSize = newSize;
|
||||||
|
optLog = optLogGuess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(optLog <= HUF_TABLELOG_MAX);
|
||||||
|
return optLog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* HUF_compress_internal() :
|
/* HUF_compress_internal() :
|
||||||
* `workSpace_align4` must be aligned on 4-bytes boundaries,
|
* `workSpace_align4` must be aligned on 4-bytes boundaries,
|
||||||
* and occupies the same space as a table of HUF_WORKSPACE_SIZE_U64 unsigned */
|
* and occupies the same space as a table of HUF_WORKSPACE_SIZE_U64 unsigned */
|
||||||
|
|
@ -1177,14 +1333,14 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
HUF_nbStreams_e nbStreams,
|
HUF_nbStreams_e nbStreams,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
|
HUF_CElt* oldHufTable, HUF_repeat* repeat, int flags)
|
||||||
const int bmi2, unsigned suspectUncompressible)
|
|
||||||
{
|
{
|
||||||
HUF_compress_tables_t* const table = (HUF_compress_tables_t*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(size_t));
|
HUF_compress_tables_t* const table = (HUF_compress_tables_t*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(size_t));
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
BYTE* const oend = ostart + dstSize;
|
BYTE* const oend = ostart + dstSize;
|
||||||
BYTE* op = ostart;
|
BYTE* op = ostart;
|
||||||
|
|
||||||
|
DEBUGLOG(5, "HUF_compress_internal (srcSize=%zu)", srcSize);
|
||||||
HUF_STATIC_ASSERT(sizeof(*table) + HUF_WORKSPACE_MAX_ALIGNMENT <= HUF_WORKSPACE_SIZE);
|
HUF_STATIC_ASSERT(sizeof(*table) + HUF_WORKSPACE_MAX_ALIGNMENT <= HUF_WORKSPACE_SIZE);
|
||||||
|
|
||||||
/* checks & inits */
|
/* checks & inits */
|
||||||
|
|
@ -1198,16 +1354,17 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
||||||
if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
|
if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
|
||||||
|
|
||||||
/* Heuristic : If old table is valid, use it for small inputs */
|
/* Heuristic : If old table is valid, use it for small inputs */
|
||||||
if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
|
if ((flags & HUF_flags_preferRepeat) && repeat && *repeat == HUF_repeat_valid) {
|
||||||
return HUF_compressCTable_internal(ostart, op, oend,
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
src, srcSize,
|
src, srcSize,
|
||||||
nbStreams, oldHufTable, bmi2);
|
nbStreams, oldHufTable, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If uncompressible data is suspected, do a smaller sampling first */
|
/* If uncompressible data is suspected, do a smaller sampling first */
|
||||||
DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2);
|
DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2);
|
||||||
if (suspectUncompressible && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) {
|
if ((flags & HUF_flags_suspectUncompressible) && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) {
|
||||||
size_t largestTotal = 0;
|
size_t largestTotal = 0;
|
||||||
|
DEBUGLOG(5, "input suspected incompressible : sampling to check");
|
||||||
{ unsigned maxSymbolValueBegin = maxSymbolValue;
|
{ unsigned maxSymbolValueBegin = maxSymbolValue;
|
||||||
CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) );
|
CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) );
|
||||||
largestTotal += largestBegin;
|
largestTotal += largestBegin;
|
||||||
|
|
@ -1224,6 +1381,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
||||||
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
|
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
|
||||||
if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */
|
if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */
|
||||||
}
|
}
|
||||||
|
DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1));
|
||||||
|
|
||||||
/* Check validity of previous table */
|
/* Check validity of previous table */
|
||||||
if ( repeat
|
if ( repeat
|
||||||
|
|
@ -1232,25 +1390,20 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
||||||
*repeat = HUF_repeat_none;
|
*repeat = HUF_repeat_none;
|
||||||
}
|
}
|
||||||
/* Heuristic : use existing table for small inputs */
|
/* Heuristic : use existing table for small inputs */
|
||||||
if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
|
if ((flags & HUF_flags_preferRepeat) && repeat && *repeat != HUF_repeat_none) {
|
||||||
return HUF_compressCTable_internal(ostart, op, oend,
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
src, srcSize,
|
src, srcSize,
|
||||||
nbStreams, oldHufTable, bmi2);
|
nbStreams, oldHufTable, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build Huffman Tree */
|
/* Build Huffman Tree */
|
||||||
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, &table->wksps, sizeof(table->wksps), table->CTable, table->count, flags);
|
||||||
{ size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
|
{ size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
|
||||||
maxSymbolValue, huffLog,
|
maxSymbolValue, huffLog,
|
||||||
&table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp));
|
&table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp));
|
||||||
CHECK_F(maxBits);
|
CHECK_F(maxBits);
|
||||||
huffLog = (U32)maxBits;
|
huffLog = (U32)maxBits;
|
||||||
}
|
DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1));
|
||||||
/* Zero unused symbols in CTable, so we can check it for validity */
|
|
||||||
{
|
|
||||||
size_t const ctableSize = HUF_CTABLE_SIZE_ST(maxSymbolValue);
|
|
||||||
size_t const unusedSize = sizeof(table->CTable) - ctableSize * sizeof(HUF_CElt);
|
|
||||||
ZSTD_memset(table->CTable + ctableSize, 0, unusedSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write table description header */
|
/* Write table description header */
|
||||||
|
|
@ -1263,7 +1416,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
||||||
if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
|
if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
|
||||||
return HUF_compressCTable_internal(ostart, op, oend,
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
src, srcSize,
|
src, srcSize,
|
||||||
nbStreams, oldHufTable, bmi2);
|
nbStreams, oldHufTable, flags);
|
||||||
} }
|
} }
|
||||||
|
|
||||||
/* Use the new huffman table */
|
/* Use the new huffman table */
|
||||||
|
|
@ -1275,61 +1428,35 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
||||||
}
|
}
|
||||||
return HUF_compressCTable_internal(ostart, op, oend,
|
return HUF_compressCTable_internal(ostart, op, oend,
|
||||||
src, srcSize,
|
src, srcSize,
|
||||||
nbStreams, table->CTable, bmi2);
|
nbStreams, table->CTable, flags);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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, HUF_singleStream,
|
|
||||||
workSpace, wkspSize,
|
|
||||||
NULL, NULL, 0, 0 /*bmi2*/, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat,
|
HUF_CElt* hufTable, HUF_repeat* repeat, int flags)
|
||||||
int bmi2, unsigned suspectUncompressible)
|
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(5, "HUF_compress1X_repeat (srcSize = %zu)", srcSize);
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
maxSymbolValue, huffLog, HUF_singleStream,
|
maxSymbolValue, huffLog, HUF_singleStream,
|
||||||
workSpace, wkspSize, hufTable,
|
workSpace, wkspSize, hufTable,
|
||||||
repeat, preferRepeat, bmi2, suspectUncompressible);
|
repeat, flags);
|
||||||
}
|
|
||||||
|
|
||||||
/* HUF_compress4X_repeat():
|
|
||||||
* compress input using 4 streams.
|
|
||||||
* provide workspace to generate compression tables */
|
|
||||||
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, HUF_fourStreams,
|
|
||||||
workSpace, wkspSize,
|
|
||||||
NULL, NULL, 0, 0 /*bmi2*/, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HUF_compress4X_repeat():
|
/* HUF_compress4X_repeat():
|
||||||
* compress input using 4 streams.
|
* compress input using 4 streams.
|
||||||
* consider skipping quickly
|
* consider skipping quickly
|
||||||
* re-use an existing huffman compression table */
|
* reuse an existing huffman compression table */
|
||||||
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible)
|
HUF_CElt* hufTable, HUF_repeat* repeat, int flags)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(5, "HUF_compress4X_repeat (srcSize = %zu)", srcSize);
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
maxSymbolValue, huffLog, HUF_fourStreams,
|
maxSymbolValue, huffLog, HUF_fourStreams,
|
||||||
workSpace, wkspSize,
|
workSpace, wkspSize,
|
||||||
hufTable, repeat, preferRepeat, bmi2, suspectUncompressible);
|
hufTable, repeat, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -13,11 +14,36 @@
|
||||||
***************************************/
|
***************************************/
|
||||||
#include "zstd_compress_literals.h"
|
#include "zstd_compress_literals.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Debug Traces
|
||||||
|
****************************************************************/
|
||||||
|
#if DEBUGLEVEL >= 2
|
||||||
|
|
||||||
|
static size_t showHexa(const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
const BYTE* const ip = (const BYTE*)src;
|
||||||
|
size_t u;
|
||||||
|
for (u=0; u<srcSize; u++) {
|
||||||
|
RAWLOG(5, " %02X", ip[u]); (void)ip;
|
||||||
|
}
|
||||||
|
RAWLOG(5, " \n");
|
||||||
|
return srcSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Literals compression - special cases
|
||||||
|
****************************************************************/
|
||||||
size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
||||||
|
|
||||||
|
DEBUGLOG(5, "ZSTD_noCompressLiterals: srcSize=%zu, dstCapacity=%zu", srcSize, dstCapacity);
|
||||||
|
|
||||||
RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, "");
|
RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, "");
|
||||||
|
|
||||||
switch(flSize)
|
switch(flSize)
|
||||||
|
|
@ -36,16 +62,30 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src,
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_memcpy(ostart + flSize, src, srcSize);
|
ZSTD_memcpy(ostart + flSize, src, srcSize);
|
||||||
DEBUGLOG(5, "Raw literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize));
|
DEBUGLOG(5, "Raw (uncompressed) literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize));
|
||||||
return srcSize + flSize;
|
return srcSize + flSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int allBytesIdentical(const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
assert(srcSize >= 1);
|
||||||
|
assert(src != NULL);
|
||||||
|
{ const BYTE b = ((const BYTE*)src)[0];
|
||||||
|
size_t p;
|
||||||
|
for (p=1; p<srcSize; p++) {
|
||||||
|
if (((const BYTE*)src)[p] != b) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
||||||
|
|
||||||
(void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
|
assert(dstCapacity >= 4); (void)dstCapacity;
|
||||||
|
assert(allBytesIdentical(src, srcSize));
|
||||||
|
|
||||||
switch(flSize)
|
switch(flSize)
|
||||||
{
|
{
|
||||||
|
|
@ -63,28 +103,51 @@ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void*
|
||||||
}
|
}
|
||||||
|
|
||||||
ostart[flSize] = *(const BYTE*)src;
|
ostart[flSize] = *(const BYTE*)src;
|
||||||
DEBUGLOG(5, "RLE literals: %u -> %u", (U32)srcSize, (U32)flSize + 1);
|
DEBUGLOG(5, "RLE : Repeated Literal (%02X: %u times) -> %u bytes encoded", ((const BYTE*)src)[0], (U32)srcSize, (U32)flSize + 1);
|
||||||
return flSize+1;
|
return flSize+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
/* ZSTD_minLiteralsToCompress() :
|
||||||
ZSTD_hufCTables_t* nextHuf,
|
* returns minimal amount of literals
|
||||||
ZSTD_strategy strategy, int disableLiteralCompression,
|
* for literal compression to even be attempted.
|
||||||
|
* Minimum is made tighter as compression strategy increases.
|
||||||
|
*/
|
||||||
|
static size_t
|
||||||
|
ZSTD_minLiteralsToCompress(ZSTD_strategy strategy, HUF_repeat huf_repeat)
|
||||||
|
{
|
||||||
|
assert((int)strategy >= 0);
|
||||||
|
assert((int)strategy <= 9);
|
||||||
|
/* btultra2 : min 8 bytes;
|
||||||
|
* then 2x larger for each successive compression strategy
|
||||||
|
* max threshold 64 bytes */
|
||||||
|
{ int const shift = MIN(9-(int)strategy, 3);
|
||||||
|
size_t const mintc = (huf_repeat == HUF_repeat_valid) ? 6 : (size_t)8 << shift;
|
||||||
|
DEBUGLOG(7, "minLiteralsToCompress = %zu", mintc);
|
||||||
|
return mintc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_compressLiterals (
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
||||||
const int bmi2,
|
const ZSTD_hufCTables_t* prevHuf,
|
||||||
unsigned suspectUncompressible)
|
ZSTD_hufCTables_t* nextHuf,
|
||||||
|
ZSTD_strategy strategy,
|
||||||
|
int disableLiteralCompression,
|
||||||
|
int suspectUncompressible,
|
||||||
|
int bmi2)
|
||||||
{
|
{
|
||||||
size_t const minGain = ZSTD_minGain(srcSize, strategy);
|
|
||||||
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
U32 singleStream = srcSize < 256;
|
U32 singleStream = srcSize < 256;
|
||||||
symbolEncodingType_e hType = set_compressed;
|
SymbolEncodingType_e hType = set_compressed;
|
||||||
size_t cLitSize;
|
size_t cLitSize;
|
||||||
|
|
||||||
DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i srcSize=%u)",
|
DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i, srcSize=%u, dstCapacity=%zu)",
|
||||||
disableLiteralCompression, (U32)srcSize);
|
disableLiteralCompression, (U32)srcSize, dstCapacity);
|
||||||
|
|
||||||
|
DEBUGLOG(6, "Completed literals listing (%zu bytes)", showHexa(src, srcSize));
|
||||||
|
|
||||||
/* Prepare nextEntropy assuming reusing the existing table */
|
/* Prepare nextEntropy assuming reusing the existing table */
|
||||||
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||||
|
|
@ -92,40 +155,51 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
||||||
if (disableLiteralCompression)
|
if (disableLiteralCompression)
|
||||||
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
|
|
||||||
/* small ? don't even attempt compression (speed opt) */
|
/* if too small, don't even attempt compression (speed opt) */
|
||||||
# define COMPRESS_LITERALS_SIZE_MIN 63
|
if (srcSize < ZSTD_minLiteralsToCompress(strategy, prevHuf->repeatMode))
|
||||||
{ size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
|
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression");
|
RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression");
|
||||||
{ HUF_repeat repeat = prevHuf->repeatMode;
|
{ HUF_repeat repeat = prevHuf->repeatMode;
|
||||||
int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
|
int const flags = 0
|
||||||
|
| (bmi2 ? HUF_flags_bmi2 : 0)
|
||||||
|
| (strategy < ZSTD_lazy && srcSize <= 1024 ? HUF_flags_preferRepeat : 0)
|
||||||
|
| (strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD ? HUF_flags_optimalDepth : 0)
|
||||||
|
| (suspectUncompressible ? HUF_flags_suspectUncompressible : 0);
|
||||||
|
|
||||||
|
typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int);
|
||||||
|
huf_compress_f huf_compress;
|
||||||
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
||||||
cLitSize = singleStream ?
|
huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat;
|
||||||
HUF_compress1X_repeat(
|
cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize,
|
||||||
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
|
src, srcSize,
|
||||||
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
|
HUF_SYMBOLVALUE_MAX, LitHufLog,
|
||||||
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible) :
|
entropyWorkspace, entropyWorkspaceSize,
|
||||||
HUF_compress4X_repeat(
|
(HUF_CElt*)nextHuf->CTable,
|
||||||
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
|
&repeat, flags);
|
||||||
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
|
DEBUGLOG(5, "%zu literals compressed into %zu bytes (before header)", srcSize, cLitSize);
|
||||||
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible);
|
|
||||||
if (repeat != HUF_repeat_none) {
|
if (repeat != HUF_repeat_none) {
|
||||||
/* reused the existing table */
|
/* reused the existing table */
|
||||||
DEBUGLOG(5, "Reusing previous huffman table");
|
DEBUGLOG(5, "reusing statistics from previous huffman block");
|
||||||
hType = set_repeat;
|
hType = set_repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ size_t const minGain = ZSTD_minGain(srcSize, strategy);
|
||||||
if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) {
|
if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) {
|
||||||
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||||
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
}
|
} }
|
||||||
if (cLitSize==1) {
|
if (cLitSize==1) {
|
||||||
|
/* A return value of 1 signals that the alphabet consists of a single symbol.
|
||||||
|
* However, in some rare circumstances, it could be the compressed size (a single byte).
|
||||||
|
* For that outcome to have a chance to happen, it's necessary that `srcSize < 8`.
|
||||||
|
* (it's also necessary to not generate statistics).
|
||||||
|
* Therefore, in such a case, actively check that all bytes are identical. */
|
||||||
|
if ((srcSize >= 8) || allBytesIdentical(src, srcSize)) {
|
||||||
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||||
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
||||||
}
|
} }
|
||||||
|
|
||||||
if (hType == set_compressed) {
|
if (hType == set_compressed) {
|
||||||
/* using a newly constructed table */
|
/* using a newly constructed table */
|
||||||
|
|
@ -136,16 +210,19 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
||||||
switch(lhSize)
|
switch(lhSize)
|
||||||
{
|
{
|
||||||
case 3: /* 2 - 2 - 10 - 10 */
|
case 3: /* 2 - 2 - 10 - 10 */
|
||||||
{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
|
if (!singleStream) assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS);
|
||||||
|
{ U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
|
||||||
MEM_writeLE24(ostart, lhc);
|
MEM_writeLE24(ostart, lhc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4: /* 2 - 2 - 14 - 14 */
|
case 4: /* 2 - 2 - 14 - 14 */
|
||||||
|
assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS);
|
||||||
{ U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
|
{ U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
|
||||||
MEM_writeLE32(ostart, lhc);
|
MEM_writeLE32(ostart, lhc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 5: /* 2 - 2 - 18 - 18 */
|
case 5: /* 2 - 2 - 18 - 18 */
|
||||||
|
assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS);
|
||||||
{ U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
|
{ U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
|
||||||
MEM_writeLE32(ostart, lhc);
|
MEM_writeLE32(ostart, lhc);
|
||||||
ostart[4] = (BYTE)(cLitSize >> 10);
|
ostart[4] = (BYTE)(cLitSize >> 10);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -16,16 +17,24 @@
|
||||||
|
|
||||||
size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/* ZSTD_compressRleLiteralsBlock() :
|
||||||
|
* Conditions :
|
||||||
|
* - All bytes in @src are identical
|
||||||
|
* - dstCapacity >= 4 */
|
||||||
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
|
||||||
/* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
|
/* ZSTD_compressLiterals():
|
||||||
size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
* @entropyWorkspace: must be aligned on 4-bytes boundaries
|
||||||
ZSTD_hufCTables_t* nextHuf,
|
* @entropyWorkspaceSize : must be >= HUF_WORKSPACE_SIZE
|
||||||
ZSTD_strategy strategy, int disableLiteralCompression,
|
* @suspectUncompressible: sampling checks, to potentially skip huffman coding
|
||||||
void* dst, size_t dstCapacity,
|
*/
|
||||||
|
size_t ZSTD_compressLiterals (void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
||||||
const int bmi2,
|
const ZSTD_hufCTables_t* prevHuf,
|
||||||
unsigned suspectUncompressible);
|
ZSTD_hufCTables_t* nextHuf,
|
||||||
|
ZSTD_strategy strategy, int disableLiteralCompression,
|
||||||
|
int suspectUncompressible,
|
||||||
|
int bmi2);
|
||||||
|
|
||||||
#endif /* ZSTD_COMPRESS_LITERALS_H */
|
#endif /* ZSTD_COMPRESS_LITERALS_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -58,7 +59,7 @@ static unsigned ZSTD_useLowProbCount(size_t const nbSeq)
|
||||||
{
|
{
|
||||||
/* Heuristic: This should cover most blocks <= 16K and
|
/* Heuristic: This should cover most blocks <= 16K and
|
||||||
* start to fade out after 16K to about 32K depending on
|
* start to fade out after 16K to about 32K depending on
|
||||||
* comprssibility.
|
* compressibility.
|
||||||
*/
|
*/
|
||||||
return nbSeq >= 2048;
|
return nbSeq >= 2048;
|
||||||
}
|
}
|
||||||
|
|
@ -153,20 +154,20 @@ size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
|
||||||
return cost >> 8;
|
return cost >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolEncodingType_e
|
SymbolEncodingType_e
|
||||||
ZSTD_selectEncodingType(
|
ZSTD_selectEncodingType(
|
||||||
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
||||||
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
||||||
FSE_CTable const* prevCTable,
|
FSE_CTable const* prevCTable,
|
||||||
short const* defaultNorm, U32 defaultNormLog,
|
short const* defaultNorm, U32 defaultNormLog,
|
||||||
ZSTD_defaultPolicy_e const isDefaultAllowed,
|
ZSTD_DefaultPolicy_e const isDefaultAllowed,
|
||||||
ZSTD_strategy const strategy)
|
ZSTD_strategy const strategy)
|
||||||
{
|
{
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
|
ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
|
||||||
if (mostFrequent == nbSeq) {
|
if (mostFrequent == nbSeq) {
|
||||||
*repeatMode = FSE_repeat_none;
|
*repeatMode = FSE_repeat_none;
|
||||||
if (isDefaultAllowed && nbSeq <= 2) {
|
if (isDefaultAllowed && nbSeq <= 2) {
|
||||||
/* Prefer set_basic over set_rle when there are 2 or less symbols,
|
/* Prefer set_basic over set_rle when there are 2 or fewer symbols,
|
||||||
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
|
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
|
||||||
* If basic encoding isn't possible, always choose RLE.
|
* If basic encoding isn't possible, always choose RLE.
|
||||||
*/
|
*/
|
||||||
|
|
@ -241,7 +242,7 @@ typedef struct {
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||||
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
FSE_CTable* nextCTable, U32 FSELog, SymbolEncodingType_e type,
|
||||||
unsigned* count, U32 max,
|
unsigned* count, U32 max,
|
||||||
const BYTE* codeTable, size_t nbSeq,
|
const BYTE* codeTable, size_t nbSeq,
|
||||||
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||||
|
|
@ -293,7 +294,7 @@ ZSTD_encodeSequences_body(
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
SeqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
{
|
{
|
||||||
BIT_CStream_t blockStream;
|
BIT_CStream_t blockStream;
|
||||||
FSE_CState_t stateMatchLength;
|
FSE_CState_t stateMatchLength;
|
||||||
|
|
@ -387,7 +388,7 @@ ZSTD_encodeSequences_default(
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
SeqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
{
|
{
|
||||||
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
||||||
CTable_MatchLength, mlCodeTable,
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
|
@ -405,7 +406,7 @@ ZSTD_encodeSequences_bmi2(
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
SeqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
{
|
{
|
||||||
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
||||||
CTable_MatchLength, mlCodeTable,
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
|
@ -421,7 +422,7 @@ size_t ZSTD_encodeSequences(
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
|
SeqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
|
||||||
{
|
{
|
||||||
DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
|
DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
|
||||||
#if DYNAMIC_BMI2
|
#if DYNAMIC_BMI2
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,26 +12,27 @@
|
||||||
#ifndef ZSTD_COMPRESS_SEQUENCES_H
|
#ifndef ZSTD_COMPRESS_SEQUENCES_H
|
||||||
#define ZSTD_COMPRESS_SEQUENCES_H
|
#define ZSTD_COMPRESS_SEQUENCES_H
|
||||||
|
|
||||||
|
#include "zstd_compress_internal.h" /* SeqDef */
|
||||||
#include "../common/fse.h" /* FSE_repeat, FSE_CTable */
|
#include "../common/fse.h" /* FSE_repeat, FSE_CTable */
|
||||||
#include "../common/zstd_internal.h" /* symbolEncodingType_e, ZSTD_strategy */
|
#include "../common/zstd_internal.h" /* SymbolEncodingType_e, ZSTD_strategy */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ZSTD_defaultDisallowed = 0,
|
ZSTD_defaultDisallowed = 0,
|
||||||
ZSTD_defaultAllowed = 1
|
ZSTD_defaultAllowed = 1
|
||||||
} ZSTD_defaultPolicy_e;
|
} ZSTD_DefaultPolicy_e;
|
||||||
|
|
||||||
symbolEncodingType_e
|
SymbolEncodingType_e
|
||||||
ZSTD_selectEncodingType(
|
ZSTD_selectEncodingType(
|
||||||
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
||||||
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
||||||
FSE_CTable const* prevCTable,
|
FSE_CTable const* prevCTable,
|
||||||
short const* defaultNorm, U32 defaultNormLog,
|
short const* defaultNorm, U32 defaultNormLog,
|
||||||
ZSTD_defaultPolicy_e const isDefaultAllowed,
|
ZSTD_DefaultPolicy_e const isDefaultAllowed,
|
||||||
ZSTD_strategy const strategy);
|
ZSTD_strategy const strategy);
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||||
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
FSE_CTable* nextCTable, U32 FSELog, SymbolEncodingType_e type,
|
||||||
unsigned* count, U32 max,
|
unsigned* count, U32 max,
|
||||||
const BYTE* codeTable, size_t nbSeq,
|
const BYTE* codeTable, size_t nbSeq,
|
||||||
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||||
|
|
@ -42,7 +44,7 @@ size_t ZSTD_encodeSequences(
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2);
|
SeqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2);
|
||||||
|
|
||||||
size_t ZSTD_fseBitCost(
|
size_t ZSTD_fseBitCost(
|
||||||
FSE_CTable const* ctable,
|
FSE_CTable const* ctable,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -36,9 +37,10 @@
|
||||||
* If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block
|
* If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block
|
||||||
* and the following sub-blocks' literals sections will be Treeless_Literals_Block.
|
* and the following sub-blocks' literals sections will be Treeless_Literals_Block.
|
||||||
* @return : compressed size of literals section of a sub-block
|
* @return : compressed size of literals section of a sub-block
|
||||||
* Or 0 if it unable to compress.
|
* Or 0 if unable to compress.
|
||||||
* Or error code */
|
* Or error code */
|
||||||
static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
static size_t
|
||||||
|
ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||||
const ZSTD_hufCTablesMetadata_t* hufMetadata,
|
const ZSTD_hufCTablesMetadata_t* hufMetadata,
|
||||||
const BYTE* literals, size_t litSize,
|
const BYTE* literals, size_t litSize,
|
||||||
void* dst, size_t dstSize,
|
void* dst, size_t dstSize,
|
||||||
|
|
@ -50,11 +52,9 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||||
BYTE* const oend = ostart + dstSize;
|
BYTE* const oend = ostart + dstSize;
|
||||||
BYTE* op = ostart + lhSize;
|
BYTE* op = ostart + lhSize;
|
||||||
U32 const singleStream = lhSize == 3;
|
U32 const singleStream = lhSize == 3;
|
||||||
symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat;
|
SymbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat;
|
||||||
size_t cLitSize = 0;
|
size_t cLitSize = 0;
|
||||||
|
|
||||||
(void)bmi2; /* TODO bmi2... */
|
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy);
|
DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy);
|
||||||
|
|
||||||
*entropyWritten = 0;
|
*entropyWritten = 0;
|
||||||
|
|
@ -76,9 +76,9 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||||
DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize);
|
DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO bmi2 */
|
{ int const flags = bmi2 ? HUF_flags_bmi2 : 0;
|
||||||
{ const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable)
|
const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags)
|
||||||
: HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable);
|
: HUF_compress4X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
cLitSize += cSize;
|
cLitSize += cSize;
|
||||||
if (cSize == 0 || ERR_isError(cSize)) {
|
if (cSize == 0 || ERR_isError(cSize)) {
|
||||||
|
|
@ -103,7 +103,7 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||||
switch(lhSize)
|
switch(lhSize)
|
||||||
{
|
{
|
||||||
case 3: /* 2 - 2 - 10 - 10 */
|
case 3: /* 2 - 2 - 10 - 10 */
|
||||||
{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
|
{ U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
|
||||||
MEM_writeLE24(ostart, lhc);
|
MEM_writeLE24(ostart, lhc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -123,26 +123,30 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||||
}
|
}
|
||||||
*entropyWritten = 1;
|
*entropyWritten = 1;
|
||||||
DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));
|
DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));
|
||||||
return op-ostart;
|
return (size_t)(op-ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* sequences, size_t nbSeq, size_t litSize, int lastSequence) {
|
static size_t
|
||||||
const seqDef* const sstart = sequences;
|
ZSTD_seqDecompressedSize(SeqStore_t const* seqStore,
|
||||||
const seqDef* const send = sequences + nbSeq;
|
const SeqDef* sequences, size_t nbSeqs,
|
||||||
const seqDef* sp = sstart;
|
size_t litSize, int lastSubBlock)
|
||||||
|
{
|
||||||
size_t matchLengthSum = 0;
|
size_t matchLengthSum = 0;
|
||||||
size_t litLengthSum = 0;
|
size_t litLengthSum = 0;
|
||||||
(void)(litLengthSum); /* suppress unused variable warning on some environments */
|
size_t n;
|
||||||
while (send-sp > 0) {
|
for (n=0; n<nbSeqs; n++) {
|
||||||
ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);
|
const ZSTD_SequenceLength seqLen = ZSTD_getSequenceLength(seqStore, sequences+n);
|
||||||
litLengthSum += seqLen.litLength;
|
litLengthSum += seqLen.litLength;
|
||||||
matchLengthSum += seqLen.matchLength;
|
matchLengthSum += seqLen.matchLength;
|
||||||
sp++;
|
|
||||||
}
|
}
|
||||||
assert(litLengthSum <= litSize);
|
DEBUGLOG(5, "ZSTD_seqDecompressedSize: %u sequences from %p: %u literals + %u matchlength",
|
||||||
if (!lastSequence) {
|
(unsigned)nbSeqs, (const void*)sequences,
|
||||||
|
(unsigned)litLengthSum, (unsigned)matchLengthSum);
|
||||||
|
if (!lastSubBlock)
|
||||||
assert(litLengthSum == litSize);
|
assert(litLengthSum == litSize);
|
||||||
}
|
else
|
||||||
|
assert(litLengthSum <= litSize);
|
||||||
|
(void)litLengthSum;
|
||||||
return matchLengthSum + litSize;
|
return matchLengthSum + litSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,9 +160,10 @@ static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef*
|
||||||
* @return : compressed size of sequences section of a sub-block
|
* @return : compressed size of sequences section of a sub-block
|
||||||
* Or 0 if it is unable to compress
|
* Or 0 if it is unable to compress
|
||||||
* Or error code. */
|
* Or error code. */
|
||||||
static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
static size_t
|
||||||
|
ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
||||||
const ZSTD_fseCTablesMetadata_t* fseMetadata,
|
const ZSTD_fseCTablesMetadata_t* fseMetadata,
|
||||||
const seqDef* sequences, size_t nbSeq,
|
const SeqDef* sequences, size_t nbSeq,
|
||||||
const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
|
const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
|
||||||
const ZSTD_CCtx_params* cctxParams,
|
const ZSTD_CCtx_params* cctxParams,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
|
|
@ -176,14 +181,14 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables
|
||||||
/* Sequences Header */
|
/* Sequences Header */
|
||||||
RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
|
RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
|
||||||
dstSize_tooSmall, "");
|
dstSize_tooSmall, "");
|
||||||
if (nbSeq < 0x7F)
|
if (nbSeq < 128)
|
||||||
*op++ = (BYTE)nbSeq;
|
*op++ = (BYTE)nbSeq;
|
||||||
else if (nbSeq < LONGNBSEQ)
|
else if (nbSeq < LONGNBSEQ)
|
||||||
op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
|
op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
|
||||||
else
|
else
|
||||||
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
||||||
if (nbSeq==0) {
|
if (nbSeq==0) {
|
||||||
return op - ostart;
|
return (size_t)(op - ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* seqHead : flags for FSE encoding type */
|
/* seqHead : flags for FSE encoding type */
|
||||||
|
|
@ -205,7 +210,7 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables
|
||||||
}
|
}
|
||||||
|
|
||||||
{ size_t const bitstreamSize = ZSTD_encodeSequences(
|
{ size_t const bitstreamSize = ZSTD_encodeSequences(
|
||||||
op, oend - op,
|
op, (size_t)(oend - op),
|
||||||
fseTables->matchlengthCTable, mlCode,
|
fseTables->matchlengthCTable, mlCode,
|
||||||
fseTables->offcodeCTable, ofCode,
|
fseTables->offcodeCTable, ofCode,
|
||||||
fseTables->litlengthCTable, llCode,
|
fseTables->litlengthCTable, llCode,
|
||||||
|
|
@ -249,7 +254,7 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
*entropyWritten = 1;
|
*entropyWritten = 1;
|
||||||
return op - ostart;
|
return (size_t)(op - ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_compressSubBlock() :
|
/* ZSTD_compressSubBlock() :
|
||||||
|
|
@ -258,7 +263,7 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables
|
||||||
* Or 0 if it failed to compress. */
|
* Or 0 if it failed to compress. */
|
||||||
static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
||||||
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
||||||
const seqDef* sequences, size_t nbSeq,
|
const SeqDef* sequences, size_t nbSeq,
|
||||||
const BYTE* literals, size_t litSize,
|
const BYTE* literals, size_t litSize,
|
||||||
const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
|
const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
|
||||||
const ZSTD_CCtx_params* cctxParams,
|
const ZSTD_CCtx_params* cctxParams,
|
||||||
|
|
@ -275,7 +280,8 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
||||||
litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);
|
litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);
|
||||||
{ size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,
|
{ size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,
|
||||||
&entropyMetadata->hufMetadata, literals, litSize,
|
&entropyMetadata->hufMetadata, literals, litSize,
|
||||||
op, oend-op, bmi2, writeLitEntropy, litEntropyWritten);
|
op, (size_t)(oend-op),
|
||||||
|
bmi2, writeLitEntropy, litEntropyWritten);
|
||||||
FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");
|
FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");
|
||||||
if (cLitSize == 0) return 0;
|
if (cLitSize == 0) return 0;
|
||||||
op += cLitSize;
|
op += cLitSize;
|
||||||
|
|
@ -285,18 +291,18 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
||||||
sequences, nbSeq,
|
sequences, nbSeq,
|
||||||
llCode, mlCode, ofCode,
|
llCode, mlCode, ofCode,
|
||||||
cctxParams,
|
cctxParams,
|
||||||
op, oend-op,
|
op, (size_t)(oend-op),
|
||||||
bmi2, writeSeqEntropy, seqEntropyWritten);
|
bmi2, writeSeqEntropy, seqEntropyWritten);
|
||||||
FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");
|
FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");
|
||||||
if (cSeqSize == 0) return 0;
|
if (cSeqSize == 0) return 0;
|
||||||
op += cSeqSize;
|
op += cSeqSize;
|
||||||
}
|
}
|
||||||
/* Write block header */
|
/* Write block header */
|
||||||
{ size_t cSize = (op-ostart)-ZSTD_blockHeaderSize;
|
{ size_t cSize = (size_t)(op-ostart) - ZSTD_blockHeaderSize;
|
||||||
U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
|
U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
|
||||||
MEM_writeLE24(ostart, cBlockHeader24);
|
MEM_writeLE24(ostart, cBlockHeader24);
|
||||||
}
|
}
|
||||||
return op-ostart;
|
return (size_t)(op-ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,
|
static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,
|
||||||
|
|
@ -322,7 +328,7 @@ static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t lit
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,
|
static size_t ZSTD_estimateSubBlockSize_symbolType(SymbolEncodingType_e type,
|
||||||
const BYTE* codeTable, unsigned maxCode,
|
const BYTE* codeTable, unsigned maxCode,
|
||||||
size_t nbSeq, const FSE_CTable* fseCTable,
|
size_t nbSeq, const FSE_CTable* fseCTable,
|
||||||
const U8* additionalBits,
|
const U8* additionalBits,
|
||||||
|
|
@ -385,7 +391,11 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
|
||||||
return cSeqSizeEstimate + sequencesSectionHeaderSize;
|
return cSeqSizeEstimate + sequencesSectionHeaderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
typedef struct {
|
||||||
|
size_t estLitSize;
|
||||||
|
size_t estBlockSize;
|
||||||
|
} EstimatedBlockSize;
|
||||||
|
static EstimatedBlockSize ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||||
const BYTE* ofCodeTable,
|
const BYTE* ofCodeTable,
|
||||||
const BYTE* llCodeTable,
|
const BYTE* llCodeTable,
|
||||||
const BYTE* mlCodeTable,
|
const BYTE* mlCodeTable,
|
||||||
|
|
@ -393,15 +403,17 @@ static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||||
const ZSTD_entropyCTables_t* entropy,
|
const ZSTD_entropyCTables_t* entropy,
|
||||||
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
||||||
void* workspace, size_t wkspSize,
|
void* workspace, size_t wkspSize,
|
||||||
int writeLitEntropy, int writeSeqEntropy) {
|
int writeLitEntropy, int writeSeqEntropy)
|
||||||
size_t cSizeEstimate = 0;
|
{
|
||||||
cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize,
|
EstimatedBlockSize ebs;
|
||||||
|
ebs.estLitSize = ZSTD_estimateSubBlockSize_literal(literals, litSize,
|
||||||
&entropy->huf, &entropyMetadata->hufMetadata,
|
&entropy->huf, &entropyMetadata->hufMetadata,
|
||||||
workspace, wkspSize, writeLitEntropy);
|
workspace, wkspSize, writeLitEntropy);
|
||||||
cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
|
ebs.estBlockSize = ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
|
||||||
nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
|
nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
|
||||||
workspace, wkspSize, writeSeqEntropy);
|
workspace, wkspSize, writeSeqEntropy);
|
||||||
return cSizeEstimate + ZSTD_blockHeaderSize;
|
ebs.estBlockSize += ebs.estLitSize + ZSTD_blockHeaderSize;
|
||||||
|
return ebs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)
|
static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)
|
||||||
|
|
@ -415,14 +427,57 @@ static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMe
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t countLiterals(SeqStore_t const* seqStore, const SeqDef* sp, size_t seqCount)
|
||||||
|
{
|
||||||
|
size_t n, total = 0;
|
||||||
|
assert(sp != NULL);
|
||||||
|
for (n=0; n<seqCount; n++) {
|
||||||
|
total += ZSTD_getSequenceLength(seqStore, sp+n).litLength;
|
||||||
|
}
|
||||||
|
DEBUGLOG(6, "countLiterals for %zu sequences from %p => %zu bytes", seqCount, (const void*)sp, total);
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BYTESCALE 256
|
||||||
|
|
||||||
|
static size_t sizeBlockSequences(const SeqDef* sp, size_t nbSeqs,
|
||||||
|
size_t targetBudget, size_t avgLitCost, size_t avgSeqCost,
|
||||||
|
int firstSubBlock)
|
||||||
|
{
|
||||||
|
size_t n, budget = 0, inSize=0;
|
||||||
|
/* entropy headers */
|
||||||
|
size_t const headerSize = (size_t)firstSubBlock * 120 * BYTESCALE; /* generous estimate */
|
||||||
|
assert(firstSubBlock==0 || firstSubBlock==1);
|
||||||
|
budget += headerSize;
|
||||||
|
|
||||||
|
/* first sequence => at least one sequence*/
|
||||||
|
budget += sp[0].litLength * avgLitCost + avgSeqCost;
|
||||||
|
if (budget > targetBudget) return 1;
|
||||||
|
inSize = sp[0].litLength + (sp[0].mlBase+MINMATCH);
|
||||||
|
|
||||||
|
/* loop over sequences */
|
||||||
|
for (n=1; n<nbSeqs; n++) {
|
||||||
|
size_t currentCost = sp[n].litLength * avgLitCost + avgSeqCost;
|
||||||
|
budget += currentCost;
|
||||||
|
inSize += sp[n].litLength + (sp[n].mlBase+MINMATCH);
|
||||||
|
/* stop when sub-block budget is reached */
|
||||||
|
if ( (budget > targetBudget)
|
||||||
|
/* though continue to expand until the sub-block is deemed compressible */
|
||||||
|
&& (budget < inSize * BYTESCALE) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
/* ZSTD_compressSubBlock_multi() :
|
/* ZSTD_compressSubBlock_multi() :
|
||||||
* Breaks super-block into multiple sub-blocks and compresses them.
|
* Breaks super-block into multiple sub-blocks and compresses them.
|
||||||
* Entropy will be written to the first block.
|
* Entropy will be written into the first block.
|
||||||
* The following blocks will use repeat mode to compress.
|
* The following blocks use repeat_mode to compress.
|
||||||
* All sub-blocks are compressed blocks (no raw or rle blocks).
|
* Sub-blocks are all compressed, except the last one when beneficial.
|
||||||
* @return : compressed size of the super block (which is multiple ZSTD blocks)
|
* @return : compressed size of the super block (which features multiple ZSTD blocks)
|
||||||
* Or 0 if it failed to compress. */
|
* or 0 if it failed to compress. */
|
||||||
static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
static size_t ZSTD_compressSubBlock_multi(const SeqStore_t* seqStorePtr,
|
||||||
const ZSTD_compressedBlockState_t* prevCBlock,
|
const ZSTD_compressedBlockState_t* prevCBlock,
|
||||||
ZSTD_compressedBlockState_t* nextCBlock,
|
ZSTD_compressedBlockState_t* nextCBlock,
|
||||||
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
||||||
|
|
@ -432,12 +487,14 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||||
const int bmi2, U32 lastBlock,
|
const int bmi2, U32 lastBlock,
|
||||||
void* workspace, size_t wkspSize)
|
void* workspace, size_t wkspSize)
|
||||||
{
|
{
|
||||||
const seqDef* const sstart = seqStorePtr->sequencesStart;
|
const SeqDef* const sstart = seqStorePtr->sequencesStart;
|
||||||
const seqDef* const send = seqStorePtr->sequences;
|
const SeqDef* const send = seqStorePtr->sequences;
|
||||||
const seqDef* sp = sstart;
|
const SeqDef* sp = sstart; /* tracks progresses within seqStorePtr->sequences */
|
||||||
|
size_t const nbSeqs = (size_t)(send - sstart);
|
||||||
const BYTE* const lstart = seqStorePtr->litStart;
|
const BYTE* const lstart = seqStorePtr->litStart;
|
||||||
const BYTE* const lend = seqStorePtr->lit;
|
const BYTE* const lend = seqStorePtr->lit;
|
||||||
const BYTE* lp = lstart;
|
const BYTE* lp = lstart;
|
||||||
|
size_t const nbLiterals = (size_t)(lend - lstart);
|
||||||
BYTE const* ip = (BYTE const*)src;
|
BYTE const* ip = (BYTE const*)src;
|
||||||
BYTE const* const iend = ip + srcSize;
|
BYTE const* const iend = ip + srcSize;
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
|
|
@ -446,66 +503,73 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||||
const BYTE* llCodePtr = seqStorePtr->llCode;
|
const BYTE* llCodePtr = seqStorePtr->llCode;
|
||||||
const BYTE* mlCodePtr = seqStorePtr->mlCode;
|
const BYTE* mlCodePtr = seqStorePtr->mlCode;
|
||||||
const BYTE* ofCodePtr = seqStorePtr->ofCode;
|
const BYTE* ofCodePtr = seqStorePtr->ofCode;
|
||||||
size_t targetCBlockSize = cctxParams->targetCBlockSize;
|
size_t const minTarget = ZSTD_TARGETCBLOCKSIZE_MIN; /* enforce minimum size, to reduce undesirable side effects */
|
||||||
size_t litSize, seqCount;
|
size_t const targetCBlockSize = MAX(minTarget, cctxParams->targetCBlockSize);
|
||||||
int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed;
|
int writeLitEntropy = (entropyMetadata->hufMetadata.hType == set_compressed);
|
||||||
int writeSeqEntropy = 1;
|
int writeSeqEntropy = 1;
|
||||||
int lastSequence = 0;
|
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)",
|
DEBUGLOG(5, "ZSTD_compressSubBlock_multi (srcSize=%u, litSize=%u, nbSeq=%u)",
|
||||||
(unsigned)(lend-lp), (unsigned)(send-sstart));
|
(unsigned)srcSize, (unsigned)(lend-lstart), (unsigned)(send-sstart));
|
||||||
|
|
||||||
litSize = 0;
|
/* let's start by a general estimation for the full block */
|
||||||
seqCount = 0;
|
if (nbSeqs > 0) {
|
||||||
do {
|
EstimatedBlockSize const ebs =
|
||||||
size_t cBlockSizeEstimate = 0;
|
ZSTD_estimateSubBlockSize(lp, nbLiterals,
|
||||||
if (sstart == send) {
|
ofCodePtr, llCodePtr, mlCodePtr, nbSeqs,
|
||||||
lastSequence = 1;
|
|
||||||
} else {
|
|
||||||
const seqDef* const sequence = sp + seqCount;
|
|
||||||
lastSequence = sequence == send - 1;
|
|
||||||
litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength;
|
|
||||||
seqCount++;
|
|
||||||
}
|
|
||||||
if (lastSequence) {
|
|
||||||
assert(lp <= lend);
|
|
||||||
assert(litSize <= (size_t)(lend - lp));
|
|
||||||
litSize = (size_t)(lend - lp);
|
|
||||||
}
|
|
||||||
/* I think there is an optimization opportunity here.
|
|
||||||
* Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful
|
|
||||||
* since it recalculates estimate from scratch.
|
|
||||||
* For example, it would recount literal distribution and symbol codes every time.
|
|
||||||
*/
|
|
||||||
cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount,
|
|
||||||
&nextCBlock->entropy, entropyMetadata,
|
&nextCBlock->entropy, entropyMetadata,
|
||||||
workspace, wkspSize, writeLitEntropy, writeSeqEntropy);
|
workspace, wkspSize,
|
||||||
if (cBlockSizeEstimate > targetCBlockSize || lastSequence) {
|
writeLitEntropy, writeSeqEntropy);
|
||||||
int litEntropyWritten = 0;
|
/* quick estimation */
|
||||||
|
size_t const avgLitCost = nbLiterals ? (ebs.estLitSize * BYTESCALE) / nbLiterals : BYTESCALE;
|
||||||
|
size_t const avgSeqCost = ((ebs.estBlockSize - ebs.estLitSize) * BYTESCALE) / nbSeqs;
|
||||||
|
const size_t nbSubBlocks = MAX((ebs.estBlockSize + (targetCBlockSize/2)) / targetCBlockSize, 1);
|
||||||
|
size_t n, avgBlockBudget, blockBudgetSupp=0;
|
||||||
|
avgBlockBudget = (ebs.estBlockSize * BYTESCALE) / nbSubBlocks;
|
||||||
|
DEBUGLOG(5, "estimated fullblock size=%u bytes ; avgLitCost=%.2f ; avgSeqCost=%.2f ; targetCBlockSize=%u, nbSubBlocks=%u ; avgBlockBudget=%.0f bytes",
|
||||||
|
(unsigned)ebs.estBlockSize, (double)avgLitCost/BYTESCALE, (double)avgSeqCost/BYTESCALE,
|
||||||
|
(unsigned)targetCBlockSize, (unsigned)nbSubBlocks, (double)avgBlockBudget/BYTESCALE);
|
||||||
|
/* simplification: if estimates states that the full superblock doesn't compress, just bail out immediately
|
||||||
|
* this will result in the production of a single uncompressed block covering @srcSize.*/
|
||||||
|
if (ebs.estBlockSize > srcSize) return 0;
|
||||||
|
|
||||||
|
/* compress and write sub-blocks */
|
||||||
|
assert(nbSubBlocks>0);
|
||||||
|
for (n=0; n < nbSubBlocks-1; n++) {
|
||||||
|
/* determine nb of sequences for current sub-block + nbLiterals from next sequence */
|
||||||
|
size_t const seqCount = sizeBlockSequences(sp, (size_t)(send-sp),
|
||||||
|
avgBlockBudget + blockBudgetSupp, avgLitCost, avgSeqCost, n==0);
|
||||||
|
/* if reached last sequence : break to last sub-block (simplification) */
|
||||||
|
assert(seqCount <= (size_t)(send-sp));
|
||||||
|
if (sp + seqCount == send) break;
|
||||||
|
assert(seqCount > 0);
|
||||||
|
/* compress sub-block */
|
||||||
|
{ int litEntropyWritten = 0;
|
||||||
int seqEntropyWritten = 0;
|
int seqEntropyWritten = 0;
|
||||||
const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence);
|
size_t litSize = countLiterals(seqStorePtr, sp, seqCount);
|
||||||
const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
const size_t decompressedSize =
|
||||||
|
ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 0);
|
||||||
|
size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||||
sp, seqCount,
|
sp, seqCount,
|
||||||
lp, litSize,
|
lp, litSize,
|
||||||
llCodePtr, mlCodePtr, ofCodePtr,
|
llCodePtr, mlCodePtr, ofCodePtr,
|
||||||
cctxParams,
|
cctxParams,
|
||||||
op, oend-op,
|
op, (size_t)(oend-op),
|
||||||
bmi2, writeLitEntropy, writeSeqEntropy,
|
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||||
&litEntropyWritten, &seqEntropyWritten,
|
&litEntropyWritten, &seqEntropyWritten,
|
||||||
lastBlock && lastSequence);
|
0);
|
||||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||||
|
|
||||||
|
/* check compressibility, update state components */
|
||||||
if (cSize > 0 && cSize < decompressedSize) {
|
if (cSize > 0 && cSize < decompressedSize) {
|
||||||
DEBUGLOG(5, "Committed the sub-block");
|
DEBUGLOG(5, "Committed sub-block compressing %u bytes => %u bytes",
|
||||||
|
(unsigned)decompressedSize, (unsigned)cSize);
|
||||||
assert(ip + decompressedSize <= iend);
|
assert(ip + decompressedSize <= iend);
|
||||||
ip += decompressedSize;
|
ip += decompressedSize;
|
||||||
sp += seqCount;
|
|
||||||
lp += litSize;
|
lp += litSize;
|
||||||
op += cSize;
|
op += cSize;
|
||||||
llCodePtr += seqCount;
|
llCodePtr += seqCount;
|
||||||
mlCodePtr += seqCount;
|
mlCodePtr += seqCount;
|
||||||
ofCodePtr += seqCount;
|
ofCodePtr += seqCount;
|
||||||
litSize = 0;
|
|
||||||
seqCount = 0;
|
|
||||||
/* Entropy only needs to be written once */
|
/* Entropy only needs to be written once */
|
||||||
if (litEntropyWritten) {
|
if (litEntropyWritten) {
|
||||||
writeLitEntropy = 0;
|
writeLitEntropy = 0;
|
||||||
|
|
@ -513,45 +577,97 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||||
if (seqEntropyWritten) {
|
if (seqEntropyWritten) {
|
||||||
writeSeqEntropy = 0;
|
writeSeqEntropy = 0;
|
||||||
}
|
}
|
||||||
|
sp += seqCount;
|
||||||
|
blockBudgetSupp = 0;
|
||||||
|
} }
|
||||||
|
/* otherwise : do not compress yet, coalesce current sub-block with following one */
|
||||||
|
}
|
||||||
|
} /* if (nbSeqs > 0) */
|
||||||
|
|
||||||
|
/* write last block */
|
||||||
|
DEBUGLOG(5, "Generate last sub-block: %u sequences remaining", (unsigned)(send - sp));
|
||||||
|
{ int litEntropyWritten = 0;
|
||||||
|
int seqEntropyWritten = 0;
|
||||||
|
size_t litSize = (size_t)(lend - lp);
|
||||||
|
size_t seqCount = (size_t)(send - sp);
|
||||||
|
const size_t decompressedSize =
|
||||||
|
ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 1);
|
||||||
|
size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||||
|
sp, seqCount,
|
||||||
|
lp, litSize,
|
||||||
|
llCodePtr, mlCodePtr, ofCodePtr,
|
||||||
|
cctxParams,
|
||||||
|
op, (size_t)(oend-op),
|
||||||
|
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||||
|
&litEntropyWritten, &seqEntropyWritten,
|
||||||
|
lastBlock);
|
||||||
|
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||||
|
|
||||||
|
/* update pointers, the nb of literals borrowed from next sequence must be preserved */
|
||||||
|
if (cSize > 0 && cSize < decompressedSize) {
|
||||||
|
DEBUGLOG(5, "Last sub-block compressed %u bytes => %u bytes",
|
||||||
|
(unsigned)decompressedSize, (unsigned)cSize);
|
||||||
|
assert(ip + decompressedSize <= iend);
|
||||||
|
ip += decompressedSize;
|
||||||
|
lp += litSize;
|
||||||
|
op += cSize;
|
||||||
|
llCodePtr += seqCount;
|
||||||
|
mlCodePtr += seqCount;
|
||||||
|
ofCodePtr += seqCount;
|
||||||
|
/* Entropy only needs to be written once */
|
||||||
|
if (litEntropyWritten) {
|
||||||
|
writeLitEntropy = 0;
|
||||||
|
}
|
||||||
|
if (seqEntropyWritten) {
|
||||||
|
writeSeqEntropy = 0;
|
||||||
|
}
|
||||||
|
sp += seqCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (!lastSequence);
|
|
||||||
|
|
||||||
if (writeLitEntropy) {
|
if (writeLitEntropy) {
|
||||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");
|
DEBUGLOG(5, "Literal entropy tables were never written");
|
||||||
ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
|
ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
|
||||||
}
|
}
|
||||||
if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
|
if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
|
||||||
/* If we haven't written our entropy tables, then we've violated our contract and
|
/* If we haven't written our entropy tables, then we've violated our contract and
|
||||||
* must emit an uncompressed block.
|
* must emit an uncompressed block.
|
||||||
*/
|
*/
|
||||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten");
|
DEBUGLOG(5, "Sequence entropy tables were never written => cancel, emit an uncompressed block");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip < iend) {
|
if (ip < iend) {
|
||||||
size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock);
|
/* some data left : last part of the block sent uncompressed */
|
||||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip));
|
size_t const rSize = (size_t)((iend - ip));
|
||||||
|
size_t const cSize = ZSTD_noCompressBlock(op, (size_t)(oend - op), ip, rSize, lastBlock);
|
||||||
|
DEBUGLOG(5, "Generate last uncompressed sub-block of %u bytes", (unsigned)(rSize));
|
||||||
FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
|
FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
|
||||||
assert(cSize != 0);
|
assert(cSize != 0);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
/* We have to regenerate the repcodes because we've skipped some sequences */
|
/* We have to regenerate the repcodes because we've skipped some sequences */
|
||||||
if (sp < send) {
|
if (sp < send) {
|
||||||
seqDef const* seq;
|
const SeqDef* seq;
|
||||||
repcodes_t rep;
|
Repcodes_t rep;
|
||||||
ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));
|
ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));
|
||||||
for (seq = sstart; seq < sp; ++seq) {
|
for (seq = sstart; seq < sp; ++seq) {
|
||||||
ZSTD_updateRep(rep.rep, seq->offBase - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);
|
ZSTD_updateRep(rep.rep, seq->offBase, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);
|
||||||
}
|
}
|
||||||
ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep));
|
ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");
|
|
||||||
return op-ostart;
|
DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed all subBlocks: total compressed size = %u",
|
||||||
|
(unsigned)(op-ostart));
|
||||||
|
return (size_t)(op-ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
|
size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
void const* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned lastBlock) {
|
unsigned lastBlock)
|
||||||
|
{
|
||||||
ZSTD_entropyCTablesMetadata_t entropyMetadata;
|
ZSTD_entropyCTablesMetadata_t entropyMetadata;
|
||||||
|
|
||||||
FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,
|
FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,
|
||||||
|
|
@ -559,7 +675,7 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
|
||||||
&zc->blockState.nextCBlock->entropy,
|
&zc->blockState.nextCBlock->entropy,
|
||||||
&zc->appliedParams,
|
&zc->appliedParams,
|
||||||
&entropyMetadata,
|
&entropyMetadata,
|
||||||
zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
|
zc->tmpWorkspace, zc->tmpWkspSize /* statically allocated in resetCCtx */), "");
|
||||||
|
|
||||||
return ZSTD_compressSubBlock_multi(&zc->seqStore,
|
return ZSTD_compressSubBlock_multi(&zc->seqStore,
|
||||||
zc->blockState.prevCBlock,
|
zc->blockState.prevCBlock,
|
||||||
|
|
@ -569,5 +685,5 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
|
||||||
dst, dstCapacity,
|
dst, dstCapacity,
|
||||||
src, srcSize,
|
src, srcSize,
|
||||||
zc->bmi2, lastBlock,
|
zc->bmi2, lastBlock,
|
||||||
zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */);
|
zc->tmpWorkspace, zc->tmpWkspSize /* statically allocated in resetCCtx */);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -14,8 +15,10 @@
|
||||||
/*-*************************************
|
/*-*************************************
|
||||||
* Dependencies
|
* Dependencies
|
||||||
***************************************/
|
***************************************/
|
||||||
|
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */
|
||||||
#include "../common/zstd_internal.h"
|
#include "../common/zstd_internal.h"
|
||||||
|
#include "../common/portability_macros.h"
|
||||||
|
#include "../common/compiler.h" /* ZS2_isPower2 */
|
||||||
|
|
||||||
/*-*************************************
|
/*-*************************************
|
||||||
* Constants
|
* Constants
|
||||||
|
|
@ -41,8 +44,9 @@
|
||||||
***************************************/
|
***************************************/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ZSTD_cwksp_alloc_objects,
|
ZSTD_cwksp_alloc_objects,
|
||||||
ZSTD_cwksp_alloc_buffers,
|
ZSTD_cwksp_alloc_aligned_init_once,
|
||||||
ZSTD_cwksp_alloc_aligned
|
ZSTD_cwksp_alloc_aligned,
|
||||||
|
ZSTD_cwksp_alloc_buffers
|
||||||
} ZSTD_cwksp_alloc_phase_e;
|
} ZSTD_cwksp_alloc_phase_e;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -96,7 +100,7 @@ typedef enum {
|
||||||
* Workspace Layout:
|
* Workspace Layout:
|
||||||
*
|
*
|
||||||
* [ ... workspace ... ]
|
* [ ... workspace ... ]
|
||||||
* [objects][tables ... ->] free space [<- ... aligned][<- ... buffers]
|
* [objects][tables ->] free space [<- buffers][<- aligned][<- init once]
|
||||||
*
|
*
|
||||||
* The various objects that live in the workspace are divided into the
|
* The various objects that live in the workspace are divided into the
|
||||||
* following categories, and are allocated separately:
|
* following categories, and are allocated separately:
|
||||||
|
|
@ -120,9 +124,18 @@ typedef enum {
|
||||||
* uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
|
* uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
|
||||||
* Their sizes depend on the cparams. These tables are 64-byte aligned.
|
* Their sizes depend on the cparams. These tables are 64-byte aligned.
|
||||||
*
|
*
|
||||||
* - Aligned: these buffers are used for various purposes that require 4 byte
|
* - Init once: these buffers require to be initialized at least once before
|
||||||
* alignment, but don't require any initialization before they're used. These
|
* use. They should be used when we want to skip memory initialization
|
||||||
* buffers are each aligned to 64 bytes.
|
* while not triggering memory checkers (like Valgrind) when reading from
|
||||||
|
* from this memory without writing to it first.
|
||||||
|
* These buffers should be used carefully as they might contain data
|
||||||
|
* from previous compressions.
|
||||||
|
* Buffers are aligned to 64 bytes.
|
||||||
|
*
|
||||||
|
* - Aligned: these buffers don't require any initialization before they're
|
||||||
|
* used. The user of the buffer should make sure they write into a buffer
|
||||||
|
* location before reading from it.
|
||||||
|
* Buffers are aligned to 64 bytes.
|
||||||
*
|
*
|
||||||
* - Buffers: these buffers are used for various purposes that don't require
|
* - Buffers: these buffers are used for various purposes that don't require
|
||||||
* any alignment or initialization before they're used. This means they can
|
* any alignment or initialization before they're used. This means they can
|
||||||
|
|
@ -134,8 +147,9 @@ typedef enum {
|
||||||
* correctly packed into the workspace buffer. That order is:
|
* correctly packed into the workspace buffer. That order is:
|
||||||
*
|
*
|
||||||
* 1. Objects
|
* 1. Objects
|
||||||
* 2. Buffers
|
* 2. Init once / Tables
|
||||||
* 3. Aligned/Tables
|
* 3. Aligned / Tables
|
||||||
|
* 4. Buffers / Tables
|
||||||
*
|
*
|
||||||
* Attempts to reserve objects of different types out of order will fail.
|
* Attempts to reserve objects of different types out of order will fail.
|
||||||
*/
|
*/
|
||||||
|
|
@ -147,6 +161,7 @@ typedef struct {
|
||||||
void* tableEnd;
|
void* tableEnd;
|
||||||
void* tableValidEnd;
|
void* tableValidEnd;
|
||||||
void* allocStart;
|
void* allocStart;
|
||||||
|
void* initOnceStart;
|
||||||
|
|
||||||
BYTE allocFailed;
|
BYTE allocFailed;
|
||||||
int workspaceOversizedDuration;
|
int workspaceOversizedDuration;
|
||||||
|
|
@ -159,6 +174,7 @@ typedef struct {
|
||||||
***************************************/
|
***************************************/
|
||||||
|
|
||||||
MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws);
|
MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws);
|
||||||
|
MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws);
|
||||||
|
|
||||||
MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
|
MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
|
||||||
(void)ws;
|
(void)ws;
|
||||||
|
|
@ -168,14 +184,16 @@ MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
|
||||||
assert(ws->tableEnd <= ws->allocStart);
|
assert(ws->tableEnd <= ws->allocStart);
|
||||||
assert(ws->tableValidEnd <= ws->allocStart);
|
assert(ws->tableValidEnd <= ws->allocStart);
|
||||||
assert(ws->allocStart <= ws->workspaceEnd);
|
assert(ws->allocStart <= ws->workspaceEnd);
|
||||||
|
assert(ws->initOnceStart <= ZSTD_cwksp_initialAllocStart(ws));
|
||||||
|
assert(ws->workspace <= ws->initOnceStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Align must be a power of 2.
|
* Align must be a power of 2.
|
||||||
*/
|
*/
|
||||||
MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
|
MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t align) {
|
||||||
size_t const mask = align - 1;
|
size_t const mask = align - 1;
|
||||||
assert((align & mask) == 0);
|
assert(ZSTD_isPower2(align));
|
||||||
return (size + mask) & ~mask;
|
return (size + mask) & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +207,7 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
|
||||||
* to figure out how much space you need for the matchState tables. Everything
|
* to figure out how much space you need for the matchState tables. Everything
|
||||||
* else is though.
|
* else is though.
|
||||||
*
|
*
|
||||||
* Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size().
|
* Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned64_alloc_size().
|
||||||
*/
|
*/
|
||||||
MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
|
MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
|
|
@ -197,12 +215,16 @@ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size, size_t alignment) {
|
||||||
|
return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, alignment));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes.
|
* Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes.
|
||||||
* Used to determine the number of bytes required for a given "aligned".
|
* Used to determine the number of bytes required for a given "aligned".
|
||||||
*/
|
*/
|
||||||
MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
|
MEM_STATIC size_t ZSTD_cwksp_aligned64_alloc_size(size_t size) {
|
||||||
return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES));
|
return ZSTD_cwksp_aligned_alloc_size(size, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -210,14 +232,10 @@ MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
|
||||||
* for internal purposes (currently only alignment).
|
* for internal purposes (currently only alignment).
|
||||||
*/
|
*/
|
||||||
MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
|
MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
|
||||||
/* For alignment, the wksp will always allocate an additional n_1=[1, 64] bytes
|
/* For alignment, the wksp will always allocate an additional 2*ZSTD_CWKSP_ALIGNMENT_BYTES
|
||||||
* to align the beginning of tables section, as well as another n_2=[0, 63] bytes
|
* bytes to align the beginning of tables section and end of buffers;
|
||||||
* to align the beginning of the aligned section.
|
|
||||||
*
|
|
||||||
* n_1 + n_2 == 64 bytes if the cwksp is freshly allocated, due to tables and
|
|
||||||
* aligneds being sized in multiples of 64 bytes.
|
|
||||||
*/
|
*/
|
||||||
size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES;
|
size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2;
|
||||||
return slackSpace;
|
return slackSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,11 +247,23 @@ MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
|
||||||
MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) {
|
MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) {
|
||||||
size_t const alignBytesMask = alignBytes - 1;
|
size_t const alignBytesMask = alignBytes - 1;
|
||||||
size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
|
size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
|
||||||
assert((alignBytes & alignBytesMask) == 0);
|
assert(ZSTD_isPower2(alignBytes));
|
||||||
assert(bytes != ZSTD_CWKSP_ALIGNMENT_BYTES);
|
assert(bytes < alignBytes);
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the initial value for allocStart which is used to determine the position from
|
||||||
|
* which we can allocate from the end of the workspace.
|
||||||
|
*/
|
||||||
|
MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws)
|
||||||
|
{
|
||||||
|
char* endPtr = (char*)ws->workspaceEnd;
|
||||||
|
assert(ZSTD_isPower2(ZSTD_CWKSP_ALIGNMENT_BYTES));
|
||||||
|
endPtr = endPtr - ((size_t)endPtr % ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||||
|
return (void*)endPtr;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal function. Do not use directly.
|
* Internal function. Do not use directly.
|
||||||
* Reserves the given number of bytes within the aligned/buffer segment of the wksp,
|
* Reserves the given number of bytes within the aligned/buffer segment of the wksp,
|
||||||
|
|
@ -246,7 +276,7 @@ ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes)
|
||||||
{
|
{
|
||||||
void* const alloc = (BYTE*)ws->allocStart - bytes;
|
void* const alloc = (BYTE*)ws->allocStart - bytes;
|
||||||
void* const bottom = ws->tableEnd;
|
void* const bottom = ws->tableEnd;
|
||||||
DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
|
DEBUGLOG(5, "cwksp: reserving [0x%p]:%zd bytes; %zd bytes remaining",
|
||||||
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
||||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||||
assert(alloc >= bottom);
|
assert(alloc >= bottom);
|
||||||
|
|
@ -274,27 +304,16 @@ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase
|
||||||
{
|
{
|
||||||
assert(phase >= ws->phase);
|
assert(phase >= ws->phase);
|
||||||
if (phase > ws->phase) {
|
if (phase > ws->phase) {
|
||||||
/* Going from allocating objects to allocating buffers */
|
/* Going from allocating objects to allocating initOnce / tables */
|
||||||
if (ws->phase < ZSTD_cwksp_alloc_buffers &&
|
if (ws->phase < ZSTD_cwksp_alloc_aligned_init_once &&
|
||||||
phase >= ZSTD_cwksp_alloc_buffers) {
|
phase >= ZSTD_cwksp_alloc_aligned_init_once) {
|
||||||
ws->tableValidEnd = ws->objectEnd;
|
ws->tableValidEnd = ws->objectEnd;
|
||||||
}
|
ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
|
||||||
|
|
||||||
/* Going from allocating buffers to allocating aligneds/tables */
|
|
||||||
if (ws->phase < ZSTD_cwksp_alloc_aligned &&
|
|
||||||
phase >= ZSTD_cwksp_alloc_aligned) {
|
|
||||||
{ /* Align the start of the "aligned" to 64 bytes. Use [1, 64] bytes. */
|
|
||||||
size_t const bytesToAlign =
|
|
||||||
ZSTD_CWKSP_ALIGNMENT_BYTES - ZSTD_cwksp_bytes_to_align_ptr(ws->allocStart, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
|
||||||
DEBUGLOG(5, "reserving aligned alignment addtl space: %zu", bytesToAlign);
|
|
||||||
ZSTD_STATIC_ASSERT((ZSTD_CWKSP_ALIGNMENT_BYTES & (ZSTD_CWKSP_ALIGNMENT_BYTES - 1)) == 0); /* power of 2 */
|
|
||||||
RETURN_ERROR_IF(!ZSTD_cwksp_reserve_internal_buffer_space(ws, bytesToAlign),
|
|
||||||
memory_allocation, "aligned phase - alignment initial allocation failed!");
|
|
||||||
}
|
|
||||||
{ /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
|
{ /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
|
||||||
void* const alloc = ws->objectEnd;
|
void *const alloc = ws->objectEnd;
|
||||||
size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||||
void* const objectEnd = (BYTE*)alloc + bytesToAlign;
|
void *const objectEnd = (BYTE *) alloc + bytesToAlign;
|
||||||
DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
|
DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
|
||||||
RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation,
|
RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation,
|
||||||
"table phase - alignment initial allocation failed!");
|
"table phase - alignment initial allocation failed!");
|
||||||
|
|
@ -302,7 +321,9 @@ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase
|
||||||
ws->tableEnd = objectEnd; /* table area starts being empty */
|
ws->tableEnd = objectEnd; /* table area starts being empty */
|
||||||
if (ws->tableValidEnd < ws->tableEnd) {
|
if (ws->tableValidEnd < ws->tableEnd) {
|
||||||
ws->tableValidEnd = ws->tableEnd;
|
ws->tableValidEnd = ws->tableEnd;
|
||||||
} } }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ws->phase = phase;
|
ws->phase = phase;
|
||||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +335,7 @@ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase
|
||||||
*/
|
*/
|
||||||
MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr)
|
MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr)
|
||||||
{
|
{
|
||||||
return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd);
|
return (ptr != NULL) && (ws->workspace <= ptr) && (ptr < ws->workspaceEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -345,30 +366,62 @@ MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
|
* Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
|
||||||
|
* This memory has been initialized at least once in the past.
|
||||||
|
* This doesn't mean it has been initialized this time, and it might contain data from previous
|
||||||
|
* operations.
|
||||||
|
* The main usage is for algorithms that might need read access into uninitialized memory.
|
||||||
|
* The algorithm must maintain safety under these conditions and must make sure it doesn't
|
||||||
|
* leak any of the past data (directly or in side channels).
|
||||||
*/
|
*/
|
||||||
MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes)
|
MEM_STATIC void* ZSTD_cwksp_reserve_aligned_init_once(ZSTD_cwksp* ws, size_t bytes)
|
||||||
{
|
{
|
||||||
void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES),
|
size_t const alignedBytes = ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
||||||
|
void* ptr = ZSTD_cwksp_reserve_internal(ws, alignedBytes, ZSTD_cwksp_alloc_aligned_init_once);
|
||||||
|
assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
|
||||||
|
if(ptr && ptr < ws->initOnceStart) {
|
||||||
|
/* We assume the memory following the current allocation is either:
|
||||||
|
* 1. Not usable as initOnce memory (end of workspace)
|
||||||
|
* 2. Another initOnce buffer that has been allocated before (and so was previously memset)
|
||||||
|
* 3. An ASAN redzone, in which case we don't want to write on it
|
||||||
|
* For these reasons it should be fine to not explicitly zero every byte up to ws->initOnceStart.
|
||||||
|
* Note that we assume here that MSAN and ASAN cannot run in the same time. */
|
||||||
|
ZSTD_memset(ptr, 0, MIN((size_t)((U8*)ws->initOnceStart - (U8*)ptr), alignedBytes));
|
||||||
|
ws->initOnceStart = ptr;
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
|
||||||
|
*/
|
||||||
|
MEM_STATIC void* ZSTD_cwksp_reserve_aligned64(ZSTD_cwksp* ws, size_t bytes)
|
||||||
|
{
|
||||||
|
void* const ptr = ZSTD_cwksp_reserve_internal(ws,
|
||||||
|
ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES),
|
||||||
ZSTD_cwksp_alloc_aligned);
|
ZSTD_cwksp_alloc_aligned);
|
||||||
assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
|
assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Aligned on 64 bytes. These buffers have the special property that
|
* Aligned on 64 bytes. These buffers have the special property that
|
||||||
* their values remain constrained, allowing us to re-use them without
|
* their values remain constrained, allowing us to reuse them without
|
||||||
* memset()-ing them.
|
* memset()-ing them.
|
||||||
*/
|
*/
|
||||||
MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes)
|
MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes)
|
||||||
{
|
{
|
||||||
const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
|
const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned_init_once;
|
||||||
void* alloc;
|
void* alloc;
|
||||||
void* end;
|
void* end;
|
||||||
void* top;
|
void* top;
|
||||||
|
|
||||||
|
/* We can only start allocating tables after we are done reserving space for objects at the
|
||||||
|
* start of the workspace */
|
||||||
|
if(ws->phase < phase) {
|
||||||
if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
|
if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
alloc = ws->tableEnd;
|
alloc = ws->tableEnd;
|
||||||
end = (BYTE *)alloc + bytes;
|
end = (BYTE *)alloc + bytes;
|
||||||
top = ws->allocStart;
|
top = ws->allocStart;
|
||||||
|
|
@ -387,7 +440,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes)
|
||||||
|
|
||||||
|
|
||||||
assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
|
assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
|
||||||
assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
|
assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,6 +474,20 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes)
|
||||||
|
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* with alignment control
|
||||||
|
* Note : should happen only once, at workspace first initialization
|
||||||
|
*/
|
||||||
|
MEM_STATIC void* ZSTD_cwksp_reserve_object_aligned(ZSTD_cwksp* ws, size_t byteSize, size_t alignment)
|
||||||
|
{
|
||||||
|
size_t const mask = alignment - 1;
|
||||||
|
size_t const surplus = (alignment > sizeof(void*)) ? alignment - sizeof(void*) : 0;
|
||||||
|
void* const start = ZSTD_cwksp_reserve_object(ws, byteSize + surplus);
|
||||||
|
if (start == NULL) return NULL;
|
||||||
|
if (surplus == 0) return start;
|
||||||
|
assert(ZSTD_isPower2(alignment));
|
||||||
|
return (void*)(((size_t)start + surplus) & ~mask);
|
||||||
|
}
|
||||||
|
|
||||||
MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws)
|
MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws)
|
||||||
{
|
{
|
||||||
|
|
@ -451,7 +518,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
|
||||||
assert(ws->tableValidEnd >= ws->objectEnd);
|
assert(ws->tableValidEnd >= ws->objectEnd);
|
||||||
assert(ws->tableValidEnd <= ws->allocStart);
|
assert(ws->tableValidEnd <= ws->allocStart);
|
||||||
if (ws->tableValidEnd < ws->tableEnd) {
|
if (ws->tableValidEnd < ws->tableEnd) {
|
||||||
ZSTD_memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd);
|
ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd));
|
||||||
}
|
}
|
||||||
ZSTD_cwksp_mark_tables_clean(ws);
|
ZSTD_cwksp_mark_tables_clean(ws);
|
||||||
}
|
}
|
||||||
|
|
@ -460,7 +527,8 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
|
||||||
* Invalidates table allocations.
|
* Invalidates table allocations.
|
||||||
* All other allocations remain valid.
|
* All other allocations remain valid.
|
||||||
*/
|
*/
|
||||||
MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) {
|
MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws)
|
||||||
|
{
|
||||||
DEBUGLOG(4, "cwksp: clearing tables!");
|
DEBUGLOG(4, "cwksp: clearing tables!");
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -478,14 +546,23 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
|
||||||
|
|
||||||
|
|
||||||
ws->tableEnd = ws->objectEnd;
|
ws->tableEnd = ws->objectEnd;
|
||||||
ws->allocStart = ws->workspaceEnd;
|
ws->allocStart = ZSTD_cwksp_initialAllocStart(ws);
|
||||||
ws->allocFailed = 0;
|
ws->allocFailed = 0;
|
||||||
if (ws->phase > ZSTD_cwksp_alloc_buffers) {
|
if (ws->phase > ZSTD_cwksp_alloc_aligned_init_once) {
|
||||||
ws->phase = ZSTD_cwksp_alloc_buffers;
|
ws->phase = ZSTD_cwksp_alloc_aligned_init_once;
|
||||||
}
|
}
|
||||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
|
||||||
|
return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
|
||||||
|
return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
|
||||||
|
+ (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The provided workspace takes ownership of the buffer [start, start+size).
|
* The provided workspace takes ownership of the buffer [start, start+size).
|
||||||
* Any existing values in the workspace are ignored (the previously managed
|
* Any existing values in the workspace are ignored (the previously managed
|
||||||
|
|
@ -498,6 +575,7 @@ MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_c
|
||||||
ws->workspaceEnd = (BYTE*)start + size;
|
ws->workspaceEnd = (BYTE*)start + size;
|
||||||
ws->objectEnd = ws->workspace;
|
ws->objectEnd = ws->workspace;
|
||||||
ws->tableValidEnd = ws->objectEnd;
|
ws->tableValidEnd = ws->objectEnd;
|
||||||
|
ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
|
||||||
ws->phase = ZSTD_cwksp_alloc_objects;
|
ws->phase = ZSTD_cwksp_alloc_objects;
|
||||||
ws->isStatic = isStatic;
|
ws->isStatic = isStatic;
|
||||||
ZSTD_cwksp_clear(ws);
|
ZSTD_cwksp_clear(ws);
|
||||||
|
|
@ -529,15 +607,6 @@ MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
|
||||||
ZSTD_memset(src, 0, sizeof(ZSTD_cwksp));
|
ZSTD_memset(src, 0, sizeof(ZSTD_cwksp));
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
|
|
||||||
return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
|
|
||||||
return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
|
|
||||||
+ (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
||||||
return ws->allocFailed;
|
return ws->allocFailed;
|
||||||
}
|
}
|
||||||
|
|
@ -550,17 +619,11 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
||||||
* Returns if the estimated space needed for a wksp is within an acceptable limit of the
|
* Returns if the estimated space needed for a wksp is within an acceptable limit of the
|
||||||
* actual amount of space used.
|
* actual amount of space used.
|
||||||
*/
|
*/
|
||||||
MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp* const ws,
|
MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp *const ws, size_t const estimatedSpace) {
|
||||||
size_t const estimatedSpace, int resizedWorkspace) {
|
/* We have an alignment space between objects and tables between tables and buffers, so we can have up to twice
|
||||||
if (resizedWorkspace) {
|
* the alignment bytes difference between estimation and actual usage */
|
||||||
/* Resized/newly allocated wksp should have exact bounds */
|
return (estimatedSpace - ZSTD_cwksp_slack_space_required()) <= ZSTD_cwksp_used(ws) &&
|
||||||
return ZSTD_cwksp_used(ws) == estimatedSpace;
|
ZSTD_cwksp_used(ws) <= estimatedSpace;
|
||||||
} else {
|
|
||||||
/* Due to alignment, when reusing a workspace, we can actually consume 63 fewer or more bytes
|
|
||||||
* than estimatedSpace. See the comments in zstd_cwksp.h for details.
|
|
||||||
*/
|
|
||||||
return (ZSTD_cwksp_used(ws) >= estimatedSpace - 63) && (ZSTD_cwksp_used(ws) <= estimatedSpace + 63);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -591,5 +654,4 @@ MEM_STATIC void ZSTD_cwksp_bump_oversized_duration(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* ZSTD_CWKSP_H */
|
#endif /* ZSTD_CWKSP_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,8 +12,49 @@
|
||||||
#include "zstd_compress_internal.h"
|
#include "zstd_compress_internal.h"
|
||||||
#include "zstd_double_fast.h"
|
#include "zstd_double_fast.h"
|
||||||
|
|
||||||
|
#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
|
||||||
|
|
||||||
void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
static
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
void ZSTD_fillDoubleHashTableForCDict(ZSTD_MatchState_t* ms,
|
||||||
|
void const* end, ZSTD_dictTableLoadMethod_e dtlm)
|
||||||
|
{
|
||||||
|
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||||
|
U32* const hashLarge = ms->hashTable;
|
||||||
|
U32 const hBitsL = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS;
|
||||||
|
U32 const mls = cParams->minMatch;
|
||||||
|
U32* const hashSmall = ms->chainTable;
|
||||||
|
U32 const hBitsS = cParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS;
|
||||||
|
const BYTE* const base = ms->window.base;
|
||||||
|
const BYTE* ip = base + ms->nextToUpdate;
|
||||||
|
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
||||||
|
const U32 fastHashFillStep = 3;
|
||||||
|
|
||||||
|
/* Always insert every fastHashFillStep position into the hash tables.
|
||||||
|
* Insert the other positions into the large hash table if their entry
|
||||||
|
* is empty.
|
||||||
|
*/
|
||||||
|
for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
|
||||||
|
U32 const curr = (U32)(ip - base);
|
||||||
|
U32 i;
|
||||||
|
for (i = 0; i < fastHashFillStep; ++i) {
|
||||||
|
size_t const smHashAndTag = ZSTD_hashPtr(ip + i, hBitsS, mls);
|
||||||
|
size_t const lgHashAndTag = ZSTD_hashPtr(ip + i, hBitsL, 8);
|
||||||
|
if (i == 0) {
|
||||||
|
ZSTD_writeTaggedIndex(hashSmall, smHashAndTag, curr + i);
|
||||||
|
}
|
||||||
|
if (i == 0 || hashLarge[lgHashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) {
|
||||||
|
ZSTD_writeTaggedIndex(hashLarge, lgHashAndTag, curr + i);
|
||||||
|
}
|
||||||
|
/* Only load extra positions for ZSTD_dtlm_full */
|
||||||
|
if (dtlm == ZSTD_dtlm_fast)
|
||||||
|
break;
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
void ZSTD_fillDoubleHashTableForCCtx(ZSTD_MatchState_t* ms,
|
||||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm)
|
void const* end, ZSTD_dictTableLoadMethod_e dtlm)
|
||||||
{
|
{
|
||||||
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||||
|
|
@ -46,10 +88,23 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
||||||
} }
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZSTD_fillDoubleHashTable(ZSTD_MatchState_t* ms,
|
||||||
|
const void* const end,
|
||||||
|
ZSTD_dictTableLoadMethod_e dtlm,
|
||||||
|
ZSTD_tableFillPurpose_e tfp)
|
||||||
|
{
|
||||||
|
if (tfp == ZSTD_tfp_forCDict) {
|
||||||
|
ZSTD_fillDoubleHashTableForCDict(ms, end, dtlm);
|
||||||
|
} else {
|
||||||
|
ZSTD_fillDoubleHashTableForCCtx(ms, end, dtlm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize, U32 const mls /* template */)
|
void const* src, size_t srcSize, U32 const mls /* template */)
|
||||||
{
|
{
|
||||||
ZSTD_compressionParameters const* cParams = &ms->cParams;
|
ZSTD_compressionParameters const* cParams = &ms->cParams;
|
||||||
|
|
@ -67,7 +122,7 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||||
U32 offset_1=rep[0], offset_2=rep[1];
|
U32 offset_1=rep[0], offset_2=rep[1];
|
||||||
U32 offsetSaved = 0;
|
U32 offsetSaved1 = 0, offsetSaved2 = 0;
|
||||||
|
|
||||||
size_t mLength;
|
size_t mLength;
|
||||||
U32 offset;
|
U32 offset;
|
||||||
|
|
@ -88,9 +143,14 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
||||||
const BYTE* matchl0; /* the long match for ip */
|
const BYTE* matchl0; /* the long match for ip */
|
||||||
const BYTE* matchs0; /* the short match for ip */
|
const BYTE* matchs0; /* the short match for ip */
|
||||||
const BYTE* matchl1; /* the long match for ip1 */
|
const BYTE* matchl1; /* the long match for ip1 */
|
||||||
|
const BYTE* matchs0_safe; /* matchs0 or safe address */
|
||||||
|
|
||||||
const BYTE* ip = istart; /* the current position */
|
const BYTE* ip = istart; /* the current position */
|
||||||
const BYTE* ip1; /* the next position */
|
const BYTE* ip1; /* the next position */
|
||||||
|
/* Array of ~random data, should have low probability of matching data
|
||||||
|
* we load from here instead of from tables, if matchl0/matchl1 are
|
||||||
|
* invalid indices. Used to avoid unpredictable branches. */
|
||||||
|
const BYTE dummy[] = {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0xe2,0xb4};
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_noDict_generic");
|
DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_noDict_generic");
|
||||||
|
|
||||||
|
|
@ -100,8 +160,8 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
||||||
U32 const current = (U32)(ip - base);
|
U32 const current = (U32)(ip - base);
|
||||||
U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
|
U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
|
||||||
U32 const maxRep = current - windowLow;
|
U32 const maxRep = current - windowLow;
|
||||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0;
|
||||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Outer Loop: one iteration per match found and stored */
|
/* Outer Loop: one iteration per match found and stored */
|
||||||
|
|
@ -131,31 +191,36 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
||||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
||||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, mLength);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength);
|
||||||
goto _match_stored;
|
goto _match_stored;
|
||||||
}
|
}
|
||||||
|
|
||||||
hl1 = ZSTD_hashPtr(ip1, hBitsL, 8);
|
hl1 = ZSTD_hashPtr(ip1, hBitsL, 8);
|
||||||
|
|
||||||
if (idxl0 > prefixLowestIndex) {
|
/* idxl0 > prefixLowestIndex is a (somewhat) unpredictable branch.
|
||||||
|
* However expression below complies into conditional move. Since
|
||||||
|
* match is unlikely and we only *branch* on idxl0 > prefixLowestIndex
|
||||||
|
* if there is a match, all branches become predictable. */
|
||||||
|
{ const BYTE* const matchl0_safe = ZSTD_selectAddr(idxl0, prefixLowestIndex, matchl0, &dummy[0]);
|
||||||
|
|
||||||
/* check prefix long match */
|
/* check prefix long match */
|
||||||
if (MEM_read64(matchl0) == MEM_read64(ip)) {
|
if (MEM_read64(matchl0_safe) == MEM_read64(ip) && matchl0_safe == matchl0) {
|
||||||
mLength = ZSTD_count(ip+8, matchl0+8, iend) + 8;
|
mLength = ZSTD_count(ip+8, matchl0+8, iend) + 8;
|
||||||
offset = (U32)(ip-matchl0);
|
offset = (U32)(ip-matchl0);
|
||||||
while (((ip>anchor) & (matchl0>prefixLowest)) && (ip[-1] == matchl0[-1])) { ip--; matchl0--; mLength++; } /* catch up */
|
while (((ip>anchor) & (matchl0>prefixLowest)) && (ip[-1] == matchl0[-1])) { ip--; matchl0--; mLength++; } /* catch up */
|
||||||
goto _match_found;
|
goto _match_found;
|
||||||
}
|
} }
|
||||||
}
|
|
||||||
|
|
||||||
idxl1 = hashLong[hl1];
|
idxl1 = hashLong[hl1];
|
||||||
matchl1 = base + idxl1;
|
matchl1 = base + idxl1;
|
||||||
|
|
||||||
if (idxs0 > prefixLowestIndex) {
|
/* Same optimization as matchl0 above */
|
||||||
|
matchs0_safe = ZSTD_selectAddr(idxs0, prefixLowestIndex, matchs0, &dummy[0]);
|
||||||
|
|
||||||
/* check prefix short match */
|
/* check prefix short match */
|
||||||
if (MEM_read32(matchs0) == MEM_read32(ip)) {
|
if(MEM_read32(matchs0_safe) == MEM_read32(ip) && matchs0_safe == matchs0) {
|
||||||
goto _search_next_long;
|
goto _search_next_long;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ip1 >= nextStep) {
|
if (ip1 >= nextStep) {
|
||||||
PREFETCH_L1(ip1 + 64);
|
PREFETCH_L1(ip1 + 64);
|
||||||
|
|
@ -175,30 +240,36 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic(
|
||||||
} while (ip1 <= ilimit);
|
} while (ip1 <= ilimit);
|
||||||
|
|
||||||
_cleanup:
|
_cleanup:
|
||||||
|
/* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0),
|
||||||
|
* rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */
|
||||||
|
offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2;
|
||||||
|
|
||||||
/* save reps for next block */
|
/* save reps for next block */
|
||||||
rep[0] = offset_1 ? offset_1 : offsetSaved;
|
rep[0] = offset_1 ? offset_1 : offsetSaved1;
|
||||||
rep[1] = offset_2 ? offset_2 : offsetSaved;
|
rep[1] = offset_2 ? offset_2 : offsetSaved2;
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return (size_t)(iend - anchor);
|
return (size_t)(iend - anchor);
|
||||||
|
|
||||||
_search_next_long:
|
_search_next_long:
|
||||||
|
|
||||||
/* check prefix long +1 match */
|
/* short match found: let's check for a longer one */
|
||||||
if (idxl1 > prefixLowestIndex) {
|
mLength = ZSTD_count(ip+4, matchs0+4, iend) + 4;
|
||||||
if (MEM_read64(matchl1) == MEM_read64(ip1)) {
|
offset = (U32)(ip - matchs0);
|
||||||
|
|
||||||
|
/* check long match at +1 position */
|
||||||
|
if ((idxl1 > prefixLowestIndex) && (MEM_read64(matchl1) == MEM_read64(ip1))) {
|
||||||
|
size_t const l1len = ZSTD_count(ip1+8, matchl1+8, iend) + 8;
|
||||||
|
if (l1len > mLength) {
|
||||||
|
/* use the long match instead */
|
||||||
ip = ip1;
|
ip = ip1;
|
||||||
mLength = ZSTD_count(ip+8, matchl1+8, iend) + 8;
|
mLength = l1len;
|
||||||
offset = (U32)(ip-matchl1);
|
offset = (U32)(ip-matchl1);
|
||||||
while (((ip>anchor) & (matchl1>prefixLowest)) && (ip[-1] == matchl1[-1])) { ip--; matchl1--; mLength++; } /* catch up */
|
matchs0 = matchl1;
|
||||||
goto _match_found;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if no long +1 match, explore the short match we found */
|
while (((ip>anchor) & (matchs0>prefixLowest)) && (ip[-1] == matchs0[-1])) { ip--; matchs0--; mLength++; } /* complete backward */
|
||||||
mLength = ZSTD_count(ip+4, matchs0+4, iend) + 4;
|
|
||||||
offset = (U32)(ip - matchs0);
|
|
||||||
while (((ip>anchor) & (matchs0>prefixLowest)) && (ip[-1] == matchs0[-1])) { ip--; matchs0--; mLength++; } /* catch up */
|
|
||||||
|
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
||||||
|
|
@ -217,7 +288,7 @@ _match_found: /* requires ip, offset, mLength */
|
||||||
hashLong[hl1] = (U32)(ip1 - base);
|
hashLong[hl1] = (U32)(ip1 - base);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength);
|
||||||
|
|
||||||
_match_stored:
|
_match_stored:
|
||||||
/* match found */
|
/* match found */
|
||||||
|
|
@ -243,7 +314,7 @@ _match_stored:
|
||||||
U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
|
U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
|
||||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
|
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
|
||||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
|
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
|
||||||
ZSTD_storeSeq(seqStore, 0, anchor, iend, STORE_REPCODE_1, rLength);
|
ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, rLength);
|
||||||
ip += rLength;
|
ip += rLength;
|
||||||
anchor = ip;
|
anchor = ip;
|
||||||
continue; /* faster when present ... (?) */
|
continue; /* faster when present ... (?) */
|
||||||
|
|
@ -254,8 +325,9 @@ _match_stored:
|
||||||
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE
|
FORCE_INLINE_TEMPLATE
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize,
|
void const* src, size_t srcSize,
|
||||||
U32 const mls /* template */)
|
U32 const mls /* template */)
|
||||||
{
|
{
|
||||||
|
|
@ -275,9 +347,8 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||||
U32 offset_1=rep[0], offset_2=rep[1];
|
U32 offset_1=rep[0], offset_2=rep[1];
|
||||||
U32 offsetSaved = 0;
|
|
||||||
|
|
||||||
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
const ZSTD_MatchState_t* const dms = ms->dictMatchState;
|
||||||
const ZSTD_compressionParameters* const dictCParams = &dms->cParams;
|
const ZSTD_compressionParameters* const dictCParams = &dms->cParams;
|
||||||
const U32* const dictHashLong = dms->hashTable;
|
const U32* const dictHashLong = dms->hashTable;
|
||||||
const U32* const dictHashSmall = dms->chainTable;
|
const U32* const dictHashSmall = dms->chainTable;
|
||||||
|
|
@ -286,8 +357,8 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
const BYTE* const dictStart = dictBase + dictStartIndex;
|
const BYTE* const dictStart = dictBase + dictStartIndex;
|
||||||
const BYTE* const dictEnd = dms->window.nextSrc;
|
const BYTE* const dictEnd = dms->window.nextSrc;
|
||||||
const U32 dictIndexDelta = prefixLowestIndex - (U32)(dictEnd - dictBase);
|
const U32 dictIndexDelta = prefixLowestIndex - (U32)(dictEnd - dictBase);
|
||||||
const U32 dictHBitsL = dictCParams->hashLog;
|
const U32 dictHBitsL = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS;
|
||||||
const U32 dictHBitsS = dictCParams->chainLog;
|
const U32 dictHBitsS = dictCParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS;
|
||||||
const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart));
|
const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart));
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic");
|
DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic");
|
||||||
|
|
@ -295,6 +366,13 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
/* if a dictionary is attached, it must be within window range */
|
/* if a dictionary is attached, it must be within window range */
|
||||||
assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex);
|
assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex);
|
||||||
|
|
||||||
|
if (ms->prefetchCDictTables) {
|
||||||
|
size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32);
|
||||||
|
size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32);
|
||||||
|
PREFETCH_AREA(dictHashLong, hashTableBytes);
|
||||||
|
PREFETCH_AREA(dictHashSmall, chainTableBytes);
|
||||||
|
}
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
ip += (dictAndPrefixLength == 0);
|
ip += (dictAndPrefixLength == 0);
|
||||||
|
|
||||||
|
|
@ -309,8 +387,12 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
U32 offset;
|
U32 offset;
|
||||||
size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
|
size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
|
||||||
size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
|
size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
|
||||||
size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8);
|
size_t const dictHashAndTagL = ZSTD_hashPtr(ip, dictHBitsL, 8);
|
||||||
size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls);
|
size_t const dictHashAndTagS = ZSTD_hashPtr(ip, dictHBitsS, mls);
|
||||||
|
U32 const dictMatchIndexAndTagL = dictHashLong[dictHashAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS];
|
||||||
|
U32 const dictMatchIndexAndTagS = dictHashSmall[dictHashAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS];
|
||||||
|
int const dictTagsMatchL = ZSTD_comparePackedTags(dictMatchIndexAndTagL, dictHashAndTagL);
|
||||||
|
int const dictTagsMatchS = ZSTD_comparePackedTags(dictMatchIndexAndTagS, dictHashAndTagS);
|
||||||
U32 const curr = (U32)(ip-base);
|
U32 const curr = (U32)(ip-base);
|
||||||
U32 const matchIndexL = hashLong[h2];
|
U32 const matchIndexL = hashLong[h2];
|
||||||
U32 matchIndexS = hashSmall[h];
|
U32 matchIndexS = hashSmall[h];
|
||||||
|
|
@ -323,26 +405,24 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
hashLong[h2] = hashSmall[h] = curr; /* update hash tables */
|
hashLong[h2] = hashSmall[h] = curr; /* update hash tables */
|
||||||
|
|
||||||
/* check repcode */
|
/* check repcode */
|
||||||
if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
|
if ((ZSTD_index_overlap_check(prefixLowestIndex, repIndex))
|
||||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||||
const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
|
const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
|
||||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
|
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, mLength);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength);
|
||||||
goto _match_stored;
|
goto _match_stored;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchIndexL > prefixLowestIndex) {
|
if ((matchIndexL >= prefixLowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
||||||
/* check prefix long match */
|
/* check prefix long match */
|
||||||
if (MEM_read64(matchLong) == MEM_read64(ip)) {
|
|
||||||
mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
|
mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
|
||||||
offset = (U32)(ip-matchLong);
|
offset = (U32)(ip-matchLong);
|
||||||
while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||||
goto _match_found;
|
goto _match_found;
|
||||||
}
|
} else if (dictTagsMatchL) {
|
||||||
} else {
|
|
||||||
/* check dictMatchState long match */
|
/* check dictMatchState long match */
|
||||||
U32 const dictMatchIndexL = dictHashLong[dictHL];
|
U32 const dictMatchIndexL = dictMatchIndexAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS;
|
||||||
const BYTE* dictMatchL = dictBase + dictMatchIndexL;
|
const BYTE* dictMatchL = dictBase + dictMatchIndexL;
|
||||||
assert(dictMatchL < dictEnd);
|
assert(dictMatchL < dictEnd);
|
||||||
|
|
||||||
|
|
@ -354,13 +434,13 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
} }
|
} }
|
||||||
|
|
||||||
if (matchIndexS > prefixLowestIndex) {
|
if (matchIndexS > prefixLowestIndex) {
|
||||||
/* check prefix short match */
|
/* short match candidate */
|
||||||
if (MEM_read32(match) == MEM_read32(ip)) {
|
if (MEM_read32(match) == MEM_read32(ip)) {
|
||||||
goto _search_next_long;
|
goto _search_next_long;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (dictTagsMatchS) {
|
||||||
/* check dictMatchState short match */
|
/* check dictMatchState short match */
|
||||||
U32 const dictMatchIndexS = dictHashSmall[dictHS];
|
U32 const dictMatchIndexS = dictMatchIndexAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS;
|
||||||
match = dictBase + dictMatchIndexS;
|
match = dictBase + dictMatchIndexS;
|
||||||
matchIndexS = dictMatchIndexS + dictIndexDelta;
|
matchIndexS = dictMatchIndexS + dictIndexDelta;
|
||||||
|
|
||||||
|
|
@ -375,25 +455,24 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_search_next_long:
|
_search_next_long:
|
||||||
|
|
||||||
{ size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
{ size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||||
size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
|
size_t const dictHashAndTagL3 = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
|
||||||
U32 const matchIndexL3 = hashLong[hl3];
|
U32 const matchIndexL3 = hashLong[hl3];
|
||||||
|
U32 const dictMatchIndexAndTagL3 = dictHashLong[dictHashAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS];
|
||||||
|
int const dictTagsMatchL3 = ZSTD_comparePackedTags(dictMatchIndexAndTagL3, dictHashAndTagL3);
|
||||||
const BYTE* matchL3 = base + matchIndexL3;
|
const BYTE* matchL3 = base + matchIndexL3;
|
||||||
hashLong[hl3] = curr + 1;
|
hashLong[hl3] = curr + 1;
|
||||||
|
|
||||||
/* check prefix long +1 match */
|
/* check prefix long +1 match */
|
||||||
if (matchIndexL3 > prefixLowestIndex) {
|
if ((matchIndexL3 >= prefixLowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1))) {
|
||||||
if (MEM_read64(matchL3) == MEM_read64(ip+1)) {
|
|
||||||
mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
|
mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
|
||||||
ip++;
|
ip++;
|
||||||
offset = (U32)(ip-matchL3);
|
offset = (U32)(ip-matchL3);
|
||||||
while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
|
while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
|
||||||
goto _match_found;
|
goto _match_found;
|
||||||
}
|
} else if (dictTagsMatchL3) {
|
||||||
} else {
|
|
||||||
/* check dict long +1 match */
|
/* check dict long +1 match */
|
||||||
U32 const dictMatchIndexL3 = dictHashLong[dictHLNext];
|
U32 const dictMatchIndexL3 = dictMatchIndexAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS;
|
||||||
const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
|
const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
|
||||||
assert(dictMatchL3 < dictEnd);
|
assert(dictMatchL3 < dictEnd);
|
||||||
if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
|
if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
|
||||||
|
|
@ -419,7 +498,7 @@ _match_found:
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
offset_1 = offset;
|
||||||
|
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength);
|
||||||
|
|
||||||
_match_stored:
|
_match_stored:
|
||||||
/* match found */
|
/* match found */
|
||||||
|
|
@ -443,12 +522,12 @@ _match_stored:
|
||||||
const BYTE* repMatch2 = repIndex2 < prefixLowestIndex ?
|
const BYTE* repMatch2 = repIndex2 < prefixLowestIndex ?
|
||||||
dictBase + repIndex2 - dictIndexDelta :
|
dictBase + repIndex2 - dictIndexDelta :
|
||||||
base + repIndex2;
|
base + repIndex2;
|
||||||
if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
|
if ( (ZSTD_index_overlap_check(prefixLowestIndex, repIndex2))
|
||||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||||
const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
|
const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
|
||||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
|
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
|
||||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||||
ZSTD_storeSeq(seqStore, 0, anchor, iend, STORE_REPCODE_1, repLength2);
|
ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2);
|
||||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
||||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
||||||
ip += repLength2;
|
ip += repLength2;
|
||||||
|
|
@ -461,8 +540,8 @@ _match_stored:
|
||||||
} /* while (ip < ilimit) */
|
} /* while (ip < ilimit) */
|
||||||
|
|
||||||
/* save reps for next block */
|
/* save reps for next block */
|
||||||
rep[0] = offset_1 ? offset_1 : offsetSaved;
|
rep[0] = offset_1;
|
||||||
rep[1] = offset_2 ? offset_2 : offsetSaved;
|
rep[1] = offset_2;
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return (size_t)(iend - anchor);
|
return (size_t)(iend - anchor);
|
||||||
|
|
@ -470,7 +549,7 @@ _match_stored:
|
||||||
|
|
||||||
#define ZSTD_GEN_DFAST_FN(dictMode, mls) \
|
#define ZSTD_GEN_DFAST_FN(dictMode, mls) \
|
||||||
static size_t ZSTD_compressBlock_doubleFast_##dictMode##_##mls( \
|
static size_t ZSTD_compressBlock_doubleFast_##dictMode##_##mls( \
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \
|
||||||
void const* src, size_t srcSize) \
|
void const* src, size_t srcSize) \
|
||||||
{ \
|
{ \
|
||||||
return ZSTD_compressBlock_doubleFast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls); \
|
return ZSTD_compressBlock_doubleFast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls); \
|
||||||
|
|
@ -488,7 +567,7 @@ ZSTD_GEN_DFAST_FN(dictMatchState, 7)
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_doubleFast(
|
size_t ZSTD_compressBlock_doubleFast(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
const U32 mls = ms->cParams.minMatch;
|
const U32 mls = ms->cParams.minMatch;
|
||||||
|
|
@ -508,7 +587,7 @@ size_t ZSTD_compressBlock_doubleFast(
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_doubleFast_dictMatchState(
|
size_t ZSTD_compressBlock_doubleFast_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
const U32 mls = ms->cParams.minMatch;
|
const U32 mls = ms->cParams.minMatch;
|
||||||
|
|
@ -527,8 +606,10 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
static
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize,
|
void const* src, size_t srcSize,
|
||||||
U32 const mls /* template */)
|
U32 const mls /* template */)
|
||||||
{
|
{
|
||||||
|
|
@ -579,13 +660,13 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||||
size_t mLength;
|
size_t mLength;
|
||||||
hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */
|
hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */
|
||||||
|
|
||||||
if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
|
if (((ZSTD_index_overlap_check(prefixStartIndex, repIndex))
|
||||||
& (offset_1 <= curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */
|
& (offset_1 <= curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */
|
||||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||||
const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
|
const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
|
||||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
|
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, mLength);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength);
|
||||||
} else {
|
} else {
|
||||||
if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
||||||
const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
|
const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
|
||||||
|
|
@ -596,7 +677,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||||
while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
offset_1 = offset;
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength);
|
||||||
|
|
||||||
} else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
|
} else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
|
||||||
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||||
|
|
@ -621,7 +702,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||||
}
|
}
|
||||||
offset_2 = offset_1;
|
offset_2 = offset_1;
|
||||||
offset_1 = offset;
|
offset_1 = offset;
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ip += ((ip-anchor) >> kSearchStrength) + 1;
|
ip += ((ip-anchor) >> kSearchStrength) + 1;
|
||||||
|
|
@ -647,13 +728,13 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||||
U32 const current2 = (U32)(ip-base);
|
U32 const current2 = (U32)(ip-base);
|
||||||
U32 const repIndex2 = current2 - offset_2;
|
U32 const repIndex2 = current2 - offset_2;
|
||||||
const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
|
const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
|
||||||
if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
|
if ( ((ZSTD_index_overlap_check(prefixStartIndex, repIndex2))
|
||||||
& (offset_2 <= current2 - dictStartIndex))
|
& (offset_2 <= current2 - dictStartIndex))
|
||||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||||
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
|
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
|
||||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
|
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
|
||||||
U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||||
ZSTD_storeSeq(seqStore, 0, anchor, iend, STORE_REPCODE_1, repLength2);
|
ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2);
|
||||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
||||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
||||||
ip += repLength2;
|
ip += repLength2;
|
||||||
|
|
@ -677,7 +758,7 @@ ZSTD_GEN_DFAST_FN(extDict, 6)
|
||||||
ZSTD_GEN_DFAST_FN(extDict, 7)
|
ZSTD_GEN_DFAST_FN(extDict, 7)
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_doubleFast_extDict(
|
size_t ZSTD_compressBlock_doubleFast_extDict(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
U32 const mls = ms->cParams.minMatch;
|
U32 const mls = ms->cParams.minMatch;
|
||||||
|
|
@ -694,3 +775,5 @@ size_t ZSTD_compressBlock_doubleFast_extDict(
|
||||||
return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize);
|
return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,22 +12,32 @@
|
||||||
#ifndef ZSTD_DOUBLE_FAST_H
|
#ifndef ZSTD_DOUBLE_FAST_H
|
||||||
#define ZSTD_DOUBLE_FAST_H
|
#define ZSTD_DOUBLE_FAST_H
|
||||||
|
|
||||||
|
|
||||||
#include "../common/mem.h" /* U32 */
|
#include "../common/mem.h" /* U32 */
|
||||||
#include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */
|
#include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */
|
||||||
|
|
||||||
void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
|
#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
|
||||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm);
|
|
||||||
|
void ZSTD_fillDoubleHashTable(ZSTD_MatchState_t* ms,
|
||||||
|
void const* end, ZSTD_dictTableLoadMethod_e dtlm,
|
||||||
|
ZSTD_tableFillPurpose_e tfp);
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_doubleFast(
|
size_t ZSTD_compressBlock_doubleFast(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_doubleFast_dictMatchState(
|
size_t ZSTD_compressBlock_doubleFast_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_doubleFast_extDict(
|
size_t ZSTD_compressBlock_doubleFast_extDict(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST ZSTD_compressBlock_doubleFast
|
||||||
|
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE ZSTD_compressBlock_doubleFast_dictMatchState
|
||||||
|
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT ZSTD_compressBlock_doubleFast_extDict
|
||||||
|
#else
|
||||||
|
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT NULL
|
||||||
|
#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */
|
||||||
|
|
||||||
#endif /* ZSTD_DOUBLE_FAST_H */
|
#endif /* ZSTD_DOUBLE_FAST_H */
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,21 +12,20 @@
|
||||||
#ifndef ZSTD_FAST_H
|
#ifndef ZSTD_FAST_H
|
||||||
#define ZSTD_FAST_H
|
#define ZSTD_FAST_H
|
||||||
|
|
||||||
|
|
||||||
#include "../common/mem.h" /* U32 */
|
#include "../common/mem.h" /* U32 */
|
||||||
#include "zstd_compress_internal.h"
|
#include "zstd_compress_internal.h"
|
||||||
|
|
||||||
void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
|
void ZSTD_fillHashTable(ZSTD_MatchState_t* ms,
|
||||||
void const* end, ZSTD_dictTableLoadMethod_e dtlm);
|
void const* end, ZSTD_dictTableLoadMethod_e dtlm,
|
||||||
|
ZSTD_tableFillPurpose_e tfp);
|
||||||
size_t ZSTD_compressBlock_fast(
|
size_t ZSTD_compressBlock_fast(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_fast_dictMatchState(
|
size_t ZSTD_compressBlock_fast_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_fast_extDict(
|
size_t ZSTD_compressBlock_fast_extDict(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
||||||
#endif /* ZSTD_FAST_H */
|
#endif /* ZSTD_FAST_H */
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,7 +12,6 @@
|
||||||
#ifndef ZSTD_LAZY_H
|
#ifndef ZSTD_LAZY_H
|
||||||
#define ZSTD_LAZY_H
|
#define ZSTD_LAZY_H
|
||||||
|
|
||||||
|
|
||||||
#include "zstd_compress_internal.h"
|
#include "zstd_compress_internal.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -22,98 +22,173 @@
|
||||||
*/
|
*/
|
||||||
#define ZSTD_LAZY_DDSS_BUCKET_LOG 2
|
#define ZSTD_LAZY_DDSS_BUCKET_LOG 2
|
||||||
|
|
||||||
U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
|
#define ZSTD_ROW_HASH_TAG_BITS 8 /* nb bits to use for the tag */
|
||||||
void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip);
|
|
||||||
|
|
||||||
void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip);
|
#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \
|
||||||
|
|| !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \
|
||||||
|
|| !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \
|
||||||
|
|| !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR)
|
||||||
|
U32 ZSTD_insertAndFindFirstIndex(ZSTD_MatchState_t* ms, const BYTE* ip);
|
||||||
|
void ZSTD_row_update(ZSTD_MatchState_t* const ms, const BYTE* ip);
|
||||||
|
|
||||||
|
void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_MatchState_t* ms, const BYTE* const ip);
|
||||||
|
|
||||||
void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */
|
void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btlazy2(
|
#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy2(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_greedy(
|
size_t ZSTD_compressBlock_greedy(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy2_row(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy_row(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_greedy_row(
|
size_t ZSTD_compressBlock_greedy_row(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_greedy_dictMatchState(
|
size_t ZSTD_compressBlock_greedy_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy_dictMatchState_row(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_greedy_dictMatchState_row(
|
size_t ZSTD_compressBlock_greedy_dictMatchState_row(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
|
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
|
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_greedy_extDict(
|
size_t ZSTD_compressBlock_greedy_extDict(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy_extDict(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_lazy2_extDict(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_greedy_extDict_row(
|
size_t ZSTD_compressBlock_greedy_extDict_row(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY ZSTD_compressBlock_greedy
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_ROW ZSTD_compressBlock_greedy_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE ZSTD_compressBlock_greedy_dictMatchState
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW ZSTD_compressBlock_greedy_dictMatchState_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH ZSTD_compressBlock_greedy_dedicatedDictSearch
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_greedy_dedicatedDictSearch_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT ZSTD_compressBlock_greedy_extDict
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW ZSTD_compressBlock_greedy_extDict_row
|
||||||
|
#else
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR
|
||||||
|
size_t ZSTD_compressBlock_lazy(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy_row(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy_dictMatchState_row(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy_extDict(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_lazy_extDict_row(
|
size_t ZSTD_compressBlock_lazy_extDict_row(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY ZSTD_compressBlock_lazy
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_ROW ZSTD_compressBlock_lazy_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE ZSTD_compressBlock_lazy_dictMatchState
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy_dictMatchState_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy_dedicatedDictSearch
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy_dedicatedDictSearch_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT ZSTD_compressBlock_lazy_extDict
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW ZSTD_compressBlock_lazy_extDict_row
|
||||||
|
#else
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR
|
||||||
|
size_t ZSTD_compressBlock_lazy2(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy2_row(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_lazy2_extDict(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_lazy2_extDict_row(
|
size_t ZSTD_compressBlock_lazy2_extDict_row(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2 ZSTD_compressBlock_lazy2
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_ROW ZSTD_compressBlock_lazy2_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE ZSTD_compressBlock_lazy2_dictMatchState
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy2_dictMatchState_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy2_dedicatedDictSearch
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy2_dedicatedDictSearch_row
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT ZSTD_compressBlock_lazy2_extDict
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW ZSTD_compressBlock_lazy2_extDict_row
|
||||||
|
#else
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2 NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR
|
||||||
|
size_t ZSTD_compressBlock_btlazy2(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_btlazy2_extDict(
|
size_t ZSTD_compressBlock_btlazy2_extDict(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTLAZY2 ZSTD_compressBlock_btlazy2
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE ZSTD_compressBlock_btlazy2_dictMatchState
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT ZSTD_compressBlock_btlazy2_extDict
|
||||||
|
#else
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTLAZY2 NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* ZSTD_LAZY_H */
|
#endif /* ZSTD_LAZY_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -16,7 +17,7 @@
|
||||||
#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
|
#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
|
||||||
#include "zstd_ldm_geartab.h"
|
#include "zstd_ldm_geartab.h"
|
||||||
|
|
||||||
#define LDM_BUCKET_SIZE_LOG 3
|
#define LDM_BUCKET_SIZE_LOG 4
|
||||||
#define LDM_MIN_MATCH_LENGTH 64
|
#define LDM_MIN_MATCH_LENGTH 64
|
||||||
#define LDM_HASH_RLOG 7
|
#define LDM_HASH_RLOG 7
|
||||||
|
|
||||||
|
|
@ -133,21 +134,35 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
||||||
ZSTD_compressionParameters const* cParams)
|
const ZSTD_compressionParameters* cParams)
|
||||||
{
|
{
|
||||||
params->windowLog = cParams->windowLog;
|
params->windowLog = cParams->windowLog;
|
||||||
ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
|
ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
|
||||||
DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
|
DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
|
||||||
if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
|
|
||||||
if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
|
|
||||||
if (params->hashLog == 0) {
|
|
||||||
params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
|
|
||||||
assert(params->hashLog <= ZSTD_HASHLOG_MAX);
|
|
||||||
}
|
|
||||||
if (params->hashRateLog == 0) {
|
if (params->hashRateLog == 0) {
|
||||||
params->hashRateLog = params->windowLog < params->hashLog
|
if (params->hashLog > 0) {
|
||||||
? 0
|
/* if params->hashLog is set, derive hashRateLog from it */
|
||||||
: params->windowLog - params->hashLog;
|
assert(params->hashLog <= ZSTD_HASHLOG_MAX);
|
||||||
|
if (params->windowLog > params->hashLog) {
|
||||||
|
params->hashRateLog = params->windowLog - params->hashLog;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(1 <= (int)cParams->strategy && (int)cParams->strategy <= 9);
|
||||||
|
/* mapping from [fast, rate7] to [btultra2, rate4] */
|
||||||
|
params->hashRateLog = 7 - (cParams->strategy/3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (params->hashLog == 0) {
|
||||||
|
params->hashLog = BOUNDED(ZSTD_HASHLOG_MIN, params->windowLog - params->hashRateLog, ZSTD_HASHLOG_MAX);
|
||||||
|
}
|
||||||
|
if (params->minMatchLength == 0) {
|
||||||
|
params->minMatchLength = LDM_MIN_MATCH_LENGTH;
|
||||||
|
if (cParams->strategy >= ZSTD_btultra)
|
||||||
|
params->minMatchLength /= 2;
|
||||||
|
}
|
||||||
|
if (params->bucketSizeLog==0) {
|
||||||
|
assert(1 <= (int)cParams->strategy && (int)cParams->strategy <= 9);
|
||||||
|
params->bucketSizeLog = BOUNDED(LDM_BUCKET_SIZE_LOG, (U32)cParams->strategy, ZSTD_LDM_BUCKETSIZELOG_MAX);
|
||||||
}
|
}
|
||||||
params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
|
params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
|
||||||
}
|
}
|
||||||
|
|
@ -170,22 +185,22 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
|
||||||
/* ZSTD_ldm_getBucket() :
|
/* ZSTD_ldm_getBucket() :
|
||||||
* Returns a pointer to the start of the bucket associated with hash. */
|
* Returns a pointer to the start of the bucket associated with hash. */
|
||||||
static ldmEntry_t* ZSTD_ldm_getBucket(
|
static ldmEntry_t* ZSTD_ldm_getBucket(
|
||||||
ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
|
const ldmState_t* ldmState, size_t hash, U32 const bucketSizeLog)
|
||||||
{
|
{
|
||||||
return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
|
return ldmState->hashTable + (hash << bucketSizeLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_ldm_insertEntry() :
|
/* ZSTD_ldm_insertEntry() :
|
||||||
* Insert the entry with corresponding hash into the hash table */
|
* Insert the entry with corresponding hash into the hash table */
|
||||||
static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
|
static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
|
||||||
size_t const hash, const ldmEntry_t entry,
|
size_t const hash, const ldmEntry_t entry,
|
||||||
ldmParams_t const ldmParams)
|
U32 const bucketSizeLog)
|
||||||
{
|
{
|
||||||
BYTE* const pOffset = ldmState->bucketOffsets + hash;
|
BYTE* const pOffset = ldmState->bucketOffsets + hash;
|
||||||
unsigned const offset = *pOffset;
|
unsigned const offset = *pOffset;
|
||||||
|
|
||||||
*(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry;
|
*(ZSTD_ldm_getBucket(ldmState, hash, bucketSizeLog) + offset) = entry;
|
||||||
*pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1));
|
*pOffset = (BYTE)((offset + 1) & ((1u << bucketSizeLog) - 1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,7 +249,7 @@ static size_t ZSTD_ldm_countBackwardsMatch_2segments(
|
||||||
*
|
*
|
||||||
* The tables for the other strategies are filled within their
|
* The tables for the other strategies are filled within their
|
||||||
* block compressors. */
|
* block compressors. */
|
||||||
static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
|
static size_t ZSTD_ldm_fillFastTables(ZSTD_MatchState_t* ms,
|
||||||
void const* end)
|
void const* end)
|
||||||
{
|
{
|
||||||
const BYTE* const iend = (const BYTE*)end;
|
const BYTE* const iend = (const BYTE*)end;
|
||||||
|
|
@ -242,11 +257,15 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
|
||||||
switch(ms->cParams.strategy)
|
switch(ms->cParams.strategy)
|
||||||
{
|
{
|
||||||
case ZSTD_fast:
|
case ZSTD_fast:
|
||||||
ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast);
|
ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSTD_dfast:
|
case ZSTD_dfast:
|
||||||
ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast);
|
#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
|
||||||
|
ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx);
|
||||||
|
#else
|
||||||
|
assert(0); /* shouldn't be called: cparams should've been adjusted. */
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSTD_greedy:
|
case ZSTD_greedy:
|
||||||
|
|
@ -269,7 +288,8 @@ void ZSTD_ldm_fillHashTable(
|
||||||
const BYTE* iend, ldmParams_t const* params)
|
const BYTE* iend, ldmParams_t const* params)
|
||||||
{
|
{
|
||||||
U32 const minMatchLength = params->minMatchLength;
|
U32 const minMatchLength = params->minMatchLength;
|
||||||
U32 const hBits = params->hashLog - params->bucketSizeLog;
|
U32 const bucketSizeLog = params->bucketSizeLog;
|
||||||
|
U32 const hBits = params->hashLog - bucketSizeLog;
|
||||||
BYTE const* const base = ldmState->window.base;
|
BYTE const* const base = ldmState->window.base;
|
||||||
BYTE const* const istart = ip;
|
BYTE const* const istart = ip;
|
||||||
ldmRollingHashState_t hashState;
|
ldmRollingHashState_t hashState;
|
||||||
|
|
@ -284,7 +304,7 @@ void ZSTD_ldm_fillHashTable(
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
|
||||||
numSplits = 0;
|
numSplits = 0;
|
||||||
hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits);
|
hashed = ZSTD_ldm_gear_feed(&hashState, ip, (size_t)(iend - ip), splits, &numSplits);
|
||||||
|
|
||||||
for (n = 0; n < numSplits; n++) {
|
for (n = 0; n < numSplits; n++) {
|
||||||
if (ip + splits[n] >= istart + minMatchLength) {
|
if (ip + splits[n] >= istart + minMatchLength) {
|
||||||
|
|
@ -295,7 +315,7 @@ void ZSTD_ldm_fillHashTable(
|
||||||
|
|
||||||
entry.offset = (U32)(split - base);
|
entry.offset = (U32)(split - base);
|
||||||
entry.checksum = (U32)(xxhash >> 32);
|
entry.checksum = (U32)(xxhash >> 32);
|
||||||
ZSTD_ldm_insertEntry(ldmState, hash, entry, *params);
|
ZSTD_ldm_insertEntry(ldmState, hash, entry, params->bucketSizeLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,7 +329,7 @@ void ZSTD_ldm_fillHashTable(
|
||||||
* Sets cctx->nextToUpdate to a position corresponding closer to anchor
|
* Sets cctx->nextToUpdate to a position corresponding closer to anchor
|
||||||
* if it is far way
|
* if it is far way
|
||||||
* (after a long match, only update tables a limited amount). */
|
* (after a long match, only update tables a limited amount). */
|
||||||
static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
|
static void ZSTD_ldm_limitTableUpdate(ZSTD_MatchState_t* ms, const BYTE* anchor)
|
||||||
{
|
{
|
||||||
U32 const curr = (U32)(anchor - ms->window.base);
|
U32 const curr = (U32)(anchor - ms->window.base);
|
||||||
if (curr > ms->nextToUpdate + 1024) {
|
if (curr > ms->nextToUpdate + 1024) {
|
||||||
|
|
@ -318,8 +338,10 @@ static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_ldm_generateSequences_internal(
|
static
|
||||||
ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
size_t ZSTD_ldm_generateSequences_internal(
|
||||||
|
ldmState_t* ldmState, RawSeqStore_t* rawSeqStore,
|
||||||
ldmParams_t const* params, void const* src, size_t srcSize)
|
ldmParams_t const* params, void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
/* LDM parameters */
|
/* LDM parameters */
|
||||||
|
|
@ -373,7 +395,7 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
||||||
candidates[n].split = split;
|
candidates[n].split = split;
|
||||||
candidates[n].hash = hash;
|
candidates[n].hash = hash;
|
||||||
candidates[n].checksum = (U32)(xxhash >> 32);
|
candidates[n].checksum = (U32)(xxhash >> 32);
|
||||||
candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params);
|
candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, params->bucketSizeLog);
|
||||||
PREFETCH_L1(candidates[n].bucket);
|
PREFETCH_L1(candidates[n].bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -396,7 +418,7 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
||||||
* the previous one, we merely register it in the hash table and
|
* the previous one, we merely register it in the hash table and
|
||||||
* move on */
|
* move on */
|
||||||
if (split < anchor) {
|
if (split < anchor) {
|
||||||
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, params->bucketSizeLog);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -443,7 +465,7 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
||||||
/* No match found -- insert an entry into the hash table
|
/* No match found -- insert an entry into the hash table
|
||||||
* and process the next candidate match */
|
* and process the next candidate match */
|
||||||
if (bestEntry == NULL) {
|
if (bestEntry == NULL) {
|
||||||
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, params->bucketSizeLog);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -464,7 +486,7 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
||||||
|
|
||||||
/* Insert the current entry into the hash table --- it must be
|
/* Insert the current entry into the hash table --- it must be
|
||||||
* done after the previous block to avoid clobbering bestEntry */
|
* done after the previous block to avoid clobbering bestEntry */
|
||||||
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, params->bucketSizeLog);
|
||||||
|
|
||||||
anchor = split + forwardMatchLength;
|
anchor = split + forwardMatchLength;
|
||||||
|
|
||||||
|
|
@ -503,7 +525,7 @@ static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_ldm_generateSequences(
|
size_t ZSTD_ldm_generateSequences(
|
||||||
ldmState_t* ldmState, rawSeqStore_t* sequences,
|
ldmState_t* ldmState, RawSeqStore_t* sequences,
|
||||||
ldmParams_t const* params, void const* src, size_t srcSize)
|
ldmParams_t const* params, void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
U32 const maxDist = 1U << params->windowLog;
|
U32 const maxDist = 1U << params->windowLog;
|
||||||
|
|
@ -549,7 +571,7 @@ size_t ZSTD_ldm_generateSequences(
|
||||||
* the window through early invalidation.
|
* the window through early invalidation.
|
||||||
* TODO: * Test the chunk size.
|
* TODO: * Test the chunk size.
|
||||||
* * Try invalidation after the sequence generation and test the
|
* * Try invalidation after the sequence generation and test the
|
||||||
* the offset against maxDist directly.
|
* offset against maxDist directly.
|
||||||
*
|
*
|
||||||
* NOTE: Because of dictionaries + sequence splitting we MUST make sure
|
* NOTE: Because of dictionaries + sequence splitting we MUST make sure
|
||||||
* that any offset used is valid at the END of the sequence, since it may
|
* that any offset used is valid at the END of the sequence, since it may
|
||||||
|
|
@ -580,7 +602,7 @@ size_t ZSTD_ldm_generateSequences(
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch)
|
ZSTD_ldm_skipSequences(RawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch)
|
||||||
{
|
{
|
||||||
while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
|
while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
|
||||||
rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
|
rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
|
||||||
|
|
@ -616,7 +638,7 @@ ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const min
|
||||||
* Returns the current sequence to handle, or if the rest of the block should
|
* Returns the current sequence to handle, or if the rest of the block should
|
||||||
* be literals, it returns a sequence with offset == 0.
|
* be literals, it returns a sequence with offset == 0.
|
||||||
*/
|
*/
|
||||||
static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
|
static rawSeq maybeSplitSequence(RawSeqStore_t* rawSeqStore,
|
||||||
U32 const remaining, U32 const minMatch)
|
U32 const remaining, U32 const minMatch)
|
||||||
{
|
{
|
||||||
rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
|
rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
|
||||||
|
|
@ -640,7 +662,7 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
|
||||||
return sequence;
|
return sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) {
|
void ZSTD_ldm_skipRawSeqStoreBytes(RawSeqStore_t* rawSeqStore, size_t nbBytes) {
|
||||||
U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes);
|
U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes);
|
||||||
while (currPos && rawSeqStore->pos < rawSeqStore->size) {
|
while (currPos && rawSeqStore->pos < rawSeqStore->size) {
|
||||||
rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos];
|
rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos];
|
||||||
|
|
@ -657,14 +679,14 @@ void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
size_t ZSTD_ldm_blockCompress(RawSeqStore_t* rawSeqStore,
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
ZSTD_paramSwitch_e useRowMatchFinder,
|
ZSTD_ParamSwitch_e useRowMatchFinder,
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||||
unsigned const minMatch = cParams->minMatch;
|
unsigned const minMatch = cParams->minMatch;
|
||||||
ZSTD_blockCompressor const blockCompressor =
|
ZSTD_BlockCompressor_f const blockCompressor =
|
||||||
ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms));
|
ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms));
|
||||||
/* Input bounds */
|
/* Input bounds */
|
||||||
BYTE const* const istart = (BYTE const*)src;
|
BYTE const* const istart = (BYTE const*)src;
|
||||||
|
|
@ -689,7 +711,6 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||||
/* maybeSplitSequence updates rawSeqStore->pos */
|
/* maybeSplitSequence updates rawSeqStore->pos */
|
||||||
rawSeq const sequence = maybeSplitSequence(rawSeqStore,
|
rawSeq const sequence = maybeSplitSequence(rawSeqStore,
|
||||||
(U32)(iend - ip), minMatch);
|
(U32)(iend - ip), minMatch);
|
||||||
int i;
|
|
||||||
/* End signal */
|
/* End signal */
|
||||||
if (sequence.offset == 0)
|
if (sequence.offset == 0)
|
||||||
break;
|
break;
|
||||||
|
|
@ -702,6 +723,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||||
/* Run the block compressor */
|
/* Run the block compressor */
|
||||||
DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
|
DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
size_t const newLitLength =
|
size_t const newLitLength =
|
||||||
blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
|
blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
|
||||||
ip += sequence.litLength;
|
ip += sequence.litLength;
|
||||||
|
|
@ -711,7 +733,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||||
rep[0] = sequence.offset;
|
rep[0] = sequence.offset;
|
||||||
/* Store the sequence */
|
/* Store the sequence */
|
||||||
ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend,
|
ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend,
|
||||||
STORE_OFFSET(sequence.offset),
|
OFFSET_TO_OFFBASE(sequence.offset),
|
||||||
sequence.matchLength);
|
sequence.matchLength);
|
||||||
ip += sequence.matchLength;
|
ip += sequence.matchLength;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,7 +12,6 @@
|
||||||
#ifndef ZSTD_LDM_H
|
#ifndef ZSTD_LDM_H
|
||||||
#define ZSTD_LDM_H
|
#define ZSTD_LDM_H
|
||||||
|
|
||||||
|
|
||||||
#include "zstd_compress_internal.h" /* ldmParams_t, U32 */
|
#include "zstd_compress_internal.h" /* ldmParams_t, U32 */
|
||||||
#include <linux/zstd.h> /* ZSTD_CCtx, size_t */
|
#include <linux/zstd.h> /* ZSTD_CCtx, size_t */
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ void ZSTD_ldm_fillHashTable(
|
||||||
* sequences.
|
* sequences.
|
||||||
*/
|
*/
|
||||||
size_t ZSTD_ldm_generateSequences(
|
size_t ZSTD_ldm_generateSequences(
|
||||||
ldmState_t* ldms, rawSeqStore_t* sequences,
|
ldmState_t* ldms, RawSeqStore_t* sequences,
|
||||||
ldmParams_t const* params, void const* src, size_t srcSize);
|
ldmParams_t const* params, void const* src, size_t srcSize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -61,9 +61,9 @@ size_t ZSTD_ldm_generateSequences(
|
||||||
* two. We handle that case correctly, and update `rawSeqStore` appropriately.
|
* two. We handle that case correctly, and update `rawSeqStore` appropriately.
|
||||||
* NOTE: This function does not return any errors.
|
* NOTE: This function does not return any errors.
|
||||||
*/
|
*/
|
||||||
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
size_t ZSTD_ldm_blockCompress(RawSeqStore_t* rawSeqStore,
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
ZSTD_paramSwitch_e useRowMatchFinder,
|
ZSTD_ParamSwitch_e useRowMatchFinder,
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -73,7 +73,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||||
* Avoids emitting matches less than `minMatch` bytes.
|
* Avoids emitting matches less than `minMatch` bytes.
|
||||||
* Must be called for data that is not passed to ZSTD_ldm_blockCompress().
|
* Must be called for data that is not passed to ZSTD_ldm_blockCompress().
|
||||||
*/
|
*/
|
||||||
void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
|
void ZSTD_ldm_skipSequences(RawSeqStore_t* rawSeqStore, size_t srcSize,
|
||||||
U32 const minMatch);
|
U32 const minMatch);
|
||||||
|
|
||||||
/* ZSTD_ldm_skipRawSeqStoreBytes():
|
/* ZSTD_ldm_skipRawSeqStoreBytes():
|
||||||
|
|
@ -81,7 +81,7 @@ void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
|
||||||
* Not to be used in conjunction with ZSTD_ldm_skipSequences().
|
* Not to be used in conjunction with ZSTD_ldm_skipSequences().
|
||||||
* Must be called for data with is not passed to ZSTD_ldm_blockCompress().
|
* Must be called for data with is not passed to ZSTD_ldm_blockCompress().
|
||||||
*/
|
*/
|
||||||
void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes);
|
void ZSTD_ldm_skipRawSeqStoreBytes(RawSeqStore_t* rawSeqStore, size_t nbBytes);
|
||||||
|
|
||||||
/* ZSTD_ldm_getTableSize() :
|
/* ZSTD_ldm_getTableSize() :
|
||||||
* Estimate the space needed for long distance matching tables or 0 if LDM is
|
* Estimate the space needed for long distance matching tables or 0 if LDM is
|
||||||
|
|
@ -107,5 +107,4 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize);
|
||||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
||||||
ZSTD_compressionParameters const* cParams);
|
ZSTD_compressionParameters const* cParams);
|
||||||
|
|
||||||
|
|
||||||
#endif /* ZSTD_FAST_H */
|
#endif /* ZSTD_FAST_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -11,40 +12,62 @@
|
||||||
#ifndef ZSTD_OPT_H
|
#ifndef ZSTD_OPT_H
|
||||||
#define ZSTD_OPT_H
|
#define ZSTD_OPT_H
|
||||||
|
|
||||||
|
|
||||||
#include "zstd_compress_internal.h"
|
#include "zstd_compress_internal.h"
|
||||||
|
|
||||||
|
#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \
|
||||||
|
|| !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \
|
||||||
|
|| !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR)
|
||||||
/* used in ZSTD_loadDictionaryContent() */
|
/* used in ZSTD_loadDictionaryContent() */
|
||||||
void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend);
|
void ZSTD_updateTree(ZSTD_MatchState_t* ms, const BYTE* ip, const BYTE* iend);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
|
||||||
size_t ZSTD_compressBlock_btopt(
|
size_t ZSTD_compressBlock_btopt(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_btultra(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
size_t ZSTD_compressBlock_btultra2(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
|
||||||
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btopt_dictMatchState(
|
size_t ZSTD_compressBlock_btopt_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
size_t ZSTD_compressBlock_btopt_extDict(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTOPT ZSTD_compressBlock_btopt
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE ZSTD_compressBlock_btopt_dictMatchState
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT ZSTD_compressBlock_btopt_extDict
|
||||||
|
#else
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTOPT NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
|
||||||
|
size_t ZSTD_compressBlock_btultra(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btopt_extDict(
|
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
size_t ZSTD_compressBlock_btultra_extDict(
|
size_t ZSTD_compressBlock_btultra_extDict(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize);
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
/* note : no btultra2 variant for extDict nor dictMatchState,
|
/* note : no btultra2 variant for extDict nor dictMatchState,
|
||||||
* because btultra2 is not meant to work with dictionaries
|
* because btultra2 is not meant to work with dictionaries
|
||||||
* and is only specific for the first block (no prefix) */
|
* and is only specific for the first block (no prefix) */
|
||||||
|
size_t ZSTD_compressBlock_btultra2(
|
||||||
|
ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
|
void const* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA ZSTD_compressBlock_btultra
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE ZSTD_compressBlock_btultra_dictMatchState
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT ZSTD_compressBlock_btultra_extDict
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA2 ZSTD_compressBlock_btultra2
|
||||||
|
#else
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT NULL
|
||||||
|
#define ZSTD_COMPRESSBLOCK_BTULTRA2 NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* ZSTD_OPT_H */
|
#endif /* ZSTD_OPT_H */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,239 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../common/compiler.h" /* ZSTD_ALIGNOF */
|
||||||
|
#include "../common/mem.h" /* S64 */
|
||||||
|
#include "../common/zstd_deps.h" /* ZSTD_memset */
|
||||||
|
#include "../common/zstd_internal.h" /* ZSTD_STATIC_ASSERT */
|
||||||
|
#include "hist.h" /* HIST_add */
|
||||||
|
#include "zstd_preSplit.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BLOCKSIZE_MIN 3500
|
||||||
|
#define THRESHOLD_PENALTY_RATE 16
|
||||||
|
#define THRESHOLD_BASE (THRESHOLD_PENALTY_RATE - 2)
|
||||||
|
#define THRESHOLD_PENALTY 3
|
||||||
|
|
||||||
|
#define HASHLENGTH 2
|
||||||
|
#define HASHLOG_MAX 10
|
||||||
|
#define HASHTABLESIZE (1 << HASHLOG_MAX)
|
||||||
|
#define HASHMASK (HASHTABLESIZE - 1)
|
||||||
|
#define KNUTH 0x9e3779b9
|
||||||
|
|
||||||
|
/* for hashLog > 8, hash 2 bytes.
|
||||||
|
* for hashLog == 8, just take the byte, no hashing.
|
||||||
|
* The speed of this method relies on compile-time constant propagation */
|
||||||
|
FORCE_INLINE_TEMPLATE unsigned hash2(const void *p, unsigned hashLog)
|
||||||
|
{
|
||||||
|
assert(hashLog >= 8);
|
||||||
|
if (hashLog == 8) return (U32)((const BYTE*)p)[0];
|
||||||
|
assert(hashLog <= HASHLOG_MAX);
|
||||||
|
return (U32)(MEM_read16(p)) * KNUTH >> (32 - hashLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned events[HASHTABLESIZE];
|
||||||
|
size_t nbEvents;
|
||||||
|
} Fingerprint;
|
||||||
|
typedef struct {
|
||||||
|
Fingerprint pastEvents;
|
||||||
|
Fingerprint newEvents;
|
||||||
|
} FPStats;
|
||||||
|
|
||||||
|
static void initStats(FPStats* fpstats)
|
||||||
|
{
|
||||||
|
ZSTD_memset(fpstats, 0, sizeof(FPStats));
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE void
|
||||||
|
addEvents_generic(Fingerprint* fp, const void* src, size_t srcSize, size_t samplingRate, unsigned hashLog)
|
||||||
|
{
|
||||||
|
const char* p = (const char*)src;
|
||||||
|
size_t limit = srcSize - HASHLENGTH + 1;
|
||||||
|
size_t n;
|
||||||
|
assert(srcSize >= HASHLENGTH);
|
||||||
|
for (n = 0; n < limit; n+=samplingRate) {
|
||||||
|
fp->events[hash2(p+n, hashLog)]++;
|
||||||
|
}
|
||||||
|
fp->nbEvents += limit/samplingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE void
|
||||||
|
recordFingerprint_generic(Fingerprint* fp, const void* src, size_t srcSize, size_t samplingRate, unsigned hashLog)
|
||||||
|
{
|
||||||
|
ZSTD_memset(fp, 0, sizeof(unsigned) * ((size_t)1 << hashLog));
|
||||||
|
fp->nbEvents = 0;
|
||||||
|
addEvents_generic(fp, src, srcSize, samplingRate, hashLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*RecordEvents_f)(Fingerprint* fp, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
#define FP_RECORD(_rate) ZSTD_recordFingerprint_##_rate
|
||||||
|
|
||||||
|
#define ZSTD_GEN_RECORD_FINGERPRINT(_rate, _hSize) \
|
||||||
|
static void FP_RECORD(_rate)(Fingerprint* fp, const void* src, size_t srcSize) \
|
||||||
|
{ \
|
||||||
|
recordFingerprint_generic(fp, src, srcSize, _rate, _hSize); \
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_GEN_RECORD_FINGERPRINT(1, 10)
|
||||||
|
ZSTD_GEN_RECORD_FINGERPRINT(5, 10)
|
||||||
|
ZSTD_GEN_RECORD_FINGERPRINT(11, 9)
|
||||||
|
ZSTD_GEN_RECORD_FINGERPRINT(43, 8)
|
||||||
|
|
||||||
|
|
||||||
|
static U64 abs64(S64 s64) { return (U64)((s64 < 0) ? -s64 : s64); }
|
||||||
|
|
||||||
|
static U64 fpDistance(const Fingerprint* fp1, const Fingerprint* fp2, unsigned hashLog)
|
||||||
|
{
|
||||||
|
U64 distance = 0;
|
||||||
|
size_t n;
|
||||||
|
assert(hashLog <= HASHLOG_MAX);
|
||||||
|
for (n = 0; n < ((size_t)1 << hashLog); n++) {
|
||||||
|
distance +=
|
||||||
|
abs64((S64)fp1->events[n] * (S64)fp2->nbEvents - (S64)fp2->events[n] * (S64)fp1->nbEvents);
|
||||||
|
}
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare newEvents with pastEvents
|
||||||
|
* return 1 when considered "too different"
|
||||||
|
*/
|
||||||
|
static int compareFingerprints(const Fingerprint* ref,
|
||||||
|
const Fingerprint* newfp,
|
||||||
|
int penalty,
|
||||||
|
unsigned hashLog)
|
||||||
|
{
|
||||||
|
assert(ref->nbEvents > 0);
|
||||||
|
assert(newfp->nbEvents > 0);
|
||||||
|
{ U64 p50 = (U64)ref->nbEvents * (U64)newfp->nbEvents;
|
||||||
|
U64 deviation = fpDistance(ref, newfp, hashLog);
|
||||||
|
U64 threshold = p50 * (U64)(THRESHOLD_BASE + penalty) / THRESHOLD_PENALTY_RATE;
|
||||||
|
return deviation >= threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mergeEvents(Fingerprint* acc, const Fingerprint* newfp)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
for (n = 0; n < HASHTABLESIZE; n++) {
|
||||||
|
acc->events[n] += newfp->events[n];
|
||||||
|
}
|
||||||
|
acc->nbEvents += newfp->nbEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flushEvents(FPStats* fpstats)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
for (n = 0; n < HASHTABLESIZE; n++) {
|
||||||
|
fpstats->pastEvents.events[n] = fpstats->newEvents.events[n];
|
||||||
|
}
|
||||||
|
fpstats->pastEvents.nbEvents = fpstats->newEvents.nbEvents;
|
||||||
|
ZSTD_memset(&fpstats->newEvents, 0, sizeof(fpstats->newEvents));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void removeEvents(Fingerprint* acc, const Fingerprint* slice)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
for (n = 0; n < HASHTABLESIZE; n++) {
|
||||||
|
assert(acc->events[n] >= slice->events[n]);
|
||||||
|
acc->events[n] -= slice->events[n];
|
||||||
|
}
|
||||||
|
acc->nbEvents -= slice->nbEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHUNKSIZE (8 << 10)
|
||||||
|
static size_t ZSTD_splitBlock_byChunks(const void* blockStart, size_t blockSize,
|
||||||
|
int level,
|
||||||
|
void* workspace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
static const RecordEvents_f records_fs[] = {
|
||||||
|
FP_RECORD(43), FP_RECORD(11), FP_RECORD(5), FP_RECORD(1)
|
||||||
|
};
|
||||||
|
static const unsigned hashParams[] = { 8, 9, 10, 10 };
|
||||||
|
const RecordEvents_f record_f = (assert(0<=level && level<=3), records_fs[level]);
|
||||||
|
FPStats* const fpstats = (FPStats*)workspace;
|
||||||
|
const char* p = (const char*)blockStart;
|
||||||
|
int penalty = THRESHOLD_PENALTY;
|
||||||
|
size_t pos = 0;
|
||||||
|
assert(blockSize == (128 << 10));
|
||||||
|
assert(workspace != NULL);
|
||||||
|
assert((size_t)workspace % ZSTD_ALIGNOF(FPStats) == 0);
|
||||||
|
ZSTD_STATIC_ASSERT(ZSTD_SLIPBLOCK_WORKSPACESIZE >= sizeof(FPStats));
|
||||||
|
assert(wkspSize >= sizeof(FPStats)); (void)wkspSize;
|
||||||
|
|
||||||
|
initStats(fpstats);
|
||||||
|
record_f(&fpstats->pastEvents, p, CHUNKSIZE);
|
||||||
|
for (pos = CHUNKSIZE; pos <= blockSize - CHUNKSIZE; pos += CHUNKSIZE) {
|
||||||
|
record_f(&fpstats->newEvents, p + pos, CHUNKSIZE);
|
||||||
|
if (compareFingerprints(&fpstats->pastEvents, &fpstats->newEvents, penalty, hashParams[level])) {
|
||||||
|
return pos;
|
||||||
|
} else {
|
||||||
|
mergeEvents(&fpstats->pastEvents, &fpstats->newEvents);
|
||||||
|
if (penalty > 0) penalty--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(pos == blockSize);
|
||||||
|
return blockSize;
|
||||||
|
(void)flushEvents; (void)removeEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTD_splitBlock_fromBorders(): very fast strategy :
|
||||||
|
* compare fingerprint from beginning and end of the block,
|
||||||
|
* derive from their difference if it's preferable to split in the middle,
|
||||||
|
* repeat the process a second time, for finer grained decision.
|
||||||
|
* 3 times did not brought improvements, so I stopped at 2.
|
||||||
|
* Benefits are good enough for a cheap heuristic.
|
||||||
|
* More accurate splitting saves more, but speed impact is also more perceptible.
|
||||||
|
* For better accuracy, use more elaborate variant *_byChunks.
|
||||||
|
*/
|
||||||
|
static size_t ZSTD_splitBlock_fromBorders(const void* blockStart, size_t blockSize,
|
||||||
|
void* workspace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
#define SEGMENT_SIZE 512
|
||||||
|
FPStats* const fpstats = (FPStats*)workspace;
|
||||||
|
Fingerprint* middleEvents = (Fingerprint*)(void*)((char*)workspace + 512 * sizeof(unsigned));
|
||||||
|
assert(blockSize == (128 << 10));
|
||||||
|
assert(workspace != NULL);
|
||||||
|
assert((size_t)workspace % ZSTD_ALIGNOF(FPStats) == 0);
|
||||||
|
ZSTD_STATIC_ASSERT(ZSTD_SLIPBLOCK_WORKSPACESIZE >= sizeof(FPStats));
|
||||||
|
assert(wkspSize >= sizeof(FPStats)); (void)wkspSize;
|
||||||
|
|
||||||
|
initStats(fpstats);
|
||||||
|
HIST_add(fpstats->pastEvents.events, blockStart, SEGMENT_SIZE);
|
||||||
|
HIST_add(fpstats->newEvents.events, (const char*)blockStart + blockSize - SEGMENT_SIZE, SEGMENT_SIZE);
|
||||||
|
fpstats->pastEvents.nbEvents = fpstats->newEvents.nbEvents = SEGMENT_SIZE;
|
||||||
|
if (!compareFingerprints(&fpstats->pastEvents, &fpstats->newEvents, 0, 8))
|
||||||
|
return blockSize;
|
||||||
|
|
||||||
|
HIST_add(middleEvents->events, (const char*)blockStart + blockSize/2 - SEGMENT_SIZE/2, SEGMENT_SIZE);
|
||||||
|
middleEvents->nbEvents = SEGMENT_SIZE;
|
||||||
|
{ U64 const distFromBegin = fpDistance(&fpstats->pastEvents, middleEvents, 8);
|
||||||
|
U64 const distFromEnd = fpDistance(&fpstats->newEvents, middleEvents, 8);
|
||||||
|
U64 const minDistance = SEGMENT_SIZE * SEGMENT_SIZE / 3;
|
||||||
|
if (abs64((S64)distFromBegin - (S64)distFromEnd) < minDistance)
|
||||||
|
return 64 KB;
|
||||||
|
return (distFromBegin > distFromEnd) ? 32 KB : 96 KB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_splitBlock(const void* blockStart, size_t blockSize,
|
||||||
|
int level,
|
||||||
|
void* workspace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
DEBUGLOG(6, "ZSTD_splitBlock (level=%i)", level);
|
||||||
|
assert(0<=level && level<=4);
|
||||||
|
if (level == 0)
|
||||||
|
return ZSTD_splitBlock_fromBorders(blockStart, blockSize, workspace, wkspSize);
|
||||||
|
/* level >= 1*/
|
||||||
|
return ZSTD_splitBlock_byChunks(blockStart, blockSize, level-1, workspace, wkspSize);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_PRESPLIT_H
|
||||||
|
#define ZSTD_PRESPLIT_H
|
||||||
|
|
||||||
|
#include <linux/types.h> /* size_t */
|
||||||
|
|
||||||
|
#define ZSTD_SLIPBLOCK_WORKSPACESIZE 8208
|
||||||
|
|
||||||
|
/* ZSTD_splitBlock():
|
||||||
|
* @level must be a value between 0 and 4.
|
||||||
|
* higher levels spend more energy to detect block boundaries.
|
||||||
|
* @workspace must be aligned for size_t.
|
||||||
|
* @wkspSize must be at least >= ZSTD_SLIPBLOCK_WORKSPACESIZE
|
||||||
|
* note:
|
||||||
|
* For the time being, this function only accepts full 128 KB blocks.
|
||||||
|
* Therefore, @blockSize must be == 128 KB.
|
||||||
|
* While this could be extended to smaller sizes in the future,
|
||||||
|
* it is not yet clear if this would be useful. TBD.
|
||||||
|
*/
|
||||||
|
size_t ZSTD_splitBlock(const void* blockStart, size_t blockSize,
|
||||||
|
int level,
|
||||||
|
void* workspace, size_t wkspSize);
|
||||||
|
|
||||||
|
#endif /* ZSTD_PRESPLIT_H */
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -14,12 +15,12 @@
|
||||||
/*-*******************************************************
|
/*-*******************************************************
|
||||||
* Dependencies
|
* Dependencies
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */
|
||||||
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
||||||
#include "../common/cpu.h" /* bmi2 */
|
#include "../common/cpu.h" /* bmi2 */
|
||||||
#include "../common/mem.h" /* low level memory routines */
|
#include "../common/mem.h" /* low level memory routines */
|
||||||
#define FSE_STATIC_LINKING_ONLY
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
#include "../common/fse.h"
|
#include "../common/fse.h"
|
||||||
#define HUF_STATIC_LINKING_ONLY
|
|
||||||
#include "../common/huf.h"
|
#include "../common/huf.h"
|
||||||
#include "zstd_decompress_internal.h"
|
#include "zstd_decompress_internal.h"
|
||||||
#include "zstd_ddict.h"
|
#include "zstd_ddict.h"
|
||||||
|
|
@ -131,7 +132,7 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
|
||||||
ZSTD_memcpy(internalBuffer, dict, dictSize);
|
ZSTD_memcpy(internalBuffer, dict, dictSize);
|
||||||
}
|
}
|
||||||
ddict->dictSize = dictSize;
|
ddict->dictSize = dictSize;
|
||||||
ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */
|
||||||
|
|
||||||
/* parse dictionary content */
|
/* parse dictionary content */
|
||||||
FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , "");
|
FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , "");
|
||||||
|
|
@ -237,5 +238,5 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)
|
||||||
unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
|
unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
|
||||||
{
|
{
|
||||||
if (ddict==NULL) return 0;
|
if (ddict==NULL) return 0;
|
||||||
return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
|
return ddict->dictID;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -53,13 +54,15 @@
|
||||||
* Dependencies
|
* Dependencies
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
||||||
|
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */
|
||||||
|
#include "../common/error_private.h"
|
||||||
|
#include "../common/zstd_internal.h" /* blockProperties_t */
|
||||||
#include "../common/mem.h" /* low level memory routines */
|
#include "../common/mem.h" /* low level memory routines */
|
||||||
|
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||||
#define FSE_STATIC_LINKING_ONLY
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
#include "../common/fse.h"
|
#include "../common/fse.h"
|
||||||
#define HUF_STATIC_LINKING_ONLY
|
|
||||||
#include "../common/huf.h"
|
#include "../common/huf.h"
|
||||||
#include <linux/xxhash.h> /* xxh64_reset, xxh64_update, xxh64_digest, XXH64 */
|
#include <linux/xxhash.h> /* xxh64_reset, xxh64_update, xxh64_digest, XXH64 */
|
||||||
#include "../common/zstd_internal.h" /* blockProperties_t */
|
|
||||||
#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
|
#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
|
||||||
#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
|
#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
|
||||||
#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
|
#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
|
||||||
|
|
@ -237,6 +240,8 @@ static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)
|
||||||
dctx->outBufferMode = ZSTD_bm_buffered;
|
dctx->outBufferMode = ZSTD_bm_buffered;
|
||||||
dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
|
dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
|
||||||
dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;
|
dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;
|
||||||
|
dctx->disableHufAsm = 0;
|
||||||
|
dctx->maxBlockSizeParam = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||||
|
|
@ -253,6 +258,7 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||||
dctx->streamStage = zdss_init;
|
dctx->streamStage = zdss_init;
|
||||||
dctx->noForwardProgress = 0;
|
dctx->noForwardProgress = 0;
|
||||||
dctx->oversizedDuration = 0;
|
dctx->oversizedDuration = 0;
|
||||||
|
dctx->isFrameDecompression = 1;
|
||||||
#if DYNAMIC_BMI2
|
#if DYNAMIC_BMI2
|
||||||
dctx->bmi2 = ZSTD_cpuSupportsBmi2();
|
dctx->bmi2 = ZSTD_cpuSupportsBmi2();
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -421,16 +427,40 @@ size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
|
||||||
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
|
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
|
||||||
* @return : 0, `zfhPtr` is correctly filled,
|
* @return : 0, `zfhPtr` is correctly filled,
|
||||||
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
||||||
* or an error code, which can be tested using ZSTD_isError() */
|
** or an error code, which can be tested using ZSTD_isError() */
|
||||||
size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
|
size_t ZSTD_getFrameHeader_advanced(ZSTD_FrameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
|
||||||
{
|
{
|
||||||
const BYTE* ip = (const BYTE*)src;
|
const BYTE* ip = (const BYTE*)src;
|
||||||
size_t const minInputSize = ZSTD_startingInputLength(format);
|
size_t const minInputSize = ZSTD_startingInputLength(format);
|
||||||
|
|
||||||
ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
|
DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize);
|
||||||
if (srcSize < minInputSize) return minInputSize;
|
|
||||||
RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
|
|
||||||
|
|
||||||
|
if (srcSize > 0) {
|
||||||
|
/* note : technically could be considered an assert(), since it's an invalid entry */
|
||||||
|
RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0");
|
||||||
|
}
|
||||||
|
if (srcSize < minInputSize) {
|
||||||
|
if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) {
|
||||||
|
/* when receiving less than @minInputSize bytes,
|
||||||
|
* control these bytes at least correspond to a supported magic number
|
||||||
|
* in order to error out early if they don't.
|
||||||
|
**/
|
||||||
|
size_t const toCopy = MIN(4, srcSize);
|
||||||
|
unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER);
|
||||||
|
assert(src != NULL);
|
||||||
|
ZSTD_memcpy(hbuf, src, toCopy);
|
||||||
|
if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) {
|
||||||
|
/* not a zstd frame : let's check if it's a skippable frame */
|
||||||
|
MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START);
|
||||||
|
ZSTD_memcpy(hbuf, src, toCopy);
|
||||||
|
if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) {
|
||||||
|
RETURN_ERROR(prefix_unknown,
|
||||||
|
"first bytes don't correspond to any supported magic number");
|
||||||
|
} } }
|
||||||
|
return minInputSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */
|
||||||
if ( (format != ZSTD_f_zstd1_magicless)
|
if ( (format != ZSTD_f_zstd1_magicless)
|
||||||
&& (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
|
&& (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
|
||||||
if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||||
|
|
@ -438,8 +468,10 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
|
||||||
if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
|
if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
|
||||||
return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
|
return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
|
||||||
ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));
|
ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));
|
||||||
zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
|
|
||||||
zfhPtr->frameType = ZSTD_skippableFrame;
|
zfhPtr->frameType = ZSTD_skippableFrame;
|
||||||
|
zfhPtr->dictID = MEM_readLE32(src) - ZSTD_MAGIC_SKIPPABLE_START;
|
||||||
|
zfhPtr->headerSize = ZSTD_SKIPPABLEHEADERSIZE;
|
||||||
|
zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
RETURN_ERROR(prefix_unknown, "");
|
RETURN_ERROR(prefix_unknown, "");
|
||||||
|
|
@ -508,7 +540,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
|
||||||
* @return : 0, `zfhPtr` is correctly filled,
|
* @return : 0, `zfhPtr` is correctly filled,
|
||||||
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
||||||
* or an error code, which can be tested using ZSTD_isError() */
|
* or an error code, which can be tested using ZSTD_isError() */
|
||||||
size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
|
size_t ZSTD_getFrameHeader(ZSTD_FrameHeader* zfhPtr, const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
|
return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
|
||||||
}
|
}
|
||||||
|
|
@ -520,7 +552,7 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
|
||||||
* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
|
* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
|
||||||
unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
|
unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
|
||||||
{
|
{
|
||||||
{ ZSTD_frameHeader zfh;
|
{ ZSTD_FrameHeader zfh;
|
||||||
if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
|
if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
|
||||||
return ZSTD_CONTENTSIZE_ERROR;
|
return ZSTD_CONTENTSIZE_ERROR;
|
||||||
if (zfh.frameType == ZSTD_skippableFrame) {
|
if (zfh.frameType == ZSTD_skippableFrame) {
|
||||||
|
|
@ -540,28 +572,30 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize)
|
||||||
sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
|
sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
|
||||||
RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
|
RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
|
||||||
frameParameter_unsupported, "");
|
frameParameter_unsupported, "");
|
||||||
{
|
{ size_t const skippableSize = skippableHeaderSize + sizeU32;
|
||||||
size_t const skippableSize = skippableHeaderSize + sizeU32;
|
|
||||||
RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
|
RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
|
||||||
return skippableSize;
|
return skippableSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ZSTD_readSkippableFrame() :
|
/*! ZSTD_readSkippableFrame() :
|
||||||
* Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer.
|
* Retrieves content of a skippable frame, and writes it to dst buffer.
|
||||||
*
|
*
|
||||||
* The parameter magicVariant will receive the magicVariant that was supplied when the frame was written,
|
* The parameter magicVariant will receive the magicVariant that was supplied when the frame was written,
|
||||||
* i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested
|
* i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested
|
||||||
* in the magicVariant.
|
* in the magicVariant.
|
||||||
*
|
*
|
||||||
* Returns an error if destination buffer is not large enough, or if the frame is not skippable.
|
* Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame.
|
||||||
*
|
*
|
||||||
* @return : number of bytes written or a ZSTD error.
|
* @return : number of bytes written or a ZSTD error.
|
||||||
*/
|
*/
|
||||||
ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant,
|
size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity,
|
||||||
|
unsigned* magicVariant, /* optional, can be NULL */
|
||||||
const void* src, size_t srcSize)
|
const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
U32 const magicNumber = MEM_readLE32(src);
|
RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");
|
||||||
|
|
||||||
|
{ U32 const magicNumber = MEM_readLE32(src);
|
||||||
size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);
|
size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);
|
||||||
size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;
|
size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;
|
||||||
|
|
||||||
|
|
@ -576,12 +610,13 @@ ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsign
|
||||||
if (magicVariant != NULL)
|
if (magicVariant != NULL)
|
||||||
*magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;
|
*magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;
|
||||||
return skippableContentSize;
|
return skippableContentSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_findDecompressedSize() :
|
/* ZSTD_findDecompressedSize() :
|
||||||
* compatible with legacy mode
|
|
||||||
* `srcSize` must be the exact length of some number of ZSTD compressed and/or
|
* `srcSize` must be the exact length of some number of ZSTD compressed and/or
|
||||||
* skippable frames
|
* skippable frames
|
||||||
|
* note: compatible with legacy mode
|
||||||
* @return : decompressed size of the frames contained */
|
* @return : decompressed size of the frames contained */
|
||||||
unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
|
|
@ -592,9 +627,7 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||||
|
|
||||||
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||||
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
|
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
|
||||||
if (ZSTD_isError(skippableSize)) {
|
if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR;
|
||||||
return ZSTD_CONTENTSIZE_ERROR;
|
|
||||||
}
|
|
||||||
assert(skippableSize <= srcSize);
|
assert(skippableSize <= srcSize);
|
||||||
|
|
||||||
src = (const BYTE *)src + skippableSize;
|
src = (const BYTE *)src + skippableSize;
|
||||||
|
|
@ -602,17 +635,17 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
|
{ unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize);
|
||||||
if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
|
if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs;
|
||||||
|
|
||||||
/* check for overflow */
|
if (totalDstSize + fcs < totalDstSize)
|
||||||
if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
|
return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */
|
||||||
totalDstSize += ret;
|
totalDstSize += fcs;
|
||||||
}
|
}
|
||||||
|
/* skip to next frame */
|
||||||
{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
|
{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
|
||||||
if (ZSTD_isError(frameSrcSize)) {
|
if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR;
|
||||||
return ZSTD_CONTENTSIZE_ERROR;
|
assert(frameSrcSize <= srcSize);
|
||||||
}
|
|
||||||
|
|
||||||
src = (const BYTE *)src + frameSrcSize;
|
src = (const BYTE *)src + frameSrcSize;
|
||||||
srcSize -= frameSrcSize;
|
srcSize -= frameSrcSize;
|
||||||
|
|
@ -676,13 +709,13 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
|
||||||
return frameSizeInfo;
|
return frameSizeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
|
static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize, ZSTD_format_e format)
|
||||||
{
|
{
|
||||||
ZSTD_frameSizeInfo frameSizeInfo;
|
ZSTD_frameSizeInfo frameSizeInfo;
|
||||||
ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
|
ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
|
||||||
|
|
||||||
|
|
||||||
if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
|
if (format == ZSTD_f_zstd1 && (srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
|
||||||
&& (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
&& (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||||
frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
|
frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
|
||||||
assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
|
assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
|
||||||
|
|
@ -693,10 +726,10 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
|
||||||
const BYTE* const ipstart = ip;
|
const BYTE* const ipstart = ip;
|
||||||
size_t remainingSize = srcSize;
|
size_t remainingSize = srcSize;
|
||||||
size_t nbBlocks = 0;
|
size_t nbBlocks = 0;
|
||||||
ZSTD_frameHeader zfh;
|
ZSTD_FrameHeader zfh;
|
||||||
|
|
||||||
/* Extract Frame Header */
|
/* Extract Frame Header */
|
||||||
{ size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
|
{ size_t const ret = ZSTD_getFrameHeader_advanced(&zfh, src, srcSize, format);
|
||||||
if (ZSTD_isError(ret))
|
if (ZSTD_isError(ret))
|
||||||
return ZSTD_errorFrameSizeInfo(ret);
|
return ZSTD_errorFrameSizeInfo(ret);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
|
|
@ -730,28 +763,31 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
|
||||||
ip += 4;
|
ip += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frameSizeInfo.nbBlocks = nbBlocks;
|
||||||
frameSizeInfo.compressedSize = (size_t)(ip - ipstart);
|
frameSizeInfo.compressedSize = (size_t)(ip - ipstart);
|
||||||
frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
|
frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
|
||||||
? zfh.frameContentSize
|
? zfh.frameContentSize
|
||||||
: nbBlocks * zfh.blockSizeMax;
|
: (unsigned long long)nbBlocks * zfh.blockSizeMax;
|
||||||
return frameSizeInfo;
|
return frameSizeInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t ZSTD_findFrameCompressedSize_advanced(const void *src, size_t srcSize, ZSTD_format_e format) {
|
||||||
|
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, format);
|
||||||
|
return frameSizeInfo.compressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
/* ZSTD_findFrameCompressedSize() :
|
/* ZSTD_findFrameCompressedSize() :
|
||||||
* compatible with legacy mode
|
* See docs in zstd.h
|
||||||
* `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
|
* Note: compatible with legacy mode */
|
||||||
* `srcSize` must be at least as large as the frame contained
|
|
||||||
* @return : the compressed size of the frame starting at `src` */
|
|
||||||
size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
|
size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
|
||||||
{
|
{
|
||||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
|
return ZSTD_findFrameCompressedSize_advanced(src, srcSize, ZSTD_f_zstd1);
|
||||||
return frameSizeInfo.compressedSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_decompressBound() :
|
/* ZSTD_decompressBound() :
|
||||||
* compatible with legacy mode
|
* compatible with legacy mode
|
||||||
* `src` must point to the start of a ZSTD frame or a skippeable frame
|
* `src` must point to the start of a ZSTD frame or a skippable frame
|
||||||
* `srcSize` must be at least as large as the frame contained
|
* `srcSize` must be at least as large as the frame contained
|
||||||
* @return : the maximum decompressed size of the compressed source
|
* @return : the maximum decompressed size of the compressed source
|
||||||
*/
|
*/
|
||||||
|
|
@ -760,7 +796,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
|
||||||
unsigned long long bound = 0;
|
unsigned long long bound = 0;
|
||||||
/* Iterate over each frame */
|
/* Iterate over each frame */
|
||||||
while (srcSize > 0) {
|
while (srcSize > 0) {
|
||||||
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
|
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1);
|
||||||
size_t const compressedSize = frameSizeInfo.compressedSize;
|
size_t const compressedSize = frameSizeInfo.compressedSize;
|
||||||
unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
|
unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
|
||||||
if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
|
if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
|
||||||
|
|
@ -773,6 +809,48 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
|
||||||
return bound;
|
return bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_decompressionMargin(void const* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
size_t margin = 0;
|
||||||
|
unsigned maxBlockSize = 0;
|
||||||
|
|
||||||
|
/* Iterate over each frame */
|
||||||
|
while (srcSize > 0) {
|
||||||
|
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1);
|
||||||
|
size_t const compressedSize = frameSizeInfo.compressedSize;
|
||||||
|
unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
|
||||||
|
ZSTD_FrameHeader zfh;
|
||||||
|
|
||||||
|
FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), "");
|
||||||
|
if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
|
||||||
|
return ERROR(corruption_detected);
|
||||||
|
|
||||||
|
if (zfh.frameType == ZSTD_frame) {
|
||||||
|
/* Add the frame header to our margin */
|
||||||
|
margin += zfh.headerSize;
|
||||||
|
/* Add the checksum to our margin */
|
||||||
|
margin += zfh.checksumFlag ? 4 : 0;
|
||||||
|
/* Add 3 bytes per block */
|
||||||
|
margin += 3 * frameSizeInfo.nbBlocks;
|
||||||
|
|
||||||
|
/* Compute the max block size */
|
||||||
|
maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax);
|
||||||
|
} else {
|
||||||
|
assert(zfh.frameType == ZSTD_skippableFrame);
|
||||||
|
/* Add the entire skippable frame size to our margin. */
|
||||||
|
margin += compressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(srcSize >= compressedSize);
|
||||||
|
src = (const BYTE*)src + compressedSize;
|
||||||
|
srcSize -= compressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the max block size back to the margin. */
|
||||||
|
margin += maxBlockSize;
|
||||||
|
|
||||||
|
return margin;
|
||||||
|
}
|
||||||
|
|
||||||
/*-*************************************************************
|
/*-*************************************************************
|
||||||
* Frame decoding
|
* Frame decoding
|
||||||
|
|
@ -815,7 +893,7 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
|
||||||
return regenSize;
|
return regenSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming)
|
static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, int streaming)
|
||||||
{
|
{
|
||||||
(void)dctx;
|
(void)dctx;
|
||||||
(void)uncompressedSize;
|
(void)uncompressedSize;
|
||||||
|
|
@ -856,6 +934,10 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||||
ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
|
ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shrink the blockSizeMax if enabled */
|
||||||
|
if (dctx->maxBlockSizeParam != 0)
|
||||||
|
dctx->fParams.blockSizeMax = MIN(dctx->fParams.blockSizeMax, (unsigned)dctx->maxBlockSizeParam);
|
||||||
|
|
||||||
/* Loop on each block */
|
/* Loop on each block */
|
||||||
while (1) {
|
while (1) {
|
||||||
BYTE* oBlockEnd = oend;
|
BYTE* oBlockEnd = oend;
|
||||||
|
|
@ -888,7 +970,8 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||||
switch(blockProperties.blockType)
|
switch(blockProperties.blockType)
|
||||||
{
|
{
|
||||||
case bt_compressed:
|
case bt_compressed:
|
||||||
decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, /* frame */ 1, not_streaming);
|
assert(dctx->isFrameDecompression == 1);
|
||||||
|
decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, not_streaming);
|
||||||
break;
|
break;
|
||||||
case bt_raw :
|
case bt_raw :
|
||||||
/* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */
|
/* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */
|
||||||
|
|
@ -901,12 +984,14 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||||
default:
|
default:
|
||||||
RETURN_ERROR(corruption_detected, "invalid block type");
|
RETURN_ERROR(corruption_detected, "invalid block type");
|
||||||
}
|
}
|
||||||
|
FORWARD_IF_ERROR(decodedSize, "Block decompression failure");
|
||||||
if (ZSTD_isError(decodedSize)) return decodedSize;
|
DEBUGLOG(5, "Decompressed block of dSize = %u", (unsigned)decodedSize);
|
||||||
if (dctx->validateChecksum)
|
if (dctx->validateChecksum) {
|
||||||
xxh64_update(&dctx->xxhState, op, decodedSize);
|
xxh64_update(&dctx->xxhState, op, decodedSize);
|
||||||
if (decodedSize != 0)
|
}
|
||||||
|
if (decodedSize) /* support dst = NULL,0 */ {
|
||||||
op += decodedSize;
|
op += decodedSize;
|
||||||
|
}
|
||||||
assert(ip != NULL);
|
assert(ip != NULL);
|
||||||
ip += cBlockSize;
|
ip += cBlockSize;
|
||||||
remainingSrcSize -= cBlockSize;
|
remainingSrcSize -= cBlockSize;
|
||||||
|
|
@ -930,12 +1015,15 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||||
}
|
}
|
||||||
ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);
|
ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);
|
||||||
/* Allow caller to get size read */
|
/* Allow caller to get size read */
|
||||||
|
DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %i, consuming %i bytes of input", (int)(op-ostart), (int)(ip - (const BYTE*)*srcPtr));
|
||||||
*srcPtr = ip;
|
*srcPtr = ip;
|
||||||
*srcSizePtr = remainingSrcSize;
|
*srcSizePtr = remainingSrcSize;
|
||||||
return (size_t)(op-ostart);
|
return (size_t)(op-ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
static
|
||||||
|
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||||
|
size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const void* dict, size_t dictSize,
|
const void* dict, size_t dictSize,
|
||||||
|
|
@ -955,17 +1043,18 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||||
while (srcSize >= ZSTD_startingInputLength(dctx->format)) {
|
while (srcSize >= ZSTD_startingInputLength(dctx->format)) {
|
||||||
|
|
||||||
|
|
||||||
{ U32 const magicNumber = MEM_readLE32(src);
|
if (dctx->format == ZSTD_f_zstd1 && srcSize >= 4) {
|
||||||
DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
|
U32 const magicNumber = MEM_readLE32(src);
|
||||||
(unsigned)magicNumber, ZSTD_MAGICNUMBER);
|
DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber);
|
||||||
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||||
|
/* skippable frame detected : skip it */
|
||||||
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
|
size_t const skippableSize = readSkippableFrameSize(src, srcSize);
|
||||||
FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");
|
FORWARD_IF_ERROR(skippableSize, "invalid skippable frame");
|
||||||
assert(skippableSize <= srcSize);
|
assert(skippableSize <= srcSize);
|
||||||
|
|
||||||
src = (const BYTE *)src + skippableSize;
|
src = (const BYTE *)src + skippableSize;
|
||||||
srcSize -= skippableSize;
|
srcSize -= skippableSize;
|
||||||
continue;
|
continue; /* check next frame */
|
||||||
} }
|
} }
|
||||||
|
|
||||||
if (ddict) {
|
if (ddict) {
|
||||||
|
|
@ -1061,8 +1150,8 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr
|
||||||
size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
|
size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed,
|
* Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we
|
||||||
* we allow taking a partial block as the input. Currently only raw uncompressed blocks can
|
* allow taking a partial block as the input. Currently only raw uncompressed blocks can
|
||||||
* be streamed.
|
* be streamed.
|
||||||
*
|
*
|
||||||
* For blocks that can be streamed, this allows us to reduce the latency until we produce
|
* For blocks that can be streamed, this allows us to reduce the latency until we produce
|
||||||
|
|
@ -1181,7 +1270,8 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||||
{
|
{
|
||||||
case bt_compressed:
|
case bt_compressed:
|
||||||
DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
|
DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
|
||||||
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming);
|
assert(dctx->isFrameDecompression == 1);
|
||||||
|
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, is_streaming);
|
||||||
dctx->expected = 0; /* Streaming not supported */
|
dctx->expected = 0; /* Streaming not supported */
|
||||||
break;
|
break;
|
||||||
case bt_raw :
|
case bt_raw :
|
||||||
|
|
@ -1250,6 +1340,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||||
case ZSTDds_decodeSkippableHeader:
|
case ZSTDds_decodeSkippableHeader:
|
||||||
assert(src != NULL);
|
assert(src != NULL);
|
||||||
assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
|
assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
|
||||||
|
assert(dctx->format != ZSTD_f_zstd1_magicless);
|
||||||
ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
|
ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
|
||||||
dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
|
dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
|
||||||
dctx->stage = ZSTDds_skipFrame;
|
dctx->stage = ZSTDds_skipFrame;
|
||||||
|
|
@ -1262,7 +1353,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0); /* impossible */
|
assert(0); /* impossible */
|
||||||
RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
|
RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1303,11 +1394,11 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
|
||||||
/* in minimal huffman, we always use X1 variants */
|
/* in minimal huffman, we always use X1 variants */
|
||||||
size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
|
size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
|
||||||
dictPtr, dictEnd - dictPtr,
|
dictPtr, dictEnd - dictPtr,
|
||||||
workspace, workspaceSize);
|
workspace, workspaceSize, /* flags */ 0);
|
||||||
#else
|
#else
|
||||||
size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
|
size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
|
||||||
dictPtr, (size_t)(dictEnd - dictPtr),
|
dictPtr, (size_t)(dictEnd - dictPtr),
|
||||||
workspace, workspaceSize);
|
workspace, workspaceSize, /* flags */ 0);
|
||||||
#endif
|
#endif
|
||||||
RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
|
RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
|
||||||
dictPtr += hSize;
|
dictPtr += hSize;
|
||||||
|
|
@ -1403,10 +1494,11 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
|
||||||
dctx->prefixStart = NULL;
|
dctx->prefixStart = NULL;
|
||||||
dctx->virtualStart = NULL;
|
dctx->virtualStart = NULL;
|
||||||
dctx->dictEnd = NULL;
|
dctx->dictEnd = NULL;
|
||||||
dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */
|
||||||
dctx->litEntropy = dctx->fseEntropy = 0;
|
dctx->litEntropy = dctx->fseEntropy = 0;
|
||||||
dctx->dictID = 0;
|
dctx->dictID = 0;
|
||||||
dctx->bType = bt_reserved;
|
dctx->bType = bt_reserved;
|
||||||
|
dctx->isFrameDecompression = 1;
|
||||||
ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
|
ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
|
||||||
ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
|
ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
|
||||||
dctx->LLTptr = dctx->entropy.LLTable;
|
dctx->LLTptr = dctx->entropy.LLTable;
|
||||||
|
|
@ -1465,7 +1557,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
|
||||||
* This could for one of the following reasons :
|
* This could for one of the following reasons :
|
||||||
* - The frame does not require a dictionary (most common case).
|
* - The frame does not require a dictionary (most common case).
|
||||||
* - The frame was built with dictID intentionally removed.
|
* - The frame was built with dictID intentionally removed.
|
||||||
* Needed dictionary is a hidden information.
|
* Needed dictionary is a hidden piece of information.
|
||||||
* Note : this use case also happens when using a non-conformant dictionary.
|
* Note : this use case also happens when using a non-conformant dictionary.
|
||||||
* - `srcSize` is too small, and as a result, frame header could not be decoded.
|
* - `srcSize` is too small, and as a result, frame header could not be decoded.
|
||||||
* Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
|
* Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
|
||||||
|
|
@ -1474,7 +1566,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
|
||||||
* ZSTD_getFrameHeader(), which will provide a more precise error code. */
|
* ZSTD_getFrameHeader(), which will provide a more precise error code. */
|
||||||
unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
|
unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
|
ZSTD_FrameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 };
|
||||||
size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
|
size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
|
||||||
if (ZSTD_isError(hError)) return 0;
|
if (ZSTD_isError(hError)) return 0;
|
||||||
return zfp.dictID;
|
return zfp.dictID;
|
||||||
|
|
@ -1581,7 +1673,9 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
|
||||||
size_t ZSTD_initDStream(ZSTD_DStream* zds)
|
size_t ZSTD_initDStream(ZSTD_DStream* zds)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_initDStream");
|
DEBUGLOG(4, "ZSTD_initDStream");
|
||||||
return ZSTD_initDStream_usingDDict(zds, NULL);
|
FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), "");
|
||||||
|
FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), "");
|
||||||
|
return ZSTD_startingInputLength(zds->format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_initDStream_usingDDict() :
|
/* ZSTD_initDStream_usingDDict() :
|
||||||
|
|
@ -1589,6 +1683,7 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds)
|
||||||
* this function cannot fail */
|
* this function cannot fail */
|
||||||
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
|
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(4, "ZSTD_initDStream_usingDDict");
|
||||||
FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");
|
FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");
|
||||||
FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");
|
FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");
|
||||||
return ZSTD_startingInputLength(dctx->format);
|
return ZSTD_startingInputLength(dctx->format);
|
||||||
|
|
@ -1599,6 +1694,7 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
|
||||||
* this function cannot fail */
|
* this function cannot fail */
|
||||||
size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
|
size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(4, "ZSTD_resetDStream");
|
||||||
FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");
|
FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");
|
||||||
return ZSTD_startingInputLength(dctx->format);
|
return ZSTD_startingInputLength(dctx->format);
|
||||||
}
|
}
|
||||||
|
|
@ -1670,6 +1766,15 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
|
||||||
bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;
|
bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;
|
||||||
bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;
|
bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;
|
||||||
return bounds;
|
return bounds;
|
||||||
|
case ZSTD_d_disableHuffmanAssembly:
|
||||||
|
bounds.lowerBound = 0;
|
||||||
|
bounds.upperBound = 1;
|
||||||
|
return bounds;
|
||||||
|
case ZSTD_d_maxBlockSize:
|
||||||
|
bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN;
|
||||||
|
bounds.upperBound = ZSTD_BLOCKSIZE_MAX;
|
||||||
|
return bounds;
|
||||||
|
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
bounds.error = ERROR(parameter_unsupported);
|
bounds.error = ERROR(parameter_unsupported);
|
||||||
|
|
@ -1710,6 +1815,12 @@ size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value
|
||||||
case ZSTD_d_refMultipleDDicts:
|
case ZSTD_d_refMultipleDDicts:
|
||||||
*value = (int)dctx->refMultipleDDicts;
|
*value = (int)dctx->refMultipleDDicts;
|
||||||
return 0;
|
return 0;
|
||||||
|
case ZSTD_d_disableHuffmanAssembly:
|
||||||
|
*value = (int)dctx->disableHufAsm;
|
||||||
|
return 0;
|
||||||
|
case ZSTD_d_maxBlockSize:
|
||||||
|
*value = dctx->maxBlockSizeParam;
|
||||||
|
return 0;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
RETURN_ERROR(parameter_unsupported, "");
|
RETURN_ERROR(parameter_unsupported, "");
|
||||||
|
|
@ -1743,6 +1854,14 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value
|
||||||
}
|
}
|
||||||
dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;
|
dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;
|
||||||
return 0;
|
return 0;
|
||||||
|
case ZSTD_d_disableHuffmanAssembly:
|
||||||
|
CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value);
|
||||||
|
dctx->disableHufAsm = value != 0;
|
||||||
|
return 0;
|
||||||
|
case ZSTD_d_maxBlockSize:
|
||||||
|
if (value != 0) CHECK_DBOUNDS(ZSTD_d_maxBlockSize, value);
|
||||||
|
dctx->maxBlockSizeParam = value;
|
||||||
|
return 0;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
RETURN_ERROR(parameter_unsupported, "");
|
RETURN_ERROR(parameter_unsupported, "");
|
||||||
|
|
@ -1754,6 +1873,7 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
|
||||||
|| (reset == ZSTD_reset_session_and_parameters) ) {
|
|| (reset == ZSTD_reset_session_and_parameters) ) {
|
||||||
dctx->streamStage = zdss_init;
|
dctx->streamStage = zdss_init;
|
||||||
dctx->noForwardProgress = 0;
|
dctx->noForwardProgress = 0;
|
||||||
|
dctx->isFrameDecompression = 1;
|
||||||
}
|
}
|
||||||
if ( (reset == ZSTD_reset_parameters)
|
if ( (reset == ZSTD_reset_parameters)
|
||||||
|| (reset == ZSTD_reset_session_and_parameters) ) {
|
|| (reset == ZSTD_reset_session_and_parameters) ) {
|
||||||
|
|
@ -1770,11 +1890,17 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
|
||||||
return ZSTD_sizeof_DCtx(dctx);
|
return ZSTD_sizeof_DCtx(dctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
|
static size_t ZSTD_decodingBufferSize_internal(unsigned long long windowSize, unsigned long long frameContentSize, size_t blockSizeMax)
|
||||||
{
|
{
|
||||||
size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
size_t const blockSize = MIN((size_t)MIN(windowSize, ZSTD_BLOCKSIZE_MAX), blockSizeMax);
|
||||||
/* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/
|
/* We need blockSize + WILDCOPY_OVERLENGTH worth of buffer so that if a block
|
||||||
unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2);
|
* ends at windowSize + WILDCOPY_OVERLENGTH + 1 bytes, we can start writing
|
||||||
|
* the block at the beginning of the output buffer, and maintain a full window.
|
||||||
|
*
|
||||||
|
* We need another blockSize worth of buffer so that we can store split
|
||||||
|
* literals at the end of the block without overwriting the extDict window.
|
||||||
|
*/
|
||||||
|
unsigned long long const neededRBSize = windowSize + (blockSize * 2) + (WILDCOPY_OVERLENGTH * 2);
|
||||||
unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
|
unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
|
||||||
size_t const minRBSize = (size_t) neededSize;
|
size_t const minRBSize = (size_t) neededSize;
|
||||||
RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
|
RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
|
||||||
|
|
@ -1782,6 +1908,11 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||||
return minRBSize;
|
return minRBSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
|
||||||
|
{
|
||||||
|
return ZSTD_decodingBufferSize_internal(windowSize, frameContentSize, ZSTD_BLOCKSIZE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
size_t ZSTD_estimateDStreamSize(size_t windowSize)
|
size_t ZSTD_estimateDStreamSize(size_t windowSize)
|
||||||
{
|
{
|
||||||
size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
||||||
|
|
@ -1793,7 +1924,7 @@ size_t ZSTD_estimateDStreamSize(size_t windowSize)
|
||||||
size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
|
size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
|
U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
|
||||||
ZSTD_frameHeader zfh;
|
ZSTD_FrameHeader zfh;
|
||||||
size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
|
size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
|
||||||
if (ZSTD_isError(err)) return err;
|
if (ZSTD_isError(err)) return err;
|
||||||
RETURN_ERROR_IF(err>0, srcSize_wrong, "");
|
RETURN_ERROR_IF(err>0, srcSize_wrong, "");
|
||||||
|
|
@ -1888,6 +2019,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
U32 someMoreWork = 1;
|
U32 someMoreWork = 1;
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_decompressStream");
|
DEBUGLOG(5, "ZSTD_decompressStream");
|
||||||
|
assert(zds != NULL);
|
||||||
RETURN_ERROR_IF(
|
RETURN_ERROR_IF(
|
||||||
input->pos > input->size,
|
input->pos > input->size,
|
||||||
srcSize_wrong,
|
srcSize_wrong,
|
||||||
|
|
@ -1918,7 +2050,6 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
if (zds->refMultipleDDicts && zds->ddictSet) {
|
if (zds->refMultipleDDicts && zds->ddictSet) {
|
||||||
ZSTD_DCtx_selectFrameDDict(zds);
|
ZSTD_DCtx_selectFrameDDict(zds);
|
||||||
}
|
}
|
||||||
DEBUGLOG(5, "header size : %u", (U32)hSize);
|
|
||||||
if (ZSTD_isError(hSize)) {
|
if (ZSTD_isError(hSize)) {
|
||||||
return hSize; /* error */
|
return hSize; /* error */
|
||||||
}
|
}
|
||||||
|
|
@ -1932,6 +2063,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
zds->lhSize += remainingInput;
|
zds->lhSize += remainingInput;
|
||||||
}
|
}
|
||||||
input->pos = input->size;
|
input->pos = input->size;
|
||||||
|
/* check first few bytes */
|
||||||
|
FORWARD_IF_ERROR(
|
||||||
|
ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format),
|
||||||
|
"First few bytes detected incorrect" );
|
||||||
|
/* return hint input size */
|
||||||
return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
|
return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
|
||||||
}
|
}
|
||||||
assert(ip != NULL);
|
assert(ip != NULL);
|
||||||
|
|
@ -1943,14 +2079,15 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
|
if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
|
||||||
&& zds->fParams.frameType != ZSTD_skippableFrame
|
&& zds->fParams.frameType != ZSTD_skippableFrame
|
||||||
&& (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
|
&& (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
|
||||||
size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart));
|
size_t const cSize = ZSTD_findFrameCompressedSize_advanced(istart, (size_t)(iend-istart), zds->format);
|
||||||
if (cSize <= (size_t)(iend-istart)) {
|
if (cSize <= (size_t)(iend-istart)) {
|
||||||
/* shortcut : using single-pass mode */
|
/* shortcut : using single-pass mode */
|
||||||
size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
|
size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
|
||||||
if (ZSTD_isError(decompressedSize)) return decompressedSize;
|
if (ZSTD_isError(decompressedSize)) return decompressedSize;
|
||||||
DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
|
DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()");
|
||||||
|
assert(istart != NULL);
|
||||||
ip = istart + cSize;
|
ip = istart + cSize;
|
||||||
op += decompressedSize;
|
op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */
|
||||||
zds->expected = 0;
|
zds->expected = 0;
|
||||||
zds->streamStage = zdss_init;
|
zds->streamStage = zdss_init;
|
||||||
someMoreWork = 0;
|
someMoreWork = 0;
|
||||||
|
|
@ -1969,7 +2106,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
DEBUGLOG(4, "Consume header");
|
DEBUGLOG(4, "Consume header");
|
||||||
FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");
|
FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");
|
||||||
|
|
||||||
if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
|
if (zds->format == ZSTD_f_zstd1
|
||||||
|
&& (MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
|
||||||
zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
|
zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
|
||||||
zds->stage = ZSTDds_skipFrame;
|
zds->stage = ZSTDds_skipFrame;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1985,11 +2123,13 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
|
zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
|
||||||
RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
|
RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
|
||||||
frameParameter_windowTooLarge, "");
|
frameParameter_windowTooLarge, "");
|
||||||
|
if (zds->maxBlockSizeParam != 0)
|
||||||
|
zds->fParams.blockSizeMax = MIN(zds->fParams.blockSizeMax, (unsigned)zds->maxBlockSizeParam);
|
||||||
|
|
||||||
/* Adapt buffer sizes to frame header instructions */
|
/* Adapt buffer sizes to frame header instructions */
|
||||||
{ size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
|
{ size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
|
||||||
size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered
|
size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered
|
||||||
? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)
|
? ZSTD_decodingBufferSize_internal(zds->fParams.windowSize, zds->fParams.frameContentSize, zds->fParams.blockSizeMax)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
|
ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
|
||||||
|
|
@ -2034,6 +2174,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
}
|
}
|
||||||
if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
|
if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
|
||||||
FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");
|
FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");
|
||||||
|
assert(ip != NULL);
|
||||||
ip += neededInSize;
|
ip += neededInSize;
|
||||||
/* Function modifies the stage so we must break */
|
/* Function modifies the stage so we must break */
|
||||||
break;
|
break;
|
||||||
|
|
@ -2048,7 +2189,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
int const isSkipFrame = ZSTD_isSkipFrame(zds);
|
int const isSkipFrame = ZSTD_isSkipFrame(zds);
|
||||||
size_t loadedSize;
|
size_t loadedSize;
|
||||||
/* At this point we shouldn't be decompressing a block that we can stream. */
|
/* At this point we shouldn't be decompressing a block that we can stream. */
|
||||||
assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip));
|
assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)));
|
||||||
if (isSkipFrame) {
|
if (isSkipFrame) {
|
||||||
loadedSize = MIN(toLoad, (size_t)(iend-ip));
|
loadedSize = MIN(toLoad, (size_t)(iend-ip));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2057,8 +2198,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
"should never happen");
|
"should never happen");
|
||||||
loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));
|
loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));
|
||||||
}
|
}
|
||||||
|
if (loadedSize != 0) {
|
||||||
|
/* ip may be NULL */
|
||||||
ip += loadedSize;
|
ip += loadedSize;
|
||||||
zds->inPos += loadedSize;
|
zds->inPos += loadedSize;
|
||||||
|
}
|
||||||
if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
|
if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
|
||||||
|
|
||||||
/* decode loaded input */
|
/* decode loaded input */
|
||||||
|
|
@ -2068,9 +2212,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case zdss_flush:
|
case zdss_flush:
|
||||||
{ size_t const toFlushSize = zds->outEnd - zds->outStart;
|
{
|
||||||
|
size_t const toFlushSize = zds->outEnd - zds->outStart;
|
||||||
size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);
|
size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);
|
||||||
op += flushedSize;
|
|
||||||
|
op = op ? op + flushedSize : op;
|
||||||
|
|
||||||
zds->outStart += flushedSize;
|
zds->outStart += flushedSize;
|
||||||
if (flushedSize == toFlushSize) { /* flush completed */
|
if (flushedSize == toFlushSize) { /* flush completed */
|
||||||
zds->streamStage = zdss_read;
|
zds->streamStage = zdss_read;
|
||||||
|
|
@ -2089,7 +2236,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0); /* impossible */
|
assert(0); /* impossible */
|
||||||
RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
|
RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */
|
||||||
} }
|
} }
|
||||||
|
|
||||||
/* result */
|
/* result */
|
||||||
|
|
@ -2102,8 +2249,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||||
if ((ip==istart) && (op==ostart)) { /* no forward progress */
|
if ((ip==istart) && (op==ostart)) { /* no forward progress */
|
||||||
zds->noForwardProgress ++;
|
zds->noForwardProgress ++;
|
||||||
if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
|
if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
|
||||||
RETURN_ERROR_IF(op==oend, dstSize_tooSmall, "");
|
RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, "");
|
||||||
RETURN_ERROR_IF(ip==iend, srcSize_wrong, "");
|
RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, "");
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2140,11 +2287,17 @@ size_t ZSTD_decompressStream_simpleArgs (
|
||||||
void* dst, size_t dstCapacity, size_t* dstPos,
|
void* dst, size_t dstCapacity, size_t* dstPos,
|
||||||
const void* src, size_t srcSize, size_t* srcPos)
|
const void* src, size_t srcSize, size_t* srcPos)
|
||||||
{
|
{
|
||||||
ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
|
ZSTD_outBuffer output;
|
||||||
ZSTD_inBuffer input = { src, srcSize, *srcPos };
|
ZSTD_inBuffer input;
|
||||||
/* ZSTD_compress_generic() will check validity of dstPos and srcPos */
|
output.dst = dst;
|
||||||
size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
|
output.size = dstCapacity;
|
||||||
|
output.pos = *dstPos;
|
||||||
|
input.src = src;
|
||||||
|
input.size = srcSize;
|
||||||
|
input.pos = *srcPos;
|
||||||
|
{ size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
|
||||||
*dstPos = output.pos;
|
*dstPos = output.pos;
|
||||||
*srcPos = input.pos;
|
*srcPos = input.pos;
|
||||||
return cErr;
|
return cErr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -47,7 +48,7 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize, const int frame, const streaming_operation streaming);
|
const void* src, size_t srcSize, const streaming_operation streaming);
|
||||||
|
|
||||||
/* ZSTD_buildFSETable() :
|
/* ZSTD_buildFSETable() :
|
||||||
* generate FSE decoding table for one symbol (ll, ml or off)
|
* generate FSE decoding table for one symbol (ll, ml or off)
|
||||||
|
|
@ -64,5 +65,10 @@ void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
|
||||||
unsigned tableLog, void* wksp, size_t wkspSize,
|
unsigned tableLog, void* wksp, size_t wkspSize,
|
||||||
int bmi2);
|
int bmi2);
|
||||||
|
|
||||||
|
/* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */
|
||||||
|
size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
|
||||||
#endif /* ZSTD_DEC_BLOCK_H */
|
#endif /* ZSTD_DEC_BLOCK_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Yann Collet, Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -75,12 +76,13 @@ static UNUSED_ATTR const U32 ML_base[MaxML+1] = {
|
||||||
|
|
||||||
#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64))
|
#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64))
|
||||||
#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32))
|
#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32))
|
||||||
|
#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */
|
ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */
|
||||||
ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */
|
ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */
|
||||||
ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
|
ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
|
||||||
HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
|
HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */
|
||||||
U32 rep[ZSTD_REP_NUM];
|
U32 rep[ZSTD_REP_NUM];
|
||||||
U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32];
|
U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32];
|
||||||
} ZSTD_entropyDTables_t;
|
} ZSTD_entropyDTables_t;
|
||||||
|
|
@ -135,7 +137,7 @@ struct ZSTD_DCtx_s
|
||||||
const void* virtualStart; /* virtual start of previous segment if it was just before current one */
|
const void* virtualStart; /* virtual start of previous segment if it was just before current one */
|
||||||
const void* dictEnd; /* end of previous segment */
|
const void* dictEnd; /* end of previous segment */
|
||||||
size_t expected;
|
size_t expected;
|
||||||
ZSTD_frameHeader fParams;
|
ZSTD_FrameHeader fParams;
|
||||||
U64 processedCSize;
|
U64 processedCSize;
|
||||||
U64 decodedSize;
|
U64 decodedSize;
|
||||||
blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
|
blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
|
||||||
|
|
@ -152,7 +154,8 @@ struct ZSTD_DCtx_s
|
||||||
size_t litSize;
|
size_t litSize;
|
||||||
size_t rleSize;
|
size_t rleSize;
|
||||||
size_t staticSize;
|
size_t staticSize;
|
||||||
#if DYNAMIC_BMI2 != 0
|
int isFrameDecompression;
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
|
int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -164,6 +167,8 @@ struct ZSTD_DCtx_s
|
||||||
ZSTD_dictUses_e dictUses;
|
ZSTD_dictUses_e dictUses;
|
||||||
ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */
|
ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */
|
||||||
ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */
|
ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */
|
||||||
|
int disableHufAsm;
|
||||||
|
int maxBlockSizeParam;
|
||||||
|
|
||||||
/* streaming */
|
/* streaming */
|
||||||
ZSTD_dStreamStage streamStage;
|
ZSTD_dStreamStage streamStage;
|
||||||
|
|
@ -199,7 +204,7 @@ struct ZSTD_DCtx_s
|
||||||
}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
|
}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
|
||||||
|
|
||||||
MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) {
|
MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) {
|
||||||
#if DYNAMIC_BMI2 != 0
|
#if DYNAMIC_BMI2
|
||||||
return dctx->bmi2;
|
return dctx->bmi2;
|
||||||
#else
|
#else
|
||||||
(void)dctx;
|
(void)dctx;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -24,9 +24,6 @@ EXPORT_SYMBOL_GPL(HUF_readStats_wksp);
|
||||||
EXPORT_SYMBOL_GPL(ZSTD_isError);
|
EXPORT_SYMBOL_GPL(ZSTD_isError);
|
||||||
EXPORT_SYMBOL_GPL(ZSTD_getErrorName);
|
EXPORT_SYMBOL_GPL(ZSTD_getErrorName);
|
||||||
EXPORT_SYMBOL_GPL(ZSTD_getErrorCode);
|
EXPORT_SYMBOL_GPL(ZSTD_getErrorCode);
|
||||||
EXPORT_SYMBOL_GPL(ZSTD_customMalloc);
|
|
||||||
EXPORT_SYMBOL_GPL(ZSTD_customCalloc);
|
|
||||||
EXPORT_SYMBOL_GPL(ZSTD_customFree);
|
|
||||||
|
|
||||||
MODULE_LICENSE("Dual BSD/GPL");
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
MODULE_DESCRIPTION("Zstd Common");
|
MODULE_DESCRIPTION("Zstd Common");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "common/zstd_deps.h"
|
#include "common/zstd_deps.h"
|
||||||
#include "common/zstd_internal.h"
|
#include "common/zstd_internal.h"
|
||||||
|
#include "compress/zstd_compress_internal.h"
|
||||||
|
|
||||||
#define ZSTD_FORWARD_IF_ERR(ret) \
|
#define ZSTD_FORWARD_IF_ERR(ret) \
|
||||||
do { \
|
do { \
|
||||||
|
|
@ -92,12 +93,64 @@ zstd_compression_parameters zstd_get_cparams(int level,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(zstd_get_cparams);
|
EXPORT_SYMBOL(zstd_get_cparams);
|
||||||
|
|
||||||
|
size_t zstd_cctx_set_param(zstd_cctx *cctx, ZSTD_cParameter param, int value)
|
||||||
|
{
|
||||||
|
return ZSTD_CCtx_setParameter(cctx, param, value);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_cctx_set_param);
|
||||||
|
|
||||||
size_t zstd_cctx_workspace_bound(const zstd_compression_parameters *cparams)
|
size_t zstd_cctx_workspace_bound(const zstd_compression_parameters *cparams)
|
||||||
{
|
{
|
||||||
return ZSTD_estimateCCtxSize_usingCParams(*cparams);
|
return ZSTD_estimateCCtxSize_usingCParams(*cparams);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(zstd_cctx_workspace_bound);
|
EXPORT_SYMBOL(zstd_cctx_workspace_bound);
|
||||||
|
|
||||||
|
// Used by zstd_cctx_workspace_bound_with_ext_seq_prod()
|
||||||
|
static size_t dummy_external_sequence_producer(
|
||||||
|
void *sequenceProducerState,
|
||||||
|
ZSTD_Sequence *outSeqs, size_t outSeqsCapacity,
|
||||||
|
const void *src, size_t srcSize,
|
||||||
|
const void *dict, size_t dictSize,
|
||||||
|
int compressionLevel,
|
||||||
|
size_t windowSize)
|
||||||
|
{
|
||||||
|
(void)sequenceProducerState;
|
||||||
|
(void)outSeqs; (void)outSeqsCapacity;
|
||||||
|
(void)src; (void)srcSize;
|
||||||
|
(void)dict; (void)dictSize;
|
||||||
|
(void)compressionLevel;
|
||||||
|
(void)windowSize;
|
||||||
|
return ZSTD_SEQUENCE_PRODUCER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_cctx_params_from_compress_params(
|
||||||
|
ZSTD_CCtx_params *cctx_params,
|
||||||
|
const zstd_compression_parameters *compress_params)
|
||||||
|
{
|
||||||
|
ZSTD_parameters zstd_params;
|
||||||
|
memset(&zstd_params, 0, sizeof(zstd_params));
|
||||||
|
zstd_params.cParams = *compress_params;
|
||||||
|
ZSTD_CCtxParams_init_advanced(cctx_params, zstd_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t zstd_cctx_workspace_bound_with_ext_seq_prod(const zstd_compression_parameters *compress_params)
|
||||||
|
{
|
||||||
|
ZSTD_CCtx_params cctx_params;
|
||||||
|
init_cctx_params_from_compress_params(&cctx_params, compress_params);
|
||||||
|
ZSTD_CCtxParams_registerSequenceProducer(&cctx_params, NULL, dummy_external_sequence_producer);
|
||||||
|
return ZSTD_estimateCCtxSize_usingCCtxParams(&cctx_params);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_cctx_workspace_bound_with_ext_seq_prod);
|
||||||
|
|
||||||
|
size_t zstd_cstream_workspace_bound_with_ext_seq_prod(const zstd_compression_parameters *compress_params)
|
||||||
|
{
|
||||||
|
ZSTD_CCtx_params cctx_params;
|
||||||
|
init_cctx_params_from_compress_params(&cctx_params, compress_params);
|
||||||
|
ZSTD_CCtxParams_registerSequenceProducer(&cctx_params, NULL, dummy_external_sequence_producer);
|
||||||
|
return ZSTD_estimateCStreamSize_usingCCtxParams(&cctx_params);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_cstream_workspace_bound_with_ext_seq_prod);
|
||||||
|
|
||||||
zstd_cctx *zstd_init_cctx(void *workspace, size_t workspace_size)
|
zstd_cctx *zstd_init_cctx(void *workspace, size_t workspace_size)
|
||||||
{
|
{
|
||||||
if (workspace == NULL)
|
if (workspace == NULL)
|
||||||
|
|
@ -209,5 +262,25 @@ size_t zstd_end_stream(zstd_cstream *cstream, zstd_out_buffer *output)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(zstd_end_stream);
|
EXPORT_SYMBOL(zstd_end_stream);
|
||||||
|
|
||||||
|
void zstd_register_sequence_producer(
|
||||||
|
zstd_cctx *cctx,
|
||||||
|
void* sequence_producer_state,
|
||||||
|
zstd_sequence_producer_f sequence_producer
|
||||||
|
) {
|
||||||
|
ZSTD_registerSequenceProducer(cctx, sequence_producer_state, sequence_producer);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_register_sequence_producer);
|
||||||
|
|
||||||
|
size_t zstd_compress_sequences_and_literals(zstd_cctx *cctx, void* dst, size_t dst_capacity,
|
||||||
|
const zstd_sequence *in_seqs, size_t in_seqs_size,
|
||||||
|
const void* literals, size_t lit_size, size_t lit_capacity,
|
||||||
|
size_t decompressed_size)
|
||||||
|
{
|
||||||
|
return ZSTD_compressSequencesAndLiterals(cctx, dst, dst_capacity, in_seqs,
|
||||||
|
in_seqs_size, literals, lit_size,
|
||||||
|
lit_capacity, decompressed_size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_compress_sequences_and_literals);
|
||||||
|
|
||||||
MODULE_LICENSE("Dual BSD/GPL");
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
MODULE_DESCRIPTION("Zstd Compressor");
|
MODULE_DESCRIPTION("Zstd Compressor");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Facebook, Inc.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under both the BSD-style license (found in the
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
|
@ -113,7 +113,7 @@ EXPORT_SYMBOL(zstd_init_dstream);
|
||||||
|
|
||||||
size_t zstd_reset_dstream(zstd_dstream *dstream)
|
size_t zstd_reset_dstream(zstd_dstream *dstream)
|
||||||
{
|
{
|
||||||
return ZSTD_resetDStream(dstream);
|
return ZSTD_DCtx_reset(dstream, ZSTD_reset_session_only);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(zstd_reset_dstream);
|
EXPORT_SYMBOL(zstd_reset_dstream);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue