sc/inc/conditio.hxx              |   41 +++++++++
 sc/source/core/data/conditio.cxx |  168 +++++++++++++++++++++++++++++----------
 sc/source/core/data/fillinfo.cxx |    5 +
 3 files changed, 171 insertions(+), 43 deletions(-)

New commits:
commit af0c93da33f2bf39a673c2dc29fb44b90322d137
Author: Markus Mohrhard <markus.mohrh...@googlemail.com>
Date:   Mon Sep 24 23:19:41 2012 +0200

    kill O(N^2) algorithm generating cond format render information, fdo#54396
    
    Change-Id: I63536625eaf9b73c8e63d3cf88b6b798a6bf017b

diff --git a/sc/inc/conditio.hxx b/sc/inc/conditio.hxx
index 7b1cf17..ae16d6b 100644
--- a/sc/inc/conditio.hxx
+++ b/sc/inc/conditio.hxx
@@ -35,8 +35,11 @@
 #include "scdllapi.h"
 #include "rangelst.hxx"
 
+#include <rtl/math.hxx>
+
 #include <boost/ptr_container/ptr_set.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/scoped_ptr.hpp>
 
 class ScBaseCell;
 class ScFormulaCell;
@@ -116,11 +119,26 @@ public:
 #if DUMP_FORMAT_INFO
     virtual void dumpInfo(rtl::OUStringBuffer& rBuf) const = 0;
 #endif
+
+    virtual void startRendering();
+    virtual void endRendering();
 protected:
     ScDocument* mpDoc;
 
 };
 
+class approx_less : public std::binary_function<double, double, bool>
+{
+public:
+    bool operator() (double nVal1, double nVal2)
+    {
+        if(nVal1 < nVal2 && !rtl::math::approxEqual(nVal1, nVal2))
+            return true;
+
+        return false;
+    }
+};
+
 class SC_DLLPUBLIC ScConditionEntry : public ScFormatEntry
 {
                                         // stored data:
@@ -216,10 +234,27 @@ public:
     virtual void dumpInfo(rtl::OUStringBuffer& ) const {}
 #endif
 
+    virtual void endRendering();
+    virtual void startRendering();
+
 protected:
     virtual void    DataChanged( const ScRange* pModified ) const;
     ScDocument*     GetDocument() const     { return mpDoc; }
     ScConditionalFormat*    pCondFormat;
+
+private:
+
+    bool IsDuplicate(double nArg, const rtl::OUString& rStr, const ScAddress& 
rAddr, const ScRangeList& rRanges) const;
+
+    struct ScConditionEntryCache
+    {
+        typedef std::map<rtl::OUString, sal_Int32> StringCacheType;
+        StringCacheType maStrings;
+        typedef std::map<double, sal_Int32, approx_less> ValueCacheType;
+        ValueCacheType maValues;
+    };
+
+    mutable boost::scoped_ptr<ScConditionEntryCache> mpCache;
 };
 
 //
@@ -326,6 +361,9 @@ public:
     //  operator== only for sorting
     bool operator ==( const ScConditionalFormat& r ) const  { return nKey == 
r.nKey; }
     bool operator < ( const ScConditionalFormat& r ) const  { return nKey <  
r.nKey; }
+
+    void startRendering();
+    void endRendering();
 };
 
 //
@@ -371,6 +409,9 @@ public:
     size_t size() const;
 
     void erase(sal_uLong nIndex);
+
+    void startRendering();
+    void endRendering();
 };
 
 // see 
http://www.boost.org/doc/libs/1_49_0/libs/ptr_container/doc/tutorial.html#cloneability
diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx
index c8e2dbc..f7b6b86 100644
--- a/sc/source/core/data/conditio.cxx
+++ b/sc/source/core/data/conditio.cxx
@@ -72,6 +72,14 @@ bool ScFormatEntry::operator==( const ScFormatEntry& r ) 
const
     }
 }
 
+void ScFormatEntry::startRendering()
+{
+}
+
+void ScFormatEntry::endRendering()
+{
+}
+
 bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 
nRecursion = 0 )
 {
     if (pFormula)
@@ -716,7 +724,7 @@ void ScConditionEntry::Interpret( const ScAddress& rPos )
     bFirstRun = false;
 }
 
