1 // Copyright (c) Microsoft. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
9 // An immutable data structure that supports adding, removing, and enumerating elements.
11 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
13 using System.Collections.Generic;
14 using System.Diagnostics.Contracts;
15 using System.Diagnostics;
17 namespace System.Threading.Tasks.Dataflow.Internal
19 /// <summary>Provides a simple, immutable list.</summary>
20 /// <typeparam name="T">Specifies the type of the data stored in the list.</typeparam>
21 [DebuggerDisplay("Count={Count}")]
22 [DebuggerTypeProxy(typeof(EnumerableDebugView<>))]
23 internal sealed class ImmutableList<T> : IEnumerable<T>
25 /// <summary>An empty list.</summary>
26 private readonly static ImmutableList<T> _empty = new ImmutableList<T>();
27 /// <summary>The immutable data in this list instance.</summary>
28 private readonly T[] _array;
30 /// <summary>Gets the empty list.</summary>
31 public static ImmutableList<T> Empty { get { return _empty; } }
33 /// <summary>Initializes the immutable list to be empty.</summary>
34 private ImmutableList() : this(new T[0]) { }
36 /// <summary>Initializes the immutable list with the specified elements.</summary>
37 /// <param name="elements">The element array to use for this list's data.</param>
38 private ImmutableList(T[] elements)
40 Contract.Requires(elements != null, "List requires an array to wrap.");
44 /// <summary>Creates a new immutable list from this list and the additional element.</summary>
45 /// <param name="item">The item to add.</param>
46 /// <returns>The new list.</returns>
47 public ImmutableList<T> Add(T item)
49 // Copy the elements from this list and the item
50 // to a new list that's returned.
51 var newArray = new T[_array.Length + 1];
52 Array.Copy(_array, 0, newArray, 0, _array.Length);
53 newArray[newArray.Length - 1] = item;
54 return new ImmutableList<T>(newArray);
57 /// <summary>Creates a new immutable list from this list and without the specified element.</summary>
58 /// <param name="item">The item to remove.</param>
59 /// <returns>The new list.</returns>
60 public ImmutableList<T> Remove(T item)
62 // Get the index of the element. If it's not in the list, just return this list.
63 int index = Array.IndexOf(_array, item);
64 if (index < 0) return this;
66 // It's in the list, so if it's the only one, just return the empty list
67 if (_array.Length == 1) return Empty;
69 // Otherwise, copy the other elements to a new list that's returned.
70 var newArray = new T[_array.Length - 1];
71 Array.Copy(_array, 0, newArray, 0, index);
72 Array.Copy(_array, index + 1, newArray, index, _array.Length - index - 1);
73 return new ImmutableList<T>(newArray);
76 /// <summary>Gets the number of elements in this list.</summary>
77 public int Count { get { return _array.Length; } }
79 /// <summary>Gets whether the list contains the specified item.</summary>
80 /// <param name="item">The item to lookup.</param>
81 /// <returns>true if the list contains the item; otherwise, false.</returns>
82 public bool Contains(T item) { return Array.IndexOf(_array, item) >= 0; }
84 /// <summary>Returns an enumerator that iterates through the collection.</summary>
85 public IEnumerator<T> GetEnumerator() { return ((IEnumerable<T>)_array).GetEnumerator(); }
86 /// <summary>Returns an enumerator that iterates through the collection.</summary>
87 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); }