| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| BSD License | ||
|
|
||
| For Zstandard software | ||
|
|
||
| Copyright (c) 2016-present, Facebook, Inc. All rights reserved. | ||
|
|
||
| Redistribution and use in source and binary forms, with or without modification, | ||
| are permitted provided that the following conditions are met: | ||
|
|
||
| * Redistributions of source code must retain the above copyright notice, this | ||
| list of conditions and the following disclaimer. | ||
|
|
||
| * Redistributions in binary form must reproduce the above copyright notice, | ||
| this list of conditions and the following disclaimer in the documentation | ||
| and/or other materials provided with the distribution. | ||
|
|
||
| * Neither the name Facebook nor the names of its contributors may be used to | ||
| endorse or promote products derived from this software without specific | ||
| prior written permission. | ||
|
|
||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | ||
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
| #ifndef ZSTD_COMPILER_H | ||
| #define ZSTD_COMPILER_H | ||
|
|
||
| /*-******************************************************* | ||
| * Compiler specifics | ||
| *********************************************************/ | ||
| /* force inlining */ | ||
|
|
||
| #if !defined(ZSTD_NO_INLINE) | ||
| #if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ | ||
| # define INLINE_KEYWORD inline | ||
| #else | ||
| # define INLINE_KEYWORD | ||
| #endif | ||
|
|
||
| #if defined(__GNUC__) || defined(__ICCARM__) | ||
| # define FORCE_INLINE_ATTR __attribute__((always_inline)) | ||
| #elif defined(_MSC_VER) | ||
| # define FORCE_INLINE_ATTR __forceinline | ||
| #else | ||
| # define FORCE_INLINE_ATTR | ||
| #endif | ||
|
|
||
| #else | ||
|
|
||
| #define INLINE_KEYWORD | ||
| #define FORCE_INLINE_ATTR | ||
|
|
||
| #endif | ||
|
|
||
| /** | ||
| * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant | ||
| * parameters. They must be inlined for the compiler to eliminate the constant | ||
| * branches. | ||
| */ | ||
| #define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR | ||
| /** | ||
| * 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 | ||
| * performance. | ||
| * | ||
| * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the | ||
| * always_inline attribute. | ||
| * | ||
| * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline | ||
| * attribute. | ||
| */ | ||
| #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5 | ||
| # define HINT_INLINE static INLINE_KEYWORD | ||
| #else | ||
| # define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR | ||
| #endif | ||
|
|
||
| /* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ | ||
| #if defined(__GNUC__) | ||
| # define UNUSED_ATTR __attribute__((unused)) | ||
| #else | ||
| # define UNUSED_ATTR | ||
| #endif | ||
|
|
||
| /* force no inlining */ | ||
| #ifdef _MSC_VER | ||
| # define FORCE_NOINLINE static __declspec(noinline) | ||
| #else | ||
| # if defined(__GNUC__) || defined(__ICCARM__) | ||
| # define FORCE_NOINLINE static __attribute__((__noinline__)) | ||
| # else | ||
| # define FORCE_NOINLINE static | ||
| # endif | ||
| #endif | ||
|
|
||
| /* target attribute */ | ||
| #ifndef __has_attribute | ||
| #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ | ||
| #endif | ||
| #if defined(__GNUC__) || defined(__ICCARM__) | ||
| # define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) | ||
| #else | ||
| # define TARGET_ATTRIBUTE(target) | ||
| #endif | ||
|
|
||
| /* Enable runtime BMI2 dispatch based on the CPU. | ||
| * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. | ||
| */ | ||
| #ifndef DYNAMIC_BMI2 | ||
| #if ((defined(__clang__) && __has_attribute(__target__)) \ | ||
| || (defined(__GNUC__) \ | ||
| && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ | ||
| && (defined(__x86_64__) || defined(_M_X86)) \ | ||
| && !defined(__BMI2__) | ||
| # define DYNAMIC_BMI2 1 | ||
| #else | ||
| # define DYNAMIC_BMI2 0 | ||
| #endif | ||
| #endif | ||
|
|
||
| /* prefetch | ||
| * can be disabled, by declaring NO_PREFETCH build macro */ | ||
| #if defined(NO_PREFETCH) | ||
| # define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ | ||
| # define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ | ||
| #else | ||
| # if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ | ||
| # include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ | ||
| # define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) | ||
| # define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) | ||
| # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) | ||
| # define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) | ||
| # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) | ||
| # else | ||
| # define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ | ||
| # define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ | ||
| # endif | ||
| #endif /* NO_PREFETCH */ | ||
|
|
||
| #define CACHELINE_SIZE 64 | ||
|
|
||
| #define PREFETCH_AREA(p, s) { \ | ||
| const char* const _ptr = (const char*)(p); \ | ||
| size_t const _size = (size_t)(s); \ | ||
| size_t _pos; \ | ||
| for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ | ||
| PREFETCH_L2(_ptr + _pos); \ | ||
| } \ | ||
| } | ||
|
|
||
| /* vectorization | ||
| * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */ | ||
| #if !defined(__clang__) && defined(__GNUC__) | ||
| # if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) | ||
| # define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) | ||
| # else | ||
| # define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")") | ||
| # endif | ||
| #else | ||
| # define DONT_VECTORIZE | ||
| #endif | ||
|
|
||
| /* disable warnings */ | ||
| #ifdef _MSC_VER /* Visual Studio */ | ||
| # include <intrin.h> /* For Visual 2005 */ | ||
| # pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ | ||
| # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ | ||
| # pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ | ||
| # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ | ||
| # pragma warning(disable : 4324) /* disable: C4324: padded structure */ | ||
| #endif | ||
|
|
||
| #endif /* ZSTD_COMPILER_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,215 @@ | ||
| /* | ||
| * Copyright (c) 2018-present, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
| #ifndef ZSTD_COMMON_CPU_H | ||
| #define ZSTD_COMMON_CPU_H | ||
|
|
||
| /** | ||
| * Implementation taken from folly/CpuId.h | ||
| * https://github.com/facebook/folly/blob/master/folly/CpuId.h | ||
| */ | ||
|
|
||
| #include <string.h> | ||
|
|
||
| #include "mem.h" | ||
|
|
||
| #ifdef _MSC_VER | ||
| #include <intrin.h> | ||
| #endif | ||
|
|
||
| typedef struct { | ||
| U32 f1c; | ||
| U32 f1d; | ||
| U32 f7b; | ||
| U32 f7c; | ||
| } ZSTD_cpuid_t; | ||
|
|
||
| MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { | ||
| U32 f1c = 0; | ||
| U32 f1d = 0; | ||
| U32 f7b = 0; | ||
| U32 f7c = 0; | ||
| #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) | ||
| int reg[4]; | ||
| __cpuid((int*)reg, 0); | ||
| { | ||
| int const n = reg[0]; | ||
| if (n >= 1) { | ||
| __cpuid((int*)reg, 1); | ||
| f1c = (U32)reg[2]; | ||
| f1d = (U32)reg[3]; | ||
| } | ||
| if (n >= 7) { | ||
| __cpuidex((int*)reg, 7, 0); | ||
| f7b = (U32)reg[1]; | ||
| f7c = (U32)reg[2]; | ||
| } | ||
| } | ||
| #elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) | ||
| /* The following block like the normal cpuid branch below, but gcc | ||
| * reserves ebx for use of its pic register so we must specially | ||
| * handle the save and restore to avoid clobbering the register | ||
| */ | ||
| U32 n; | ||
| __asm__( | ||
| "pushl %%ebx\n\t" | ||
| "cpuid\n\t" | ||
| "popl %%ebx\n\t" | ||
| : "=a"(n) | ||
| : "a"(0) | ||
| : "ecx", "edx"); | ||
| if (n >= 1) { | ||
| U32 f1a; | ||
| __asm__( | ||
| "pushl %%ebx\n\t" | ||
| "cpuid\n\t" | ||
| "popl %%ebx\n\t" | ||
| : "=a"(f1a), "=c"(f1c), "=d"(f1d) | ||
| : "a"(1)); | ||
| } | ||
| if (n >= 7) { | ||
| __asm__( | ||
| "pushl %%ebx\n\t" | ||
| "cpuid\n\t" | ||
| "movl %%ebx, %%eax\n\t" | ||
| "popl %%ebx" | ||
| : "=a"(f7b), "=c"(f7c) | ||
| : "a"(7), "c"(0) | ||
| : "edx"); | ||
| } | ||
| #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) | ||
| U32 n; | ||
| __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); | ||
| if (n >= 1) { | ||
| U32 f1a; | ||
| __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); | ||
| } | ||
| if (n >= 7) { | ||
| U32 f7a; | ||
| __asm__("cpuid" | ||
| : "=a"(f7a), "=b"(f7b), "=c"(f7c) | ||
| : "a"(7), "c"(0) | ||
| : "edx"); | ||
| } | ||
| #endif | ||
| { | ||
| ZSTD_cpuid_t cpuid; | ||
| cpuid.f1c = f1c; | ||
| cpuid.f1d = f1d; | ||
| cpuid.f7b = f7b; | ||
| cpuid.f7c = f7c; | ||
| return cpuid; | ||
| } | ||
| } | ||
|
|
||
| #define X(name, r, bit) \ | ||
| MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ | ||
| return ((cpuid.r) & (1U << bit)) != 0; \ | ||
| } | ||
|
|
||
| /* cpuid(1): Processor Info and Feature Bits. */ | ||
| #define C(name, bit) X(name, f1c, bit) | ||
| C(sse3, 0) | ||
| C(pclmuldq, 1) | ||
| C(dtes64, 2) | ||
| C(monitor, 3) | ||
| C(dscpl, 4) | ||
| C(vmx, 5) | ||
| C(smx, 6) | ||
| C(eist, 7) | ||
| C(tm2, 8) | ||
| C(ssse3, 9) | ||
| C(cnxtid, 10) | ||
| C(fma, 12) | ||
| C(cx16, 13) | ||
| C(xtpr, 14) | ||
| C(pdcm, 15) | ||
| C(pcid, 17) | ||
| C(dca, 18) | ||
| C(sse41, 19) | ||
| C(sse42, 20) | ||
| C(x2apic, 21) | ||
| C(movbe, 22) | ||
| C(popcnt, 23) | ||
| C(tscdeadline, 24) | ||
| C(aes, 25) | ||
| C(xsave, 26) | ||
| C(osxsave, 27) | ||
| C(avx, 28) | ||
| C(f16c, 29) | ||
| C(rdrand, 30) | ||
| #undef C | ||
| #define D(name, bit) X(name, f1d, bit) | ||
| D(fpu, 0) | ||
| D(vme, 1) | ||
| D(de, 2) | ||
| D(pse, 3) | ||
| D(tsc, 4) | ||
| D(msr, 5) | ||
| D(pae, 6) | ||
| D(mce, 7) | ||
| D(cx8, 8) | ||
| D(apic, 9) | ||
| D(sep, 11) | ||
| D(mtrr, 12) | ||
| D(pge, 13) | ||
| D(mca, 14) | ||
| D(cmov, 15) | ||
| D(pat, 16) | ||
| D(pse36, 17) | ||
| D(psn, 18) | ||
| D(clfsh, 19) | ||
| D(ds, 21) | ||
| D(acpi, 22) | ||
| D(mmx, 23) | ||
| D(fxsr, 24) | ||
| D(sse, 25) | ||
| D(sse2, 26) | ||
| D(ss, 27) | ||
| D(htt, 28) | ||
| D(tm, 29) | ||
| D(pbe, 31) | ||
| #undef D | ||
|
|
||
| /* cpuid(7): Extended Features. */ | ||
| #define B(name, bit) X(name, f7b, bit) | ||
| B(bmi1, 3) | ||
| B(hle, 4) | ||
| B(avx2, 5) | ||
| B(smep, 7) | ||
| B(bmi2, 8) | ||
| B(erms, 9) | ||
| B(invpcid, 10) | ||
| B(rtm, 11) | ||
| B(mpx, 14) | ||
| B(avx512f, 16) | ||
| B(avx512dq, 17) | ||
| B(rdseed, 18) | ||
| B(adx, 19) | ||
| B(smap, 20) | ||
| B(avx512ifma, 21) | ||
| B(pcommit, 22) | ||
| B(clflushopt, 23) | ||
| B(clwb, 24) | ||
| B(avx512pf, 26) | ||
| B(avx512er, 27) | ||
| B(avx512cd, 28) | ||
| B(sha, 29) | ||
| B(avx512bw, 30) | ||
| B(avx512vl, 31) | ||
| #undef B | ||
| #define C(name, bit) X(name, f7c, bit) | ||
| C(prefetchwt1, 0) | ||
| C(avx512vbmi, 1) | ||
| #undef C | ||
|
|
||
| #undef X | ||
|
|
||
| #endif /* ZSTD_COMMON_CPU_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /* ****************************************************************** | ||
| debug | ||
| Part of FSE library | ||
| Copyright (C) 2013-present, Yann Collet. | ||
| BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | ||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions are | ||
| met: | ||
| * Redistributions of source code must retain the above copyright | ||
| notice, this list of conditions and the following disclaimer. | ||
| * Redistributions in binary form must reproduce the above | ||
| copyright notice, this list of conditions and the following disclaimer | ||
| in the documentation and/or other materials provided with the | ||
| distribution. | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| You can contact the author at : | ||
| - Source repository : https://github.com/Cyan4973/FiniteStateEntropy | ||
| ****************************************************************** */ | ||
|
|
||
|
|
||
| /* | ||
| * This module only hosts one global variable | ||
| * which can be used to dynamically influence the verbosity of traces, | ||
| * such as DEBUGLOG and RAWLOG | ||
| */ | ||
|
|
||
| #include "debug.h" | ||
|
|
||
| int g_debuglevel = DEBUGLEVEL; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| /* ****************************************************************** | ||
| debug | ||
| Part of FSE library | ||
| Copyright (C) 2013-present, Yann Collet. | ||
| BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | ||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions are | ||
| met: | ||
| * Redistributions of source code must retain the above copyright | ||
| notice, this list of conditions and the following disclaimer. | ||
| * Redistributions in binary form must reproduce the above | ||
| copyright notice, this list of conditions and the following disclaimer | ||
| in the documentation and/or other materials provided with the | ||
| distribution. | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| You can contact the author at : | ||
| - Source repository : https://github.com/Cyan4973/FiniteStateEntropy | ||
| ****************************************************************** */ | ||
|
|
||
|
|
||
| /* | ||
| * The purpose of this header is to enable debug functions. | ||
| * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time, | ||
| * and DEBUG_STATIC_ASSERT() for compile-time. | ||
| * | ||
| * By default, DEBUGLEVEL==0, which means run-time debug is disabled. | ||
| * | ||
| * Level 1 enables assert() only. | ||
| * Starting level 2, traces can be generated and pushed to stderr. | ||
| * The higher the level, the more verbose the traces. | ||
| * | ||
| * It's possible to dynamically adjust level using variable g_debug_level, | ||
| * which is only declared if DEBUGLEVEL>=2, | ||
| * and is a global variable, not multi-thread protected (use with care) | ||
| */ | ||
|
|
||
| #ifndef DEBUG_H_12987983217 | ||
| #define DEBUG_H_12987983217 | ||
|
|
||
| #if defined (__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
|
|
||
| /* static assert is triggered at compile time, leaving no runtime artefact. | ||
| * static assert only works with compile-time constants. | ||
| * Also, this variant can only be used inside a function. */ | ||
| #define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1]) | ||
|
|
||
|
|
||
| /* DEBUGLEVEL is expected to be defined externally, | ||
| * typically through compiler command line. | ||
| * Value must be a number. */ | ||
| #ifndef DEBUGLEVEL | ||
| # define DEBUGLEVEL 0 | ||
| #endif | ||
|
|
||
|
|
||
| /* DEBUGFILE can be defined externally, | ||
| * typically through compiler command line. | ||
| * note : currently useless. | ||
| * Value must be stderr or stdout */ | ||
| #ifndef DEBUGFILE | ||
| # define DEBUGFILE stderr | ||
| #endif | ||
|
|
||
|
|
||
| /* recommended values for DEBUGLEVEL : | ||
| * 0 : release mode, no debug, all run-time checks disabled | ||
| * 1 : enables assert() only, no display | ||
| * 2 : reserved, for currently active debug path | ||
| * 3 : events once per object lifetime (CCtx, CDict, etc.) | ||
| * 4 : events once per frame | ||
| * 5 : events once per block | ||
| * 6 : events once per sequence (verbose) | ||
| * 7+: events at every position (*very* verbose) | ||
| * | ||
| * It's generally inconvenient to output traces > 5. | ||
| * In which case, it's possible to selectively trigger high verbosity levels | ||
| * by modifying g_debug_level. | ||
| */ | ||
|
|
||
| #if (DEBUGLEVEL>=1) | ||
| # include <assert.h> | ||
| #else | ||
| # ifndef assert /* assert may be already defined, due to prior #include <assert.h> */ | ||
| # define assert(condition) ((void)0) /* disable assert (default) */ | ||
| # endif | ||
| #endif | ||
|
|
||
| #if (DEBUGLEVEL>=2) | ||
| # include <stdio.h> | ||
| extern int g_debuglevel; /* the variable is only declared, | ||
| it actually lives in debug.c, | ||
| and is shared by the whole process. | ||
| It's not thread-safe. | ||
| It's useful when enabling very verbose levels | ||
| on selective conditions (such as position in src) */ | ||
|
|
||
| # define RAWLOG(l, ...) { \ | ||
| if (l<=g_debuglevel) { \ | ||
| fprintf(stderr, __VA_ARGS__); \ | ||
| } } | ||
| # define DEBUGLOG(l, ...) { \ | ||
| if (l<=g_debuglevel) { \ | ||
| fprintf(stderr, __FILE__ ": " __VA_ARGS__); \ | ||
| fprintf(stderr, " \n"); \ | ||
| } } | ||
| #else | ||
| # define RAWLOG(l, ...) {} /* disabled */ | ||
| # define DEBUGLOG(l, ...) {} /* disabled */ | ||
| #endif | ||
|
|
||
|
|
||
| #if defined (__cplusplus) | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* DEBUG_H_12987983217 */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| /* | ||
| Common functions of New Generation Entropy library | ||
| Copyright (C) 2016, Yann Collet. | ||
| BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | ||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions are | ||
| met: | ||
| * Redistributions of source code must retain the above copyright | ||
| notice, this list of conditions and the following disclaimer. | ||
| * Redistributions in binary form must reproduce the above | ||
| copyright notice, this list of conditions and the following disclaimer | ||
| in the documentation and/or other materials provided with the | ||
| distribution. | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| You can contact the author at : | ||
| - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy | ||
| - Public forum : https://groups.google.com/forum/#!forum/lz4c | ||
| *************************************************************************** */ | ||
|
|
||
| /* ************************************* | ||
| * Dependencies | ||
| ***************************************/ | ||
| #include "mem.h" | ||
| #include "error_private.h" /* ERR_*, ERROR */ | ||
| #define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ | ||
| #include "fse.h" | ||
| #define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */ | ||
| #include "huf.h" | ||
|
|
||
|
|
||
| /*=== Version ===*/ | ||
| unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; } | ||
|
|
||
|
|
||
| /*=== Error Management ===*/ | ||
| unsigned FSE_isError(size_t code) { return ERR_isError(code); } | ||
| const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); } | ||
|
|
||
| unsigned HUF_isError(size_t code) { return ERR_isError(code); } | ||
| const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } | ||
|
|
||
|
|
||
| /*-************************************************************** | ||
| * FSE NCount encoding-decoding | ||
| ****************************************************************/ | ||
| size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, | ||
| const void* headerBuffer, size_t hbSize) | ||
| { | ||
| const BYTE* const istart = (const BYTE*) headerBuffer; | ||
| const BYTE* const iend = istart + hbSize; | ||
| const BYTE* ip = istart; | ||
| int nbBits; | ||
| int remaining; | ||
| int threshold; | ||
| U32 bitStream; | ||
| int bitCount; | ||
| unsigned charnum = 0; | ||
| int previous0 = 0; | ||
|
|
||
| if (hbSize < 4) { | ||
| /* This function only works when hbSize >= 4 */ | ||
| char buffer[4]; | ||
| memset(buffer, 0, sizeof(buffer)); | ||
| memcpy(buffer, headerBuffer, hbSize); | ||
| { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, | ||
| buffer, sizeof(buffer)); | ||
| if (FSE_isError(countSize)) return countSize; | ||
| if (countSize > hbSize) return ERROR(corruption_detected); | ||
| return countSize; | ||
| } } | ||
| assert(hbSize >= 4); | ||
|
|
||
| /* init */ | ||
| memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ | ||
| bitStream = MEM_readLE32(ip); | ||
| nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ | ||
| if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); | ||
| bitStream >>= 4; | ||
| bitCount = 4; | ||
| *tableLogPtr = nbBits; | ||
| remaining = (1<<nbBits)+1; | ||
| threshold = 1<<nbBits; | ||
| nbBits++; | ||
|
|
||
| while ((remaining>1) & (charnum<=*maxSVPtr)) { | ||
| if (previous0) { | ||
| unsigned n0 = charnum; | ||
| while ((bitStream & 0xFFFF) == 0xFFFF) { | ||
| n0 += 24; | ||
| if (ip < iend-5) { | ||
| ip += 2; | ||
| bitStream = MEM_readLE32(ip) >> bitCount; | ||
| } else { | ||
| bitStream >>= 16; | ||
| bitCount += 16; | ||
| } } | ||
| while ((bitStream & 3) == 3) { | ||
| n0 += 3; | ||
| bitStream >>= 2; | ||
| bitCount += 2; | ||
| } | ||
| n0 += bitStream & 3; | ||
| bitCount += 2; | ||
| if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); | ||
| while (charnum < n0) normalizedCounter[charnum++] = 0; | ||
| if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { | ||
| assert((bitCount >> 3) <= 3); /* For first condition to work */ | ||
| ip += bitCount>>3; | ||
| bitCount &= 7; | ||
| bitStream = MEM_readLE32(ip) >> bitCount; | ||
| } else { | ||
| bitStream >>= 2; | ||
| } } | ||
| { int const max = (2*threshold-1) - remaining; | ||
| int count; | ||
|
|
||
| if ((bitStream & (threshold-1)) < (U32)max) { | ||
| count = bitStream & (threshold-1); | ||
| bitCount += nbBits-1; | ||
| } else { | ||
| count = bitStream & (2*threshold-1); | ||
| if (count >= threshold) count -= max; | ||
| bitCount += nbBits; | ||
| } | ||
|
|
||
| count--; /* extra accuracy */ | ||
| remaining -= count < 0 ? -count : count; /* -1 means +1 */ | ||
| normalizedCounter[charnum++] = (short)count; | ||
| previous0 = !count; | ||
| while (remaining < threshold) { | ||
| nbBits--; | ||
| threshold >>= 1; | ||
| } | ||
|
|
||
| if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { | ||
| ip += bitCount>>3; | ||
| bitCount &= 7; | ||
| } else { | ||
| bitCount -= (int)(8 * (iend - 4 - ip)); | ||
| ip = iend - 4; | ||
| } | ||
| bitStream = MEM_readLE32(ip) >> (bitCount & 31); | ||
| } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */ | ||
| if (remaining != 1) return ERROR(corruption_detected); | ||
| if (bitCount > 32) return ERROR(corruption_detected); | ||
| *maxSVPtr = charnum-1; | ||
|
|
||
| ip += (bitCount+7)>>3; | ||
| return ip-istart; | ||
| } | ||
|
|
||
|
|
||
| /*! HUF_readStats() : | ||
| Read compact Huffman tree, saved by HUF_writeCTable(). | ||
| `huffWeight` is destination buffer. | ||
| `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32. | ||
| @return : size read from `src` , or an error Code . | ||
| Note : Needed by HUF_readCTable() and HUF_readDTableX?() . | ||
| */ | ||
| size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, | ||
| U32* nbSymbolsPtr, U32* tableLogPtr, | ||
| const void* src, size_t srcSize) | ||
| { | ||
| U32 weightTotal; | ||
| const BYTE* ip = (const BYTE*) src; | ||
| size_t iSize; | ||
| size_t oSize; | ||
|
|
||
| if (!srcSize) return ERROR(srcSize_wrong); | ||
| iSize = ip[0]; | ||
| /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ | ||
|
|
||
| if (iSize >= 128) { /* special header */ | ||
| oSize = iSize - 127; | ||
| iSize = ((oSize+1)/2); | ||
| if (iSize+1 > srcSize) return ERROR(srcSize_wrong); | ||
| if (oSize >= hwSize) return ERROR(corruption_detected); | ||
| ip += 1; | ||
| { U32 n; | ||
| for (n=0; n<oSize; n+=2) { | ||
| huffWeight[n] = ip[n/2] >> 4; | ||
| huffWeight[n+1] = ip[n/2] & 15; | ||
| } } } | ||
| else { /* header compressed with FSE (normal case) */ | ||
| FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */ | ||
| if (iSize+1 > srcSize) return ERROR(srcSize_wrong); | ||
| oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */ | ||
| if (FSE_isError(oSize)) return oSize; | ||
| } | ||
|
|
||
| /* collect weight stats */ | ||
| memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); | ||
| weightTotal = 0; | ||
| { U32 n; for (n=0; n<oSize; n++) { | ||
| if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected); | ||
| rankStats[huffWeight[n]]++; | ||
| weightTotal += (1 << huffWeight[n]) >> 1; | ||
| } } | ||
| if (weightTotal == 0) return ERROR(corruption_detected); | ||
|
|
||
| /* get last non-null symbol weight (implied, total must be 2^n) */ | ||
| { U32 const tableLog = BIT_highbit32(weightTotal) + 1; | ||
| if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); | ||
| *tableLogPtr = tableLog; | ||
| /* determine last weight */ | ||
| { U32 const total = 1 << tableLog; | ||
| U32 const rest = total - weightTotal; | ||
| U32 const verif = 1 << BIT_highbit32(rest); | ||
| U32 const lastWeight = BIT_highbit32(rest) + 1; | ||
| if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ | ||
| huffWeight[oSize] = (BYTE)lastWeight; | ||
| rankStats[lastWeight]++; | ||
| } } | ||
|
|
||
| /* check tree construction validity */ | ||
| if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ | ||
|
|
||
| /* results */ | ||
| *nbSymbolsPtr = (U32)(oSize+1); | ||
| return iSize+1; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
| /* The purpose of this file is to have a single list of error strings embedded in binary */ | ||
|
|
||
| #include "error_private.h" | ||
|
|
||
| const char* ERR_getErrorString(ERR_enum code) | ||
| { | ||
| #ifdef ZSTD_STRIP_ERROR_STRINGS | ||
| (void)code; | ||
| return "Error strings stripped"; | ||
| #else | ||
| static const char* const notErrorCode = "Unspecified error code"; | ||
| switch( code ) | ||
| { | ||
| case PREFIX(no_error): return "No error detected"; | ||
| case PREFIX(GENERIC): return "Error (generic)"; | ||
| case PREFIX(prefix_unknown): return "Unknown frame descriptor"; | ||
| case PREFIX(version_unsupported): return "Version not supported"; | ||
| case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; | ||
| case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; | ||
| case PREFIX(corruption_detected): return "Corrupted block detected"; | ||
| case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; | ||
| case PREFIX(parameter_unsupported): return "Unsupported parameter"; | ||
| case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; | ||
| case PREFIX(init_missing): return "Context should be init first"; | ||
| case PREFIX(memory_allocation): return "Allocation error : not enough memory"; | ||
| case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough"; | ||
| case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; | ||
| case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; | ||
| case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; | ||
| case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; | ||
| case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; | ||
| case PREFIX(dictionary_wrong): return "Dictionary mismatch"; | ||
| case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; | ||
| case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; | ||
| case PREFIX(srcSize_wrong): return "Src size is incorrect"; | ||
| case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; | ||
| /* 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(seekableIO): return "An I/O error occurred when reading/seeking"; | ||
| case PREFIX(maxCode): | ||
| default: return notErrorCode; | ||
| } | ||
| #endif | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
| /* Note : this module is expected to remain private, do not expose it */ | ||
|
|
||
| #ifndef ERROR_H_MODULE | ||
| #define ERROR_H_MODULE | ||
|
|
||
| #if defined (__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
|
|
||
| /* **************************************** | ||
| * Dependencies | ||
| ******************************************/ | ||
| #include <stddef.h> /* size_t */ | ||
| #include "zstd_errors.h" /* enum list */ | ||
|
|
||
|
|
||
| /* **************************************** | ||
| * Compiler-specific | ||
| ******************************************/ | ||
| #if defined(__GNUC__) | ||
| # define ERR_STATIC static __attribute__((unused)) | ||
| #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) | ||
| # define ERR_STATIC static inline | ||
| #elif defined(_MSC_VER) | ||
| # define ERR_STATIC static __inline | ||
| #else | ||
| # define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ | ||
| #endif | ||
|
|
||
|
|
||
| /*-**************************************** | ||
| * Customization (error_public.h) | ||
| ******************************************/ | ||
| typedef ZSTD_ErrorCode ERR_enum; | ||
| #define PREFIX(name) ZSTD_error_##name | ||
|
|
||
|
|
||
| /*-**************************************** | ||
| * Error codes handling | ||
| ******************************************/ | ||
| #undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ | ||
| #define ERROR(name) ZSTD_ERROR(name) | ||
| #define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) | ||
|
|
||
| ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } | ||
|
|
||
| ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } | ||
|
|
||
|
|
||
| /*-**************************************** | ||
| * Error Strings | ||
| ******************************************/ | ||
|
|
||
| const char* ERR_getErrorString(ERR_enum code); /* error_private.c */ | ||
|
|
||
| ERR_STATIC const char* ERR_getErrorName(size_t code) | ||
| { | ||
| return ERR_getErrorString(ERR_getErrorCode(code)); | ||
| } | ||
|
|
||
| #if defined (__cplusplus) | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* ERROR_H_MODULE */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,311 @@ | ||
| /* ****************************************************************** | ||
| FSE : Finite State Entropy decoder | ||
| Copyright (C) 2013-2015, Yann Collet. | ||
| BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | ||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions are | ||
| met: | ||
| * Redistributions of source code must retain the above copyright | ||
| notice, this list of conditions and the following disclaimer. | ||
| * Redistributions in binary form must reproduce the above | ||
| copyright notice, this list of conditions and the following disclaimer | ||
| in the documentation and/or other materials provided with the | ||
| distribution. | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| You can contact the author at : | ||
| - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy | ||
| - Public forum : https://groups.google.com/forum/#!forum/lz4c | ||
| ****************************************************************** */ | ||
|
|
||
|
|
||
| /* ************************************************************** | ||
| * Includes | ||
| ****************************************************************/ | ||
| #include <stdlib.h> /* malloc, free, qsort */ | ||
| #include <string.h> /* memcpy, memset */ | ||
| #include "bitstream.h" | ||
| #include "compiler.h" | ||
| #define FSE_STATIC_LINKING_ONLY | ||
| #include "fse.h" | ||
| #include "error_private.h" | ||
|
|
||
|
|
||
| /* ************************************************************** | ||
| * Error Management | ||
| ****************************************************************/ | ||
| #define FSE_isError ERR_isError | ||
| #define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ | ||
|
|
||
| /* check and forward error code */ | ||
| #ifndef CHECK_F | ||
| #define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; } | ||
| #endif | ||
|
|
||
|
|
||
| /* ************************************************************** | ||
| * Templates | ||
| ****************************************************************/ | ||
| /* | ||
| designed to be included | ||
| for type-specific functions (template emulation in C) | ||
| Objective is to write these functions only once, for improved maintenance | ||
| */ | ||
|
|
||
| /* safety checks */ | ||
| #ifndef FSE_FUNCTION_EXTENSION | ||
| # error "FSE_FUNCTION_EXTENSION must be defined" | ||
| #endif | ||
| #ifndef FSE_FUNCTION_TYPE | ||
| # error "FSE_FUNCTION_TYPE must be defined" | ||
| #endif | ||
|
|
||
| /* Function names */ | ||
| #define FSE_CAT(X,Y) X##Y | ||
| #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) | ||
| #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) | ||
|
|
||
|
|
||
| /* Function templates */ | ||
| FSE_DTable* FSE_createDTable (unsigned tableLog) | ||
| { | ||
| if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; | ||
| return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); | ||
| } | ||
|
|
||
| void FSE_freeDTable (FSE_DTable* dt) | ||
| { | ||
| free(dt); | ||
| } | ||
|
|
||
| size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) | ||
| { | ||
| void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ | ||
| FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); | ||
| U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1]; | ||
|
|
||
| U32 const maxSV1 = maxSymbolValue + 1; | ||
| U32 const tableSize = 1 << tableLog; | ||
| U32 highThreshold = tableSize-1; | ||
|
|
||
| /* Sanity Checks */ | ||
| if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); | ||
| if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); | ||
|
|
||
| /* Init, lay down lowprob symbols */ | ||
| { FSE_DTableHeader DTableH; | ||
| DTableH.tableLog = (U16)tableLog; | ||
| DTableH.fastMode = 1; | ||
| { S16 const largeLimit= (S16)(1 << (tableLog-1)); | ||
| U32 s; | ||
| for (s=0; s<maxSV1; s++) { | ||
| if (normalizedCounter[s]==-1) { | ||
| tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s; | ||
| symbolNext[s] = 1; | ||
| } else { | ||
| if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0; | ||
| symbolNext[s] = normalizedCounter[s]; | ||
| } } } | ||
| memcpy(dt, &DTableH, sizeof(DTableH)); | ||
| } | ||
|
|
||
| /* Spread symbols */ | ||
| { U32 const tableMask = tableSize-1; | ||
| U32 const step = FSE_TABLESTEP(tableSize); | ||
| U32 s, position = 0; | ||
| for (s=0; s<maxSV1; s++) { | ||
| int i; | ||
| for (i=0; i<normalizedCounter[s]; i++) { | ||
| tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s; | ||
| position = (position + step) & tableMask; | ||
| while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */ | ||
| } } | ||
| if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ | ||
| } | ||
|
|
||
| /* Build Decoding table */ | ||
| { U32 u; | ||
| for (u=0; u<tableSize; u++) { | ||
| FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol); | ||
| U32 const nextState = symbolNext[symbol]++; | ||
| tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) ); | ||
| tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize); | ||
| } } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
|
|
||
| #ifndef FSE_COMMONDEFS_ONLY | ||
|
|
||
| /*-******************************************************* | ||
| * Decompression (Byte symbols) | ||
| *********************************************************/ | ||
| size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue) | ||
| { | ||
| void* ptr = dt; | ||
| FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; | ||
| void* dPtr = dt + 1; | ||
| FSE_decode_t* const cell = (FSE_decode_t*)dPtr; | ||
|
|
||
| DTableH->tableLog = 0; | ||
| DTableH->fastMode = 0; | ||
|
|
||
| cell->newState = 0; | ||
| cell->symbol = symbolValue; | ||
| cell->nbBits = 0; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
|
|
||
| size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) | ||
| { | ||
| void* ptr = dt; | ||
| FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; | ||
| void* dPtr = dt + 1; | ||
| FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; | ||
| const unsigned tableSize = 1 << nbBits; | ||
| const unsigned tableMask = tableSize - 1; | ||
| const unsigned maxSV1 = tableMask+1; | ||
| unsigned s; | ||
|
|
||
| /* Sanity checks */ | ||
| if (nbBits < 1) return ERROR(GENERIC); /* min size */ | ||
|
|
||
| /* Build Decoding Table */ | ||
| DTableH->tableLog = (U16)nbBits; | ||
| DTableH->fastMode = 1; | ||
| for (s=0; s<maxSV1; s++) { | ||
| dinfo[s].newState = 0; | ||
| dinfo[s].symbol = (BYTE)s; | ||
| dinfo[s].nbBits = (BYTE)nbBits; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic( | ||
| void* dst, size_t maxDstSize, | ||
| const void* cSrc, size_t cSrcSize, | ||
| const FSE_DTable* dt, const unsigned fast) | ||
| { | ||
| BYTE* const ostart = (BYTE*) dst; | ||
| BYTE* op = ostart; | ||
| BYTE* const omax = op + maxDstSize; | ||
| BYTE* const olimit = omax-3; | ||
|
|
||
| BIT_DStream_t bitD; | ||
| FSE_DState_t state1; | ||
| FSE_DState_t state2; | ||
|
|
||
| /* Init */ | ||
| CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize)); | ||
|
|
||
| FSE_initDState(&state1, &bitD, dt); | ||
| FSE_initDState(&state2, &bitD, dt); | ||
|
|
||
| #define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD) | ||
|
|
||
| /* 4 symbols per loop */ | ||
| for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) { | ||
| op[0] = FSE_GETSYMBOL(&state1); | ||
|
|
||
| if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ | ||
| BIT_reloadDStream(&bitD); | ||
|
|
||
| op[1] = FSE_GETSYMBOL(&state2); | ||
|
|
||
| if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ | ||
| { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } } | ||
|
|
||
| op[2] = FSE_GETSYMBOL(&state1); | ||
|
|
||
| if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ | ||
| BIT_reloadDStream(&bitD); | ||
|
|
||
| op[3] = FSE_GETSYMBOL(&state2); | ||
| } | ||
|
|
||
| /* tail */ | ||
| /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ | ||
| while (1) { | ||
| if (op>(omax-2)) return ERROR(dstSize_tooSmall); | ||
| *op++ = FSE_GETSYMBOL(&state1); | ||
| if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { | ||
| *op++ = FSE_GETSYMBOL(&state2); | ||
| break; | ||
| } | ||
|
|
||
| if (op>(omax-2)) return ERROR(dstSize_tooSmall); | ||
| *op++ = FSE_GETSYMBOL(&state2); | ||
| if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { | ||
| *op++ = FSE_GETSYMBOL(&state1); | ||
| break; | ||
| } } | ||
|
|
||
| return op-ostart; | ||
| } | ||
|
|
||
|
|
||
| size_t FSE_decompress_usingDTable(void* dst, size_t originalSize, | ||
| const void* cSrc, size_t cSrcSize, | ||
| const FSE_DTable* dt) | ||
| { | ||
| const void* ptr = dt; | ||
| const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; | ||
| const U32 fastMode = DTableH->fastMode; | ||
|
|
||
| /* select fast mode (static) */ | ||
| if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); | ||
| return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); | ||
| } | ||
|
|
||
|
|
||
| size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog) | ||
| { | ||
| const BYTE* const istart = (const BYTE*)cSrc; | ||
| const BYTE* ip = istart; | ||
| short counting[FSE_MAX_SYMBOL_VALUE+1]; | ||
| unsigned tableLog; | ||
| unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; | ||
|
|
||
| /* normal FSE decoding mode */ | ||
| size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); | ||
| if (FSE_isError(NCountLength)) return NCountLength; | ||
| //if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */ | ||
| if (tableLog > maxLog) return ERROR(tableLog_tooLarge); | ||
| ip += NCountLength; | ||
| cSrcSize -= NCountLength; | ||
|
|
||
| CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) ); | ||
|
|
||
| return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */ | ||
| } | ||
|
|
||
|
|
||
| typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; | ||
|
|
||
| size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) | ||
| { | ||
| DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ | ||
| return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| #endif /* FSE_COMMONDEFS_ONLY */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,344 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
|
|
||
| /* ====== Dependencies ======= */ | ||
| #include <stddef.h> /* size_t */ | ||
| #include "debug.h" /* assert */ | ||
| #include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */ | ||
| #include "pool.h" | ||
|
|
||
| /* ====== Compiler specifics ====== */ | ||
| #if defined(_MSC_VER) | ||
| # pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ | ||
| #endif | ||
|
|
||
|
|
||
| #ifdef ZSTD_MULTITHREAD | ||
|
|
||
| #include "threading.h" /* pthread adaptation */ | ||
|
|
||
| /* A job is a function and an opaque argument */ | ||
| typedef struct POOL_job_s { | ||
| POOL_function function; | ||
| void *opaque; | ||
| } POOL_job; | ||
|
|
||
| struct POOL_ctx_s { | ||
| ZSTD_customMem customMem; | ||
| /* Keep track of the threads */ | ||
| ZSTD_pthread_t* threads; | ||
| size_t threadCapacity; | ||
| size_t threadLimit; | ||
|
|
||
| /* The queue is a circular buffer */ | ||
| POOL_job *queue; | ||
| size_t queueHead; | ||
| size_t queueTail; | ||
| size_t queueSize; | ||
|
|
||
| /* The number of threads working on jobs */ | ||
| size_t numThreadsBusy; | ||
| /* Indicates if the queue is empty */ | ||
| int queueEmpty; | ||
|
|
||
| /* The mutex protects the queue */ | ||
| ZSTD_pthread_mutex_t queueMutex; | ||
| /* Condition variable for pushers to wait on when the queue is full */ | ||
| ZSTD_pthread_cond_t queuePushCond; | ||
| /* Condition variables for poppers to wait on when the queue is empty */ | ||
| ZSTD_pthread_cond_t queuePopCond; | ||
| /* Indicates if the queue is shutting down */ | ||
| int shutdown; | ||
| }; | ||
|
|
||
| /* POOL_thread() : | ||
| * Work thread for the thread pool. | ||
| * Waits for jobs and executes them. | ||
| * @returns : NULL on failure else non-null. | ||
| */ | ||
| static void* POOL_thread(void* opaque) { | ||
| POOL_ctx* const ctx = (POOL_ctx*)opaque; | ||
| if (!ctx) { return NULL; } | ||
| for (;;) { | ||
| /* Lock the mutex and wait for a non-empty queue or until shutdown */ | ||
| ZSTD_pthread_mutex_lock(&ctx->queueMutex); | ||
|
|
||
| while ( ctx->queueEmpty | ||
| || (ctx->numThreadsBusy >= ctx->threadLimit) ) { | ||
| if (ctx->shutdown) { | ||
| /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit), | ||
| * a few threads will be shutdown while !queueEmpty, | ||
| * but enough threads will remain active to finish the queue */ | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
| return opaque; | ||
| } | ||
| ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); | ||
| } | ||
| /* Pop a job off the queue */ | ||
| { POOL_job const job = ctx->queue[ctx->queueHead]; | ||
| ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; | ||
| ctx->numThreadsBusy++; | ||
| ctx->queueEmpty = ctx->queueHead == ctx->queueTail; | ||
| /* Unlock the mutex, signal a pusher, and run the job */ | ||
| ZSTD_pthread_cond_signal(&ctx->queuePushCond); | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
|
|
||
| job.function(job.opaque); | ||
|
|
||
| /* If the intended queue size was 0, signal after finishing job */ | ||
| ZSTD_pthread_mutex_lock(&ctx->queueMutex); | ||
| ctx->numThreadsBusy--; | ||
| if (ctx->queueSize == 1) { | ||
| ZSTD_pthread_cond_signal(&ctx->queuePushCond); | ||
| } | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
| } | ||
| } /* for (;;) */ | ||
| assert(0); /* Unreachable */ | ||
| } | ||
|
|
||
| POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { | ||
| return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); | ||
| } | ||
|
|
||
| POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, | ||
| ZSTD_customMem customMem) { | ||
| POOL_ctx* ctx; | ||
| /* Check parameters */ | ||
| if (!numThreads) { return NULL; } | ||
| /* Allocate the context and zero initialize */ | ||
| ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem); | ||
| if (!ctx) { return NULL; } | ||
| /* Initialize the job queue. | ||
| * It needs one extra space since one space is wasted to differentiate | ||
| * empty and full queues. | ||
| */ | ||
| ctx->queueSize = queueSize + 1; | ||
| ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem); | ||
| ctx->queueHead = 0; | ||
| ctx->queueTail = 0; | ||
| ctx->numThreadsBusy = 0; | ||
| ctx->queueEmpty = 1; | ||
| { | ||
| int error = 0; | ||
| error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL); | ||
| error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL); | ||
| error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL); | ||
| if (error) { POOL_free(ctx); return NULL; } | ||
| } | ||
| ctx->shutdown = 0; | ||
| /* Allocate space for the thread handles */ | ||
| ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem); | ||
| ctx->threadCapacity = 0; | ||
| ctx->customMem = customMem; | ||
| /* Check for errors */ | ||
| if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } | ||
| /* Initialize the threads */ | ||
| { size_t i; | ||
| for (i = 0; i < numThreads; ++i) { | ||
| if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { | ||
| ctx->threadCapacity = i; | ||
| POOL_free(ctx); | ||
| return NULL; | ||
| } } | ||
| ctx->threadCapacity = numThreads; | ||
| ctx->threadLimit = numThreads; | ||
| } | ||
| return ctx; | ||
| } | ||
|
|
||
| /*! POOL_join() : | ||
| Shutdown the queue, wake any sleeping threads, and join all of the threads. | ||
| */ | ||
| static void POOL_join(POOL_ctx* ctx) { | ||
| /* Shut down the queue */ | ||
| ZSTD_pthread_mutex_lock(&ctx->queueMutex); | ||
| ctx->shutdown = 1; | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
| /* Wake up sleeping threads */ | ||
| ZSTD_pthread_cond_broadcast(&ctx->queuePushCond); | ||
| ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); | ||
| /* Join all of the threads */ | ||
| { size_t i; | ||
| for (i = 0; i < ctx->threadCapacity; ++i) { | ||
| ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */ | ||
| } } | ||
| } | ||
|
|
||
| void POOL_free(POOL_ctx *ctx) { | ||
| if (!ctx) { return; } | ||
| POOL_join(ctx); | ||
| ZSTD_pthread_mutex_destroy(&ctx->queueMutex); | ||
| ZSTD_pthread_cond_destroy(&ctx->queuePushCond); | ||
| ZSTD_pthread_cond_destroy(&ctx->queuePopCond); | ||
| ZSTD_free(ctx->queue, ctx->customMem); | ||
| ZSTD_free(ctx->threads, ctx->customMem); | ||
| ZSTD_free(ctx, ctx->customMem); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| size_t POOL_sizeof(POOL_ctx *ctx) { | ||
| if (ctx==NULL) return 0; /* supports sizeof NULL */ | ||
| return sizeof(*ctx) | ||
| + ctx->queueSize * sizeof(POOL_job) | ||
| + ctx->threadCapacity * sizeof(ZSTD_pthread_t); | ||
| } | ||
|
|
||
|
|
||
| /* @return : 0 on success, 1 on error */ | ||
| static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) | ||
| { | ||
| if (numThreads <= ctx->threadCapacity) { | ||
| if (!numThreads) return 1; | ||
| ctx->threadLimit = numThreads; | ||
| return 0; | ||
| } | ||
| /* numThreads > threadCapacity */ | ||
| { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); | ||
| if (!threadPool) return 1; | ||
| /* replace existing thread pool */ | ||
| memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); | ||
| ZSTD_free(ctx->threads, ctx->customMem); | ||
| ctx->threads = threadPool; | ||
| /* Initialize additional threads */ | ||
| { size_t threadId; | ||
| for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { | ||
| if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { | ||
| ctx->threadCapacity = threadId; | ||
| return 1; | ||
| } } | ||
| } } | ||
| /* successfully expanded */ | ||
| ctx->threadCapacity = numThreads; | ||
| ctx->threadLimit = numThreads; | ||
| return 0; | ||
| } | ||
|
|
||
| /* @return : 0 on success, 1 on error */ | ||
| int POOL_resize(POOL_ctx* ctx, size_t numThreads) | ||
| { | ||
| int result; | ||
| if (ctx==NULL) return 1; | ||
| ZSTD_pthread_mutex_lock(&ctx->queueMutex); | ||
| result = POOL_resize_internal(ctx, numThreads); | ||
| ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
| return result; | ||
| } | ||
|
|
||
| /** | ||
| * Returns 1 if the queue is full and 0 otherwise. | ||
| * | ||
| * When queueSize is 1 (pool was created with an intended queueSize of 0), | ||
| * then a queue is empty if there is a thread free _and_ no job is waiting. | ||
| */ | ||
| static int isQueueFull(POOL_ctx const* ctx) { | ||
| if (ctx->queueSize > 1) { | ||
| return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize); | ||
| } else { | ||
| return (ctx->numThreadsBusy == ctx->threadLimit) || | ||
| !ctx->queueEmpty; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) | ||
| { | ||
| POOL_job const job = {function, opaque}; | ||
| assert(ctx != NULL); | ||
| if (ctx->shutdown) return; | ||
|
|
||
| ctx->queueEmpty = 0; | ||
| ctx->queue[ctx->queueTail] = job; | ||
| ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize; | ||
| ZSTD_pthread_cond_signal(&ctx->queuePopCond); | ||
| } | ||
|
|
||
| void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) | ||
| { | ||
| assert(ctx != NULL); | ||
| ZSTD_pthread_mutex_lock(&ctx->queueMutex); | ||
| /* Wait until there is space in the queue for the new job */ | ||
| while (isQueueFull(ctx) && (!ctx->shutdown)) { | ||
| ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); | ||
| } | ||
| POOL_add_internal(ctx, function, opaque); | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
| } | ||
|
|
||
|
|
||
| int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) | ||
| { | ||
| assert(ctx != NULL); | ||
| ZSTD_pthread_mutex_lock(&ctx->queueMutex); | ||
| if (isQueueFull(ctx)) { | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
| return 0; | ||
| } | ||
| POOL_add_internal(ctx, function, opaque); | ||
| ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | ||
| return 1; | ||
| } | ||
|
|
||
|
|
||
| #else /* ZSTD_MULTITHREAD not defined */ | ||
|
|
||
| /* ========================== */ | ||
| /* No multi-threading support */ | ||
| /* ========================== */ | ||
|
|
||
|
|
||
| /* We don't need any data, but if it is empty, malloc() might return NULL. */ | ||
| struct POOL_ctx_s { | ||
| int dummy; | ||
| }; | ||
| static POOL_ctx g_ctx; | ||
|
|
||
| POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { | ||
| return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); | ||
| } | ||
|
|
||
| POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) { | ||
| (void)numThreads; | ||
| (void)queueSize; | ||
| (void)customMem; | ||
| return &g_ctx; | ||
| } | ||
|
|
||
| void POOL_free(POOL_ctx* ctx) { | ||
| assert(!ctx || ctx == &g_ctx); | ||
| (void)ctx; | ||
| } | ||
|
|
||
| int POOL_resize(POOL_ctx* ctx, size_t numThreads) { | ||
| (void)ctx; (void)numThreads; | ||
| return 0; | ||
| } | ||
|
|
||
| void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) { | ||
| (void)ctx; | ||
| function(opaque); | ||
| } | ||
|
|
||
| int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { | ||
| (void)ctx; | ||
| function(opaque); | ||
| return 1; | ||
| } | ||
|
|
||
| size_t POOL_sizeof(POOL_ctx* ctx) { | ||
| if (ctx==NULL) return 0; /* supports sizeof NULL */ | ||
| assert(ctx == &g_ctx); | ||
| return sizeof(*ctx); | ||
| } | ||
|
|
||
| #endif /* ZSTD_MULTITHREAD */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
| #ifndef POOL_H | ||
| #define POOL_H | ||
|
|
||
| #if defined (__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
|
|
||
| #include <stddef.h> /* size_t */ | ||
| #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ | ||
| #include "zstd.h" | ||
|
|
||
| typedef struct POOL_ctx_s POOL_ctx; | ||
|
|
||
| /*! POOL_create() : | ||
| * Create a thread pool with at most `numThreads` threads. | ||
| * `numThreads` must be at least 1. | ||
| * The maximum number of queued jobs before blocking is `queueSize`. | ||
| * @return : POOL_ctx pointer on success, else NULL. | ||
| */ | ||
| POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); | ||
|
|
||
| POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, | ||
| ZSTD_customMem customMem); | ||
|
|
||
| /*! POOL_free() : | ||
| * Free a thread pool returned by POOL_create(). | ||
| */ | ||
| void POOL_free(POOL_ctx* ctx); | ||
|
|
||
| /*! POOL_resize() : | ||
| * Expands or shrinks pool's number of threads. | ||
| * This is more efficient than releasing + creating a new context, | ||
| * since it tries to preserve and re-use existing threads. | ||
| * `numThreads` must be at least 1. | ||
| * @return : 0 when resize was successful, | ||
| * !0 (typically 1) if there is an error. | ||
| * note : only numThreads can be resized, queueSize remains unchanged. | ||
| */ | ||
| int POOL_resize(POOL_ctx* ctx, size_t numThreads); | ||
|
|
||
| /*! POOL_sizeof() : | ||
| * @return threadpool memory usage | ||
| * note : compatible with NULL (returns 0 in this case) | ||
| */ | ||
| size_t POOL_sizeof(POOL_ctx* ctx); | ||
|
|
||
| /*! POOL_function : | ||
| * The function type that can be added to a thread pool. | ||
| */ | ||
| typedef void (*POOL_function)(void*); | ||
|
|
||
| /*! POOL_add() : | ||
| * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. | ||
| * Possibly blocks until there is room in the queue. | ||
| * Note : The function may be executed asynchronously, | ||
| * therefore, `opaque` must live until function has been completed. | ||
| */ | ||
| void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); | ||
|
|
||
|
|
||
| /*! POOL_tryAdd() : | ||
| * Add the job `function(opaque)` to thread pool _if_ a worker is available. | ||
| * Returns immediately even if not (does not block). | ||
| * @return : 1 if successful, 0 if not. | ||
| */ | ||
| int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); | ||
|
|
||
|
|
||
| #if defined (__cplusplus) | ||
| } | ||
| #endif | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| /** | ||
| * Copyright (c) 2016 Tino Reichardt | ||
| * 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 can contact the author at: | ||
| * - zstdmt source repository: https://github.com/mcmilk/zstdmt | ||
| */ | ||
|
|
||
| /** | ||
| * This file will hold wrapper for systems, which do not support pthreads | ||
| */ | ||
|
|
||
| #include "threading.h" | ||
|
|
||
| /* create fake symbol to avoid empty translation unit warning */ | ||
| int g_ZSTD_threading_useless_symbol; | ||
|
|
||
| #if defined(ZSTD_MULTITHREAD) && defined(_WIN32) | ||
|
|
||
| /** | ||
| * Windows minimalist Pthread Wrapper, based on : | ||
| * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html | ||
| */ | ||
|
|
||
|
|
||
| /* === Dependencies === */ | ||
| #include <process.h> | ||
| #include <errno.h> | ||
|
|
||
|
|
||
| /* === Implementation === */ | ||
|
|
||
| static unsigned __stdcall worker(void *arg) | ||
| { | ||
| ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg; | ||
| thread->arg = thread->start_routine(thread->arg); | ||
| return 0; | ||
| } | ||
|
|
||
| int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, | ||
| void* (*start_routine) (void*), void* arg) | ||
| { | ||
| (void)unused; | ||
| thread->arg = arg; | ||
| thread->start_routine = start_routine; | ||
| thread->handle = (HANDLE) _beginthreadex(NULL, 0, worker, thread, 0, NULL); | ||
|
|
||
| if (!thread->handle) | ||
| return errno; | ||
| else | ||
| return 0; | ||
| } | ||
|
|
||
| int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr) | ||
| { | ||
| DWORD result; | ||
|
|
||
| if (!thread.handle) return 0; | ||
|
|
||
| result = WaitForSingleObject(thread.handle, INFINITE); | ||
| switch (result) { | ||
| case WAIT_OBJECT_0: | ||
| if (value_ptr) *value_ptr = thread.arg; | ||
| return 0; | ||
| case WAIT_ABANDONED: | ||
| return EINVAL; | ||
| default: | ||
| return GetLastError(); | ||
| } | ||
| } | ||
|
|
||
| #endif /* ZSTD_MULTITHREAD */ | ||
|
|
||
| #if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) | ||
|
|
||
| #include <stdlib.h> | ||
|
|
||
| int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) | ||
| { | ||
| *mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); | ||
| if (!*mutex) | ||
| return 1; | ||
| return pthread_mutex_init(*mutex, attr); | ||
| } | ||
|
|
||
| int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) | ||
| { | ||
| if (!*mutex) | ||
| return 0; | ||
| { | ||
| int const ret = pthread_mutex_destroy(*mutex); | ||
| free(*mutex); | ||
| return ret; | ||
| } | ||
| } | ||
|
|
||
| int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) | ||
| { | ||
| *cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t)); | ||
| if (!*cond) | ||
| return 1; | ||
| return pthread_cond_init(*cond, attr); | ||
| } | ||
|
|
||
| int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) | ||
| { | ||
| if (!*cond) | ||
| return 0; | ||
| { | ||
| int const ret = pthread_cond_destroy(*cond); | ||
| free(*cond); | ||
| return ret; | ||
| } | ||
| } | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| /** | ||
| * Copyright (c) 2016 Tino Reichardt | ||
| * 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 can contact the author at: | ||
| * - zstdmt source repository: https://github.com/mcmilk/zstdmt | ||
| */ | ||
|
|
||
| #ifndef THREADING_H_938743 | ||
| #define THREADING_H_938743 | ||
|
|
||
| #include "debug.h" | ||
|
|
||
| #if defined (__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #if defined(ZSTD_MULTITHREAD) && defined(_WIN32) | ||
|
|
||
| /** | ||
| * Windows minimalist Pthread Wrapper, based on : | ||
| * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html | ||
| */ | ||
| #ifdef WINVER | ||
| # undef WINVER | ||
| #endif | ||
| #define WINVER 0x0600 | ||
|
|
||
| #ifdef _WIN32_WINNT | ||
| # undef _WIN32_WINNT | ||
| #endif | ||
| #define _WIN32_WINNT 0x0600 | ||
|
|
||
| #ifndef WIN32_LEAN_AND_MEAN | ||
| # define WIN32_LEAN_AND_MEAN | ||
| #endif | ||
|
|
||
| #undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ | ||
| #include <windows.h> | ||
| #undef ERROR | ||
| #define ERROR(name) ZSTD_ERROR(name) | ||
|
|
||
|
|
||
| /* mutex */ | ||
| #define ZSTD_pthread_mutex_t CRITICAL_SECTION | ||
| #define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0) | ||
| #define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) | ||
| #define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) | ||
| #define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) | ||
|
|
||
| /* condition variable */ | ||
| #define ZSTD_pthread_cond_t CONDITION_VARIABLE | ||
| #define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0) | ||
| #define ZSTD_pthread_cond_destroy(a) ((void)(a)) | ||
| #define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) | ||
| #define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) | ||
| #define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) | ||
|
|
||
| /* ZSTD_pthread_create() and ZSTD_pthread_join() */ | ||
| typedef struct { | ||
| HANDLE handle; | ||
| void* (*start_routine)(void*); | ||
| void* arg; | ||
| } ZSTD_pthread_t; | ||
|
|
||
| int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, | ||
| void* (*start_routine) (void*), void* arg); | ||
|
|
||
| int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr); | ||
|
|
||
| /** | ||
| * add here more wrappers as required | ||
| */ | ||
|
|
||
|
|
||
| #elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */ | ||
| /* === POSIX Systems === */ | ||
| # include <pthread.h> | ||
|
|
||
| #if DEBUGLEVEL < 1 | ||
|
|
||
| #define ZSTD_pthread_mutex_t pthread_mutex_t | ||
| #define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) | ||
| #define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) | ||
| #define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) | ||
| #define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) | ||
|
|
||
| #define ZSTD_pthread_cond_t pthread_cond_t | ||
| #define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) | ||
| #define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) | ||
| #define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) | ||
| #define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) | ||
| #define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) | ||
|
|
||
| #define ZSTD_pthread_t pthread_t | ||
| #define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) | ||
| #define ZSTD_pthread_join(a, b) pthread_join((a),(b)) | ||
|
|
||
| #else /* DEBUGLEVEL >= 1 */ | ||
|
|
||
| /* Debug implementation of threading. | ||
| * In this implementation we use pointers for mutexes and condition variables. | ||
| * This way, if we forget to init/destroy them the program will crash or ASAN | ||
| * will report leaks. | ||
| */ | ||
|
|
||
| #define ZSTD_pthread_mutex_t pthread_mutex_t* | ||
| int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr); | ||
| int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex); | ||
| #define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a)) | ||
| #define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a)) | ||
|
|
||
| #define ZSTD_pthread_cond_t pthread_cond_t* | ||
| int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr); | ||
| int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); | ||
| #define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b)) | ||
| #define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a)) | ||
| #define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a)) | ||
|
|
||
| #define ZSTD_pthread_t pthread_t | ||
| #define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) | ||
| #define ZSTD_pthread_join(a, b) pthread_join((a),(b)) | ||
|
|
||
| #endif | ||
|
|
||
| #else /* ZSTD_MULTITHREAD not defined */ | ||
| /* No multithreading support */ | ||
|
|
||
| typedef int ZSTD_pthread_mutex_t; | ||
| #define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0) | ||
| #define ZSTD_pthread_mutex_destroy(a) ((void)(a)) | ||
| #define ZSTD_pthread_mutex_lock(a) ((void)(a)) | ||
| #define ZSTD_pthread_mutex_unlock(a) ((void)(a)) | ||
|
|
||
| typedef int ZSTD_pthread_cond_t; | ||
| #define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0) | ||
| #define ZSTD_pthread_cond_destroy(a) ((void)(a)) | ||
| #define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b)) | ||
| #define ZSTD_pthread_cond_signal(a) ((void)(a)) | ||
| #define ZSTD_pthread_cond_broadcast(a) ((void)(a)) | ||
|
|
||
| /* do not use ZSTD_pthread_t */ | ||
|
|
||
| #endif /* ZSTD_MULTITHREAD */ | ||
|
|
||
| #if defined (__cplusplus) | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* THREADING_H_938743 */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,305 @@ | ||
| /* | ||
| xxHash - Extremely Fast Hash algorithm | ||
| Header File | ||
| Copyright (C) 2012-2016, Yann Collet. | ||
| BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | ||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions are | ||
| met: | ||
| * Redistributions of source code must retain the above copyright | ||
| notice, this list of conditions and the following disclaimer. | ||
| * Redistributions in binary form must reproduce the above | ||
| copyright notice, this list of conditions and the following disclaimer | ||
| in the documentation and/or other materials provided with the | ||
| distribution. | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| You can contact the author at : | ||
| - xxHash source repository : https://github.com/Cyan4973/xxHash | ||
| */ | ||
|
|
||
| /* Notice extracted from xxHash homepage : | ||
| xxHash is an extremely fast Hash algorithm, running at RAM speed limits. | ||
| It also successfully passes all tests from the SMHasher suite. | ||
| Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) | ||
| Name Speed Q.Score Author | ||
| xxHash 5.4 GB/s 10 | ||
| CrapWow 3.2 GB/s 2 Andrew | ||
| MumurHash 3a 2.7 GB/s 10 Austin Appleby | ||
| SpookyHash 2.0 GB/s 10 Bob Jenkins | ||
| SBox 1.4 GB/s 9 Bret Mulvey | ||
| Lookup3 1.2 GB/s 9 Bob Jenkins | ||
| SuperFastHash 1.2 GB/s 1 Paul Hsieh | ||
| CityHash64 1.05 GB/s 10 Pike & Alakuijala | ||
| FNV 0.55 GB/s 5 Fowler, Noll, Vo | ||
| CRC32 0.43 GB/s 9 | ||
| MD5-32 0.33 GB/s 10 Ronald L. Rivest | ||
| SHA1-32 0.28 GB/s 10 | ||
| Q.Score is a measure of quality of the hash function. | ||
| It depends on successfully passing SMHasher test set. | ||
| 10 is a perfect score. | ||
| A 64-bits version, named XXH64, is available since r35. | ||
| It offers much better speed, but for 64-bits applications only. | ||
| Name Speed on 64 bits Speed on 32 bits | ||
| XXH64 13.8 GB/s 1.9 GB/s | ||
| XXH32 6.8 GB/s 6.0 GB/s | ||
| */ | ||
|
|
||
| #if defined (__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #ifndef XXHASH_H_5627135585666179 | ||
| #define XXHASH_H_5627135585666179 1 | ||
|
|
||
|
|
||
| /* **************************** | ||
| * Definitions | ||
| ******************************/ | ||
| #include <stddef.h> /* size_t */ | ||
| typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; | ||
|
|
||
|
|
||
| /* **************************** | ||
| * API modifier | ||
| ******************************/ | ||
| /** XXH_PRIVATE_API | ||
| * This is useful if you want to include xxhash functions in `static` mode | ||
| * in order to inline them, and remove their symbol from the public list. | ||
| * Methodology : | ||
| * #define XXH_PRIVATE_API | ||
| * #include "xxhash.h" | ||
| * `xxhash.c` is automatically included. | ||
| * It's not useful to compile and link it as a separate module anymore. | ||
| */ | ||
| #ifdef XXH_PRIVATE_API | ||
| # ifndef XXH_STATIC_LINKING_ONLY | ||
| # define XXH_STATIC_LINKING_ONLY | ||
| # endif | ||
| # if defined(__GNUC__) | ||
| # define XXH_PUBLIC_API static __inline __attribute__((unused)) | ||
| # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) | ||
| # define XXH_PUBLIC_API static inline | ||
| # elif defined(_MSC_VER) | ||
| # define XXH_PUBLIC_API static __inline | ||
| # else | ||
| # define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */ | ||
| # endif | ||
| #else | ||
| # define XXH_PUBLIC_API /* do nothing */ | ||
| #endif /* XXH_PRIVATE_API */ | ||
|
|
||
| /*!XXH_NAMESPACE, aka Namespace Emulation : | ||
| If you want to include _and expose_ xxHash functions from within your own library, | ||
| but also want to avoid symbol collisions with another library which also includes xxHash, | ||
| you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library | ||
| with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values). | ||
| Note that no change is required within the calling program as long as it includes `xxhash.h` : | ||
| regular symbol name will be automatically translated by this header. | ||
| */ | ||
| #ifdef XXH_NAMESPACE | ||
| # define XXH_CAT(A,B) A##B | ||
| # define XXH_NAME2(A,B) XXH_CAT(A,B) | ||
| # define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) | ||
| # define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) | ||
| # define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) | ||
| # define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) | ||
| # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) | ||
| # define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) | ||
| # define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) | ||
| # define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) | ||
| # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) | ||
| # define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) | ||
| # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) | ||
| # define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) | ||
| # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) | ||
| # define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) | ||
| # define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) | ||
| # define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) | ||
| # define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) | ||
| # define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) | ||
| # define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) | ||
| #endif | ||
|
|
||
|
|
||
| /* ************************************* | ||
| * Version | ||
| ***************************************/ | ||
| #define XXH_VERSION_MAJOR 0 | ||
| #define XXH_VERSION_MINOR 6 | ||
| #define XXH_VERSION_RELEASE 2 | ||
| #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) | ||
| XXH_PUBLIC_API unsigned XXH_versionNumber (void); | ||
|
|
||
|
|
||
| /* **************************** | ||
| * Simple Hash Functions | ||
| ******************************/ | ||
| typedef unsigned int XXH32_hash_t; | ||
| typedef unsigned long long XXH64_hash_t; | ||
|
|
||
| XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed); | ||
| XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed); | ||
|
|
||
| /*! | ||
| XXH32() : | ||
| Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input". | ||
| The memory between input & input+length must be valid (allocated and read-accessible). | ||
| "seed" can be used to alter the result predictably. | ||
| Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s | ||
| XXH64() : | ||
| Calculate the 64-bits hash of sequence of length "len" stored at memory address "input". | ||
| "seed" can be used to alter the result predictably. | ||
| This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark). | ||
| */ | ||
|
|
||
|
|
||
| /* **************************** | ||
| * Streaming Hash Functions | ||
| ******************************/ | ||
| typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ | ||
| typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ | ||
|
|
||
| /*! State allocation, compatible with dynamic libraries */ | ||
|
|
||
| XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); | ||
| XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); | ||
|
|
||
| XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); | ||
| XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); | ||
|
|
||
|
|
||
| /* hash streaming */ | ||
|
|
||
| XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed); | ||
| XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); | ||
| XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); | ||
|
|
||
| XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed); | ||
| XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); | ||
| XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); | ||
|
|
||
| /* | ||
| These functions generate the xxHash of an input provided in multiple segments. | ||
| Note that, for small input, they are slower than single-call functions, due to state management. | ||
| For small input, prefer `XXH32()` and `XXH64()` . | ||
| XXH state must first be allocated, using XXH*_createState() . | ||
| Start a new hash by initializing state with a seed, using XXH*_reset(). | ||
| Then, feed the hash state by calling XXH*_update() as many times as necessary. | ||
| Obviously, input must be allocated and read accessible. | ||
| The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. | ||
| Finally, a hash value can be produced anytime, by using XXH*_digest(). | ||
| This function returns the nn-bits hash as an int or long long. | ||
| It's still possible to continue inserting input into the hash state after a digest, | ||
| and generate some new hashes later on, by calling again XXH*_digest(). | ||
| When done, free XXH state space if it was allocated dynamically. | ||
| */ | ||
|
|
||
|
|
||
| /* ************************** | ||
| * Utils | ||
| ****************************/ | ||
| #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* ! C99 */ | ||
| # define restrict /* disable restrict */ | ||
| #endif | ||
|
|
||
| XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state); | ||
| XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state); | ||
|
|
||
|
|
||
| /* ************************** | ||
| * Canonical representation | ||
| ****************************/ | ||
| /* Default result type for XXH functions are primitive unsigned 32 and 64 bits. | ||
| * The canonical representation uses human-readable write convention, aka big-endian (large digits first). | ||
| * These functions allow transformation of hash result into and from its canonical format. | ||
| * This way, hash values can be written into a file / memory, and remain comparable on different systems and programs. | ||
| */ | ||
| typedef struct { unsigned char digest[4]; } XXH32_canonical_t; | ||
| typedef struct { unsigned char digest[8]; } XXH64_canonical_t; | ||
|
|
||
| XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); | ||
| XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); | ||
|
|
||
| XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); | ||
| XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); | ||
|
|
||
| #endif /* XXHASH_H_5627135585666179 */ | ||
|
|
||
|
|
||
|
|
||
| /* ================================================================================================ | ||
| This section contains definitions which are not guaranteed to remain stable. | ||
| They may change in future versions, becoming incompatible with a different version of the library. | ||
| They shall only be used with static linking. | ||
| Never use these definitions in association with dynamic linking ! | ||
| =================================================================================================== */ | ||
| #if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXH_STATIC_H_3543687687345) | ||
| #define XXH_STATIC_H_3543687687345 | ||
|
|
||
| /* These definitions are only meant to allow allocation of XXH state | ||
| statically, on stack, or in a struct for example. | ||
| Do not use members directly. */ | ||
|
|
||
| struct XXH32_state_s { | ||
| unsigned total_len_32; | ||
| unsigned large_len; | ||
| unsigned v1; | ||
| unsigned v2; | ||
| unsigned v3; | ||
| unsigned v4; | ||
| unsigned mem32[4]; /* buffer defined as U32 for alignment */ | ||
| unsigned memsize; | ||
| unsigned reserved; /* never read nor write, will be removed in a future version */ | ||
| }; /* typedef'd to XXH32_state_t */ | ||
|
|
||
| struct XXH64_state_s { | ||
| unsigned long long total_len; | ||
| unsigned long long v1; | ||
| unsigned long long v2; | ||
| unsigned long long v3; | ||
| unsigned long long v4; | ||
| unsigned long long mem64[4]; /* buffer defined as U64 for alignment */ | ||
| unsigned memsize; | ||
| unsigned reserved[2]; /* never read nor write, will be removed in a future version */ | ||
| }; /* typedef'd to XXH64_state_t */ | ||
|
|
||
|
|
||
| # ifdef XXH_PRIVATE_API | ||
| # include "xxhash.c" /* include xxhash functions as `static`, for inlining */ | ||
| # endif | ||
|
|
||
| #endif /* XXH_STATIC_LINKING_ONLY && XXH_STATIC_H_3543687687345 */ | ||
|
|
||
|
|
||
| #if defined (__cplusplus) | ||
| } | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
|
|
||
|
|
||
| /*-************************************* | ||
| * Dependencies | ||
| ***************************************/ | ||
| #include <stdlib.h> /* malloc, calloc, free */ | ||
| #include <string.h> /* memset */ | ||
| #include "error_private.h" | ||
| #include "zstd_internal.h" | ||
|
|
||
|
|
||
| /*-**************************************** | ||
| * Version | ||
| ******************************************/ | ||
| unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; } | ||
|
|
||
| const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; } | ||
|
|
||
|
|
||
| /*-**************************************** | ||
| * ZSTD Error Management | ||
| ******************************************/ | ||
| #undef ZSTD_isError /* defined within zstd_internal.h */ | ||
| /*! ZSTD_isError() : | ||
| * tells if a return value is an error code | ||
| * symbol is required for external callers */ | ||
| unsigned ZSTD_isError(size_t code) { return ERR_isError(code); } | ||
|
|
||
| /*! ZSTD_getErrorName() : | ||
| * provides error code string from function result (useful for debugging) */ | ||
| const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); } | ||
|
|
||
| /*! ZSTD_getError() : | ||
| * convert a `size_t` function result into a proper ZSTD_errorCode enum */ | ||
| ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } | ||
|
|
||
| /*! ZSTD_getErrorString() : | ||
| * provides error code string from enum */ | ||
| const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } | ||
|
|
||
|
|
||
|
|
||
| /*=************************************************************** | ||
| * Custom allocator | ||
| ****************************************************************/ | ||
| void* ZSTD_malloc(size_t size, ZSTD_customMem customMem) | ||
| { | ||
| if (customMem.customAlloc) | ||
| return customMem.customAlloc(customMem.opaque, size); | ||
| return malloc(size); | ||
| } | ||
|
|
||
| void* ZSTD_calloc(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); | ||
| memset(ptr, 0, size); | ||
| return ptr; | ||
| } | ||
| return calloc(1, size); | ||
| } | ||
|
|
||
| void ZSTD_free(void* ptr, ZSTD_customMem customMem) | ||
| { | ||
| if (ptr!=NULL) { | ||
| if (customMem.customFree) | ||
| customMem.customFree(customMem.opaque, ptr); | ||
| else | ||
| free(ptr); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
| #ifndef ZSTD_ERRORS_H_398273423 | ||
| #define ZSTD_ERRORS_H_398273423 | ||
|
|
||
| #if defined (__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /*===== dependency =====*/ | ||
| #include <stddef.h> /* size_t */ | ||
|
|
||
|
|
||
| /* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ | ||
| #ifndef ZSTDERRORLIB_VISIBILITY | ||
| # if defined(__GNUC__) && (__GNUC__ >= 4) | ||
| # define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) | ||
| # else | ||
| # define ZSTDERRORLIB_VISIBILITY | ||
| # endif | ||
| #endif | ||
| #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) | ||
| # define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY | ||
| #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) | ||
| # define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ | ||
| #else | ||
| # define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY | ||
| #endif | ||
|
|
||
| /*-********************************************* | ||
| * Error codes list | ||
| *-********************************************* | ||
| * Error codes _values_ are pinned down since v1.3.1 only. | ||
| * Therefore, don't rely on values if you may link to any version < v1.3.1. | ||
| * | ||
| * Only values < 100 are considered stable. | ||
| * | ||
| * note 1 : this API shall be used with static linking only. | ||
| * dynamic linking is not yet officially supported. | ||
| * note 2 : Prefer relying on the enum than on its value whenever possible | ||
| * This is the only supported way to use the error list < v1.3.1 | ||
| * note 3 : ZSTD_isError() is always correct, whatever the library version. | ||
| **********************************************/ | ||
| typedef enum { | ||
| ZSTD_error_no_error = 0, | ||
| ZSTD_error_GENERIC = 1, | ||
| ZSTD_error_prefix_unknown = 10, | ||
| ZSTD_error_version_unsupported = 12, | ||
| ZSTD_error_frameParameter_unsupported = 14, | ||
| ZSTD_error_frameParameter_windowTooLarge = 16, | ||
| ZSTD_error_corruption_detected = 20, | ||
| ZSTD_error_checksum_wrong = 22, | ||
| ZSTD_error_dictionary_corrupted = 30, | ||
| ZSTD_error_dictionary_wrong = 32, | ||
| ZSTD_error_dictionaryCreation_failed = 34, | ||
| ZSTD_error_parameter_unsupported = 40, | ||
| ZSTD_error_parameter_outOfBound = 42, | ||
| ZSTD_error_tableLog_tooLarge = 44, | ||
| ZSTD_error_maxSymbolValue_tooLarge = 46, | ||
| ZSTD_error_maxSymbolValue_tooSmall = 48, | ||
| ZSTD_error_stage_wrong = 60, | ||
| ZSTD_error_init_missing = 62, | ||
| ZSTD_error_memory_allocation = 64, | ||
| ZSTD_error_workSpace_tooSmall= 66, | ||
| ZSTD_error_dstSize_tooSmall = 70, | ||
| ZSTD_error_srcSize_wrong = 72, | ||
| ZSTD_error_dstBuffer_null = 74, | ||
| /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ | ||
| ZSTD_error_frameIndex_tooLarge = 100, | ||
| ZSTD_error_seekableIO = 102, | ||
| ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ | ||
| } ZSTD_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 */ | ||
|
|
||
|
|
||
| #if defined (__cplusplus) | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* ZSTD_ERRORS_H_398273423 */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,350 @@ | ||
| /* | ||
| * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under both the BSD-style license (found in the | ||
| * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||
| * in the COPYING file in the root directory of this source tree). | ||
| * You may select, at your option, one of the above-listed licenses. | ||
| */ | ||
|
|
||
| #ifndef ZSTD_CCOMMON_H_MODULE | ||
| #define ZSTD_CCOMMON_H_MODULE | ||
|
|
||
| /* this module contains definitions which must be identical | ||
| * across compression, decompression and dictBuilder. | ||
| * It also contains a few functions useful to at least 2 of them | ||
| * and which benefit from being inlined */ | ||
|
|
||
| /*-************************************* | ||
| * Dependencies | ||
| ***************************************/ | ||
| #include "compiler.h" | ||
| #include "mem.h" | ||
| #include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ | ||
| #include "error_private.h" | ||
| #define ZSTD_STATIC_LINKING_ONLY | ||
| #include "zstd.h" | ||
| #define FSE_STATIC_LINKING_ONLY | ||
| #include "fse.h" | ||
| #define HUF_STATIC_LINKING_ONLY | ||
| #include "huf.h" | ||
| #ifndef XXH_STATIC_LINKING_ONLY | ||
| # define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ | ||
| #endif | ||
| #include "xxhash.h" /* XXH_reset, update, digest */ | ||
|
|
||
| #if defined (__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /* ---- static assert (debug) --- */ | ||
| #define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) | ||
| #define ZSTD_isError ERR_isError /* for inlining */ | ||
| #define FSE_isError ERR_isError | ||
| #define HUF_isError ERR_isError | ||
|
|
||
|
|
||
| /*-************************************* | ||
| * shared macros | ||
| ***************************************/ | ||
| #undef MIN | ||
| #undef MAX | ||
| #define MIN(a,b) ((a)<(b) ? (a) : (b)) | ||
| #define MAX(a,b) ((a)>(b) ? (a) : (b)) | ||
|
|
||
| /** | ||
| * Return the specified error if the condition evaluates to true. | ||
| * | ||
| * In debug modes, prints additional information. | ||
| * In order to do that (particularly, printing the conditional that failed), | ||
| * this can't just wrap RETURN_ERROR(). | ||
| */ | ||
| #define RETURN_ERROR_IF(cond, err, ...) \ | ||
| if (cond) { \ | ||
| RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", __FILE__, __LINE__, ZSTD_QUOTE(cond), ZSTD_QUOTE(ERROR(err))); \ | ||
| RAWLOG(3, ": " __VA_ARGS__); \ | ||
| RAWLOG(3, "\n"); \ | ||
| return ERROR(err); \ | ||
| } | ||
|
|
||
| /** | ||
| * Unconditionally return the specified error. | ||
| * | ||
| * In debug modes, prints additional information. | ||
| */ | ||
| #define RETURN_ERROR(err, ...) \ | ||
| do { \ | ||
| RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", __FILE__, __LINE__, ZSTD_QUOTE(ERROR(err))); \ | ||
| RAWLOG(3, ": " __VA_ARGS__); \ | ||
| RAWLOG(3, "\n"); \ | ||
| return ERROR(err); \ | ||
| } while(0); | ||
|
|
||
| /** | ||
| * If the provided expression evaluates to an error code, returns that error code. | ||
| * | ||
| * In debug modes, prints additional information. | ||
| */ | ||
| #define FORWARD_IF_ERROR(err, ...) \ | ||
| do { \ | ||
| size_t const err_code = (err); \ | ||
| if (ERR_isError(err_code)) { \ | ||
| RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", __FILE__, __LINE__, ZSTD_QUOTE(err), ERR_getErrorName(err_code)); \ | ||
| RAWLOG(3, ": " __VA_ARGS__); \ | ||
| RAWLOG(3, "\n"); \ | ||
| return err_code; \ | ||
| } \ | ||
| } while(0); | ||
|
|
||
|
|
||
| /*-************************************* | ||
| * Common constants | ||
| ***************************************/ | ||
| #define ZSTD_OPT_NUM (1<<12) | ||
|
|
||
| #define ZSTD_REP_NUM 3 /* number of repcodes */ | ||
| #define ZSTD_REP_MOVE (ZSTD_REP_NUM-1) | ||
| static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; | ||
|
|
||
| #define KB *(1 <<10) | ||
| #define MB *(1 <<20) | ||
| #define GB *(1U<<30) | ||
|
|
||
| #define BIT7 128 | ||
| #define BIT6 64 | ||
| #define BIT5 32 | ||
| #define BIT4 16 | ||
| #define BIT1 2 | ||
| #define BIT0 1 | ||
|
|
||
| #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 | ||
| static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; | ||
| static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; | ||
|
|
||
| #define ZSTD_FRAMEIDSIZE 4 /* magic number size */ | ||
|
|
||
| #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ | ||
| static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; | ||
| typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; | ||
|
|
||
| #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ | ||
| #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ | ||
|
|
||
| #define HufLog 12 | ||
| typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; | ||
|
|
||
| #define LONGNBSEQ 0x7F00 | ||
|
|
||
| #define MINMATCH 3 | ||
|
|
||
| #define Litbits 8 | ||
| #define MaxLit ((1<<Litbits) - 1) | ||
| #define MaxML 52 | ||
| #define MaxLL 35 | ||
| #define DefaultMaxOff 28 | ||
| #define MaxOff 31 | ||
| #define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */ | ||
| #define MLFSELog 9 | ||
| #define LLFSELog 9 | ||
| #define OffFSELog 8 | ||
| #define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog) | ||
|
|
||
| static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 1, 1, 1, 1, 2, 2, 3, 3, | ||
| 4, 6, 7, 8, 9,10,11,12, | ||
| 13,14,15,16 }; | ||
| static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, | ||
| 2, 2, 2, 2, 2, 1, 1, 1, | ||
| 2, 2, 2, 2, 2, 2, 2, 2, | ||
| 2, 3, 2, 1, 1, 1, 1, 1, | ||
| -1,-1,-1,-1 }; | ||
| #define LL_DEFAULTNORMLOG 6 /* for static allocation */ | ||
| static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG; | ||
|
|
||
| static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 1, 1, 1, 1, 2, 2, 3, 3, | ||
| 4, 4, 5, 7, 8, 9,10,11, | ||
| 12,13,14,15,16 }; | ||
| static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, | ||
| 2, 1, 1, 1, 1, 1, 1, 1, | ||
| 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 1, 1, 1, 1, 1, 1,-1,-1, | ||
| -1,-1,-1,-1,-1 }; | ||
| #define ML_DEFAULTNORMLOG 6 /* for static allocation */ | ||
| static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG; | ||
|
|
||
| static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, | ||
| 2, 1, 1, 1, 1, 1, 1, 1, | ||
| 1, 1, 1, 1, 1, 1, 1, 1, | ||
| -1,-1,-1,-1,-1 }; | ||
| #define OF_DEFAULTNORMLOG 5 /* for static allocation */ | ||
| static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG; | ||
|
|
||
|
|
||
| /*-******************************************* | ||
| * Shared functions to include for inlining | ||
| *********************************************/ | ||
| static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } | ||
|
|
||
| #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; } | ||
| static void ZSTD_copy16(void* dst, const void* src) { memcpy(dst, src, 16); } | ||
| #define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; } | ||
|
|
||
| #define WILDCOPY_OVERLENGTH 32 | ||
| #define WILDCOPY_VECLEN 16 | ||
|
|
||
| typedef enum { | ||
| ZSTD_no_overlap, | ||
| ZSTD_overlap_src_before_dst | ||
| /* ZSTD_overlap_dst_before_src, */ | ||
| } ZSTD_overlap_e; | ||
|
|
||
| /*! ZSTD_wildcopy() : | ||
| * Custom version of memcpy(), can over read/write up to WILDCOPY_OVERLENGTH bytes (if length==0) | ||
| * @param ovtype controls the overlap detection | ||
| * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart. | ||
| * - ZSTD_overlap_src_before_dst: The src and dst may overlap, but they MUST be at least 8 bytes apart. | ||
| * The src buffer must be before the dst buffer. | ||
| */ | ||
| MEM_STATIC FORCE_INLINE_ATTR DONT_VECTORIZE | ||
| void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e const ovtype) | ||
| { | ||
| ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src; | ||
| const BYTE* ip = (const BYTE*)src; | ||
| BYTE* op = (BYTE*)dst; | ||
| BYTE* const oend = op + length; | ||
|
|
||
| assert(diff >= 8 || (ovtype == ZSTD_no_overlap && diff <= -WILDCOPY_VECLEN)); | ||
|
|
||
| if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) { | ||
| /* Handle short offset copies. */ | ||
| do { | ||
| COPY8(op, ip) | ||
| } while (op < oend); | ||
| } else { | ||
| assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); | ||
| /* Separate out the first two COPY16() calls because the copy length is | ||
| * almost certain to be short, so the branches have different | ||
| * probabilities. | ||
| * On gcc-9 unrolling once is +1.6%, twice is +2%, thrice is +1.8%. | ||
| * On clang-8 unrolling once is +1.4%, twice is +3.3%, thrice is +3%. | ||
| */ | ||
| COPY16(op, ip); | ||
| COPY16(op, ip); | ||
| if (op >= oend) return; | ||
| do { | ||
| COPY16(op, ip); | ||
| COPY16(op, ip); | ||
| } | ||
| while (op < oend); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /*-******************************************* | ||
| * Private declarations | ||
| *********************************************/ | ||
| typedef struct seqDef_s { | ||
| U32 offset; | ||
| U16 litLength; | ||
| U16 matchLength; | ||
| } seqDef; | ||
|
|
||
| typedef struct { | ||
| seqDef* sequencesStart; | ||
| seqDef* sequences; | ||
| BYTE* litStart; | ||
| BYTE* lit; | ||
| BYTE* llCode; | ||
| BYTE* mlCode; | ||
| BYTE* ofCode; | ||
| size_t maxNbSeq; | ||
| size_t maxNbLit; | ||
| U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */ | ||
| U32 longLengthPos; | ||
| } seqStore_t; | ||
|
|
||
| /** | ||
| * Contains the compressed frame size and an upper-bound for the decompressed frame size. | ||
| * Note: before using `compressedSize`, check for errors using ZSTD_isError(). | ||
| * similarly, before using `decompressedBound`, check for errors using: | ||
| * `decompressedBound != ZSTD_CONTENTSIZE_ERROR` | ||
| */ | ||
| typedef struct { | ||
| size_t compressedSize; | ||
| unsigned long long decompressedBound; | ||
| } 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_malloc(size_t size, ZSTD_customMem customMem); | ||
| void* ZSTD_calloc(size_t size, ZSTD_customMem customMem); | ||
| void ZSTD_free(void* ptr, ZSTD_customMem customMem); | ||
|
|
||
|
|
||
| MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ | ||
| { | ||
| assert(val != 0); | ||
| { | ||
| # if defined(_MSC_VER) /* Visual */ | ||
| unsigned long r=0; | ||
| _BitScanReverse(&r, val); | ||
| return (unsigned)r; | ||
| # elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ | ||
| return __builtin_clz (val) ^ 31; | ||
| # elif defined(__ICCARM__) /* IAR Intrinsic */ | ||
| return 31 - __CLZ(val); | ||
| # 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 | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /* ZSTD_invalidateRepCodes() : | ||
| * ensures next compression will not use repcodes from previous block. | ||
| * Note : only works with regular variant; | ||
| * do not use with extDict variant ! */ | ||
| void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */ | ||
|
|
||
|
|
||
| typedef struct { | ||
| blockType_e blockType; | ||
| U32 lastBlock; | ||
| U32 origSize; | ||
| } blockProperties_t; /* declared here for decompress and fullbench */ | ||
|
|
||
| /*! ZSTD_getcBlockSize() : | ||
| * Provides the size of compressed block from block header `src` */ | ||
| /* Used by: decompress, fullbench (does not get its definition from here) */ | ||
| size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, | ||
| blockProperties_t* bpPtr); | ||
|
|
||
| /*! ZSTD_decodeSeqHeaders() : | ||
| * decode sequence header from src */ | ||
| /* Used by: decompress, fullbench (does not get its definition from here) */ | ||
| size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, | ||
| const void* src, size_t srcSize); | ||
|
|
||
|
|
||
| #if defined (__cplusplus) | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* ZSTD_CCOMMON_H_MODULE */ |