sc/inc/compiler.hxx | 2 sc/inc/rangenam.hxx | 30 +++++++++--- sc/source/core/tool/compiler.cxx | 36 ++++++++++---- sc/source/core/tool/rangenam.cxx | 75 +++++++++++++++---------------- sc/source/ui/docshell/externalrefmgr.cxx | 6 +- 5 files changed, 90 insertions(+), 59 deletions(-)
New commits: commit 4f2ec0ab9c1055920cb5c08b2d237087493130b8 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Mar 8 17:53:27 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue Mar 8 21:18:00 2022 +0100 optimize checking for conflicting named ranges This extends 582fc887f1faafe8ff5f16a13a0208483a93353f, first check if there is any named range that could possibly conflict (which generally should be rare). Change-Id: Ia5e9e56cab29b459bcb489e871b4960ba215b665 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131219 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx index 15b3823f649d..5f3b6354c967 100644 --- a/sc/inc/compiler.hxx +++ b/sc/inc/compiler.hxx @@ -375,6 +375,8 @@ private: */ ScRangeData* GetRangeData( const formula::FormulaToken& pToken ) const; + bool HasPossibleNamedRangeConflict(SCTAB nTab) const; + static const CharClass* GetCharClassEnglish(); static const CharClass* GetCharClassLocalized(); diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx index d51aa85a1008..31bdd1f5a23c 100644 --- a/sc/inc/rangenam.hxx +++ b/sc/inc/rangenam.hxx @@ -156,6 +156,8 @@ public: SC_DLLPUBLIC static IsNameValidType IsNameValid( const OUString& rName, const ScDocument& rDoc ); + bool HasPossibleAddressConflict() const; + void CompileUnresolvedXML( sc::CompileFormulaContext& rCxt ); #if DEBUG_FORMULA_COMPILER @@ -187,6 +189,12 @@ private: typedef ::std::map<OUString, std::unique_ptr<ScRangeData>> DataType; DataType m_Data; IndexDataType maIndexToData; + // Use for optimization, true if any of the contained names resolves + // as a valid cell address (e.g. 'day1' with 16k columns). + mutable bool mHasPossibleAddressConflict : 1; + mutable bool mHasPossibleAddressConflictDirty : 1; + + void checkHasPossibleAddressConflict() const; public: /// Map that stores non-managed pointers to ScRangeName instances. @@ -266,6 +274,13 @@ public: void clear(); bool operator== (const ScRangeName& r) const; + + bool hasPossibleAddressConflict() const + { + if( mHasPossibleAddressConflictDirty ) + checkHasPossibleAddressConflict(); + return mHasPossibleAddressConflict; + } }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index fca54da17f9c..151ccefd6134 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -3344,17 +3344,20 @@ bool ScCompiler::ParseSingleReference( const OUString& rName, const OUString* pE return false; } - // A named range named e.g. 'num1' is valid with 1k columns, but would become a reference - // when the document is opened later with 16k columns. Resolve the conflict by not - // considering it a reference. - OUString aUpper; - bool bAsciiUpper = ToUpperAsciiOrI18nIsAscii( aUpper, rName ); - if (bAsciiUpper || mbCharClassesDiffer) - aUpper = ScGlobal::getCharClass().uppercase( rName ); - mnCurrentSheetTab = aAddr.Tab(); // temporarily set for ParseNamedRange() - if(ParseNamedRange( aUpper, true )) // only check - return false; - mnCurrentSheetTab = -1; + if( HasPossibleNamedRangeConflict( aAddr.Tab())) + { + // A named range named e.g. 'num1' is valid with 1k columns, but would become a reference + // when the document is opened later with 16k columns. Resolve the conflict by not + // considering it a reference. + OUString aUpper; + bool bAsciiUpper = ToUpperAsciiOrI18nIsAscii( aUpper, rName ); + if (bAsciiUpper || mbCharClassesDiffer) + aUpper = ScGlobal::getCharClass().uppercase( rName ); + mnCurrentSheetTab = aAddr.Tab(); // temporarily set for ParseNamedRange() + if(ParseNamedRange( aUpper, true )) // only check + return false; + mnCurrentSheetTab = -1; + } ScSingleRefData aRef; aRef.InitAddress( aAddr ); @@ -3586,6 +3589,17 @@ const ScRangeData* ScCompiler::GetRangeData( SCTAB& rSheet, const OUString& rUpp return pData; } +bool ScCompiler::HasPossibleNamedRangeConflict( SCTAB nTab ) const +{ + const ScRangeName* pRangeName = rDoc.GetRangeName(); + if (pRangeName && pRangeName->hasPossibleAddressConflict()) + return true; + pRangeName = rDoc.GetRangeName(nTab); + if (pRangeName && pRangeName->hasPossibleAddressConflict()) + return true; + return false; +} + bool ScCompiler::ParseNamedRange( const OUString& rUpperName, bool onlyCheck ) { // ParseNamedRange is called only from NextNewToken, with an upper-case string diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx index 09bef58a1bd4..89d3f9e75055 100644 --- a/sc/source/core/tool/rangenam.cxx +++ b/sc/source/core/tool/rangenam.cxx @@ -497,6 +497,21 @@ ScRangeData::IsNameValidType ScRangeData::IsNameValid( const OUString& rName, co return IsNameValidType::NAME_VALID; } +bool ScRangeData::HasPossibleAddressConflict() const +{ + // Similar to part of IsNameValid(), but only check if the name is a valid address. + ScAddress aAddr; + for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; ) + { + ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) ); + // Don't check Parse on VALID, any partial only VALID may result in + // #REF! during compile later! + if(aAddr.Parse(aUpperName, rDoc, details) != ScRefFlags::ZERO) + return true; + } + return false; +} + FormulaError ScRangeData::GetErrCode() const { return pCode ? pCode->GetCodeError() : FormulaError::NONE; @@ -654,6 +669,8 @@ public: ScRangeName::ScRangeName() {} ScRangeName::ScRangeName(const ScRangeName& r) + : mHasPossibleAddressConflict( r.mHasPossibleAddressConflict ) + , mHasPossibleAddressConflictDirty( r.mHasPossibleAddressConflictDirty ) { for (auto const& it : r.m_Data) { @@ -817,6 +834,7 @@ bool ScRangeName::insert( ScRangeData* p, bool bReuseFreeIndex ) if (nPos >= maIndexToData.size()) maIndexToData.resize(nPos+1, nullptr); maIndexToData[nPos] = p; + mHasPossibleAddressConflictDirty = true; } return r.second; } @@ -840,12 +858,30 @@ void ScRangeName::erase(const_iterator itr) OSL_ENSURE( 0 < nIndex && nIndex <= maIndexToData.size(), "ScRangeName::erase: bad index"); if (0 < nIndex && nIndex <= maIndexToData.size()) maIndexToData[nIndex-1] = nullptr; + if(mHasPossibleAddressConflict) + mHasPossibleAddressConflictDirty = true; } void ScRangeName::clear() { m_Data.clear(); maIndexToData.clear(); + mHasPossibleAddressConflict = false; + mHasPossibleAddressConflictDirty = false; +} + +void ScRangeName::checkHasPossibleAddressConflict() const +{ + mHasPossibleAddressConflict = false; + mHasPossibleAddressConflictDirty = false; + for (auto const& itr : m_Data) + { + if( itr.second->HasPossibleAddressConflict()) + { + mHasPossibleAddressConflict = true; + return; + } + } } bool ScRangeName::operator== (const ScRangeName& r) const commit 371e82c2d90c21bb9df6e4c110a229d29e24c4d3 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Mar 8 17:08:55 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue Mar 8 21:17:46 2022 +0100 don't provide non-const iterators to ScRangeName internal data Also make few trivial functions inline. Change-Id: I89b11b2aa4558696d624c9bde9135b1324b8eb36 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131218 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx index f7217d567e87..d51aa85a1008 100644 --- a/sc/inc/rangenam.hxx +++ b/sc/inc/rangenam.hxx @@ -234,13 +234,11 @@ public: void CopyUsedNames( const SCTAB nLocalTab, const SCTAB nOldTab, const SCTAB nNewTab, const ScDocument& rOldDoc, ScDocument& rNewDoc, const bool bGlobalNamesToLocal ) const; - SC_DLLPUBLIC const_iterator begin() const; - SC_DLLPUBLIC const_iterator end() const; - SC_DLLPUBLIC iterator begin(); - SC_DLLPUBLIC iterator end(); - SC_DLLPUBLIC size_t size() const; - SC_DLLPUBLIC size_t index_size() const; - bool empty() const; + SC_DLLPUBLIC const_iterator begin() const { return m_Data.begin(); } + SC_DLLPUBLIC const_iterator end() const { return m_Data.end(); } + SC_DLLPUBLIC size_t size() const { return m_Data.size(); } + SC_DLLPUBLIC size_t index_size() const { return maIndexToData.size(); } + bool empty() const { return m_Data.empty(); } /** Insert object into set. @ATTENTION: The underlying ::std::map<std::unique_ptr>::insert(p) takes @@ -264,7 +262,8 @@ public: * iterator's validity. The caller must make sure that the iterator is * valid. */ - void erase(const iterator& itr); + void erase(const_iterator itr); + void clear(); bool operator== (const ScRangeName& r) const; }; diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx index 11e177158148..09bef58a1bd4 100644 --- a/sc/source/core/tool/rangenam.cxx +++ b/sc/source/core/tool/rangenam.cxx @@ -778,41 +778,6 @@ void ScRangeName::CopyUsedNames( const SCTAB nLocalTab, const SCTAB nOldTab, con } } -ScRangeName::const_iterator ScRangeName::begin() const -{ - return m_Data.begin(); -} - -ScRangeName::const_iterator ScRangeName::end() const -{ - return m_Data.end(); -} - -ScRangeName::iterator ScRangeName::begin() -{ - return m_Data.begin(); -} - -ScRangeName::iterator ScRangeName::end() -{ - return m_Data.end(); -} - -size_t ScRangeName::size() const -{ - return m_Data.size(); -} - -size_t ScRangeName::index_size() const -{ - return maIndexToData.size(); -} - -bool ScRangeName::empty() const -{ - return m_Data.empty(); -} - bool ScRangeName::insert( ScRangeData* p, bool bReuseFreeIndex ) { if (!p) @@ -863,12 +828,12 @@ void ScRangeName::erase(const ScRangeData& r) void ScRangeName::erase(const OUString& rName) { - DataType::iterator itr = m_Data.find(rName); + DataType::const_iterator itr = m_Data.find(rName); if (itr != m_Data.end()) erase(itr); } -void ScRangeName::erase(const iterator& itr) +void ScRangeName::erase(const_iterator itr) { sal_uInt16 nIndex = itr->second->GetIndex(); m_Data.erase(itr); diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx index 1fac22e41861..c25a79f1f919 100644 --- a/sc/source/ui/docshell/externalrefmgr.cxx +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -222,7 +222,7 @@ class EraseRangeByIterator ScRangeName& mrRanges; public: explicit EraseRangeByIterator(ScRangeName& rRanges) : mrRanges(rRanges) {} - void operator() (const ScRangeName::iterator& itr) + void operator() (const ScRangeName::const_iterator& itr) { mrRanges.erase(itr); } @@ -234,8 +234,8 @@ public: */ void removeRangeNamesBySrcDoc(ScRangeName& rRanges, sal_uInt16 nFileId) { - ScRangeName::iterator itr = rRanges.begin(), itrEnd = rRanges.end(); - vector<ScRangeName::iterator> v; + ScRangeName::const_iterator itr = rRanges.begin(), itrEnd = rRanges.end(); + vector<ScRangeName::const_iterator> v; for (; itr != itrEnd; ++itr) { if (hasRefsToSrcDoc(*itr->second, nFileId))