| File: BuildCheck\EnumerableExtensions.cs | Web Access |
| Project: src\msbuild\src\Framework\Microsoft.Build.Framework.csproj (Microsoft.Build.Framework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; #if !NET using System.Collections.ObjectModel; #endif namespace Microsoft.Build.Experimental.BuildCheck; internal static class EnumerableExtensions { /// <summary> /// Concatenates items of input sequence into csv string. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source">Sequence to be turned into csv string.</param> /// <param name="useSpace">Indicates whether space should be inserted between commas and following items.</param> /// <returns>Csv string.</returns> public static string ToCsvString<T>(this IEnumerable<T>? source, bool useSpace = true) { return source == null ? "<NULL>" : string.Join(useSpace ? ", " : ",", source); } /// <summary> /// Returns the item as an enumerable with single item. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="item"></param> /// <returns></returns> public static IEnumerable<T> AsSingleItemEnumerable<T>(this T item) { yield return item; } public static HashSet<T> NewHashSet<T>(int capacity) => NewHashSet<T>(capacity, null); public static HashSet<T> NewHashSet<T>(IEqualityComparer<T> equalityComparer) => NewHashSet<T>(0, equalityComparer); public static HashSet<T> NewHashSet<T>(int capacity, IEqualityComparer<T>? equalityComparer) { #if NETSTANDARD2_0 return new HashSet<T>(equalityComparer); #else return new HashSet<T>(capacity, equalityComparer); #endif } public static HashSet<T>? ToHashSet<T>(this ICollection<T>? source, IEqualityComparer<T>? equalityComparer = null) { if (source is null) { return null; } if (source is HashSet<T> set) { return set; } return new HashSet<T>(source, equalityComparer); } #if !NET /// <summary> /// Returns a read-only <see cref="ReadOnlyDictionary{TKey, TValue}"/> wrapper /// for the current dictionary. /// </summary> public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> dictionary) => new(dictionary); #endif /// <summary> /// Adds a content of given dictionary to current dictionary. /// </summary> /// <typeparam name="TKey"></typeparam> /// <typeparam name="TValue"></typeparam> /// <param name="dict">Dictionary to receive another values.</param> /// <param name="another">Dictionary to be merged into current.</param> /// <param name="mergeValues">Way of resolving keys conflicts.</param> public static void Merge<TKey, TValue>( this IDictionary<TKey, TValue> dict, IReadOnlyDictionary<TKey, TValue> another, Func<TValue, TValue, TValue> mergeValues) { foreach (var pair in another) { if (!dict.TryGetValue(pair.Key, out TValue? value)) { dict[pair.Key] = pair.Value; } else { dict[pair.Key] = mergeValues(value, pair.Value); } } } /// <summary> /// Adds a content of given list to current dictionary. /// </summary> /// <typeparam name="TKey"></typeparam> /// <typeparam name="TValue"></typeparam> /// <param name="dict">Dictionary to receive another values.</param> /// <param name="another">List to be merged into current.</param> /// <param name="extractKey">Way of getting a key of an incoming value.</param> /// <param name="mergeValues">Way of resolving keys conflicts.</param> public static void Merge<TKey, TValue>( this IDictionary<TKey, TValue> dict, IReadOnlyList<TValue> another, Func<TValue, TKey> extractKey, Func<TValue, TValue, TValue> mergeValues) { foreach (var mergeValue in another) { TKey key = extractKey(mergeValue); if (!dict.TryGetValue(key, out TValue? value)) { dict[key] = mergeValue; } else { dict[key] = mergeValues(value, mergeValue); } } } }