[Libreoffice-commits] .: Branch 'libreoffice-3-5' - sc/inc sc/source

Kohei Yoshida kohei at kemper.freedesktop.org
Wed Jan 11 12:28:26 PST 2012


 sc/inc/dpobject.hxx              |    8 ++-
 sc/source/core/data/dpobject.cxx |  100 +++++++++++++++++++++++++++++++++++----
 2 files changed, 99 insertions(+), 9 deletions(-)

New commits:
commit 1e88cd643a5959271f28eaaab3d14488374df11f
Author: Kohei Yoshida <kohei.yoshida at suse.com>
Date:   Wed Jan 11 15:24:52 2012 -0500

    fdo#44661: Properly update range keys for pivot cache.
    
    When the internal data source range gets modified, we should also
    update the affected range keys that are used to look up pivot caches.
    
    Otherwise we'll end up creating a brand new cache, without removing
    the old one that's no longer referenced.

diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx
index cc73fcb..db8ea92 100644
--- a/sc/inc/dpobject.hxx
+++ b/sc/inc/dpobject.hxx
@@ -259,12 +259,18 @@ public:
     class SheetCaches
     {
         friend class ScDPCollection;
-        typedef ::boost::ptr_map<ScRange, ScDPCache> CachesType;
+        typedef boost::ptr_map<size_t, ScDPCache> CachesType;
+        typedef std::vector<ScRange> RangeIndexType;
         CachesType maCaches;
+        RangeIndexType maRanges;
         ScDocument* mpDoc;
     public:
         SheetCaches(ScDocument* pDoc);
         const ScDPCache* getCache(const ScRange& rRange);
+
+        void updateReference(
+            UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz);
+
     private:
         void removeCache(const ScRange& rRange);
     };
diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx
index 51be02d..b0bbace 100644
--- a/sc/source/core/data/dpobject.cxx
+++ b/sc/source/core/data/dpobject.cxx
@@ -2459,27 +2459,108 @@ uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPS
 
 ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
 
+namespace {
+
+struct FindInvalidRange : public std::unary_function<ScRange, bool>
+{
+    bool operator() (const ScRange& r) const
+    {
+        return !r.IsValid();
+    }
+};
+
+}
+
 const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange)
 {
-    CachesType::const_iterator itr = maCaches.find(rRange);
-    if (itr != maCaches.end())
-        // already cached.
-        return itr->second;
+    RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
+    if (it != maRanges.end())
+    {
+        // Already cached.
+        size_t nIndex = std::distance(maRanges.begin(), it);
+        CachesType::iterator itCache = maCaches.find(nIndex);
+        if (itCache == maCaches.end())
+            // cache pool and index pool out-of-sync !!!
+            return NULL;
 
+        return itCache->second;
+    }
+
+    // Not cached.  Create a new cache.
     SAL_WNODEPRECATED_DECLARATIONS_PUSH
     ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
     SAL_WNODEPRECATED_DECLARATIONS_POP
     pCache->InitFromDoc(mpDoc, rRange);
+
+    // Get the smallest available range index.
+    it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange());
+
+    size_t nIndex = maRanges.size();
+    if (it == maRanges.end())
+    {
+        // All range indices are valid.  Append a new index.
+        maRanges.push_back(rRange);
+    }
+    else
+    {
+        // Slot with invalid range.  Re-use this slot.
+        *it = rRange;
+        nIndex = std::distance(maRanges.begin(), it);
+    }
+
     const ScDPCache* p = pCache.get();
-    maCaches.insert(rRange, pCache);
+    maCaches.insert(nIndex, pCache);
     return p;
 }
 
+void ScDPCollection::SheetCaches::updateReference(
+    UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz)
+{
+    if (maRanges.empty())
+        // No caches.
+        return;
+
+    RangeIndexType::iterator it = maRanges.begin(), itEnd = maRanges.end();
+    for (; it != itEnd; ++it)
+    {
+        const ScRange& rKeyRange = *it;
+        SCCOL nCol1 = rKeyRange.aStart.Col();
+        SCROW nRow1 = rKeyRange.aStart.Row();
+        SCTAB nTab1 = rKeyRange.aStart.Tab();
+        SCCOL nCol2 = rKeyRange.aEnd.Col();
+        SCROW nRow2 = rKeyRange.aEnd.Row();
+        SCTAB nTab2 = rKeyRange.aEnd.Tab();
+
+        ScRefUpdateRes eRes = ScRefUpdate::Update(
+            mpDoc, eMode,
+            r.aStart.Col(), r.aStart.Row(), r.aStart.Tab(),
+            r.aEnd.Col(), r.aEnd.Row(), r.aEnd.Tab(), nDx, nDy, nDz,
+            nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+
+        if (eRes != UR_NOTHING)
+        {
+            // range updated.
+            ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+            *it = aNew;
+        }
+    }
+}
+
 void ScDPCollection::SheetCaches::removeCache(const ScRange& rRange)
 {
-    CachesType::iterator itr = maCaches.find(rRange);
-    if (itr != maCaches.end())
-        maCaches.erase(itr);
+    RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
+    if (it == maRanges.end())
+        // Not cached.  Nothing to do.
+        return;
+
+    size_t nIndex = std::distance(maRanges.begin(), it);
+    CachesType::iterator itCache = maCaches.find(nIndex);
+    if (itCache == maCaches.end())
+        // Cache pool and index pool out-of-sync !!!
+        return;
+
+    it->SetInvalid(); // Make this slot available for future caches.
+    maCaches.erase(itCache);
 }
 
 ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
@@ -2687,6 +2768,9 @@ void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
     TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
     for (; itr != itrEnd; ++itr)
         itr->UpdateReference(eUpdateRefMode, r, nDx, nDy, nDz);
+
+    // Update the source ranges of the caches.
+    maSheetCaches.updateReference(eUpdateRefMode, r, nDx, nDy, nDz);
 }
 
 bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const


More information about the Libreoffice-commits mailing list