Skip to content

Commit 4b43131

Browse files
authored
More perf tuning (#1161)
* change type of ICommand.Arguments and .Options from IEnumerable to IReadOnlyList * replace a bunch of foreach loops with for loops * a few fewer allocations, here and there
1 parent df91fa1 commit 4b43131

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+435
-600
lines changed

src/System.CommandLine.DragonFruit.Tests/ConfigureFromMethodTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,7 @@ public void Options_are_not_generated_for_command_argument_parameters(string met
138138
"args"
139139
};
140140

141-
rootCommand.Children
142-
.OfType<IOption>()
141+
rootCommand.Options
143142
.Should()
144143
.NotContain(o => argumentParameterNames.Contains(o.Name));
145144
}

src/System.CommandLine.DragonFruit/CommandLine.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,13 @@ public static CommandLineBuilder ConfigureHelpFromXmlComments(
223223
}
224224
else
225225
{
226-
foreach (var argument in builder.Command.Arguments)
226+
for (var i = 0; i < builder.Command.Arguments.Count; i++)
227227
{
228+
var argument = builder.Command.Arguments[i];
228229
if (string.Equals(
229-
argument.Name,
230-
kebabCasedParameterName,
231-
StringComparison.OrdinalIgnoreCase))
230+
argument.Name,
231+
kebabCasedParameterName,
232+
StringComparison.OrdinalIgnoreCase))
232233
{
233234
argument.Description = parameterDescription.Value;
234235
}

src/System.CommandLine.Rendering/StringExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ internal static class StringExtensions
77
{
88
public static bool EndsWithWhitespace(this string value) =>
99
value.Length > 0
10-
&& Char.IsWhiteSpace(value[value.Length - 1]);
10+
&& char.IsWhiteSpace(value[value.Length - 1]);
1111

1212
public static bool StartsWithWhitespace(this string value) =>
1313
value.Length > 0
14-
&& Char.IsWhiteSpace(value[0]);
14+
&& char.IsWhiteSpace(value[0]);
1515

1616
public static bool IsNewLine(this string value) => value == "\n" || value == "\r\n";
1717
}

src/System.CommandLine.Suggest/GlobalToolsSuggestionRegistration.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ public IEnumerable<Registration> FindAllRegistrations()
4646

4747
public Registration FindRegistration(FileInfo soughtExecutable)
4848
{
49-
if (soughtExecutable == null) throw new ArgumentNullException(nameof(soughtExecutable));
49+
if (soughtExecutable == null)
50+
{
51+
throw new ArgumentNullException(nameof(soughtExecutable));
52+
}
5053

5154
if (_nullableToolsShimPath == null)
5255
{

src/System.CommandLine.Suggest/SuggestionDispatcher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ IEnumerable<string> Prefixes()
179179

180180
yield return fileNameWithoutExtension;
181181

182-
if (fileNameWithoutExtension.StartsWith("dotnet-", StringComparison.Ordinal))
182+
if (fileNameWithoutExtension?.StartsWith("dotnet-", StringComparison.Ordinal) == true)
183183
{
184184
yield return "dotnet " + fileNameWithoutExtension.Substring("dotnet-".Length);
185185
}

src/System.CommandLine.Tests/Binding/TypeConversionTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,16 +493,18 @@ public void A_default_value_with_a_custom_constructor_can_be_specified_for_a_com
493493
{
494494
var directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());
495495

496+
var argument = new Argument<DirectoryInfo>("the-arg", () => directoryInfo);
497+
496498
var command = new Command("something")
497499
{
498-
new Argument<DirectoryInfo>("the-arg", () => directoryInfo)
500+
argument
499501
};
500502

501503
var result = command.Parse("something");
502504

503505
result.Errors.Should().BeEmpty();
504506

505-
var value = result.CommandResult.GetArgumentValueOrDefault("the-arg");
507+
var value = result.ValueForArgument("the-arg");
506508

507509
value.Should().Be(directoryInfo);
508510
}

src/System.CommandLine.Tests/CommandTests.cs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -134,37 +134,6 @@ public void Commands_at_multiple_levels_can_have_their_own_arguments()
134134
.BeEquivalentTo("arg2", "arg3");
135135
}
136136

137-
[Theory]
138-
[InlineData("aa:", ":")]
139-
[InlineData("aa=", "=")]
140-
[InlineData(":aa", ":")]
141-
[InlineData("=aa", "=")]
142-
[InlineData("aa:aa", ":")]
143-
[InlineData("aa=aa", "=")]
144-
public void When_a_command_name_contains_a_delimiter_then_an_error_is_returned(
145-
string commandWithDelimiter,
146-
string delimiter)
147-
{
148-
Action create = () =>
149-
{
150-
new Parser(
151-
new Command(commandWithDelimiter)
152-
{
153-
new Argument
154-
{
155-
Arity = ArgumentArity.ExactlyOne
156-
}
157-
});
158-
};
159-
160-
create.Should()
161-
.Throw<ArgumentException>()
162-
.Which
163-
.Message
164-
.Should()
165-
.Be($"Command \"{commandWithDelimiter}\" is not allowed to contain a delimiter but it contains \"{delimiter}\"");
166-
}
167-
168137
[Fact]
169138
public void Aliases_is_aware_of_added_alias()
170139
{

src/System.CommandLine.Tests/GlobalOptionTests.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,22 +75,6 @@ public void Global_options_appear_in_options_list()
7575
root.Options.Should().Contain(option);
7676
}
7777

