@joebigelow / wix-1 / commits / 73bd35f5

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 }