Skip to content

Commit 8dfef29

Browse files
Merge pull request #7 from SixLabors/sp/faster-guard-apis
Faster Guard APIs
2 parents 1d92ff1 + 2cbd2bc commit 8dfef29

File tree

13 files changed

+355
-100
lines changed

13 files changed

+355
-100
lines changed

.editorconfig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,6 @@ csharp_style_throw_expression = true:suggestion
368368
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
369369
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
370370

371-
csharp_style_var_for_built_in_types = false:silent
371+
csharp_style_var_for_built_in_types = never
372372
csharp_style_var_when_type_is_apparent = true:warning
373373
csharp_style_var_elsewhere = false:warning
374-
375-
csharp_prefer_simple_using_statement = false:silent

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,4 @@ __pycache__/
286286
*.btm.cs
287287
*.odx.cs
288288
*.xsd.cs
289+
src/SharedInfrastructure/Guard.Numeric.cs

SharedInfrastructure.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedInfrastructure", "src
99
EndProject
1010
Global
1111
GlobalSection(SharedMSBuildProjectFiles) = preSolution
12+
src\SharedInfrastructure\SharedInfrastructure.projitems*{1664b46a-d99f-4c66-9424-a3a17c926a4c}*SharedItemsImports = 5
1213
src\SharedInfrastructure\SharedInfrastructure.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13
1314
EndGlobalSection
1415
GlobalSection(SolutionConfigurationPlatforms) = preSolution

