Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/System.Buffers/ref/System.Buffers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ public abstract class ArrayPool<T>
public abstract T[] Rent(int minimumLength);
public abstract void Return(T[] array, bool clearArray = false);
}
}
}
77 changes: 77 additions & 0 deletions src/System.Memory/ref/System.Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,81 @@ public abstract class OwnedMemory<T> : IDisposable, IRetainable
public abstract void Retain();
protected internal abstract bool TryGetArray(out ArraySegment<T> arraySegment);
}
}

namespace System.Buffers.Binary
{
public static class BinaryPrimitives
{
public static sbyte ReverseEndianness(sbyte value) { throw null; }
public static byte ReverseEndianness(byte value) { throw null; }
public static short ReverseEndianness(short value) { throw null; }
public static ushort ReverseEndianness(ushort value) { throw null; }
public static int ReverseEndianness(int value) { throw null; }
public static uint ReverseEndianness(uint value) { throw null; }
public static long ReverseEndianness(long value) { throw null; }
public static ulong ReverseEndianness(ulong value) { throw null; }

public static T ReadMachineEndian<T>(ReadOnlySpan<byte> buffer) where T : struct { throw null; }
public static bool TryReadMachineEndian<T>(ReadOnlySpan<byte> buffer, out T value) where T : struct { throw null; }

public static short ReadInt16LittleEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static int ReadInt32LittleEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static long ReadInt64LittleEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static ushort ReadUInt16LittleEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static uint ReadUInt32LittleEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static ulong ReadUInt64LittleEndian(ReadOnlySpan<byte> buffer) { throw null; }

public static bool TryReadInt16LittleEndian(ReadOnlySpan<byte> buffer, out short value) { throw null; }
public static bool TryReadInt32LittleEndian(ReadOnlySpan<byte> buffer, out int value) { throw null; }
public static bool TryReadInt64LittleEndian(ReadOnlySpan<byte> buffer, out long value) { throw null; }
public static bool TryReadUInt16LittleEndian(ReadOnlySpan<byte> buffer, out ushort value) { throw null; }
public static bool TryReadUInt32LittleEndian(ReadOnlySpan<byte> buffer, out uint value) { throw null; }
public static bool TryReadUInt64LittleEndian(ReadOnlySpan<byte> buffer, out ulong value) { throw null; }

public static short ReadInt16BigEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static int ReadInt32BigEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static long ReadInt64BigEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static ushort ReadUInt16BigEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static uint ReadUInt32BigEndian(ReadOnlySpan<byte> buffer) { throw null; }
public static ulong ReadUInt64BigEndian(ReadOnlySpan<byte> buffer) { throw null; }

public static bool TryReadInt16BigEndian(ReadOnlySpan<byte> buffer, out short value) { throw null; }
public static bool TryReadInt32BigEndian(ReadOnlySpan<byte> buffer, out int value) { throw null; }
public static bool TryReadInt64BigEndian(ReadOnlySpan<byte> buffer, out long value) { throw null; }
public static bool TryReadUInt16BigEndian(ReadOnlySpan<byte> buffer, out ushort value) { throw null; }
public static bool TryReadUInt32BigEndian(ReadOnlySpan<byte> buffer, out uint value) { throw null; }
public static bool TryReadUInt64BigEndian(ReadOnlySpan<byte> buffer, out ulong value) { throw null; }

public static void WriteMachineEndian<T>(Span<byte> buffer, ref T value) where T : struct { throw null; }
public static bool TryWriteMachineEndian<T>(Span<byte> buffer, ref T value) where T : struct { throw null; }

public static void WriteInt16LittleEndian(Span<byte> buffer, short value) { throw null; }
public static void WriteInt32LittleEndian(Span<byte> buffer, int value) { throw null; }
public static void WriteInt64LittleEndian(Span<byte> buffer, long value) { throw null; }
public static void WriteUInt16LittleEndian(Span<byte> buffer, ushort value) { throw null; }
public static void WriteUInt32LittleEndian(Span<byte> buffer, uint value) { throw null; }
public static void WriteUInt64LittleEndian(Span<byte> buffer, ulong value) { throw null; }

public static bool TryWriteInt16LittleEndian(Span<byte> buffer, short value) { throw null; }
public static bool TryWriteInt32LittleEndian(Span<byte> buffer, int value) { throw null; }
public static bool TryWriteInt64LittleEndian(Span<byte> buffer, long value) { throw null; }
public static bool TryWriteUInt16LittleEndian(Span<byte> buffer, ushort value) { throw null; }
public static bool TryWriteUInt32LittleEndian(Span<byte> buffer, uint value) { throw null; }
public static bool TryWriteUInt64LittleEndian(Span<byte> buffer, ulong value) { throw null; }

public static void WriteInt16BigEndian(Span<byte> buffer, short value) { throw null; }
public static void WriteInt32BigEndian(Span<byte> buffer, int value) { throw null; }
public static void WriteInt64BigEndian(Span<byte> buffer, long value) { throw null; }
public static void WriteUInt16BigEndian(Span<byte> buffer, ushort value) { throw null; }
public static void WriteUInt32BigEndian(Span<byte> buffer, uint value) { throw null; }
public static void WriteUInt64BigEndian(Span<byte> buffer, ulong value) { throw null; }

public static bool TryWriteInt16BigEndian(Span<byte> buffer, short value) { throw null; }
public static bool TryWriteInt32BigEndian(Span<byte> buffer, int value) { throw null; }
public static bool TryWriteInt64BigEndian(Span<byte> buffer, long value) { throw null; }
public static bool TryWriteUInt16BigEndian(Span<byte> buffer, ushort value) { throw null; }
public static bool TryWriteUInt32BigEndian(Span<byte> buffer, uint value) { throw null; }
public static bool TryWriteUInt64BigEndian(Span<byte> buffer, ulong value) { throw null; }
}
}
10 changes: 9 additions & 1 deletion src/System.Memory/src/System.Memory.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<CLSCompliant>false</CLSCompliant>
<DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap'">true</IsPartialFacadeAssembly>
<DefineConstants Condition="'$(IsPartialFacadeAssembly)' == 'true'">$(DefineConstants);IsPartialFacade</DefineConstants>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsPartialFacade doesn't really seem to capture a real condition here. Can we instead switch the define to something that captures the thing you are trying to use? See https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/project-guidelines.md#define-naming-convention for our guidelines.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to resolve this issue in a separate PR given this one is already green. I could keep it the way I had before, which is separate netcoreapp and uap constants and do the 'or' in code.

