Skip to content

Commit 01df556

Browse files
committed
feat: add more optimisation
1 parent bfa4868 commit 01df556

2 files changed

Lines changed: 34 additions & 14 deletions

File tree

csharp/PhoneNumbers/PhoneNumberUtil.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -987,27 +987,26 @@ private static bool DescHasData(PhoneNumberDesc desc)
987987
|| desc.HasNationalNumberPattern;
988988
}
989989

990+
// Pre-filtered: excludes FIXED_LINE_OR_MOBILE (convenience aggregate) and UNKNOWN (non-type).
991+
private static readonly PhoneNumberType[] s_checkablePhoneNumberTypes =
992+
[
993+
PhoneNumberType.FIXED_LINE, PhoneNumberType.MOBILE, PhoneNumberType.TOLL_FREE,
994+
PhoneNumberType.PREMIUM_RATE, PhoneNumberType.SHARED_COST, PhoneNumberType.VOIP,
995+
PhoneNumberType.PERSONAL_NUMBER, PhoneNumberType.PAGER, PhoneNumberType.UAN,
996+
PhoneNumberType.VOICEMAIL,
997+
];
998+
990999
/// <summary>
9911000
/// Returns the types we have metadata for based on the PhoneMetadata object passed in, which must
9921001
/// be non-null.
9931002
/// </summary>
994-
/// <param name="metadata"></param>
995-
/// <returns></returns>
9961003
private HashSet<PhoneNumberType> GetSupportedTypesForMetadata(PhoneMetadata metadata)
9971004
{
9981005
var types = new HashSet<PhoneNumberType>();
999-
foreach (PhoneNumberType type in Enum.GetValues(typeof(PhoneNumberType)))
1006+
foreach (var type in s_checkablePhoneNumberTypes)
10001007
{
1001-
if (type == PhoneNumberType.FIXED_LINE_OR_MOBILE || type == PhoneNumberType.UNKNOWN)
1002-
{
1003-
// Never return FIXED_LINE_OR_MOBILE (it is a convenience type, and represents that a
1004-
// particular number type can't be determined) or UNKNOWN (the non-type).
1005-
continue;
1006-
}
10071008
if (DescHasData(GetNumberDescByType(metadata, type)))
1008-
{
10091009
types.Add(type);
1010-
}
10111010
}
10121011
return types;
10131012
}
@@ -2307,6 +2306,14 @@ private int MaybeExtractCountryCode(string number, PhoneMetadata defaultRegionMe
23072306
nationalNumber, keepRawInput, phoneNumber);
23082307
}
23092308

2309+
private static bool StringBuilderStartsWith(StringBuilder sb, string value)
2310+
{
2311+
if (sb.Length < value.Length) return false;
2312+
for (var i = 0; i < value.Length; i++)
2313+
if (sb[i] != value[i]) return false;
2314+
return true;
2315+
}
2316+
23102317
// Same as the string overload above, but takes a StringBuilder workspace directly so callers
23112318
// that already hold a StringBuilder can avoid an extra string<->StringBuilder round-trip.
23122319
// The fullNumber buffer is always mutated (Normalize is unconditional, and any leading '+' or
@@ -2357,9 +2364,10 @@ private int MaybeExtractCountryCode(StringBuilder fullNumber, PhoneMetadata defa
23572364
// before and after.
23582365
var defaultCountryCode = defaultRegionMetadata.CountryCode;
23592366
var defaultCountryCodeString = defaultCountryCode.ToString();
2360-
var normalizedNumber = fullNumber.ToString();
2361-
if (normalizedNumber.StartsWith(defaultCountryCodeString, StringComparison.Ordinal))
2367+
// Avoid the ToString() allocation unless the prefix actually matches (common case: it won't).
2368+
if (StringBuilderStartsWith(fullNumber, defaultCountryCodeString))
23622369
{
2370+
var normalizedNumber = fullNumber.ToString();
23632371
var potentialNationalNumberString = normalizedNumber.Substring(defaultCountryCodeString.Length);
23642372
// Use a separate buffer for the strip-CC trial so callers that share fullNumber as
23652373
// their workspace are not corrupted when this branch decides not to commit.
@@ -2373,7 +2381,7 @@ private int MaybeExtractCountryCode(StringBuilder fullNumber, PhoneMetadata defa
23732381
var validNumberPattern = generalDesc.GetNationalNumberPattern();
23742382
if ((!validNumberPattern.IsMatchAll(normalizedNumber) &&
23752383
validNumberPattern.IsMatchAll(potentialNationalNumberString)) ||
2376-
TestNumberLength(normalizedNumber.Length, defaultRegionMetadata) == ValidationResult.TOO_LONG)
2384+
TestNumberLength(fullNumber.Length, defaultRegionMetadata) == ValidationResult.TOO_LONG)
23772385
{
23782386
nationalNumber.Append(potentialNationalNumberString);
23792387
if (keepRawInput)
@@ -2531,7 +2539,11 @@ static string MaybeStripExtension(StringBuilder number, string numberString)
25312539
var m = ExtnPattern().Match(numberString);
25322540
// If we find a potential extension, and the number preceding this is a viable number, we assume
25332541
// it is an extension.
2542+
#if NET7_0_OR_GREATER
2543+
if (m.Success && IsViablePhoneNumberSpan(numberString.AsSpan(0, m.Index)))
2544+
#else
25342545
if (m.Success && IsViablePhoneNumber(numberString.Substring(0, m.Index)))
2546+
#endif
25352547
{
25362548
// The numbers are captured into groups in the regular expression.
25372549
for (int i = 1, length = m.Groups.Count; i < length; i++)

csharp/PhoneNumbers/PhoneNumberUtil.net.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,14 @@ private void PrefixNumberWithCountryCallingCode(ref Span<char> span,
759759
return;
760760
}
761761
}
762+
763+
#if NET7_0_OR_GREATER
764+
internal static bool IsViablePhoneNumberSpan(ReadOnlySpan<char> number)
765+
{
766+
if (number.Length < MIN_LENGTH_FOR_NSN) return false;
767+
return ValidPhoneNumber().IsMatch(number);
768+
}
769+
#endif
762770
}
763771
}
764772
#endif

0 commit comments

Comments
 (0)