-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor offset+repcode sumtype #2962
Changes from all commits
aeff128
bec7bbb
1aed962
2068889
435f5a2
b7630a4
321583c
6fa640e
681c81f
e909fa6
92a08ee
a34ccad
de9f52e
8da4142
ad7c9fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,7 +129,7 @@ size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr, | |
*********************************/ | ||
|
||
typedef struct { | ||
U32 off; /* Offset code (offset + ZSTD_REP_MOVE) for the match */ | ||
U32 off; /* Offset sumtype code for the match, using ZSTD_storeSeq() format */ | ||
U32 len; /* Raw length of match */ | ||
} ZSTD_match_t; | ||
|
||
|
@@ -497,31 +497,6 @@ MEM_STATIC U32 ZSTD_MLcode(U32 mlBase) | |
return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase]; | ||
} | ||
|
||
typedef struct repcodes_s { | ||
U32 rep[3]; | ||
} repcodes_t; | ||
|
||
MEM_STATIC repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0) | ||
{ | ||
repcodes_t newReps; | ||
if (offset >= ZSTD_REP_NUM) { /* full offset */ | ||
newReps.rep[2] = rep[1]; | ||
newReps.rep[1] = rep[0]; | ||
newReps.rep[0] = offset - ZSTD_REP_MOVE; | ||
} else { /* repcode */ | ||
U32 const repCode = offset + ll0; | ||
if (repCode > 0) { /* note : if repCode==0, no change */ | ||
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; | ||
newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2]; | ||
newReps.rep[1] = rep[0]; | ||
newReps.rep[0] = currentOffset; | ||
} else { /* repCode == 0 */ | ||
ZSTD_memcpy(&newReps, rep, sizeof(newReps)); | ||
} | ||
} | ||
return newReps; | ||
} | ||
|
||
/* ZSTD_cParam_withinBounds: | ||
* @return 1 if value is within cParam bounds, | ||
* 0 otherwise */ | ||
|
@@ -590,7 +565,9 @@ MEM_STATIC int ZSTD_literalsCompressionIsDisabled(const ZSTD_CCtx_params* cctxPa | |
* Only called when the sequence ends past ilimit_w, so it only needs to be optimized for single | ||
* large copies. | ||
*/ | ||
static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) { | ||
static void | ||
ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) | ||
{ | ||
assert(iend > ilimit_w); | ||
if (ip <= ilimit_w) { | ||
ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap); | ||
|
@@ -600,14 +577,30 @@ static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const ie | |
while (ip < iend) *op++ = *ip++; | ||
} | ||
|
||
#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1) | ||
#define STORE_REPCODE_1 STORE_REPCODE(1) | ||
#define STORE_REPCODE_2 STORE_REPCODE(2) | ||
#define STORE_REPCODE_3 STORE_REPCODE(3) | ||
#define STORE_REPCODE(r) (assert((r)>=1), assert((r)<=3), (r)-1) | ||
#define STORE_OFFSET(o) (assert((o)>0), o + ZSTD_REP_MOVE) | ||
#define STORED_IS_OFFSET(o) ((o) > ZSTD_REP_MOVE) | ||
#define STORED_IS_REPCODE(o) ((o) <= ZSTD_REP_MOVE) | ||
#define STORED_OFFSET(o) (assert(STORED_IS_OFFSET(o)), (o)-ZSTD_REP_MOVE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. It's more a temporary situation. |
||
#define STORED_REPCODE(o) (assert(STORED_IS_REPCODE(o)), (o)+1) /* returns ID 1,2,3 */ | ||
#define STORED_TO_OFFBASE(o) ((o)+1) | ||
#define OFFBASE_TO_STORED(o) ((o)-1) | ||
|
||
/*! ZSTD_storeSeq() : | ||
* Store a sequence (litlen, litPtr, offCode and matchLength) into seqStore_t. | ||
* `offCode` : distance to match + ZSTD_REP_MOVE (values <= ZSTD_REP_MOVE are repCodes). | ||
* @offBase_minus1 : Users should use employ macros STORE_REPCODE_X and STORE_OFFSET(). | ||
* @matchLength : must be >= MINMATCH | ||
* Allowed to overread literals up to litLimit. | ||
*/ | ||
HINT_INLINE UNUSED_ATTR | ||
void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, const BYTE* litLimit, U32 offCode, size_t matchLength) | ||
HINT_INLINE UNUSED_ATTR void | ||
ZSTD_storeSeq(seqStore_t* seqStorePtr, | ||
size_t litLength, const BYTE* literals, const BYTE* litLimit, | ||
U32 offBase_minus1, | ||
size_t matchLength) | ||
{ | ||
BYTE const* const litLimit_w = litLimit - WILDCOPY_OVERLENGTH; | ||
BYTE const* const litEnd = literals + litLength; | ||
|
@@ -616,7 +609,7 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera | |
if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */ | ||
{ U32 const pos = (U32)((const BYTE*)literals - g_start); | ||
DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u", | ||
pos, (U32)litLength, (U32)matchLength, (U32)offCode); | ||
pos, (U32)litLength, (U32)matchLength, (U32)offBase_minus1); | ||
} | ||
#endif | ||
assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq); | ||
|
@@ -647,7 +640,7 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera | |
seqStorePtr->sequences[0].litLength = (U16)litLength; | ||
|
||
/* match offset */ | ||
seqStorePtr->sequences[0].offset = offCode + 1; | ||
seqStorePtr->sequences[0].offBase = STORED_TO_OFFBASE(offBase_minus1); | ||
|
||
/* match Length */ | ||
assert(matchLength >= MINMATCH); | ||
|
@@ -663,6 +656,43 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera | |
seqStorePtr->sequences++; | ||
} | ||
|
||
/* ZSTD_updateRep() : | ||
* updates in-place @rep (array of repeat offsets) | ||
* @offBase_minus1 : sum-type, with same numeric representation as ZSTD_storeSeq() | ||
*/ | ||
MEM_STATIC void | ||
ZSTD_updateRep(U32 rep[ZSTD_REP_NUM], U32 const offBase_minus1, U32 const ll0) | ||
{ | ||
if (STORED_IS_OFFSET(offBase_minus1)) { /* full offset */ | ||
rep[2] = rep[1]; | ||
rep[1] = rep[0]; | ||
rep[0] = STORED_OFFSET(offBase_minus1); | ||
} else { /* repcode */ | ||
U32 const repCode = STORED_REPCODE(offBase_minus1) - 1 + ll0; | ||
if (repCode > 0) { /* note : if repCode==0, no change */ | ||
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; | ||
rep[2] = (repCode >= 2) ? rep[1] : rep[2]; | ||
rep[1] = rep[0]; | ||
rep[0] = currentOffset; | ||
} else { /* repCode == 0 */ | ||
/* nothing to do */ | ||
} | ||
} | ||
} | ||
|
||
typedef struct repcodes_s { | ||
U32 rep[3]; | ||
} repcodes_t; | ||
|
||
MEM_STATIC repcodes_t | ||
ZSTD_newRep(U32 const rep[ZSTD_REP_NUM], U32 const offBase_minus1, U32 const ll0) | ||
{ | ||
repcodes_t newReps; | ||
ZSTD_memcpy(&newReps, rep, sizeof(newReps)); | ||
ZSTD_updateRep(newReps.rep, offBase_minus1, ll0); | ||
return newReps; | ||
} | ||
|
||
|
||
/*-************************************* | ||
* Match length counter | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this pattern means evaluating the argument must not have any side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is a known side effect of macros.
Indeed, these macros shall only be used with scalar variables, not invoking function calls.
And it happens this condition is well respected, throughout the whole code base.
For more defensive properties, a possible alternative would be to swap these macros with
inline
functions,although this second solution introduces its own set of potential casting issues.