src/SharedInfrastructure/DebugGuard.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ namespace SixLabors
1212
/// Provides methods to protect against invalid parameters for a DEBUG build.
1313
/// </summary>
1414
[DebuggerStepThrough]
15+
#pragma warning disable CS0436 // Type conflicts with imported type
1516
[ExcludeFromCodeCoverage]
17+
#pragma warning restore CS0436 // Type conflicts with imported type
1618
internal static partial class DebugGuard
1719
{
1820
/// <summary>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<#@ template debug="false" hostspecific="false" language="C#" #>
2+
<#@ assembly name="System.Core" #>
3+
<#@ output extension=".cs" #>
4+
// Copyright (c) Six Labors and contributors.
5+
// Licensed under the Apache License, Version 2.0.
6+
7+
using System;
8+
using System.Runtime.CompilerServices;
9+
10+
namespace SixLabors
11+
{
12+
/// <summary>
13+
/// Provides methods to protect against invalid parameters.
14+
/// </summary>
15+
internal static partial class Guard
16+
{
17+
<#
18+
var types = new[] { "byte", "sbyte", "short", "ushort", "char", "int", "uint", "float", "long", "ulong", "double", "decimal" };
19+
20+
for (var i = 0; i < types.Length; i++)
21+
{
22+
if (i > 0) WriteLine("");
23+
24+
var T = types[i];
25+
#>
26+
/// <summary>
27+
/// Ensures that the specified value is less than a maximum value.
28+
/// </summary>
29+
/// <param name="value">The target value, which should be validated.</param>
30+
/// <param name="max">The maximum value.</param>
31+
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
32+
/// <exception cref="ArgumentException">
33+
/// <paramref name="value"/> is greater than the maximum value.
34+
/// </exception>
35+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
36+
public static void MustBeLessThan(<#=T#> value, <#=T#> max, string parameterName)
37+
{
38+
if (value >= max)
39+
{
40+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
41+
}
42+
}
43+
44+
/// <summary>
45+
/// Verifies that the specified value is less than or equal to a maximum value
46+
/// and throws an exception if it is not.
47+
/// </summary>
48+
/// <param name="value">The target value, which should be validated.</param>
49+
/// <param name="max">The maximum value.</param>
50+
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
51+
/// <exception cref="ArgumentException">
52+
/// <paramref name="value"/> is greater than the maximum value.
53+
/// </exception>
54+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
55+
public static void MustBeLessThanOrEqualTo(<#=T#> value, <#=T#> max, string parameterName)
56+
{
57+
if (value > max)
58+
{
59+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
60+
}
61+
}
62+
63+
/// <summary>
64+
/// Verifies that the specified value is greater than a minimum value
65+
/// and throws an exception if it is not.
66+
/// </summary>
67+
/// <param name="value">The target value, which should be validated.</param>
68+
/// <param name="min">The minimum value.</param>
69+
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
70+
/// <exception cref="ArgumentException">
71+
/// <paramref name="value"/> is less than the minimum value.
72+
/// </exception>
73+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
74+
public static void MustBeGreaterThan(<#=T#> value, <#=T#> min, string parameterName)
75+
{
76+
if (value <= min)
77+
{
78+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
79+
}
80+
}
81+
82+
/// <summary>
83+
/// Verifies that the specified value is greater than or equal to a minimum value
84+
/// and throws an exception if it is not.
85+
/// </summary>
86+
/// <param name="value">The target value, which should be validated.</param>
87+
/// <param name="min">The minimum value.</param>
88+
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
89+
/// <exception cref="ArgumentException">
90+
/// <paramref name="value"/> is less than the minimum value.
91+
/// </exception>
92+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
93+
public static void MustBeGreaterThanOrEqualTo(<#=T#> value, <#=T#> min, string parameterName)
94+
{
95+
if (value < min)
96+
{
97+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
98+
}
99+
}
100+
101+
/// <summary>
102+
/// Verifies that the specified value is greater than or equal to a minimum value and less than
103+
/// or equal to a maximum value and throws an exception if it is not.
104+
/// </summary>
105+
/// <param name="value">The target value, which should be validated.</param>
106+
/// <param name="min">The minimum value.</param>
107+
/// <param name="max">The maximum value.</param>
108+
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
109+
/// <exception cref="ArgumentException">
110+
/// <paramref name="value"/> is less than the minimum value of greater than the maximum value.
111+
/// </exception>
112+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
113+
public static void MustBeBetweenOrEqualTo(<#=T#> value, <#=T#> min, <#=T#> max, string parameterName)
114+
{
115+
if (value < min || value > max)
116+
{
117+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
118+
}
119+
}
120+
<#
121+
}
122+
#>
123+
}
124+
}

src/SharedInfrastructure/Guard.cs

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ namespace SixLabors
1212
/// Provides methods to protect against invalid parameters.
1313
/// </summary>
1414
[DebuggerStepThrough]
15+
#pragma warning disable CS0436 // Type conflicts with imported type
1516
[ExcludeFromCodeCoverage]
17+
#pragma warning restore CS0436 // Type conflicts with imported type
1618
internal static partial class Guard
1719
{
1820
/// <summary>
@@ -28,7 +30,7 @@ public static void NotNull<TValue>(TValue value, string parameterName)
2830
{
2931
if (value is null)
3032
{
31-
ThrowArgumentNullException(parameterName);
33+
ThrowHelper.ThrowArgumentNullExceptionForNotNull(parameterName);
3234
}
3335
}
3436

@@ -42,14 +44,9 @@ public static void NotNull<TValue>(TValue value, string parameterName)
4244
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4345
public static void NotNullOrWhiteSpace(string value, string parameterName)
4446
{
45-
if (value is null)
46-
{
47-
ThrowArgumentNullException(parameterName);
48-
}
49-
5047
if (string.IsNullOrWhiteSpace(value))
5148
{
52-
ThrowArgumentException("Must not be empty or whitespace.", parameterName);
49+
ThrowHelper.ThrowArgumentExceptionForNotNullOrWhitespace(value, parameterName);
5350
}
5451
}
5552

@@ -69,7 +66,7 @@ public static void MustBeLessThan<TValue>(TValue value, TValue max, string param
6966
{
7067
if (value.CompareTo(max) >= 0)
7168
{
72-
ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}.");
69+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
7370
}
7471
}
7572

@@ -90,7 +87,7 @@ public static void MustBeLessThanOrEqualTo<TValue>(TValue value, TValue max, str
9087
{
9188
if (value.CompareTo(max) > 0)
9289
{
93-
ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}.");
90+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
9491
}
9592
}
9693

@@ -111,9 +108,7 @@ public static void MustBeGreaterThan<TValue>(TValue value, TValue min, string pa
111108
{
112109
if (value.CompareTo(min) <= 0)
113110
{
114-
ThrowArgumentOutOfRangeException(
115-
parameterName,
116-
$"Value {value} must be greater than {min}.");
111+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
117112
}
118113
}
119114

@@ -134,7 +129,7 @@ public static void MustBeGreaterThanOrEqualTo<TValue>(TValue value, TValue min,
134129
{
135130
if (value.CompareTo(min) < 0)
136131
{
137-
ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}.");
132+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
138133
}
139134
}
140135

@@ -156,7 +151,7 @@ public static void MustBeBetweenOrEqualTo<TValue>(TValue value, TValue min, TVal
156151
{
157152
if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
158153
{
159-
ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}.");
154+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
160155
}
161156
}
162157

@@ -175,7 +170,7 @@ public static void IsTrue(bool target, string parameterName, string message)
175170
{
176171
if (!target)
177172
{
178-
ThrowArgumentException(message, parameterName);
173+
ThrowHelper.ThrowArgumentException(message, parameterName);
179174
}
180175
}
181176

@@ -194,7 +189,7 @@ public static void IsFalse(bool target, string parameterName, string message)
194189
{
195190
if (target)
196191
{
197-
ThrowArgumentException(message, parameterName);
192+
ThrowHelper.ThrowArgumentException(message, parameterName);
198193
}
199194
}
200195

@@ -213,7 +208,7 @@ public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength,
213208
{
214209
if (source.Length < minLength)
215210
{
216-
ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
211+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName);
217212
}
218213
}
219214

@@ -232,7 +227,7 @@ public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string p
232227
{
233228
if (source.Length < minLength)
234229
{
235-
ThrowArgumentException($"The size must be at least {minLength}.", parameterName);
230+
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName);
236231
}
237232
}
238233

@@ -252,7 +247,7 @@ public static void DestinationShouldNotBeTooShort<TSource, TDest>(
252247
{
253248
if (destination.Length < source.Length)
254249
{
255-
ThrowArgumentException($"Destination span is too short!", destinationParamName);
250+
ThrowHelper.ThrowArgumentException("Destination span is too short!", destinationParamName);
256251
}
257252
}
258253

@@ -272,20 +267,8 @@ public static void DestinationShouldNotBeTooShort<TSource, TDest>(
272267
{
273268
if (destination.Length < source.Length)
274269
{
275-
ThrowArgumentException($"Destination span is too short!", destinationParamName);
270+
ThrowHelper.ThrowArgumentException("Destination span is too short!", destinationParamName);
276271
}
277272
}
278-
279-
[MethodImpl(MethodImplOptions.NoInlining)]
280-
private static void ThrowArgumentException(string message, string parameterName) =>
281-
throw new ArgumentException(message, parameterName);
282-
283-
[MethodImpl(MethodImplOptions.NoInlining)]
284-
private static void ThrowArgumentOutOfRangeException(string parameterName, string message) =>
285-
throw new ArgumentOutOfRangeException(parameterName, message);
286-
287-
[MethodImpl(MethodImplOptions.NoInlining)]
288-
private static void ThrowArgumentNullException(string parameterName) =>
289-
throw new ArgumentNullException(parameterName);
290273
}
291274
}

src/SharedInfrastructure/HashCode.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
#pragma warning disable SA1636, SA1600, SA1503, SA1202, SA1101, SA1132, SA1309, SA1520, SA1108, SA1203, SA1028, SA1512, SA1308
2-
1+
// <auto-generated />
32
// SOURCE: https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/HashCode.cs
43

54
// Licensed to the .NET Foundation under one or more agreements.
@@ -58,7 +57,9 @@ namespace System
5857
{
5958
// xxHash32 is used for the hash code.
6059
// https://github.com/Cyan4973/xxHash
60+
#pragma warning disable CS0436 // Type conflicts with imported type
6161
[ExcludeFromCodeCoverage]
62+
#pragma warning restore CS0436 // Type conflicts with imported type
6263
internal struct HashCode
6364
{
6465
#pragma warning disable SA1311 // Static readonly fields should begin with upper-case letter

src/SharedInfrastructure/MathF.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ namespace System
1414
/// Provides single-precision floating point constants and static methods for trigonometric, logarithmic, and other common mathematical functions.
1515
/// </summary>
1616
/// <remarks>MathF emulation on platforms that don't support it natively.</remarks>
17+
#pragma warning disable CS0436 // Type conflicts with imported type
1718
[ExcludeFromCodeCoverage]
19+
#pragma warning restore CS0436 // Type conflicts with imported type
1820
internal static class MathF
1921
{
2022
/// <summary>

src/SharedInfrastructure/SharedInfrastructure.projitems

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,11 @@
1414
<Compile Include="$(MSBuildThisFileDirectory)Guard.cs" />
1515
<Compile Include="$(MSBuildThisFileDirectory)HashCode.cs" />
1616
<Compile Include="$(MSBuildThisFileDirectory)MathF.cs" />
17+
<Compile Include="$(MSBuildThisFileDirectory)ThrowHelper.cs" />
1718
</ItemGroup>
18-
</Project>
19+
<ItemGroup>
20+
<None Include="$(MSBuildThisFileDirectory)Guard.Numeric.tt">
21+
<Generator>TextTemplatingFileGenerator</Generator>
22+
</None>
23+
</ItemGroup>
24+
</Project>
Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3-
<PropertyGroup Label="Globals">
4-
<ProjectGuid>68a8cc40-6aed-4e96-b524-31b1158fdeea</ProjectGuid>
5-
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
6-
</PropertyGroup>
7-
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
8-
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
9-
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
10-
<PropertyGroup />
11-
<Import Project="SharedInfrastructure.projitems" Label="Shared" />
12-
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
3+
<PropertyGroup Label="Globals">
4+
<ProjectGuid>68a8cc40-6aed-4e96-b524-31b1158fdeea</ProjectGuid>
5+
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
6+
</PropertyGroup>
7+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
8+
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
9+
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
10+
<Import Project="SharedInfrastructure.projitems" Label="Shared" />
11+
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
1312
</Project>

0 commit comments

Comments
 (0)