Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand string and span extension methods #10629

Merged
merged 5 commits into from
Jul 17, 2024
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
@@ -1,13 +1,188 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;

#if !NET
using ThrowHelper = Microsoft.AspNetCore.Razor.Utilities.ThrowHelper;
#endif

namespace Microsoft.AspNetCore.Razor;

internal static class ArrayExtensions
{
/// <summary>
/// Creates a new span over the portion of the target array defined by an <see cref="Index"/> value.
/// </summary>
/// <param name="array">
/// The array to convert.
/// </param>
/// <param name="startIndex">
/// The starting index.
/// </param>
/// <remarks>
/// This uses Razor's <see cref="Index"/> type, which is type-forwarded on .NET.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="startIndex"/> is less than 0 or greater than <paramref name="array"/>.Length.
/// </exception>
/// <exception cref="ArrayTypeMismatchException">
/// <paramref name="array"/> is covariant, and the array's type is not exactly <typeparamref name="T"/>[].
/// </exception>
public static ReadOnlySpan<T> AsSpan<T>(this T[]? array, Index startIndex)
{
#if NET
return MemoryExtensions.AsSpan(array, startIndex);
#else
if (array is null)
{
if (!startIndex.Equals(Index.Start))
{
ThrowHelper.ThrowArgumentOutOfRange(nameof(startIndex));
}

return default;
}

return MemoryExtensions.AsSpan(array, startIndex.GetOffset(array.Length));
#endif
}

/// <summary>
/// Creates a new span over the portion of the target array defined by a <see cref="Range"/> value.
/// </summary>
/// <param name="array">
/// The array to convert.
/// </param>
/// <param name="range">
/// The range of the array to convert.
/// </param>
/// <remarks>
/// This uses Razor's <see cref="Range"/> type, which is type-forwarded on .NET.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="range"/>'s start or end index is not within the bounds of the string.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="range"/>'s start index is greater than its end index.
/// </exception>
/// <exception cref="ArrayTypeMismatchException">
/// <paramref name="array"/> is covariant, and the array's type is not exactly <typeparamref name="T"/>[].
/// </exception>
public static ReadOnlySpan<T> AsSpan<T>(this T[]? array, Range range)
{
#if NET
return MemoryExtensions.AsSpan(array, range);
#else
if (array is null)
{
if (!range.Start.Equals(Index.Start) || !range.End.Equals(Index.Start))
{
ThrowHelper.ThrowArgumentNull(nameof(array));
}

return default;
}

var (start, length) = range.GetOffsetAndLength(array.Length);
return MemoryExtensions.AsSpan(array, start, length);
#endif
}

/// <summary>
/// Creates a new memory region over the portion of the target starting at the specified index
/// to the end of the array.
/// </summary>
/// <param name="array">
/// The array to convert.
/// </param>
/// <param name="startIndex">
/// The first position of the array.
/// </param>
/// <remarks>
/// This uses Razor's <see cref="Index"/> type, which is type-forwarded on .NET.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="startIndex"/> is less than 0 or greater than <paramref name="array"/>.Length.
/// </exception>
/// <exception cref="ArrayTypeMismatchException">
/// <paramref name="array"/> is covariant, and the array's type is not exactly <typeparamref name="T"/>[].
/// </exception>
public static ReadOnlyMemory<T> AsMemory<T>(this T[]? array, Index startIndex)
{
#if NET
return MemoryExtensions.AsMemory(array, startIndex);
#else
if (array is null)
{
if (!startIndex.Equals(Index.Start))
{
ThrowHelper.ThrowArgumentOutOfRange(nameof(startIndex));
}

return default;
}

return MemoryExtensions.AsMemory(array, startIndex.GetOffset(array.Length));
#endif
}

/// <summary>
/// Creates a new memory region over the portion of the target array beginning at
/// inclusive start index of the range and ending at the exclusive end index of the range.
/// </summary>
/// <param name="array">
/// The array to convert.
/// </param>
/// <param name="range">
/// The range of the array to convert.
/// </param>
/// <remarks>
/// This uses Razor's <see cref="Range"/> type, which is type-forwarded on .NET.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="range"/>'s start or end index is not within the bounds of the string.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="range"/>'s start index is greater than its end index.
/// </exception>
/// <exception cref="ArrayTypeMismatchException">
/// <paramref name="array"/> is covariant, and the array's type is not exactly <typeparamref name="T"/>[].
/// </exception>
public static ReadOnlyMemory<T> AsMemory<T>(this T[]? array, Range range)
{
#if NET
return MemoryExtensions.AsMemory(array, range);
#else
if (array is null)
{
if (!range.Start.Equals(Index.Start) || !range.End.Equals(Index.Start))
{
ThrowHelper.ThrowArgumentNull(nameof(array));
}

return default;
}

var (start, length) = range.GetOffsetAndLength(array.Length);
return MemoryExtensions.AsMemory(array, start, length);
#endif
}

public static ImmutableDictionary<TKey, TValue> ToImmutableDictionary<TKey, TValue>(
this (TKey key, TValue value)[] array, IEqualityComparer<TKey> keyComparer)
where TKey : notnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,39 +29,6 @@ public static void SetCapacityIfLarger<T>(this ImmutableArray<T>.Builder builder
}
}

/// <summary>
/// Returns the current contents as an <see cref="ImmutableArray{T}"/> and sets
/// the collection to a zero length array.
/// </summary>
/// <remarks>
/// If <see cref="ImmutableArray{T}.Builder.Capacity"/> equals
/// <see cref="ImmutableArray{T}.Builder.Count"/>, the internal array will be extracted
/// as an <see cref="ImmutableArray{T}"/> without copying the contents. Otherwise, the
/// contents will be copied into a new array. The collection will then be set to a
/// zero-length array.
/// </remarks>
/// <returns>An immutable array.</returns>
public static ImmutableArray<T> DrainToImmutable<T>(this ImmutableArray<T>.Builder builder)
{
#if NET8_0_OR_GREATER
return builder.DrainToImmutable();
#else
if (builder.Count == 0)
{
return [];
}

if (builder.Count == builder.Capacity)
{
return builder.MoveToImmutable();
}

var result = builder.ToImmutable();
builder.Clear();
return result;
#endif
}

public static ImmutableArray<TResult> SelectAsArray<T, TResult>(this ImmutableArray<T> source, Func<T, TResult> selector)
{
return source switch
Expand Down
Loading