<data name="Argument_OffsetAndCapacityOutOfBounds" xml:space="preserve">
<value>Offset and capacity were greater than the size of the view.</value>
</data>
- <data name="Argument_OffsetAndLengthOutOfBounds" xml:space="preserve">
- <value>Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.</value>
- </data>
<data name="Argument_OffsetLocalMismatch" xml:space="preserve">
<value>The UTC Offset of the local dateTime parameter does not match the offset argument.</value>
</data>
<Compile Include="$(BclSourcesRoot)\System\IO\FileLoadException.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\FileNotFoundException.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\Stream.cs" />
- <Compile Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryAccessor.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Security\DynamicSecurityMethodAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PinnedBufferMemoryStream.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\SeekOrigin.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\StreamHelpers.CopyValidation.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\UnmanagedMemoryAccessor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\UnmanagedMemoryStream.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\UnmanagedMemoryStreamWrapper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IObservable.cs" />
if (destination.Length < sizeof(byte))
return false;
- Unsafe.WriteUnaligned(ref destination.DangerousGetPinnableReference(), value ? (byte)1: (byte)0);
+ Unsafe.WriteUnaligned(ref destination.DangerousGetPinnableReference(), value ? (byte)1 : (byte)0);
return true;
}
}
// Converts an array of bytes into a char.
- public static char ToChar(byte[] value, int startIndex) => unchecked((char)ReadInt16(value, startIndex));
+ public static char ToChar(byte[] value, int startIndex) => unchecked((char)ToInt16(value, startIndex));
// Converts a Span into a char
public static char ToChar(ReadOnlySpan<byte> value)
return Unsafe.ReadUnaligned<char>(ref value.DangerousGetPinnableReference());
}
- private static short ReadInt16(byte[] value, int startIndex)
+ // Converts an array of bytes into a short.
+ public static short ToInt16(byte[] value, int startIndex)
{
if (value == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
return Unsafe.ReadUnaligned<short>(ref value[startIndex]);
}
- private static int ReadInt32(byte[] value, int startIndex)
+ // Converts a Span into a short
+ public static short ToInt16(ReadOnlySpan<byte> value)
{
- if (value == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
- if (startIndex > value.Length - sizeof(int))
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
-
- return Unsafe.ReadUnaligned<int>(ref value[startIndex]);
+ if (value.Length < sizeof(short))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+ return Unsafe.ReadUnaligned<short>(ref value.DangerousGetPinnableReference());
}
- private static long ReadInt64(byte[] value, int startIndex)
+ // Converts an array of bytes into an int.
+ public static int ToInt32(byte[] value, int startIndex)
{
if (value == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
- if (startIndex > value.Length - sizeof(long))
+ if (startIndex > value.Length - sizeof(int))
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
- return Unsafe.ReadUnaligned<long>(ref value[startIndex]);
- }
-
- // Converts an array of bytes into a short.
- public static short ToInt16(byte[] value, int startIndex) => ReadInt16(value, startIndex);
-
- // Converts a Span into a short
- public static short ToInt16(ReadOnlySpan<byte> value)
- {
- if (value.Length < sizeof(short))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
- return Unsafe.ReadUnaligned<short>(ref value.DangerousGetPinnableReference());
+ return Unsafe.ReadUnaligned<int>(ref value[startIndex]);
}
- // Converts an array of bytes into an int.
- public static int ToInt32(byte[] value, int startIndex) => ReadInt32(value, startIndex);
-
// Converts a Span into an int
public static int ToInt32(ReadOnlySpan<byte> value)
{
}
// Converts an array of bytes into a long.
- public static long ToInt64(byte[] value, int startIndex) => ReadInt64(value, startIndex);
+ public static long ToInt64(byte[] value, int startIndex)
+ {
+ if (value == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
+ if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
+ if (startIndex > value.Length - sizeof(long))
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
+
+ return Unsafe.ReadUnaligned<long>(ref value[startIndex]);
+ }
// Converts a Span into a long
public static long ToInt64(ReadOnlySpan<byte> value)
// Converts an array of bytes into an ushort.
//
[CLSCompliant(false)]
- public static ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)ReadInt16(value, startIndex));
+ public static ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)ToInt16(value, startIndex));
// Converts a Span into a ushort
[CLSCompliant(false)]
// Converts an array of bytes into an uint.
//
[CLSCompliant(false)]
- public static uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)ReadInt32(value, startIndex));
+ public static uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)ToInt32(value, startIndex));
// Convert a Span into a uint
[CLSCompliant(false)]
// Converts an array of bytes into an unsigned long.
//
[CLSCompliant(false)]
- public static ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)ReadInt64(value, startIndex));
+ public static ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)ToInt64(value, startIndex));
// Converts a Span into an unsigned long
[CLSCompliant(false)]
}
// Converts an array of bytes into a float.
- public static unsafe float ToSingle(byte[] value, int startIndex)
- {
- int val = ReadInt32(value, startIndex);
- return *(float*)&val;
- }
+ public static float ToSingle(byte[] value, int startIndex) => Int32BitsToSingle(ToInt32(value, startIndex));
// Converts a Span into a float
public static float ToSingle(ReadOnlySpan<byte> value)
}
// Converts an array of bytes into a double.
- public static unsafe double ToDouble(byte[] value, int startIndex)
- {
- long val = ReadInt64(value, startIndex);
- return *(double*)&val;
- }
+ public static double ToDouble(byte[] value, int startIndex) => Int64BitsToDouble(ToInt64(value, startIndex));
// Converts a Span into a double
public static double ToDouble(ReadOnlySpan<byte> value)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+**
+**
+**
+** Purpose: Provides a fast, AV free, cross-language way of
+** accessing unmanaged memory in a random fashion.
+**
+**
+===========================================================*/
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.IO
+{
+ /// Perf notes: ReadXXX, WriteXXX (for basic types) acquire and release the
+ /// SafeBuffer pointer rather than relying on generic Read(T) from SafeBuffer because
+ /// this gives better throughput; benchmarks showed about 12-15% better.
+ public class UnmanagedMemoryAccessor : IDisposable
+ {
+ private SafeBuffer _buffer;
+ private long _offset;
+ private long _capacity;
+ private FileAccess _access;
+ private bool _isOpen;
+ private bool _canRead;
+ private bool _canWrite;
+
+ protected UnmanagedMemoryAccessor()
+ {
+ _isOpen = false;
+ }
+
+ public UnmanagedMemoryAccessor(SafeBuffer buffer, long offset, long capacity)
+ {
+ Initialize(buffer, offset, capacity, FileAccess.Read);
+ }
+
+ public UnmanagedMemoryAccessor(SafeBuffer buffer, long offset, long capacity, FileAccess access)
+ {
+ Initialize(buffer, offset, capacity, access);
+ }
+
+ protected void Initialize(SafeBuffer buffer, long offset, long capacity, FileAccess access)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+ if (offset < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (capacity < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (buffer.ByteLength < (ulong)(offset + capacity))
+ {
+ throw new ArgumentException(SR.Argument_OffsetAndCapacityOutOfBounds);
+ }
+ if (access < FileAccess.Read || access > FileAccess.ReadWrite)
+ {
+ throw new ArgumentOutOfRangeException(nameof(access));
+ }
+
+ if (_isOpen)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_CalledTwice);
+ }
+
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ buffer.AcquirePointer(ref pointer);
+ if (((byte*)((long)pointer + offset + capacity)) < pointer)
+ {
+ throw new ArgumentException(SR.Argument_UnmanagedMemAccessorWrapAround);
+ }
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ buffer.ReleasePointer();
+ }
+ }
+ }
+
+ _offset = offset;
+ _buffer = buffer;
+ _capacity = capacity;
+ _access = access;
+ _isOpen = true;
+ _canRead = (_access & FileAccess.Read) != 0;
+ _canWrite = (_access & FileAccess.Write) != 0;
+ }
+
+ public long Capacity => _capacity;
+
+ public bool CanRead => _isOpen && _canRead;
+
+ public bool CanWrite => _isOpen && _canWrite;
+
+ protected virtual void Dispose(bool disposing)
+ {
+ _isOpen = false;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected bool IsOpen => _isOpen;
+
+ // ************** Read Methods ****************/
+
+ public bool ReadBoolean(long position) => ReadByte(position) != 0;
+
+ public byte ReadByte(long position)
+ {
+ EnsureSafeToRead(position, sizeof(byte));
+
+ byte result;
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ result = *((byte*)(pointer + _offset + position));
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ return result;
+ }
+
+ public char ReadChar(long position) => unchecked((char)ReadInt16(position));
+
+ public short ReadInt16(long position)
+ {
+ EnsureSafeToRead(position, sizeof(short));
+
+ short result;
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ result = Unsafe.ReadUnaligned<short>(pointer + _offset + position);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ return result;
+ }
+
+ public int ReadInt32(long position)
+ {
+ EnsureSafeToRead(position, sizeof(int));
+
+ int result;
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ result = Unsafe.ReadUnaligned<int>(pointer + _offset + position);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ return result;
+ }
+
+ public long ReadInt64(long position)
+ {
+ EnsureSafeToRead(position, sizeof(long));
+
+ long result;
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ result = Unsafe.ReadUnaligned<long>(pointer + _offset + position);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ return result;
+ }
+
+ public decimal ReadDecimal(long position)
+ {
+ const int ScaleMask = 0x00FF0000;
+ const int SignMask = unchecked((int)0x80000000);
+
+ EnsureSafeToRead(position, sizeof(decimal));
+
+ int lo, mid, hi, flags;
+
+ unsafe
+ {
+ byte* pointer = null;
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ pointer += (_offset + position);
+
+ lo = Unsafe.ReadUnaligned<int>(pointer);
+ mid = Unsafe.ReadUnaligned<int>(pointer + 4);
+ hi = Unsafe.ReadUnaligned<int>(pointer + 8);
+ flags = Unsafe.ReadUnaligned<int>(pointer + 12);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+
+ // Check for invalid Decimal values
+ if (!((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16)))
+ {
+ throw new ArgumentException(SR.Arg_BadDecimal); // Throw same Exception type as Decimal(int[]) ctor for compat
+ }
+
+ bool isNegative = (flags & SignMask) != 0;
+ byte scale = (byte)(flags >> 16);
+
+ return new decimal(lo, mid, hi, isNegative, scale);
+ }
+
+ public float ReadSingle(long position) => BitConverter.Int32BitsToSingle(ReadInt32(position));
+
+ public double ReadDouble(long position) => BitConverter.Int64BitsToDouble(ReadInt64(position));
+
+ [CLSCompliant(false)]
+ public sbyte ReadSByte(long position) => unchecked((sbyte)ReadByte(position));
+
+ [CLSCompliant(false)]
+ public ushort ReadUInt16(long position) => unchecked((ushort)ReadInt16(position));
+
+ [CLSCompliant(false)]
+ public uint ReadUInt32(long position) => unchecked((uint)ReadInt32(position));
+
+ [CLSCompliant(false)]
+ public ulong ReadUInt64(long position) => unchecked((ulong)ReadInt64(position));
+
+ // Reads a struct of type T from unmanaged memory, into the reference pointed to by ref value.
+ // Note: this method is not safe, since it overwrites the contents of a structure, it can be
+ // used to modify the private members of a struct.
+ // This method is most performant when used with medium to large sized structs
+ // (larger than 8 bytes -- though this is number is JIT and architecture dependent). As
+ // such, it is best to use the ReadXXX methods for small standard types such as ints, longs,
+ // bools, etc.
+ public void Read<T>(long position, out T structure) where T : struct
+ {
+ if (position < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ if (!_isOpen)
+ {
+ throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed);
+ }
+ if (!_canRead)
+ {
+ throw new NotSupportedException(SR.NotSupported_Reading);
+ }
+
+ uint sizeOfT = SafeBuffer.SizeOf<T>();
+ if (position > _capacity - sizeOfT)
+ {
+ if (position >= _capacity)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
+ }
+ else
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToRead, typeof(T)), nameof(position));
+ }
+ }
+
+ structure = _buffer.Read<T>((ulong)(_offset + position));
+ }
+
+ // Reads 'count' structs of type T from unmanaged memory, into 'array' starting at 'offset'.
+ // Note: this method is not safe, since it overwrites the contents of structures, it can
+ // be used to modify the private members of a struct.
+ public int ReadArray<T>(long position, T[] array, int offset, int count) where T : struct
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException(nameof(array), SR.ArgumentNull_Buffer);
+ }
+ if (offset < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (array.Length - offset < count)
+ {
+ throw new ArgumentException(SR.Argument_InvalidOffLen);
+ }
+ if (!_isOpen)
+ {
+ throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed);
+ }
+ if (!_canRead)
+ {
+ throw new NotSupportedException(SR.NotSupported_Reading);
+ }
+ if (position < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+
+ uint sizeOfT = SafeBuffer.AlignedSizeOf<T>();
+
+ // only check position and ask for fewer Ts if count is too big
+ if (position >= _capacity)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
+ }
+
+ int n = count;
+ long spaceLeft = _capacity - position;
+ if (spaceLeft < 0)
+ {
+ n = 0;
+ }
+ else
+ {
+ ulong spaceNeeded = (ulong)(sizeOfT * count);
+ if ((ulong)spaceLeft < spaceNeeded)
+ {
+ n = (int)(spaceLeft / sizeOfT);
+ }
+ }
+
+ _buffer.ReadArray<T>((ulong)(_offset + position), array, offset, n);
+
+ return n;
+ }
+
+ // ************** Write Methods ****************/
+
+ public void Write(long position, bool value) => Write(position, (byte)(value ? 1 : 0));
+
+ public void Write(long position, byte value)
+ {
+ EnsureSafeToWrite(position, sizeof(byte));
+
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ *((byte*)(pointer + _offset + position)) = value;
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ }
+
+ public void Write(long position, char value) => Write(position, unchecked((short)value));
+
+ public void Write(long position, short value)
+ {
+ EnsureSafeToWrite(position, sizeof(short));
+
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ Unsafe.WriteUnaligned<short>(pointer + _offset + position, value);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ }
+
+ public void Write(long position, int value)
+ {
+ EnsureSafeToWrite(position, sizeof(int));
+
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ Unsafe.WriteUnaligned<int>(pointer + _offset + position, value);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ }
+
+ public void Write(long position, long value)
+ {
+ EnsureSafeToWrite(position, sizeof(long));
+
+ unsafe
+ {
+ byte* pointer = null;
+
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ Unsafe.WriteUnaligned<long>(pointer + _offset + position, value);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ }
+
+ public void Write(long position, decimal value)
+ {
+ EnsureSafeToWrite(position, sizeof(decimal));
+
+ unsafe
+ {
+ int* valuePtr = (int*)(&value);
+ int flags = *valuePtr;
+ int hi = *(valuePtr + 1);
+ int lo = *(valuePtr + 2);
+ int mid = *(valuePtr + 3);
+
+ byte* pointer = null;
+ try
+ {
+ _buffer.AcquirePointer(ref pointer);
+ pointer += (_offset + position);
+
+ Unsafe.WriteUnaligned<int>(pointer, lo);
+ Unsafe.WriteUnaligned<int>(pointer + 4, mid);
+ Unsafe.WriteUnaligned<int>(pointer + 8, hi);
+ Unsafe.WriteUnaligned<int>(pointer + 12, flags);
+ }
+ finally
+ {
+ if (pointer != null)
+ {
+ _buffer.ReleasePointer();
+ }
+ }
+ }
+ }
+
+ public void Write(long position, float value) => Write(position, BitConverter.SingleToInt32Bits(value));
+
+ public void Write(long position, double value) => Write(position, BitConverter.DoubleToInt64Bits(value));
+
+ [CLSCompliant(false)]
+ public void Write(long position, sbyte value) => Write(position, unchecked((byte)value));
+
+ [CLSCompliant(false)]
+ public void Write(long position, ushort value) => Write(position, unchecked((short)value));
+
+ [CLSCompliant(false)]
+ public void Write(long position, uint value) => Write(position, unchecked((int)value));
+
+ [CLSCompliant(false)]
+ public void Write(long position, ulong value) => Write(position, unchecked((long)value));
+
+ // Writes the struct pointed to by ref value into unmanaged memory. Note that this method
+ // is most performant when used with medium to large sized structs (larger than 8 bytes
+ // though this is number is JIT and architecture dependent). As such, it is best to use
+ // the WriteX methods for small standard types such as ints, longs, bools, etc.
+ public void Write<T>(long position, ref T structure) where T : struct
+ {
+ if (position < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (!_isOpen)
+ {
+ throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed);
+ }
+ if (!_canWrite)
+ {
+ throw new NotSupportedException(SR.NotSupported_Writing);
+ }
+
+ uint sizeOfT = SafeBuffer.SizeOf<T>();
+ if (position > _capacity - sizeOfT)
+ {
+ if (position >= _capacity)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
+ }
+ else
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToWrite, typeof(T)), nameof(position));
+ }
+ }
+
+ _buffer.Write<T>((ulong)(_offset + position), structure);
+ }
+
+ // Writes 'count' structs of type T from 'array' (starting at 'offset') into unmanaged memory.
+ public void WriteArray<T>(long position, T[] array, int offset, int count) where T : struct
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException(nameof(array), SR.ArgumentNull_Buffer);
+ }
+ if (offset < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (array.Length - offset < count)
+ {
+ throw new ArgumentException(SR.Argument_InvalidOffLen);
+ }
+ if (position < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (position >= Capacity)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
+ }
+
+ if (!_isOpen)
+ {
+ throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed);
+ }
+ if (!_canWrite)
+ {
+ throw new NotSupportedException(SR.NotSupported_Writing);
+ }
+
+ _buffer.WriteArray<T>((ulong)(_offset + position), array, offset, count);
+ }
+
+ private void EnsureSafeToRead(long position, int sizeOfType)
+ {
+ if (!_isOpen)
+ {
+ throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed);
+ }
+ if (!_canRead)
+ {
+ throw new NotSupportedException(SR.NotSupported_Reading);
+ }
+ if (position < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (position > _capacity - sizeOfType)
+ {
+ if (position >= _capacity)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
+ }
+ else
+ {
+ throw new ArgumentException(SR.Argument_NotEnoughBytesToRead, nameof(position));
+ }
+ }
+ }
+
+ private void EnsureSafeToWrite(long position, int sizeOfType)
+ {
+ if (!_isOpen)
+ {
+ throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed);
+ }
+ if (!_canWrite)
+ {
+ throw new NotSupportedException(SR.NotSupported_Writing);
+ }
+ if (position < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ if (position > _capacity - sizeOfType)
+ {
+ if (position >= _capacity)
+ {
+ throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
+ }
+ else
+ {
+ throw new ArgumentException(SR.Argument_NotEnoughBytesToWrite, nameof(position));
+ }
+ }
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*============================================================
-**
-**
-**
-**
-** Purpose: Provides a fast, AV free, cross-language way of
-** accessing unmanaged memory in a random fashion.
-**
-**
-===========================================================*/
-
-using System;
-using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.Versioning;
-using Microsoft.Win32.SafeHandles;
-using System.Diagnostics;
-
-namespace System.IO
-{
- /// Perf notes: ReadXXX, WriteXXX (for basic types) acquire and release the
- /// SafeBuffer pointer rather than relying on generic Read(T) from SafeBuffer because
- /// this gives better throughput; benchmarks showed about 12-15% better.
- public class UnmanagedMemoryAccessor : IDisposable
- {
- private SafeBuffer _buffer;
- private Int64 _offset;
- private Int64 _capacity;
- private FileAccess _access;
- private bool _isOpen;
- private bool _canRead;
- private bool _canWrite;
-
- protected UnmanagedMemoryAccessor()
- {
- _isOpen = false;
- }
-
- #region SafeBuffer ctors and initializers
- // <SecurityKernel Critical="True" Ring="1">
- // <ReferencesCritical Name="Method: Initialize(SafeBuffer, Int64, Int64, FileAccess):Void" Ring="1" />
- // </SecurityKernel>
- public UnmanagedMemoryAccessor(SafeBuffer buffer, Int64 offset, Int64 capacity)
- {
- Initialize(buffer, offset, capacity, FileAccess.Read);
- }
-
- public UnmanagedMemoryAccessor(SafeBuffer buffer, Int64 offset, Int64 capacity, FileAccess access)
- {
- Initialize(buffer, offset, capacity, access);
- }
-
- protected void Initialize(SafeBuffer buffer, Int64 offset, Int64 capacity, FileAccess access)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (capacity < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (buffer.ByteLength < (UInt64)(offset + capacity))
- {
- throw new ArgumentException(SR.Argument_OffsetAndCapacityOutOfBounds);
- }
- if (access < FileAccess.Read || access > FileAccess.ReadWrite)
- {
- throw new ArgumentOutOfRangeException(nameof(access));
- }
-
- if (_isOpen)
- {
- throw new InvalidOperationException(SR.InvalidOperation_CalledTwice);
- }
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- buffer.AcquirePointer(ref pointer);
- if (((byte*)((Int64)pointer + offset + capacity)) < pointer)
- {
- throw new ArgumentException(SR.Argument_UnmanagedMemAccessorWrapAround);
- }
- }
- finally
- {
- if (pointer != null)
- {
- buffer.ReleasePointer();
- }
- }
- }
-
- _offset = offset;
- _buffer = buffer;
- _capacity = capacity;
- _access = access;
- _isOpen = true;
- _canRead = (_access & FileAccess.Read) != 0;
- _canWrite = (_access & FileAccess.Write) != 0;
- }
-
- #endregion
-
- public Int64 Capacity
- {
- get
- {
- return _capacity;
- }
- }
-
- public bool CanRead
- {
- get
- {
- return _isOpen && _canRead;
- }
- }
-
- public bool CanWrite
- {
- get
- {
- return _isOpen && _canWrite;
- }
- }
-
- protected virtual void Dispose(bool disposing)
- {
- _isOpen = false;
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected bool IsOpen
- {
- get { return _isOpen; }
- }
-
- public bool ReadBoolean(Int64 position)
- {
- int sizeOfType = sizeof(bool);
- EnsureSafeToRead(position, sizeOfType);
-
- byte b = InternalReadByte(position);
- return b != 0;
- }
-
- public byte ReadByte(Int64 position)
- {
- int sizeOfType = sizeof(byte);
- EnsureSafeToRead(position, sizeOfType);
-
- return InternalReadByte(position);
- }
-
- public char ReadChar(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(char));
-
- char result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<char>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- // See comment above.
- public Int16 ReadInt16(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(Int16));
-
- Int16 result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<Int16>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
-
- public Int32 ReadInt32(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(Int32));
-
- Int32 result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<Int32>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- public Int64 ReadInt64(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(Int64));
-
- Int64 result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<Int64>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- public Decimal ReadDecimal(Int64 position)
- {
- const int ScaleMask = 0x00FF0000;
- const int SignMask = unchecked((int)0x80000000);
-
- EnsureSafeToRead(position, sizeof(Decimal));
-
- int lo, mid, hi, flags;
-
- unsafe
- {
- byte* pointer = null;
- try
- {
- _buffer.AcquirePointer(ref pointer);
-
- lo = Unsafe.ReadUnaligned<Int32>(pointer + _offset + position);
- mid = Unsafe.ReadUnaligned<Int32>(pointer + _offset + position + 4);
- hi = Unsafe.ReadUnaligned<Int32>(pointer + _offset + position + 8);
- flags = Unsafe.ReadUnaligned<Int32>(pointer + _offset + position + 12);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- // Check for invalid Decimal values
- if (!((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16)))
- {
- throw new ArgumentException(SR.Arg_BadDecimal); // Throw same Exception type as Decimal(int[]) ctor for compat
- }
-
- bool isNegative = (flags & SignMask) != 0;
- byte scale = (byte)(flags >> 16);
-
- return new decimal(lo, mid, hi, isNegative, scale);
- }
-
- public Single ReadSingle(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(Single));
-
- Single result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<Single>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- public Double ReadDouble(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(Double));
-
- Double result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<Double>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- [CLSCompliant(false)]
- public SByte ReadSByte(Int64 position)
- {
- int sizeOfType = sizeof(SByte);
- EnsureSafeToRead(position, sizeOfType);
-
- SByte result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = *((SByte*)(pointer + _offset + position));
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- [CLSCompliant(false)]
- public UInt16 ReadUInt16(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(UInt16));
-
- UInt16 result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<UInt16>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- [CLSCompliant(false)]
- public UInt32 ReadUInt32(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(UInt32));
-
- UInt32 result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<UInt32>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- [CLSCompliant(false)]
- public UInt64 ReadUInt64(Int64 position)
- {
- EnsureSafeToRead(position, sizeof(UInt64));
-
- UInt64 result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = Unsafe.ReadUnaligned<UInt64>(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
-
- return result;
- }
-
- // Reads a struct of type T from unmanaged memory, into the reference pointed to by ref value.
- // Note: this method is not safe, since it overwrites the contents of a structure, it can be
- // used to modify the private members of a struct. Furthermore, using this with a struct that
- // contains reference members will most likely cause the runtime to AV. Note, that despite
- // various checks made by the C++ code used by Marshal.PtrToStructure, Marshal.PtrToStructure
- // will still overwrite privates and will also crash the runtime when used with structs
- // containing reference members. For this reason, I am sticking an UnmanagedCode requirement
- // on this method to match Marshal.PtrToStructure.
-
- // Alos note that this method is most performant when used with medium to large sized structs
- // (larger than 8 bytes -- though this is number is JIT and architecture dependent). As
- // such, it is best to use the ReadXXX methods for small standard types such as ints, longs,
- // bools, etc.
-
- public void Read<T>(Int64 position, out T structure) where T : struct
- {
- if (position < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
-
- if (!_isOpen)
- {
- throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed);
- }
- if (!CanRead)
- {
- throw new NotSupportedException(SR.NotSupported_Reading);
- }
-
- UInt32 sizeOfT = Marshal.SizeOfType(typeof(T));
- if (position > _capacity - sizeOfT)
- {
- if (position >= _capacity)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToRead, typeof (T).FullName), nameof(position));
- }
- }
-
- structure = _buffer.Read<T>((UInt64)(_offset + position));
- }
-
- // Reads 'count' structs of type T from unmanaged memory, into 'array' starting at 'offset'.
- // Note: this method is not safe, since it overwrites the contents of structures, it can
- // be used to modify the private members of a struct. Furthermore, using this with a
- // struct that contains reference members will most likely cause the runtime to AV. This
- // is consistent with Marshal.PtrToStructure.
-
- public int ReadArray<T>(Int64 position, T[] array, Int32 offset, Int32 count) where T : struct
- {
- if (array == null)
- {
- throw new ArgumentNullException(nameof(array), "Buffer cannot be null.");
- }
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (array.Length - offset < count)
- {
- throw new ArgumentException(SR.Argument_OffsetAndLengthOutOfBounds);
- }
- if (!CanRead)
- {
- if (!_isOpen)
- {
- throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed);
- }
- else
- {
- throw new NotSupportedException(SR.NotSupported_Reading);
- }
- }
- if (position < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
-
- UInt32 sizeOfT = Marshal.AlignedSizeOf<T>();
-
- // only check position and ask for fewer Ts if count is too big
- if (position >= _capacity)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
- }
-
- int n = count;
- long spaceLeft = _capacity - position;
- if (spaceLeft < 0)
- {
- n = 0;
- }
- else
- {
- ulong spaceNeeded = (ulong)(sizeOfT * count);
- if ((ulong)spaceLeft < spaceNeeded)
- {
- n = (int)(spaceLeft / sizeOfT);
- }
- }
-
- _buffer.ReadArray<T>((UInt64)(_offset + position), array, offset, n);
-
- return n;
- }
-
- // ************** Write Methods ****************/
-
- // The following 13 WriteXXX methods write a value of type XXX into unmanaged memory at 'positon'.
- // The bounds of the unmanaged memory are checked against to ensure that there is enough
- // space after 'position' to write a value of type XXX. XXX can be a bool, byte, char, decimal,
- // double, short, int, long, sbyte, float, ushort, uint, or ulong.
-
-
- public void Write(Int64 position, bool value)
- {
- int sizeOfType = sizeof(bool);
- EnsureSafeToWrite(position, sizeOfType);
-
- byte b = (byte)(value ? 1 : 0);
- InternalWrite(position, b);
- }
-
- public void Write(Int64 position, byte value)
- {
- int sizeOfType = sizeof(byte);
- EnsureSafeToWrite(position, sizeOfType);
-
- InternalWrite(position, value);
- }
-
- public void Write(Int64 position, char value)
- {
- EnsureSafeToWrite(position, sizeof(char));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<char>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
-
- public void Write(Int64 position, Int16 value)
- {
- EnsureSafeToWrite(position, sizeof(Int16));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<Int16>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
-
- public void Write(Int64 position, Int32 value)
- {
- EnsureSafeToWrite(position, sizeof(Int32));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<Int32>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- public void Write(Int64 position, Int64 value)
- {
- EnsureSafeToWrite(position, sizeof(Int64));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<Int64>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- public void Write(Int64 position, Decimal value)
- {
- EnsureSafeToWrite(position, sizeof(Decimal));
-
- unsafe
- {
- int* valuePtr = (int*)(&value);
- int flags = *valuePtr;
- int hi = *(valuePtr + 1);
- int lo = *(valuePtr + 2);
- int mid = *(valuePtr + 3);
-
- byte* pointer = null;
- try
- {
- _buffer.AcquirePointer(ref pointer);
-
- Unsafe.WriteUnaligned<Int32>(pointer + _offset + position, lo);
- Unsafe.WriteUnaligned<Int32>(pointer + _offset + position + 4, mid);
- Unsafe.WriteUnaligned<Int32>(pointer + _offset + position + 8, hi);
- Unsafe.WriteUnaligned<Int32>(pointer + _offset + position + 12, flags);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- public void Write(Int64 position, Single value)
- {
- EnsureSafeToWrite(position, sizeof(Single));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<Single>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- public void Write(Int64 position, Double value)
- {
- EnsureSafeToWrite(position, sizeof(Double));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<Double>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- [CLSCompliant(false)]
- public void Write(Int64 position, SByte value)
- {
- EnsureSafeToWrite(position, sizeof(SByte));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- *((SByte*)(pointer + _offset + position)) = value;
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- [CLSCompliant(false)]
- public void Write(Int64 position, UInt16 value)
- {
- int sizeOfType = sizeof(UInt16);
- EnsureSafeToWrite(position, sizeOfType);
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<UInt16>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- [CLSCompliant(false)]
- public void Write(Int64 position, UInt32 value)
- {
- EnsureSafeToWrite(position, sizeof(UInt32));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<UInt32>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- [CLSCompliant(false)]
- public void Write(Int64 position, UInt64 value)
- {
- EnsureSafeToWrite(position, sizeof(UInt64));
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- Unsafe.WriteUnaligned<UInt64>(pointer + _offset + position, value);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- // Writes the struct pointed to by ref value into unmanaged memory. Note that this method
- // is most performant when used with medium to large sized structs (larger than 8 bytes
- // though this is number is JIT and architecture dependent). As such, it is best to use
- // the WriteX methods for small standard types such as ints, longs, bools, etc.
-
- public void Write<T>(Int64 position, ref T structure) where T : struct
- {
- if (position < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
-
- if (!_isOpen)
- {
- throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed);
- }
- if (!CanWrite)
- {
- throw new NotSupportedException(SR.NotSupported_Writing);
- }
-
- UInt32 sizeOfT = Marshal.SizeOfType(typeof(T));
- if (position > _capacity - sizeOfT)
- {
- if (position >= _capacity)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToWrite, typeof (T).FullName), nameof(position));
- }
- }
-
- _buffer.Write<T>((UInt64)(_offset + position), structure);
- }
-
- // Writes 'count' structs of type T from 'array' (starting at 'offset') into unmanaged memory.
-
-
- public void WriteArray<T>(Int64 position, T[] array, Int32 offset, Int32 count) where T : struct
- {
- if (array == null)
- {
- throw new ArgumentNullException(nameof(array), "Buffer cannot be null.");
- }
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (array.Length - offset < count)
- {
- throw new ArgumentException(SR.Argument_OffsetAndLengthOutOfBounds);
- }
- if (position < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (position >= Capacity)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
- }
-
- if (!_isOpen)
- {
- throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed);
- }
- if (!CanWrite)
- {
- throw new NotSupportedException(SR.NotSupported_Writing);
- }
-
- _buffer.WriteArray<T>((UInt64)(_offset + position), array, offset, count);
- }
-
- private byte InternalReadByte(Int64 position)
- {
- Debug.Assert(CanRead, "UMA not readable");
- Debug.Assert(position >= 0, "position less than 0");
- Debug.Assert(position <= _capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)");
-
- byte result;
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- result = *(pointer + _offset + position);
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- return result;
- }
-
- private void InternalWrite(Int64 position, byte value)
- {
- Debug.Assert(CanWrite, "UMA not writable");
- Debug.Assert(position >= 0, "position less than 0");
- Debug.Assert(position <= _capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)");
-
- unsafe
- {
- byte* pointer = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- _buffer.AcquirePointer(ref pointer);
- *(pointer + _offset + position) = value;
- }
- finally
- {
- if (pointer != null)
- {
- _buffer.ReleasePointer();
- }
- }
- }
- }
-
- private void EnsureSafeToRead(Int64 position, int sizeOfType)
- {
- if (!_isOpen)
- {
- throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed);
- }
- if (!CanRead)
- {
- throw new NotSupportedException(SR.NotSupported_Reading);
- }
- if (position < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (position > _capacity - sizeOfType)
- {
- if (position >= _capacity)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
- }
- else
- {
- throw new ArgumentException(SR.Argument_NotEnoughBytesToRead, nameof(position));
- }
- }
- }
-
- private void EnsureSafeToWrite(Int64 position, int sizeOfType)
- {
- if (!_isOpen)
- {
- throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed);
- }
- if (!CanWrite)
- {
- throw new NotSupportedException(SR.NotSupported_Writing);
- }
- if (position < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
- if (position > _capacity - sizeOfType)
- {
- if (position >= _capacity)
- {
- throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired);
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToWrite, nameof(Byte)), nameof(position));
- }
- }
- }
- }
-}
return SizeOf(typeof(T));
}
- /// <summary>
- /// Returns the aligned size of an instance of a value type.
- /// </summary>
- /// <typeparam name="T">Provide a value type to figure out its size</typeparam>
- /// <returns>The aligned size of T in bytes.</returns>
- internal static uint AlignedSizeOf<T>() where T : struct
- {
- uint size = SizeOfType(typeof(T));
- if (size == 1 || size == 2)
- {
- return size;
- }
- if (IntPtr.Size == 8 && size == 4)
- {
- return size;
- }
- return AlignedSizeOfType(typeof(T));
- }
-
- // Type must be a value type with no object reference fields. We only
- // assert this, due to the lack of a suitable generic constraint.
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern uint SizeOfType(Type type);
-
- // Type must be a value type with no object reference fields. We only
- // assert this, due to the lack of a suitable generic constraint.
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern uint AlignedSizeOfType(Type type);
-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable);
[CLSCompliant(false)]
public void Initialize<T>(uint numElements) where T : struct
{
- Initialize(numElements, Marshal.AlignedSizeOf<T>());
+ Initialize(numElements, AlignedSizeOf<T>());
}
// Callers should ensure that they check whether the pointer ref param
if (_numBytes == Uninitialized)
throw NotInitialized();
- uint sizeofT = Marshal.SizeOfType(typeof(T));
+ uint sizeofT = SizeOf<T>();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, sizeofT);
if (_numBytes == Uninitialized)
throw NotInitialized();
- uint sizeofT = Marshal.SizeOfType(typeof(T));
- uint alignedSizeofT = Marshal.AlignedSizeOf<T>();
+ uint sizeofT = SizeOf<T>();
+ uint alignedSizeofT = AlignedSizeOf<T>();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count)));
if (_numBytes == Uninitialized)
throw NotInitialized();
- uint sizeofT = Marshal.SizeOfType(typeof(T));
+ uint sizeofT = SizeOf<T>();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, sizeofT);
if (_numBytes == Uninitialized)
throw NotInitialized();
- uint sizeofT = Marshal.SizeOfType(typeof(T));
- uint alignedSizeofT = Marshal.AlignedSizeOf<T>();
+ uint sizeofT = SizeOf<T>();
+ uint alignedSizeofT = AlignedSizeOf<T>();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count)));
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void StructureToPtrNative(/*ref T*/ TypedReference structure, byte* ptr, uint sizeofT);
+
+ /// <summary>
+ /// Returns the aligned size of an instance of a value type.
+ /// </summary>
+ /// <typeparam name="T">Provide a value type to figure out its size</typeparam>
+ /// <returns>The aligned size of T in bytes.</returns>
+ internal static uint SizeOf<T>() where T : struct
+ {
+ return SizeOfType(typeof(T));
+ }
+
+ /// <summary>
+ /// Returns the aligned size of an instance of a value type.
+ /// </summary>
+ /// <typeparam name="T">Provide a value type to figure out its size</typeparam>
+ /// <returns>The aligned size of T in bytes.</returns>
+ internal static uint AlignedSizeOf<T>() where T : struct
+ {
+ uint size = SizeOfType(typeof(T));
+ if (size == 1 || size == 2)
+ {
+ return size;
+ }
+ if (IntPtr.Size == 8 && size == 4)
+ {
+ return size;
+ }
+ return AlignedSizeOfType(typeof(T));
+ }
+
+ // Type must be a value type with no object reference fields. We only
+ // assert this, due to the lack of a suitable generic constraint.
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern uint SizeOfType(Type type);
+
+ // Type must be a value type with no object reference fields. We only
+ // assert this, due to the lack of a suitable generic constraint.
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern uint AlignedSizeOfType(Type type);
}
}
FCFuncStart(gSafeBufferFuncs)
FCFuncElement("PtrToStructureNative", SafeBuffer::PtrToStructure)
FCFuncElement("StructureToPtrNative", SafeBuffer::StructureToPtr)
+ FCFuncElement("SizeOfType", SafeBuffer::SizeOfType)
+ FCFuncElement("AlignedSizeOfType", SafeBuffer::AlignedSizeOfType)
FCFuncEnd()
FCFuncStart(gTypedReferenceFuncs)
QCFuncElement("GetHINSTANCE", COMModule::GetHINSTANCE)
FCFuncElement("OffsetOfHelper", MarshalNative::OffsetOfHelper)
- FCFuncElement("SizeOfType", SafeBuffer::SizeOfType)
- FCFuncElement("AlignedSizeOfType", SafeBuffer::AlignedSizeOfType)
QCFuncElement("InternalPrelink", MarshalNative::Prelink)
FCFuncElement("CopyToNative", MarshalNative::CopyToNative)