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;
|
return DirectoryEntryType.File;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new FileNotFoundException("path");
|
throw new FileNotFoundException(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Commit()
|
public void Commit()
|
||||||
|
|
|
@ -36,6 +36,6 @@ namespace LibHac.IO
|
||||||
Storage.Flush();
|
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
|
public class MemoryStorage : StorageBase
|
||||||
{
|
{
|
||||||
private byte[] Buffer { get; }
|
private byte[] _buffer;
|
||||||
private int Start { get; }
|
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)
|
public MemoryStorage(byte[] buffer, int index, int count)
|
||||||
{
|
{
|
||||||
if (buffer == null) throw new NullReferenceException(nameof(buffer));
|
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 (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.");
|
if (buffer.Length - index < count) throw new ArgumentException("Length, index and count parameters are invalid.");
|
||||||
|
|
||||||
Buffer = buffer;
|
_buffer = buffer;
|
||||||
Start = index;
|
_start = index;
|
||||||
Length = count;
|
_length = count;
|
||||||
|
_capacity = count;
|
||||||
|
_isExpandable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ReadImpl(Span<byte> destination, long offset)
|
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)
|
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 void Flush() { }
|
||||||
|
|
||||||
public override long Length { get; }
|
public override long Length => _length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace LibHac.IO
|
||||||
{
|
{
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
protected internal List<IDisposable> ToDispose { get; } = new List<IDisposable>();
|
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 ReadImpl(Span<byte> destination, long offset);
|
||||||
protected abstract void WriteImpl(ReadOnlySpan<byte> source, 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 (span == null) throw new ArgumentNullException(nameof(span));
|
||||||
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
|
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");
|
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