tdf#141415 reduce time spent loading language data

cache LocaleDataWrapper because otherwise we spend quite a bit of
time doing function-pointer-symbol lookups.

Change-Id: Ic1bd07dabac95a2e1bdad70cffbc2b4cabdc62ed
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183221
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
Noel Grandin
2025-03-22 17:26:53 +01:00
parent b417954503
commit 8c0d8f5071
19 changed files with 81 additions and 69 deletions
@@ -44,8 +44,8 @@ SvxForbiddenCharactersTable::GetForbiddenCharacters(LanguageType nLanguage, bool
pForbiddenCharacters = &(it->second);
else if (bGetDefault && m_xContext.is())
{
LocaleDataWrapper aWrapper(m_xContext, LanguageTag(nLanguage));
maMap[nLanguage] = aWrapper.getForbiddenCharacters();
const LocaleDataWrapper* pWrapper = LocaleDataWrapper::get(LanguageTag(nLanguage));
maMap[nLanguage] = pWrapper->getForbiddenCharacters();
pForbiddenCharacters = &maMap[nLanguage];
}
return pForbiddenCharacters;
+9 -9
View File
@@ -55,8 +55,8 @@ class OnDemandLocaleDataWrapper
SvtSysLocale aSysLocale;
LanguageType eCurrentLanguage;
LanguageType eLastAnyLanguage;
std::optional<LocaleDataWrapper> moEnglish;
std::optional<LocaleDataWrapper> moAny;
const LocaleDataWrapper* mpEnglish{ nullptr };
const LocaleDataWrapper* mpAny{ nullptr };
int nCurrent; // 0 == system, 1 == english, 2 == any
bool bInitialized;
@@ -86,20 +86,20 @@ public:
nCurrent = 0;
else if (eLang == LANGUAGE_ENGLISH_US)
{
if (!moEnglish)
moEnglish.emplace(m_xContext, rLanguageTag);
if (!mpEnglish)
mpEnglish = LocaleDataWrapper::get(rLanguageTag);
nCurrent = 1;
}
else
{
if (!moAny)
if (!mpAny)
{
moAny.emplace(m_xContext, rLanguageTag);
mpAny = LocaleDataWrapper::get(rLanguageTag);
eLastAnyLanguage = eLang;
}
else if (eLastAnyLanguage != eLang)
{
moAny.emplace(m_xContext, rLanguageTag);
mpAny = LocaleDataWrapper::get(rLanguageTag);
eLastAnyLanguage = eLang;
}
nCurrent = 2;
@@ -116,9 +116,9 @@ public:
case 0:
return &aSysLocale.GetLocaleData();
case 1:
return &*moEnglish;
return mpEnglish;
case 2:
return &*moAny;
return mpAny;
default:
assert(false);
return nullptr;
+2 -2
View File
@@ -54,7 +54,7 @@ private:
LanguageTag maLanguageTag;
css::uno::Reference< css::uno::XComponentContext > m_xContext;
std::unique_ptr<LocaleDataWrapper> pLocaleData;
const LocaleDataWrapper* pLocaleData { nullptr };
std::optional<CollatorWrapper> moCollator;
std::optional<CollatorWrapper> moCaseCollator;
@@ -69,7 +69,7 @@ public:
{
if ( !pLocaleData )
ImplNewLocaleData();
return pLocaleData.get();
return pLocaleData;
}
/// case insensitive collator, simple IGNORE_CASE
const CollatorWrapper* getCollator() const
+8 -1
View File
@@ -118,11 +118,18 @@ class UNOTOOLS_DLLPUBLIC LocaleDataWrapper
SAL_DLLPRIVATE void loadDigitGrouping();
public:
LocaleDataWrapper(
const css::uno::Reference< css::uno::XComponentContext > & rxContext,
LanguageTag aLanguageTag
);
public:
/**
* retrieve a cached LocaleDataWrapper
*/
static const LocaleDataWrapper* get(const LanguageTag& aLanguageTag);
/**
@param rOverrideDateAcceptancePatterns Override locale's date acceptance patterns.
An empty sequence resets the patterns to the locale's pattern sequence.
+2 -2
View File
@@ -45,7 +45,7 @@ class VCL_DLLPUBLIC I18nHelper
LanguageTag maLanguageTag;
css::uno::Reference< css::uno::XComponentContext > m_xContext;
std::unique_ptr<LocaleDataWrapper> mpLocaleDataWrapper;
const LocaleDataWrapper* mpLocaleDataWrapper { nullptr };
std::unique_ptr<utl::TransliterationWrapper> mpTransliterationWrapper;
bool mbTransliterateIgnoreCase;
@@ -53,7 +53,7 @@ class VCL_DLLPUBLIC I18nHelper
SAL_DLLPRIVATE void ImplDestroyWrappers();
SAL_DLLPRIVATE utl::TransliterationWrapper& ImplGetTransliterationWrapper() const;
SAL_DLLPRIVATE LocaleDataWrapper& ImplGetLocaleDataWrapper() const;
SAL_DLLPRIVATE const LocaleDataWrapper& ImplGetLocaleDataWrapper() const;
public:
+1 -1
View File
@@ -54,7 +54,7 @@ private:
OUStringBuffer m_sBlankWidthString;
bool m_bHasText;
std::unique_ptr<SvXMLNumUsedList_Impl> m_pUsedList;
std::unique_ptr<LocaleDataWrapper> m_pLocaleData;
const LocaleDataWrapper* m_pLocaleData { nullptr };
SAL_DLLPRIVATE void AddCalendarAttr_Impl( const OUString& rCalendar );
SAL_DLLPRIVATE void AddStyleAttr_Impl( bool bLong );
+2 -3
View File
@@ -36,10 +36,9 @@ namespace
return ScGlobal::getLocaleData().getNumDecimalSep();
// LocaleDataWrapper can be expensive to construct, so cache the result for
// repeated calls
static std::optional<LocaleDataWrapper> localeCache;
static const LocaleDataWrapper* localeCache { nullptr };
if (!localeCache || localeCache->getLanguageTag().getLanguageType() != nFormatLang)
localeCache.emplace(
comphelper::getProcessComponentContext(), LanguageTag(nFormatLang));
localeCache = LocaleDataWrapper::get(LanguageTag(nFormatLang));
return localeCache->getNumDecimalSep();
}
}
+3 -3
View File
@@ -809,11 +809,11 @@ sal_Int32 ScXMLImport::SetCurrencySymbol(const sal_Int32 nKey, std::u16string_vi
{
{
ScXMLImport::MutexGuard aGuard(*this);
LocaleDataWrapper aLocaleData( comphelper::getProcessComponentContext(), LanguageTag( aLocale) );
const LocaleDataWrapper* pLocaleData = LocaleDataWrapper::get( LanguageTag( aLocale) );
sFormatString = "#" +
aLocaleData.getNumThousandSep() +
pLocaleData->getNumThousandSep() +
"##0" +
aLocaleData.getNumDecimalSep() +
pLocaleData->getNumDecimalSep() +
"00 [$" +
rCurrency +
"]";
+2 -2
View File
@@ -2009,8 +2009,8 @@ CPPUNIT_TEST_FIXTURE(Test, testLanguageNone)
sal_uInt32 nKey = aFormatter.GetEntryKey(code, LANGUAGE_GERMAN);
CPPUNIT_ASSERT(nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
SvNumberformat const*const pFormat = aFormatter.GetEntry(nKey);
LocaleDataWrapper ldw(m_xContext, LanguageTag(pFormat->GetLanguage()));
CPPUNIT_ASSERT_EQUAL(u"dd.mm.yyyy"_ustr, pFormat->GetMappedFormatstring(keywords, ldw));
const LocaleDataWrapper* ldw = LocaleDataWrapper::get(LanguageTag(pFormat->GetLanguage()));
CPPUNIT_ASSERT_EQUAL(u"dd.mm.yyyy"_ustr, pFormat->GetMappedFormatstring(keywords, *ldw));
}
CPPUNIT_TEST_FIXTURE(Test, testTdf160306)
+2 -6
View File
@@ -4673,8 +4673,7 @@ void SvNumberFormatter::ImpInitCurrencyTable()
bInitializing = true;
LanguageType eSysLang = SvtSysLocale().GetLanguageTag().getLanguageType();
std::optional<LocaleDataWrapper> pLocaleData(std::in_place,
::comphelper::getProcessComponentContext(),
const LocaleDataWrapper* pLocaleData = LocaleDataWrapper::get(
SvtSysLocale().GetLanguageTag() );
// get user configured currency
OUString aConfiguredCurrencyAbbrev;
@@ -4700,9 +4699,7 @@ void SvNumberFormatter::ImpInitCurrencyTable()
{
LanguageType eLang = LanguageTag::convertToLanguageType( rLocale, false);
theInstalledLocales.insert( eLang);
pLocaleData.emplace(
::comphelper::getProcessComponentContext(),
LanguageTag(rLocale) );
pLocaleData = LocaleDataWrapper::get( LanguageTag(rLocale) );
Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
sal_Int32 nCurrencyCount = aCurrSeq.getLength();
Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
@@ -4814,7 +4811,6 @@ void SvNumberFormatter::ImpInitCurrencyTable()
LocaleDataWrapper::outputCheckMessage(
"SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
}
pLocaleData.reset();
SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( nullptr, SvNumberFormatter, CurrencyChangeLink ) );
bInitializing = false;
g_CurrencyTableInitialized = true;
+2 -2
View File
@@ -75,10 +75,10 @@ void SwBreakIt::GetLocale_( const LanguageTag& rLanguageTag )
void SwBreakIt::GetForbidden_( const LanguageType aLang )
{
LocaleDataWrapper aWrap(m_xContext, GetLanguageTag(aLang));
const LocaleDataWrapper* pWrap = LocaleDataWrapper::get(GetLanguageTag(aLang));
m_aForbiddenLang = aLang;
m_oForbidden.emplace(aWrap.getForbiddenCharacters());
m_oForbidden.emplace(pWrap->getForbiddenCharacters());
}
sal_uInt16 SwBreakIt::GetRealScriptOfText( const OUString& rText, sal_Int32 nPos ) const
+2 -3
View File
@@ -2744,11 +2744,10 @@ bool MSWordExportBase::GetNumberFormat(const SwField& rField, OUString& rStr)
{
nLng = pNumFormat->GetLanguage();
}
LocaleDataWrapper aLocDat(pNFormatr->GetComponentContext(),
LanguageTag(nLng));
const LocaleDataWrapper* pLocDat = LocaleDataWrapper::get(LanguageTag(nLng));
OUString sFormat(pNumFormat->GetMappedFormatstring(GetNfKeywordTable(),
aLocDat));
*pLocDat));
if (!sFormat.isEmpty())
{
+4 -4
View File
@@ -330,14 +330,14 @@ css::uno::Any UnoControlModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const
}
// the remaining is the locale
LocaleDataWrapper aLocaleInfo( m_xContext, LanguageTag(sDefaultCurrency) );
const LocaleDataWrapper* pLocaleInfo = LocaleDataWrapper::get( LanguageTag(sDefaultCurrency) );
if ( sBankSymbol.isEmpty() )
sBankSymbol = aLocaleInfo.getCurrBankSymbol();
sBankSymbol = pLocaleInfo->getCurrBankSymbol();
// look for the currency entry (for this language) which has the given bank symbol
const Sequence< Currency2 > aAllCurrencies = aLocaleInfo.getAllCurrencies();
const Sequence< Currency2 > aAllCurrencies = pLocaleInfo->getAllCurrencies();
OUString sCurrencySymbol = aLocaleInfo.getCurrSymbol();
OUString sCurrencySymbol = pLocaleInfo->getCurrSymbol();
if ( sBankSymbol.isEmpty() )
{
DBG_ASSERT( aAllCurrencies.hasElements(), "UnoControlModel::ImplGetDefaultValue: no currencies at all!" );
+1 -1
View File
@@ -37,7 +37,7 @@ IntlWrapper::~IntlWrapper()
void IntlWrapper::ImplNewLocaleData() const
{
const_cast<IntlWrapper*>(this)->pLocaleData.reset( new LocaleDataWrapper( m_xContext, maLanguageTag ) );
const_cast<IntlWrapper*>(this)->pLocaleData = LocaleDataWrapper::get( maLanguageTag );
}
void IntlWrapper::ImplNewCollator( bool bCaseSensitive ) const
@@ -43,6 +43,8 @@
#include <tools/time.hxx>
#include <tools/duration.hxx>
#include <o3tl/string_view.hxx>
#include <map>
#include <mutex>
#include <utility>
const sal_uInt16 nCurrFormatDefault = 0;
@@ -59,6 +61,26 @@ namespace
sal_uInt8 LocaleDataWrapper::nLocaleDataChecking = 0;
/**
* Loading LocaleDataWrapper can become expensive because of all the function-symbol lookups required, so
* we cache these.
*/
// static
const LocaleDataWrapper* LocaleDataWrapper::get(const LanguageTag& aLanguageTag)
{
static std::map<LanguageTag, std::unique_ptr<LocaleDataWrapper>> gCache;
static std::mutex gMutex;
std::unique_lock l(gMutex);
auto it = gCache.find(aLanguageTag);
if (it != gCache.end())
return it->second.get();
auto pNew = new LocaleDataWrapper(comphelper::getProcessComponentContext(), aLanguageTag);
gCache.insert({aLanguageTag, std::unique_ptr<LocaleDataWrapper>(pNew)});
return pNew;
};
LocaleDataWrapper::LocaleDataWrapper(
const Reference< uno::XComponentContext > & rxContext,
LanguageTag aLanguageTag
+3 -3
View File
@@ -47,7 +47,7 @@ vcl::I18nHelper::~I18nHelper()
void vcl::I18nHelper::ImplDestroyWrappers()
{
mpLocaleDataWrapper.reset();
mpLocaleDataWrapper = nullptr;
mpTransliterationWrapper.reset();
}
@@ -65,11 +65,11 @@ utl::TransliterationWrapper& vcl::I18nHelper::ImplGetTransliterationWrapper() co
return *mpTransliterationWrapper;
}
LocaleDataWrapper& vcl::I18nHelper::ImplGetLocaleDataWrapper() const
const LocaleDataWrapper& vcl::I18nHelper::ImplGetLocaleDataWrapper() const
{
if ( !mpLocaleDataWrapper )
{
const_cast<vcl::I18nHelper*>(this)->mpLocaleDataWrapper.reset(new LocaleDataWrapper( m_xContext, maLanguageTag ));
const_cast<vcl::I18nHelper*>(this)->mpLocaleDataWrapper = LocaleDataWrapper::get( maLanguageTag );
}
return *mpLocaleDataWrapper;
}
+7 -13
View File
@@ -282,9 +282,9 @@ struct ImplAllSettingsData
SvtSysLocale maSysLocale;
LanguageTag maLocale;
LanguageTag maUILocale;
mutable std::unique_ptr<LocaleDataWrapper> mpLocaleDataWrapper;
mutable std::unique_ptr<LocaleDataWrapper> mpUILocaleDataWrapper;
mutable std::unique_ptr<LocaleDataWrapper> mpNeutralLocaleDataWrapper;
mutable const LocaleDataWrapper* mpLocaleDataWrapper { nullptr };
mutable const LocaleDataWrapper* mpUILocaleDataWrapper { nullptr };
mutable const LocaleDataWrapper* mpNeutralLocaleDataWrapper { nullptr };
mutable std::unique_ptr<vcl::I18nHelper> mpI18nHelper;
mutable std::unique_ptr<vcl::I18nHelper> mpUII18nHelper;
@@ -2545,9 +2545,6 @@ ImplAllSettingsData::ImplAllSettingsData( const ImplAllSettingsData& rData ) :
ImplAllSettingsData::~ImplAllSettingsData()
{
mpLocaleDataWrapper.reset();
mpUILocaleDataWrapper.reset();
mpNeutralLocaleDataWrapper.reset();
mpI18nHelper.reset();
mpUII18nHelper.reset();
}
@@ -2650,7 +2647,7 @@ void AllSettings::SetLanguageTag( const LanguageTag& rLanguageTag )
if ( myData->mpLocaleDataWrapper )
{
myData->mpLocaleDataWrapper.reset();
myData->mpLocaleDataWrapper = nullptr;
}
if ( myData->mpI18nHelper )
{
@@ -2753,24 +2750,21 @@ const LanguageTag& AllSettings::GetUILanguageTag() const
const LocaleDataWrapper& AllSettings::GetLocaleDataWrapper() const
{
if ( !mxData->mpLocaleDataWrapper )
mxData->mpLocaleDataWrapper.reset( new LocaleDataWrapper(
comphelper::getProcessComponentContext(), GetLanguageTag() ) );
mxData->mpLocaleDataWrapper = LocaleDataWrapper::get( GetLanguageTag() );
return *mxData->mpLocaleDataWrapper;
}
const LocaleDataWrapper& AllSettings::GetUILocaleDataWrapper() const
{
if ( !mxData->mpUILocaleDataWrapper )
mxData->mpUILocaleDataWrapper.reset( new LocaleDataWrapper(
comphelper::getProcessComponentContext(), GetUILanguageTag() ) );
mxData->mpUILocaleDataWrapper = LocaleDataWrapper::get( GetUILanguageTag() );
return *mxData->mpUILocaleDataWrapper;
}
const LocaleDataWrapper& AllSettings::GetNeutralLocaleDataWrapper() const
{
if ( !mxData->mpNeutralLocaleDataWrapper )
mxData->mpNeutralLocaleDataWrapper.reset( new LocaleDataWrapper(
comphelper::getProcessComponentContext(), LanguageTag(u"en-US"_ustr) ) );
mxData->mpNeutralLocaleDataWrapper = LocaleDataWrapper::get( LanguageTag(u"en-US"_ustr) );
return *mxData->mpNeutralLocaleDataWrapper;
}
+5 -8
View File
@@ -224,14 +224,13 @@ SvXMLNumFmtExport::SvXMLNumFmtExport(
if ( m_pFormatter )
{
m_pLocaleData.reset( new LocaleDataWrapper( m_pFormatter->GetComponentContext(),
m_pFormatter->GetLanguageTag() ) );
m_pLocaleData = LocaleDataWrapper::get( m_pFormatter->GetLanguageTag() );
}
else
{
LanguageTag aLanguageTag( MsLangId::getConfiguredSystemLanguage() );
m_pLocaleData.reset( new LocaleDataWrapper( m_rExport.getComponentContext(), std::move(aLanguageTag) ) );
m_pLocaleData = LocaleDataWrapper::get( std::move(aLanguageTag) );
}
m_pUsedList.reset(new SvXMLNumUsedList_Impl);
@@ -254,14 +253,13 @@ SvXMLNumFmtExport::SvXMLNumFmtExport(
if ( m_pFormatter )
{
m_pLocaleData.reset( new LocaleDataWrapper( m_pFormatter->GetComponentContext(),
m_pFormatter->GetLanguageTag() ) );
m_pLocaleData = LocaleDataWrapper::get( m_pFormatter->GetLanguageTag() );
}
else
{
LanguageTag aLanguageTag( MsLangId::getConfiguredSystemLanguage() );
m_pLocaleData.reset( new LocaleDataWrapper( m_rExport.getComponentContext(), std::move(aLanguageTag) ) );
m_pLocaleData = LocaleDataWrapper::get( std::move(aLanguageTag) );
}
m_pUsedList.reset(new SvXMLNumUsedList_Impl);
@@ -1780,8 +1778,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt
if ( nElemType == NF_KEY_NNNN )
{
// write additional text element for separator
m_pLocaleData.reset( new LocaleDataWrapper( m_pFormatter->GetComponentContext(),
LanguageTag( nLang ) ) );
m_pLocaleData = LocaleDataWrapper::get( LanguageTag( nLang ) );
AddToTextElement_Impl( m_pLocaleData->getLongDateDayOfWeekSep() );
}
}
+2 -4
View File
@@ -65,7 +65,7 @@ struct SvXMLNumFmtEntry
class SvXMLNumImpData
{
SvNumberFormatter* pFormatter;
std::unique_ptr<LocaleDataWrapper> pLocaleData;
const LocaleDataWrapper* pLocaleData { nullptr };
std::vector<SvXMLNumFmtEntry> m_NameEntries;
uno::Reference< uno::XComponentContext > m_xContext;
@@ -370,9 +370,7 @@ void SvXMLNumImpData::RemoveVolatileFormats()
const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang )
{
if ( !pLocaleData || pLocaleData->getLanguageTag() != LanguageTag(nLang) )
pLocaleData = std::make_unique<LocaleDataWrapper>(
pFormatter ? pFormatter->GetComponentContext() : m_xContext,
LanguageTag( nLang ) );
pLocaleData = LocaleDataWrapper::get( LanguageTag( nLang ) );
return *pLocaleData;
}