Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

c# feature(RepeatedField): Capacity property to resize the internal array #6530

Merged
merged 1 commit into from Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -216,14 +216,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