implemented async rangecoder

This commit is contained in:
Adam Hathcock
2026-01-25 15:17:44 +00:00
parent d0823db595
commit 244acc0c9e
6 changed files with 382 additions and 6 deletions

View File

@@ -0,0 +1,192 @@
#nullable disable
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Compressors.LZMA.RangeCoder;
internal partial class Encoder
{
public async ValueTask ShiftLowAsync(CancellationToken cancellationToken = default)
{
if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1)
{
var temp = _cache;
do
{
var b = (byte)(temp + (uint)(_low >> 32));
var buffer = new[] { b };
await _stream.WriteAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false);
temp = 0xFF;
} while (--_cacheSize != 0);
_cache = (byte)(((uint)_low) >> 24);
}
_cacheSize++;
_low = ((uint)_low) << 8;
}
public async ValueTask EncodeAsync(
uint start,
uint size,
uint total,
CancellationToken cancellationToken = default
)
{
_low += start * (_range /= total);
_range *= size;
while (_range < K_TOP_VALUE)
{
_range <<= 8;
await ShiftLowAsync(cancellationToken).ConfigureAwait(false);
}
}
public async ValueTask EncodeBitAsync(
uint size0,
int numTotalBits,
uint symbol,
CancellationToken cancellationToken = default
)
{
var newBound = (_range >> numTotalBits) * size0;
if (symbol == 0)
{
_range = newBound;
}
else
{
_low += newBound;
_range -= newBound;
}
while (_range < K_TOP_VALUE)
{
_range <<= 8;
await ShiftLowAsync(cancellationToken).ConfigureAwait(false);
}
}
public async ValueTask EncodeDirectBitsAsync(
uint v,
int numTotalBits,
CancellationToken cancellationToken = default
)
{
for (var i = numTotalBits - 1; i >= 0; i--)
{
_range >>= 1;
if (((v >> i) & 1) == 1)
{
_low += _range;
}
if (_range < K_TOP_VALUE)
{
_range <<= 8;
await ShiftLowAsync(cancellationToken).ConfigureAwait(false);
}
}
}
public async ValueTask FlushStreamAsync(CancellationToken cancellationToken = default) =>
await _stream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
internal partial class Decoder
{
public async ValueTask InitAsync(Stream stream, CancellationToken cancellationToken = default)
{
_stream = stream;
_code = 0;
_range = 0xFFFFFFFF;
var buffer = new byte[1];
for (var i = 0; i < 5; i++)
{
var read = await _stream
.ReadAsync(buffer, 0, 1, cancellationToken)
.ConfigureAwait(false);
if (read == 0)
{
throw new EndOfStreamException();
}
_code = (_code << 8) | buffer[0];
}
_total = 5;
}
public async ValueTask NormalizeAsync(CancellationToken cancellationToken = default)
{
while (_range < K_TOP_VALUE)
{
var buffer = new byte[1];
var read = await _stream
.ReadAsync(buffer, 0, 1, cancellationToken)
.ConfigureAwait(false);
if (read == 0)
{
throw new EndOfStreamException();
}
_code = (_code << 8) | buffer[0];
_range <<= 8;
_total++;
}
}
public async ValueTask<uint> DecodeDirectBitsAsync(
int numTotalBits,
CancellationToken cancellationToken = default
)
{
var range = _range;
var code = _code;
uint result = 0;
var buffer = new byte[1];
for (var i = numTotalBits; i > 0; i--)
{
range >>= 1;
var t = (code - range) >> 31;
code -= range & (t - 1);
result = (result << 1) | (1 - t);
if (range < K_TOP_VALUE)
{
var read = await _stream
.ReadAsync(buffer, 0, 1, cancellationToken)
.ConfigureAwait(false);
if (read == 0)
{
throw new EndOfStreamException();
}
code = (code << 8) | buffer[0];
range <<= 8;
_total++;
}
}
_range = range;
_code = code;
return result;
}
public async ValueTask<uint> DecodeBitAsync(
uint size0,
int numTotalBits,
CancellationToken cancellationToken = default
)
{
var newBound = (_range >> numTotalBits) * size0;
uint symbol;
if (_code < newBound)
{
symbol = 0;
_range = newBound;
}
else
{
symbol = 1;
_code -= newBound;
_range -= newBound;
}
await NormalizeAsync(cancellationToken).ConfigureAwait(false);
return symbol;
}
}

View File

