sc/inc/chart2uno.hxx              |    9 +-
 sc/source/ui/unoobj/chart2uno.cxx |  130 ++++++++++++++++++++------------------
 2 files changed, 74 insertions(+), 65 deletions(-)

New commits:
commit 03ef97c7605f4d3f537d5a1f31c2f131a439578d
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Tue Oct 18 14:16:08 2022 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Tue Oct 18 19:07:00 2022 +0200

    tdf#131910 speed up chart display
    
    the chart2 module likes cloning ScChart2DataSequence, which can take a
    long time if we have lots of data, so share the data via shared_ptr
    
    Change-Id: I4b0948610810c41a8569b97c58b2b52e8e3190f3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141501
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/sc/inc/chart2uno.hxx b/sc/inc/chart2uno.hxx
index a5e4f53b032f..a8ac4422464e 100644
--- a/sc/inc/chart2uno.hxx
+++ b/sc/inc/chart2uno.hxx
@@ -205,6 +205,7 @@ public:
             ::std::vector<ScTokenRef>&& rTokens, bool bIncludeHiddenCells );
 
     virtual ~ScChart2DataSequence() override;
+    ScChart2DataSequence(ScDocument* pDoc, const ScChart2DataSequence&);
     ScChart2DataSequence(const ScChart2DataSequence&) = delete;
     ScChart2DataSequence& operator=(const ScChart2DataSequence&) = delete;
 
@@ -324,8 +325,6 @@ private:
 
     void StopListeningToAllExternalRefs();
 
-    void CopyData(const ScChart2DataSequence& r);
-
 private:
 
     // data array
@@ -350,8 +349,10 @@ private:
         ScChart2DataSequence& mrParent;
     };
 
-    /** This vector contains the cached data which was calculated with 
BuildDataCache(). */
-    std::vector<Item>           m_aDataArray;
+    /** This vector contains the cached data which was calculated with 
BuildDataCache().
+        We use a shared_ptr because chart likes to Clone this class, which is 
very
+        expensive when we have lots of data. */
+    std::shared_ptr<std::vector<Item>> m_xDataArray;
 
     /**
      * Cached data for getData.  We may also need to cache data for the
diff --git a/sc/source/ui/unoobj/chart2uno.cxx 
b/sc/source/ui/unoobj/chart2uno.cxx
index 729249790a9d..58ca25ae854e 100644
--- a/sc/source/ui/unoobj/chart2uno.cxx
+++ b/sc/source/ui/unoobj/chart2uno.cxx
@@ -2409,7 +2409,8 @@ void ScChart2DataSequence::HiddenRangeListener::notify()
 ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
         vector<ScTokenRef>&& rTokens,
         bool bIncludeHiddenCells )
-    : m_bIncludeHiddenCells( bIncludeHiddenCells)
+    : m_xDataArray(new std::vector<Item>)
+    , m_bIncludeHiddenCells( bIncludeHiddenCells)
     , m_nObjectId( 0 )
     , m_pDocument( pDoc)
     , m_aTokens(std::move(rTokens))
@@ -2439,6 +2440,54 @@ ScChart2DataSequence::ScChart2DataSequence( ScDocument* 
pDoc,
 //      m_aIdentifier += OUString::valueOf( ++nID);
 }
 
+/** called from Clone() */
+ScChart2DataSequence::ScChart2DataSequence(ScDocument* pDoc, const 
ScChart2DataSequence& r)
+    : m_xDataArray(r.m_xDataArray)
+    , m_aHiddenValues(r.m_aHiddenValues)
+    , m_aRole(r.m_aRole)
+    , m_bIncludeHiddenCells( r.m_bIncludeHiddenCells)
+    , m_nObjectId( 0 )
+    , m_pDocument( pDoc)
+    , m_aPropSet(lcl_GetDataSequencePropertyMap())
+    , m_bGotDataChangedHint(false)
+    , m_bExtDataRebuildQueued(false)
+    , mbTimeBased(false)
+    , mnTimeBasedStart(0)
+    , mnTimeBasedEnd(0)
+    , mnCurrentTab(0)
+{
+    assert(pDoc);
+
+    // Clone tokens.
+    m_aTokens.reserve(r.m_aTokens.size());
+    for (const auto& rxToken : m_aTokens)
+    {
+        ScTokenRef p(rxToken->Clone());
+        m_aTokens.push_back(p);
+    }
+
+    m_pDocument->AddUnoObject( *this);
+    m_nObjectId = m_pDocument->GetNewUnoId();
+
+    if (r.m_oRangeIndices)
+        m_oRangeIndices = *r.m_oRangeIndices;
+
+    if (!r.m_pExtRefListener)
+        return;
+
+    // Re-register all external files that the old instance was
+    // listening to.
+
+    ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+    m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
+    const std::unordered_set<sal_uInt16>& rFileIds = 
r.m_pExtRefListener->getAllFileIds();
+    for (const auto& rFileId : rFileIds)
+    {
+        pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
+        m_pExtRefListener->addFileId(rFileId);
+    }
+}
+
 ScChart2DataSequence::~ScChart2DataSequence()
 {
     SolarMutexGuard g;
@@ -2492,7 +2541,7 @@ void ScChart2DataSequence::BuildDataCache()
 {
     m_bExtDataRebuildQueued = false;
 
-    if (!m_aDataArray.empty())
+    if (!m_xDataArray->empty())
         return;
 
     StopListeningToAllExternalRefs();
@@ -2569,7 +2618,7 @@ void ScChart2DataSequence::BuildDataCache()
 
                         aItem.mAddress = ScAddress(nCol, nRow, nTab);
 
-                        m_aDataArray.push_back(std::move(aItem));
+                        m_xDataArray->push_back(std::move(aItem));
                         ++nDataCount;
                     }
                 }
