diff --git a/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs index 6977997b31..5509581601 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs @@ -308,7 +308,7 @@ namespace Debugger.AddIn Value Visit(ArrayAccessResolveResult result) { var val = Convert(result.Array).GetPermanentReference(evalThread); - return val.GetArrayElement(result.Indexes.Select(rr => (int)Convert(rr).PrimitiveValue).ToArray()); + return val.GetArrayElement(result.Indexes.Select(rr => (uint)(int)Convert(rr).PrimitiveValue).ToArray()); } Value Visit(ArrayCreateResolveResult result) @@ -390,10 +390,11 @@ namespace Debugger.AddIn sb.Append(val.Type.Name); sb.Append(" {"); bool first = true; - foreach(Value item in val.GetArrayElements()) { + int size = val.ArrayLength; + for (int i = 0; i < size; i++) { if (!first) sb.Append(", "); first = false; - sb.Append(FormatValue(evalThread, item)); + sb.Append(FormatValue(evalThread, val.GetElementAtPosition(i))); } sb.Append("}"); return sb.ToString(); diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs index f2702d97c3..682bc6cbfa 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs @@ -109,9 +109,10 @@ namespace Debugger.AddIn.TreeModel } else if (val.Type.IsPrimitiveType() || val.Type.IsKnownType(KnownTypeCode.String)) { // Must be before IsClass this.GetChildren = null; } else if (val.Type.Kind == TypeKind.Array) { // Must be before IsClass - var dims = val.ArrayDimensions; // Eval now - if (dims.TotalElementCount > 0) { - this.GetChildren = () => GetArrayChildren(dims, dims); + var dimBase = val.ArrayBaseIndicies; // Eval now + var dimSize = val.ArrayDimensions; // Eval now + if (val.ArrayLength > 0) { + this.GetChildren = () => GetArrayChildren(dimBase, dimSize); } } else if (val.Type.Kind == TypeKind.Class || val.Type.Kind == TypeKind.Struct) { if (val.Type.IsKnownType(typeof(List<>))) { @@ -373,83 +374,87 @@ namespace Debugger.AddIn.TreeModel } } - TreeNode GetArraySubsetNode(ArrayDimensions bounds, ArrayDimensions originalBounds) - { - StringBuilder name = new StringBuilder(); - bool isFirst = true; - name.Append("["); - for(int i = 0; i < bounds.Count; i++) { - if (!isFirst) name.Append(", "); - isFirst = false; - ArrayDimension dim = bounds[i]; - ArrayDimension originalDim = originalBounds[i]; - - if (dim.Count == 0) { - name.Append("-"); - } else if (dim.Count == 1) { - name.Append(dim.LowerBound.ToString()); - } else if (dim.Equals(originalDim)) { - name.Append("*"); - } else { - name.Append(dim.LowerBound); - name.Append(".."); - name.Append(dim.UpperBound); - } - } - name.Append("]"); - - return new TreeNode(name.ToString(), () => GetArrayChildren(bounds, originalBounds)); - } - - IEnumerable GetArrayChildren(ArrayDimensions bounds, ArrayDimensions originalBounds) + IEnumerable GetArrayChildren(uint[] dimBase, uint[] dimSize) { const int MaxElementCount = 100; - if (bounds.TotalElementCount == 0) + int rank = dimSize.Length; + uint totalSize = dimSize.Aggregate((uint)1, (acc, s) => acc * s); + + if (totalSize == 0) { yield return new TreeNode("(empty)", null); yield break; } - // The whole array is small - just add all elements as childs - if (bounds.TotalElementCount <= MaxElementCount * 2) { - foreach(int[] indices in bounds.Indices) { - StringBuilder sb = new StringBuilder(indices.Length * 4); - sb.Append("["); + // The array is small - just add all elements as children + StringBuilder sb = new StringBuilder(); + if (totalSize <= MaxElementCount) { + uint[] indices = (uint[])dimBase.Clone(); + while(indices[0] < dimBase[0] + dimSize[0]) { + // Make element name + sb.Clear(); + sb.Append('['); bool isFirst = true; foreach(int index in indices) { if (!isFirst) sb.Append(", "); - sb.Append(index.ToString()); + sb.Append(index); isFirst = false; } - sb.Append("]"); - int[] indicesCopy = indices; + sb.Append(']'); + + // The getValue delegate might be called later or several times + uint[] indicesCopy = (uint[])indices.Clone(); yield return new ValueNode(ClassBrowserIconService.Field, sb.ToString(), () => GetValue().GetArrayElement(indicesCopy)); + + // Get next combination + indices[rank - 1]++; + for (int i = rank - 1; i > 0; i--) { + if (indices[i] >= dimBase[i] + dimSize[i]) { + indices[i] = dimBase[i]; + indices[i - 1]++; + } + } } yield break; } - // Find a dimension of size at least 2 - int splitDimensionIndex = bounds.Count - 1; - for(int i = 0; i < bounds.Count; i++) { - if (bounds[i].Count > 1) { - splitDimensionIndex = i; - break; - } + // Split the array into smaller subsets + int splitIndex = Array.FindIndex(dimSize, s => (s > 1)); + uint groupSize = 1; + while (dimSize[splitIndex] > groupSize * MaxElementCount) { + groupSize *= MaxElementCount; } - ArrayDimension splitDim = bounds[splitDimensionIndex]; - - // Split the dimension - int elementsPerSegment = 1; - while (splitDim.Count > elementsPerSegment * MaxElementCount) { - elementsPerSegment *= MaxElementCount; - } - for(int i = splitDim.LowerBound; i <= splitDim.UpperBound; i += elementsPerSegment) { - List newDims = new List(bounds); - newDims[splitDimensionIndex] = new ArrayDimension(i, Math.Min(i + elementsPerSegment - 1, splitDim.UpperBound)); - yield return GetArraySubsetNode(new ArrayDimensions(newDims), originalBounds); + for(uint i = dimBase[splitIndex]; i < dimBase[splitIndex] + dimSize[splitIndex]; i += groupSize) { + // Get the base&size for the subset + uint[] newDimBase = (uint[])dimBase.Clone(); + uint[] newDimSize = (uint[])dimSize.Clone(); + newDimBase[splitIndex] = i; + newDimSize[splitIndex] = Math.Min(groupSize, dimBase[splitIndex] + dimSize[splitIndex] - i); + + // Make the subset name + sb.Clear(); + sb.Append('['); + bool isFirst = true; + for (int j = 0; j < rank; j++) { + if (!isFirst) sb.Append(", "); + if (j < splitIndex) { + sb.Append(newDimBase[j]); + } else if (j == splitIndex) { + sb.Append(i); + if (newDimSize[splitIndex] > 1) { + sb.Append(".."); + sb.Append(i + newDimSize[splitIndex] - 1); + } + } else if (j > splitIndex) { + sb.Append('*'); + } + isFirst = false; + } + sb.Append(']'); + + yield return new TreeNode(sb.ToString(), () => GetArrayChildren(newDimBase, newDimSize)); } - yield break; } } } diff --git a/src/AddIns/Debugger/Debugger.Core/ArrayDimension.cs b/src/AddIns/Debugger/Debugger.Core/ArrayDimension.cs deleted file mode 100644 index 2d8ec3156d..0000000000 --- a/src/AddIns/Debugger/Debugger.Core/ArrayDimension.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; - -namespace Debugger -{ - /// - /// Specifies the range of valid indicies for an array dimension - /// - public class ArrayDimension - { - int lowerBound; - int upperBound; - - /// The smallest valid index in this dimension - public int LowerBound { - get { return lowerBound; } - } - - /// The largest valid index in this dimension. - /// Returns LowerBound - 1 if the array is empty. - public int UpperBound { - get { return upperBound; } - } - - /// The number of valid indicies of this dimension - public int Count { - get { return upperBound - lowerBound + 1; } - } - - /// Determines whether the given index is a valid index for this dimension - public bool IsIndexValid(int index) - { - return (this.LowerBound <= index && index <= this.UpperBound); - } - - public ArrayDimension(int lowerBound, int upperBound) - { - this.lowerBound = lowerBound; - this.upperBound = upperBound; - } - - public override string ToString() - { - if (this.LowerBound == 0) { - return this.Count.ToString(); - } else { - return this.LowerBound + ".." + this.UpperBound; - } - } - - public override int GetHashCode() - { - int hashCode = 0; - unchecked { - hashCode += 1000000007 * lowerBound.GetHashCode(); - hashCode += 1000000009 * upperBound.GetHashCode(); - } - return hashCode; - } - - public override bool Equals(object obj) - { - ArrayDimension other = obj as ArrayDimension; - if (other == null) return false; - return this.lowerBound == other.lowerBound && this.upperBound == other.upperBound; - } - } -} diff --git a/src/AddIns/Debugger/Debugger.Core/ArrayDimensions.cs b/src/AddIns/Debugger/Debugger.Core/ArrayDimensions.cs deleted file mode 100644 index b7973bf872..0000000000 --- a/src/AddIns/Debugger/Debugger.Core/ArrayDimensions.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Debugger -{ - /// - /// Specifies the range of valid indicies for all array dimensions - /// - public class ArrayDimensions: IEnumerable - { - List dimensions = new List(); - - public IEnumerator GetEnumerator() - { - return dimensions.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)dimensions).GetEnumerator(); - } - - /// Gets a given dimension - public ArrayDimension this[int index] { - get { - return dimensions[index]; - } - } - - /// Get the number of dimensions of the array - public int Count { - get { - return dimensions.Count; - } - } - - /// Get the total number of elements within the bounds - /// of an array specified by these dimensions. - public int TotalElementCount { - get { - int totalCount = 1; - foreach(ArrayDimension dim in this) { - totalCount *= dim.Count; - } - return totalCount; - } - } - - /// Enumerate all vaild indicies in the array - public IEnumerable Indices { - get { - foreach(ArrayDimension dim in this) { - if (dim.Count == 0) yield break; - } - - int rank = this.Count; - int[] indices = new int[rank]; - for(int i = 0; i < rank; i++) { - indices[i] = this[i].LowerBound; - } - - while(true) { // Go thought all combinations - for (int i = rank - 1; i >= 1; i--) { - if (indices[i] > this[i].UpperBound) { - indices[i] = this[i].LowerBound; - indices[i - 1]++; - } - } - if (indices[0] > this[0].UpperBound) yield break; // We are done - - yield return (int[])indices.Clone(); - - indices[rank - 1]++; - } - } - } - - /// Determines whether the given index is a valid index for the array - public bool IsIndexValid(int[] indices) - { - for (int i = 0; i < this.Count; i++) { - if (!this[i].IsIndexValid(indices[i])) return false; - } - return true; - } - - public ArrayDimensions(List dimensions) - { - this.dimensions = dimensions; - } - - public override string ToString() - { - string result = "["; - bool isFirst = true; - foreach(ArrayDimension dim in this) { - if (!isFirst) result += ", "; - result += dim.ToString(); - isFirst = false; - } - result += "]"; - return result; - } - } -} diff --git a/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj b/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj index 6e70907bf1..7e85b22727 100644 --- a/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj +++ b/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj @@ -64,8 +64,6 @@ - - diff --git a/src/AddIns/Debugger/Debugger.Core/Value.cs b/src/AddIns/Debugger/Debugger.Core/Value.cs index 4bb8c7742c..47edbdd767 100644 --- a/src/AddIns/Debugger/Debugger.Core/Value.cs +++ b/src/AddIns/Debugger/Debugger.Core/Value.cs @@ -297,10 +297,7 @@ namespace Debugger #region Array - /// - /// Gets the number of elements in the array. - /// eg new object[4,5] returns 20 - /// + /// Gets the number of elements in the array. (eg new object[4,5] returns 20) /// 0 for non-arrays public int ArrayLength { get { @@ -309,10 +306,7 @@ namespace Debugger } } - /// - /// Gets the number of dimensions of the array. - /// eg new object[4,5] returns 2 - /// + /// Gets the number of dimensions of the array. (eg new object[4,5] returns 2) /// 0 for non-arrays public int ArrayRank { get { @@ -321,73 +315,58 @@ namespace Debugger } } - /// Gets the dimensions of the array - /// null for non-arrays - public ArrayDimensions ArrayDimensions { + /// Returns the lowest allowed index for each dimension. Generally zero. + public uint[] ArrayBaseIndicies { get { if (this.Type.Kind != TypeKind.Array) return null; - int rank = this.ArrayRank; - uint[] baseIndicies; if (CorArrayValue.HasBaseIndicies() == 1) { - baseIndicies = CorArrayValue.GetBaseIndicies(); + return CorArrayValue.GetBaseIndicies(); } else { - baseIndicies = new uint[this.ArrayRank]; - } - uint[] dimensionCounts = CorArrayValue.GetDimensions(); - - List dimensions = new List(); - for(int i = 0; i < rank; i++) { - dimensions.Add(new ArrayDimension((int)baseIndicies[i], (int)baseIndicies[i] + (int)dimensionCounts[i] - 1)); + return new uint[this.ArrayRank]; } - - return new ArrayDimensions(dimensions); + } + } + + /// Returns the number of elements in each dimension + public uint[] ArrayDimensions { + get { + if (this.Type.Kind != TypeKind.Array) return null; + return CorArrayValue.GetDimensions(); } } /// Returns an element of a single-dimensional array public Value GetArrayElement(int index) { - return GetArrayElement(new int[] {index}); + return GetArrayElement(new uint[] { (uint)index }); } /// Returns an element of an array - public Value GetArrayElement(int[] elementIndices) + public Value GetArrayElement(uint[] indices) { - int[] indices = (int[])elementIndices.Clone(); - - return new Value(this.AppDomain, GetCorValueOfArrayElement(indices)); + try { + return new Value(this.AppDomain, CorArrayValue.GetElement(indices)); + } catch (ArgumentException) { + throw new GetValueException("Invalid array index"); + } } - // May be called later - ICorDebugValue GetCorValueOfArrayElement(int[] indices) + /// Returns an element of an array (treats the array as zero-based and single dimensional) + public Value GetElementAtPosition(int index) { - if (indices.Length != ArrayRank) { - throw new GetValueException("Given indicies do not have the same dimension as array."); - } - if (!this.ArrayDimensions.IsIndexValid(indices)) { - throw new GetValueException("Given indices are out of range of the array"); + try { + return new Value(this.AppDomain, CorArrayValue.GetElementAtPosition((uint)index)); + } catch (ArgumentException) { + throw new GetValueException("Invalid array index"); } - - return CorArrayValue.GetElement(indices); } - public void SetArrayElement(Thread evalThread, int[] elementIndices, Value newVal) + public void SetArrayElement(Thread evalThread, uint[] elementIndices, Value newVal) { Value elem = GetArrayElement(elementIndices); elem.SetValue(evalThread, newVal); } - /// Returns all elements in the array - public Value[] GetArrayElements() - { - if (this.Type.Kind != TypeKind.Array) return null; - List values = new List(); - foreach(int[] indices in this.ArrayDimensions.Indices) { - values.Add(GetArrayElement(indices)); - } - return values.ToArray(); - } - #endregion #region Object diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs index 5610668f8d..35b2ad912a 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs @@ -46,7 +46,7 @@ namespace Debugger.Tests { Value lbArray = this.CurrentStackFrame.GetLocalVariableValue("lbArray").GetPermanentReference(this.EvalThread); ObjectDump("lbArray", lbArray); - ObjectDump("lbArray-10-20", lbArray.GetArrayElement(new int[] {10, 20})); + ObjectDump("lbArray-10-20", lbArray.GetArrayElement(new uint[] {10, 20})); EndTest(); } @@ -108,20 +108,20 @@ namespace Debugger.Tests {