Skip to content

Commit

Permalink
Merge pull request #6530 from prat0088/csharp-ensuresize
Browse files Browse the repository at this point in the history
c# feature(RepeatedField): Capacity property to resize the internal array
  • Loading branch information
jtattermusch committed Oct 18, 2019
2 parents 77646a4 + da57400 commit 2f7f670
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 2 deletions.
48 changes: 48 additions & 0 deletions csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
Expand Up @@ -33,6 +33,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -756,5 +757,52 @@ public void NaNValuesComparedBitwise()
Assert.True(list1.Contains(SampleNaNs.SignallingFlipped));
Assert.False(list2.Contains(SampleNaNs.SignallingFlipped));
}

[Test]
public void Capacity_Increase()
{
// Unfortunately this case tests implementation details of RepeatedField. This is necessary

var list = new RepeatedField<int>() { 1, 2, 3 };

Assert.AreEqual(8, list.Capacity);
Assert.AreEqual(3, list.Count);

list.Capacity = 10; // Set capacity to a larger value to trigger growth
Assert.AreEqual(10, list.Capacity, "Capacity increased");
Assert.AreEqual(3, list.Count);

CollectionAssert.AreEqual(new int[] {1, 2, 3}, list.ToArray(), "We didn't lose our data in the resize");
}

[Test]
public void Capacity_Decrease()
{
var list = new RepeatedField<int>() { 1, 2, 3 };

Assert.AreEqual(8, list.Capacity);
Assert.DoesNotThrow(() => list.Capacity = 5, "Can decrease capacity if new capacity is greater than list.Count");
Assert.AreEqual(5, list.Capacity);

Assert.DoesNotThrow(() => list.Capacity = 3, "Can set capacity exactly to list.Count" );

Assert.Throws<ArgumentOutOfRangeException>(() => list.Capacity = 2, "Can't set the capacity smaller than list.Count" );

Assert.Throws<ArgumentOutOfRangeException>(() => list.Capacity = 0, "Can't set the capacity to zero" );

Assert.Throws<ArgumentOutOfRangeException>(() => list.Capacity = -1, "Can't set the capacity to negative" );
}

[Test]
public void Capacity_Zero()
{
var list = new RepeatedField<int>() { 1 };
list.RemoveAt(0);
Assert.AreEqual(0, list.Count);
Assert.AreEqual(8, list.Capacity);

Assert.DoesNotThrow(() => list.Capacity = 0, "Can set Capacity to 0");
Assert.AreEqual(0, list.Capacity);
}
}
}
36 changes: 34 additions & 2 deletions csharp/src/Google.Protobuf/Collections/RepeatedField.cs
Expand Up @@ -220,14 +220,46 @@ public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
}
}

/// <summary>
/// Gets and sets the capacity of the RepeatedField's internal array. WHen set, the internal array is reallocated to the given capacity.
/// <exception cref="ArgumentOutOfRangeException">The new value is less than Count -or- when Count is less than 0.</exception>
/// </summary>
public int Capacity
{
get { return array.Length; }
set
{
if (value < count)
{
throw new ArgumentOutOfRangeException("Capacity", value,
$"Cannot set Capacity to a value smaller than the current item count, {count}");
}

if (value >= 0 && value != array.Length)
{
SetSize(value);
}
}
}

// May increase the size of the internal array, but will never shrink it.
private void EnsureSize(int size)
{
if (array.Length < size)
{
size = Math.Max(size, MinArraySize);
int newSize = Math.Max(array.Length * 2, size);
var tmp = new T[newSize];
Array.Copy(array, 0, tmp, 0, array.Length);
SetSize(newSize);
}
}

// Sets the internal array to an exact size.
private void SetSize(int size)
{
if (size != array.Length)
{
var tmp = new T[size];
Array.Copy(array, 0, tmp, 0, count);
array = tmp;
}
}
Expand Down

0 comments on commit 2f7f670

Please sign in to comment.