sc/inc/formulacell.hxx              |    1 
 sc/qa/unit/ucalc.cxx                |   75 +++++++++++++++++++++++++++++++++---
 sc/qa/unit/ucalc.hxx                |    2 
 sc/source/core/data/column.cxx      |   31 +++++++++-----
 sc/source/core/data/formulacell.cxx |   44 ++++++++++++++++++++-
 5 files changed, 133 insertions(+), 20 deletions(-)

New commits:
commit ff89c120f5f5036c3792b9cfc3f0329de3ac0a43
Author: Michael Meeks <michael.me...@collabora.com>
Date:   Fri Mar 14 16:31:59 2014 +0000

    fdo#72741 - write unit test for in formula group swapping.
    
    Change-Id: I9da62b026b40b08784415e0421556946646d25e2

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index cfc94e0..e1e9529 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -4525,10 +4525,8 @@ void Test::testFindAreaPosColRight()
 void Test::testSortWithFormulaRefs()
 {
     ScDocument* pDoc = getDocShell().GetDocument();
-    OUString aTabName1("List1");
-    OUString aTabName2("List2");
-    pDoc->InsertTab(0, aTabName1);
-    pDoc->InsertTab(1, aTabName2);
+    pDoc->InsertTab(0, "List1");
+    pDoc->InsertTab(1, "List2");
 
     const char* aFormulaData[6] = {
         "=IF($List1.A2<>\"\",$List1.A2,\"\")",
@@ -4627,8 +4625,7 @@ void Test::testSortWithStrings()
 
 void Test::testSort()
 {
-    OUString aTabName1("test1");
-    m_pDoc->InsertTab(0, aTabName1);
+    m_pDoc->InsertTab(0, "test1");
 
     ScRange aDataRange;
     ScAddress aPos(0,0,0);
@@ -4717,6 +4714,72 @@ void Test::testSort()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSortInFormulaGroup()
+{
+    static struct {
+        SCCOL nCol;
+        SCROW nRow;
+        const char *pData;
+    } aEntries[] = {
+        { 0, 0, "3" },   { 1, 0, "=A1" },
+        { 0, 1, "1" },   { 1, 1, "=A2" },
+        { 0, 2, "20" },  { 1, 2, "=A3" },
+        { 0, 3, "10" },  { 1, 3, "=A4+1" }, // swap across groups
+        { 0, 4, "2"  },  { 1, 4, "=A5+1" },
+        { 0, 5, "101" }, { 1, 5, "=A6" }, // swap inside contiguious group
+        { 0, 6, "100" }, { 1, 6, "=A7" },
+        { 0, 7, "102" }, { 1, 7, "=A8" },
+        { 0, 8, "104" }, { 1, 8, "=A9" },
+        { 0, 9, "103" }, { 1, 9, "=A10" },
+    };
+
+    m_pDoc->InsertTab(0, "sorttest");
+
+    for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
+        m_pDoc->SetString( aEntries[i].nCol, aEntries[i].nRow, 0,
+                           OUString::createFromAscii( aEntries[i].pData) );
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 1;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 9;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+
+    m_pDoc->Sort(0, aSortData, false, NULL);
+
+    static struct {
+        SCCOL nCol;
+        SCROW nRow;
+        double fValue;
+    } aResults[] = {
+        { 0, 0, 1.0 },   { 1, 0, 1.0 },
+        { 0, 1, 2.0 },   { 1, 1, 3.0 },
+        { 0, 2, 3.0 },   { 1, 2, 3.0 },
+        { 0, 3, 10.0 },  { 1, 3, 11.0 },
+        { 0, 4, 20.0 },  { 1, 4, 20.0 },
+        { 0, 5, 100.0 }, { 1, 5, 100.0 },
+        { 0, 6, 101.0 }, { 1, 6, 101.0 },
+        { 0, 7, 102.0 }, { 1, 7, 102.0 },
+        { 0, 8, 103.0 }, { 1, 8, 103.0 },
+        { 0, 9, 104.0 }, { 1, 9, 104.0 },
+    };
+
+    for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
+    {
+        double val = m_pDoc->GetValue( aEntries[i].nCol, aEntries[i].nRow, 0 );
+//        fprintf(stderr, "value at %d %d is %g = %g\n",
+//                (int)aResults[i].nRow, (int)aResults[i].nCol,
+//                val, aResults[i].fValue);
+        CPPUNIT_ASSERT_MESSAGE("Mis-matching value after sort.",
+                               rtl::math::approxEqual(val, 
aResults[i].fValue));
+    }
+
+    m_pDoc->DeleteTab( 0 );
+}
+
 void Test::testShiftCells()
 {
     m_pDoc->InsertTab(0, "foo");
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 68f5bc4..8c3ec8f 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -315,6 +315,7 @@ public:
     void testSort();
     void testSortWithFormulaRefs();
     void testSortWithStrings();
+    void testSortInFormulaGroup();
     void testShiftCells();
 
     void testNoteBasic();
@@ -460,6 +461,7 @@ public:
     CPPUNIT_TEST(testSort);
     CPPUNIT_TEST(testSortWithFormulaRefs);
     CPPUNIT_TEST(testSortWithStrings);
+    CPPUNIT_TEST(testSortInFormulaGroup);
     CPPUNIT_TEST(testShiftCells);
     CPPUNIT_TEST(testNoteBasic);
     CPPUNIT_TEST(testNoteDeleteRow);
commit 0698c49ccdbf62dd84d3f9c5d25ee039f4fff722
Author: Michael Meeks <michael.me...@collabora.com>
Date:   Fri Mar 14 14:26:02 2014 +0000

    fdo#72741 - swap values only inside a formula group.
    
    Speeds up sorting large ranges containing formula groups by a
    computational order or two: can sort 1 million rows of =A1 in sub 10s
    
    Change-Id: I729c801e68154986956b1726e1c35ef973cc4248

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index f2bc36c..9b47046 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -203,6 +203,7 @@ public:
     void            SetDirtyAfterLoad();
     void ResetTableOpDirtyVar();
     void            SetTableOpDirty();
+    bool            SwapWithinGroup( ScFormulaCell *pSwap );
     bool            IsDirtyOrInTableOpDirty() const;
     bool GetDirty() const;
     void ResetDirty();
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 1fa7120..2e9192d 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -871,18 +871,25 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
                 std::advance(itf1, aPos1.second);
                 std::advance(itf2, aPos2.second);
 
-                // TODO: Find out a way to adjust references without cloning 
new instances.
-                boost::scoped_ptr<ScFormulaCell> pOld1(*itf1);
-                boost::scoped_ptr<ScFormulaCell> pOld2(*itf2);
-                DetachFormulaCell(aPos1, **itf1);
-                DetachFormulaCell(aPos2, **itf2);
-                ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, 
ScAddress(nCol, nRow1, nTab), *pOld2);
-                ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, 
ScAddress(nCol, nRow2, nTab), *pOld1);
-                *itf1 = pNew1;
-                *itf2 = pNew2;
-
-                ActivateNewFormulaCell(aPos1, *pNew1);
-                ActivateNewFormulaCell(aPos2, *pNew2);
+                // Is it an identical formula in the same group - if so,
+                // take a shortcut to swap the result data:
+                if(!(*itf1)->SwapWithinGroup(*itf2))
+                {
+                    // otherwise we need to really move the formula &
+                    // re-write dependencies etc.
+                    boost::scoped_ptr<ScFormulaCell> pOld1(*itf1);
+                    boost::scoped_ptr<ScFormulaCell> pOld2(*itf2);
+
+                    DetachFormulaCell(aPos1, **itf1);
+                    DetachFormulaCell(aPos2, **itf2);
+                    ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, 
ScAddress(nCol, nRow1, nTab), *pOld2);
+                    ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, 
ScAddress(nCol, nRow2, nTab), *pOld1);
+                    *itf1 = pNew1;
+                    *itf2 = pNew2;
+
+                    ActivateNewFormulaCell(aPos1, *pNew1);
+                    ActivateNewFormulaCell(aPos2, *pNew2);
+                }
             }
             break;
             default:
