[Libreoffice-commits] core.git: 4 commits - sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Mon Oct 28 07:42:11 PDT 2013


 sc/inc/column.hxx                    |    2 
 sc/inc/document.hxx                  |    7 
 sc/inc/formulagroup.hxx              |   41 ++
 sc/inc/table.hxx                     |    3 
 sc/qa/unit/ucalc_formula.cxx         |   89 +++++
 sc/source/core/data/column2.cxx      |  546 +++++++++++++----------------------
 sc/source/core/data/documen2.cxx     |    3 
 sc/source/core/data/documen7.cxx     |    5 
 sc/source/core/data/document.cxx     |   15 
 sc/source/core/data/formulacell.cxx  |   12 
 sc/source/core/data/table1.cxx       |    5 
 sc/source/core/tool/formulagroup.cxx |   87 +++++
 12 files changed, 452 insertions(+), 363 deletions(-)

New commits:
commit a25c18677cea656ac52b5c08508ac70b107588bc
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Oct 28 10:37:28 2013 -0400

    Cache column data arrays to avoid duplicating data arrays.
    
    Each array's start position is always row 0, to keep the array element
    indices in sync with row positions.
    
    Change-Id: I4781fd8c24111bd991216293ad362eef283767bd

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index ca0374e..44ddf38 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -480,7 +480,7 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( SCROW nRow );
     bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 );
     void FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2 ) const;
-    formula::VectorRefArray FetchVectorRefArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 );
+    formula::VectorRefArray FetchVectorRefArray( SCROW nRow1, SCROW nRow2 );
     void SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen );
     void SetFormulaResults( SCROW nRow, const formula::FormulaTokenRef* pResults, size_t nLen );
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 840ecf0..dd84f5d 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -68,6 +68,7 @@ struct ColumnBlockPosition;
 struct RefUpdateContext;
 class EditTextIterator;
 struct NoteEntry;
+struct FormulaGroupContext;
 
 }
 
@@ -254,6 +255,7 @@ private:
     rtl::Reference<ScPoolHelper> xPoolHelper;
 
     boost::scoped_ptr<svl::SharedStringPool> mpCellStringPool;
+    boost::scoped_ptr<sc::FormulaGroupContext> mpFormulaGroupCxt;
 
     SfxUndoManager*     mpUndoManager;
     ScFieldEditEngine*  pEditEngine;                    // uses pEditPool from xPoolHelper
@@ -862,6 +864,8 @@ public:
 
     svl::SharedString GetSharedString( const ScAddress& rPos ) const;
 
+    sc::FormulaGroupContext& GetFormulaGroupContext();
+
     SC_DLLPUBLIC void GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString );
     sal_uInt16 GetStringForFormula( const ScAddress& rPos, OUString& rString );
     SC_DLLPUBLIC double GetValue( const ScAddress& rPos ) const;
@@ -2017,8 +2021,7 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos );
     formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
 
-    formula::VectorRefArray FetchVectorRefArray(
-        sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength );
+    formula::VectorRefArray FetchVectorRefArray( const ScAddress& rPos, SCROW nLength );
 
     SvtBroadcaster* GetBroadcaster( const ScAddress& rPos );
     const SvtBroadcaster* GetBroadcaster( const ScAddress& rPos ) const;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 3c7aa0e..394847f 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -854,8 +854,7 @@ public:
     ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
-    formula::VectorRefArray FetchVectorRefArray(
-        sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 );
+    formula::VectorRefArray FetchVectorRefArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
 
     ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow );
 
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index ab16141..e87878a 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -76,8 +76,7 @@ void Test::testFetchVectorRefArray()
     m_pDoc->SetValue(ScAddress(0,2,0), 3);
     m_pDoc->SetValue(ScAddress(0,3,0), 4);
 
-    sc::FormulaGroupContext aCxt;
-    formula::VectorRefArray aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(0,0,0), 4);
+    formula::VectorRefArray aArray = m_pDoc->FetchVectorRefArray(ScAddress(0,0,0), 4);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array is expected to be numeric cells only.", !aArray.mpStringArray);
     CPPUNIT_ASSERT_EQUAL(1.0, aArray.mpNumericArray[0]);
@@ -85,7 +84,7 @@ void Test::testFetchVectorRefArray()
     CPPUNIT_ASSERT_EQUAL(3.0, aArray.mpNumericArray[2]);
     CPPUNIT_ASSERT_EQUAL(4.0, aArray.mpNumericArray[3]);
 
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(0,0,0), 5);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(0,0,0), 5);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array is expected to be numeric cells only.", !aArray.mpStringArray);
     CPPUNIT_ASSERT_EQUAL(1.0, aArray.mpNumericArray[0]);
@@ -102,7 +101,7 @@ void Test::testFetchVectorRefArray()
     m_pDoc->SetString(ScAddress(1,1,0), "Bruce");
     m_pDoc->SetString(ScAddress(1,2,0), "Charlie");
     m_pDoc->SetString(ScAddress(1,3,0), "David");
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(1,0,0), 5);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(1,0,0), 5);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array is expected to be string cells only.", !aArray.mpNumericArray);
     CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray, 0, "Andy"));
@@ -119,7 +118,7 @@ void Test::testFetchVectorRefArray()
     m_pDoc->SetString(ScAddress(2,5,0), "=SUM(C2:C4)");
     m_pDoc->CalcAll();
 
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(2,0,0), 7);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(2,0,0), 7);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray.mpNumericArray && aArray.mpStringArray);
     CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray, 0, "Header"));
@@ -140,7 +139,7 @@ void Test::testFetchVectorRefArray()
     m_pDoc->SetString(ScAddress(3,7,0), "=CONCATENATE(\"A\";\"B\";\"C\")");
     m_pDoc->CalcAll();
 
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(3,0,0), 8);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(3,0,0), 8);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray.mpNumericArray && aArray.mpStringArray);
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 10));
@@ -162,7 +161,7 @@ void Test::testFetchVectorRefArray()
     m_pDoc->SetValue(ScAddress(4,9,0), 123);
 
     // This array fits within a single formula block.
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(4,0,0), 5);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(4,0,0), 5);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should be purely numeric.", aArray.mpNumericArray && !aArray.mpStringArray);
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 1));
@@ -172,7 +171,7 @@ void Test::testFetchVectorRefArray()
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 4, 5));
 
     // This array spans over multiple blocks.
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(4,0,0), 11);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(4,0,0), 11);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray.mpNumericArray && aArray.mpStringArray);
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 1));
@@ -188,7 +187,7 @@ void Test::testFetchVectorRefArray()
     CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 10));
 
     // Hit the cache but at a different start row.
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(4,2,0), 3);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(4,2,0), 3);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 3));
@@ -201,7 +200,7 @@ void Test::testFetchVectorRefArray()
     m_pDoc->SetString(ScAddress(5,4,0), "=2*8");
     m_pDoc->CalcAll();
 
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(5,2,0), 4);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(5,2,0), 4);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 1.1));
@@ -209,14 +208,14 @@ void Test::testFetchVectorRefArray()
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 16));
     CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 3));
 
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(5,0,0), 3);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(5,0,0), 3);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
     CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 0));
     CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 1));
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 1.1));
 
