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
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

#if NETFRAMEWORK || NETSTANDARD2_0
using System.Runtime.Serialization;
#else
using System.Runtime.CompilerServices;
#endif

namespace Microsoft.Extensions.Internal
{
Expand Down Expand Up @@ -40,11 +35,7 @@ public static bool TryGetDefaultValue(ParameterInfo parameter, out object? defau
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern",
Justification = "CreateValueType is only called on a ValueType. You can always create an instance of a ValueType.")]
static object? CreateValueType(Type t) =>
#if NETFRAMEWORK || NETSTANDARD2_0
FormatterServices.GetUninitializedObject(t);
#else
RuntimeHelpers.GetUninitializedObject(t);
#endif

// Handle nullable enums
if (defaultValue != null && isNullableParameterType)
Expand Down
34 changes: 34 additions & 0 deletions src/libraries/Common/src/Polyfills/ArrayPolyfills.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,40 @@ internal static class ArrayPolyfills
{
public static int MaxLength => 0x7FFFFFC7;

public static void Reverse<T>(T[] array, int index, int length)
{
if (array is null)
{
throw new ArgumentNullException(nameof(array));
}

if (index < 0)
{
throw new ArgumentOutOfRangeException(nameof(index));
}

if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length));
}

if (array.Length - index < length)
{
throw new ArgumentException();
}

int i = index;
int j = index + length - 1;
while (i < j)
{
T temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
}

