Skip to content

Instantly share code, notes, and snippets.

@jnm2
Created August 24, 2019 22:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnm2/acc3872a8be0fa5bcec1f5dffef91390 to your computer and use it in GitHub Desktop.
Save jnm2/acc3872a8be0fa5bcec1f5dffef91390 to your computer and use it in GitHub Desktop.
using System;
public static class CommonUtils
{
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when <paramref name="minCapacity"/> is less than zero.
/// </exception>
/// <exception cref="OutOfMemoryException">
/// Thrown when <paramref name="minCapacity"/> is greater than the maximum available array length.
/// </exception>
public static void EnsureCapacity<T>(ref T[] array, int minCapacity)
{
if (minCapacity < 0)
throw new ArgumentOutOfRangeException(nameof(minCapacity), minCapacity, "Minimum capacity must be greater than or equal to zero.");
var originalArray = array;
if (originalArray != null && originalArray.Length >= minCapacity) return;
var newCapacity = originalArray is null || originalArray.Length == 0 ? 4 : originalArray.Length * 2;
const int maxArrayLength = 0x7FEFFFFF;
if ((uint)newCapacity > maxArrayLength) newCapacity = maxArrayLength;
if (newCapacity < minCapacity) newCapacity = minCapacity;
Array.Resize(ref array, newCapacity);
}
}
using System;
using System.Linq;
using NUnit.Framework;
using Shouldly;
public static class EnsureCapacityTests
{
private const int MaxArrayLength = 0x7FEFFFFF;
[Test]
public static void Null_array_is_replaced_with_array_at_capacity()
{
var array = (int[])null;
CommonUtils.EnsureCapacity(ref array, 10);
array.ShouldNotBeNull();
array.Length.ShouldBe(10);
}
[Test]
public static void Minimum_capacity_is_applied_to_null_array()
{
var array = (int[])null;
CommonUtils.EnsureCapacity(ref array, 0);
array.Length.ShouldBe(4);
}
[Test]
public static void Minimum_capacity_is_applied_to_empty_array()
{
var array = new int[0];
CommonUtils.EnsureCapacity(ref array, 1);
array.Length.ShouldBe(4);
}
[Test]
public static void MinCapacity_must_not_be_negative()
{
var ex = Should.Throw<ArgumentOutOfRangeException>(() =>
{
var array = (int[])null;
CommonUtils.EnsureCapacity(ref array, minCapacity: -1);
});
ex.ParamName.ShouldBe("minCapacity");
ex.ActualValue.ShouldBe(-1);
}
[Test]
public static void Capacity_is_doubled_if_requested_capacity_is_less_than_double_the_current_capacity()
{
var array = new int[10];
CommonUtils.EnsureCapacity(ref array, 11);
array.Length.ShouldBe(20);
}
[Test]
public static void Capacity_is_set_to_requested_capacity_when_greater_than_double_the_current_capacity()
{
var array = new int[10];
CommonUtils.EnsureCapacity(ref array, 21);
array.Length.ShouldBe(21);
}
[Test]
public static void Array_reference_is_not_changed_when_requested_capacity_is_equal_to_the_current_capacity()
{
var originalArray = new int[10];
var array = originalArray;
CommonUtils.EnsureCapacity(ref array, 10);
array.ShouldBeSameAs(originalArray);
}
[Test]
public static void Array_reference_is_not_changed_when_requested_capacity_is_less_than_the_current_capacity()
{
var originalArray = new int[10];
var array = originalArray;
CommonUtils.EnsureCapacity(ref array, 5);
array.ShouldBeSameAs(originalArray);
}
[Test]
public static void Array_values_are_copied_on_resize()
{
var originalArray = Enumerable.Range(1, 10).ToArray();
var array = originalArray;
CommonUtils.EnsureCapacity(ref array, 20);
array.ShouldBe(originalArray.Concat(Enumerable.Repeat(default(int), 10)));
}
[Test]
public static void Out_of_memory_is_thrown_when_requested_capacity_is_greater_than_max_array_length()
{
Should.Throw<OutOfMemoryException>(() =>
{
var array = new int[10];
CommonUtils.EnsureCapacity(ref array, MaxArrayLength + 1);
});
}
[Test]
public static void Capacity_is_not_doubled_past_max_array_length()
{
try
{
var array = new int[(MaxArrayLength / 2) + 1];
CommonUtils.EnsureCapacity(ref array, array.Length + 1);
array.Length.ShouldBe(MaxArrayLength);
}
catch (OutOfMemoryException)
{
Assert.Inconclusive("The current process does not support creating arrays large enough to test this functionality.");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment