Optimize SourceLineNumber and add support for setting Parent
Rob Mensching committed
Mar 1, 2021 at 23:23 UTC
73bd35f56189da4e9f5aaf4625247078e0486887
1 file changed
+80
-43
src/WixToolset.Data/SourceLineNumber.cs
+80
-43
@@ -34,11 +34,35 @@ namespace WixToolset.Data
34
this.LineNumber = lineNumber;
35
}
36
37
+ /// <summary>
38
+ /// Constructor for a source with a parent and no line information.
39
+ /// </summary>
40
+ /// <param name="fileName">File name of the source.</param>
41
+ /// <param name="parent">Parent of this source line number</param>
42
+ public SourceLineNumber(string fileName, SourceLineNumber parent)
43
+ {
44
+ this.FileName = fileName;
45
+ this.Parent = parent;
46
+ }
47
+
48
+ /// <summary>
49
+ /// Constructor for a source with a parent and line information.
50
+ /// </summary>
51
+ /// <param name="fileName">File name of the source.</param>
52
+ /// <param name="parent">Parent of this source line number</param>
53
+ /// <param name="lineNumber">Line number of the source.</param>
54
+ public SourceLineNumber(string fileName, SourceLineNumber parent, int lineNumber)
55
+ {
56
+ this.FileName = fileName;
57
+ this.Parent = parent;
58
+ this.LineNumber = lineNumber;
59
+ }
60
+
61
/// <summary>
62
/// Gets the file name of the source.
63
/// </summary>
64
/// <value>File name for the source.</value>
41
- public string FileName { get; private set; }
65
+ public string FileName { get; }
66
67
/// <summary>
68
/// Gets or sets the line number of the source.
@@ -49,19 +73,13 @@ namespace WixToolset.Data
73
/// <summary>
74
/// Gets or sets the parent source line number that included this source line number.
75
/// </summary>
52
- public SourceLineNumber Parent { get; set; }
76
+ public SourceLineNumber Parent { get; private set; }
77
78
/// <summary>
79
/// Gets the file name and line information.
80
/// </summary>
81
/// <value>File name and line information.</value>
58
- public string QualifiedFileName
59
- {
60
- get
61
- {
62
- return this.LineNumber.HasValue ? String.Concat(this.FileName, "*", this.LineNumber) : this.FileName;
63
- }
64
- }
82
+ public string QualifiedFileName => this.LineNumber.HasValue ? String.Concat(this.FileName, "*", this.LineNumber) : this.FileName;
83
84
internal static SourceLineNumber Deserialize(JsonObject jsonObject)
85
{
@@ -101,37 +119,46 @@ namespace WixToolset.Data
119
/// <param name="encodedSourceLineNumbers">Encoded string to parse.</param>
120
public static SourceLineNumber CreateFromEncoded(string encodedSourceLineNumbers)
121
{
104
- string[] linesSplit = encodedSourceLineNumbers.Split('|');
122
+ var linesSplitIndex = encodedSourceLineNumbers.IndexOf('|');
123
106
- SourceLineNumber first = null;
107
- SourceLineNumber parent = null;
108
- for (int i = 0; i < linesSplit.Length; ++i)
124
+ // The most common case is that there is a single encoded line,
125
+ // so optimize for that case.
126
+ if (linesSplitIndex < 0)
127
{
110
- string[] filenameSplit = linesSplit[i].Split('*');
111
- SourceLineNumber source;
112
-
113
- if (2 == filenameSplit.Length)
114
- {
115
- source = new SourceLineNumber(filenameSplit[0], Convert.ToInt32(filenameSplit[1]));
116
- }
117
- else
118
- {
119
- source = new SourceLineNumber(filenameSplit[0]);
120
- }
128
+ return DecodeSourceLineNumber(encodedSourceLineNumbers, 0, -1);
129
+ }
130
+ else // decode the multiple lines.
131
+ {
132
+ var startLine = 0;
133
122
- if (null != parent)
134
+ SourceLineNumber first = null;
135
+ SourceLineNumber parent = null;
136
+ while (startLine < encodedSourceLineNumbers.Length)
137
{
124
- parent.Parent = source;
138
+ var source = DecodeSourceLineNumber(encodedSourceLineNumbers, startLine, linesSplitIndex - 1);
139
+
140
+ if (null != parent)
141
+ {
142
+ parent.Parent = source;
143
+ }
144
+
145
+ parent = source;
146
+ if (null == first)
147
+ {
148
+ first = parent;
149
+ }
150
+
151
+ if (linesSplitIndex < 0)
152
+ {
153
+ break;
154
+ }
155
+
156
+ startLine = linesSplitIndex + 1;
157
+ linesSplitIndex = encodedSourceLineNumbers.IndexOf('|', startLine);
158
}
159
127
- parent = source;
128
- if (null == first)
129
- {
130
- first = parent;
131
- }
160
+ return first;
161
}
133
-
134
- return first;
162
}
163
164
/// <summary>
@@ -159,11 +186,8 @@ namespace WixToolset.Data
186
/// <param name="offset">Optional line number offset into XML file not already included in the line information.</param>
187
public static SourceLineNumber CreateFromXObject(XObject node, int offset = 0)
188
{
162
- string uri = node.BaseUri;
163
- IXmlLineInfo lineInfo = node as IXmlLineInfo;
164
-
165
- SourceLineNumber result = CreateFromUri(uri);
166
- if (null != result && null != lineInfo)
189
+ var result = CreateFromUri(node.BaseUri);
190
+ if (null != result && node is IXmlLineInfo lineInfo)
191
{
192
result.LineNumber = lineInfo.LineNumber + offset;
193
}
@@ -191,12 +215,12 @@ namespace WixToolset.Data
215
/// </summary>
216
public string GetEncoded()
217
{
194
- StringBuilder sb = new StringBuilder(this.QualifiedFileName);
218
+ var sb = new StringBuilder(this.QualifiedFileName);
219
196
- for (SourceLineNumber source = this.Parent; null != source; source = source.Parent)
220
+ for (var parent = this.Parent; null != parent; parent = parent.Parent)
221
{
222
sb.Append("|");
199
- sb.Append(source.QualifiedFileName);
223
+ sb.Append(parent.QualifiedFileName);
224
}
225
226
return sb.ToString();
@@ -209,8 +233,7 @@ namespace WixToolset.Data
233
/// <returns>True if SourceLineNumbers are equivalent.</returns>
234
public override bool Equals(object obj)
235
{
212
- SourceLineNumber other = obj as SourceLineNumber;
213
- return null != other &&
236
+ return obj is SourceLineNumber other &&
237
this.LineNumber.HasValue == other.LineNumber.HasValue &&
238
(!this.LineNumber.HasValue || this.LineNumber == other.LineNumber) &&
239
this.FileName.Equals(other.FileName, StringComparison.OrdinalIgnoreCase) &&
@@ -234,5 +257,19 @@ namespace WixToolset.Data
257
{
258
return this.LineNumber.HasValue && !String.IsNullOrEmpty(this.FileName) ? String.Concat(this.FileName, "(", this.LineNumber, ")") : this.FileName ?? String.Empty;
259
}
260
+
261
+ private static SourceLineNumber DecodeSourceLineNumber(string encoded, int startIndex, int endIndex)
262
+ {
263
+ if (endIndex < 0)
264
+ {
265
+ endIndex = encoded.Length - 1;
266
+ }
267
+
268
+ var count = endIndex - startIndex;
269
+ var filenameSplitIndex = encoded.LastIndexOf('*', endIndex - 1, count);
270
+ return (filenameSplitIndex < 0) ? new SourceLineNumber(encoded) :
271
+ new SourceLineNumber(encoded.Substring(startIndex, filenameSplitIndex - startIndex),
272
+ Convert.ToInt32(encoded.Substring(filenameSplitIndex + 1, endIndex - filenameSplitIndex)));
273
+ }
274
}
275
}