public static void Clear(Array array)
{
if (array is null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Buffers.Binary;

/// <summary>Provides downlevel polyfills for reversing the endianness of spans.</summary>
internal static partial class BinaryPrimitivesPolyfills
{
extension(BinaryPrimitives)
{
public static void ReverseEndianness(ReadOnlySpan<short> source, Span<short> destination)
{
source.CopyTo(destination);
for (int i = 0; i < source.Length; i++)
{
destination[i] = BinaryPrimitives.ReverseEndianness(destination[i]);
}
}

public static void ReverseEndianness(ReadOnlySpan<int> source, Span<int> destination)
{
source.CopyTo(destination);
for (int i = 0; i < source.Length; i++)
{
destination[i] = BinaryPrimitives.ReverseEndianness(destination[i]);
}
}

public static void ReverseEndianness(ReadOnlySpan<long> source, Span<long> destination)
{
source.CopyTo(destination);
for (int i = 0; i < source.Length; i++)
{
destination[i] = BinaryPrimitives.ReverseEndianness(destination[i]);
}
}
}
}
29 changes: 29 additions & 0 deletions src/libraries/Common/src/Polyfills/BinaryPrimitivesPolyfills.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Buffers.Binary;

/// <summary>Provides downlevel polyfills for static methods on <see cref="BinaryPrimitives"/>.</summary>
internal static partial class BinaryPrimitivesPolyfills
{
extension(BinaryPrimitives)
{
public static float ReadSingleBigEndian(ReadOnlySpan<byte> source) =>
BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32BigEndian(source));

public static double ReadDoubleBigEndian(ReadOnlySpan<byte> source) =>
BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64BigEndian(source));

public static void WriteSingleBigEndian(Span<byte> destination, float value) =>
BinaryPrimitives.WriteInt32BigEndian(destination, BitConverter.SingleToInt32Bits(value));

public static void WriteDoubleBigEndian(Span<byte> destination, double value) =>
BinaryPrimitives.WriteInt64BigEndian(destination, BitConverter.DoubleToInt64Bits(value));

public static void WriteSingleLittleEndian(Span<byte> destination, float value) =>
BinaryPrimitives.WriteInt32LittleEndian(destination, BitConverter.SingleToInt32Bits(value));

public static void WriteDoubleLittleEndian(Span<byte> destination, double value) =>
BinaryPrimitives.WriteInt64LittleEndian(destination, BitConverter.DoubleToInt64Bits(value));
}
}
6 changes: 6 additions & 0 deletions src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ internal static class BitConverterPolyfills
{
extension(BitConverter)
{
public static unsafe int SingleToInt32Bits(float value) => *(int*)&value;

public static unsafe float Int32BitsToSingle(int value) => *(float*)&value;

public static float UInt32BitsToSingle(uint value) => BitConverter.Int32BitsToSingle((int)value);

public static uint SingleToUInt32Bits(float value)
{
unsafe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@

namespace System;

/// <summary>Provides downlevel polyfills for instance members on <see cref="DateTimeOffset"/>.</summary>
/// <summary>Provides downlevel polyfills for members on <see cref="DateTimeOffset"/>.</summary>
internal static class DateTimeOffsetPolyfills
{
private static readonly DateTimeOffset s_unixEpoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
Comment thread
eiriktsarpalis marked this conversation as resolved.

extension(DateTimeOffset value)
{
public static DateTimeOffset UnixEpoch => s_unixEpoch;

public int TotalOffsetMinutes =>
(int)(value.Offset.Ticks / TimeSpan.TicksPerMinute);
}
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/Common/src/Polyfills/EnumPolyfills.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ internal static class EnumPolyfills
{
extension(Enum)
{
public static string[] GetNames<TEnum>() where TEnum : struct, Enum =>
Enum.GetNames(typeof(TEnum));

public static TEnum[] GetValues<TEnum>() where TEnum : struct, Enum =>
(TEnum[])Enum.GetValues(typeof(TEnum));

public static TEnum Parse<TEnum>(string value, bool ignoreCase) where TEnum : struct, Enum =>
(TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
}
Expand Down
27 changes: 27 additions & 0 deletions src/libraries/Common/src/Polyfills/MathPolyfills.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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.CompilerServices;

namespace System;

/// <summary>Provides downlevel polyfills for static methods on <see cref="Math"/>.</summary>
internal static class MathPolyfills
{
extension(Math)
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong BigMul(ulong a, ulong b, out ulong low)
{
ulong lowerLow = (ulong)(uint)a * (uint)b;
ulong higherLow = (ulong)(uint)(a >> 32) * (uint)b;
ulong lowerHigh = (ulong)(uint)a * (uint)(b >> 32);
ulong higherHigh = (ulong)(uint)(a >> 32) * (uint)(b >> 32);

ulong cross = (lowerLow >> 32) + (higherLow & uint.MaxValue) + lowerHigh;
ulong upper = (higherLow >> 32) + (cross >> 32) + higherHigh;
low = (cross << 32) | (lowerLow & uint.MaxValue);
return upper;
}
}
}
26 changes: 26 additions & 0 deletions src/libraries/Common/src/Polyfills/MemoryExtensionsPolyfills.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ public static bool ContainsAnyExcept<T>(this ReadOnlySpan<T> span, T value) wher
public static bool ContainsAny(this ReadOnlySpan<char> span, ReadOnlySpan<char> values) =>
span.IndexOfAny(values) >= 0;

public static int IndexOfAnyExcept(this ReadOnlySpan<byte> span, byte value)
{
for (int i = 0; i < span.Length; i++)
{
if (span[i] != value)
{
return i;
}
}

return -1;
}

public static int LastIndexOfAnyExcept(this ReadOnlySpan<byte> span, byte value)
{
for (int i = span.Length - 1; i >= 0; i--)
{
if (span[i] != value)
{
return i;
}
}

return -1;
}

public static int Count<T>(this ReadOnlySpan<T> span, T value) where T : IEquatable<T>
{
int count = 0;
Expand Down
22 changes: 22 additions & 0 deletions src/libraries/Common/src/Polyfills/OperatingSystemPolyfills.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if !NETFRAMEWORK
using System.Runtime.InteropServices;
#endif

namespace System;

/// <summary>Provides downlevel polyfills for static methods on <see cref="OperatingSystem"/>.</summary>
internal static class OperatingSystemPolyfills
{
extension(OperatingSystem)
{
public static bool IsWindows() =>
#if NETFRAMEWORK
Environment.OSVersion.Platform == PlatformID.Win32NT;
#else
RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#endif
}
}
13 changes: 13 additions & 0 deletions src/libraries/Common/src/Polyfills/ReadOnlySequencePolyfills.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Buffers;

/// <summary>Provides downlevel polyfills for instance members on <see cref="ReadOnlySequence{T}"/>.</summary>
internal static class ReadOnlySequencePolyfills
{
extension<T>(ReadOnlySequence<T> sequence)
{
public ReadOnlySpan<T> FirstSpan => sequence.First.Span;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace System.Runtime.CompilerServices;
Expand All @@ -24,7 +25,8 @@ public static bool TryEnsureSufficientExecutionStack()
}
}

public static object GetUninitializedObject(Type type)
public static object GetUninitializedObject(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type)
{
#pragma warning disable SYSLIB0050 // FormatterServices.GetUninitializedObject is obsolete
return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
Expand Down
28 changes: 28 additions & 0 deletions src/libraries/Common/src/Polyfills/StringPolyfills.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;

namespace System;

/// <summary>Provides a downlevel polyfill for creating strings with a span callback.</summary>
internal static partial class StringPolyfills
{
extension(string)
{
public static string Create<TState>(int length, TState state, SpanAction<char, TState> action)
{
ArgumentNullException.ThrowIfNull(action);
ArgumentOutOfRangeException.ThrowIfNegative(length);

if (length == 0)
{
return string.Empty;
}

char[] chars = new char[length];
action(chars, state);
return new string(chars);
}
}
}
34 changes: 34 additions & 0 deletions src/libraries/Common/src/Polyfills/TypePolyfills.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;

/// <summary>Provides downlevel polyfills for instance members on <see cref="Type"/>.</summary>
internal static class TypePolyfills
{
extension(Type type)
{
public bool IsByRefLike
{
get
{
if (!type.IsValueType)
{
return false;
}

object[] attributes = type.GetCustomAttributes(inherit: false);

for (int i = 0; i < attributes.Length; i++)
{
if (attributes[i].GetType().FullName == "System.Runtime.CompilerServices.IsByRefLikeAttribute")
{
return true;
}
}

return false;
}
}
}
}
23 changes: 23 additions & 0 deletions src/libraries/Common/src/Polyfills/UInt64Polyfills.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;

/// <summary>Provides downlevel polyfills for static methods on <see cref="ulong"/>.</summary>
internal static class UInt64Polyfills
{
extension(ulong)
{
public static ulong PopCount(ulong value)
{
ulong count = 0;
while (value != 0)
{
value &= value - 1;
count++;
}

return count;
}
}
}
6 changes: 6 additions & 0 deletions src/libraries/Common/src/System/Buffers/SpanAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Buffers;

internal delegate void SpanAction<T, in TArg>(Span<T> span, TArg arg);
Loading
Loading