mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 05:25:00 +00:00
implemented async rangecoder
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user