diff --git a/ExaArray/ExaArray1D.Factories.cs b/ExaArray/ExaArray1D.Factories.cs
index 2e4f576..b487aa9 100644
--- a/ExaArray/ExaArray1D.Factories.cs
+++ b/ExaArray/ExaArray1D.Factories.cs
@@ -32,14 +32,33 @@ namespace Exa
return next;
}
+ ///
+ /// Creates a new ExaArray1D from another, respecting the given range.
+ ///
+ ///
+ /// When T is a value type, data gets copied as values. When T is a reference type, the pointers
+ /// to the original objects are copied. Thus, this factory method does not create a deep copy.
+ ///
+ /// Performance: O(n)
+ ///
+ /// The indices are inclusive.
+ ///
+ /// The instance from which the new instance is to be created.
+ /// The first source element which should be part of the new array.
+ /// The last source element which should be part of the new array.
+ /// The new instance
+ /// Throws, when one or both of the indices are out of range.
public static ExaArray1D CreateFrom(ExaArray1D other, ulong indexFrom, ulong indexTo)
{
if (indexTo < indexFrom)
throw new IndexOutOfRangeException("Index to must be greater than index from.");
if (indexTo >= other.Length || indexFrom >= other.Length)
- throw new IndexOutOfRangeException("Index to must be greater than index from.");
+ throw new IndexOutOfRangeException("Index to must be within the range of the source.");
+ //
+ // Determine the source start chunk and index.
+ //
int sourceChunkIndexTo = -1;
int sourceElementIndexTo = -1;
switch (other.OptimizationStrategy)
@@ -54,6 +73,9 @@ namespace Exa
break;
}
+ //
+ // Determine the source end chunk and index.
+ //
int sourceChunkIndexFrom = -1;
int sourceElementIndexFrom = -1;
switch (other.OptimizationStrategy)
@@ -68,7 +90,12 @@ namespace Exa
break;
}
+ // How many element we have to copy?
ulong newRange = indexTo - indexFrom + 1;
+
+ //
+ // Determine, how many total chunks we need for the copy.
+ //
int destChunks = -1;
switch (other.OptimizationStrategy)
{
@@ -80,20 +107,29 @@ namespace Exa
break;
}
+ // Create the copy and allocate the needed number of outer chunk.
var next = new ExaArray1D(other.OptimizationStrategy)
{
Length = newRange,
chunks = new T[destChunks][],
};
-
- int sourceChunkIndex = sourceChunkIndexFrom;
- int destinChunkIndex = 0;
- int sourceElementIndex = sourceElementIndexFrom;
- int destinElementIndex = 0;
- ulong leftOver = newRange;
+ //
+ // Variables for the copy process.
+ //
+
+ int sourceChunkIndex = sourceChunkIndexFrom;
+ int destinationChunkIndex = 0;
+ int sourceElementIndex = sourceElementIndexFrom;
+ int destinationElementIndex = 0;
+ ulong leftOverTotal = newRange;
+
do
{
+ //
+ // Determine how many elements we copy next.
+ //
+
uint numberToCopy = 0;
// Case: small number of elements from first chunk only
@@ -105,36 +141,47 @@ namespace Exa
numberToCopy = (uint) (other.maxArrayCapacity - sourceElementIndex);
// Case: multiple chunks + we are in the middle of huge copy process + next chunk does __not__ exist
- else if (next.chunks[destinChunkIndex] == null && sourceElementIndex == 0 && leftOver >= other.maxArrayCapacity)
+ else if (next.chunks[destinationChunkIndex] == null && sourceElementIndex == 0 && leftOverTotal >= other.maxArrayCapacity)
numberToCopy = other.maxArrayCapacity;
// Case: multiple chunks + we are in the middle of huge copy process + next chunk does exist
- else if (next.chunks[destinChunkIndex] != null && sourceElementIndex == 0 && leftOver >= other.maxArrayCapacity)
- numberToCopy = (uint) (other.maxArrayCapacity - next.chunks[destinChunkIndex].Length);
+ else if (next.chunks[destinationChunkIndex] != null && sourceElementIndex == 0 && leftOverTotal >= other.maxArrayCapacity)
+ numberToCopy = (uint) (other.maxArrayCapacity - next.chunks[destinationChunkIndex].Length);
// Case: multiple chunks + this seems to be the last chunk
- else if (sourceElementIndex == 0 && leftOver < other.maxArrayCapacity)
- numberToCopy = (uint) leftOver;
+ else if (sourceElementIndex == 0 && leftOverTotal < other.maxArrayCapacity)
+ numberToCopy = (uint) leftOverTotal;
- if(next.chunks[destinChunkIndex] == null)
- next.chunks[destinChunkIndex] = new T[numberToCopy];
+ //
+ // Can we allocate an entire chunk or do we have to fill up the existing
+ // chunk first?
+ //
+ if(next.chunks[destinationChunkIndex] == null)
+ next.chunks[destinationChunkIndex] = new T[numberToCopy];
else
{
- var extended = new T[next.chunks[destinChunkIndex].Length + numberToCopy];
- Array.Copy(next.chunks[destinChunkIndex], extended, next.chunks[destinChunkIndex].Length);
- next.chunks[destinChunkIndex] = extended;
+ var extended = new T[next.chunks[destinationChunkIndex].Length + numberToCopy];
+ Array.Copy(next.chunks[destinationChunkIndex], extended, next.chunks[destinationChunkIndex].Length);
+ next.chunks[destinationChunkIndex] = extended;
}
- Array.Copy(other.chunks[sourceChunkIndex], sourceElementIndex, next.chunks[destinChunkIndex], destinElementIndex, numberToCopy);
+ // Copy the data:
+ Array.Copy(other.chunks[sourceChunkIndex], sourceElementIndex, next.chunks[destinationChunkIndex], destinationElementIndex, numberToCopy);
- var needNewChunk = next.chunks[destinChunkIndex].Length == next.maxArrayCapacity;
- leftOver -= numberToCopy;
- sourceChunkIndex++;
- destinChunkIndex = needNewChunk ? destinChunkIndex + 1 : destinChunkIndex;
- sourceElementIndex = 0;
- destinElementIndex = (int) (needNewChunk ? 0 : numberToCopy);
+ //
+ // Update the state machine.
+ //
+ var needNewDestinationChunk = next.chunks[destinationChunkIndex].Length == next.maxArrayCapacity;
+ var readNextSourceChunk = sourceElementIndex + numberToCopy == other.maxArrayCapacity;
+ var leftOverCurrentSourceChunk = (int) (readNextSourceChunk ? 0 : other.maxArrayCapacity - sourceElementIndex - numberToCopy);
+
+ leftOverTotal -= numberToCopy;
+ sourceChunkIndex = readNextSourceChunk ? sourceChunkIndex + 1 : sourceChunkIndex;
+ destinationChunkIndex = needNewDestinationChunk ? destinationChunkIndex + 1 : destinationChunkIndex;
+ sourceElementIndex = leftOverCurrentSourceChunk;
+ destinationElementIndex = (int) (needNewDestinationChunk ? 0 : numberToCopy);
- } while (leftOver > 0);
+ } while (leftOverTotal > 0);
return next;
}
}