@@ -2590,7 +2639,7 @@ void ScChart2DataSequence::RebuildDataCache()
 {
     if (!m_bExtDataRebuildQueued)
     {
-        m_aDataArray.clear();
+        m_xDataArray.reset(new std::vector<Item>);
         m_pDocument->BroadcastUno(ScHint(SfxHintId::ScDataChanged, 
ScAddress()));
         m_bExtDataRebuildQueued = true;
         m_bGotDataChangedHint = true;
@@ -2616,6 +2665,7 @@ sal_Int32 
ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToke
     pRefMgr->addLinkListener(nFileId, pExtRefListener);
     pExtRefListener->addFileId(nFileId);
 
+    m_xDataArray.reset(new std::vector<Item>);
     ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, 
aTabName, false);
     sal_Int32 nDataCount = 0;
     FormulaTokenArrayPlainIterator aIter(*pArray);
@@ -2662,7 +2712,7 @@ sal_Int32 
ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToke
                         pFormatter->GetOutputString(fVal, nFmt, 
aItem.maString, &pColor);
                     }
 
-                    m_aDataArray.push_back(aItem);
+                    m_xDataArray->push_back(std::move(aItem));
                     ++nDataCount;
                 }
                 else if (pMat->IsStringOrEmpty(nC, nR))
@@ -2672,7 +2722,7 @@ sal_Int32 
ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToke
                     aItem.mbIsValue = false;
                     aItem.maString = pMat->GetString(nC, nR).getString();
 
-                    m_aDataArray.emplace_back(aItem);
+                    m_xDataArray->push_back(std::move(aItem));
                     ++nDataCount;
                 }
             }
@@ -2724,38 +2774,6 @@ void 
ScChart2DataSequence::StopListeningToAllExternalRefs()
     m_pExtRefListener.reset();
 }
 
-void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
-{
-    if (!m_pDocument)
-    {
-        OSL_FAIL("document instance is nullptr!?");
-        return;
-    }
-
-    std::vector<Item> aDataArray(r.m_aDataArray);
-    m_aDataArray.swap(aDataArray);
-
-    m_aHiddenValues = r.m_aHiddenValues;
-    m_aRole = r.m_aRole;
-
-    if (r.m_oRangeIndices)
-        m_oRangeIndices = *r.m_oRangeIndices;
-
-    if (!r.m_pExtRefListener)
-        return;
-
-    // Re-register all external files that the old instance was
-    // listening to.
-
-    ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
-    m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
-    const std::unordered_set<sal_uInt16>& rFileIds = 
r.m_pExtRefListener->getAllFileIds();
-    for (const auto& rFileId : rFileIds)
-    {
-        pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
-        m_pExtRefListener->addFileId(rFileId);
-    }
-}
 
 void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& 
