mirror of
https://github.com/aphrody-labs/NuGet.Client.git
synced 2026-10-14 13:29:05 +00:00
184 lines
5.6 KiB
C#
184 lines
5.6 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
#nullable enable
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace NuGet.Shared
|
|
{
|
|
internal static class Extensions
|
|
{
|
|
/// <summary>
|
|
/// Return the enumerable as a List of T, copying if required. Optimized for common case where it is an List of T.
|
|
/// Avoid mutating the return value.
|
|
/// </summary>
|
|
/// <remarks>https://aspnetwebstack.codeplex.com/SourceControl/latest#src/Common/CollectionExtensions.cs</remarks>
|
|
public static List<T> AsList<T>(this IEnumerable<T> enumerable)
|
|
{
|
|
var list = enumerable as List<T>;
|
|
if (list != null)
|
|
{
|
|
return list;
|
|
}
|
|
|
|
return new List<T>(enumerable);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the ISet as a HashSet of T, copying if required. Optimized for common case where it is a HashSet of T.
|
|
/// Avoid mutating the return value.
|
|
/// </summary>
|
|
public static HashSet<T>? AsHashSet<T>(this ISet<T> enumerable, IEqualityComparer<T>? comparer = null)
|
|
{
|
|
if (enumerable == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var set = enumerable as HashSet<T>;
|
|
if (set != null)
|
|
{
|
|
return set;
|
|
}
|
|
else
|
|
{
|
|
if (comparer == null)
|
|
{
|
|
comparer = EqualityComparer<T>.Default;
|
|
}
|
|
|
|
return new HashSet<T>(enumerable, comparer);
|
|
}
|
|
}
|
|
|
|
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
|
|
{
|
|
foreach (var item in enumeration)
|
|
{
|
|
action(item);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Helper function to append an <see cref="int"/> to a <see cref="StringBuilder"/>. Calling
|
|
/// <see cref="StringBuilder.Append(int)"/> directly causes an allocation by first converting the
|
|
/// <see cref="int"/> to a string and then appending that result:
|
|
/// <code>
|
|
/// public StringBuilder Append(int value)
|
|
/// {
|
|
/// return Append(value.ToString(CultureInfo.CurrentCulture));
|
|
/// }
|
|
/// </code>
|
|
///
|
|
/// Note that this uses the current culture to do the conversion while <see cref="AppendInt(StringBuilder, int)"/> does
|
|
/// not do any cultural sensitive conversion.
|
|
/// </summary>
|
|
/// <param name="sb">The <see cref="StringBuilder"/> to append to.</param>
|
|
/// <param name="value">The <see cref="int"/> to append.</param>
|
|
public static void AppendInt(this StringBuilder sb, int value)
|
|
{
|
|
if (value == 0)
|
|
{
|
|
sb.Append('0');
|
|
return;
|
|
}
|
|
|
|
// special case min value since it'll overflow if we negate it
|
|
if (value == int.MinValue)
|
|
{
|
|
sb.Append("-2147483648");
|
|
return;
|
|
}
|
|
|
|
// do all math with positive integers
|
|
if (value < 0)
|
|
{
|
|
sb.Append('-');
|
|
value = -value;
|
|
}
|
|
|
|
// upper range of int is 1 billion, so we start dividing by that to get the digit at that position
|
|
int divisor = 1_000_000_000;
|
|
|
|
// remember when we found our first digit so we can keep adding intermediate zeroes
|
|
bool digitFound = false;
|
|
while (divisor > 0)
|
|
{
|
|
if (digitFound || value >= divisor)
|
|
{
|
|
digitFound = true;
|
|
int digit = value / divisor;
|
|
value -= digit * divisor;
|
|
|
|
// convert the digit to char by adding the value to '0'.
|
|
// '0' + 0 = 48 + 0 = 48 = '0'
|
|
// '0' + 1 = 48 + 1 = 49 = '1'
|
|
// '0' + 2 = 48 + 2 = 50 = '2'
|
|
// etc...
|
|
sb.Append((char)('0' + digit));
|
|
}
|
|
|
|
divisor /= 10;
|
|
}
|
|
}
|
|
|
|
public static int SingleIndex<T>(this IList<T> lst, Predicate<T> isMatch)
|
|
{
|
|
var foundIndex = -1;
|
|
|
|
for (var index = 0; index < lst.Count; index++)
|
|
{
|
|
var item = lst[index];
|
|
if (isMatch(item))
|
|
{
|
|
if (foundIndex != -1)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
foundIndex = index;
|
|
}
|
|
}
|
|
|
|
if (foundIndex == -1)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
return foundIndex;
|
|
}
|
|
|
|
public static int FirstIndex<T>(this IList<T> lst, Predicate<T> isMatch)
|
|
{
|
|
for (var index = 0; index < lst.Count; index++)
|
|
{
|
|
var item = lst[index];
|
|
if (isMatch(item))
|
|
{
|
|
return index;
|
|
}
|
|
}
|
|
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
public static bool Any<T>(this IReadOnlyList<T> lst, Predicate<T> isMatch)
|
|
{
|
|
for (var index = 0; index < lst.Count; index++)
|
|
{
|
|
var item = lst[index];
|
|
if (isMatch(item))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|