From bff3b43f2e10e21de60a1e99f6f727976f1af2b0 Mon Sep 17 00:00:00 2001 From: tijanavg Date: Wed, 25 Mar 2026 10:32:23 +0000 Subject: [PATCH 1/2] Call chooseFormattingPatternForNumber only once in formatInOriginalFormat. This is a non-behavior change which optimizes memory usage on Android by decreasing the number of times a NumberFormat is chosen for a given PhoneNumber (which is expensive due to all the Matcher instantiations) --- .../i18n/phonenumbers/PhoneNumberUtil.java | 49 ++++++++----------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java index 6d8004f182..fd8f1a3067 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java @@ -1656,7 +1656,8 @@ public String formatOutOfCountryCallingNumber(PhoneNumber number, * @return the formatted phone number in its original number format */ public String formatInOriginalFormat(PhoneNumber number, String regionCallingFrom) { - if (number.hasRawInput() && !hasFormattingPatternForNumber(number)) { + NumberFormat formatRule = chooseFormattingPatternForNumber(number); + if (number.hasRawInput() && formatRule == null) { // We check if we have the formatting pattern because without that, we might format the number // as a group without national prefix. return number.getRawInput(); @@ -1696,12 +1697,6 @@ public String formatInOriginalFormat(PhoneNumber number, String regionCallingFro formattedNumber = nationalFormat; break; } - // Metadata cannot be null here because getNddPrefixForRegion() (above) returns null if - // there is no metadata for the region. - PhoneMetadata metadata = getMetadataForRegion(regionCode); - String nationalNumber = getNationalSignificantNumber(number); - NumberFormat formatRule = - chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); // The format rule could still be null here if the national number was 0 and there was no // raw input (this should not be possible for numbers generated by the phonenumber library // as they would also not have a country calling code and we would have exited earlier). @@ -1770,18 +1765,32 @@ private boolean rawInputContainsNationalPrefix(String rawInput, String nationalP return false; } - private boolean hasFormattingPatternForNumber(PhoneNumber number) { + private NumberFormat chooseFormattingPatternForNumber(PhoneNumber number) { int countryCallingCode = number.getCountryCode(); String phoneNumberRegion = getRegionCodeForCountryCode(countryCallingCode); PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCallingCode, phoneNumberRegion); if (metadata == null) { - return false; + return null; } String nationalNumber = getNationalSignificantNumber(number); - NumberFormat formatRule = - chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); - return formatRule != null; + return chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); + } + + NumberFormat chooseFormattingPatternForNumber(List availableFormats, + String nationalNumber) { + for (NumberFormat numFormat : availableFormats) { + int size = numFormat.getLeadingDigitsPatternCount(); + if (size == 0 || regexCache.getPatternForRegex( + // We always use the last leading_digits_pattern, as it is the most detailed. + numFormat.getLeadingDigitsPattern(size - 1)).matcher(nationalNumber).lookingAt()) { + Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber); + if (m.matches()) { + return numFormat; + } + } + } + return null; } /** @@ -1970,22 +1979,6 @@ private String formatNsn(String number, : formatNsnUsingPattern(number, formattingPattern, numberFormat, carrierCode); } - NumberFormat chooseFormattingPatternForNumber(List availableFormats, - String nationalNumber) { - for (NumberFormat numFormat : availableFormats) { - int size = numFormat.getLeadingDigitsPatternCount(); - if (size == 0 || regexCache.getPatternForRegex( - // We always use the last leading_digits_pattern, as it is the most detailed. - numFormat.getLeadingDigitsPattern(size - 1)).matcher(nationalNumber).lookingAt()) { - Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber); - if (m.matches()) { - return numFormat; - } - } - } - return null; - } - // Simple wrapper of formatNsnUsingPattern for the common case of no carrier code. String formatNsnUsingPattern(String nationalNumber, NumberFormat formattingPattern, From 8b0ee5d611a18664de94816c868a1f63d4e129ee Mon Sep 17 00:00:00 2001 From: tijanavg Date: Wed, 25 Mar 2026 10:32:23 +0000 Subject: [PATCH 2/2] Call chooseFormattingPatternForNumber only once in formatInOriginalFormat. This is a non-behavior change which optimizes memory usage on Android by decreasing the number of times a NumberFormat is chosen for a given PhoneNumber (which is expensive due to all the Matcher instantiations) --- .../i18n/phonenumbers/PhoneNumberUtil.java | 49 ++++++++----------- pending_code_changes.txt | 2 +- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java index 6d8004f182..fd8f1a3067 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java @@ -1656,7 +1656,8 @@ public String formatOutOfCountryCallingNumber(PhoneNumber number, * @return the formatted phone number in its original number format */ public String formatInOriginalFormat(PhoneNumber number, String regionCallingFrom) { - if (number.hasRawInput() && !hasFormattingPatternForNumber(number)) { + NumberFormat formatRule = chooseFormattingPatternForNumber(number); + if (number.hasRawInput() && formatRule == null) { // We check if we have the formatting pattern because without that, we might format the number // as a group without national prefix. return number.getRawInput(); @@ -1696,12 +1697,6 @@ public String formatInOriginalFormat(PhoneNumber number, String regionCallingFro formattedNumber = nationalFormat; break; } - // Metadata cannot be null here because getNddPrefixForRegion() (above) returns null if - // there is no metadata for the region. - PhoneMetadata metadata = getMetadataForRegion(regionCode); - String nationalNumber = getNationalSignificantNumber(number); - NumberFormat formatRule = - chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); // The format rule could still be null here if the national number was 0 and there was no // raw input (this should not be possible for numbers generated by the phonenumber library // as they would also not have a country calling code and we would have exited earlier). @@ -1770,18 +1765,32 @@ private boolean rawInputContainsNationalPrefix(String rawInput, String nationalP return false; } - private boolean hasFormattingPatternForNumber(PhoneNumber number) { + private NumberFormat chooseFormattingPatternForNumber(PhoneNumber number) { int countryCallingCode = number.getCountryCode(); String phoneNumberRegion = getRegionCodeForCountryCode(countryCallingCode); PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCallingCode, phoneNumberRegion); if (metadata == null) { - return false; + return null; } String nationalNumber = getNationalSignificantNumber(number); - NumberFormat formatRule = - chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); - return formatRule != null; + return chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); + } + + NumberFormat chooseFormattingPatternForNumber(List availableFormats, + String nationalNumber) { + for (NumberFormat numFormat : availableFormats) { + int size = numFormat.getLeadingDigitsPatternCount(); + if (size == 0 || regexCache.getPatternForRegex( + // We always use the last leading_digits_pattern, as it is the most detailed. + numFormat.getLeadingDigitsPattern(size - 1)).matcher(nationalNumber).lookingAt()) { + Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber); + if (m.matches()) { + return numFormat; + } + } + } + return null; } /** @@ -1970,22 +1979,6 @@ private String formatNsn(String number, : formatNsnUsingPattern(number, formattingPattern, numberFormat, carrierCode); } - NumberFormat chooseFormattingPatternForNumber(List availableFormats, - String nationalNumber) { - for (NumberFormat numFormat : availableFormats) { - int size = numFormat.getLeadingDigitsPatternCount(); - if (size == 0 || regexCache.getPatternForRegex( - // We always use the last leading_digits_pattern, as it is the most detailed. - numFormat.getLeadingDigitsPattern(size - 1)).matcher(nationalNumber).lookingAt()) { - Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber); - if (m.matches()) { - return numFormat; - } - } - } - return null; - } - // Simple wrapper of formatNsnUsingPattern for the common case of no carrier code. String formatNsnUsingPattern(String nationalNumber, NumberFormat formattingPattern, diff --git a/pending_code_changes.txt b/pending_code_changes.txt index 8b13789179..25ae795343 100644 --- a/pending_code_changes.txt +++ b/pending_code_changes.txt @@ -1 +1 @@ - +- Decreased the number of invocations of chooseFormattingPatternForNumber in PhoneNumberUtil#formatInOriginalFormat \ No newline at end of file