sc/inc/document.hxx              |    6 +++++
 sc/inc/table.hxx                 |   17 ++++++++------
 sc/source/core/data/documen4.cxx |    2 -
 sc/source/core/data/document.cxx |   24 +++++++++++++++-----
 sc/source/core/data/table1.cxx   |   45 ++++++++++++++++++++-------------------
 sc/source/core/data/table2.cxx   |    2 -
 sc/source/core/data/table3.cxx   |    4 +--
 sc/source/core/data/table7.cxx   |    2 -
 sc/source/filter/dif/difimp.cxx  |    2 -
 sc/source/ui/unoobj/docuno.cxx   |    2 -
 10 files changed, 65 insertions(+), 41 deletions(-)

New commits:
commit 4dfdb5a3c9b9ce1eb61c28d8f570398c04fb0d01
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Apr 21 19:11:38 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Thu Apr 21 21:07:25 2022 +0200

    rework GetColumnsRange() and ScColumnsRange
    
    The problem with GetColumnsRange() was that it was clamping the range
    to the number of allocated columns, but that's not always wanted,
    e.g. ScDocument::InsertMatrixFormula() needs to iterate over the whole
    range and allocate columns if necessary instead of ignoring them.
    From an API point of view it's also not very obvious that something
    called GetColumnsRange() actually does something more than just
    returning the given range.
    
    Handle this by making GetColumnsRange() return the actual given range,
    and add GetWriteableColumnsRange() and GetAllocatedColumnsRange()
    for the specific cases. This also required changing ScColumnsRange
    to work simply on SCCOL value instead of using std::vector iterator
    (since the vector may not have all the elements in the range).
    
    Change-Id: I9b645459461efe6b282e8ac5d7a29549830f46c1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133295
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 26e43c046164..d24f4f170239 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2607,6 +2607,12 @@ public:
     void                finalizeOutlineImport();
     bool                TableExists( SCTAB nTab ) const;
 
+    // Returns the given column range, first allocating all the columns if 
necessary.
+    SC_DLLPUBLIC ScColumnsRange GetWritableColumnsRange(SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd);
+    // Returns a column range, clamped to the allocated columns.
+    SC_DLLPUBLIC ScColumnsRange GetAllocatedColumnsRange(SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd) const;
+    // Returns the given range, without any adjustments. One of the variants 
above may return
+    // a smaller range (better performance) if the use case is known.
     SC_DLLPUBLIC ScColumnsRange GetColumnsRange(SCTAB nTab, SCCOL nColBegin, 
SCCOL nColEnd) const;
 
     bool IsInDocShellRecalc() const   { return mbDocShellRecalc; }
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 36ff984ed8fa..ba8ed9e328d8 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -123,7 +123,7 @@ class ScColumnsRange final
  public:
     class Iterator final
     {
-        std::vector<std::unique_ptr<ScColumn, 
o3tl::default_delete<ScColumn>>>::const_iterator maColIter;
+        SCCOL mCol;
     public:
         typedef std::bidirectional_iterator_tag iterator_category;
         typedef SCCOL value_type;
@@ -131,17 +131,18 @@ class ScColumnsRange final
         typedef const SCCOL* pointer;
         typedef SCCOL reference;
 
-        explicit Iterator(const std::vector<std::unique_ptr<ScColumn, 
o3tl::default_delete<ScColumn>>>::const_iterator& colIter) : maColIter(colIter) 
{}
+        explicit Iterator(SCCOL nCol) : mCol(nCol) {}
 
-        Iterator& operator++() { ++maColIter; return *this;}
-        Iterator& operator--() { --maColIter; return *this;}
+        Iterator& operator++() { ++mCol; return *this;}
+        Iterator& operator--() { --mCol; return *this;}
 
-        bool operator==(const Iterator & rOther) const {return maColIter == 
rOther.maColIter;}
+        // Comparing iterators from different containers is undefined, so 
comparing mCol is enough.
+        bool operator==(const Iterator & rOther) const {return mCol == 
rOther.mCol;}
         bool operator!=(const Iterator & rOther) const {return !(*this == 
rOther);}
-        SCCOL operator*() const {return (*maColIter)->GetCol();}
+        SCCOL operator*() const {return mCol;}
     };
 
