Last active
May 24, 2017 11:43
-
-
Save AlphaGit/964b56b5f6e144932477e7e1ab2e537f to your computer and use it in GitHub Desktop.
BigArray.cs -- Allowing more than Int32.MaxValue elements in an array
This file contains hidden or 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
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