@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
namespace SharpCompress.Compressors.LZMA.RangeCoder;
internal class Encoder
internal partial class Encoder
{
public const uint K_TOP_VALUE = (1 << 24);
@@ -113,7 +113,7 @@ internal class Encoder
// (long)Stream.GetProcessedSize();
}
internal class Decoder
internal partial class Decoder
{
public const uint K_TOP_VALUE = (1 << 24);
public uint _range;

View File

@@ -0,0 +1,57 @@
#nullable disable
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Compressors.LZMA.RangeCoder;
internal partial struct BitEncoder
{
public async ValueTask EncodeAsync(
Encoder encoder,
uint symbol,
CancellationToken cancellationToken = default
)
{
var newBound = (encoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob;
if (symbol == 0)
{
encoder._range = newBound;
_prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS;
}
else
{
encoder._low += newBound;
encoder._range -= newBound;
_prob -= (_prob) >> K_NUM_MOVE_BITS;
}
if (encoder._range < Encoder.K_TOP_VALUE)
{
encoder._range <<= 8;
await encoder.ShiftLowAsync(cancellationToken).ConfigureAwait(false);
}
}
}
internal partial struct BitDecoder
{
public async ValueTask<uint> DecodeAsync(
Decoder decoder,
CancellationToken cancellationToken = default
)
{
var newBound = (decoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob;
if (decoder._code < newBound)
{
decoder._range = newBound;
_prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS;
await decoder.NormalizeAsync(cancellationToken).ConfigureAwait(false);
return 0;
}
decoder._range -= newBound;
decoder._code -= newBound;
_prob -= (_prob) >> K_NUM_MOVE_BITS;
await decoder.NormalizeAsync(cancellationToken).ConfigureAwait(false);
return 1;
}
}

View File

@@ -1,6 +1,6 @@
namespace SharpCompress.Compressors.LZMA.RangeCoder;
internal struct BitEncoder
internal partial struct BitEncoder
{
public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11;
public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS);
@@ -78,7 +78,7 @@ internal struct BitEncoder
public uint GetPrice1() => PROB_PRICES[(K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_REDUCING_BITS];
}
internal struct BitDecoder
internal partial struct BitDecoder
{
public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11;
public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS);

View File

@@ -0,0 +1,127 @@
#nullable disable
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Compressors.LZMA.RangeCoder;
internal readonly partial struct BitTreeEncoder
{
public async ValueTask EncodeAsync(
Encoder rangeEncoder,
uint symbol,
CancellationToken cancellationToken = default
)
{
uint m = 1;
for (var bitIndex = _numBitLevels; bitIndex > 0; )
{
bitIndex--;
var bit = (symbol >> bitIndex) & 1;
await _models[m]
.EncodeAsync(rangeEncoder, bit, cancellationToken)
.ConfigureAwait(false);
m = (m << 1) | bit;
}
}
public async ValueTask ReverseEncodeAsync(
Encoder rangeEncoder,
uint symbol,
CancellationToken cancellationToken = default
)
{
uint m = 1;
for (uint i = 0; i < _numBitLevels; i++)
{
var bit = symbol & 1;
await _models[m]
.EncodeAsync(rangeEncoder, bit, cancellationToken)
.ConfigureAwait(false);
m = (m << 1) | bit;
symbol >>= 1;
}
}
public static async ValueTask ReverseEncodeAsync(
BitEncoder[] models,
uint startIndex,
Encoder rangeEncoder,
int numBitLevels,
uint symbol,
CancellationToken cancellationToken = default
)
{
uint m = 1;
for (var i = 0; i < numBitLevels; i++)
{
var bit = symbol & 1;
await models[startIndex + m]
.EncodeAsync(rangeEncoder, bit, cancellationToken)
.ConfigureAwait(false);
m = (m << 1) | bit;
symbol >>= 1;
}
}
}
internal readonly partial struct BitTreeDecoder
{
public async ValueTask<uint> DecodeAsync(
Decoder rangeDecoder,
CancellationToken cancellationToken = default
)
{
uint m = 1;
for (var bitIndex = _numBitLevels; bitIndex > 0; bitIndex--)
{
m =
(m << 1)
+ await _models[m]
.DecodeAsync(rangeDecoder, cancellationToken)
.ConfigureAwait(false);
}
return m - ((uint)1 << _numBitLevels);
}
public async ValueTask<uint> ReverseDecodeAsync(
Decoder rangeDecoder,
CancellationToken cancellationToken = default
)
{
uint m = 1;
uint symbol = 0;
for (var bitIndex = 0; bitIndex < _numBitLevels; bitIndex++)
{
var bit = await _models[m]
.DecodeAsync(rangeDecoder, cancellationToken)
.ConfigureAwait(false);
m <<= 1;
m += bit;
symbol |= (bit << bitIndex);
}
return symbol;
}
public static async ValueTask<uint> ReverseDecodeAsync(
BitDecoder[] models,
uint startIndex,
Decoder rangeDecoder,
int numBitLevels,
CancellationToken cancellationToken = default
)
{
uint m = 1;
uint symbol = 0;
for (var bitIndex = 0; bitIndex < numBitLevels; bitIndex++)
{
var bit = await models[startIndex + m]
.DecodeAsync(rangeDecoder, cancellationToken)
.ConfigureAwait(false);
m <<= 1;
m += bit;
symbol |= (bit << bitIndex);
}
return symbol;
}
}

View File

@@ -1,6 +1,6 @@
namespace SharpCompress.Compressors.LZMA.RangeCoder;
internal readonly struct BitTreeEncoder
internal readonly partial struct BitTreeEncoder
{
private readonly BitEncoder[] _models;
private readonly int _numBitLevels;
@@ -109,7 +109,7 @@ internal readonly struct BitTreeEncoder
}
}
internal readonly struct BitTreeDecoder
internal readonly partial struct BitTreeDecoder
{
private readonly BitDecoder[] _models;
private readonly int _numBitLevels;