78-
[Fact]
79-
public void Global_options_appear_in_child_command_options_list()
80-
{
81-
var root = new Command("parent");
82-
83-
var option = new Option<int>("--global");
84-
85-
root.AddGlobalOption(option);
86-
87-
var child = new Command("child");
88-
89-
root.AddCommand(child);
90-
91-
child.Options.Should().Contain(option);
92-
}
93-
9478
[Fact]
9579
public void Subcommands_added_after_a_global_option_is_added_to_parent_will_recognize_the_global_option()
9680
{

src/System.CommandLine.Tests/OptionTests.cs

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -165,32 +165,6 @@ public void Raw_aliases_are_exposed_by_an_option()
165165
.BeEquivalentTo("-h", "--help", "/?");
166166
}
167167

168-
[Theory]
169-
[InlineData(":", "-x{0}")]
170-
[InlineData("=", "-x{0}")]
171-
[InlineData(":", "{0}-x")]
172-
[InlineData("=", "{0}-x")]
173-
[InlineData(":", "--aa{0}aa")]
174-
[InlineData("=", "--aa{0}aa")]
175-
public void When_an_option_alias_contains_a_delimiter_then_an_informative_error_is_returned(
176-
string delimiter,
177-
string template)
178-
{
179-
var alias = string.Format(template, delimiter);
180-
181-
Action create = () =>
182-
{
183-
new Parser(new Option(alias));
184-
};
185-
186-
create.Should()
187-
.Throw<ArgumentException>()
188-
.Which
189-
.Message
190-
.Should()
191-
.Be($"Option \"{alias}\" is not allowed to contain a delimiter but it contains \"{delimiter}\"");
192-
}
193-
194168
[Theory]
195169
[InlineData("-x ")]
196170
[InlineData(" -x")]

src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,9 @@ public void Multiple_arguments_can_differ_by_arity()
3333

3434
var result = command.Parse("1 2 3 4");
3535

36-
var several = result.CommandResult
37-
.GetArgumentValueOrDefault<IEnumerable<string>>("several");
36+
var several = result.ValueForArgument<IEnumerable<string>>("several");
3837

39-
var one = result.CommandResult
40-
.GetArgumentValueOrDefault<IEnumerable<string>>("one");
38+
var one = result.ValueForArgument<IEnumerable<string>>("one");
4139

4240
several.Should()
4341
.BeEquivalentSequenceTo("1", "2", "3");
@@ -62,11 +60,9 @@ public void Multiple_arguments_can_differ_by_type()
6260

6361
var result = command.Parse("1 2");
6462

65-
var theString = result.CommandResult
66-
.GetArgumentValueOrDefault<string>("the-string");
63+
var theString = result.ValueForArgument<string>("the-string");
6764

68-
var theInt = result.CommandResult
69-
.GetArgumentValueOrDefault<int>("the-int");
65+
var theInt = result.ValueForArgument<int>("the-int");
7066

7167
theString.Should().Be("1");
7268
theInt.Should().Be(2);
@@ -124,27 +120,29 @@ public void When_multiple_arguments_are_present_then_their_order_relative_to_sib
124120
[Fact]
125121
public void Multiple_arguments_of_unspecified_type_are_parsed_correctly()
126122
{
123+
var sourceArg = new Argument("source")
124+
{
125+
Arity = ArgumentArity.ExactlyOne
126+
};
127+
var destinationArg = new Argument("destination")
128+
{
129+
Arity = ArgumentArity.ExactlyOne
130+
};
127131
var root = new RootCommand
128132
{
129-
new Argument("source")
130-
{
131-
Arity = ArgumentArity.ExactlyOne
132-
},
133-
new Argument("destination")
134-
{
135-
Arity = ArgumentArity.ExactlyOne
136-
}
133+
sourceArg,
134+
destinationArg
137135
};
138136

139137
var result = root.Parse("src.txt dest.txt");
140138

141-
result.RootCommandResult
142-
.GetArgumentValueOrDefault("source")
139+
result.FindResultFor(sourceArg)
140+
.GetValueOrDefault()
143141
.Should()
144142
.Be("src.txt");
145143

146-
result.RootCommandResult
147-
.GetArgumentValueOrDefault("destination")
144+
result.FindResultFor(destinationArg)
145+
.GetValueOrDefault()
148146
.Should()
149147
.Be("dest.txt");
150148
}

0 commit comments

Comments
 (0)