Skip to content

Match slices without materialising them when parsing - #382

Merged
twcclegg merged 2 commits into
mainfrom
perf/span-ismatch
Aug 6, 2026
Merged

Match slices without materialising them when parsing#382
twcclegg merged 2 commits into
mainfrom
perf/span-ismatch

Conversation

@twcclegg

@twcclegg twcclegg commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Two Substring calls on the parse path existed only to hand a slice to a regex:

  • MaybeStripNationalPrefixAndCarrierCodenumberString.Substring(prefixMatch.Length) for an
    IsMatchAll check
  • MaybeStripExtensionnumberString.Substring(0, m.Index) for the viability check

On net7.0+ Regex.IsMatch(ReadOnlySpan<char>) means neither slice needs to become a string. Both
call sites now go through a small helper that holds the #if, so the parse logic itself reads the
same as before — this file is kept diffable against the upstream Java.

The PhoneRegex span overload is internal: a public one would exist on the net8.0 and net10.0
assets but not netstandard2.0, which is what package validation's cross-framework check polices.
Replacing the public string overloads outright is recorded on #375 for a major version.

These are the paths #381 made measurable — an E164 parse never reaches either, since both regexes
fail and cost nothing. Watch ParseNationalFormat and ParseWithExtension allocation.

@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.01%. Comparing base (af40c92) to head (848dd21).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #382   +/-   ##
=======================================
  Coverage   98.01%   98.01%           
=======================================
  Files          39       39           
  Lines       52818    52821    +3     
  Branches     1105     1106    +1     
=======================================
+ Hits        51770    51773    +3     
  Misses        795      795           
  Partials      253      253           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

📊 Benchmark Results

Commit: 848dd21 · Full run · Linux ubuntu-24.04-arm

Both sides were measured on the same runner in the same job, so the numbers are
comparable. Treat sub-percent differences as noise.

PR branch

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
InputDigitPerKeystroke 1000 4.601 ms 0.0685 ms 0.0641 ms 54.6875 3.87 MB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  Job-AMQORM : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Runtime=.NET 10.0  InvocationCount=1  IterationCount=20  
LaunchCount=1  RunStrategy=ColdStart  UnrollFactor=1  
WarmupCount=1  

Method Mean Error StdDev Allocated
CreateInstance 413.3 μs 117.7 μs 135.5 μs 119.48 KB
CreateInstanceAndLoadAllRegions 7,081.2 μs 446.9 μs 514.6 μs 1619.1 KB
FirstRegionLookup 458.6 μs 142.1 μs 163.6 μs 124.54 KB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
ExtractPossibleNumber_CleanInput 1000 21.65 μs 0.027 μs 0.025 μs - -
ExtractPossibleNumber_WithLeadingJunk 1000 38.56 μs 0.071 μs 0.066 μs 0.6714 48360 B

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
FindNumbers_Valid 100 140.5 μs 0.24 μs 0.21 μs 0.9766 69.93 KB
FindNumbers_StrictGrouping 100 314.4 μs 0.75 μs 0.67 μs 1.4648 123.2 KB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
GetDescriptionForNumber 1000 1,502.35 μs 4.562 μs 4.044 μs 1.9531 196.63 KB
GetDisplayCountry 1000 24.87 μs 0.042 μs 0.039 μs 0.0916 7.56 KB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
ParseValidateAndFormatPhoneNumbers 1000 2,704.7 μs 16.50 μs 13.78 μs 7.8125 580.13 KB
ParseOnly 1000 436.2 μs 0.57 μs 0.51 μs 4.8828 350.55 KB
ParseNationalFormat 1000 846.6 μs 1.41 μs 1.18 μs 8.7891 581.22 KB
ParseWithExtension 1000 1,213.5 μs 1.90 μs 1.78 μs 21.4844 1405.12 KB
ValidateOnly 1000 779.2 μs 2.80 μs 2.48 μs - 41.11 KB
FormatOnly 1000 1,123.1 μs 2.15 μs 1.90 μs 1.9531 187.92 KB
PR base

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
InputDigitPerKeystroke 1000 4.660 ms 0.0497 ms 0.0415 ms 54.6875 3.87 MB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  Job-AMQORM : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Runtime=.NET 10.0  InvocationCount=1  IterationCount=20  
LaunchCount=1  RunStrategy=ColdStart  UnrollFactor=1  
WarmupCount=1  

Method Mean Error StdDev Allocated
CreateInstance 423.6 μs 122.4 μs 140.9 μs 119.48 KB
CreateInstanceAndLoadAllRegions 7,103.9 μs 419.9 μs 483.6 μs 1619.1 KB
FirstRegionLookup 471.4 μs 147.4 μs 169.8 μs 124.54 KB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
ExtractPossibleNumber_CleanInput 1000 21.63 μs 0.020 μs 0.018 μs - -
ExtractPossibleNumber_WithLeadingJunk 1000 38.32 μs 0.058 μs 0.055 μs 0.6714 48360 B

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
FindNumbers_Valid 100 142.4 μs 0.22 μs 0.18 μs 0.9766 69.93 KB
FindNumbers_StrictGrouping 100 315.6 μs 0.72 μs 0.67 μs 1.4648 123.2 KB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
GetDescriptionForNumber 1000 1,484.30 μs 9.331 μs 8.728 μs 1.9531 196.63 KB
GetDisplayCountry 1000 21.33 μs 0.009 μs 0.007 μs 0.0916 7.56 KB

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Neoverse-N2, 4 physical cores
.NET SDK 10.0.302
  [Host]    : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a
  .NET 10.0 : .NET 10.0.10 (10.0.10, 10.0.1026.32716), Arm64 RyuJIT armv8.0-a

Job=.NET 10.0  Runtime=.NET 10.0  

Method PhoneNumberCount Mean Error StdDev Gen0 Allocated
ParseValidateAndFormatPhoneNumbers 1000 2,967.0 μs 58.74 μs 126.43 μs 7.8125 580.51 KB
ParseOnly 1000 435.3 μs 0.62 μs 0.55 μs 4.8828 350.95 KB
ParseNationalFormat 1000 848.1 μs 2.78 μs 2.46 μs 8.7891 581.22 KB
ParseWithExtension 1000 1,217.4 μs 2.69 μs 2.25 μs 21.4844 1459.2 KB
ValidateOnly 1000 781.7 μs 2.39 μs 2.12 μs - 41.11 KB
FormatOnly 1000 1,096.9 μs 2.32 μs 2.06 μs 1.9531 187.92 KB

@twcclegg
twcclegg merged commit 9e06b64 into main Aug 6, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant