Skip to content

Commit 3231500

Browse files
use a StringBuilder when converting to string
1 parent 7966e8f commit 3231500

File tree

4 files changed

+85
-8
lines changed

4 files changed

+85
-8
lines changed

Semver.Test/IntExtensionsTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Globalization;
2+
using Xunit;
3+
4+
namespace Semver.Test
5+
{
6+
public class IntExtensionsTests
7+
{
8+
[Theory]
9+
[InlineData(0)]
10+
[InlineData(1)]
11+
[InlineData(9)]
12+
[InlineData(10)]
13+
[InlineData(986)]
14+
[InlineData(4569)]
15+
[InlineData(96854)]
16+
[InlineData(565627)]
17+
[InlineData(6615776)]
18+
[InlineData(78415675)]
19+
[InlineData(787_415_757)]
20+
[InlineData(int.MaxValue)]
21+
public void DigitsTest(int n)
22+
{
23+
Assert.Equal(n.ToString(CultureInfo.InvariantCulture).Length, n.Digits());
24+
}
25+
}
26+
}

Semver/IntExtensions.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Text;
2+
3+
namespace Semver
4+
{
5+
internal static class IntExtensions
6+
{
7+
/// <summary>
8+
/// The number of digits in a non-negative number. Returns 1 for all
9+
/// negative numbers. That is ok because we are using it to calculate
10+
/// string length for a <see cref="StringBuilder"/> for numbers that
11+
/// aren't supposed to be negative, but when they are it is just a little
12+
/// slower.
13+
/// </summary>
14+
/// <remarks>
15+
/// This approach is based on https://stackoverflow.com/a/51099524/268898
16+
/// where the poster offers performance benchmarks showing this is the
17+
/// fastest way to get a number of digits.
18+
/// </remarks>
19+
public static int Digits(this int n)
20+
{
21+
if (n < 10) return 1;
22+
if (n < 100) return 2;
23+
if (n < 1000) return 3;
24+
if (n < 10000) return 4;
25+
if (n < 100000) return 5;
26+
if (n < 1000000) return 6;
27+
if (n < 10000000) return 7;
28+
if (n < 100000000) return 8;
29+
if (n < 1000000000) return 9;
30+
return 10;
31+
}
32+
}
33+
}

Semver/Properties/AssemblyInfo.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using System.Runtime.InteropServices;
1+
using System.Runtime.CompilerServices;
2+
using System.Runtime.InteropServices;
23

34
[assembly: ComVisible(false)]
4-
[assembly: Guid("e208ca67-5b59-45d9-a29a-7f30137d3beb")]
5+
[assembly: Guid("e208ca67-5b59-45d9-a29a-7f30137d3beb")]
6+
7+
[assembly: InternalsVisibleTo("Semver.Test")]

Semver/SemVersion.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Globalization;
3+
using System.Text;
34
#if !NETSTANDARD
45
using System.Runtime.Serialization;
56
using System.Security.Permissions;
@@ -279,12 +280,26 @@ public SemVersion Change(int? major = null, int? minor = null, int? patch = null
279280
/// </returns>
280281
public override string ToString()
281282
{
282-
var version = "" + Major + "." + Minor + "." + Patch;
283-
if (!string.IsNullOrEmpty(Prerelease))
284-
version += "-" + Prerelease;
285-
if (!string.IsNullOrEmpty(Build))
286-
version += "+" + Build;
287-
return version;
283+
// Assume all separators ("..-+"), at most 2 extra chars
284+
var estimatedLength = 4 + Major.Digits() + Minor.Digits() + Patch.Digits()
285+
+ Prerelease.Length + Build.Length;
286+
var version = new StringBuilder(estimatedLength);
287+
version.Append(Major);
288+
version.Append('.');
289+
version.Append(Minor);
290+
version.Append('.');
291+
version.Append(Patch);
292+
if (Prerelease.Length > 0)
293+
{
294+
version.Append('-');
295+
version.Append(Prerelease);
296+
}
297+
if (Build.Length > 0)
298+
{
299+
version.Append('+');
300+
version.Append(Build);
301+
}
302+
return version.ToString();
288303
}
289304

290305
/// <summary>

0 commit comments

Comments
 (0)