summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@suse.com>2012-01-11 15:24:52 -0500
committerKohei Yoshida <kohei.yoshida@suse.com>2012-01-11 15:28:15 -0500
commit1e88cd643a5959271f28eaaab3d14488374df11f (patch)
tree03ce40fe02da55f19d180bb10bf6017b2f772fe9
parentde89f1694b4cb2a5bf8ade020bfdef33e7135d35 (diff)
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.
-rw-r--r--sc/inc/dpobject.hxx8
-rw-r--r--sc/source/core/data/dpobject.cxx100
2 files changed, 99 insertions, 9 deletions
diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx
index cc73fcbee82a..db8ea9222f0f 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 51be02db8971..b0bbace516fa 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