Skip to content
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
13 changes: 13 additions & 0 deletions src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

namespace System;

/// <summary>Provides downlevel polyfills for static methods on <see cref="BitConverter"/>.</summary>
Expand All @@ -23,5 +25,16 @@ public static ulong DoubleToUInt64Bits(double value)
return *(ulong*)&value;
}
}

// ---- ReadOnlySpan<byte> read overloads (host-endian, semantics match BCL net5+) ----

public static short ToInt16(ReadOnlySpan<byte> value) => MemoryMarshal.Read<short>(value);
public static ushort ToUInt16(ReadOnlySpan<byte> value) => MemoryMarshal.Read<ushort>(value);
public static int ToInt32(ReadOnlySpan<byte> value) => MemoryMarshal.Read<int>(value);
public static uint ToUInt32(ReadOnlySpan<byte> value) => MemoryMarshal.Read<uint>(value);
public static long ToInt64(ReadOnlySpan<byte> value) => MemoryMarshal.Read<long>(value);
public static ulong ToUInt64(ReadOnlySpan<byte> value) => MemoryMarshal.Read<ulong>(value);
public static float ToSingle(ReadOnlySpan<byte> value) => MemoryMarshal.Read<float>(value);
public static double ToDouble(ReadOnlySpan<byte> value) => MemoryMarshal.Read<double>(value);
Comment thread
EgorBo marked this conversation as resolved.
}
}
2 changes: 1 addition & 1 deletion src/libraries/Common/src/Polyfills/HashCodePolyfills.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static void AddBytes(this ref HashCode hashCode, ReadOnlySpan<byte> value
{
while (value.Length >= sizeof(int))
{
hashCode.Add(MemoryMarshal.Read<int>(value));
hashCode.Add(BitConverter.ToInt32(value));
value = value.Slice(sizeof(int));
Comment thread
EgorBo marked this conversation as resolved.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1087,8 +1087,8 @@ public unsafe string[] GetValueNames()
case Interop.Advapi32.RegistryValues.REG_QWORD:
return dataLength switch
{
4 => MemoryMarshal.Read<int>(span),
8 => MemoryMarshal.Read<long>(span),
4 => BitConverter.ToInt32(span),
8 => BitConverter.ToInt64(span),
_ => span.Slice(0, dataLength).ToArray(), // This shouldn't happen, but the previous implementation included it defensively.
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ System.Diagnostics.PerformanceCounter</PackageDescription>
Link="Common\DisableRuntimeMarshalling.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp' and '$(TargetPlatformIdentifier)' == 'windows'">
<Compile Include="$(CommonPath)Polyfills\BitConverterPolyfills.cs" Link="Common\Polyfills\BitConverterPolyfills.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<ProjectReference Include="$(LibrariesProjectRoot)System.Configuration.ConfigurationManager\src\System.Configuration.ConfigurationManager.csproj" />
<ProjectReference Condition="$([MSBuild]::VersionLessThan('$(TargetFrameworkVersion)', '10.0'))" Include="$(LibrariesProjectRoot)System.Threading.AccessControl\src\System.Threading.AccessControl.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1713,11 +1713,11 @@ private long ReadValue(ReadOnlySpan<byte> data)
{
if (_size == 4)
{
return (long)MemoryMarshal.Read<uint>(data.Slice(_offset));
return (long)BitConverter.ToUInt32(data.Slice(_offset));
}
else if (_size == 8)
{
return MemoryMarshal.Read<long>(data.Slice(_offset));
return BitConverter.ToInt64(data.Slice(_offset));
}

return -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,9 @@ private static ValueId GetValueId(string counterName)
private static long ReadCounterValue(int counterType, ReadOnlySpan<byte> data)
{
if ((counterType & PerfCounterOptions.NtPerfCounterSizeLarge) != 0)
return MemoryMarshal.Read<long>(data);
return BitConverter.ToInt64(data);
else
return MemoryMarshal.Read<int>(data);
return BitConverter.ToInt32(data);
}

private enum ValueId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ System.Formats.Cbor.CborWriter</PackageDescription>
<Compile Include="System\Formats\Cbor\Writer\CborWriter.Simple.netstandard.cs" />
<Compile Include="$(CommonPath)Polyfills\DateTimeOffsetPolyfills.cs" Link="Common\Polyfills\DateTimeOffsetPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\HashCodePolyfills.cs" Link="Common\Polyfills\HashCodePolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\BitConverterPolyfills.cs" Link="Common\Polyfills\BitConverterPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\ArrayPolyfills.cs" Link="Common\Polyfills\ArrayPolyfills.cs" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,71 +91,27 @@ public static string BuildStringFromIndefiniteLengthTextString<TState>(int lengt

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ReadHalfBigEndian(ReadOnlySpan<byte> source)
{
ushort value = BitConverter.IsLittleEndian ?
BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read<ushort>(source)) :
MemoryMarshal.Read<ushort>(source);

return value;
}
=> BinaryPrimitives.ReadUInt16BigEndian(source);
Comment thread
MihaZupan marked this conversation as resolved.

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteHalfBigEndian(Span<byte> destination, ushort value)
{
if (BitConverter.IsLittleEndian)
{
ushort tmp = BinaryPrimitives.ReverseEndianness(value);
MemoryMarshal.Write(destination, ref tmp);
}
else
{
MemoryMarshal.Write(destination, ref value);
}
}
=> BinaryPrimitives.WriteUInt16BigEndian(destination, value);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ReadSingleBigEndian(ReadOnlySpan<byte> source)
{
return BitConverter.IsLittleEndian ?
Int32BitsToSingle(BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read<int>(source))) :
MemoryMarshal.Read<float>(source);
}
=> Int32BitsToSingle(BinaryPrimitives.ReadInt32BigEndian(source));

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteSingleBigEndian(Span<byte> destination, float value)
{
if (BitConverter.IsLittleEndian)
{
int tmp = BinaryPrimitives.ReverseEndianness(SingleToInt32Bits(value));
MemoryMarshal.Write(destination, ref tmp);
}
else
{
MemoryMarshal.Write(destination, ref value);
}
}
=> BinaryPrimitives.WriteInt32BigEndian(destination, SingleToInt32Bits(value));

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double ReadDoubleBigEndian(ReadOnlySpan<byte> source)
{
return BitConverter.IsLittleEndian ?
BitConverter.Int64BitsToDouble(BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read<long>(source))) :
MemoryMarshal.Read<double>(source);
}
=> BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64BigEndian(source));

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteDoubleBigEndian(Span<byte> destination, double value)
{
if (BitConverter.IsLittleEndian)
{
long tmp = BinaryPrimitives.ReverseEndianness(BitConverter.DoubleToInt64Bits(value));
MemoryMarshal.Write(destination, ref tmp);
}
else
{
MemoryMarshal.Write(destination, ref value);
}
}
=> BinaryPrimitives.WriteInt64BigEndian(destination, BitConverter.DoubleToInt64Bits(value));

internal static uint SingleToUInt32Bits(float value)
=> (uint)SingleToInt32Bits(value);
Expand Down
10 changes: 5 additions & 5 deletions src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public IPAddress(ReadOnlySpan<byte> address)
{
if (address.Length == IPAddressParserStatics.IPv4AddressBytes)
{
PrivateAddress = MemoryMarshal.Read<uint>(address);
PrivateAddress = BitConverter.ToUInt32(address);
}
else if (address.Length == IPAddressParserStatics.IPv6AddressBytes)
{
Expand Down Expand Up @@ -721,10 +721,10 @@ public override int GetHashCode()
{
ReadOnlySpan<byte> numbers = MemoryMarshal.AsBytes<ushort>(_numbers).Slice(0, 16);
_hashCode = HashCode.Combine(
MemoryMarshal.Read<uint>(numbers),
MemoryMarshal.Read<uint>(numbers.Slice(4)),
MemoryMarshal.Read<uint>(numbers.Slice(8)),
MemoryMarshal.Read<uint>(numbers.Slice(12)),
BitConverter.ToUInt32(numbers),
BitConverter.ToUInt32(numbers.Slice(4)),
BitConverter.ToUInt32(numbers.Slice(8)),
BitConverter.ToUInt32(numbers.Slice(12)),
_addressOrScopeId);
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ public string[] GetValueNames()
case Interop.Advapi32.RegistryValues.REG_QWORD:
return dataLength switch
{
4 => MemoryMarshal.Read<int>(span),
8 => MemoryMarshal.Read<long>(span),
4 => BitConverter.ToInt32(span),
8 => BitConverter.ToInt64(span),
_ => span.Slice(0, dataLength).ToArray(), // This shouldn't happen, but the previous implementation included it defensively.
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ internal static object[] DecodePayload(ref EventSource.EventMetadata metadata, R
}
else if (parameterType == typeof(byte) || enumType == typeof(byte))
{
decodedFields[i] = MemoryMarshal.Read<byte>(payload);
decodedFields[i] = payload[0];
payload = payload.Slice(sizeof(byte));
}
else if (parameterType == typeof(sbyte) || enumType == typeof(sbyte))
{
decodedFields[i] = MemoryMarshal.Read<sbyte>(payload);
decodedFields[i] = (sbyte)payload[0];
payload = payload.Slice(sizeof(sbyte));
}
else if (parameterType == typeof(short) || enumType == typeof(short))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<PackageReference Include="Microsoft.Bcl.HashCode" Version="$(MicrosoftBclHashCodeVersion)" />
<Compile Include="$(CommonPath)Polyfills\HashCodePolyfills.cs" Link="Common\Polyfills\HashCodePolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\BitConverterPolyfills.cs" Link="Common\Polyfills\BitConverterPolyfills.cs" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0'))">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ public static CspParameters GetProvParameters(this SafeProvOrNCryptKeyHandle han
throw new CryptographicException();
}

int provType = MemoryMarshal.Read<int>(stackSpan.Slice(0, size));
int provType = BitConverter.ToInt32(stackSpan.Slice(0, size));

size = stackSpan.Length;
if (!Interop.Advapi32.CryptGetProvParam(handle, CryptProvParam.PP_KEYSET_TYPE, stackSpan, ref size))
Expand All @@ -399,7 +399,7 @@ public static CspParameters GetProvParameters(this SafeProvOrNCryptKeyHandle han
throw new CryptographicException();
}

int keysetType = MemoryMarshal.Read<int>(stackSpan.Slice(0, size));
int keysetType = BitConverter.ToInt32(stackSpan.Slice(0, size));

// Only CRYPT_MACHINE_KEYSET is described as coming back, but be defensive.
CspProviderFlags provFlags =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,10 @@ System.Security.Cryptography.Pkcs.EnvelopedCms</PackageDescription>
<PackageReference Include="System.Memory" Version="$(SystemMemoryVersion)" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp' and '$(TargetPlatformIdentifier)' == 'windows'">
<Compile Include="$(CommonPath)Polyfills\BitConverterPolyfills.cs" Link="Common\Polyfills\BitConverterPolyfills.cs" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\ExperimentalAttribute.cs" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ private static string GetCrlFileName(SafeX509Handle cert, string crlUrl)
throw new CryptographicException();
}

uint urlHash = MemoryMarshal.Read<uint>(hash);
uint urlHash = BitConverter.ToUInt32(hash);

// OpenSSL's hashed filename algorithm is the 8-character hex version of the 32-bit value
// of X509_issuer_name_hash (or X509_subject_name_hash, depending on the context).
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/src/System.Text.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET
<Compile Include="$(CommonPath)Polyfills\DoublePolyfills.cs" Link="Common\Polyfills\DoublePolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\SinglePolyfills.cs" Link="Common\Polyfills\SinglePolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\BitArrayPolyfills.cs" Link="Common\Polyfills\BitArrayPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\BitConverterPolyfills.cs" Link="Common\Polyfills\BitConverterPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\ArrayPolyfills.cs" Link="Common\Polyfills\ArrayPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\RuntimeHelpersPolyfills.cs" Link="Common\Polyfills\RuntimeHelpersPolyfills.cs" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ public static ulong GetKey(ReadOnlySpan<byte> name)
{
0 => 0,
1 => name[0],
2 => MemoryMarshal.Read<ushort>(name),
3 => MemoryMarshal.Read<ushort>(name) | ((ulong)name[2] << 16),
4 => MemoryMarshal.Read<uint>(name),
5 => MemoryMarshal.Read<uint>(name) | ((ulong)name[4] << 32),
6 => MemoryMarshal.Read<uint>(name) | ((ulong)MemoryMarshal.Read<ushort>(name.Slice(4, 2)) << 32),
7 => MemoryMarshal.Read<uint>(name) | ((ulong)MemoryMarshal.Read<ushort>(name.Slice(4, 2)) << 32) | ((ulong)name[6] << 48),
_ => MemoryMarshal.Read<ulong>(name) & 0x00ffffffffffffffUL
2 => BitConverter.ToUInt16(name),
3 => BitConverter.ToUInt16(name) | ((ulong)name[2] << 16),
4 => BitConverter.ToUInt32(name),
5 => BitConverter.ToUInt32(name) | ((ulong)name[4] << 32),
6 => BitConverter.ToUInt32(name) | ((ulong)BitConverter.ToUInt16(name.Slice(4, 2)) << 32),
7 => BitConverter.ToUInt32(name) | ((ulong)BitConverter.ToUInt16(name.Slice(4, 2)) << 32) | ((ulong)name[6] << 48),
_ => BitConverter.ToUInt64(name) & 0x00ffffffffffffffUL
};
#if DEBUG
// Verify key contains the embedded bytes as expected.
Expand Down
Loading