So, replace #if IsPartialFacade with #if netcoreapp || uap. Does that work?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or give it a FEATURE_NAME name specific to what you are trying to use.

<DefineConstants Condition="'$(TargetGroup)'=='netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
<DefineConstants Condition="'$(TargetGroup)'=='netstandard1.1'">$(DefineConstants);netstandard11</DefineConstants>
</PropertyGroup>
Expand All @@ -24,6 +25,12 @@
<Compile Include="System\SpanExtensions.cs" />
<Compile Include="System\SpanHelpers.T.cs" />
<Compile Include="System\SpanHelpers.byte.cs" />
<Compile Include="System\Buffers\Binary\Reader.cs" />
<Compile Include="System\Buffers\Binary\ReaderBigEndian.cs" />
<Compile Include="System\Buffers\Binary\ReaderLittleEndian.cs" />
<Compile Include="System\Buffers\Binary\Writer.cs" />
<Compile Include="System\Buffers\Binary\WriterBigEndian.cs" />
<Compile Include="System\Buffers\Binary\WriterLittleEndian.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Compile Include="System\ReadOnlySpan.cs" />
Expand All @@ -46,10 +53,11 @@
<Reference Include="System.Reflection" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Condition="'$(TargetGroup)' != 'netstandard1.1'" Include="System.Numerics.Vectors" />
<Reference Condition="'$(TargetGroup)' != 'netstandard1.1'" Include="System.Runtime.CompilerServices.Unsafe" />
<ProjectReference Condition="'$(TargetGroup)' == 'netstandard1.1'" Include="..\..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you have to change from ref to src here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also why do we need this to be a ProjectReference at all? A normal reference should work.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From @safern, #24400 (comment)

That is correct, the only thing that is not correct is that all the ProjectReference that we add in a src project has to be to src projects not reference assembly.
So the reference below has to be a reference to the src project as well.

For netstandard, there is a normal reference.
But for netstandard1.1, we need a project reference since the Unsafe class was added in netstandard1.6.
https://apisof.net/catalog/System.Runtime.CompilerServices.Unsafe
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But for netstandard1.1, we need a project reference since the Unsafe class was added in netstandard1.6.