-    ScColumnsRange(const Iterator & rBegin, const Iterator & rEnd) : 
maBegin(rBegin), maEnd(rEnd) {}
+    ScColumnsRange(SCCOL nBegin, SCCOL nEnd) : maBegin(nBegin), maEnd(nEnd) {}
     const Iterator & begin() { return maBegin; }
     const Iterator & end() { return maEnd; }
     std::reverse_iterator<Iterator> rbegin() { return 
std::reverse_iterator<Iterator>(maEnd); }
@@ -1114,6 +1115,8 @@ public:
     */
     static void UpdateSearchItemAddressForReplace( const SvxSearchItem& 
rSearchItem, SCCOL& rCol, SCROW& rRow );
 
+    ScColumnsRange GetWritableColumnsRange(SCCOL begin, SCCOL end);
+    ScColumnsRange GetAllocatedColumnsRange(SCCOL begin, SCCOL end) const;
     ScColumnsRange GetColumnsRange(SCCOL begin, SCCOL end) const;
     SCCOL ClampToAllocatedColumns(SCCOL nCol) const { return std::min(nCol, 
static_cast<SCCOL>(aCol.size() - 1)); }
     SCCOL GetAllocatedColumnsCount() const { return aCol.size(); }
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index 271e07619ef8..dff8e71c7373 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/sc/source/core/data/documen4.cxx
@@ -339,7 +339,7 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW 
nRow1,
             *t->GetSingleRef() = aRefData;
         }
 
-        for (SCCOL nCol : GetColumnsRange(nTab1, nCol1, nCol2))
+        for (SCCOL nCol : GetWritableColumnsRange(nTab1, nCol1, nCol2))
         {
             for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
             {
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 60dc6b749b82..b0b9242a1a63 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2550,15 +2550,27 @@ const ScTable* ScDocument::FetchTable( SCTAB nTab ) 
const
     return maTabs[nTab].get();
 }
 
-ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL 
nColEnd) const
+ScColumnsRange ScDocument::GetWritableColumnsRange( SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd)
 {
     if (!TableExists(nTab))
     {
-        std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>> 
aEmptyVector;
-        return ScColumnsRange(ScColumnsRange::Iterator(aEmptyVector.begin()),
-                              ScColumnsRange::Iterator(aEmptyVector.end()));
+        SAL_WARN("sc",  "GetWritableColumnsRange() called for non-existent 
table");
+        return ScColumnsRange(-1, -1);
     }
+    return maTabs[nTab]->GetWritableColumnsRange(nColBegin, nColEnd);
+}
 
+ScColumnsRange ScDocument::GetAllocatedColumnsRange( SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd) const
+{
+    if (!TableExists(nTab))
+        return ScColumnsRange(-1, -1);
+    return maTabs[nTab]->GetAllocatedColumnsRange(nColBegin, nColEnd);
+}
+
+ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL 
nColEnd) const
+{
+    if (!TableExists(nTab))
+        return ScColumnsRange(-1, -1);
     return maTabs[nTab]->GetColumnsRange(nColBegin, nColEnd);
 }
 
@@ -6869,7 +6881,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) 
const
 {
     for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
     {
-        for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
+        for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol()))
         {
             size_t nColNoteCount = GetNoteCount(nTab, nCol);
             if (!nColNoteCount)
@@ -6896,7 +6908,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) 
const
 
 ScAddress ScDocument::GetNotePosition( size_t nIndex, SCTAB nTab ) const
 {
-    for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
+    for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol()))
     {
         size_t nColNoteCount = GetNoteCount(nTab, nCol);
         if (!nColNoteCount)
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 45bd5c777cc0..1d8a072a0635 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2672,31 +2672,34 @@ const ScConditionalFormatList* 
ScTable::GetCondFormList() const
     return mpCondFormatList.get();
 }
 
-ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
+ScColumnsRange ScTable::GetWritableColumnsRange(SCCOL nColBegin, SCCOL nColEnd)
+{
+    // because the range is inclusive, some code will pass nColEnd<nColBegin 
to indicate an empty range
+    if (nColEnd < nColBegin)
+        return ScColumnsRange(-1, -1);
+    assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
+    CreateColumnIfNotExists(nColEnd);
+    return GetColumnsRange(nColBegin, nColEnd);
+}
+
+ScColumnsRange ScTable::GetAllocatedColumnsRange(SCCOL nColBegin, SCCOL 
nColEnd) const
 {
-    ScColContainer::ScColumnVector::const_iterator beginIter;
-    ScColContainer::ScColumnVector::const_iterator endIter;
+    if (nColBegin >= aCol.size())
+        return ScColumnsRange(-1, -1);
+    // clamp end of range to available columns
+    if (nColEnd >= aCol.size())
+        nColEnd = aCol.size() - 1;
+    return GetColumnsRange(nColBegin, nColEnd);
+}
 
+ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
+{
     // because the range is inclusive, some code will pass nColEnd<nColBegin 
to indicate an empty range
     if (nColEnd < nColBegin)
-    {
-        beginIter = aCol.end();
-        endIter = aCol.end();
-    }
-    else if (nColBegin >= aCol.size())
-    {
-        beginIter = aCol.end();
-        endIter = aCol.end();
-    }
-    else
-    {
-        // clamp end of range to available columns
-        if (nColEnd >= aCol.size())
-            nColEnd = aCol.size() - 1;
-        beginIter = aCol.begin() + nColBegin;
-        endIter = aCol.begin() + nColEnd + 1;
-    }
-    return ScColumnsRange(ScColumnsRange::Iterator(beginIter), 
ScColumnsRange::Iterator(endIter));
+        return ScColumnsRange(-1, -1);
+    assert( nColBegin >= 0 && nColBegin <= GetDoc().MaxCol());
+    assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
+    return ScColumnsRange(nColBegin, nColEnd + 1); // change inclusive end to 
past-end
 }
 
 // out-of-line the cold part of the CreateColumnIfNotExists function
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 421a3c96dc02..e9b5bb371a85 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -260,7 +260,7 @@ bool ScTable::TestInsertCol( SCROW nStartRow, SCROW 
nEndRow, SCSIZE nSize ) cons
         && ! pOutlineTable->TestInsertCol(nSize) )
             return false;
 
-    auto range = GetColumnsRange( rDocument.MaxCol() - 
static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() );
+    auto range = GetAllocatedColumnsRange( rDocument.MaxCol() - 
static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() );
     for (auto it = range.rbegin(); it != range.rend(); ++it )
         if (! aCol[*it].TestInsertCol(nStartRow, nEndRow))
             return false;
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 511d4a3c80ed..a04f0b4c8541 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -1926,12 +1926,12 @@ public:
         SCCOL nStartCol = mrParam.nCol1;
         SCCOL nEndCol = mrParam.nCol2;
 
-        for (SCCOL nCol : mrTab.GetColumnsRange(0, nStartCol - 1))
+        for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(0, nStartCol - 1))
         {
             if (mrTab.HasData(nCol, nRow))
                 return true;
         }
-        for (SCCOL nCol : mrTab.GetColumnsRange(nEndCol + 1, 
mrTab.GetDoc().MaxCol()))
+        for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(nEndCol + 1, 
mrTab.GetDoc().MaxCol()))
         {
             if (mrTab.HasData(nCol, nRow))
                 return true;
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index dc3a8c045dd9..30788b0daca7 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -321,7 +321,7 @@ void ScTable::EndListeningIntersectedGroups(
     if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2))
         return;
 
-    for (SCCOL nCol : GetColumnsRange(nCol1, nCol2))
+    for (SCCOL nCol : GetAllocatedColumnsRange(nCol1, nCol2))
         aCol[nCol].EndListeningIntersectedGroups(rCxt, nRow1, nRow2, 
pGroupPos);
 }
 
diff --git a/sc/source/filter/dif/difimp.cxx b/sc/source/filter/dif/difimp.cxx
index ede4af6cf753..f6e1fd0b0a36 100644
--- a/sc/source/filter/dif/difimp.cxx
+++ b/sc/source/filter/dif/difimp.cxx
@@ -664,7 +664,7 @@ void DifAttrCache::SetNumFormat( const ScDocument* pDoc, 
const SCCOL nCol, const
 
 void DifAttrCache::Apply( ScDocument& rDoc, SCTAB nTab )
 {
-    for( SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()) )
+    for( SCCOL nCol : rDoc.GetWritableColumnsRange(nTab, 0, rDoc.MaxCol()) )
     {
         if( maColMap.count(nCol) )
             maColMap[ nCol ]->Apply( rDoc, nCol, nTab );
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index f7bddf569605..e2b24d517b83 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -4627,7 +4627,7 @@ sal_Int32 SAL_CALL ScAnnotationsObj::getCount()
     if (pDocShell)
     {
         const ScDocument& rDoc = pDocShell->GetDocument();
-        for (SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()))
+        for (SCCOL nCol : rDoc.GetAllocatedColumnsRange(nTab, 0, 
rDoc.MaxCol()))
             nCount += rDoc.GetNoteCount(nTab, nCol);
     }
     return nCount;

Reply via email to