From d71c66daf98dc686ad46ad6b4b929bc00caf11eb Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Tue, 28 Jul 2020 19:03:19 +0200 Subject: [PATCH] Initial --- ExaArray/EArray1D.cs | 7 -- ExaArray/ExaArray1D.cs | 150 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 7 deletions(-) delete mode 100644 ExaArray/EArray1D.cs create mode 100644 ExaArray/ExaArray1D.cs diff --git a/ExaArray/EArray1D.cs b/ExaArray/EArray1D.cs deleted file mode 100644 index 0be8614..0000000 --- a/ExaArray/EArray1D.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Exa -{ - public sealed class EArray1D - { - - } -} \ No newline at end of file diff --git a/ExaArray/ExaArray1D.cs b/ExaArray/ExaArray1D.cs new file mode 100644 index 0000000..67df0ed --- /dev/null +++ b/ExaArray/ExaArray1D.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; + +namespace Exa +{ + /// + /// This class represents an one-dimensional array with the ability to grow up + /// to 4.4 quintillion (4,410,000,000,000,000,000) or 4.4 exa elements. + /// + /// The desired type to use, e.g. byte, int, etc. + public sealed class ExaArray1D + { + /// + /// Unfortunately, this seems to be the maximal number of entries an + /// C# array can hold e.g. of uint. Due to this limitation, this is + /// also the maximum number of possible chunks. + /// + private const int MAX_CAPACITY_ARRAY = 2_100_000_000; + + /// + /// The total number of possible elements. + /// + public const ulong MAX_NUMBER_ELEMENTS = 4_410_000_000_000_000_000; + + // Chunk storage: + private T[][] chunks = new T[1][]; + + /// + /// Creates an empty one-dimensional exa-scale array. + /// + public ExaArray1D() => this.chunks[0] = new T[0]; + + /// + /// Extends the array's capacity by some extend. + /// + /// + /// Please ensure, that neither the extendBy parameter nor the total number of + /// elements can exceed 4,410,000,000,000,000,000. Otherwise, an ArgumentOutOfRangeException + /// will be thrown. You can use the constant to perform checks. + /// + /// Performance: O(n) where n is the new total number of elements + /// Memory: O(n+m) where n is the necessary memory for the previously elements, and m + /// is the memory needed for the desired new capacity. + /// + /// Extend this array by this number of elements. Cannot exceed 4,410,000,000,000,000,000. + /// Throws, if either the total number of elements or the + /// extendBy argument exceeds the limit of 4,410,000,000,000,000,000 elements. + public void Extend(ulong extendBy = 1) + { + if(extendBy > MAX_NUMBER_ELEMENTS || this.Length + extendBy >= MAX_NUMBER_ELEMENTS) + throw new ArgumentOutOfRangeException($"It is not possible to extend more than {MAX_NUMBER_ELEMENTS} elements."); + + this.Length += extendBy; + int availableInCurrentChunk = MAX_CAPACITY_ARRAY - this.chunks[^1]?.Length ?? 0; + if (extendBy >= (ulong)availableInCurrentChunk) + { + // Extend the current chunk to its max: + var extendedInner = new T[MAX_CAPACITY_ARRAY]; + Array.Copy(this.chunks[^1], extendedInner, this.chunks[^1].Length); + this.chunks[^1] = extendedInner; + + // + // Now, adding as much new chunks as necessary: + // + ulong leftOver = extendBy - (ulong) availableInCurrentChunk; + if(leftOver == 0) + return; + + do + { + int allocating = leftOver >= MAX_CAPACITY_ARRAY ? MAX_CAPACITY_ARRAY : (int)leftOver; + leftOver -= (ulong) allocating; + + // First, we allocate space for the new chunk: + var extendedOuter = new T[this.chunks.Length + 1][]; + Array.Copy(this.chunks, extendedOuter, this.chunks.Length); + this.chunks = extendedOuter; + + // Now, we allocate the inner array i.e. the new chunk itself: + this.chunks[^1] = new T[allocating]; + + } while (leftOver > 0); + + return; + } + + // Extend the current chunk as necessary: + var extendedChunk = new T[(this.chunks[^1]?.Length ?? 0) + (int)extendBy]; + Array.Copy(this.chunks[^1], extendedChunk, this.chunks[^1].Length); + this.chunks[^1] = extendedChunk; + } + + /// + /// Gets the currently available number of possible values i.e. the capacity of the array. + /// + /// + /// Performance: O(1) + /// + public ulong Length { get; private set; } = 0; + + /// + /// Gets or sets a value at a certain position. + /// + /// + /// Performance: O(1) + /// + /// The desired position in the exa-scale array. The index is zero-based. + /// Throws, if the index exceeds or + /// the desired index is not available due to missing extending. + public T this[ulong index] + { + get + { + if(index >= MAX_NUMBER_ELEMENTS) + throw new IndexOutOfRangeException(); + + int chunkIndex = (int) (index / (ulong)MAX_CAPACITY_ARRAY); + int elementIndex = (int) (index - (ulong) chunkIndex * MAX_CAPACITY_ARRAY); + return this.chunks[chunkIndex][elementIndex]; + } + + set + { + if(index >= MAX_NUMBER_ELEMENTS) + throw new IndexOutOfRangeException(); + + int chunkIndex = (int) (index / (ulong)MAX_CAPACITY_ARRAY); + int elementIndex = (int) (index - (ulong) chunkIndex * MAX_CAPACITY_ARRAY); + if (chunkIndex >= this.chunks.Length || elementIndex >= this.chunks[chunkIndex].Length) + throw new IndexOutOfRangeException(); + + this.chunks[chunkIndex][elementIndex] = value; + } + } + + /// + /// Yields an enumerator across all elements. + /// + /// + /// Performance: O(n) + /// Memory: O(1) + /// + /// An enumerator across all elements. + public IEnumerable Items() + { + for (ulong n = 0; n < this.Length; n++) + yield return this[n]; + } + } +} \ No newline at end of file