-    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(5,0,0), 10);
+    aArray = m_pDoc->FetchVectorRefArray(ScAddress(5,0,0), 10);
     CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
     CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
     CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 0));
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index b44cf97..aff16d5 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2616,12 +2616,13 @@ copyFirstFormulaBlock(
 
 }
 
-formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 )
+formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2 )
 {
     if (nRow1 > nRow2)
         return formula::VectorRefArray();
 
     // See if the requested range is already cached.
+    sc::FormulaGroupContext& rCxt = pDocument->GetFormulaGroupContext();
     sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
     if (pColArray)
     {
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 982d977..930c8d1 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -90,6 +90,7 @@
 #include "clipcontext.hxx"
 #include "refupdatecontext.hxx"
 #include "scopetools.hxx"
+#include "formulagroup.hxx"
 
 using namespace com::sun::star;
 
@@ -121,6 +122,7 @@ private:
 
 ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
         mpCellStringPool(new svl::SharedStringPool(ScGlobal::pCharClass)),
+        mpFormulaGroupCxt(NULL),
         mpUndoManager( NULL ),
         pEditEngine( NULL ),
         pNoteEngine( NULL ),
@@ -442,6 +444,7 @@ ScDocument::~ScDocument()
     delete pPreviewFont;
     OSL_POSTCOND( !pAutoNameCache, "AutoNameCache still set in dtor" );
 
+    mpFormulaGroupCxt.reset();
     mpCellStringPool.reset();
 }
 
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index 56ce8d1..7dd9821 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -36,6 +36,7 @@
 #include "sheetevents.hxx"
 #include "tokenarray.hxx"
 #include "listenercontext.hxx"
+#include "formulagroup.hxx"
 
 #include <tools/shl.hxx>
 
@@ -296,6 +297,8 @@ void ScDocument::CalcFormulaTree( bool bOnlyForced, bool bProgressBar, bool bSet
     // never ever recurse into this, might end up lost in infinity
     if ( IsCalculatingFormulaTree() )
         return ;
+
+    mpFormulaGroupCxt.reset();
     bCalculatingFormulaTree = true;
 
     SetForcedFormulaPending( false );
@@ -394,6 +397,8 @@ void ScDocument::CalcFormulaTree( bool bOnlyForced, bool bProgressBar, bool bSet
     bAutoCalc = bOldAutoCalc;
     EnableIdle(bOldIdleEnabled);
     bCalculatingFormulaTree = false;
+
+    mpFormulaGroupCxt.reset();
 }
 
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 15e7ee5..f8a6d92 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -94,6 +94,7 @@
 #include "listenercontext.hxx"
 #include "scopetools.hxx"
 #include "refupdatecontext.hxx"
+#include "formulagroup.hxx"
 
 #include "formula/vectortoken.hxx"
 
@@ -1675,14 +1676,13 @@ formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRan
         rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
 }
 
-formula::VectorRefArray ScDocument::FetchVectorRefArray(
-    sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength )
+formula::VectorRefArray ScDocument::FetchVectorRefArray( const ScAddress& rPos, SCROW nLength )
 {
     SCTAB nTab = rPos.Tab();
     if (!TableExists(nTab))
         return formula::VectorRefArray();
 
-    return maTabs[nTab]->FetchVectorRefArray(rCxt, rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+    return maTabs[nTab]->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
 }
 
 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
@@ -3223,6 +3223,14 @@ svl::SharedString ScDocument::GetSharedString( const ScAddress& rPos ) const
     return maTabs[rPos.Tab()]->GetSharedString(rPos.Col(), rPos.Row());
 }
 
+sc::FormulaGroupContext& ScDocument::GetFormulaGroupContext()
+{
+    if (!mpFormulaGroupCxt)
+        mpFormulaGroupCxt.reset(new sc::FormulaGroupContext);
+
+    return *mpFormulaGroupCxt;
+}
+
 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
 {
     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
@@ -3603,6 +3611,7 @@ void ScDocument::CalcAll()
         if (*it)
             (*it)->CalcAll();
     ClearFormulaTree();
+    mpFormulaGroupCxt.reset();
 }
 
 
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 4d0284b..4f27592 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3327,7 +3327,6 @@ namespace {
 
 class GroupTokenConverter
 {
-    sc::FormulaGroupContext& mrCxt;
     ScTokenArray& mrGroupTokens;
     ScDocument& mrDoc;
     ScFormulaCell& mrCell;
@@ -3389,8 +3388,8 @@ class GroupTokenConverter
         return nRowLen;
     }
 public:
-    GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
-        mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {}
+    GroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
+        mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {}
 
     bool convert(ScTokenArray& rCode)
     {
@@ -3430,7 +3429,7 @@ public:
                         // returned array equals or greater than the requested
                         // length.
 
-                        formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(mrCxt, aRefPos, nLen);
+                        formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(aRefPos, nLen);
                         if (!aArray.isValid())
                             return false;
 
@@ -3498,7 +3497,7 @@ public:
                     for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
                     {
                         aRefPos.SetCol(i);
-                        formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(mrCxt, aRefPos, nArrayLength);
+                        formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(aRefPos, nArrayLength);
                         if (!aArray.isValid())
                             return false;
 
@@ -3575,11 +3574,10 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (mxGroup->mbInvariant && false)
         return InterpretInvariantFormulaGroup();
 
-    sc::FormulaGroupContext aCxt;
     ScTokenArray aCode;
     ScAddress aTopPos = aPos;
     aTopPos.SetRow(mxGroup->mnStart);
-    GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos);
+    GroupTokenConverter aConverter(aCode, *pDocument, *this, aTopPos);
     if (!aConverter.convert(*pCode))
     {
         mxGroup->meCalcState = sc::GroupCalcDisabled;
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 45762fa..ee1ed95 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2175,8 +2175,7 @@ formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRo
     return formula::FormulaTokenRef(new ScMatrixToken(pMat));
 }
 
-formula::VectorRefArray ScTable::FetchVectorRefArray(
-    sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 )
+formula::VectorRefArray ScTable::FetchVectorRefArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
 {
     if (nRow2 < nRow1)
         return formula::VectorRefArray();
@@ -2184,7 +2183,7 @@ formula::VectorRefArray ScTable::FetchVectorRefArray(
     if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
         return formula::VectorRefArray();
 
-    return aCol[nCol].FetchVectorRefArray(rCxt, nRow1, nRow2);
+    return aCol[nCol].FetchVectorRefArray(nRow1, nRow2);
 }
 
 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
commit 7c8625b0dc7fd961404125441e33c33b1123fe4f
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 25 23:45:14 2013 -0400

    Remove duplicated code blocks.
    
    Change-Id: If9d8f96af0a216609288ef11d83a622bb490fd98

diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index c1eadbb..1691e8d 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -69,6 +69,9 @@ struct FormulaGroupContext : boost::noncopyable
 
     ColArray* setCachedColArray(
         SCTAB nTab, SCCOL nCol, NumArrayType* pNumArray, StrArrayType* pStrArray );
+
+    void ensureStrArray( ColArray& rColArray, size_t nArrayLen );
+    void ensureNumArray( ColArray& rColArray, size_t nArrayLen );
 };
 
 /**
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index daaff25..b44cf97 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2426,13 +2426,7 @@ bool appendToBlock(
             {
                 sc::string_block::iterator itData, itDataEnd;
                 getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
-
-                if (!rColArray.mpStrArray)
-                {
-                    rCxt.maStrArrays.push_back(
-                        new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
-                    rColArray.mpStrArray = &rCxt.maStrArrays.back();
-                }
+                rCxt.ensureStrArray(rColArray, nArrayLen);
 
                 for (; itData != itDataEnd; ++itData, ++nPos)
                     (*rColArray.mpStrArray)[nPos] = itData->getDataIgnoreCase();
@@ -2442,13 +2436,7 @@ bool appendToBlock(
             {
                 sc::edittext_block::iterator itData, itDataEnd;
                 getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
-
-                if (!rColArray.mpStrArray)
-                {
-                    rCxt.maStrArrays.push_back(
-                        new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
-                    rColArray.mpStrArray = &rCxt.maStrArrays.back();
-                }
+                rCxt.ensureStrArray(rColArray, nArrayLen);
 
                 for (; itData != itDataEnd; ++itData, ++nPos)
                 {
@@ -2479,24 +2467,12 @@ bool appendToBlock(
 
                     if (aRes.meType == sc::FormulaResultValue::String)
                     {
-                        if (!rColArray.mpStrArray)
-                        {
-                            rCxt.maStrArrays.push_back(
-                                new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
-                            rColArray.mpStrArray = &rCxt.maStrArrays.back();
-                        }
-
+                        rCxt.ensureStrArray(rColArray, nArrayLen);
                         (*rColArray.mpStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
                     }
                     else
                     {
-                        if (!rColArray.mpNumArray)
-                        {
-                            rCxt.maNumArrays.push_back(
-                                new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
-                            rColArray.mpNumArray = &rCxt.maNumArrays.back();
-                        }
-
+                        rCxt.ensureNumArray(rColArray, nArrayLen);
                         (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
                     }
                 }
@@ -2520,13 +2496,7 @@ bool appendToBlock(
             {
                 sc::numeric_block::iterator itData, itDataEnd;
                 getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
-
-                if (!rColArray.mpNumArray)
-                {
-                    rCxt.maNumArrays.push_back(
-                        new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
-                    rColArray.mpNumArray = &rCxt.maNumArrays.back();
-                }
+                rCxt.ensureNumArray(rColArray, nArrayLen);
 
                 for (; itData != itDataEnd; ++itData, ++nPos)
                     (*rColArray.mpNumArray)[nPos] = *itData;
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 9482b1f..05f098f 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -103,6 +103,29 @@ FormulaGroupContext::ColArray* FormulaGroupContext::setCachedColArray(
     return &rArray;
 }
 
+void FormulaGroupContext::ensureStrArray( ColArray& rColArray, size_t nArrayLen )
+{
+    if (rColArray.mpStrArray)
+        return;
+
+    maStrArrays.push_back(
+        new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
+    rColArray.mpStrArray = &maStrArrays.back();
+}
+
+void FormulaGroupContext::ensureNumArray( ColArray& rColArray, size_t nArrayLen )
+{
+    if (rColArray.mpNumArray)
+        return;
+
+    double fNan;
+    rtl::math::setNan(&fNan);
+
+    maNumArrays.push_back(
+        new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
+    rColArray.mpNumArray = &maNumArrays.back();
+}
+
 namespace {
 
 /**
commit babe7c899c08f58bdd1050320dd6e400e3f20ac9
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 25 23:08:52 2013 -0400

    Some cleanup to remove duplicated code.
    
    Change-Id: I522d3259636f6ebb29c3f4da2155c9322a382903

diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 22aca0a..daaff25 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2409,87 +2409,14 @@ void getBlockIterators(
     }
 }
 
-bool appendDouble(
-    sc::FormulaGroupContext::NumArrayType& rArray, size_t nLen,
-    sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
-{
-    size_t nLenRemain = nLen;
-    double fNan;
-    rtl::math::setNan(&fNan);
-
-    for (; it != itEnd; ++it)
-    {
-        switch (it->type)
-        {
-            case sc::element_type_numeric:
-            {
-                sc::numeric_block::iterator itData, itDataEnd;
-                getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
-
-                for (; itData != itDataEnd; ++itData)
-                    rArray.push_back(*itData);
-            }
-            break;
-            case sc::element_type_formula:
-            {
-                sc::formula_block::iterator itData, itDataEnd;
-                getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
-
-                sal_uInt16 nErr;
-                double fVal;
-                for (; itData != itDataEnd; ++itData)
-                {
-                    ScFormulaCell& rFC = **itData;
-                    if (!rFC.GetErrorOrValue(nErr, fVal) || nErr)
-                    {
-                        if (nErr == ScErrorCodes::errCircularReference)
-                        {
-                            // This cell needs to be recalculated on next visit.
-                            rFC.SetErrCode(0);
-                            rFC.SetDirtyVar();
-                        }
-                        return false;
-                    }
-
-                    rArray.push_back(fVal);
-                }
-            }
-            break;
-            case sc::element_type_empty:
-            {
-                // Fill it with NaN's.
-                if (nLenRemain >= it->size)
-                {
-                    rArray.resize(rArray.size() + it->size, fNan);
-                    nLenRemain -= it->size;
-                }
-                else
-                {
-                    rArray.resize(rArray.size() + nLenRemain, fNan);
-                    nLenRemain = 0;
-                }
-            }
-            break;
-            case sc::element_type_string:
-            case sc::element_type_edittext:
-            default:
-                return false;
-        }
-
-        if (!nLenRemain)
-            return true;
-    }
-
-    return false;
-}
-
-bool appendToNumBlock(
+bool appendToBlock(
     ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
     size_t nPos, size_t nArrayLen, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
 {
-    sc::FormulaGroupContext::NumArrayType& rNumArray = *rColArray.mpNumArray;
     svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
     size_t nLenRemain = nArrayLen - nPos;
+    double fNan;
+    rtl::math::setNan(&fNan);
 
     for (; it != itEnd; ++it)
     {
@@ -2550,9 +2477,7 @@ bool appendToNumBlock(
                         return false;
                     }
 
-                    if (aRes.meType == sc::FormulaResultValue::Value)
-                        rNumArray[nPos] = aRes.mfValue;
-                    else
+                    if (aRes.meType == sc::FormulaResultValue::String)
                     {
                         if (!rColArray.mpStrArray)
                         {
@@ -2563,100 +2488,6 @@ bool appendToNumBlock(
 
                         (*rColArray.mpStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
                     }
-                }
-            }
-            break;
-            case sc::element_type_empty:
-            {
-                if (nLenRemain > it->size)
-                {
-                    nPos += it->size;
-                    nLenRemain -= it->size;
-                }
-                else
-                {
-                    nPos = nArrayLen;
-                    nLenRemain = 0;
-                }
-            }
-            break;
-            case sc::element_type_numeric:
-            {
-                sc::numeric_block::iterator itData, itDataEnd;
-                getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
-
-                for (; itData != itDataEnd; ++itData, ++nPos)
-                    rNumArray[nPos] = *itData;
-            }
-            break;
-            default:
-                return false;
-        }
-
-        if (!nLenRemain)
-            return true;
-    }
-
-    return false;
-}
-
-bool appendToStringBlock(
-    ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
-    size_t nPos, size_t nArrayLen, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
-{
-    sc::FormulaGroupContext::StrArrayType& rStrArray = *rColArray.mpStrArray;
-    svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
-    size_t nLenRemain = nArrayLen - nPos;
-    double fNan;
-    rtl::math::setNan(&fNan);
-
-    for (; it != itEnd; ++it)
-    {
-        switch (it->type)
-        {
-            case sc::element_type_string:
-            {
-                sc::string_block::iterator itData, itDataEnd;
-                getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
-
-                for (; itData != itDataEnd; ++itData, ++nPos)
-                    rStrArray[nPos] = itData->getDataIgnoreCase();
-            }
-            break;
-            case sc::element_type_edittext:
-            {
-                sc::edittext_block::iterator itData, itDataEnd;
-                getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
-
-                for (; itData != itDataEnd; ++itData, ++nPos)
-                {
-                    OUString aStr = ScEditUtil::GetString(**itData, pDoc);
-                    rStrArray[nPos] = rPool.intern(aStr).getDataIgnoreCase();
-                }
-            }
-            break;
-            case sc::element_type_formula:
-            {
-                sc::formula_block::iterator itData, itDataEnd;
-                getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
-
-                for (; itData != itDataEnd; ++itData, ++nPos)
-                {
-                    ScFormulaCell& rFC = **itData;
-                    sc::FormulaResultValue aRes = rFC.GetResult();
-                    if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
-                    {
-                        if (aRes.mnError == ScErrorCodes::errCircularReference)
-                        {
-                            // This cell needs to be recalculated on next visit.
-                            rFC.SetErrCode(0);
-                            rFC.SetDirtyVar();
-                        }
-                        return false;
-                    }
-
-                    if (aRes.meType == sc::FormulaResultValue::String)
-                        rStrArray[nPos] = aRes.maString.getDataIgnoreCase();
                     else
                     {
                         if (!rColArray.mpNumArray)
@@ -2866,10 +2697,8 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
             // Fill the remaining array with values from the following blocks.
             size_t nPos = itBlk->size;
             ++itBlk;
-            if (!appendToNumBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
-            {
+            if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
                 return formula::VectorRefArray();
-            }
 
             if (pColArray->mpStrArray)
                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
@@ -2899,7 +2728,7 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
             // Fill the remaining array with values from the following blocks.
             size_t nPos = itBlk->size;
             ++itBlk;
-            if (!appendToStringBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
+            if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
                 return formula::VectorRefArray();
 
             if (pColArray->mpNumArray)
@@ -2936,16 +2765,8 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
 
             size_t nPos = itBlk->size;
             ++itBlk;
-            if (pColArray->mpNumArray)
-            {
-                if (!appendToNumBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
-                    return formula::VectorRefArray();
-            }
-            else
-            {
-                if (!appendToStringBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
-                    return formula::VectorRefArray();
-            }
+            if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
+                return formula::VectorRefArray();
 
             const double* pNum = NULL;
             rtl_uString** pStr = NULL;
@@ -2973,7 +2794,7 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
             // Fill the remaining array with values from the following blocks.
             size_t nPos = itBlk->size;
             ++itBlk;
-            if (!appendToNumBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
+            if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
                 return formula::VectorRefArray();
 
             if (pColArray->mpStrArray)
commit 7171b26873988058d64a4bbf37c6ea211ea0d3ce
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 25 22:03:18 2013 -0400

    Add cache of column data arrays to the group formula context.
    
    Change-Id: I225491a1c6dd0b5aa2663331b30d177a7e62329b

diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index ca240f7..c1eadbb 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -33,8 +33,42 @@ struct FormulaGroupContext : boost::noncopyable
     typedef boost::ptr_vector<NumArrayType> NumArrayStoreType;
     typedef boost::ptr_vector<StrArrayType> StrArrayStoreType;
 
-    NumArrayStoreType maNumArrays;
-    StrArrayStoreType maStrArrays;
+    struct ColKey
+    {
+        SCTAB mnTab;
+        SCCOL mnCol;
+
+        struct Hash
+        {
+            size_t operator() ( const ColKey& rKey ) const;
+        };
+
+        ColKey( SCTAB nTab, SCCOL nCol );
+
+        bool operator== ( const ColKey& r ) const;
+        bool operator!= ( const ColKey& r ) const;
+    };
+
+    struct ColArray
+    {
+        NumArrayType* mpNumArray;
+        StrArrayType* mpStrArray;
+        size_t mnSize;
+
+        ColArray( NumArrayType* pNumArray, StrArrayType* pStrArray );
+    };
+
+    typedef boost::unordered_map<ColKey, ColArray, ColKey::Hash> ColArraysType;
+
+    NumArrayStoreType maNumArrays; /// manage life cycle of numeric arrays.
+    StrArrayStoreType maStrArrays; /// manage life cycle of string arrays.
+
+    ColArraysType maColArrays; /// keep track of longest array for each column.
+
+    ColArray* getCachedColArray( SCTAB nTab, SCCOL nCol, size_t nSize );
+
+    ColArray* setCachedColArray(
+        SCTAB nTab, SCCOL nCol, NumArrayType* pNumArray, StrArrayType* pStrArray );
 };
 
 /**
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 034e0e3..ab16141 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -152,6 +152,84 @@ void Test::testFetchVectorRefArray()
     CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 6, 13));
     CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray, 7, "ABC"));
 
+    // Column E consists of formula cells whose results are all numeric.
+    for (SCROW i = 0; i <= 6; ++i)
+        m_pDoc->SetString(ScAddress(4,i,0), "=ROW()");
+    m_pDoc->CalcAll();
+
+    // Leave row 7 empty.
+    m_pDoc->SetString(ScAddress(4,8,0), "Andy");
+    m_pDoc->SetValue(ScAddress(4,9,0), 123);
+
+    // This array fits within a single formula block.
+    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(4,0,0), 5);
+    CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+    CPPUNIT_ASSERT_MESSAGE("Array should be purely numeric.", aArray.mpNumericArray && !aArray.mpStringArray);
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 1));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 1, 2));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 3));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 3, 4));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 4, 5));
+
+    // This array spans over multiple blocks.
+    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(4,0,0), 11);
+    CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+    CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray.mpNumericArray && aArray.mpStringArray);
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 1));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 1, 2));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 3));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 3, 4));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 4, 5));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 5, 6));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 6, 7));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 7));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray, 8, "Andy"));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray, 9, 123));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 10));
+
+    // Hit the cache but at a different start row.
+    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(4,2,0), 3);
+    CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+    CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 3));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 1, 4));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 5));
+
+    // Column F begins with empty rows at the top.
+    m_pDoc->SetValue(ScAddress(5,2,0), 1.1);
+    m_pDoc->SetValue(ScAddress(5,3,0), 1.2);
+    m_pDoc->SetString(ScAddress(5,4,0), "=2*8");
+    m_pDoc->CalcAll();
+
+    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(5,2,0), 4);
+    CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+    CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 0, 1.1));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 1, 1.2));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 16));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 3));
+
+    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(5,0,0), 3);
+    CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+    CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 0));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 1));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 1.1));
+
+    aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(5,0,0), 10);
+    CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+    CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray.mpNumericArray);
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 0));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 1));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 2, 1.1));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 3, 1.2));
+    CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray, 4, 16));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 5));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 6));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 7));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 8));
+    CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray, 9));
+
     m_pDoc->DeleteTab(0);
 }
 
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 5113435..22aca0a 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2483,14 +2483,13 @@ bool appendDouble(
     return false;
 }
 
-formula::VectorRefArray appendToNumBlock(
-    ScDocument* pDoc, sc::FormulaGroupContext& rCxt, size_t nPos,
-    size_t nLenRequested, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
+bool appendToNumBlock(
+    ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
+    size_t nPos, size_t nArrayLen, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
 {
-    sc::FormulaGroupContext::NumArrayType& rNumArray = rCxt.maNumArrays.back();
-    sc::FormulaGroupContext::StrArrayType* pStrArray = NULL;
+    sc::FormulaGroupContext::NumArrayType& rNumArray = *rColArray.mpNumArray;
     svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
-    size_t nLenRemain = nLenRequested - nPos;
+    size_t nLenRemain = nArrayLen - nPos;
 
     for (; it != itEnd; ++it)
     {
@@ -2501,15 +2500,15 @@ formula::VectorRefArray appendToNumBlock(
                 sc::string_block::iterator itData, itDataEnd;
                 getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
 
-                if (!pStrArray)
+                if (!rColArray.mpStrArray)
                 {
                     rCxt.maStrArrays.push_back(
-                        new sc::FormulaGroupContext::StrArrayType(nLenRequested, NULL));
-                    pStrArray = &rCxt.maStrArrays.back();
+                        new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
+                    rColArray.mpStrArray = &rCxt.maStrArrays.back();
                 }
 
                 for (; itData != itDataEnd; ++itData, ++nPos)
-                    (*pStrArray)[nPos] = itData->getDataIgnoreCase();
+                    (*rColArray.mpStrArray)[nPos] = itData->getDataIgnoreCase();
             }
             break;
             case sc::element_type_edittext:
@@ -2517,17 +2516,17 @@ formula::VectorRefArray appendToNumBlock(
                 sc::edittext_block::iterator itData, itDataEnd;
                 getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
 
-                if (!pStrArray)
+                if (!rColArray.mpStrArray)
                 {
                     rCxt.maStrArrays.push_back(
-                        new sc::FormulaGroupContext::StrArrayType(nLenRequested, NULL));
-                    pStrArray = &rCxt.maStrArrays.back();
+                        new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
+                    rColArray.mpStrArray = &rCxt.maStrArrays.back();
                 }
 
                 for (; itData != itDataEnd; ++itData, ++nPos)
                 {
                     OUString aStr = ScEditUtil::GetString(**itData, pDoc);
-                    (*pStrArray)[nPos] = rPool.intern(aStr).getDataIgnoreCase();
+                    (*rColArray.mpStrArray)[nPos] = rPool.intern(aStr).getDataIgnoreCase();
                 }
             }
             break;
@@ -2548,21 +2547,21 @@ formula::VectorRefArray appendToNumBlock(
                             rFC.SetErrCode(0);
                             rFC.SetDirtyVar();
                         }
-                        return formula::VectorRefArray();
+                        return false;
                     }
 
                     if (aRes.meType == sc::FormulaResultValue::Value)
                         rNumArray[nPos] = aRes.mfValue;
                     else
                     {
-                        if (!pStrArray)
+                        if (!rColArray.mpStrArray)
                         {
                             rCxt.maStrArrays.push_back(
-                                new sc::FormulaGroupContext::StrArrayType(nLenRequested, NULL));
-                            pStrArray = &rCxt.maStrArrays.back();
+                                new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
+                            rColArray.mpStrArray = &rCxt.maStrArrays.back();
                         }
 
-                        (*pStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
+                        (*rColArray.mpStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
                     }
                 }
             }
@@ -2576,7 +2575,7 @@ formula::VectorRefArray appendToNumBlock(
                 }
                 else
                 {
-                    nPos = nLenRequested;
+                    nPos = nArrayLen;
                     nLenRemain = 0;
                 }
             }
@@ -2591,29 +2590,23 @@ formula::VectorRefArray appendToNumBlock(
             }
             break;
             default:
-                return formula::VectorRefArray();
+                return false;
         }
 
         if (!nLenRemain)
-        {
-            if (pStrArray)
-                return formula::VectorRefArray(&rNumArray[0], &(*pStrArray)[0]);
-            else
-                return formula::VectorRefArray(&rNumArray[0]);
-        }
+            return true;
     }
 
-    return formula::VectorRefArray();
+    return false;
 }
 
-formula::VectorRefArray appendToStringBlock(
-    ScDocument* pDoc, sc::FormulaGroupContext& rCxt, size_t nPos,
-    size_t nLenRequested, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
+bool appendToStringBlock(
+    ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
+    size_t nPos, size_t nArrayLen, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
 {
-    sc::FormulaGroupContext::StrArrayType& rStrArray = rCxt.maStrArrays.back();
-    sc::FormulaGroupContext::NumArrayType* pNumArray = NULL;
+    sc::FormulaGroupContext::StrArrayType& rStrArray = *rColArray.mpStrArray;
     svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
-    size_t nLenRemain = nLenRequested - nPos;
+    size_t nLenRemain = nArrayLen - nPos;
     double fNan;
     rtl::math::setNan(&fNan);
 
@@ -2659,21 +2652,21 @@ formula::VectorRefArray appendToStringBlock(
                             rFC.SetErrCode(0);
                             rFC.SetDirtyVar();
                         }
-                        return formula::VectorRefArray();
+                        return false;
                     }
 
                     if (aRes.meType == sc::FormulaResultValue::String)
                         rStrArray[nPos] = aRes.maString.getDataIgnoreCase();
                     else
                     {
-                        if (!pNumArray)
+                        if (!rColArray.mpNumArray)
                         {
                             rCxt.maNumArrays.push_back(
-                                new sc::FormulaGroupContext::NumArrayType(nLenRequested, fNan));
-                            pNumArray = &rCxt.maNumArrays.back();
+                                new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
+                            rColArray.mpNumArray = &rCxt.maNumArrays.back();
                         }
 
-                        (*pNumArray)[nPos] = aRes.mfValue;
+                        (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
                     }
                 }
             }
@@ -2687,7 +2680,7 @@ formula::VectorRefArray appendToStringBlock(
                 }
                 else
                 {
-                    nPos = nLenRequested;
+                    nPos = nArrayLen;
                     nLenRemain = 0;
                 }
             }
@@ -2697,60 +2690,56 @@ formula::VectorRefArray appendToStringBlock(
                 sc::numeric_block::iterator itData, itDataEnd;
                 getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
 
-                if (!pNumArray)
+                if (!rColArray.mpNumArray)
                 {
                     rCxt.maNumArrays.push_back(
-                        new sc::FormulaGroupContext::NumArrayType(nLenRequested, fNan));
-                    pNumArray = &rCxt.maNumArrays.back();
+                        new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
+                    rColArray.mpNumArray = &rCxt.maNumArrays.back();
                 }
 
                 for (; itData != itDataEnd; ++itData, ++nPos)
-                    (*pNumArray)[nPos] = *itData;
+                    (*rColArray.mpNumArray)[nPos] = *itData;
             }
             break;
             default:
-                return formula::VectorRefArray();
+                return false;
         }
 
         if (!nLenRemain)
-        {
-            if (pNumArray)
-                return formula::VectorRefArray(&(*pNumArray)[0], &rStrArray[0]);
-            else
-                return formula::VectorRefArray(&rStrArray[0]);
-        }
+            return true;
     }
 
-    return formula::VectorRefArray();
+    return false;
 }
 
 void copyFirstStringBlock(
-    ScDocument& rDoc, sc::FormulaGroupContext& rCxt, size_t nLen, const sc::CellStoreType::position_type& rPos )
+    ScDocument& rDoc, sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, const sc::CellStoreType::iterator& itBlk )
 {
-    rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType);
-    sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
-    rArray.reserve(nLen);
+    sc::FormulaGroupContext::StrArrayType::iterator itArray = rArray.begin();
 
-    switch (rPos.first->type)
+    switch (itBlk->type)
     {
         case sc::element_type_string:
         {
-            svl::SharedString* p = &sc::string_block::at(*rPos.first->data, rPos.second);
-            svl::SharedString* pEnd = p + nLen;
-            for (; p != pEnd; ++p)
-                rArray.push_back(p->getDataIgnoreCase());
+            sc::string_block::iterator it = sc::string_block::begin(*itBlk->data);
+            sc::string_block::iterator itEnd = it;
+            std::advance(itEnd, nLen);
+            for (; it != itEnd; ++it, ++itArray)
+                *itArray = it->getDataIgnoreCase();
         }
         break;
         case sc::element_type_edittext:
         {
-            EditTextObject** p = &sc::edittext_block::at(*rPos.first->data, rPos.second);
-            EditTextObject** pEnd = p + nLen;
+            sc::edittext_block::iterator it = sc::edittext_block::begin(*itBlk->data);
+            sc::edittext_block::iterator itEnd = it;
+            std::advance(itEnd, nLen);
+
             svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
-            for (; p != pEnd; ++p)
+            for (; it != itEnd; ++it, ++itArray)
             {
-                EditTextObject* pText = *p;
+                EditTextObject* pText = *it;
                 OUString aStr = ScEditUtil::GetString(*pText, &rDoc);
-                rArray.push_back(rPool.intern(aStr).getDataIgnoreCase());
+                *itArray = rPool.intern(aStr).getDataIgnoreCase();
             }
         }
         break;
@@ -2759,6 +2748,71 @@ void copyFirstStringBlock(
     }
 }
 
+sc::FormulaGroupContext::ColArray*
+copyFirstFormulaBlock(
+    sc::FormulaGroupContext& rCxt, sc::CellStoreType::iterator itBlk, size_t nArrayLen,
+    SCTAB nTab, SCCOL nCol )
+{
+    double fNan;
+    rtl::math::setNan(&fNan);
+
+    size_t nLen = std::min(itBlk->size, nArrayLen);
+
+    sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
+    sc::formula_block::iterator itEnd;
+
+    sc::FormulaGroupContext::NumArrayType* pNumArray = NULL;
+    sc::FormulaGroupContext::StrArrayType* pStrArray = NULL;
+
+    itEnd = it;
+    std::advance(itEnd, nLen);
+    size_t nPos = 0;
+    for (; it != itEnd; ++it, ++nPos)
+    {
+        ScFormulaCell& rFC = **it;
+        sc::FormulaResultValue aRes = rFC.GetResult();
+        if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
+        {
+            if (aRes.mnError == ScErrorCodes::errCircularReference)
+            {
+                // This cell needs to be recalculated on next visit.
+                rFC.SetErrCode(0);
+                rFC.SetDirtyVar();
+            }
+            return NULL;
+        }
+
+        if (aRes.meType == sc::FormulaResultValue::Value)
+        {
+            if (!pNumArray)
+            {
+                rCxt.maNumArrays.push_back(
+                    new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
+                pNumArray = &rCxt.maNumArrays.back();
+            }
+
+            (*pNumArray)[nPos] = aRes.mfValue;
+        }
+        else
+        {
+            if (!pStrArray)
+            {
+                rCxt.maStrArrays.push_back(
+                    new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
+                pStrArray = &rCxt.maStrArrays.back();
+            }
+
+            (*pStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
+        }
+    }
+
+    if (!pNumArray && !pStrArray)
+        // At least one of these arrays should be allocated.
+        return NULL;
+
+    return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray);
+}
+
 }
 
 formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 )
@@ -2766,142 +2820,168 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
     if (nRow1 > nRow2)
         return formula::VectorRefArray();
 
+    // See if the requested range is already cached.
+    sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
+    if (pColArray)
+    {
+        const double* pNum = NULL;
+        if (pColArray->mpNumArray)
+            pNum = &(*pColArray->mpNumArray)[nRow1];
+
+        rtl_uString** pStr = NULL;
+        if (pColArray->mpStrArray)
+            pStr = &(*pColArray->mpStrArray)[nRow1];
+
+        return formula::VectorRefArray(pNum, pStr);
+    }
+
     double fNan;
     rtl::math::setNan(&fNan);
 
-    size_t nLenRequested = nRow2 - nRow1 + 1;
-    sc::CellStoreType::position_type aPos = maCells.position(nRow1);
-    size_t nLen = aPos.first->size - aPos.second; // length of data from first block
-    switch (aPos.first->type)
+    // We need to fetch all cell values from row 0 to nRow2 for caching purposes.
+    sc::CellStoreType::iterator itBlk = maCells.begin();
+    switch (itBlk->type)
     {
         case sc::element_type_numeric:
         {
-            // This is a numeric cell block.
-            if (nLenRequested <= nLen)
+            if (static_cast<size_t>(nRow2) < itBlk->size)
             {
-                // Requested length fits a single block.
-                const double* p = &sc::numeric_block::at(*aPos.first->data, aPos.second);
+                // Requested range falls within the first block. No need to cache.
+                const double* p = &sc::numeric_block::at(*itBlk->data, nRow1);
                 return formula::VectorRefArray(p);
             }
 
             // Allocate a new array and copy the values to it.
-            sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aPos.first->data);
-            sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*aPos.first->data);
-            std::advance(it, aPos.second);
+            sc::numeric_block::const_iterator it = sc::numeric_block::begin(*itBlk->data);
+            sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*itBlk->data);
             rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(it, itEnd));
             sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
-            rArray.resize(nLenRequested, fNan); // allocate to the requested length.
+            rArray.resize(nRow2+1, fNan); // allocate to the requested length.
+
+            pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
+            if (!pColArray)
+                // Failed to insert a new cached column array.
+                return formula::VectorRefArray();
 
             // Fill the remaining array with values from the following blocks.
-            ++aPos.first;
-            return appendToNumBlock(pDocument, rCxt, nLen, nLenRequested, aPos.first, maCells.end());
+            size_t nPos = itBlk->size;
+            ++itBlk;
+            if (!appendToNumBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
+            {
+                return formula::VectorRefArray();
+            }
+
+            if (pColArray->mpStrArray)
+                return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
+            else
+                return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
         }
         break;
-        case sc::element_type_formula:
+        case sc::element_type_string:
+        case sc::element_type_edittext:
         {
-            sal_uInt16 nErr;
-            double fVal;
-
-            rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType);
-            sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
-            rArray.reserve(nLenRequested);
+            rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType(nRow2+1, NULL));
+            sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
+            pColArray = rCxt.setCachedColArray(nTab, nCol, NULL, &rArray);
+            if (!pColArray)
+                // Failed to insert a new cached column array.
+                return formula::VectorRefArray();
 
-            sc::formula_block::const_iterator it = sc::formula_block::begin(*aPos.first->data);
-            std::advance(it, aPos.second);
-            sc::formula_block::const_iterator itEnd;
-            if (nLenRequested <= nLen)
+            if (static_cast<size_t>(nRow2) < itBlk->size)
             {
-                // Requested length is within a single block.
-                itEnd = it;
-                std::advance(itEnd, nLenRequested);
-                for (; it != itEnd; ++it)
-                {
-                    ScFormulaCell& rCell = **it;
-                    if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
-                    {
-                        if (nErr == ScErrorCodes::errCircularReference)
-                        {
-                            // This cell needs to be recalculated on next visit.
-                            rCell.SetErrCode(0);
-                            rCell.SetDirtyVar();
-                        }
-                        return formula::VectorRefArray();
-                    }
-
-                    rArray.push_back(fVal);
-                }
-
+                // Requested range falls within the first block.
+                copyFirstStringBlock(*pDocument, rArray, nRow2+1, itBlk);
                 return formula::VectorRefArray(&rArray[0]);
             }
 
-            // Requested length goes beyond a single block.  Fill the array
-            // with the content of this formula block first.
-            itEnd = sc::formula_block::end(*aPos.first->data);
-            for (; it != itEnd; ++it)
-            {
-                ScFormulaCell& rCell = **it;
-                if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
-                {
-                    if (nErr == ScErrorCodes::errCircularReference)
-                    {
-                        // This cell needs to be recalculated on next visit.
-                        rCell.SetErrCode(0);
-                        rCell.SetDirtyVar();
-                    }
-                    return formula::VectorRefArray();
-                }
-
-                rArray.push_back(fVal);
-            }
+            copyFirstStringBlock(*pDocument, rArray, itBlk->size, itBlk);
 
             // Fill the remaining array with values from the following blocks.
-            ++aPos.first;
-            if (!appendDouble(rArray, nLenRequested - nLen, aPos.first, maCells.end()))
+            size_t nPos = itBlk->size;
+            ++itBlk;
+            if (!appendToStringBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
                 return formula::VectorRefArray();
 
-            return formula::VectorRefArray(&rArray[0]);
+            if (pColArray->mpNumArray)
+                return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
+            else
+                return formula::VectorRefArray(&(*pColArray->mpStrArray)[nRow1]);
         }
         break;
-        case sc::element_type_string:
-        case sc::element_type_edittext:
+        case sc::element_type_formula:
         {
-            if (nLenRequested <= nLen)
+            if (static_cast<size_t>(nRow2) < itBlk->size)
             {
-                // Requested length fits a single block.
-                copyFirstStringBlock(*pDocument, rCxt, nLenRequested, aPos);
-                sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
-                return formula::VectorRefArray(&rArray[0]);
+                // Requested length is within a single block, and the data is
+                // not cached.
+                pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
+                if (!pColArray)
+                    // Failed to insert a new cached column array.
+                    return formula::VectorRefArray();
+
+                const double* pNum = NULL;
+                rtl_uString** pStr = NULL;
+                if (pColArray->mpNumArray)
+                    pNum = &(*pColArray->mpNumArray)[0];
+                if (pColArray->mpStrArray)
+                    pStr = &(*pColArray->mpStrArray)[0];
+
+                return formula::VectorRefArray(pNum, pStr);
             }
 
-            copyFirstStringBlock(*pDocument, rCxt, nLen, aPos);
-            rCxt.maStrArrays.back().resize(nLenRequested, NULL); // allocate array to requested length.
+            pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
+            if (!pColArray)
+                // Failed to insert a new cached column array.
+                return formula::VectorRefArray();
 
-            // Fill the remaining array with values from the following blocks.
-            ++aPos.first;
-            return appendToStringBlock(pDocument, rCxt, nLen, nLenRequested, aPos.first, maCells.end());
+            size_t nPos = itBlk->size;
+            ++itBlk;
+            if (pColArray->mpNumArray)
+            {
+                if (!appendToNumBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
+                    return formula::VectorRefArray();
+            }
+            else
+            {
+                if (!appendToStringBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
+                    return formula::VectorRefArray();
+            }
+
+            const double* pNum = NULL;
+            rtl_uString** pStr = NULL;
+            if (pColArray->mpNumArray)
+                pNum = &(*pColArray->mpNumArray)[0];
+            if (pColArray->mpStrArray)
+                pStr = &(*pColArray->mpStrArray)[0];
+
+            return formula::VectorRefArray(pNum, pStr);
         }
         break;
         case sc::element_type_empty:
         {
-            if (nLenRequested <= nLen)
-            {
-                // Fill the whole length with NaN's.
-                rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLenRequested, fNan));
-                return formula::VectorRefArray(&rCxt.maNumArrays.back()[0]);
-            }
-
-            // Fill the array with zero for the length of the empty block.
-            rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLen, 0.0));
+            // Fill the whole length with NaN's.
+            rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nRow2+1, fNan));
             sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
-            rArray.reserve(nLenRequested);
+            pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
+            if (!pColArray)
+                // Failed to insert a new cached column array.
+                return formula::VectorRefArray();
+
+            if (static_cast<size_t>(nRow2) < itBlk->size)
+                return formula::VectorRefArray(&(*pColArray->mpNumArray)[0]);
 
             // Fill the remaining array with values from the following blocks.
-            ++aPos.first;
-            if (!appendDouble(rArray, nLenRequested - nLen, aPos.first, maCells.end()))
+            size_t nPos = itBlk->size;
+            ++itBlk;
+            if (!appendToNumBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
                 return formula::VectorRefArray();
 
-            return formula::VectorRefArray(&rArray[0]);
+            if (pColArray->mpStrArray)
+                return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
+            else
+                return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
         }
+        break;
         default:
             ;
     }
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 7f1bd74..9482b1f 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -39,6 +39,70 @@ extern "C" void compileOpenCLKernels(const OUString*);
 
 namespace sc {
 
+size_t FormulaGroupContext::ColKey::Hash::operator ()( const FormulaGroupContext::ColKey& rKey ) const
+{
+    return rKey.mnTab * MAXCOLCOUNT + rKey.mnCol;
+}
+
+FormulaGroupContext::ColKey::ColKey( SCTAB nTab, SCCOL nCol ) : mnTab(nTab), mnCol(nCol) {}
+
+bool FormulaGroupContext::ColKey::operator== ( const ColKey& r ) const
+{
+    return mnTab == r.mnTab && mnCol == r.mnCol;
+}
+
+bool FormulaGroupContext::ColKey::operator!= ( const ColKey& r ) const
+{
+    return !operator==(r);
+}
+
+FormulaGroupContext::ColArray::ColArray( NumArrayType* pNumArray, StrArrayType* pStrArray ) :
+    mpNumArray(pNumArray), mpStrArray(pStrArray), mnSize(0)
+{
+    if (mpNumArray)
+        mnSize = mpNumArray->size();
+    else if (mpStrArray)
+        mnSize = mpStrArray->size();
+}
+
+FormulaGroupContext::ColArray* FormulaGroupContext::getCachedColArray( SCTAB nTab, SCCOL nCol, size_t nSize )
+{
+    ColArraysType::iterator itColArray = maColArrays.find(ColKey(nTab, nCol));
+    if (itColArray == maColArrays.end())
+        // Not cached for this column.
+        return NULL;
+
+    ColArray& rCached = itColArray->second;
+    if (nSize > rCached.mnSize)
+        // Cached data array is not long enough for the requested range.
+        return NULL;
+
+    return &rCached;
+}
+
+FormulaGroupContext::ColArray* FormulaGroupContext::setCachedColArray(
+    SCTAB nTab, SCCOL nCol, NumArrayType* pNumArray, StrArrayType* pStrArray )
+{
+    ColArraysType::iterator it = maColArrays.find(ColKey(nTab, nCol));
+    if (it == maColArrays.end())
+    {
+        std::pair<ColArraysType::iterator,bool> r =
+            maColArrays.insert(
+                ColArraysType::value_type(ColKey(nTab, nCol), ColArray(pNumArray, pStrArray)));
+
+        if (!r.second)
+            // Somehow the insertion failed.
+            return NULL;
+
+        return &r.first->second;
+    }
+
+    // Prior array exists for this column. Overwrite it.
+    ColArray& rArray = it->second;
+    rArray = ColArray(pNumArray, pStrArray);
+    return &rArray;
+}
+
 namespace {
 
 /**


More information about the Libreoffice-commits mailing list