Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Code used in benchmark tests for StringResourceVisualizer when reviewing cahnging string manipulation to use Span<T>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace StrResVizBenchmarks
{
class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<StringResourceVisualizerPerf>();
Console.ReadKey(true);
}
}
public class StringResourceVisualizerPerf
{
private const string FileText = @"
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
namespace StringResourceVisualizer
{
/// <summary>
/// Resizes relevant lines in the editor.
/// </summary>
internal class MyLineTransformSource : ILineTransformSource
{
private readonly ResourceAdornmentManager manager;
public MyLineTransformSource(ResourceAdornmentManager manager)
{
Debug.WriteLine(Resources1.CreatedMyLineTransformSource);
this.manager = manager;
}
LineTransform ILineTransformSource.GetLineTransform(ITextViewLine line, double yPosition, ViewRelativePosition placement)
{
Debug.WriteLine(Resources1.Info_TransformLine);
int lineNumber = line.Snapshot.GetLineFromPosition(line.Start.Position).LineNumber;
LineTransform lineTransform;
// TODO: Don't show if line is collapsed. Issue #3
if (this.manager.DisplayedTextBlocks.ContainsKey(lineNumber))
{
var defaultTopSpace = line.DefaultLineTransform.TopSpace;
var defaultBottomSpace = line.DefaultLineTransform.BottomSpace;
lineTransform = new LineTransform(defaultTopSpace + ResourceAdornmentManager.TextSize, defaultBottomSpace, 1.0);
}
else
{
lineTransform = new LineTransform(0, 0, 1.0);
}
return lineTransform;
}
}
}
";
public List<(string path, Dictionary<string, string> xDoc)> FakeXmlDocs
{
get
{
var result = new List<(string path, Dictionary<string, string> xDoc)>
{
("c:\\path\\to\\Resources.resx",
new Dictionary<string, string>
{
{"Name1", "some value1"},
{"Nam2", "some value2"},
{"Name3", "some value3"},
}),
("c:\\path\\to\\Resources1.resx",
new Dictionary<string, string>
{
{"Name1", "some value1"},
{"Nam2", "some value2"},
{"Name3", "some value3"},
{"CreatedMyLineTransformSource", "some value"},
{"Info_TransformLine", "some value"},
}),
("c:\\path\\to\\Resources2.resx",
new Dictionary<string, string>
{
{"Name1", "some value1"},
{"Nam2", "some value2"},
{"Name3", "some value3"},
}),
("c:\\path\\to\\other\\Resources.resx",
new Dictionary<string, string>
{
{"Name1", "some other value1"},
{"Nam2", "some other value2"},
{"Name3", "some other value3"},
}),
("c:\\path\\to\\other\\Resources1.resx",
new Dictionary<string, string>
{
{"Name1", "some other value1"},
{"Nam2", "some other value2"},
{"Name3", "some other value3"},
{"CreatedMyLineTransformSource", "some other value"},
{"Info_TransformLine", "some other value"},
}),
};
return result;
}
////if (xmlDocs == null)////{//// try//// {//// xmlDocs = new List<(string, XmlDocument)>();//// foreach (var resourceFile in ResourceFiles)//// {//// var xdoc = new XmlDocument();//// xdoc.Load(resourceFile);//// xmlDocs.Add((resourceFile, xdoc));//// }//// }//// catch (Exception exc)//// {//// Debug.WriteLine(exc);//// }////}////return xmlDocs;
}
[Benchmark]
public void UsingString()
{
var fileLines = FileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
var searchTexts = new string[] { "Resources.", "Resources1.", "Resurces2.", "Resources.", "Resources1." };
for (int i = 0; i < fileLines.Length; i++)
{
ProcessLineWithString(fileLines[i], searchTexts);
}
}
// Equivalent to the interesting bits of CreateVisuals
private void ProcessLineWithString(string lineText, string[] searchTexts)
{
int matchIndex = lineText.IndexOfAny(searchTexts);
if (matchIndex >= 0)
{
var endPos = lineText.IndexOfAny(new[] { ' ', '.', '"', '(', ')' }, lineText.IndexOf('.', matchIndex) + 1);
string foundText;
if (endPos > matchIndex)
{
foundText = lineText.Substring(matchIndex, endPos - matchIndex);
}
else
{
foundText = lineText.Substring(matchIndex);
}
string displayText = null;
var resourceName = foundText.Substring(foundText.IndexOf('.') + 1);
foreach (var (path, xDoc) in FakeXmlDocs)
{
if (foundText.StartsWith($"{Path.GetFileNameWithoutExtension(path)}."))
{
foreach (var element in xDoc)
{
if (element.Key == resourceName)
{
displayText = element.Value;
break;
}
}
}
}
if (!string.IsNullOrWhiteSpace(displayText))
{
//Console.WriteLine($"Create TextBlock for '{displayText}'");
}
}
}
[Benchmark]
public void UsingSpanChar()
{
var fileLines = FileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
var searchTexts = new List<string> { "Resources.", "Resources1.", "Resurces2.", "Resources.", "Resources1." };
for (int i = 0; i < fileLines.Length; i++)
{
ProcessLineWithSpanChar(fileLines[i], searchTexts);
}
}
// This was created for benchmarking
// second parameter is still strings as can't use `ReadOnlySpan<char>` as a type parameter (i.e. `List<ReadOnlySpan<char>>` is invalid)
private void ProcessLineWithSpanChar(string lineText, List<string> searchTexts)
{
// TODO Change here
int matchIndex = lineText.AsSpan().IndexOfAnySpan(searchTexts);
if (matchIndex >= 0)
{
// TODO Change here
var endPos = lineText.AsSpan().IndexOfAnySpan(new[] { ' ', '.', '"', '(', ')' }, lineText.IndexOf('.', matchIndex) + 1);
ReadOnlySpan<char> foundText;
if (endPos > matchIndex)
{
foundText = lineText.AsSpan().Slice(matchIndex, endPos - matchIndex);
}
else
{
// TODO Change here
foundText = lineText.AsSpan().Slice(matchIndex);
}
string displayText = null;
// TODO Change here
var resourceName = foundText.Slice(foundText.IndexOf('.') + 1);
foreach (var (path, xDoc) in FakeXmlDocs)
{
if (foundText.StartsWith($"{Path.GetFileNameWithoutExtension(path)}.".AsSpan()))
{
foreach (var element in xDoc)
{
if (element.Key.AsSpan() == resourceName)
{
displayText = element.Value;
break;
}
}
}
}
// TODO Change here?
if (!string.IsNullOrWhiteSpace(displayText))
{
//Console.WriteLine($"Create TextBlock for '{displayText}'");
}
}
}
}
public static class StringExtensions
{
public static int IndexOfAny(this string source, params string[] values)
{
try
{
var valuePostions = new Dictionary<string, int>();
// Values may be duplicated if multiple apps in the project have resources with the same name.
foreach (var value in values.Distinct())
{
valuePostions.Add(value, source.IndexOf(value));
}
if (valuePostions.Any(v => v.Value > -1))
{
var result = valuePostions.Select(v => v.Value).Where(v => v > -1).OrderByDescending(v => v).FirstOrDefault();
return result;
}
}
catch (Exception e)
{
Console.WriteLine(source);
Console.WriteLine(values);
Console.WriteLine(e);
}
return -1;
}
public static int IndexOfAnySpan(this ReadOnlySpan<char> source, List<string> values)
{
return source.IndexOfAnySpan(values, 0, source.Length);
}
public static int IndexOfAnySpan(this ReadOnlySpan<char> source, List<string> values, int start)
{
return source.IndexOfAnySpan(values, start, source.Length - start);
}
public static int IndexOfAnySpan(this ReadOnlySpan<char> source, List<string> values, int start, int length)
{
try
{
var valuePostions = new Dictionary<string, int>();
// Values may be duplicated if multiple apps in the project have resources with the same name.
foreach (var value in values.ToArray().Distinct())
{
valuePostions.Add(value, source.Slice(start, length).IndexOf(value.AsSpan()));
}
if (valuePostions.Any(v => v.Value > -1))
{
var result = valuePostions.Select(v => v.Value).Where(v => v > -1).OrderByDescending(v => v).FirstOrDefault();
return result;
}
}
catch (Exception e)
{
Console.WriteLine(source.ToString());
Console.WriteLine(values);
Console.WriteLine(e);
}
return -1;
}
public static int IndexOfAnySpan(this ReadOnlySpan<char> source, char[] values, int start)
{
return source.IndexOfAnySpan(values, start, source.Length - start);
}
public static int IndexOfAnySpan(this ReadOnlySpan<char> source, char[] values, int start, int length)
{
try
{
var valuePostions = new Dictionary<string, int>();
// Values may be duplicated if multiple apps in the project have resources with the same name.
foreach (var value in values.ToArray().Distinct())
{
valuePostions.Add(value.ToString(), source.Slice(start, length).IndexOf(value));
}
if (valuePostions.Any(v => v.Value > -1))
{
var result = valuePostions.Select(v => v.Value).Where(v => v > -1).OrderByDescending(v => v).FirstOrDefault();
return result;
}
}
catch (Exception e)
{
Console.WriteLine(source.ToString());
Console.WriteLine(values);
Console.WriteLine(e);
}
return -1;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.