comparison contrib/python-zstandard/zstd/compress/zstd_compress.c @ 30895:c32454d69b85

zstd: vendor python-zstandard 0.7.0 Commit 3054ae3a66112970a091d3939fee32c2d0c1a23e from https://github.com/indygreg/python-zstandard is imported without modifications (other than removing unwanted files). The vendored zstd library within has been upgraded from 1.1.2 to 1.1.3. This version introduced new APIs for threads, thread pools, multi-threaded compression, and a new dictionary builder (COVER). These features are not yet used by python-zstandard (or Mercurial for that matter). However, that will likely change in the next python-zstandard release (and I think there are opportunities for Mercurial to take advantage of the multi-threaded APIs). Relevant to Mercurial, the CFFI bindings are now fully implemented. This means zstd should "just work" with PyPy (although I haven't tried). The python-zstandard test suite also runs all tests against both the C extension and CFFI bindings to ensure feature parity. There is also a "decompress_content_dict_chain()" API. This was derived from discussions with Yann Collet on list about alternate ways of encoding delta chains. The change most relevant to Mercurial is a performance enhancement in the simple decompression API to reuse a data structure across operations. This makes decompression of multiple inputs significantly faster. (This scenario occurs when reading revlog delta chains, for example.) Using python-zstandard's bench.py to measure the performance difference... On changelog chunks in the mozilla-unified repo: decompress discrete decompress() reuse zctx 1.262243 wall; 1.260000 CPU; 1.260000 user; 0.000000 sys 170.43 MB/s (best of 3) 0.949106 wall; 0.950000 CPU; 0.950000 user; 0.000000 sys 226.66 MB/s (best of 4) decompress discrete dict decompress() reuse zctx 0.692170 wall; 0.690000 CPU; 0.690000 user; 0.000000 sys 310.80 MB/s (best of 5) 0.437088 wall; 0.440000 CPU; 0.440000 user; 0.000000 sys 492.17 MB/s (best of 7) On manifest chunks in the mozilla-unified repo: decompress discrete decompress() reuse zctx 1.367284 wall; 1.370000 CPU; 1.370000 user; 0.000000 sys 274.01 MB/s (best of 3) 1.086831 wall; 1.080000 CPU; 1.080000 user; 0.000000 sys 344.72 MB/s (best of 3) decompress discrete dict decompress() reuse zctx 0.993272 wall; 0.990000 CPU; 0.990000 user; 0.000000 sys 377.19 MB/s (best of 3) 0.678651 wall; 0.680000 CPU; 0.680000 user; 0.000000 sys 552.06 MB/s (best of 5) That should make reads on zstd revlogs a bit faster ;) # no-check-commit
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 07 Feb 2017 23:24:47 -0800
parents b54a2984cdd4
children b1fb341d8a61
comparison
equal deleted inserted replaced
30894:5b60464efbde 30895:c32454d69b85
49 49
50 50
51 /*-************************************* 51 /*-*************************************
52 * Context memory management 52 * Context memory management
53 ***************************************/ 53 ***************************************/
54 struct ZSTD_CCtx_s 54 struct ZSTD_CCtx_s {
55 {
56 const BYTE* nextSrc; /* next block here to continue on current prefix */ 55 const BYTE* nextSrc; /* next block here to continue on current prefix */
57 const BYTE* base; /* All regular indexes relative to this position */ 56 const BYTE* base; /* All regular indexes relative to this position */
58 const BYTE* dictBase; /* extDict indexes relative to this position */ 57 const BYTE* dictBase; /* extDict indexes relative to this position */
59 U32 dictLimit; /* below that point, need extDict */ 58 U32 dictLimit; /* below that point, need extDict */
60 U32 lowLimit; /* below that point, no more data */ 59 U32 lowLimit; /* below that point, no more data */
61 U32 nextToUpdate; /* index from which to continue dictionary update */ 60 U32 nextToUpdate; /* index from which to continue dictionary update */
62 U32 nextToUpdate3; /* index from which to continue dictionary update */ 61 U32 nextToUpdate3; /* index from which to continue dictionary update */
63 U32 hashLog3; /* dispatch table : larger == faster, more memory */ 62 U32 hashLog3; /* dispatch table : larger == faster, more memory */
64 U32 loadedDictEnd; 63 U32 loadedDictEnd; /* index of end of dictionary */
64 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
65 ZSTD_compressionStage_e stage; 65 ZSTD_compressionStage_e stage;
66 U32 rep[ZSTD_REP_NUM]; 66 U32 rep[ZSTD_REP_NUM];
67 U32 savedRep[ZSTD_REP_NUM]; 67 U32 repToConfirm[ZSTD_REP_NUM];
68 U32 dictID; 68 U32 dictID;
69 ZSTD_parameters params; 69 ZSTD_parameters params;
70 void* workSpace; 70 void* workSpace;
71 size_t workSpaceSize; 71 size_t workSpaceSize;
72 size_t blockSize; 72 size_t blockSize;
99 if (!customMem.customAlloc || !customMem.customFree) return NULL; 99 if (!customMem.customAlloc || !customMem.customFree) return NULL;
100 100
101 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); 101 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
102 if (!cctx) return NULL; 102 if (!cctx) return NULL;
103 memset(cctx, 0, sizeof(ZSTD_CCtx)); 103 memset(cctx, 0, sizeof(ZSTD_CCtx));
104 memcpy(&(cctx->customMem), &customMem, sizeof(customMem)); 104 cctx->customMem = customMem;
105 return cctx; 105 return cctx;
106 } 106 }
107 107
108 size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 108 size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
109 { 109 {
115 115
116 size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 116 size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
117 { 117 {
118 if (cctx==NULL) return 0; /* support sizeof on NULL */ 118 if (cctx==NULL) return 0; /* support sizeof on NULL */
119 return sizeof(*cctx) + cctx->workSpaceSize; 119 return sizeof(*cctx) + cctx->workSpaceSize;
120 }
121
122 size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
123 {
124 switch(param)
125 {
126 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
127 default: return ERROR(parameter_unknown);
128 }
120 } 129 }
121 130
122 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */ 131 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
123 { 132 {
124 return &(ctx->seqStore); 133 return &(ctx->seqStore);
316 325
317 return 0; 326 return 0;
318 } 327 }
319 } 328 }
320 329
330 /* ZSTD_invalidateRepCodes() :
331 * ensures next compression will not use repcodes from previous block.
332 * Note : only works with regular variant;
333 * do not use with extDict variant ! */
334 void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
335 int i;
336 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
337 }
321 338
322 /*! ZSTD_copyCCtx() : 339 /*! ZSTD_copyCCtx() :
323 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 340 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
324 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 341 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
325 * @return : 0, or an error code */ 342 * @return : 0, or an error code */
733 { size_t const minGain = ZSTD_minGain(srcSize); 750 { size_t const minGain = ZSTD_minGain(srcSize);
734 size_t const maxCSize = srcSize - minGain; 751 size_t const maxCSize = srcSize - minGain;
735 if ((size_t)(op-ostart) >= maxCSize) return 0; } 752 if ((size_t)(op-ostart) >= maxCSize) return 0; }
736 753
737 /* confirm repcodes */ 754 /* confirm repcodes */
738 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; } 755 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
739 756
740 return op - ostart; 757 return op - ostart;
741 } 758 }
742 759
760
761 #if 0 /* for debug */
762 # define STORESEQ_DEBUG
763 #include <stdio.h> /* fprintf */
764 U32 g_startDebug = 0;
765 const BYTE* g_start = NULL;
766 #endif
743 767
744 /*! ZSTD_storeSeq() : 768 /*! ZSTD_storeSeq() :
745 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t. 769 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
746 `offsetCode` : distance to match, or 0 == repCode. 770 `offsetCode` : distance to match, or 0 == repCode.
747 `matchCode` : matchLength - MINMATCH 771 `matchCode` : matchLength - MINMATCH
748 */ 772 */
749 MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode) 773 MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
750 { 774 {
751 #if 0 /* for debug */ 775 #ifdef STORESEQ_DEBUG
752 static const BYTE* g_start = NULL; 776 if (g_startDebug) {
753 const U32 pos = (U32)((const BYTE*)literals - g_start); 777 const U32 pos = (U32)((const BYTE*)literals - g_start);
754 if (g_start==NULL) g_start = (const BYTE*)literals; 778 if (g_start==NULL) g_start = (const BYTE*)literals;
755 //if ((pos > 1) && (pos < 50000)) 779 if ((pos > 1895000) && (pos < 1895300))
756 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n", 780 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
757 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode); 781 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
782 }
758 #endif 783 #endif
759 /* copy Literals */ 784 /* copy Literals */
760 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength); 785 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
761 seqStorePtr->lit += litLength; 786 seqStorePtr->lit += litLength;
762 787
1002 anchor = ip; 1027 anchor = ip;
1003 continue; /* faster when present ... (?) */ 1028 continue; /* faster when present ... (?) */
1004 } } } 1029 } } }
1005 1030
1006 /* save reps for next block */ 1031 /* save reps for next block */
1007 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved; 1032 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1008 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved; 1033 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
1009 1034
1010 /* Last Literals */ 1035 /* Last Literals */
1011 { size_t const lastLLSize = iend - anchor; 1036 { size_t const lastLLSize = iend - anchor;
1012 memcpy(seqStorePtr->lit, anchor, lastLLSize); 1037 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1013 seqStorePtr->lit += lastLLSize; 1038 seqStorePtr->lit += lastLLSize;
1117 } 1142 }
1118 break; 1143 break;
1119 } } } 1144 } } }
1120 1145
1121 /* save reps for next block */ 1146 /* save reps for next block */
1122 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2; 1147 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
1123 1148
1124 /* Last Literals */ 1149 /* Last Literals */
1125 { size_t const lastLLSize = iend - anchor; 1150 { size_t const lastLLSize = iend - anchor;
1126 memcpy(seqStorePtr->lit, anchor, lastLLSize); 1151 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1127 seqStorePtr->lit += lastLLSize; 1152 seqStorePtr->lit += lastLLSize;
1271 anchor = ip; 1296 anchor = ip;
1272 continue; /* faster when present ... (?) */ 1297 continue; /* faster when present ... (?) */
1273 } } } 1298 } } }
1274 1299
1275 /* save reps for next block */ 1300 /* save reps for next block */
1276 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved; 1301 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1277 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved; 1302 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
1278 1303
1279 /* Last Literals */ 1304 /* Last Literals */
1280 { size_t const lastLLSize = iend - anchor; 1305 { size_t const lastLLSize = iend - anchor;
1281 memcpy(seqStorePtr->lit, anchor, lastLLSize); 1306 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1282 seqStorePtr->lit += lastLLSize; 1307 seqStorePtr->lit += lastLLSize;
1421 } 1446 }
1422 break; 1447 break;
1423 } } } 1448 } } }
1424 1449
1425 /* save reps for next block */ 1450 /* save reps for next block */
1426 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2; 1451 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
1427 1452
1428 /* Last Literals */ 1453 /* Last Literals */
1429 { size_t const lastLLSize = iend - anchor; 1454 { size_t const lastLLSize = iend - anchor;
1430 memcpy(seqStorePtr->lit, anchor, lastLLSize); 1455 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1431 seqStorePtr->lit += lastLLSize; 1456 seqStorePtr->lit += lastLLSize;
1953 anchor = ip; 1978 anchor = ip;
1954 continue; /* faster when present ... (?) */ 1979 continue; /* faster when present ... (?) */
1955 } } 1980 } }
1956 1981
1957 /* Save reps for next block */ 1982 /* Save reps for next block */
1958 ctx->savedRep[0] = offset_1 ? offset_1 : savedOffset; 1983 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
1959 ctx->savedRep[1] = offset_2 ? offset_2 : savedOffset; 1984 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
1960 1985
1961 /* Last Literals */ 1986 /* Last Literals */
1962 { size_t const lastLLSize = iend - anchor; 1987 { size_t const lastLLSize = iend - anchor;
1963 memcpy(seqStorePtr->lit, anchor, lastLLSize); 1988 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1964 seqStorePtr->lit += lastLLSize; 1989 seqStorePtr->lit += lastLLSize;
2148 } 2173 }
2149 break; 2174 break;
2150 } } 2175 } }
2151 2176
2152 /* Save reps for next block */ 2177 /* Save reps for next block */
2153 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2; 2178 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
2154 2179
2155 /* Last Literals */ 2180 /* Last Literals */
2156 { size_t const lastLLSize = iend - anchor; 2181 { size_t const lastLLSize = iend - anchor;
2157 memcpy(seqStorePtr->lit, anchor, lastLLSize); 2182 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2158 seqStorePtr->lit += lastLLSize; 2183 seqStorePtr->lit += lastLLSize;
2407 cctx->lowLimit = lowLimitMax; 2432 cctx->lowLimit = lowLimitMax;
2408 } 2433 }
2409 2434
2410 cctx->nextSrc = ip + srcSize; 2435 cctx->nextSrc = ip + srcSize;
2411 2436
2412 { size_t const cSize = frame ? 2437 if (srcSize) {
2438 size_t const cSize = frame ?
2413 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 2439 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2414 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); 2440 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
2415 if (ZSTD_isError(cSize)) return cSize; 2441 if (ZSTD_isError(cSize)) return cSize;
2416 return cSize + fhSize; 2442 return cSize + fhSize;
2417 } 2443 } else
2444 return fhSize;
2418 } 2445 }
2419 2446
2420 2447
2421 size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 2448 size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
2422 void* dst, size_t dstCapacity, 2449 void* dst, size_t dstCapacity,
2448 zc->lowLimit = zc->dictLimit; 2475 zc->lowLimit = zc->dictLimit;
2449 zc->dictLimit = (U32)(zc->nextSrc - zc->base); 2476 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2450 zc->dictBase = zc->base; 2477 zc->dictBase = zc->base;
2451 zc->base += ip - zc->nextSrc; 2478 zc->base += ip - zc->nextSrc;
2452 zc->nextToUpdate = zc->dictLimit; 2479 zc->nextToUpdate = zc->dictLimit;
2453 zc->loadedDictEnd = (U32)(iend - zc->base); 2480 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
2454 2481
2455 zc->nextSrc = iend; 2482 zc->nextSrc = iend;
2456 if (srcSize <= HASH_READ_SIZE) return 0; 2483 if (srcSize <= HASH_READ_SIZE) return 0;
2457 2484
2458 switch(zc->params.cParams.strategy) 2485 switch(zc->params.cParams.strategy)
2555 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted); 2582 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
2556 dictPtr += litlengthHeaderSize; 2583 dictPtr += litlengthHeaderSize;
2557 } 2584 }
2558 2585
2559 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted); 2586 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
2560 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted); 2587 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2561 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted); 2588 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2562 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted); 2589 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] == 0 || cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
2563 dictPtr += 12; 2590 dictPtr += 12;
2564 2591
2565 { U32 offcodeMax = MaxOff; 2592 { U32 offcodeMax = MaxOff;
2566 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) { 2593 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {
2567 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */ 2594 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */
2592 if (ZSTD_isError(loadError)) return loadError; 2619 if (ZSTD_isError(loadError)) return loadError;
2593 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); 2620 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2594 } 2621 }
2595 } 2622 }
2596 2623
2597
2598 /*! ZSTD_compressBegin_internal() : 2624 /*! ZSTD_compressBegin_internal() :
2599 * @return : 0, or an error code */ 2625 * @return : 0, or an error code */
2600 static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 2626 static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
2601 const void* dict, size_t dictSize, 2627 const void* dict, size_t dictSize,
2602 ZSTD_parameters params, U64 pledgedSrcSize) 2628 ZSTD_parameters params, U64 pledgedSrcSize)
2624 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); 2650 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
2625 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0); 2651 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
2626 } 2652 }
2627 2653
2628 2654
2629 size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) 2655 size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
2630 { 2656 {
2631 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel); 2657 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
2632 } 2658 }
2633 2659
2634 2660
2635 /*! ZSTD_writeEpilogue() : 2661 /*! ZSTD_writeEpilogue() :
2636 * Ends a frame. 2662 * Ends a frame.
2731 2757
2732 2758
2733 /* ===== Dictionary API ===== */ 2759 /* ===== Dictionary API ===== */
2734 2760
2735 struct ZSTD_CDict_s { 2761 struct ZSTD_CDict_s {
2736 void* dictContent; 2762 void* dictBuffer;
2763 const void* dictContent;
2737 size_t dictContentSize; 2764 size_t dictContentSize;
2738 ZSTD_CCtx* refContext; 2765 ZSTD_CCtx* refContext;
2739 }; /* typedef'd tp ZSTD_CDict within "zstd.h" */ 2766 }; /* typedef'd tp ZSTD_CDict within "zstd.h" */
2740 2767
2741 size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 2768 size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2742 { 2769 {
2743 if (cdict==NULL) return 0; /* support sizeof on NULL */ 2770 if (cdict==NULL) return 0; /* support sizeof on NULL */
2744 return ZSTD_sizeof_CCtx(cdict->refContext) + cdict->dictContentSize; 2771 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
2745 } 2772 }
2746 2773
2747 ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem) 2774 ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2775 ZSTD_parameters params, ZSTD_customMem customMem)
2748 { 2776 {
2749 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; 2777 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2750 if (!customMem.customAlloc || !customMem.customFree) return NULL; 2778 if (!customMem.customAlloc || !customMem.customFree) return NULL;
2751 2779
2752 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem); 2780 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
2753 void* const dictContent = ZSTD_malloc(dictSize, customMem);
2754 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); 2781 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2755 2782
2756 if (!dictContent || !cdict || !cctx) { 2783 if (!cdict || !cctx) {
2757 ZSTD_free(dictContent, customMem);
2758 ZSTD_free(cdict, customMem); 2784 ZSTD_free(cdict, customMem);
2759 ZSTD_free(cctx, customMem); 2785 ZSTD_free(cctx, customMem);
2760 return NULL; 2786 return NULL;
2761 } 2787 }
2762 2788
2763 if (dictSize) { 2789 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2764 memcpy(dictContent, dict, dictSize); 2790 cdict->dictBuffer = NULL;
2791 cdict->dictContent = dictBuffer;
2792 } else {
2793 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
2794 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
2795 memcpy(internalBuffer, dictBuffer, dictSize);
2796 cdict->dictBuffer = internalBuffer;
2797 cdict->dictContent = internalBuffer;
2765 } 2798 }
2766 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, dictContent, dictSize, params, 0); 2799
2800 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
2767 if (ZSTD_isError(errorCode)) { 2801 if (ZSTD_isError(errorCode)) {
2768 ZSTD_free(dictContent, customMem); 2802 ZSTD_free(cdict->dictBuffer, customMem);
2803 ZSTD_free(cctx, customMem);
2769 ZSTD_free(cdict, customMem); 2804 ZSTD_free(cdict, customMem);
2770 ZSTD_free(cctx, customMem);
2771 return NULL; 2805 return NULL;
2772 } } 2806 } }
2773 2807
2774 cdict->dictContent = dictContent; 2808 cdict->refContext = cctx;
2775 cdict->dictContentSize = dictSize; 2809 cdict->dictContentSize = dictSize;
2776 cdict->refContext = cctx;
2777 return cdict; 2810 return cdict;
2778 } 2811 }
2779 } 2812 }
2780 2813
2781 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 2814 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2782 { 2815 {
2783 ZSTD_customMem const allocator = { NULL, NULL, NULL }; 2816 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2784 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize); 2817 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2785 params.fParams.contentSizeFlag = 1; 2818 params.fParams.contentSizeFlag = 1;
2786 return ZSTD_createCDict_advanced(dict, dictSize, params, allocator); 2819 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2820 }
2821
2822 ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2823 {
2824 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2825 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2826 params.fParams.contentSizeFlag = 1;
2827 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
2787 } 2828 }
2788 2829
2789 size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 2830 size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2790 { 2831 {
2791 if (cdict==NULL) return 0; /* support free on NULL */ 2832 if (cdict==NULL) return 0; /* support free on NULL */
2792 { ZSTD_customMem const cMem = cdict->refContext->customMem; 2833 { ZSTD_customMem const cMem = cdict->refContext->customMem;
2793 ZSTD_freeCCtx(cdict->refContext); 2834 ZSTD_freeCCtx(cdict->refContext);
2794 ZSTD_free(cdict->dictContent, cMem); 2835 ZSTD_free(cdict->dictBuffer, cMem);
2795 ZSTD_free(cdict, cMem); 2836 ZSTD_free(cdict, cMem);
2796 return 0; 2837 return 0;
2797 } 2838 }
2798 } 2839 }
2799 2840
2800 static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { 2841 static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2801 return ZSTD_getParamsFromCCtx(cdict->refContext); 2842 return ZSTD_getParamsFromCCtx(cdict->refContext);
2802 } 2843 }
2803 2844
2804 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, U64 pledgedSrcSize) 2845 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
2805 { 2846 {
2806 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize)) 2847 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
2807 else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, pledgedSrcSize)); 2848 else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, pledgedSrcSize));
2808 return 0; 2849 return 0;
2809 } 2850 }
2898 size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; } 2939 size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2899 size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } 2940 size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
2900 2941
2901 size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) 2942 size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2902 { 2943 {
2903 if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once */ 2944 if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */
2904 2945
2905 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize)) 2946 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
2906 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize)); 2947 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
2907 2948
2908 zcs->inToCompress = 0; 2949 zcs->inToCompress = 0;
2935 ZSTD_free(zcs->outBuff, zcs->customMem); 2976 ZSTD_free(zcs->outBuff, zcs->customMem);
2936 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem); 2977 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
2937 if (zcs->outBuff == NULL) return ERROR(memory_allocation); 2978 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2938 } 2979 }
2939 2980
2940 if (dict) { 2981 if (dict && dictSize >= 8) {
2941 ZSTD_freeCDict(zcs->cdictLocal); 2982 ZSTD_freeCDict(zcs->cdictLocal);
2942 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, params, zcs->customMem); 2983 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
2943 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); 2984 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
2944 zcs->cdict = zcs->cdictLocal; 2985 zcs->cdict = zcs->cdictLocal;
2945 } else zcs->cdict = NULL; 2986 } else zcs->cdict = NULL;
2946 2987
2947 zcs->checksum = params.fParams.checksumFlag > 0; 2988 zcs->checksum = params.fParams.checksumFlag > 0;
2954 size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 2995 size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
2955 { 2996 {
2956 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict); 2997 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
2957 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0); 2998 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
2958 zcs->cdict = cdict; 2999 zcs->cdict = cdict;
3000 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
2959 return initError; 3001 return initError;
2960 } 3002 }
2961 3003
2962 size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 3004 size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
2963 { 3005 {
2965 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0); 3007 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
2966 } 3008 }
2967 3009
2968 size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize) 3010 size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
2969 { 3011 {
2970 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); 3012 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
3013 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;
2971 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize); 3014 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
2972 } 3015 }
2973 3016
2974 size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 3017 size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
2975 { 3018 {