make an async code

This commit is contained in:
Adam Hathcock
2025-11-01 09:42:17 +00:00
parent 55cb350d2c
commit f391c3caf3
3 changed files with 243 additions and 3 deletions

View File

@@ -87,6 +87,12 @@ internal class OutWindow : IDisposable
_stream = null;
}
public async Task ReleaseStreamAsync(CancellationToken cancellationToken = default)
{
await FlushAsync(cancellationToken).ConfigureAwait(false);
_stream = null;
}
private void Flush()
{
if (_stream is null)
@@ -147,6 +153,26 @@ internal class OutWindow : IDisposable
_pendingLen = rem;
}
public async Task CopyPendingAsync(CancellationToken cancellationToken = default)
{
if (_pendingLen < 1)
{
return;
}
var rem = _pendingLen;
var pos = (_pendingDist < _pos ? _pos : _pos + _windowSize) - _pendingDist - 1;
while (rem > 0 && HasSpace)
{
if (pos >= _windowSize)
{
pos = 0;
}
await PutByteAsync(_buffer[pos++], cancellationToken).ConfigureAwait(false);
rem--;
}
_pendingLen = rem;
}
public void CopyBlock(int distance, int len)
{
var rem = len;
@@ -180,6 +206,39 @@ internal class OutWindow : IDisposable
_pendingDist = distance;
}
public async Task CopyBlockAsync(int distance, int len, CancellationToken cancellationToken = default)
{
var rem = len;
var pos = (distance < _pos ? _pos : _pos + _windowSize) - distance - 1;
var targetSize = HasSpace ? (int)Math.Min(rem, _limit - _total) : 0;
var sizeUntilWindowEnd = Math.Min(_windowSize - _pos, _windowSize - pos);
var sizeUntilOverlap = Math.Abs(pos - _pos);
var fastSize = Math.Min(Math.Min(sizeUntilWindowEnd, sizeUntilOverlap), targetSize);
if (fastSize >= 2)
{
_buffer.AsSpan(pos, fastSize).CopyTo(_buffer.AsSpan(_pos, fastSize));
_pos += fastSize;
pos += fastSize;
_total += fastSize;
if (_pos >= _windowSize)
{
await FlushAsync(cancellationToken).ConfigureAwait(false);
}
rem -= fastSize;
}
while (rem > 0 && HasSpace)
{
if (pos >= _windowSize)
{
pos = 0;
}
await PutByteAsync(_buffer[pos++], cancellationToken).ConfigureAwait(false);
rem--;
}
_pendingLen = rem;
_pendingDist = distance;
}
public void PutByte(byte b)
{
_buffer[_pos++] = b;
@@ -190,6 +249,16 @@ internal class OutWindow : IDisposable
}
}
public async Task PutByteAsync(byte b, CancellationToken cancellationToken = default)
{
_buffer[_pos++] = b;
_total++;
if (_pos >= _windowSize)
{
await FlushAsync(cancellationToken).ConfigureAwait(false);
}
}
public byte GetByte(int distance)
{
var pos = _pos - distance - 1;

View File

@@ -313,6 +313,42 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
_outWindow = null;
}
public async System.Threading.Tasks.Task CodeAsync(
Stream inStream,
Stream outStream,
long inSize,
long outSize,
ICodeProgress progress,
System.Threading.CancellationToken cancellationToken = default
)
{
if (_outWindow is null)
{
CreateDictionary();
}
_outWindow.Init(outStream);
if (outSize > 0)
{
_outWindow.SetLimit(outSize);
}
else
{
_outWindow.SetLimit(long.MaxValue - _outWindow.Total);
}
var rangeDecoder = new RangeCoder.Decoder();
rangeDecoder.Init(inStream);
await CodeAsync(_dictionarySize, _outWindow, rangeDecoder, cancellationToken)
.ConfigureAwait(false);
await _outWindow.ReleaseStreamAsync(cancellationToken).ConfigureAwait(false);
rangeDecoder.ReleaseStream();
_outWindow.Dispose();
_outWindow = null;
}
internal bool Code(int dictionarySize, OutWindow outWindow, RangeCoder.Decoder rangeDecoder)
{
var dictionarySizeCheck = Math.Max(dictionarySize, 1);
@@ -439,6 +475,141 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
return false;
}
internal async System.Threading.Tasks.Task<bool> CodeAsync(
int dictionarySize,
OutWindow outWindow,
RangeCoder.Decoder rangeDecoder,
System.Threading.CancellationToken cancellationToken = default
)
{
var dictionarySizeCheck = Math.Max(dictionarySize, 1);
await outWindow.CopyPendingAsync(cancellationToken).ConfigureAwait(false);
while (outWindow.HasSpace)
{
cancellationToken.ThrowIfCancellationRequested();
var posState = (uint)outWindow.Total & _posStateMask;
if (
_isMatchDecoders[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState]
.Decode(rangeDecoder) == 0
)
{
byte b;
var prevByte = outWindow.GetByte(0);
if (!_state.IsCharState())
{
b = _literalDecoder.DecodeWithMatchByte(
rangeDecoder,
(uint)outWindow.Total,
prevByte,
outWindow.GetByte((int)_rep0)
);
}
else
{
b = _literalDecoder.DecodeNormal(rangeDecoder, (uint)outWindow.Total, prevByte);
}
await outWindow.PutByteAsync(b, cancellationToken).ConfigureAwait(false);
_state.UpdateChar();
}
else
{
uint len;
if (_isRepDecoders[_state._index].Decode(rangeDecoder) == 1)
{
if (_isRepG0Decoders[_state._index].Decode(rangeDecoder) == 0)
{
if (
_isRep0LongDecoders[
(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState
]
.Decode(rangeDecoder) == 0
)
{
_state.UpdateShortRep();
await outWindow
.PutByteAsync(outWindow.GetByte((int)_rep0), cancellationToken)
.ConfigureAwait(false);
continue;
}
}
else
{
uint distance;
if (_isRepG1Decoders[_state._index].Decode(rangeDecoder) == 0)
{
distance = _rep1;
}
else
{
if (_isRepG2Decoders[_state._index].Decode(rangeDecoder) == 0)
{
distance = _rep2;
}
else
{
distance = _rep3;
_rep3 = _rep2;
}
_rep2 = _rep1;
}
_rep1 = _rep0;
_rep0 = distance;
}
len = _repLenDecoder.Decode(rangeDecoder, posState) + Base.K_MATCH_MIN_LEN;
_state.UpdateRep();
}
else
{
_rep3 = _rep2;
_rep2 = _rep1;
_rep1 = _rep0;
len = Base.K_MATCH_MIN_LEN + _lenDecoder.Decode(rangeDecoder, posState);
_state.UpdateMatch();
var posSlot = _posSlotDecoder[Base.GetLenToPosState(len)].Decode(rangeDecoder);
if (posSlot >= Base.K_START_POS_MODEL_INDEX)
{
var numDirectBits = (int)((posSlot >> 1) - 1);
_rep0 = ((2 | (posSlot & 1)) << numDirectBits);
if (posSlot < Base.K_END_POS_MODEL_INDEX)
{
_rep0 += BitTreeDecoder.ReverseDecode(
_posDecoders,
_rep0 - posSlot - 1,
rangeDecoder,
numDirectBits
);
}
else
{
_rep0 += (
rangeDecoder.DecodeDirectBits(numDirectBits - Base.K_NUM_ALIGN_BITS)
<< Base.K_NUM_ALIGN_BITS
);
_rep0 += _posAlignDecoder.ReverseDecode(rangeDecoder);
}
}
else
{
_rep0 = posSlot;
}
}
if (_rep0 >= outWindow.Total || _rep0 >= dictionarySizeCheck)
{
if (_rep0 == 0xFFFFFFFF)
{
return true;
}
throw new DataErrorException();
}
await outWindow.CopyBlockAsync((int)_rep0, (int)len, cancellationToken).ConfigureAwait(false);
}
}
return false;
}
public void SetDecoderProperties(byte[] properties)
{
if (properties.Length < 1)

View File

@@ -559,7 +559,7 @@ public class LzmaStream : Stream, IStreamStack
.CopyStreamAsync(_inputStream, toProcess, cancellationToken)
.ConfigureAwait(false);
}
else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0)
else if (await _decoder.CodeAsync(_dictionarySize, _outWindow, _rangeDecoder, cancellationToken).ConfigureAwait(false) && _outputSize < 0)
{
_availableBytes = _outWindow.AvailableBytes;
}
@@ -578,7 +578,7 @@ public class LzmaStream : Stream, IStreamStack
)
{
_outWindow.SetLimit(toProcess + 1);
if (!_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder))
if (!await _decoder.CodeAsync(_dictionarySize, _outWindow, _rangeDecoder, cancellationToken).ConfigureAwait(false))
{
_rangeDecoder.ReleaseStream();
throw new DataErrorException();
@@ -614,7 +614,7 @@ public class LzmaStream : Stream, IStreamStack
byte[] buffer,
int offset,
int count,
CancellationToken cancellationToken = default
CancellationToken cancellationToken
)
{
cancellationToken.ThrowIfCancellationRequested();