private ExaArray2D(SerializationInfo info, StreamingContext context)
        {
            switch (info.GetString("version"))
            {
            case "v1":
                this.sumLengthOrdinates = info.GetUInt64("length");
                this.chunks             = info.GetValue("chunks", typeof(ExaArray1D <ExaArray1D <T> >)) as ExaArray1D <ExaArray1D <T> >;
                break;

            default:
                break;
            }
        }
        /// <summary>
        /// Creates a new ExaArray1D from an enumerable sequence of items. The number of items in the sequence is __unknown__.
        /// </summary>
        /// <remarks>
        /// This factory method is slow because the number of items in the sequence is unknown. When you know the
        /// number of items, you should use another factory method, where the number of items can be provided.
        ///
        /// Performance: O(n)
        /// </remarks>
        /// <param name="sequence">The sequence to consume in order to create the array.</param>
        /// <param name="strategy">The optional optimization strategy.</param>
        /// <returns>The desired instance</returns>
        public static ExaArray1D <T> CreateFrom(IEnumerable <T> sequence, Strategy strategy = Strategy.MAX_PERFORMANCE)
        {
            var   inst     = new ExaArray1D <T>(strategy);
            ulong position = 0;

            foreach (var element in sequence)
            {
                inst.Extend();
                inst[position++] = element;
            }

            return(inst);
        }
        /// <summary>
        /// Creates a new ExaArray1D from a collection of items.
        /// </summary>
        /// <remarks>
        /// Performance: O(n)
        /// </remarks>
        /// <param name="collection">The collection to use</param>
        /// <param name="strategy">The optional optimization strategy.</param>
        /// <returns>The desired instance</returns>
        public static ExaArray1D <T> CreateFrom(ICollection <T> collection, Strategy strategy = Strategy.MAX_PERFORMANCE)
        {
            var inst = new ExaArray1D <T>(strategy);

            inst.Extend((ulong)collection.Count);

            ulong position = 0;

            foreach (var element in collection)
            {
                inst[position++] = element;
            }

            return(inst);
        }
        /// <summary>
        /// Creates a new ExaArray1D from another.
        /// </summary>
        /// <remarks>
        /// When <c>T</c> is a value type, data gets copied as values. When <c>T</c> 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)
        /// </remarks>
        /// <param name="other">The instance from which the new instance is to be created.</param>
        /// <returns>The new instance</returns>
        public static ExaArray1D <T> CreateFrom(ExaArray1D <T> other)
        {
            var next = new ExaArray1D <T>(other.OptimizationStrategy)
            {
                Length = other.Length,
                chunks = new T[other.chunks.Length][]
            };

            for (var n = 0; n < other.chunks.Length; n++)
            {
                next.chunks[n] = new T[other.chunks[n].Length];
                Array.Copy(other.chunks[n], next.chunks[n], other.chunks[n].Length);
            }

            return(next);
        }
        /// <summary>
        /// Creates a new ExaArray1D from another, respecting the given range.
        /// </summary>
        /// <remarks>
        /// When <c>T</c> is a value type, data gets copied as values. When <c>T</c> 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.
        /// </remarks>
        /// <param name="other">The instance from which the new instance is to be created.</param>
        /// <param name="indexFrom">The first source element which should be part of the new array.</param>
        /// <param name="indexTo">The last source element which should be part of the new array.</param>
        /// <returns>The new instance</returns>
        /// <exception cref="IndexOutOfRangeException">Throws, when one or both of the indices are out of range.</exception>
        public static ExaArray1D <T> CreateFrom(ExaArray1D <T> 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 within the range of the source.");
            }

            //
            // Determine the source start chunk and index.
            //
            int sourceChunkIndexTo   = -1;
            int sourceElementIndexTo = -1;

            switch (other.OptimizationStrategy)
            {
            case Strategy.MAX_PERFORMANCE:
                sourceChunkIndexTo   = (int)(indexTo / MAX_CAPACITY_ARRAY_PERFORMANCE);
                sourceElementIndexTo = (int)(indexTo - (ulong)sourceChunkIndexTo * MAX_CAPACITY_ARRAY_PERFORMANCE);
                break;

            case Strategy.MAX_ELEMENTS:
                sourceChunkIndexTo   = (int)(indexTo / MAX_CAPACITY_ARRAY);
                sourceElementIndexTo = (int)(indexTo - (ulong)sourceChunkIndexTo * MAX_CAPACITY_ARRAY);
                break;
            }

            //
            // Determine the source end chunk and index.
            //
            int sourceChunkIndexFrom   = -1;
            int sourceElementIndexFrom = -1;

            switch (other.OptimizationStrategy)
            {
            case Strategy.MAX_PERFORMANCE:
                sourceChunkIndexFrom   = (int)(indexFrom / MAX_CAPACITY_ARRAY_PERFORMANCE);
                sourceElementIndexFrom = (int)(indexFrom - (ulong)sourceChunkIndexFrom * MAX_CAPACITY_ARRAY_PERFORMANCE);
                break;

            case Strategy.MAX_ELEMENTS:
                sourceChunkIndexFrom   = (int)(indexFrom / MAX_CAPACITY_ARRAY);
                sourceElementIndexFrom = (int)(indexFrom - (ulong)sourceChunkIndexFrom * MAX_CAPACITY_ARRAY);
                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)
            {
            case Strategy.MAX_PERFORMANCE:
                destChunks = (int)((newRange - 1) / MAX_CAPACITY_ARRAY_PERFORMANCE) + 1;
                break;

            case Strategy.MAX_ELEMENTS:
                destChunks = (int)((newRange - 1) / MAX_CAPACITY_ARRAY) + 1;
                break;
            }

            // Create the copy and allocate the needed number of outer chunk.
            var next = new ExaArray1D <T>(other.OptimizationStrategy)
            {
                Length = newRange,
                chunks = new T[destChunks][],
            };

            //
            // 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
                if (sourceChunkIndexFrom == sourceChunkIndexTo)
                {
                    numberToCopy = (uint)(sourceElementIndexTo - sourceElementIndexFrom + 1);
                }

                // Case: this is first chunk of multiple chunks + start somewhere in the middle
                else if (sourceElementIndex > 0)
                {
                    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[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[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 && leftOverTotal < other.maxArrayCapacity)
                {
                    numberToCopy = (uint)leftOverTotal;
                }

                //
                // 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[destinationChunkIndex].Length + numberToCopy];
                    Array.Copy(next.chunks[destinationChunkIndex], extended, next.chunks[destinationChunkIndex].Length);
                    next.chunks[destinationChunkIndex] = extended;
                }

                // Copy the data:
                Array.Copy(other.chunks[sourceChunkIndex], sourceElementIndex, next.chunks[destinationChunkIndex], destinationElementIndex, 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 (leftOverTotal > 0);
            return(next);
        }
 /// <summary>
 /// Creates a new ExaArray1D from this instance, respecting the given range.
 /// </summary>
 /// <remarks>
 /// When <c>T</c> is a value type, data gets copied as values. When <c>T</c> 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.
 /// </remarks>
 /// <param name="other">The instance from which the new instance is to be created.</param>
 /// <param name="indexFrom">The first source element which should be part of the new array.</param>
 /// <param name="indexTo">The last source element which should be part of the new array.</param>
 /// <returns>The new instance</returns>
 /// <exception cref="IndexOutOfRangeException">Throws, when one or both of the indices are out of range.</exception>
 public static ExaArray1D <T> Clone <T>(this ExaArray1D <T> other, ulong indexFrom, ulong indexTo) => ExaArray1D <T> .CreateFrom(other, indexFrom, indexTo);
 /// <summary>
 /// Creates a new ExaArray1D from this instance.
 /// </summary>
 /// <remarks>
 /// When <c>T</c> is a value type, data gets copied as values. When <c>T</c> 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)
 /// </remarks>
 /// <param name="other">The instance from which the new instance is to be created.</param>
 /// <returns>The new instance</returns>
 public static ExaArray1D <T> Clone <T>(this ExaArray1D <T> other) => ExaArray1D <T> .CreateFrom(other);
 /// <summary>
 /// Creates a new ExaArray1D from this enumerable sequence of items. The number of items in the sequence is __unknown__.
 /// </summary>
 /// <remarks>
 /// This method is slow because the number of items in this sequence is unknown. When you know the
 /// number of items, you should use another factory method, where the number of items can be provided.
 ///
 /// Performance: O(n)
 /// </remarks>
 /// <param name="sequence">The sequence to consume in order to create the array.</param>
 /// <param name="strategy">The optional optimization strategy.</param>
 /// <returns>The desired instance</returns>
 public static ExaArray1D <T> AsExaArray <T>(this IEnumerable <T> sequence, Strategy strategy = Strategy.MAX_PERFORMANCE) => ExaArray1D <T> .CreateFrom(sequence, strategy);
 /// <summary>
 /// Creates a new ExaArray1D from this collection of items.
 /// </summary>
 /// <remarks>
 /// Performance: O(n)
 /// </remarks>
 /// <param name="collection">The collection to use</param>
 /// <param name="strategy">The optional optimization strategy.</param>
 /// <returns>The desired instance</returns>
 public static ExaArray1D <T> AsExaArray <T>(this ICollection <T> collection, Strategy strategy = Strategy.MAX_PERFORMANCE) => ExaArray1D <T> .CreateFrom(collection, strategy);