using System; using System.Collections.Generic; using System.Linq; namespace Robust.Shared.Utility { public static class Extensions { public static IList Clone(this IList listToClone) where T : ICloneable { return listToClone.Select(item => (T)item.Clone()).ToList(); } /// /// Creates a shallow clone of a list. /// Basically a new list with all the same elements. /// /// The list to shallow clone. /// The type of the list's elements. /// A new list with the same elements as . public static List ShallowClone(this List self) { var list = new List(self.Count); list.AddRange(self); return list; } public static Dictionary ShallowClone(this Dictionary self) { var dict = new Dictionary(self.Count); foreach (var item in self) { dict[item.Key] = item.Value; } return dict; } /// /// Remove an item from the list, replacing it with the one at the very end of the list. /// This means that the order will not be preserved, but it should be an O(1) operation. /// /// The index to remove /// The removed element public static T RemoveSwap(this IList list, int index) { // This method has no implementation details, // and changing the result of an operation is a breaking change. var old = list[index]; var replacement = list[list.Count - 1]; list[index] = replacement; // TODO: Any more efficient way to pop the last element off? list.RemoveAt(list.Count - 1); return old; } // So you can do foreach (var (key, value) in dict) // This basically re-implements the CoreFX version because we're using a pretty old version of .NET Framework. // https://github.com/dotnet/roslyn/issues/20393 public static void Deconstruct(this KeyValuePair k, out TKey t, out TValue u) { t = k.Key; u = k.Value; } /// /// Pop an element from the end of a list, removing it from the list and returning it. /// /// The list to pop from. /// The type of the elements of the list. /// The popped off element. /// /// Thrown if the list is empty. /// public static T Pop(this IList list) { if (list.Count == 0) { throw new InvalidOperationException(); } var t = list[list.Count - 1]; list.RemoveAt(list.Count-1); return t; } /// /// Just like FirstOrDefault but returns null for value types as well. /// /// An to return an element from. /// A function to test each element for a condition. /// The type of the elements of . /// null if is empty or if no element passes the test specified by ; otherwise, the first element in that passes the test specified by . /// /// or is . public static TSource? FirstOrNull( this IEnumerable source, Func predicate) where TSource: struct { if (source == null) throw new ArgumentNullException(nameof (source)); if (predicate == null) throw new ArgumentNullException(nameof (predicate)); foreach (TSource source1 in source) { if (predicate(source1)) return source1; } return null; } public static TValue GetOrNew(this IDictionary dict, TKey key) where TValue : new() { if (!dict.TryGetValue(key, out var value)) { value = new TValue(); dict.Add(key, value); } return value; } // More efficient than LINQ. public static KeyValuePair[] ToArray(this Dictionary dict) { var array = new KeyValuePair[dict.Count]; var i = 0; foreach (var kvPair in dict) { array[i] = kvPair; i += 1; } return array; } } }