diff --git a/sc/source/core/data/formulacell.cxx 
b/sc/source/core/data/formulacell.cxx
index 9bbc75d..957d8b2 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1977,15 +1977,55 @@ void ScFormulaCell::SetTableOpDirty()
     }
 }
 
-
 bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
 {
     return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
 }
 
+/** Exchange formulae cell result data inside a formula
+    group if possible. Return true if both Formula cells
+    are inside the same formula group and the data has
+    been successfully exchanged; otherwise false - leaving
+    the formulae untouched.
+ */
+bool ScFormulaCell::SwapWithinGroup( ScFormulaCell *pSwap )
+{
+    if (!mxGroup || // ungrouped
+         mxGroup != pSwap->mxGroup)
+        return false;
+
+    if (pDocument != pSwap->pDocument ||
+        nSeenInIteration != pSwap->nSeenInIteration ||
+        eTempGrammar != pSwap->eTempGrammar ||
+        cMatrixFlag != pSwap->cMatrixFlag ||
+        nFormatType != pSwap->nFormatType ||
+        bDirty != pSwap->bDirty ||
+        bChanged != pSwap->bChanged ||
+        bRunning != pSwap->bRunning ||
+        bCompile != pSwap->bCompile ||
+        bSubTotal != pSwap->bSubTotal ||
+        bIsIterCell != pSwap->bIsIterCell ||
+        bInChangeTrack != pSwap->bInChangeTrack ||
+        bTableOpDirty != pSwap->bTableOpDirty ||
+        bNeedListening != pSwap->bNeedListening ||
+        mbNeedsNumberFormat != pSwap->mbNeedsNumberFormat ||
+        mbPostponedDirty != pSwap->mbPostponedDirty
+        )
+        return false; // we are paranoid for good reason.
+
+    // retain aPos as is.
+
+    // swap result value
+    ScFormulaResult aTemp(aResult);
+    aResult = pSwap->aResult;
+    pSwap->aResult.Assign(aTemp);
+
+    return true;
+}
+
 void ScFormulaCell::SetResultDouble( double n )
 {
-    aResult.SetDouble( n);
+    aResult.SetDouble(n);
 }
 
 void ScFormulaCell::SetResultToken( const formula::FormulaToken* pToken )
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to