Editor/HumanoidRetargeter/Embedded/ZstdSharp/Unsafe/HufDecompress.cs
#nullable enable
#pragma warning disable CS0168 // Retained upstream decoder locals used by debug assertions.
using System;
using System.Collections.Generic;
using System.Linq;
using static HumanoidRetargeterZstd.UnsafeHelper;
using System;
using System.Runtime.CompilerServices;
namespace HumanoidRetargeterZstd.Unsafe
{
public static unsafe partial class Methods
{
private static DTableDesc HUF_getDTableDesc(uint* table)
{
DTableDesc dtd;
memcpy(&dtd, table, (uint)sizeof(DTableDesc));
return dtd;
}
private static nuint HUF_initFastDStream(byte* ip)
{
byte lastByte = ip[7];
nuint bitsConsumed = lastByte != 0 ? 8 - ZSTD_highbit32(lastByte) : 0;
nuint value = MEM_readLEST(ip) | 1;
assert(bitsConsumed <= 8);
assert(sizeof(nuint) == 8);
return value << (int)bitsConsumed;
}
/**
* Initializes args for the fast decoding loop.
* @returns 1 on success
* 0 if the fallback implementation should be used.
* Or an error code on failure.
*/
private static nuint HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* dst, nuint dstSize, void* src, nuint srcSize, uint* DTable)
{
void* dt = DTable + 1;
uint dtLog = HUF_getDTableDesc(DTable).tableLog;
byte* istart = (byte*)src;
byte* oend = ZSTD_maybeNullPtrAdd((byte*)dst, (nint)dstSize);
if (!BitConverter.IsLittleEndian || MEM_32bits)
return 0;
if (dstSize == 0)
return 0;
assert(dst != null);
if (srcSize < 10)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (dtLog != 11)
return 0;
{
nuint length1 = MEM_readLE16(istart);
nuint length2 = MEM_readLE16(istart + 2);
nuint length3 = MEM_readLE16(istart + 4);
nuint length4 = srcSize - (length1 + length2 + length3 + 6);
args->iend.e0 = istart + 6;
args->iend.e1 = args->iend.e0 + length1;
args->iend.e2 = args->iend.e1 + length2;
args->iend.e3 = args->iend.e2 + length3;
if (length1 < 8 || length2 < 8 || length3 < 8 || length4 < 8)
return 0;
if (length4 > srcSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
}
args->ip.e0 = args->iend.e1 - sizeof(ulong);
args->ip.e1 = args->iend.e2 - sizeof(ulong);
args->ip.e2 = args->iend.e3 - sizeof(ulong);
args->ip.e3 = (byte*)src + srcSize - sizeof(ulong);
args->op.e0 = (byte*)dst;
args->op.e1 = args->op.e0 + (dstSize + 3) / 4;
args->op.e2 = args->op.e1 + (dstSize + 3) / 4;
args->op.e3 = args->op.e2 + (dstSize + 3) / 4;
if (args->op.e3 >= oend)
return 0;
args->bits[0] = HUF_initFastDStream(args->ip.e0);
args->bits[1] = HUF_initFastDStream(args->ip.e1);
args->bits[2] = HUF_initFastDStream(args->ip.e2);
args->bits[3] = HUF_initFastDStream(args->ip.e3);
args->ilowest = istart;
args->oend = oend;
args->dt = dt;
return 1;
}
private static nuint HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArgs* args, int stream, byte* segmentEnd)
{
if ((&args->op.e0)[stream] > segmentEnd)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if ((&args->ip.e0)[stream] < (&args->iend.e0)[stream] - 8)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
assert(sizeof(nuint) == 8);
bit->bitContainer = MEM_readLEST((&args->ip.e0)[stream]);
bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]);
bit->start = (sbyte*)args->ilowest;
bit->limitPtr = bit->start + sizeof(nuint);
bit->ptr = (sbyte*)(&args->ip.e0)[stream];
return 0;
}
/**
* Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at
* a time.
*/
private static ulong HUF_DEltX1_set4(byte symbol, byte nbBits)
{
ulong D4;
if (BitConverter.IsLittleEndian)
{
D4 = (ulong)((symbol << 8) + nbBits);
}
else
{
D4 = (ulong)(symbol + (nbBits << 8));
}
assert(D4 < 1U << 16);
D4 *= 0x0001000100010001UL;
return D4;
}
/**
* Increase the tableLog to targetTableLog and rescales the stats.
* If tableLog > targetTableLog this is a no-op.
* @returns New tableLog
*/
private static uint HUF_rescaleStats(byte* huffWeight, uint* rankVal, uint nbSymbols, uint tableLog, uint targetTableLog)
{
if (tableLog > targetTableLog)
return tableLog;
if (tableLog < targetTableLog)
{
uint scale = targetTableLog - tableLog;
uint s;
for (s = 0; s < nbSymbols; ++s)
{
huffWeight[s] += (byte)(huffWeight[s] == 0 ? 0 : scale);
}
for (s = targetTableLog; s > scale; --s)
{
rankVal[s] = rankVal[s - scale];
}
for (s = scale; s > 0; --s)
{
rankVal[s] = 0;
}
}
return targetTableLog;
}
private static nuint HUF_readDTableX1_wksp(uint* DTable, void* src, nuint srcSize, void* workSpace, nuint wkspSize, int flags)
{
uint tableLog = 0;
uint nbSymbols = 0;
nuint iSize;
void* dtPtr = DTable + 1;
HUF_DEltX1* dt = (HUF_DEltX1*)dtPtr;
HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace;
if ((nuint)sizeof(HUF_ReadDTableX1_Workspace) > wkspSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_tableLog_tooLarge));
iSize = HUF_readStats_wksp(wksp->huffWeight, 255 + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(uint) * 219, flags);
if (ERR_isError(iSize))
return iSize;
{
DTableDesc dtd = HUF_getDTableDesc(DTable);
uint maxTableLog = (uint)(dtd.maxTableLog + 1);
uint targetTableLog = maxTableLog < 11 ? maxTableLog : 11;
tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog);
if (tableLog > (uint)(dtd.maxTableLog + 1))
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_tableLog_tooLarge));
dtd.tableType = 0;
dtd.tableLog = (byte)tableLog;
memcpy(DTable, &dtd, (uint)sizeof(DTableDesc));
}
{
int n;
uint nextRankStart = 0;
const int unroll = 4;
int nLimit = (int)nbSymbols - unroll + 1;
for (n = 0; n < (int)tableLog + 1; n++)
{
uint curr = nextRankStart;
nextRankStart += wksp->rankVal[n];
wksp->rankStart[n] = curr;
}
for (n = 0; n < nLimit; n += unroll)
{
int u;
for (u = 0; u < unroll; ++u)
{
nuint w = wksp->huffWeight[n + u];
wksp->symbols[wksp->rankStart[w]++] = (byte)(n + u);
}
}
for (; n < (int)nbSymbols; ++n)
{
nuint w = wksp->huffWeight[n];
wksp->symbols[wksp->rankStart[w]++] = (byte)n;
}
}
{
uint w;
int symbol = (int)wksp->rankVal[0];
int rankStart = 0;
for (w = 1; w < tableLog + 1; ++w)
{
int symbolCount = (int)wksp->rankVal[w];
int length = 1 << (int)w >> 1;
int uStart = rankStart;
byte nbBits = (byte)(tableLog + 1 - w);
int s;
int u;
switch (length)
{
case 1:
for (s = 0; s < symbolCount; ++s)
{
HUF_DEltX1 D;
D.@byte = wksp->symbols[symbol + s];
D.nbBits = nbBits;
dt[uStart] = D;
uStart += 1;
}
break;
case 2:
for (s = 0; s < symbolCount; ++s)
{
HUF_DEltX1 D;
D.@byte = wksp->symbols[symbol + s];
D.nbBits = nbBits;
dt[uStart + 0] = D;
dt[uStart + 1] = D;
uStart += 2;
}
break;
case 4:
for (s = 0; s < symbolCount; ++s)
{
ulong D4 = HUF_DEltX1_set4(wksp->symbols[symbol + s], nbBits);
MEM_write64(dt + uStart, D4);
uStart += 4;
}
break;
case 8:
for (s = 0; s < symbolCount; ++s)
{
ulong D4 = HUF_DEltX1_set4(wksp->symbols[symbol + s], nbBits);
MEM_write64(dt + uStart, D4);
MEM_write64(dt + uStart + 4, D4);
uStart += 8;
}
break;
default:
for (s = 0; s < symbolCount; ++s)
{
ulong D4 = HUF_DEltX1_set4(wksp->symbols[symbol + s], nbBits);
for (u = 0; u < length; u += 16)
{
MEM_write64(dt + uStart + u + 0, D4);
MEM_write64(dt + uStart + u + 4, D4);
MEM_write64(dt + uStart + u + 8, D4);
MEM_write64(dt + uStart + u + 12, D4);
}
assert(u == length);
uStart += length;
}
break;
}
symbol += symbolCount;
rankStart += symbolCount * length;
}
}
return iSize;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte HUF_decodeSymbolX1(BIT_DStream_t* Dstream, HUF_DEltX1* dt, uint dtLog)
{
/* note : dtLog >= 1 */
nuint val = BIT_lookBitsFast(Dstream, dtLog);
byte c = dt[val].@byte;
BIT_skipBits(Dstream, dt[val].nbBits);
return c;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static nuint HUF_decodeStreamX1(byte* p, BIT_DStream_t* bitDPtr, byte* pEnd, HUF_DEltX1* dt, uint dtLog)
{
byte* pStart = p;
if (pEnd - p > 3)
{
while (BIT_reloadDStream(bitDPtr) == BIT_DStream_status.BIT_DStream_unfinished && p < pEnd - 3)
{
if (MEM_64bits)
*p++ = HUF_decodeSymbolX1(bitDPtr, dt, dtLog);
*p++ = HUF_decodeSymbolX1(bitDPtr, dt, dtLog);
if (MEM_64bits)
*p++ = HUF_decodeSymbolX1(bitDPtr, dt, dtLog);
*p++ = HUF_decodeSymbolX1(bitDPtr, dt, dtLog);
}
}
else
{
BIT_reloadDStream(bitDPtr);
}
if (MEM_32bits)
while (BIT_reloadDStream(bitDPtr) == BIT_DStream_status.BIT_DStream_unfinished && p < pEnd)
*p++ = HUF_decodeSymbolX1(bitDPtr, dt, dtLog);
while (p < pEnd)
*p++ = HUF_decodeSymbolX1(bitDPtr, dt, dtLog);
return (nuint)(pEnd - pStart);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static nuint HUF_decompress1X1_usingDTable_internal_body(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable)
{
byte* op = (byte*)dst;
byte* oend = ZSTD_maybeNullPtrAdd(op, (nint)dstSize);
void* dtPtr = DTable + 1;
HUF_DEltX1* dt = (HUF_DEltX1*)dtPtr;
BIT_DStream_t bitD;
DTableDesc dtd = HUF_getDTableDesc(DTable);
uint dtLog = dtd.tableLog;
{
nuint _var_err__ = BIT_initDStream(&bitD, cSrc, cSrcSize);
if (ERR_isError(_var_err__))
return _var_err__;
}
HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog);
if (BIT_endOfDStream(&bitD) == 0)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
return dstSize;
}
/* HUF_decompress4X1_usingDTable_internal_body():
* Conditions :
* @dstSize >= 6
*/
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static nuint HUF_decompress4X1_usingDTable_internal_body(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable)
{
if (cSrcSize < 10)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (dstSize < 6)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
{
byte* istart = (byte*)cSrc;
byte* ostart = (byte*)dst;
byte* oend = ostart + dstSize;
byte* olimit = oend - 3;
void* dtPtr = DTable + 1;
HUF_DEltX1* dt = (HUF_DEltX1*)dtPtr;
/* Init */
BIT_DStream_t bitD1;
BIT_DStream_t bitD2;
BIT_DStream_t bitD3;
BIT_DStream_t bitD4;
nuint length1 = MEM_readLE16(istart);
nuint length2 = MEM_readLE16(istart + 2);
nuint length3 = MEM_readLE16(istart + 4);
nuint length4 = cSrcSize - (length1 + length2 + length3 + 6);
/* jumpTable */
byte* istart1 = istart + 6;
byte* istart2 = istart1 + length1;
byte* istart3 = istart2 + length2;
byte* istart4 = istart3 + length3;
nuint segmentSize = (dstSize + 3) / 4;
byte* opStart2 = ostart + segmentSize;
byte* opStart3 = opStart2 + segmentSize;
byte* opStart4 = opStart3 + segmentSize;
byte* op1 = ostart;
byte* op2 = opStart2;
byte* op3 = opStart3;
byte* op4 = opStart4;
DTableDesc dtd = HUF_getDTableDesc(DTable);
uint dtLog = dtd.tableLog;
uint endSignal = 1;
if (length4 > cSrcSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (opStart4 > oend)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
assert(dstSize >= 6);
{
nuint _var_err__ = BIT_initDStream(&bitD1, istart1, length1);
if (ERR_isError(_var_err__))
return _var_err__;
}
{
nuint _var_err__ = BIT_initDStream(&bitD2, istart2, length2);
if (ERR_isError(_var_err__))
return _var_err__;
}
{
nuint _var_err__ = BIT_initDStream(&bitD3, istart3, length3);
if (ERR_isError(_var_err__))
return _var_err__;
}
{
nuint _var_err__ = BIT_initDStream(&bitD4, istart4, length4);
if (ERR_isError(_var_err__))
return _var_err__;
}
if ((nuint)(oend - op4) >= (nuint)sizeof(nuint))
{
for (; (endSignal & (uint)(op4 < olimit ? 1 : 0)) != 0;)
{
if (MEM_64bits)
*op1++ = HUF_decodeSymbolX1(&bitD1, dt, dtLog);
if (MEM_64bits)
*op2++ = HUF_decodeSymbolX1(&bitD2, dt, dtLog);
if (MEM_64bits)
*op3++ = HUF_decodeSymbolX1(&bitD3, dt, dtLog);
if (MEM_64bits)
*op4++ = HUF_decodeSymbolX1(&bitD4, dt, dtLog);
*op1++ = HUF_decodeSymbolX1(&bitD1, dt, dtLog);
*op2++ = HUF_decodeSymbolX1(&bitD2, dt, dtLog);
*op3++ = HUF_decodeSymbolX1(&bitD3, dt, dtLog);
*op4++ = HUF_decodeSymbolX1(&bitD4, dt, dtLog);
if (MEM_64bits)
*op1++ = HUF_decodeSymbolX1(&bitD1, dt, dtLog);
if (MEM_64bits)
*op2++ = HUF_decodeSymbolX1(&bitD2, dt, dtLog);
if (MEM_64bits)
*op3++ = HUF_decodeSymbolX1(&bitD3, dt, dtLog);
if (MEM_64bits)
*op4++ = HUF_decodeSymbolX1(&bitD4, dt, dtLog);
*op1++ = HUF_decodeSymbolX1(&bitD1, dt, dtLog);
*op2++ = HUF_decodeSymbolX1(&bitD2, dt, dtLog);
*op3++ = HUF_decodeSymbolX1(&bitD3, dt, dtLog);
*op4++ = HUF_decodeSymbolX1(&bitD4, dt, dtLog);
endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
}
}
if (op1 > opStart2)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (op2 > opStart3)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (op3 > opStart4)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog);
HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog);
HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog);
HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog);
{
uint endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
if (endCheck == 0)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
}
return dstSize;
}
}
private static nuint HUF_decompress4X1_usingDTable_internal_default(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable)
{
return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable);
}
private static void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args)
{
ulong bits0, bits1, bits2, bits3;
byte* ip0, ip1, ip2, ip3;
byte* op0, op1, op2, op3;
ushort* dtable = (ushort*)args->dt;
byte* oend = args->oend;
byte* ilowest = args->ilowest;
bits0 = args->bits[0];
bits1 = args->bits[1];
bits2 = args->bits[2];
bits3 = args->bits[3];
ip0 = args->ip.e0;
ip1 = args->ip.e1;
ip2 = args->ip.e2;
ip3 = args->ip.e3;
op0 = args->op.e0;
op1 = args->op.e1;
op2 = args->op.e2;
op3 = args->op.e3;
assert(BitConverter.IsLittleEndian);
assert(!MEM_32bits);
for (; ; )
{
byte* olimit;
int stream;
{
assert(op0 <= op1);
assert(ip0 >= ilowest);
}
{
assert(op1 <= op2);
assert(ip1 >= ilowest);
}
{
assert(op2 <= op3);
assert(ip2 >= ilowest);
}
{
assert(op3 <= oend);
assert(ip3 >= ilowest);
}
{
/* Each iteration produces 5 output symbols per stream */
nuint oiters = (nuint)(oend - op3) / 5;
/* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes
* per stream.
*/
nuint iiters = (nuint)(ip0 - ilowest) / 7;
/* We can safely run iters iterations before running bounds checks */
nuint iters = oiters < iiters ? oiters : iiters;
nuint symbols = iters * 5;
olimit = op3 + symbols;
if (op3 == olimit)
break;
{
if (ip1 < ip0)
goto _out;
}
{
if (ip2 < ip1)
goto _out;
}
{
if (ip3 < ip2)
goto _out;
}
}
{
assert(ip1 >= ip0);
}
{
assert(ip2 >= ip1);
}
{
assert(ip3 >= ip2);
}
do
{
{
{
/* Decode 5 symbols in each of the 4 streams */
int index = (int)(bits0 >> 53);
int entry = dtable[index];
bits0 <<= entry & 0x3F;
op0[0] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits1 >> 53);
int entry = dtable[index];
bits1 <<= entry & 0x3F;
op1[0] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits2 >> 53);
int entry = dtable[index];
bits2 <<= entry & 0x3F;
op2[0] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits3 >> 53);
int entry = dtable[index];
bits3 <<= entry & 0x3F;
op3[0] = (byte)(entry >> 8 & 0xFF);
}
}
{
{
int index = (int)(bits0 >> 53);
int entry = dtable[index];
bits0 <<= entry & 0x3F;
op0[1] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits1 >> 53);
int entry = dtable[index];
bits1 <<= entry & 0x3F;
op1[1] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits2 >> 53);
int entry = dtable[index];
bits2 <<= entry & 0x3F;
op2[1] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits3 >> 53);
int entry = dtable[index];
bits3 <<= entry & 0x3F;
op3[1] = (byte)(entry >> 8 & 0xFF);
}
}
{
{
int index = (int)(bits0 >> 53);
int entry = dtable[index];
bits0 <<= entry & 0x3F;
op0[2] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits1 >> 53);
int entry = dtable[index];
bits1 <<= entry & 0x3F;
op1[2] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits2 >> 53);
int entry = dtable[index];
bits2 <<= entry & 0x3F;
op2[2] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits3 >> 53);
int entry = dtable[index];
bits3 <<= entry & 0x3F;
op3[2] = (byte)(entry >> 8 & 0xFF);
}
}
{
{
int index = (int)(bits0 >> 53);
int entry = dtable[index];
bits0 <<= entry & 0x3F;
op0[3] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits1 >> 53);
int entry = dtable[index];
bits1 <<= entry & 0x3F;
op1[3] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits2 >> 53);
int entry = dtable[index];
bits2 <<= entry & 0x3F;
op2[3] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits3 >> 53);
int entry = dtable[index];
bits3 <<= entry & 0x3F;
op3[3] = (byte)(entry >> 8 & 0xFF);
}
}
{
{
int index = (int)(bits0 >> 53);
int entry = dtable[index];
bits0 <<= entry & 0x3F;
op0[4] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits1 >> 53);
int entry = dtable[index];
bits1 <<= entry & 0x3F;
op1[4] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits2 >> 53);
int entry = dtable[index];
bits2 <<= entry & 0x3F;
op2[4] = (byte)(entry >> 8 & 0xFF);
}
{
int index = (int)(bits3 >> 53);
int entry = dtable[index];
bits3 <<= entry & 0x3F;
op3[4] = (byte)(entry >> 8 & 0xFF);
}
}
{
{
/* Reload each of the 4 the bitstreams */
int ctz = (int)ZSTD_countTrailingZeros64(bits0);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
op0 += 5;
ip0 -= nbBytes;
bits0 = MEM_read64(ip0) | 1;
bits0 <<= nbBits;
}
{
int ctz = (int)ZSTD_countTrailingZeros64(bits1);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
op1 += 5;
ip1 -= nbBytes;
bits1 = MEM_read64(ip1) | 1;
bits1 <<= nbBits;
}
{
int ctz = (int)ZSTD_countTrailingZeros64(bits2);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
op2 += 5;
ip2 -= nbBytes;
bits2 = MEM_read64(ip2) | 1;
bits2 <<= nbBits;
}
{
int ctz = (int)ZSTD_countTrailingZeros64(bits3);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
op3 += 5;
ip3 -= nbBytes;
bits3 = MEM_read64(ip3) | 1;
bits3 <<= nbBits;
}
}
}
while (op3 < olimit);
}
_out:
args->bits[0] = bits0;
args->bits[1] = bits1;
args->bits[2] = bits2;
args->bits[3] = bits3;
args->ip.e0 = ip0;
args->ip.e1 = ip1;
args->ip.e2 = ip2;
args->ip.e3 = ip3;
args->op.e0 = op0;
args->op.e1 = op1;
args->op.e2 = op2;
args->op.e3 = op3;
}
/**
* @returns @p dstSize on success (>= 6)
* 0 if the fallback implementation should be used
* An error if an error occurred
*/
private static nuint HUF_decompress4X1_usingDTable_internal_fast(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable, void* loopFn)
{
void* dt = DTable + 1;
byte* ilowest = (byte*)cSrc;
byte* oend = ZSTD_maybeNullPtrAdd((byte*)dst, (nint)dstSize);
HUF_DecompressFastArgs args;
{
nuint ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable);
{
nuint err_code = ret;
if (ERR_isError(err_code))
{
return err_code;
}
}
if (ret == 0)
return 0;
}
assert(args.ip.e0 >= args.ilowest);
((delegate* managed<HUF_DecompressFastArgs*, void>)loopFn)(&args);
assert(args.ip.e0 >= ilowest);
assert(args.ip.e0 >= ilowest);
assert(args.ip.e1 >= ilowest);
assert(args.ip.e2 >= ilowest);
assert(args.ip.e3 >= ilowest);
assert(args.op.e3 <= oend);
assert(ilowest == args.ilowest);
assert(ilowest + 6 == args.iend.e0);
{
nuint segmentSize = (dstSize + 3) / 4;
byte* segmentEnd = (byte*)dst;
int i;
for (i = 0; i < 4; ++i)
{
BIT_DStream_t bit;
if (segmentSize <= (nuint)(oend - segmentEnd))
segmentEnd += segmentSize;
else
segmentEnd = oend;
{
nuint err_code = HUF_initRemainingDStream(&bit, &args, i, segmentEnd);
if (ERR_isError(err_code))
{
return err_code;
}
}
(&args.op.e0)[i] += HUF_decodeStreamX1((&args.op.e0)[i], &bit, segmentEnd, (HUF_DEltX1*)dt, 11);
if ((&args.op.e0)[i] != segmentEnd)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
}
}
assert(dstSize != 0);
return dstSize;
}
private static nuint HUF_decompress1X1_usingDTable_internal(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable, int flags)
{
return HUF_decompress1X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable);
}
private static nuint HUF_decompress4X1_usingDTable_internal(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable, int flags)
{
void* fallbackFn = (delegate* managed<void*, nuint, void*, nuint, uint*, nuint>)(&HUF_decompress4X1_usingDTable_internal_default);
void* loopFn = (delegate* managed<HUF_DecompressFastArgs*, void>)(&HUF_decompress4X1_usingDTable_internal_fast_c_loop);
if ((flags & (int)HUF_flags_e.HUF_flags_disableFast) == 0)
{
nuint ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
if (ret != 0)
return ret;
}
return ((delegate* managed<void*, nuint, void*, nuint, uint*, nuint>)fallbackFn)(dst, dstSize, cSrc, cSrcSize, DTable);
}
private static nuint HUF_decompress4X1_DCtx_wksp(uint* dctx, void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, void* workSpace, nuint wkspSize, int flags)
{
byte* ip = (byte*)cSrc;
nuint hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags);
if (ERR_isError(hSize))
return hSize;
if (hSize >= cSrcSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_srcSize_wrong));
ip += hSize;
cSrcSize -= hSize;
return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags);
}
/**
* Constructs a HUF_DEltX2 in a U32.
*/
private static uint HUF_buildDEltX2U32(uint symbol, uint nbBits, uint baseSeq, int level)
{
uint seq;
if (BitConverter.IsLittleEndian)
{
seq = level == 1 ? symbol : baseSeq + (symbol << 8);
return seq + (nbBits << 16) + ((uint)level << 24);
}
else
{
seq = level == 1 ? symbol << 8 : (baseSeq << 8) + symbol;
return (seq << 16) + (nbBits << 8) + (uint)level;
}
}
/**
* Constructs a HUF_DEltX2.
*/
private static HUF_DEltX2 HUF_buildDEltX2(uint symbol, uint nbBits, uint baseSeq, int level)
{
HUF_DEltX2 DElt;
uint val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level);
memcpy(&DElt, &val, sizeof(uint));
return DElt;
}
/**
* Constructs 2 HUF_DEltX2s and packs them into a U64.
*/
private static ulong HUF_buildDEltX2U64(uint symbol, uint nbBits, ushort baseSeq, int level)
{
uint DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level);
return DElt + ((ulong)DElt << 32);
}
/**
* Fills the DTable rank with all the symbols from [begin, end) that are each
* nbBits long.
*
* @param DTableRank The start of the rank in the DTable.
* @param begin The first symbol to fill (inclusive).
* @param end The last symbol to fill (exclusive).
* @param nbBits Each symbol is nbBits long.
* @param tableLog The table log.
* @param baseSeq If level == 1 { 0 } else { the first level symbol }
* @param level The level in the table. Must be 1 or 2.
*/
private static void HUF_fillDTableX2ForWeight(HUF_DEltX2* DTableRank, sortedSymbol_t* begin, sortedSymbol_t* end, uint nbBits, uint tableLog, ushort baseSeq, int level)
{
/* quiet static-analyzer */
uint length = 1U << (int)(tableLog - nbBits & 0x1F);
sortedSymbol_t* ptr;
assert(level >= 1 && level <= 2);
switch (length)
{
case 1:
for (ptr = begin; ptr != end; ++ptr)
{
HUF_DEltX2 DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level);
*DTableRank++ = DElt;
}
break;
case 2:
for (ptr = begin; ptr != end; ++ptr)
{
HUF_DEltX2 DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level);
DTableRank[0] = DElt;
DTableRank[1] = DElt;
DTableRank += 2;
}
break;
case 4:
for (ptr = begin; ptr != end; ++ptr)
{
ulong DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level);
memcpy(DTableRank + 0, &DEltX2, sizeof(ulong));
memcpy(DTableRank + 2, &DEltX2, sizeof(ulong));
DTableRank += 4;
}
break;
case 8:
for (ptr = begin; ptr != end; ++ptr)
{
ulong DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level);
memcpy(DTableRank + 0, &DEltX2, sizeof(ulong));
memcpy(DTableRank + 2, &DEltX2, sizeof(ulong));
memcpy(DTableRank + 4, &DEltX2, sizeof(ulong));
memcpy(DTableRank + 6, &DEltX2, sizeof(ulong));
DTableRank += 8;
}
break;
default:
for (ptr = begin; ptr != end; ++ptr)
{
ulong DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level);
HUF_DEltX2* DTableRankEnd = DTableRank + length;
for (; DTableRank != DTableRankEnd; DTableRank += 8)
{
memcpy(DTableRank + 0, &DEltX2, sizeof(ulong));
memcpy(DTableRank + 2, &DEltX2, sizeof(ulong));
memcpy(DTableRank + 4, &DEltX2, sizeof(ulong));
memcpy(DTableRank + 6, &DEltX2, sizeof(ulong));
}
}
break;
}
}
/* HUF_fillDTableX2Level2() :
* `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
private static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, uint targetLog, uint consumedBits, uint* rankVal, int minWeight, int maxWeight1, sortedSymbol_t* sortedSymbols, uint* rankStart, uint nbBitsBaseline, ushort baseSeq)
{
if (minWeight > 1)
{
/* quiet static-analyzer */
uint length = 1U << (int)(targetLog - consumedBits & 0x1F);
/* baseSeq */
ulong DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, 0, 1);
int skipSize = (int)rankVal[minWeight];
assert(length > 1);
assert((uint)skipSize < length);
switch (length)
{
case 2:
assert(skipSize == 1);
memcpy(DTable, &DEltX2, sizeof(ulong));
break;
case 4:
assert(skipSize <= 4);
memcpy(DTable + 0, &DEltX2, sizeof(ulong));
memcpy(DTable + 2, &DEltX2, sizeof(ulong));
break;
default:
{
int i;
for (i = 0; i < skipSize; i += 8)
{
memcpy(DTable + i + 0, &DEltX2, sizeof(ulong));
memcpy(DTable + i + 2, &DEltX2, sizeof(ulong));
memcpy(DTable + i + 4, &DEltX2, sizeof(ulong));
memcpy(DTable + i + 6, &DEltX2, sizeof(ulong));
}
}
break;
}
}
{
int w;
for (w = minWeight; w < maxWeight1; ++w)
{
int begin = (int)rankStart[w];
int end = (int)rankStart[w + 1];
uint nbBits = nbBitsBaseline - (uint)w;
uint totalBits = nbBits + consumedBits;
HUF_fillDTableX2ForWeight(DTable + rankVal[w], sortedSymbols + begin, sortedSymbols + end, totalBits, targetLog, baseSeq, 2);
}
}
}
private static void HUF_fillDTableX2(HUF_DEltX2* DTable, uint targetLog, sortedSymbol_t* sortedList, uint* rankStart, rankValCol_t* rankValOrigin, uint maxWeight, uint nbBitsBaseline)
{
uint* rankVal = (uint*)&rankValOrigin[0];
/* note : targetLog >= srcLog, hence scaleLog <= 1 */
int scaleLog = (int)(nbBitsBaseline - targetLog);
uint minBits = nbBitsBaseline - maxWeight;
int w;
int wEnd = (int)maxWeight + 1;
for (w = 1; w < wEnd; ++w)
{
int begin = (int)rankStart[w];
int end = (int)rankStart[w + 1];
uint nbBits = nbBitsBaseline - (uint)w;
if (targetLog - nbBits >= minBits)
{
/* Enough room for a second symbol. */
int start = (int)rankVal[w];
/* quiet static-analyzer */
uint length = 1U << (int)(targetLog - nbBits & 0x1F);
int minWeight = (int)(nbBits + (uint)scaleLog);
int s;
if (minWeight < 1)
minWeight = 1;
for (s = begin; s != end; ++s)
{
HUF_fillDTableX2Level2(DTable + start, targetLog, nbBits, (uint*)&rankValOrigin[nbBits], minWeight, wEnd, sortedList, rankStart, nbBitsBaseline, sortedList[s].symbol);
start += (int)length;
}
}
else
{
HUF_fillDTableX2ForWeight(DTable + rankVal[w], sortedList + begin, sortedList + end, nbBits, targetLog, 0, 1);
}
}
}
private static nuint HUF_readDTableX2_wksp(uint* DTable, void* src, nuint srcSize, void* workSpace, nuint wkspSize, int flags)
{
uint tableLog, maxW, nbSymbols;
DTableDesc dtd = HUF_getDTableDesc(DTable);
uint maxTableLog = dtd.maxTableLog;
nuint iSize;
/* force compiler to avoid strict-aliasing */
void* dtPtr = DTable + 1;
HUF_DEltX2* dt = (HUF_DEltX2*)dtPtr;
uint* rankStart;
HUF_ReadDTableX2_Workspace* wksp = (HUF_ReadDTableX2_Workspace*)workSpace;
if ((nuint)sizeof(HUF_ReadDTableX2_Workspace) > wkspSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_GENERIC));
rankStart = wksp->rankStart0 + 1;
memset(wksp->rankStats, 0, sizeof(uint) * 13);
memset(wksp->rankStart0, 0, sizeof(uint) * 15);
if (maxTableLog > 12)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_tableLog_tooLarge));
iSize = HUF_readStats_wksp(wksp->weightList, 255 + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(uint) * 219, flags);
if (ERR_isError(iSize))
return iSize;
if (tableLog > maxTableLog)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_tableLog_tooLarge));
if (tableLog <= 11 && maxTableLog > 11)
maxTableLog = 11;
for (maxW = tableLog; wksp->rankStats[maxW] == 0; maxW--)
{
}
{
uint w, nextRankStart = 0;
for (w = 1; w < maxW + 1; w++)
{
uint curr = nextRankStart;
nextRankStart += wksp->rankStats[w];
rankStart[w] = curr;
}
rankStart[0] = nextRankStart;
rankStart[maxW + 1] = nextRankStart;
}
{
uint s;
for (s = 0; s < nbSymbols; s++)
{
uint w = wksp->weightList[s];
uint r = rankStart[w]++;
(&wksp->sortedSymbol.e0)[r].symbol = (byte)s;
}
rankStart[0] = 0;
}
{
uint* rankVal0 = (uint*)&wksp->rankVal.e0;
{
/* tableLog <= maxTableLog */
int rescale = (int)(maxTableLog - tableLog - 1);
uint nextRankVal = 0;
uint w;
for (w = 1; w < maxW + 1; w++)
{
uint curr = nextRankVal;
nextRankVal += wksp->rankStats[w] << (int)(w + (uint)rescale);
rankVal0[w] = curr;
}
}
{
uint minBits = tableLog + 1 - maxW;
uint consumed;
for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++)
{
uint* rankValPtr = (uint*)&(&wksp->rankVal.e0)[consumed];
uint w;
for (w = 1; w < maxW + 1; w++)
{
rankValPtr[w] = rankVal0[w] >> (int)consumed;
}
}
}
}
HUF_fillDTableX2(dt, maxTableLog, &wksp->sortedSymbol.e0, wksp->rankStart0, &wksp->rankVal.e0, maxW, tableLog + 1);
dtd.tableLog = (byte)maxTableLog;
dtd.tableType = 1;
memcpy(DTable, &dtd, (uint)sizeof(DTableDesc));
return iSize;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, HUF_DEltX2* dt, uint dtLog)
{
/* note : dtLog >= 1 */
nuint val = BIT_lookBitsFast(DStream, dtLog);
memcpy(op, &dt[val].sequence, 2);
BIT_skipBits(DStream, dt[val].nbBits);
return dt[val].length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, HUF_DEltX2* dt, uint dtLog)
{
/* note : dtLog >= 1 */
nuint val = BIT_lookBitsFast(DStream, dtLog);
memcpy(op, &dt[val].sequence, 1);
if (dt[val].length == 1)
{
BIT_skipBits(DStream, dt[val].nbBits);
}
else
{
if (DStream->bitsConsumed < (uint)(sizeof(nuint) * 8))
{
BIT_skipBits(DStream, dt[val].nbBits);
if (DStream->bitsConsumed > (uint)(sizeof(nuint) * 8))
DStream->bitsConsumed = (uint)(sizeof(nuint) * 8);
}
}
return 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static nuint HUF_decodeStreamX2(byte* p, BIT_DStream_t* bitDPtr, byte* pEnd, HUF_DEltX2* dt, uint dtLog)
{
byte* pStart = p;
if ((nuint)(pEnd - p) >= (nuint)sizeof(nuint))
{
if (dtLog <= 11 && MEM_64bits)
{
while (BIT_reloadDStream(bitDPtr) == BIT_DStream_status.BIT_DStream_unfinished && p < pEnd - 9)
{
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
}
}
else
{
while (BIT_reloadDStream(bitDPtr) == BIT_DStream_status.BIT_DStream_unfinished && p < pEnd - (sizeof(nuint) - 1))
{
if (MEM_64bits)
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
if (MEM_64bits)
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
}
}
}
else
{
BIT_reloadDStream(bitDPtr);
}
if ((nuint)(pEnd - p) >= 2)
{
while (BIT_reloadDStream(bitDPtr) == BIT_DStream_status.BIT_DStream_unfinished && p <= pEnd - 2)
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
while (p <= pEnd - 2)
p += HUF_decodeSymbolX2(p, bitDPtr, dt, dtLog);
}
if (p < pEnd)
p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog);
return (nuint)(p - pStart);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static nuint HUF_decompress1X2_usingDTable_internal_body(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable)
{
BIT_DStream_t bitD;
{
/* Init */
nuint _var_err__ = BIT_initDStream(&bitD, cSrc, cSrcSize);
if (ERR_isError(_var_err__))
return _var_err__;
}
{
byte* ostart = (byte*)dst;
byte* oend = ZSTD_maybeNullPtrAdd(ostart, (nint)dstSize);
/* force compiler to not use strict-aliasing */
void* dtPtr = DTable + 1;
HUF_DEltX2* dt = (HUF_DEltX2*)dtPtr;
DTableDesc dtd = HUF_getDTableDesc(DTable);
HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog);
}
if (BIT_endOfDStream(&bitD) == 0)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
return dstSize;
}
/* HUF_decompress4X2_usingDTable_internal_body():
* Conditions:
* @dstSize >= 6
*/
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static nuint HUF_decompress4X2_usingDTable_internal_body(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable)
{
if (cSrcSize < 10)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (dstSize < 6)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
{
byte* istart = (byte*)cSrc;
byte* ostart = (byte*)dst;
byte* oend = ostart + dstSize;
byte* olimit = oend - (sizeof(nuint) - 1);
void* dtPtr = DTable + 1;
HUF_DEltX2* dt = (HUF_DEltX2*)dtPtr;
/* Init */
BIT_DStream_t bitD1;
BIT_DStream_t bitD2;
BIT_DStream_t bitD3;
BIT_DStream_t bitD4;
nuint length1 = MEM_readLE16(istart);
nuint length2 = MEM_readLE16(istart + 2);
nuint length3 = MEM_readLE16(istart + 4);
nuint length4 = cSrcSize - (length1 + length2 + length3 + 6);
/* jumpTable */
byte* istart1 = istart + 6;
byte* istart2 = istart1 + length1;
byte* istart3 = istart2 + length2;
byte* istart4 = istart3 + length3;
nuint segmentSize = (dstSize + 3) / 4;
byte* opStart2 = ostart + segmentSize;
byte* opStart3 = opStart2 + segmentSize;
byte* opStart4 = opStart3 + segmentSize;
byte* op1 = ostart;
byte* op2 = opStart2;
byte* op3 = opStart3;
byte* op4 = opStart4;
uint endSignal = 1;
DTableDesc dtd = HUF_getDTableDesc(DTable);
uint dtLog = dtd.tableLog;
if (length4 > cSrcSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (opStart4 > oend)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
assert(dstSize >= 6);
{
nuint _var_err__ = BIT_initDStream(&bitD1, istart1, length1);
if (ERR_isError(_var_err__))
return _var_err__;
}
{
nuint _var_err__ = BIT_initDStream(&bitD2, istart2, length2);
if (ERR_isError(_var_err__))
return _var_err__;
}
{
nuint _var_err__ = BIT_initDStream(&bitD3, istart3, length3);
if (ERR_isError(_var_err__))
return _var_err__;
}
{
nuint _var_err__ = BIT_initDStream(&bitD4, istart4, length4);
if (ERR_isError(_var_err__))
return _var_err__;
}
if ((nuint)(oend - op4) >= (nuint)sizeof(nuint))
{
for (; (endSignal & (uint)(op4 < olimit ? 1 : 0)) != 0;)
{
if (MEM_64bits)
op1 += HUF_decodeSymbolX2(op1, &bitD1, dt, dtLog);
op1 += HUF_decodeSymbolX2(op1, &bitD1, dt, dtLog);
if (MEM_64bits)
op1 += HUF_decodeSymbolX2(op1, &bitD1, dt, dtLog);
op1 += HUF_decodeSymbolX2(op1, &bitD1, dt, dtLog);
if (MEM_64bits)
op2 += HUF_decodeSymbolX2(op2, &bitD2, dt, dtLog);
op2 += HUF_decodeSymbolX2(op2, &bitD2, dt, dtLog);
if (MEM_64bits)
op2 += HUF_decodeSymbolX2(op2, &bitD2, dt, dtLog);
op2 += HUF_decodeSymbolX2(op2, &bitD2, dt, dtLog);
endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
if (MEM_64bits)
op3 += HUF_decodeSymbolX2(op3, &bitD3, dt, dtLog);
op3 += HUF_decodeSymbolX2(op3, &bitD3, dt, dtLog);
if (MEM_64bits)
op3 += HUF_decodeSymbolX2(op3, &bitD3, dt, dtLog);
op3 += HUF_decodeSymbolX2(op3, &bitD3, dt, dtLog);
if (MEM_64bits)
op4 += HUF_decodeSymbolX2(op4, &bitD4, dt, dtLog);
op4 += HUF_decodeSymbolX2(op4, &bitD4, dt, dtLog);
if (MEM_64bits)
op4 += HUF_decodeSymbolX2(op4, &bitD4, dt, dtLog);
op4 += HUF_decodeSymbolX2(op4, &bitD4, dt, dtLog);
endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_status.BIT_DStream_unfinished ? 1U : 0U;
}
}
if (op1 > opStart2)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (op2 > opStart3)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
if (op3 > opStart4)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
{
uint endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
if (endCheck == 0)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
}
return dstSize;
}
}
private static nuint HUF_decompress4X2_usingDTable_internal_default(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable)
{
return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable);
}
private static void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args)
{
ulong bits0, bits1, bits2, bits3;
byte* ip0, ip1, ip2, ip3;
byte* op0, op1, op2, op3;
byte* oend0, oend1, oend2, oend3;
HUF_DEltX2* dtable = (HUF_DEltX2*)args->dt;
byte* ilowest = args->ilowest;
bits0 = args->bits[0];
bits1 = args->bits[1];
bits2 = args->bits[2];
bits3 = args->bits[3];
ip0 = args->ip.e0;
ip1 = args->ip.e1;
ip2 = args->ip.e2;
ip3 = args->ip.e3;
op0 = args->op.e0;
op1 = args->op.e1;
op2 = args->op.e2;
op3 = args->op.e3;
oend0 = op1;
oend1 = op2;
oend2 = op3;
oend3 = args->oend;
assert(BitConverter.IsLittleEndian);
assert(!MEM_32bits);
for (; ; )
{
byte* olimit;
int stream;
{
assert(op0 <= oend0);
assert(ip0 >= ilowest);
}
{
assert(op1 <= oend1);
assert(ip1 >= ilowest);
}
{
assert(op2 <= oend2);
assert(ip2 >= ilowest);
}
{
assert(op3 <= oend3);
assert(ip3 >= ilowest);
}
{
/* Each loop does 5 table lookups for each of the 4 streams.
* Each table lookup consumes up to 11 bits of input, and produces
* up to 2 bytes of output.
*/
/* We can consume up to 7 bytes of input per iteration per stream.
* We also know that each input pointer is >= ip[0]. So we can run
* iters loops before running out of input.
*/
nuint iters = (nuint)(ip0 - ilowest) / 7;
{
nuint oiters = (nuint)(oend0 - op0) / 10;
iters = iters < oiters ? iters : oiters;
}
{
nuint oiters = (nuint)(oend1 - op1) / 10;
iters = iters < oiters ? iters : oiters;
}
{
nuint oiters = (nuint)(oend2 - op2) / 10;
iters = iters < oiters ? iters : oiters;
}
{
nuint oiters = (nuint)(oend3 - op3) / 10;
iters = iters < oiters ? iters : oiters;
}
olimit = op3 + iters * 5;
if (op3 == olimit)
break;
{
if (ip1 < ip0)
goto _out;
}
{
if (ip2 < ip1)
goto _out;
}
{
if (ip3 < ip2)
goto _out;
}
}
{
assert(ip1 >= ip0);
}
{
assert(ip2 >= ip1);
}
{
assert(ip3 >= ip2);
}
do
{
{
{
/* Decode 5 symbols from each of the first 3 streams.
* The final stream will be decoded during the reload phase
* to reduce register pressure.
*/
int index = (int)(bits0 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op0, entry.sequence);
bits0 <<= entry.nbBits & 0x3F;
op0 += entry.length;
}
{
int index = (int)(bits1 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op1, entry.sequence);
bits1 <<= entry.nbBits & 0x3F;
op1 += entry.length;
}
{
int index = (int)(bits2 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op2, entry.sequence);
bits2 <<= entry.nbBits & 0x3F;
op2 += entry.length;
}
}
{
{
int index = (int)(bits0 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op0, entry.sequence);
bits0 <<= entry.nbBits & 0x3F;
op0 += entry.length;
}
{
int index = (int)(bits1 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op1, entry.sequence);
bits1 <<= entry.nbBits & 0x3F;
op1 += entry.length;
}
{
int index = (int)(bits2 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op2, entry.sequence);
bits2 <<= entry.nbBits & 0x3F;
op2 += entry.length;
}
}
{
{
int index = (int)(bits0 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op0, entry.sequence);
bits0 <<= entry.nbBits & 0x3F;
op0 += entry.length;
}
{
int index = (int)(bits1 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op1, entry.sequence);
bits1 <<= entry.nbBits & 0x3F;
op1 += entry.length;
}
{
int index = (int)(bits2 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op2, entry.sequence);
bits2 <<= entry.nbBits & 0x3F;
op2 += entry.length;
}
}
{
{
int index = (int)(bits0 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op0, entry.sequence);
bits0 <<= entry.nbBits & 0x3F;
op0 += entry.length;
}
{
int index = (int)(bits1 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op1, entry.sequence);
bits1 <<= entry.nbBits & 0x3F;
op1 += entry.length;
}
{
int index = (int)(bits2 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op2, entry.sequence);
bits2 <<= entry.nbBits & 0x3F;
op2 += entry.length;
}
}
{
{
int index = (int)(bits0 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op0, entry.sequence);
bits0 <<= entry.nbBits & 0x3F;
op0 += entry.length;
}
{
int index = (int)(bits1 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op1, entry.sequence);
bits1 <<= entry.nbBits & 0x3F;
op1 += entry.length;
}
{
int index = (int)(bits2 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op2, entry.sequence);
bits2 <<= entry.nbBits & 0x3F;
op2 += entry.length;
}
}
{
/* Decode one symbol from the final stream */
int index = (int)(bits3 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op3, entry.sequence);
bits3 <<= entry.nbBits & 0x3F;
op3 += entry.length;
}
{
{
{
/* Decode 4 symbols from the final stream & reload bitstreams.
* The final stream is reloaded last, meaning that all 5 symbols
* are decoded from the final stream before it is reloaded.
*/
int index = (int)(bits3 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op3, entry.sequence);
bits3 <<= entry.nbBits & 0x3F;
op3 += entry.length;
}
{
int ctz = (int)ZSTD_countTrailingZeros64(bits0);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
ip0 -= nbBytes;
bits0 = MEM_read64(ip0) | 1;
bits0 <<= nbBits;
}
}
{
{
int index = (int)(bits3 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op3, entry.sequence);
bits3 <<= entry.nbBits & 0x3F;
op3 += entry.length;
}
{
int ctz = (int)ZSTD_countTrailingZeros64(bits1);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
ip1 -= nbBytes;
bits1 = MEM_read64(ip1) | 1;
bits1 <<= nbBits;
}
}
{
{
int index = (int)(bits3 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op3, entry.sequence);
bits3 <<= entry.nbBits & 0x3F;
op3 += entry.length;
}
{
int ctz = (int)ZSTD_countTrailingZeros64(bits2);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
ip2 -= nbBytes;
bits2 = MEM_read64(ip2) | 1;
bits2 <<= nbBits;
}
}
{
{
int index = (int)(bits3 >> 53);
HUF_DEltX2 entry = dtable[index];
MEM_write16(op3, entry.sequence);
bits3 <<= entry.nbBits & 0x3F;
op3 += entry.length;
}
{
int ctz = (int)ZSTD_countTrailingZeros64(bits3);
int nbBits = ctz & 7;
int nbBytes = ctz >> 3;
ip3 -= nbBytes;
bits3 = MEM_read64(ip3) | 1;
bits3 <<= nbBits;
}
}
}
}
while (op3 < olimit);
}
_out:
args->bits[0] = bits0;
args->bits[1] = bits1;
args->bits[2] = bits2;
args->bits[3] = bits3;
args->ip.e0 = ip0;
args->ip.e1 = ip1;
args->ip.e2 = ip2;
args->ip.e3 = ip3;
args->op.e0 = op0;
args->op.e1 = op1;
args->op.e2 = op2;
args->op.e3 = op3;
}
private static nuint HUF_decompress4X2_usingDTable_internal_fast(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable, void* loopFn)
{
void* dt = DTable + 1;
byte* ilowest = (byte*)cSrc;
byte* oend = ZSTD_maybeNullPtrAdd((byte*)dst, (nint)dstSize);
HUF_DecompressFastArgs args;
{
nuint ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable);
{
nuint err_code = ret;
if (ERR_isError(err_code))
{
return err_code;
}
}
if (ret == 0)
return 0;
}
assert(args.ip.e0 >= args.ilowest);
((delegate* managed<HUF_DecompressFastArgs*, void>)loopFn)(&args);
assert(args.ip.e0 >= ilowest);
assert(args.ip.e1 >= ilowest);
assert(args.ip.e2 >= ilowest);
assert(args.ip.e3 >= ilowest);
assert(args.op.e3 <= oend);
assert(ilowest == args.ilowest);
assert(ilowest + 6 == args.iend.e0);
{
nuint segmentSize = (dstSize + 3) / 4;
byte* segmentEnd = (byte*)dst;
int i;
for (i = 0; i < 4; ++i)
{
BIT_DStream_t bit;
if (segmentSize <= (nuint)(oend - segmentEnd))
segmentEnd += segmentSize;
else
segmentEnd = oend;
{
nuint err_code = HUF_initRemainingDStream(&bit, &args, i, segmentEnd);
if (ERR_isError(err_code))
{
return err_code;
}
}
(&args.op.e0)[i] += HUF_decodeStreamX2((&args.op.e0)[i], &bit, segmentEnd, (HUF_DEltX2*)dt, 11);
if ((&args.op.e0)[i] != segmentEnd)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
}
}
return dstSize;
}
private static nuint HUF_decompress4X2_usingDTable_internal(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable, int flags)
{
void* fallbackFn = (delegate* managed<void*, nuint, void*, nuint, uint*, nuint>)(&HUF_decompress4X2_usingDTable_internal_default);
void* loopFn = (delegate* managed<HUF_DecompressFastArgs*, void>)(&HUF_decompress4X2_usingDTable_internal_fast_c_loop);
if ((flags & (int)HUF_flags_e.HUF_flags_disableFast) == 0)
{
nuint ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
if (ret != 0)
return ret;
}
return ((delegate* managed<void*, nuint, void*, nuint, uint*, nuint>)fallbackFn)(dst, dstSize, cSrc, cSrcSize, DTable);
}
private static nuint HUF_decompress1X2_usingDTable_internal(void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, uint* DTable, int flags)
{
return HUF_decompress1X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable);
}
private static nuint HUF_decompress4X2_DCtx_wksp(uint* dctx, void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, void* workSpace, nuint wkspSize, int flags)
{
byte* ip = (byte*)cSrc;
nuint hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags);
if (ERR_isError(hSize))
return hSize;
if (hSize >= cSrcSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_srcSize_wrong));
ip += hSize;
cSrcSize -= hSize;
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags);
}
private static readonly algo_time_t[][] algoTime = new algo_time_t[16][]
{
new algo_time_t[2]
{
new algo_time_t(tableTime: 0, decode256Time: 0),
new algo_time_t(tableTime: 1, decode256Time: 1)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 0, decode256Time: 0),
new algo_time_t(tableTime: 1, decode256Time: 1)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 150, decode256Time: 216),
new algo_time_t(tableTime: 381, decode256Time: 119)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 170, decode256Time: 205),
new algo_time_t(tableTime: 514, decode256Time: 112)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 177, decode256Time: 199),
new algo_time_t(tableTime: 539, decode256Time: 110)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 197, decode256Time: 194),
new algo_time_t(tableTime: 644, decode256Time: 107)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 221, decode256Time: 192),
new algo_time_t(tableTime: 735, decode256Time: 107)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 256, decode256Time: 189),
new algo_time_t(tableTime: 881, decode256Time: 106)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 359, decode256Time: 188),
new algo_time_t(tableTime: 1167, decode256Time: 109)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 582, decode256Time: 187),
new algo_time_t(tableTime: 1570, decode256Time: 114)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 688, decode256Time: 187),
new algo_time_t(tableTime: 1712, decode256Time: 122)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 825, decode256Time: 186),
new algo_time_t(tableTime: 1965, decode256Time: 136)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 976, decode256Time: 185),
new algo_time_t(tableTime: 2131, decode256Time: 150)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 1180, decode256Time: 186),
new algo_time_t(tableTime: 2070, decode256Time: 175)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 1377, decode256Time: 185),
new algo_time_t(tableTime: 1731, decode256Time: 202)
},
new algo_time_t[2]
{
new algo_time_t(tableTime: 1412, decode256Time: 185),
new algo_time_t(tableTime: 1695, decode256Time: 202)
}
};
/** HUF_selectDecoder() :
* Tells which decoder is likely to decode faster,
* based on a set of pre-computed metrics.
* @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
* Assumption : 0 < dstSize <= 128 KB */
private static uint HUF_selectDecoder(nuint dstSize, nuint cSrcSize)
{
assert(dstSize > 0);
assert(dstSize <= 128 * 1024);
{
/* Q < 16 */
uint Q = cSrcSize >= dstSize ? 15 : (uint)(cSrcSize * 16 / dstSize);
uint D256 = (uint)(dstSize >> 8);
uint DTime0 = algoTime[Q][0].tableTime + algoTime[Q][0].decode256Time * D256;
uint DTime1 = algoTime[Q][1].tableTime + algoTime[Q][1].decode256Time * D256;
DTime1 += DTime1 >> 5;
return DTime1 < DTime0 ? 1U : 0U;
}
}
/* BMI2 variants.
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
*/
private static nuint HUF_decompress1X_usingDTable(void* dst, nuint maxDstSize, void* cSrc, nuint cSrcSize, uint* DTable, int flags)
{
DTableDesc dtd = HUF_getDTableDesc(DTable);
return dtd.tableType != 0 ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags);
}
private static nuint HUF_decompress1X1_DCtx_wksp(uint* dctx, void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, void* workSpace, nuint wkspSize, int flags)
{
byte* ip = (byte*)cSrc;
nuint hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags);
if (ERR_isError(hSize))
return hSize;
if (hSize >= cSrcSize)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_srcSize_wrong));
ip += hSize;
cSrcSize -= hSize;
return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags);
}
private static nuint HUF_decompress4X_usingDTable(void* dst, nuint maxDstSize, void* cSrc, nuint cSrcSize, uint* DTable, int flags)
{
DTableDesc dtd = HUF_getDTableDesc(DTable);
return dtd.tableType != 0 ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags);
}
private static nuint HUF_decompress4X_hufOnly_wksp(uint* dctx, void* dst, nuint dstSize, void* cSrc, nuint cSrcSize, void* workSpace, nuint wkspSize, int flags)
{
if (dstSize == 0)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_dstSize_tooSmall));
if (cSrcSize == 0)
return unchecked((nuint)(-(int)ZSTD_ErrorCode.ZSTD_error_corruption_detected));
{
uint algoNb = HUF_selectDecoder(dstSize, cSrcSize);
return algoNb != 0 ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags) : HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags);
}
}
}
}