diff options
author | Caolán McNamara <caolan.mcnamara@collabora.com> | 2024-03-28 09:55:06 +0000 |
---|---|---|
committer | Caolán McNamara <caolan.mcnamara@collabora.com> | 2024-03-29 09:51:12 +0100 |
commit | e8e0a3b1d7e706330ca343cf9dd5ba062e9ff0c4 (patch) | |
tree | 544402e3766feec77b0a717b45a43946da8f9ff2 | |
parent | 40176bd39c94c32ac0269d9994e8e50518d84467 (diff) |
crashtesting: fix SvNFEngine::CacheFormatRO assert
since:
commit c6c6126aa3e8de256091b829b98b5943db6a8be6
Author: Caolán McNamara <caolan.mcnamara@collabora.com>
Date: Thu Mar 21 17:25:35 2024 +0000
Related: tdf#160056 refactor SvNumberFormatter
to split it into two constituent parts
Change-Id: I4add9f383789ab03ceab751b07973448a41911ba
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165490
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
-rw-r--r-- | include/svl/nfengine.hxx | 28 | ||||
-rw-r--r-- | include/svl/numformat.hxx | 2 | ||||
-rw-r--r-- | sc/inc/interpretercontext.hxx | 7 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 1 | ||||
-rw-r--r-- | sc/source/core/tool/interpretercontext.cxx | 15 | ||||
-rw-r--r-- | svl/source/numbers/zforlist.cxx | 162 |
6 files changed, 148 insertions, 67 deletions
diff --git a/include/svl/nfengine.hxx b/include/svl/nfengine.hxx index a4890e074d1a..c0b463c189f3 100644 --- a/include/svl/nfengine.hxx +++ b/include/svl/nfengine.hxx @@ -159,10 +159,12 @@ private: class SVL_DLLPUBLIC SvNFFormatData { +public: + typedef std::map<sal_uInt32, sal_uInt32> DefaultFormatKeysMap; + private: typedef std::map<sal_uInt32, std::unique_ptr<SvNumberformat>> FormatEntryMap; FormatEntryMap aFTable; // Table of format keys to format entries - typedef std::map<sal_uInt32, sal_uInt32> DefaultFormatKeysMap; DefaultFormatKeysMap aDefaultFormatKeys; // Table of default standard to format keys sal_uInt32 MaxCLOffset; // Max language/country offset used sal_uInt32 nDefaultSystemCurrencyFormat; // NewCurrency matching SYSTEM locale @@ -190,6 +192,8 @@ public: bool GetNewCurrencySymbolString(sal_uInt32 nFormat, OUString& rSymbol, const NfCurrencyEntry** ppEntry, bool* pBank = nullptr) const; + void MergeDefaultFormatKeys(const DefaultFormatKeysMap& rDefaultFormatKeys); + private: SvNFFormatData(const SvNFFormatData&) = delete; SvNFFormatData& operator=(const SvNFFormatData&) = delete; @@ -262,8 +266,7 @@ private: SVL_DLLPRIVATE sal_uInt32 ImpGetDefaultSystemCurrencyFormat(SvNFLanguageData& rCurrentLanguage, const NativeNumberWrapper* pNatNum); - SVL_DLLPRIVATE std::pair<sal_uInt32, bool> - ImpGetDefaultFormat(SvNumFormatType nType, sal_uInt32 nSearch, sal_uInt32 CLOffset) const; + SVL_DLLPRIVATE sal_uInt32 FindCachedDefaultFormat(sal_uInt32 nSearch) const; SVL_DLLPRIVATE static sal_Int32 ImpGetFormatCodeIndex(const SvNFLanguageData& rCurrentLanguage, @@ -282,6 +285,7 @@ public: const NativeNumberWrapper* pNatNum, LanguageType eLnge)> GetCLOffset; typedef std::function<void(sal_uInt32 nSearch, sal_uInt32 nFormat)> CacheFormat; + typedef std::function<sal_uInt32(sal_uInt32 nSearch)> FindFormat; typedef std::function<sal_uInt32(SvNFLanguageData& rCurrentLanguage, const NativeNumberWrapper* pNatNum, sal_uInt32 CLOffset, @@ -292,11 +296,13 @@ public: { GetCLOffset mGetCLOffset; CacheFormat mCacheFormat; + FindFormat mFindFormat; GetDefaultCurrency mGetDefaultCurrency; }; static Accessor GetRWPolicy(SvNFFormatData& rFormatData); - static Accessor GetROPolicy(const SvNFFormatData& rFormatData); + static Accessor GetROPolicy(const SvNFFormatData& rFormatData, + SvNFFormatData::DefaultFormatKeysMap& rFormatCache); static void ChangeIntl(SvNFLanguageData& rCurrentLanguage, LanguageType eLnge); static void ChangeNullDate(SvNFLanguageData& rCurrentLanguage, sal_uInt16 nDay, @@ -403,9 +409,12 @@ public: bool IsRed, sal_uInt16 nPrecision, sal_uInt16 nLeadingZeros); private: - static sal_uInt32 ImpGetDefaultFormat(const SvNFFormatData& rFormatData, - const SvNFEngine::CacheFormat& rFunc, + static sal_uInt32 ImpGetDefaultFormat(const SvNFFormatData& rFormatData, const Accessor& rFuncs, SvNumFormatType nType, sal_uInt32 CLOffset); + + static sal_uInt32 ImpGetDefaultFormat(const SvNFFormatData& rFormatData, SvNumFormatType nType, + sal_uInt32 CLOffset); + static sal_uInt32 ImpGetStandardFormat(SvNFLanguageData& rCurrentLanguage, const SvNFFormatData& rFormatData, const NativeNumberWrapper* pNatNum, const SvNFEngine::Accessor& rFuncs, @@ -425,8 +434,13 @@ private: const NativeNumberWrapper*, LanguageType eLnge); static void CacheFormatRW(SvNFFormatData& rFormatData, sal_uInt32 nSearch, sal_uInt32 nFormat); - static void CacheFormatRO(const SvNFFormatData& rFormatData, sal_uInt32 nSearch, + static void CacheFormatRO(SvNFFormatData::DefaultFormatKeysMap& rMap, sal_uInt32 nSearch, sal_uInt32 nFormat); + + static sal_uInt32 FindFormatRW(const SvNFFormatData& rFormatData, sal_uInt32 nSearch); + static sal_uInt32 FindFormatRO(const SvNFFormatData& rFormatData, + const SvNFFormatData::DefaultFormatKeysMap& rMap, + sal_uInt32 nSearch); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/svl/numformat.hxx b/include/svl/numformat.hxx index b26e245ca8d5..92f93bb1562a 100644 --- a/include/svl/numformat.hxx +++ b/include/svl/numformat.hxx @@ -507,6 +507,8 @@ public: language/country, used in XML import */ OUString GetStandardName(LanguageType eLnge); + void MergeDefaultFormatKeys(const SvNFFormatData::DefaultFormatKeysMap& rDefaultFormatKeys); + /** Check if a specific locale has supported locale data. */ static bool IsLocaleInstalled(LanguageType eLang); diff --git a/sc/inc/interpretercontext.hxx b/sc/inc/interpretercontext.hxx index 2f89249a21a6..ead9b04c06c7 100644 --- a/sc/inc/interpretercontext.hxx +++ b/sc/inc/interpretercontext.hxx @@ -112,6 +112,8 @@ struct ScInterpreterContext OUString NFGetCalcCellReturn(sal_uInt32 nFormat) const; + void MergeDefaultFormatKeys(SvNumberFormatter& rFormatter) const; + private: friend class ScInterpreterContextPool; void ResetTokens(); @@ -125,6 +127,11 @@ private: // the NumberFormat's data and a throw-away object for currently used language // This is essentially an exploded view of mpFormatter std::unique_ptr<SvNFLanguageData> mxLanguageData; + // FormatData can be driven read-only, but may want to cache some data, + // in RO Mode we can cache per thread to mxAuxFormatKeyMap, and + // discard or merge after threaded calculation is over + std::unique_ptr<SvNFFormatData::DefaultFormatKeysMap> mxAuxFormatKeyMap; + const SvNFFormatData* mpFormatData; SvNFEngine::Accessor maROPolicy; diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 04370b62117f..e87d100b36da 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6929,6 +6929,7 @@ void ScDocument::MergeContextBackIntoNonThreadedContext(ScInterpreterContext& th std::make_move_iterator(threadedContext.maDelayedSetNumberFormat.begin()), std::make_move_iterator(threadedContext.maDelayedSetNumberFormat.end())); // lookup cache is now only in pooled ScInterpreterContext's + threadedContext.MergeDefaultFormatKeys(*GetFormatTable()); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/interpretercontext.cxx b/sc/source/core/tool/interpretercontext.cxx index f4fde3725414..e1fc5fb24252 100644 --- a/sc/source/core/tool/interpretercontext.cxx +++ b/sc/source/core/tool/interpretercontext.cxx @@ -46,8 +46,9 @@ ScInterpreterContext::ScInterpreterContext(const ScDocument& rDoc, SvNumberForma else { mxLanguageData.reset(new SvNFLanguageData(pFormatter->GetROLanguageData())); + mxAuxFormatKeyMap.reset(new SvNFFormatData::DefaultFormatKeysMap); mpFormatData = &pFormatter->GetROFormatData(); - maROPolicy = SvNFEngine::GetROPolicy(*mpFormatData); + maROPolicy = SvNFEngine::GetROPolicy(*mpFormatData, *mxAuxFormatKeyMap); } } @@ -74,8 +75,9 @@ void ScInterpreterContext::SetDocAndFormatter(const ScDocument& rDoc, SvNumberFo { // formatter has changed mxLanguageData.reset(new SvNFLanguageData(pFormatter->GetROLanguageData())); + mxAuxFormatKeyMap.reset(new SvNFFormatData::DefaultFormatKeysMap); mpFormatData = &pFormatter->GetROFormatData(); - maROPolicy = SvNFEngine::GetROPolicy(*mpFormatData); + maROPolicy = SvNFEngine::GetROPolicy(*mpFormatData, *mxAuxFormatKeyMap); mpFormatter = pFormatter; // drop cache @@ -88,8 +90,14 @@ void ScInterpreterContext::initFormatTable() { mpFormatter = mpDoc->GetFormatTable(); // will assert if not main thread mpFormatData = &mpFormatter->GetROFormatData(); - maROPolicy = SvNFEngine::GetROPolicy(*mpFormatData); mxLanguageData.reset(new SvNFLanguageData(mpFormatter->GetROLanguageData())); + mxAuxFormatKeyMap.reset(new SvNFFormatData::DefaultFormatKeysMap); + maROPolicy = SvNFEngine::GetROPolicy(*mpFormatData, *mxAuxFormatKeyMap); +} + +void ScInterpreterContext::MergeDefaultFormatKeys(SvNumberFormatter& rFormatter) const +{ + rFormatter.MergeDefaultFormatKeys(*mxAuxFormatKeyMap); } void ScInterpreterContext::Cleanup() @@ -106,6 +114,7 @@ void ScInterpreterContext::ClearLookupCache(const ScDocument* pDoc) { mxScLookupCache.reset(); mxLanguageData.reset(); + mxAuxFormatKeyMap.reset(); mpFormatter = nullptr; mpFormatData = nullptr; } diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx index 9a4490849d11..7b2bcd4352e7 100644 --- a/svl/source/numbers/zforlist.cxx +++ b/svl/source/numbers/zforlist.cxx @@ -1537,17 +1537,19 @@ static sal_uInt32 ImpGetSearchOffset(SvNumFormatType nType, sal_uInt32 CLOffset) return nSearch; } +// static sal_uInt32 SvNFEngine::ImpGetDefaultFormat(const SvNFFormatData& rFormatData, - const SvNFEngine::CacheFormat& rFunc, + const SvNFEngine::Accessor& rFuncs, SvNumFormatType nType, sal_uInt32 CLOffset) { sal_uInt32 nSearch = ImpGetSearchOffset(nType, CLOffset); - std::pair<sal_uInt32, bool> aRes = rFormatData.ImpGetDefaultFormat(nType, nSearch, CLOffset); - const sal_uInt32 nDefaultFormat = aRes.first; - const bool bShouldCache = aRes.second; - if (bShouldCache) - rFunc(nSearch, nDefaultFormat); + sal_uInt32 nDefaultFormat = rFuncs.mFindFormat(nSearch); + if (nDefaultFormat != NUMBERFORMAT_ENTRY_NOT_FOUND) + return nDefaultFormat; + + nDefaultFormat = ImpGetDefaultFormat(rFormatData, nType, CLOffset); + rFuncs.mCacheFormat(nSearch, nDefaultFormat); return nDefaultFormat; } @@ -1602,7 +1604,7 @@ sal_uInt32 SvNFEngine::ImpGetStandardFormat(SvNFLanguageData& rCurrentLanguage, case SvNumFormatType::DATETIME: case SvNumFormatType::PERCENT: case SvNumFormatType::SCIENTIFIC: - return ImpGetDefaultFormat(rFormatData, rFuncs.mCacheFormat, eType, CLOffset); + return ImpGetDefaultFormat(rFormatData, rFuncs, eType, CLOffset); case SvNumFormatType::FRACTION: return CLOffset + ZF_STANDARD_FRACTION; case SvNumFormatType::LOGICAL: @@ -1669,59 +1671,70 @@ sal_uInt32 SvNFEngine::GetStandardFormat(SvNFLanguageData& rCurrentLanguage, return ImpGetStandardFormat(rCurrentLanguage, rFormatData, pNatNum, rFuncs, eType, nCLOffset, eLnge); } -//return a std::pair with the result and true/false if that result should be cached in aDefaultFormatKeys -std::pair<sal_uInt32, bool> SvNFFormatData::ImpGetDefaultFormat(SvNumFormatType nType, sal_uInt32 nSearch, sal_uInt32 CLOffset) const +namespace { - bool bShouldCache = false; - DefaultFormatKeysMap::const_iterator it = aDefaultFormatKeys.find(nSearch); - sal_uInt32 nDefaultFormat = (it != aDefaultFormatKeys.end() ? - it->second : NUMBERFORMAT_ENTRY_NOT_FOUND); - if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + sal_uInt32 FindCachedDefaultFormat(const SvNFFormatData::DefaultFormatKeysMap& rDefaultFormatKeys, sal_uInt32 nSearch) { - // look for a defined standard - sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET; - sal_uInt32 nKey(0); - auto it2 = aFTable.find( CLOffset ); - while ( it2 != aFTable.end() && (nKey = it2->first ) >= CLOffset && nKey < nStopKey ) + auto it = rDefaultFormatKeys.find(nSearch); + sal_uInt32 nDefaultFormat = (it != rDefaultFormatKeys.end() ? + it->second : NUMBERFORMAT_ENTRY_NOT_FOUND); + return nDefaultFormat; + } +} + +sal_uInt32 SvNFFormatData::FindCachedDefaultFormat(sal_uInt32 nSearch) const +{ + return ::FindCachedDefaultFormat(aDefaultFormatKeys, nSearch); +} + +// static +sal_uInt32 SvNFEngine::ImpGetDefaultFormat(const SvNFFormatData& rFormatData, SvNumFormatType nType, sal_uInt32 CLOffset) +{ + sal_uInt32 nDefaultFormat = NUMBERFORMAT_ENTRY_NOT_FOUND; + + // look for a defined standard + sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET; + sal_uInt32 nKey(0); + auto it2 = rFormatData.aFTable.find( CLOffset ); + while ( it2 != rFormatData.aFTable.end() && (nKey = it2->first ) >= CLOffset && nKey < nStopKey ) + { + const SvNumberformat* pEntry = it2->second.get(); + if ( pEntry->IsStandard() && (pEntry->GetMaskedType() == nType) ) { - const SvNumberformat* pEntry = it2->second.get(); - if ( pEntry->IsStandard() && (pEntry->GetMaskedType() == nType) ) - { - nDefaultFormat = nKey; - break; // while - } - ++it2; + nDefaultFormat = nKey; + break; // while } + ++it2; + } - if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) - { // none found, use old fixed standards - switch( nType ) - { - case SvNumFormatType::DATE: - nDefaultFormat = CLOffset + ZF_STANDARD_DATE; - break; - case SvNumFormatType::TIME: - nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1; - break; - case SvNumFormatType::DATETIME: - nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME; - break; - case SvNumFormatType::DURATION: - nDefaultFormat = CLOffset + ZF_STANDARD_DURATION; - break; - case SvNumFormatType::PERCENT: - nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1; - break; - case SvNumFormatType::SCIENTIFIC: - nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC; - break; - default: - nDefaultFormat = CLOffset + ZF_STANDARD; - } + if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { // none found, use old fixed standards + switch( nType ) + { + case SvNumFormatType::DATE: + nDefaultFormat = CLOffset + ZF_STANDARD_DATE; + break; + case SvNumFormatType::TIME: + nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1; + break; + case SvNumFormatType::DATETIME: + nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME; + break; + case SvNumFormatType::DURATION: + nDefaultFormat = CLOffset + ZF_STANDARD_DURATION; + break; + case SvNumFormatType::PERCENT: + nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1; + break; + case SvNumFormatType::SCIENTIFIC: + nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC; + break; + default: + nDefaultFormat = CLOffset + ZF_STANDARD; } - bShouldCache = true; } - return std::make_pair(nDefaultFormat, bShouldCache); + + return nDefaultFormat; } sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, SvNumFormatType eType, @@ -3912,9 +3925,19 @@ sal_uInt32 SvNFEngine::GetCLOffsetRO(const SvNFFormatData& rFormatData, SvNFLang return nCLOffset; } -void SvNFEngine::CacheFormatRO(const SvNFFormatData&, sal_uInt32, sal_uInt32) +// we can't cache to SvNFFormatData in RO mode, so cache to a temp map which we can consult pre-thread in FindFormatRO +// caches can be merged with SvNumberFormatter::MergeDefaultFormatKeys +void SvNFEngine::CacheFormatRO(SvNFFormatData::DefaultFormatKeysMap& rFormatCache, sal_uInt32 nSearch, sal_uInt32 nFormat) { - assert(false && "not really fatal, just not cached"); + rFormatCache[nSearch] = nFormat; +} + +sal_uInt32 SvNFEngine::FindFormatRO(const SvNFFormatData& rFormatData, const SvNFFormatData::DefaultFormatKeysMap& rFormatCache, sal_uInt32 nSearch) +{ + sal_uInt32 nFormat = rFormatData.FindCachedDefaultFormat(nSearch); + if (nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND) + return nFormat; + return ::FindCachedDefaultFormat(rFormatCache, nSearch); } sal_uInt32 SvNFEngine::GetCLOffsetRW(SvNFFormatData& rFormatData, SvNFLanguageData& rCurrentLanguage, const NativeNumberWrapper* pNatNum, LanguageType eLnge) @@ -3927,6 +3950,11 @@ void SvNFEngine::CacheFormatRW(SvNFFormatData& rFormatData, sal_uInt32 nSearch, rFormatData.aDefaultFormatKeys[nSearch] = nFormat; } +sal_uInt32 SvNFEngine::FindFormatRW(const SvNFFormatData& rFormatData, sal_uInt32 nSearch) +{ + return rFormatData.FindCachedDefaultFormat(nSearch); +} + sal_uInt32 SvNFEngine::DefaultCurrencyRW(SvNFFormatData& rFormatData, SvNFLanguageData& rCurrentLanguage, const NativeNumberWrapper* pNatNum, sal_uInt32 CLOffset, LanguageType eLnge) { if (eLnge == LANGUAGE_SYSTEM) @@ -3953,16 +3981,18 @@ SvNFEngine::Accessor SvNFEngine::GetRWPolicy(SvNFFormatData& rFormatData) { std::bind(SvNFEngine::GetCLOffsetRW, std::ref(rFormatData), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), std::bind(SvNFEngine::CacheFormatRW, std::ref(rFormatData), std::placeholders::_1, std::placeholders::_2), + std::bind(SvNFEngine::FindFormatRW, std::ref(rFormatData), std::placeholders::_1), std::bind(SvNFEngine::DefaultCurrencyRW, std::ref(rFormatData), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4) }; } -SvNFEngine::Accessor SvNFEngine::GetROPolicy(const SvNFFormatData& rFormatData) +SvNFEngine::Accessor SvNFEngine::GetROPolicy(const SvNFFormatData& rFormatData, SvNFFormatData::DefaultFormatKeysMap& rFormatCache) { return { std::bind(SvNFEngine::GetCLOffsetRO, std::ref(rFormatData), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), - std::bind(SvNFEngine::CacheFormatRO, std::ref(rFormatData), std::placeholders::_1, std::placeholders::_2), + std::bind(SvNFEngine::CacheFormatRO, std::ref(rFormatCache), std::placeholders::_1, std::placeholders::_2), + std::bind(SvNFEngine::FindFormatRO, std::ref(rFormatData), std::ref(rFormatCache), std::placeholders::_1), std::bind(SvNFEngine::DefaultCurrencyRO, std::ref(rFormatData), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4) }; } @@ -4355,6 +4385,24 @@ bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody( return true; } +void SvNFFormatData::MergeDefaultFormatKeys(const DefaultFormatKeysMap& rDefaultFormatKeys) +{ + for (const auto& r : rDefaultFormatKeys) + { +#ifndef NDEBUG + auto iter = aDefaultFormatKeys.find(r.first); + assert(iter == aDefaultFormatKeys.end() || iter->second == r.second); +#endif + aDefaultFormatKeys[r.first] = r.second; + } +} + +void SvNumberFormatter::MergeDefaultFormatKeys(const SvNFFormatData::DefaultFormatKeysMap& rDefaultFormatKeys) +{ + ::osl::MutexGuard aGuard( GetInstanceMutex() ); + m_aFormatData.MergeDefaultFormatKeys(rDefaultFormatKeys); +} + bool SvNFFormatData::GetNewCurrencySymbolString(sal_uInt32 nFormat, OUString& rStr, const NfCurrencyEntry** ppEntry /* = NULL */, bool* pBank /* = NULL */) const |