mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add an optional dynamic backing array to MemoryStorage
This commit is contained in:
parent
34e926f2a4
commit
19cf003160
4 changed files with 71 additions and 12 deletions
|
@ -142,7 +142,7 @@ namespace LibHac.IO
|
|||
return DirectoryEntryType.File;
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("path");
|
||||
throw new FileNotFoundException(path);
|
||||
}
|
||||
|
||||
public void Commit()
|
||||
|
|
|
@ -36,6 +36,6 @@ namespace LibHac.IO
|
|||
Storage.Flush();
|
||||
}
|
||||
|
||||
public override long Length => Stream.Length;
|
||||
public override long Length => Storage.Length;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,26 @@ namespace LibHac.IO
|
|||
{
|
||||
public class MemoryStorage : StorageBase
|
||||
{
|
||||
private byte[] Buffer { get; }
|
||||
private int Start { get; }
|
||||
private byte[] _buffer;
|
||||
private int _start;
|
||||
private int _length;
|
||||
private int _capacity;
|
||||
private bool _isExpandable;
|
||||
|
||||
public MemoryStorage(byte[] buffer) : this(buffer, 0, buffer.Length)
|
||||
public MemoryStorage() : this(0) { }
|
||||
|
||||
public MemoryStorage(int capacity)
|
||||
{
|
||||
if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), "Argument must be positive");
|
||||
|
||||
_capacity = capacity;
|
||||
_isExpandable = true;
|
||||
CanAutoExpand = true;
|
||||
_buffer = new byte[capacity];
|
||||
}
|
||||
|
||||
public MemoryStorage(byte[] buffer) : this(buffer, 0, buffer.Length) { }
|
||||
|
||||
public MemoryStorage(byte[] buffer, int index, int count)
|
||||
{
|
||||
if (buffer == null) throw new NullReferenceException(nameof(buffer));
|
||||
|
@ -19,23 +31,69 @@ namespace LibHac.IO
|
|||
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Value must be non-negative.");
|
||||
if (buffer.Length - index < count) throw new ArgumentException("Length, index and count parameters are invalid.");
|
||||
|
||||
Buffer = buffer;
|
||||
Start = index;
|
||||
Length = count;
|
||||
_buffer = buffer;
|
||||
_start = index;
|
||||
_length = count;
|
||||
_capacity = count;
|
||||
_isExpandable = false;
|
||||
}
|
||||
|
||||
protected override void ReadImpl(Span<byte> destination, long offset)
|
||||
{
|
||||
Buffer.AsSpan((int)(Start + offset), destination.Length).CopyTo(destination);
|
||||
_buffer.AsSpan((int)(_start + offset), destination.Length).CopyTo(destination);
|
||||
}
|
||||
|
||||
protected override void WriteImpl(ReadOnlySpan<byte> source, long offset)
|
||||
{
|
||||
source.CopyTo(Buffer.AsSpan((int)(Start + offset), source.Length));
|
||||
long requiredCapacity = _start + offset + source.Length;
|
||||
|
||||
if (requiredCapacity > _length)
|
||||
{
|
||||
if (requiredCapacity > _capacity) EnsureCapacity(requiredCapacity);
|
||||
_length = (int)(requiredCapacity - _start);
|
||||
}
|
||||
|
||||
source.CopyTo(_buffer.AsSpan((int)(_start + offset), source.Length));
|
||||
}
|
||||
|
||||
public byte[] ToArray()
|
||||
{
|
||||
var array = new byte[_length];
|
||||
Buffer.BlockCopy(_buffer, _start, array, 0, _length);
|
||||
return array;
|
||||
}
|
||||
|
||||
// returns a bool saying whether we allocated a new array.
|
||||
private void EnsureCapacity(long value)
|
||||
{
|
||||
if (value < 0 || value > int.MaxValue) throw new ArgumentOutOfRangeException(nameof(value));
|
||||
if (value <= _capacity) return;
|
||||
|
||||
long newCapacity = Math.Max(value, 256);
|
||||
newCapacity = Math.Max(newCapacity, _capacity * 2);
|
||||
|
||||
SetCapacity((int)Math.Min(newCapacity, int.MaxValue));
|
||||
}
|
||||
|
||||
private void SetCapacity(int value)
|
||||
{
|
||||
if (value < Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(value), "Capacity is smaller than the current length.");
|
||||
|
||||
if (!_isExpandable && value != _capacity) throw new NotSupportedException("MemoryStorage is not expandable.");
|
||||
|
||||
if (_isExpandable && value != _capacity)
|
||||
{
|
||||
var newBuffer = new byte[value];
|
||||
Buffer.BlockCopy(_buffer, 0, newBuffer, 0, (int)Length);
|
||||
|
||||
_buffer = newBuffer;
|
||||
_capacity = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush() { }
|
||||
|
||||
public override long Length { get; }
|
||||
public override long Length => _length;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace LibHac.IO
|
|||
{
|
||||
private bool _isDisposed;
|
||||
protected internal List<IDisposable> ToDispose { get; } = new List<IDisposable>();
|
||||
protected bool CanAutoExpand { get; set; }
|
||||
|
||||
protected abstract void ReadImpl(Span<byte> destination, long offset);
|
||||
protected abstract void WriteImpl(ReadOnlySpan<byte> source, long offset);
|
||||
|
@ -53,7 +54,7 @@ namespace LibHac.IO
|
|||
if (span == null) throw new ArgumentNullException(nameof(span));
|
||||
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
|
||||
|
||||
if (Length != -1)
|
||||
if (Length != -1 && !CanAutoExpand)
|
||||
{
|
||||
if (offset + span.Length > Length) throw new ArgumentException("The given offset and count exceed the length of the Storage");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue