public IndexesEnumerator(int[] endIndexes, int[] beginIndexes, bool reverse) { if (endIndexes.Length != beginIndexes.Length) { throw new ArgumentException("UpperBound and LowerBound arrays must have the same length."); } this.endIdxs = (int[])endIndexes.Clone(); this.beginIdxs = (int[])beginIndexes.Clone(); this.reverse = reverse; if ((reverse && IndexesHelper.Less(this.endIdxs, this.beginIdxs)) || (!reverse && IndexesHelper.Less(this.beginIdxs, this.endIdxs))) { this.currentIdxs = (int[])beginIndexes.Clone(); if (reverse) { ++this.currentIdxs[this.currentIdxs.Length - 1]; } else { --this.currentIdxs[this.currentIdxs.Length - 1]; } } else { // NOTE do pervent enumeration this.currentIdxs = this.endIdxs; } }
/// <summary> Resizes the <see cref="DynamicArray{T}"/> to the given new counts. </summary> /// <param name="newCounts"> The new lengths of the <see ref="DynamicArray{T}"/>. </param> /// <remarks> If the <paramref name="newCounts"/> ith element is larger than the ith count, the new added /// elements are set to <c>default(<typeparamref name="T"/>)</c>. If <paramref name="newCounts"/> ith element /// is less then the ith count, the <see ref="DynamicArray{T}"/> is shrank to fit to the new count value, /// and the removed elements will be lost. </remarks> public void Resize(params int[] newCounts) { this.CheckIndexesLength(newCounts); if (IndexesHelper.ElementsEqual(this.counts, newCounts)) { return; } int[] oldCounts = IndexesHelper.Clone(this.counts); this.UpdateCountsAndCapacities(IndexesHelper.Add(newCounts, -1)); for (int dim = 0; dim < this.Rank; ++dim) { // NOTE When this.buffer is shrank dismissed values are reset to default(T) IndexesEnumerator ienum = new IndexesEnumerator( IndexesHelper.TakeMinOnIthDim(oldCounts, newCounts, dim - 1), IndexesHelper.ProjectOnIthDim(newCounts, dim)); foreach (int[] indexes in ienum) { this.buffer.SetValue(default(T), indexes); } } Array.Copy(newCounts, this.counts, this.counts.Length); ++this.changeCount; }
/// <summary> Strongly typed implementation of <see cref="ICollection{T}.CopyTo"/>. </summary> /// <param name="darray"> The <see cref="DynamicArray{T}"/> where to copy the values. </param> /// <param name="indexes">The zero-based indexes offset in darray at which copying begins. </param> public void CopyTo(DynamicArray <T> darray, params int[] indexes) { DynamicArrayEnumerator <T> enumerator = this.GetEnumerator(); foreach (T elt in enumerator) { darray.SetValue(elt, IndexesHelper.Add(enumerator.GetIndexes(), indexes)); } }
/// <summary> /// Initializes a new instance of the <see cref="DynamicArray{T}"/> class. If a capcity is omitted the /// <see cref="DEFAULTCAPACITY"/> is used for the missing dimension capacity. /// </summary> /// <param name="rank"> The dynamic array rank. </param> /// <param name="capacities"> The capacities to be used for the underlying buffer. </param> public DynamicArray(int rank, params int[] capacities) { this.counts = IndexesHelper.Zero(rank); int[] usedCapacities = IndexesHelper.Zero(rank); for (int i = 0; i < rank; ++i) { usedCapacities[i] = (i < capacities.Length ? capacities[i] : DEFAULTCAPACITY); } // NOTE will throw an ArgumentException if rank<1 this.buffer = Array.CreateInstance(typeof(T), usedCapacities); }
/// <summary> /// Ensures the given indexes falls into the lengths and capacities of the underlying array. If not, the /// capacities and lengths are updated accordingly. A new underlyting array may be allocated in order to adapt /// capacities. /// </summary> /// <param name="indexes"> The indexes that must fall within the array. </param> private void UpdateCountsAndCapacities(int[] indexes) { int[] newCounts = IndexesHelper.Zero(this.Rank); int[] newCapacities = IndexesHelper.Zero(this.Rank); bool newArrayNeeded = false; bool newCountsNeeded = false; for (int dimension = 0; dimension < this.Rank; ++dimension) { int requestedIndex = indexes[dimension]; int currentCapacity = this.GetCapacity(dimension); int currentCount = this.GetCount(dimension); newCounts[dimension] = currentCount; newCapacities[dimension] = currentCapacity; if (requestedIndex < currentCount) { continue; } newCountsNeeded = true; newCounts[dimension] = requestedIndex + 1; if (newCounts[dimension] <= currentCapacity) { continue; } newCapacities[dimension] = Math.Max(2 * currentCapacity, newCounts[dimension]); newArrayNeeded = true; } if (!newCountsNeeded) { return; } if (newArrayNeeded) { Array newData = Array.CreateInstance(typeof(T), newCapacities); IndexesEnumerator ienum = new IndexesEnumerator(IndexesHelper.UpperBound(this.buffer)); foreach (int[] idx in ienum) { newData.SetValue(this.buffer.GetValue(idx), idx); } this.buffer = newData; } // NOTE New lengths are set after allocation to avoid lengths corruption on failure. Array.Copy(newCounts, this.counts, this.counts.Length); }
/// <summary> /// Inserts the given <see cref="Array"/> within the given dimension and at the given position. /// </summary> /// <param name="arr"> An array to insert in the <see cref="DynamicArray{T}"/>. /// It must be not <see langword="null"/> and it must have a rank equal to <see cref="DynamicArray{T}.Rank"/>. /// </param> /// <param name="dimension"> The dimension where the elements of the <paramref name="arr"/> will be inserted. /// </param> /// <param name="indexes"> The position where the first element of the <paramref name="arr"/> will be inserted. /// </param> /// <exception cref="RankException"> If <paramref name="arr"/> has a rank not equal to /// <see cref="DynamicArray{T}.Rank"/>.</exception> /// <exception cref="ArgumentException"> If <paramref name="arr"/> has one of its lengths equal to zero. /// </exception> /// <exception cref="NullReferenceException"> If arr is <see langword="null"/></exception> public void Insert(Array arr, int dimension, params int[] indexes) { this.CheckIndexesLength(indexes); if (arr.Rank != this.Rank) { throw new RankException("Inserted array must have the same rank as this array"); } for (int dim = 0; dim < this.Rank; ++dim) { if (arr.GetLength(dim) > 0) { continue; } throw new ArgumentException("Inserted array must have non null lengths.", "arr"); } int[] oldCounts = IndexesHelper.Clone(this.counts); int dataCount = arr.GetLength(dimension); int[] lastIndices = IndexesHelper.Add(indexes, IndexesHelper.MaxIndexes(arr)); lastIndices[dimension] = Math.Max(oldCounts[dimension], indexes[dimension]) + dataCount - 1; this.UpdateCountsAndCapacities(lastIndices); int[] rangeLowerBound = IndexesHelper.Add(indexes, -1); if (indexes[dimension] < oldCounts[dimension]) { int[] rangeMax = IndexesHelper.Add(IndexesHelper.MaxIndexes(arr), indexes); rangeMax[dimension] = oldCounts[dimension] - 1; var rangeToMove = new IndexesEnumerator(rangeLowerBound, rangeMax, true); foreach (int[] source in rangeToMove) { int[] destination = IndexesHelper.Clone(source); destination[dimension] += dataCount; this.buffer.SetValue(this.buffer.GetValue(source), destination); } } foreach (int[] source in IndexesEnumerator.Enumerate(arr)) { int[] destination = IndexesHelper.Add(source, indexes); this.buffer.SetValue(arr.GetValue(source), destination); } ++this.changeCount; }
public bool MoveNext() { return(this.reverse ? IndexesHelper.Dec(this.currentIdxs, this.endIdxs, this.beginIdxs) : IndexesHelper.Inc(this.currentIdxs, this.endIdxs, this.beginIdxs)); }
public static IndexesEnumerator Enumerate(Array arr, bool reverse) { return(new IndexesEnumerator(IndexesHelper.UpperBound(arr), IndexesHelper.Zero(arr.Rank), reverse)); }
public IndexesEnumerator(int[] upperBound) : this(upperBound, IndexesHelper.Zero(upperBound.Length), false) { }
/// <summary> /// Resizes the <see cref="DynamicArray{T}"/> by adding each ith given value to the corresponding ith dimension. /// </summary> /// <param name="addedCounts"> The amounts to add to each dimension count. </param> public void Extend(params int[] addedCounts) { this.CheckIndexesLength(addedCounts); this.Resize(IndexesHelper.Add(this.counts, addedCounts)); }