I'm not sure I understand this. If we are building this library for netstandard1.1 then it cannot depend on a netstanard1.6 library. You might be getting away with this because of the ProjectReference but I still believe this should just be a Reference.

<ProjectReference Condition="'$(TargetGroup)' == 'netstandard1.1'" Include="..\..\System.Runtime.CompilerServices.Unsafe\src\System.Runtime.CompilerServices.Unsafe.ilproj" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<Compile Include="System\SpanExtensions.Fast.cs" />
Expand Down
147 changes: 147 additions & 0 deletions src/System.Memory/src/System/Buffers/Binary/Reader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// 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.

using System.Runtime;
using System.Runtime.CompilerServices;

namespace System.Buffers.Binary
{
/// <summary>
/// Reads bytes as primitives with specific endianness
/// </summary>
/// <remarks>
/// For native formats, SpanExtensions.Read&lt;T&gt; should be used.
/// Use these helpers when you need to read specific endinanness.
/// </remarks>
public static partial class BinaryPrimitives
{
/// <summary>
/// This is a no-op and added only for consistency.
/// This allows the caller to read a struct of numeric primitives and reverse each field
/// rather than having to skip sbyte fields.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static sbyte ReverseEndianness(sbyte value)
{
return value;
}

/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static short ReverseEndianness(short value)
{
return (short)((value & 0x00FF) << 8 | (value & 0xFF00) >> 8);
}

/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReverseEndianness(int value) => (int)ReverseEndianness((uint)value);

/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long ReverseEndianness(long value) => (long)ReverseEndianness((ulong)value);

/// <summary>
/// This is a no-op and added only for consistency.
/// This allows the caller to read a struct of numeric primitives and reverse each field
/// rather than having to skip byte fields.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte ReverseEndianness(byte value)
{
return value;
}

/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ReverseEndianness(ushort value)
{
return (ushort)((value & 0x00FFU) << 8 | (value & 0xFF00U) >> 8);
}

/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ReverseEndianness(uint value)
{
value = (value << 16) | (value >> 16);
value = (value & 0x00FF00FF) << 8 | (value & 0xFF00FF00) >> 8;
return value;
}

/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong ReverseEndianness(ulong value)
{
value = (value << 32) | (value >> 32);
value = (value & 0x0000FFFF0000FFFF) << 16 | (value & 0xFFFF0000FFFF0000) >> 16;
value = (value & 0x00FF00FF00FF00FF) << 8 | (value & 0xFF00FF00FF00FF00) >> 8;
return value;
}

/// <summary>
/// Reads a structure of type T out of a read-only span of bytes.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T ReadMachineEndian<T>(ReadOnlySpan<byte> buffer)
where T : struct
{
#if IsPartialFacade
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should always call SpanHelpers and have the #ifdef only in the one place which is in SpanHelpers.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would still end up with the #ifdef for the ThrowHelper so it won't reduce the number of places we have to ifdef. I am not certain how to work around it (there is already an internal ThrowHelper class in mscorlib).

Copy link
Member

@weshaggard weshaggard Oct 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't the ThrowHelper call also be in the SpanHelper #ifdef?

if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
throw new ArgumentException(SR.Format(SR.Argument_InvalidTypeWithPointersNotSupported, typeof(T)));
}
#else
if (SpanHelpers.IsReferenceOrContainsReferences<T>())
{
ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
}
#endif
if (Unsafe.SizeOf<T>() > buffer.Length)
{
throw new ArgumentOutOfRangeException();
}
return Unsafe.ReadUnaligned<T>(ref buffer.DangerousGetPinnableReference());
}

/// <summary>
/// Reads a structure of type T out of a span of bytes.
/// <returns>If the span is too small to contain the type T, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadMachineEndian<T>(ReadOnlySpan<byte> buffer, out T value)
where T : struct
{
#if IsPartialFacade
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
throw new ArgumentException(SR.Format(SR.Argument_InvalidTypeWithPointersNotSupported, typeof(T)));
}
#else
if (SpanHelpers.IsReferenceOrContainsReferences<T>())
{
ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
}
#endif
if (Unsafe.SizeOf<T>() > (uint)buffer.Length)
{
value = default;
return false;
}
value = Unsafe.ReadUnaligned<T>(ref buffer.DangerousGetPinnableReference());
return true;
}
}
}
Loading