-static bool lcl_GetCellContent( ScBaseCell* pCell, bool bIsStr1, double& rArg, 
String& rArgStr )
+static bool lcl_GetCellContent( ScBaseCell* pCell, bool bIsStr1, double& rArg, 
rtl::OUString& rArgStr )
 {
     bool bVal = true;
 
@@ -760,53 +768,84 @@ static bool lcl_GetCellContent( ScBaseCell* pCell, bool 
bIsStr1, double& rArg, S
     return bVal;
 }
 
-static bool lcl_IsDuplicate( ScDocument *pDoc, double nArg, const String& 
rStr, const ScAddress& rAddr, const ScRangeList& rRanges )
+bool ScConditionEntry::IsDuplicate( double nArg, const rtl::OUString& rStr, 
const ScAddress& rAddr, const ScRangeList& rRanges ) const
 {
-    size_t nListCount = rRanges.size();
-    for( size_t i = 0; i < nListCount; i++ )
+    if(!mpCache)
     {
-        const ScRange *aRange = rRanges[i];
-        SCROW nRow = aRange->aEnd.Row();
-        SCCOL nCol = aRange->aEnd.Col();
-        SCCOL nColStart = aRange->aStart.Col();
-        SCROW nRowStart = aRange->aEnd.Row();
-        SCTAB nTab = aRange->aStart.Tab();
-
-        // temporary fix to workaorund slow duplicate entry
-        // conditions, prevent to use a whole row
-        if(nRow == MAXROW)
+        mpCache.reset(new ScConditionEntryCache);
+        size_t nListCount = rRanges.size();
+        for( size_t i = 0; i < nListCount; i++ )
         {
-            bool bShrunk = false;
-            pDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
-                                            nCol, nRow, false);
-        }
-
-        for( SCROW r = nRowStart; r <= nRow; r++ )
-            for( SCCOL c = nColStart; c <= nCol; c++ )
+            const ScRange *aRange = rRanges[i];
+            SCROW nRow = aRange->aEnd.Row();
+            SCCOL nCol = aRange->aEnd.Col();
+            SCCOL nColStart = aRange->aStart.Col();
+            SCROW nRowStart = aRange->aStart.Row();
+            SCTAB nTab = aRange->aStart.Tab();
+
+            // temporary fix to workaorund slow duplicate entry
+            // conditions, prevent to use a whole row
+            if(nRow == MAXROW)
             {
-                double nVal = 0.0;
-                ScBaseCell *pCell = NULL;
-                String aStr;
-
-                if( c == rAddr.Col() && r == rAddr.Row() )
-                    continue;
-                pDoc->GetCell( c, r, rAddr.Tab(), pCell );
-                if( !pCell )
-                    continue;
+                bool bShrunk = false;
+                mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, 
nRowStart,
+                        nCol, nRow, false);
+            }
 
-                if( !lcl_GetCellContent( pCell, false, nVal, aStr ) )
-                {
-                    if( rStr.Len() &&
-                        ( ScGlobal::GetCollator()->compareString( rStr, aStr ) 
== COMPARE_EQUAL ) )
-                        return true;
-                }
-                else
+            for( SCROW r = nRowStart; r <= nRow; r++ )
+                for( SCCOL c = nColStart; c <= nCol; c++ )
                 {
-                    if( !rStr.Len() && ::rtl::math::approxEqual( nArg, nVal ) )
-                        return true;
+                    double nVal = 0.0;
+                    ScBaseCell *pCell = NULL;
+
+                    mpDoc->GetCell( c, r, rAddr.Tab(), pCell );
+                    if( !pCell )
+                        continue;
+
+                    rtl::OUString aStr;
+                    if( !lcl_GetCellContent( pCell, false, nVal, aStr ) )
+                    {
+                        
std::pair<ScConditionEntryCache::StringCacheType::iterator, bool> aResult = 
mpCache->maStrings.insert(std::pair<rtl::OUString, sal_Int32>(aStr, 
static_cast<sal_Int32>(1)));
+                        if(!aResult.second)
+                            aResult.first->second++;
+                    }
+                    else
+                    {
+                        
std::pair<ScConditionEntryCache::ValueCacheType::iterator, bool> aResult = 
mpCache->maValues.insert(std::pair<double, sal_Int32>(nVal, (sal_Int32)1));
+                        if(!aResult.second)
+                            aResult.first->second++;
+                    }
                 }
-            }
+        }
+    }
+
+    if(rStr.isEmpty())
+    {
+        ScConditionEntryCache::ValueCacheType::iterator itr = 
mpCache->maValues.find(nArg);
+        if(itr == mpCache->maValues.end())
+            return false;
+        else
+        {
+            if(itr->second > 1)
+                return true;
+            else
+                return false;
+        }
+    }
+    else
+    {
+        ScConditionEntryCache::StringCacheType::iterator itr = 
mpCache->maStrings.find(rStr);
+        if(itr == mpCache->maStrings.end())
+            return false;
+        else
+        {
+            if(itr->second > 1)
+                return true;
+            else
+                return false;
+        }
     }
