Created
August 24, 2019 22:46
-
-
Save jnm2/acc3872a8be0fa5bcec1f5dffef91390 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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