diff --git a/src/System.Collections.Immutable/src/Strings.Designer.cs b/src/System.Collections.Immutable/src/Strings.Designer.cs index b0db05c688d5..18031e9d16a6 100644 --- a/src/System.Collections.Immutable/src/Strings.Designer.cs +++ b/src/System.Collections.Immutable/src/Strings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.35312 +// Runtime Version:4.0.30319.34014 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -9,6 +9,7 @@ //------------------------------------------------------------------------------ namespace System.Collections.Immutable { + using System; using System.Reflection; @@ -87,6 +88,24 @@ internal static string CannotFindOldValue { } } + /// + /// Looks up a localized string similar to Capacity was less than the current Count of elements.. + /// + internal static string CapacityMustBeGreaterThanOrEqualToCount { + get { + return ResourceManager.GetString("CapacityMustBeGreaterThanOrEqualToCount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MoveToImmutable can only be performed when Count equals Capacity.. + /// + internal static string CapacityMustEqualCountOnMove { + get { + return ResourceManager.GetString("CapacityMustEqualCountOnMove", resourceCulture); + } + } + /// /// Looks up a localized string similar to Collection was modified; enumeration operation may not execute.. /// diff --git a/src/System.Collections.Immutable/src/Strings.resx b/src/System.Collections.Immutable/src/Strings.resx index b3cd27138204..540ba24c7235 100644 --- a/src/System.Collections.Immutable/src/Strings.resx +++ b/src/System.Collections.Immutable/src/Strings.resx @@ -126,6 +126,12 @@ Cannot find the old value + + Capacity was less than the current Count of elements. + + + MoveToImmutable can only be performed when Count equals Capacity. + Collection was modified; enumeration operation may not execute. diff --git a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray`1+Builder.cs b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray`1+Builder.cs index 69438b052e86..d2e99ee4daf6 100644 --- a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray`1+Builder.cs +++ b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray`1+Builder.cs @@ -22,7 +22,7 @@ public sealed class Builder : IList, IReadOnlyList /// /// The backing array for the builder. /// - private RefAsValueType[] _elements; + private T[] _elements; /// /// The number of initialized elements in the array. @@ -36,8 +36,8 @@ public sealed class Builder : IList, IReadOnlyList internal Builder(int capacity) { Requires.Range(capacity >= 0, "capacity"); - _elements = new RefAsValueType[capacity]; - this.Count = 0; + _elements = new T[capacity]; + _count = 0; } /// @@ -49,7 +49,41 @@ internal Builder() } /// - /// Gets or sets the length of the array. + /// Get and sets the length of the internal array. When set the internal array is + /// is reallocated to the given capacity if it is not already the specified length. + /// + public int Capacity + { + get { return _elements.Length; } + set + { + if (value < _count) + { + throw new ArgumentException(Strings.CapacityMustBeGreaterThanOrEqualToCount, paramName: "value"); + } + + if (value != _elements.Length) + { + if (value > 0) + { + var temp = new T[value]; + if (_count > 0) + { + Array.Copy(_elements, 0, temp, 0, _count); + } + + _elements = temp; + } + else + { + _elements = ImmutableArray.Empty.array; + } + } + } + } + + /// + /// Gets or sets the length of the builder. /// /// /// If the value is decreased, the array contents are truncated. @@ -81,7 +115,7 @@ public int Count { for (int i = value; i < this.Count; i++) { - _elements[i].Value = default(T); + _elements[i] = default(T); } } } @@ -111,7 +145,7 @@ public T this[int index] throw new IndexOutOfRangeException(); } - return _elements[index].Value; + return _elements[index]; } set @@ -121,7 +155,7 @@ public T this[int index] throw new IndexOutOfRangeException(); } - _elements[index].Value = value; + _elements[index] = value; } } @@ -141,7 +175,7 @@ bool ICollection.IsReadOnly /// An immutable array. public ImmutableArray ToImmutable() { - if (this.Count == 0) + if (Count == 0) { return Empty; } @@ -149,6 +183,25 @@ public ImmutableArray ToImmutable() return new ImmutableArray(this.ToArray()); } + /// + /// Extracts the internal array as an and replaces it + /// with a zero length array. + /// + /// When doesn't + /// equal . + public ImmutableArray MoveToImmutable() + { + if (Capacity != Count) + { + throw new InvalidOperationException(Strings.CapacityMustEqualCountOnMove); + } + + T[] temp = _elements; + _elements = ImmutableArray.Empty.array; + _count = 0; + return new ImmutableArray(temp); + } + /// /// Removes all items from the . /// @@ -173,7 +226,7 @@ public void Insert(int index, T item) } _count++; - _elements[index].Value = item; + _elements[index] = item; } /// @@ -183,7 +236,7 @@ public void Insert(int index, T item) public void Add(T item) { this.EnsureCapacity(this.Count + 1); - _elements[_count++].Value = item; + _elements[_count++] = item; } /// @@ -220,7 +273,7 @@ public void AddRange(params T[] items) var nodes = _elements; for (int i = 0; i < items.Length; i++) { - nodes[offset + i].Value = items[i]; + nodes[offset + i] = items[i]; } } @@ -238,7 +291,7 @@ public void AddRange(TDerived[] items) where TDerived : T var nodes = _elements; for (int i = 0; i < items.Length; i++) { - nodes[offset + i].Value = items[i]; + nodes[offset + i] = items[i]; } } @@ -258,7 +311,7 @@ public void AddRange(T[] items, int length) var nodes = _elements; for (int i = 0; i < length; i++) { - nodes[offset + i].Value = items[i]; + nodes[offset + i] = items[i]; } } @@ -372,7 +425,7 @@ public T[] ToArray() var elements = _elements; for (int i = 0; i < tmp.Length; i++) { - tmp[i] = elements[i].Value; + tmp[i] = elements[i]; } return tmp; @@ -387,18 +440,14 @@ public void CopyTo(T[] array, int index) { Requires.NotNull(array, "array"); Requires.Range(index >= 0 && index + this.Count <= array.Length, "start"); - - foreach (var item in this) - { - array[index++] = item; - } + Array.Copy(_elements, 0, array, index, this.Count); } /// /// Resizes the array to accommodate the specified capacity requirement. /// /// The required capacity. - public void EnsureCapacity(int capacity) + private void EnsureCapacity(int capacity) { if (_elements.Length < capacity) { @@ -468,13 +517,13 @@ public int IndexOf(T item, int startIndex, int count, IEqualityComparer equal if (equalityComparer == EqualityComparer.Default) { - return Array.IndexOf(_elements, new RefAsValueType(item), startIndex, count); + return Array.IndexOf(_elements, item, startIndex, count); } else { for (int i = startIndex; i < startIndex + count; i++) { - if (equalityComparer.Equals(_elements[i].Value, item)) + if (equalityComparer.Equals(_elements[i], item)) { return i; } @@ -555,13 +604,13 @@ public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer e if (equalityComparer == EqualityComparer.Default) { - return Array.LastIndexOf(_elements, new RefAsValueType(item), startIndex, count); + return Array.LastIndexOf(_elements, item, startIndex, count); } else { for (int i = startIndex; i >= startIndex - count + 1; i--) { - if (equalityComparer.Equals(item, _elements[i].Value)) + if (equalityComparer.Equals(item, _elements[i])) { return i; } @@ -576,13 +625,7 @@ public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer e /// public void ReverseContents() { - int end = this.Count - 1; - for (int i = 0, j = end; i < j; i++, j--) - { - var tmp = _elements[i].Value; - _elements[i] = _elements[j]; - _elements[j].Value = tmp; - } + Array.Reverse(_elements, 0, _count); } /// @@ -592,7 +635,7 @@ public void Sort() { if (Count > 1) { - Array.Sort(_elements, 0, this.Count, Comparer.Default); + Array.Sort(_elements, 0, this.Count, Comparer.Default); } } @@ -604,7 +647,7 @@ public void Sort(IComparer comparer) { if (Count > 1) { - Array.Sort(_elements, 0, this.Count, Comparer.Create(comparer)); + Array.Sort(_elements, 0, _count, comparer); } } @@ -623,7 +666,7 @@ public void Sort(int index, int count, IComparer comparer) if (count > 1) { - Array.Sort(_elements, index, count, Comparer.Create(comparer)); + Array.Sort(_elements, index, count, comparer); } } @@ -663,7 +706,7 @@ IEnumerator IEnumerable.GetEnumerator() /// The type of source elements. /// The source array. /// The number of elements to add to this array. - private void AddRange(RefAsValueType[] items, int length) where TDerived : T + private void AddRange(TDerived[] items, int length) where TDerived : T { this.EnsureCapacity(this.Count + length); @@ -673,35 +716,7 @@ private void AddRange(RefAsValueType[] items, int length) wh var nodes = _elements; for (int i = 0; i < length; i++) { - nodes[offset + i].Value = items[i].Value; - } - } - - private sealed class Comparer : IComparer> - { - private readonly IComparer _comparer; - - public static readonly Comparer Default = new Comparer(Comparer.Default); - - public static Comparer Create(IComparer comparer) - { - if (comparer == null || comparer == Comparer.Default) - { - return Default; - } - - return new Comparer(comparer); - } - - private Comparer(IComparer comparer) - { - Requires.NotNull(comparer, "comparer"); // use Comparer.Default instead of passing null - _comparer = comparer; - } - - public int Compare(RefAsValueType x, RefAsValueType y) - { - return _comparer.Compare(x.Value, y.Value); + nodes[offset + i] = items[i]; } } } diff --git a/src/System.Collections.Immutable/tests/ImmutableArrayBuilderTest.cs b/src/System.Collections.Immutable/tests/ImmutableArrayBuilderTest.cs index 5a850b6809cb..54034928e06f 100644 --- a/src/System.Collections.Immutable/tests/ImmutableArrayBuilderTest.cs +++ b/src/System.Collections.Immutable/tests/ImmutableArrayBuilderTest.cs @@ -469,6 +469,185 @@ public void IEnumerator() Assert.False(enumerator.MoveNext()); } + [Fact] + public void MoveToImmutableNormal() + { + var builder = CreateBuilderWithCount(2); + Assert.Equal(2, builder.Count); + Assert.Equal(2, builder.Capacity); + builder[1] = "b"; + builder[0] = "a"; + var array = builder.MoveToImmutable(); + Assert.Equal(new[] { "a", "b" }, array); + Assert.Equal(0, builder.Count); + Assert.Equal(0, builder.Capacity); + } + + [Fact] + public void MoveToImmutableRepeat() + { + var builder = CreateBuilderWithCount(2); + builder[0] = "a"; + builder[1] = "b"; + var array1 = builder.MoveToImmutable(); + var array2 = builder.MoveToImmutable(); + Assert.Equal(new[] { "a", "b" }, array1); + Assert.Equal(0, array2.Length); + } + + [Fact] + public void MoveToImmutablePartialFill() + { + var builder = ImmutableArray.CreateBuilder(4); + builder.Add(42); + builder.Add(13); + Assert.Equal(4, builder.Capacity); + Assert.Equal(2, builder.Count); + Assert.Throws(typeof(InvalidOperationException), () => builder.MoveToImmutable()); + } + + [Fact] + public void MoveToImmutablePartialFillWithCountUpdate() + { + var builder = ImmutableArray.CreateBuilder(4); + builder.Add(42); + builder.Add(13); + Assert.Equal(4, builder.Capacity); + Assert.Equal(2, builder.Count); + builder.Count = builder.Capacity; + var array = builder.MoveToImmutable(); + Assert.Equal(new[] { 42, 13, 0, 0 }, array); + } + + [Fact] + public void MoveToImmutableThenUse() + { + var builder = CreateBuilderWithCount(2); + Assert.Equal(2, builder.MoveToImmutable().Length); + Assert.Equal(0, builder.Capacity); + builder.Add("a"); + builder.Add("b"); + Assert.Equal(2, builder.Count); + Assert.True(builder.Capacity >= 2); + Assert.Equal(new[] { "a", "b" }, builder.MoveToImmutable()); + } + + [Fact] + public void MoveToImmutableAfterClear() + { + var builder = CreateBuilderWithCount(2); + builder[0] = "a"; + builder[1] = "b"; + builder.Clear(); + Assert.Throws(typeof(InvalidOperationException), () => builder.MoveToImmutable()); + } + + [Fact] + public void MoveToImmutableAddToCapacity() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 3); + for (int i = 0; i < builder.Capacity; i++) + { + builder.Add(i); + } + + Assert.Equal(new[] { 0, 1, 2 }, builder.MoveToImmutable()); + } + + [Fact] + public void MoveToImmutableInsertToCapacity() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 3); + for (int i = 0; i < builder.Capacity; i++) + { + builder.Insert(i, i); + } + + Assert.Equal(new[] { 0, 1, 2 }, builder.MoveToImmutable()); + } + + [Fact] + public void MoveToImmutableAddRangeToCapcity() + { + var array = new[] { 1, 2, 3, 4, 5 }; + var builder = ImmutableArray.CreateBuilder(initialCapacity: array.Length); + builder.AddRange(array); + Assert.Equal(array, builder.MoveToImmutable()); + } + + [Fact] + public void MoveToImmutableAddRemoveAddToCapacity() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 3); + for (int i = 0; i < builder.Capacity; i++) + { + builder.Add(i); + builder.RemoveAt(i); + builder.Add(i); + } + + Assert.Equal(new[] { 0, 1, 2 }, builder.MoveToImmutable()); + } + + [Fact] + public void CapacitySetToZero() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 10); + builder.Capacity = 0; + Assert.Equal(0, builder.Capacity); + Assert.Equal(new int[] { }, builder.ToArray()); + } + + [Fact] + public void CapacitySetToLessThanCount() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 10); + builder.Add(1); + builder.Add(1); + Assert.Throws(typeof(ArgumentException), () => builder.Capacity = 1); + } + + [Fact] + public void CapacitySetToCount() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 10); + builder.Add(1); + builder.Add(2); + builder.Capacity = builder.Count; + Assert.Equal(2, builder.Capacity); + Assert.Equal(new[] { 1, 2 }, builder.ToArray()); + } + + [Fact] + public void CapacitySetToCapacity() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 10); + builder.Add(1); + builder.Add(2); + builder.Capacity = builder.Capacity; + Assert.Equal(10, builder.Capacity); + Assert.Equal(new[] { 1, 2 }, builder.ToArray()); + } + + [Fact] + public void CapacitySetToBiggerCapacity() + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: 10); + builder.Add(1); + builder.Add(2); + builder.Capacity = 20; + Assert.Equal(20, builder.Capacity); + Assert.Equal(2, builder.Count); + Assert.Equal(new[] { 1, 2 }, builder.ToArray()); + } + + private static ImmutableArray.Builder CreateBuilderWithCount(int count) + { + var builder = ImmutableArray.CreateBuilder(count); + builder.Count = count; + return builder; + } + protected override IEnumerable GetEnumerableOf(params T[] contents) { var builder = new ImmutableArray.Builder(contents.Length);