+
     return false;
 }
 
@@ -873,7 +912,7 @@ bool ScConditionEntry::IsValid( double nArg, const 
ScAddress& rAddr ) const
             if( pCondFormat )
             {
                 const ScRangeList& aRanges = pCondFormat->GetRange();
-                bValid = lcl_IsDuplicate( mpDoc, nArg, String(), rAddr, 
aRanges );
+                bValid = IsDuplicate( nArg, rtl::OUString(), rAddr, aRanges );
                 if( eOp == SC_COND_NOTDUPLICATE )
                     bValid = !bValid;
             }
@@ -901,7 +940,7 @@ bool ScConditionEntry::IsValidStr( const String& rArg, 
const ScAddress& rAddr )
         if( pCondFormat && rArg.Len() )
         {
             const ScRangeList& aRanges = pCondFormat->GetRange();
-            bValid = lcl_IsDuplicate( mpDoc, 0.0, rArg, rAddr, aRanges );
+            bValid = IsDuplicate( 0.0, rArg, rAddr, aRanges );
             if( eOp == SC_COND_NOTDUPLICATE )
                 bValid = !bValid;
             return bValid;
@@ -980,7 +1019,7 @@ bool ScConditionEntry::IsCellValid( ScBaseCell* pCell, 
const ScAddress& rPos ) c
     ((ScConditionEntry*)this)->Interpret(rPos);         // Formeln auswerten
 
     double nArg = 0.0;
-    String aArgStr;
+    rtl::OUString aArgStr;
     bool bVal = lcl_GetCellContent( pCell, bIsStr1, nArg, aArgStr );
     if (bVal)
         return IsValid( nArg, rPos );
@@ -1278,6 +1317,17 @@ ScConditionMode 
ScConditionEntry::GetModeFromApi(sal_Int32 nOperation)
     }
     return eMode;
 }
+
+void ScConditionEntry::startRendering()
+{
+    mpCache.reset();
+}
+
+void ScConditionEntry::endRendering()
+{
+    mpCache.reset();
+}
+
 //------------------------------------------------------------------------
 
 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
@@ -1578,6 +1628,22 @@ bool ScConditionalFormat::MarkUsedExternalReferences() 
const
     return bAllMarked;
 }
 
+void ScConditionalFormat::startRendering()
+{
+    for(CondFormatContainer::iterator itr = maEntries.begin(); itr != 
maEntries.end(); ++itr)
+    {
+        itr->startRendering();
+    }
+}
+
+void ScConditionalFormat::endRendering()
+{
+    for(CondFormatContainer::iterator itr = maEntries.begin(); itr != 
maEntries.end(); ++itr)
+    {
+        itr->endRendering();
+    }
+}
+
 //------------------------------------------------------------------------
 
 ScConditionalFormatList::ScConditionalFormatList(const 
ScConditionalFormatList& rList)
@@ -1721,4 +1787,20 @@ void ScConditionalFormatList::erase( sal_uLong nIndex )
     }
 }
 
+void ScConditionalFormatList::startRendering()
+{
+    for(iterator itr = begin(); itr != end(); ++itr)
+    {
+        itr->startRendering();
+    }
+}
+
+void ScConditionalFormatList::endRendering()
+{
+    for(iterator itr = begin(); itr != end(); ++itr)
+    {
+        itr->endRendering();
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index ad9faa9..29fee72 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -363,6 +363,9 @@ void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL 
nX1, SCROW nY1, SCCOL nX
     }
 
     ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
+    if(pCondFormList)
+        pCondFormList->startRendering();
+
     for (nArrX=0; nArrX<=nX2+2; nArrX++)                    // links & rechts 
+ 1
     {
         nX = (nArrX>0) ? nArrX-1 : MAXCOL+1;                    // negativ -> 
ungueltig
@@ -647,6 +650,8 @@ void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL 
nX1, SCROW nY1, SCCOL nX
         // STD_COL_WIDTH ganz links und rechts wird fuer DrawExtraShadow 
gebraucht
     }
 
+    if(pCondFormList)
+        pCondFormList->endRendering();
     //-------------------------------------------------------------------------
     //  bedingte Formatierung auswerten
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to