rHint)
 {
@@ -2845,7 +2863,7 @@ void ScChart2DataSequence::Notify( SfxBroadcaster& 
/*rBC*/, const SfxHint& rHint
 
             if ( m_bGotDataChangedHint && m_pDocument )
             {
-                m_aDataArray.clear();
+                m_xDataArray.reset(new std::vector<Item>);
                 lang::EventObject aEvent;
                 aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
 
@@ -2869,7 +2887,7 @@ void ScChart2DataSequence::Notify( SfxBroadcaster& 
/*rBC*/, const SfxHint& rHint
         else if (nId == SfxHintId::ScClearCache)
         {
             // necessary after import
-            m_aDataArray.clear();
+            m_xDataArray.reset(new std::vector<Item>);
         }
     }
 }
@@ -2940,10 +2958,10 @@ uno::Sequence< uno::Any> SAL_CALL 
ScChart2DataSequence::getData()
     {
         // Build a cache for the 1st time...
 
-        sal_Int32 nCount = m_aDataArray.size();
+        sal_Int32 nCount = m_xDataArray->size();
         m_aMixedDataCache.realloc(nCount);
         uno::Any* pArr = m_aMixedDataCache.getArray();
-        for (const Item &rItem : m_aDataArray)
+        for (const Item &rItem : *m_xDataArray)
         {
             if (rItem.mbIsValue)
                 *pArr <<= rItem.mfValue;
@@ -2973,10 +2991,10 @@ uno::Sequence< double > SAL_CALL 
ScChart2DataSequence::getNumericalData()
 
     BuildDataCache();
 
-    sal_Int32 nCount = m_aDataArray.size();
+    sal_Int32 nCount = m_xDataArray->size();
     uno::Sequence<double> aSeq(nCount);
     double* pArr = aSeq.getArray();
-    for (const Item& rItem : m_aDataArray)
+    for (const Item& rItem : *m_xDataArray)
     {
         *pArr = rItem.mbIsValue ? rItem.mfValue : 
std::numeric_limits<double>::quiet_NaN();
         ++pArr;
@@ -2996,12 +3014,12 @@ uno::Sequence< OUString > SAL_CALL 
ScChart2DataSequence::getTextualData()
 
     BuildDataCache();
 
-    sal_Int32 nCount = m_aDataArray.size();
+    sal_Int32 nCount = m_xDataArray->size();
     if ( nCount > 0 )
     {
         aSeq =  uno::Sequence<OUString>(nCount);
         OUString* pArr = aSeq.getArray();
-        for (const Item& rItem : m_aDataArray)
+        for (const Item& rItem : *m_xDataArray)
         {
             *pArr = rItem.maString;
             ++pArr;
@@ -3182,7 +3200,7 @@ sal_uInt32 getDisplayNumberFormat(const ScDocument* pDoc, 
const ScAddress& rPos)
     {
         // return format of first non-empty cell
         // TODO: use nicer heuristic
-        for (const Item& rItem : m_aDataArray)
+        for (const Item& rItem : *m_xDataArray)
         {
             ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
             if (!aCell.isEmpty() && aCell.hasNumeric())
@@ -3195,13 +3213,13 @@ sal_uInt32 getDisplayNumberFormat(const ScDocument* 
pDoc, const ScAddress& rPos)
         return 0;
     }
 
-    if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= m_aDataArray.size())
+    if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= m_xDataArray->size())
     {
         SAL_WARN("sc.ui", "Passed invalid index to 
getNumberFormatKeyByIndex(). Will return default value '0'.");
         return 0;
     }
 
-    return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, 
m_aDataArray.at(nIndex).mAddress));
+    return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, 
m_xDataArray->at(nIndex).mAddress));
 }
 
 // XCloneable ================================================================
@@ -3210,17 +3228,7 @@ uno::Reference< util::XCloneable > SAL_CALL 
ScChart2DataSequence::createClone()
 {
     SolarMutexGuard aGuard;
 
-    // Clone tokens.
-    vector<ScTokenRef> aTokensNew;
-    aTokensNew.reserve(m_aTokens.size());
-    for (const auto& rxToken : m_aTokens)
-    {
-        ScTokenRef p(rxToken->Clone());
-        aTokensNew.push_back(p);
-    }
-
-    rtl::Reference<ScChart2DataSequence> p(new 
ScChart2DataSequence(m_pDocument, std::move(aTokensNew), 
m_bIncludeHiddenCells));
-    p->CopyData(*this);
+    rtl::Reference<ScChart2DataSequence> p(new 
ScChart2DataSequence(m_pDocument, *this));
     return p;
 }
 
@@ -3327,7 +3335,7 @@ void SAL_CALL ScChart2DataSequence::setPropertyValue(
         if ( !(rValue >>= m_bIncludeHiddenCells))
             throw lang::IllegalArgumentException();
         if( bOldValue != m_bIncludeHiddenCells )
-            m_aDataArray.clear();//data array is dirty now
+            m_xDataArray.reset(new std::vector<Item>);//data array is dirty now
     }
     else if( rPropertyName == "TimeBased" )
     {

Reply via email to