Skip to content

Instantly share code, notes, and snippets.

@AlphaGit
Last active May 24, 2017 11:43
Show Gist options
  • Save AlphaGit/964b56b5f6e144932477e7e1ab2e537f to your computer and use it in GitHub Desktop.
Save AlphaGit/964b56b5f6e144932477e7e1ab2e537f to your computer and use it in GitHub Desktop.
BigArray.cs -- Allowing more than Int32.MaxValue elements in an array
namespace SomeLargeDataHolder
{
// adapted from https://blogs.msdn.microsoft.com/joshwil/2005/08/10/bigarrayt-getting-around-the-2gb-array-size-limit/
// Goal: create an array that allows for a number of elements > Int.MaxValue
class BigArray<T>
{
// These need to be const so that the getter/setter get inlined by the JIT into
// calling methods just like with a real array to have any chance of meeting our
// performance goals.
//
// BLOCK_SIZE must be a power of 2, and we want it to be big enough that we allocate
// blocks in the large object heap so that they don’t move.
internal const ulong BLOCK_SIZE = 524_288;
internal const int BLOCK_SIZE_LOG2 = 19;
// Don’t use a multi-dimensional array here because then we can’t right size the last
// block and we have to do range checking on our own and since there will then be
// exception throwing in our code there is a good chance that the JIT won’t inline.
readonly T[][] _elements;
// maximum BigArray size = BLOCK_SIZE * Int.MaxValue
public BigArray(ulong size)
{
var numBlocks = size / BLOCK_SIZE;
if (numBlocks * BLOCK_SIZE < size)
{
numBlocks += 1;
}
Length = size;
_elements = new T[numBlocks][];
for (var i = 0UL; i < numBlocks - 1; i++)
{
_elements[i] = new T[BLOCK_SIZE];
}
// by making sure to make the last block right sized then we get the range checks
// for free with the normal array range checks and don’t have to add our own
_elements[numBlocks - 1] = new T[size % BLOCK_SIZE];
}
public ulong Length { get; }
public T this[ulong elementNumber]
{
// these must be _very_ simple in order to ensure that they get inlined into their caller
get
{
var blockNum = elementNumber >> BLOCK_SIZE_LOG2;
var elementNumberInBlock = elementNumber & (BLOCK_SIZE - 1);
return _elements[blockNum][elementNumberInBlock];
}
set
{
var blockNum = elementNumber >> BLOCK_SIZE_LOG2;
var elementNumberInBlock = elementNumber & (BLOCK_SIZE - 1);
_elements[blockNum][elementNumberInBlock] = value;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment