[Libreoffice-commits] core.git: 15 commits - i18npool/source sc/inc sc/qa sc/source
Eike Rathke
erack at redhat.com
Mon May 22 09:01:23 UTC 2017
i18npool/source/localedata/data/locale.dtd | 14 +
sc/inc/token.hxx | 8 -
sc/qa/unit/ucalc.hxx | 2
sc/qa/unit/ucalc_formula.cxx | 47 +++++
sc/source/core/inc/interpre.hxx | 9 +
sc/source/core/inc/jumpmatrix.hxx | 3
sc/source/core/tool/interpr1.cxx | 230 ++++++++++++++++++++++++++---
sc/source/core/tool/interpr3.cxx | 30 +--
sc/source/core/tool/interpr6.cxx | 181 +++++++++++++++++++---
sc/source/core/tool/jumpmatrix.cxx | 5
sc/source/core/tool/token.cxx | 5
11 files changed, 463 insertions(+), 71 deletions(-)
New commits:
commit f6cdba8a801ba296bd3f7ca6334fc3671b0bbe58
Author: Eike Rathke <erack at redhat.com>
Date: Sun May 21 00:20:46 2017 +0200
Factor out ScInterpreter::SwitchToArrayRefList(), tdf#58874
Change-Id: I7a672b8d0bd6dae9baa1289a3b00b0789a0d4d6d
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 3586d21c317f..9948392ea622 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -571,6 +571,10 @@ void ScMax( bool bTextAsZero = false );
/** Check for array of references to determine the maximum size of a return
column vector if in array context. */
size_t GetRefListArrayMaxSize( short nParamCount );
+/** Switch to array reference list if current TOS is one and create/init or
+ update matrix and return true. Else return false. */
+bool SwitchToArrayRefList( ScMatrixRef& xResMat, SCSIZE nMatRows, double fCurrent,
+ const std::function<bool( double& fVectorResult, const double& fCurrent )>& AssignFunc );
void IterateParameters( ScIterFunc, bool bTextAsZero = false );
void ScSumSQ();
void ScSum();
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index bf8b9dc77c00..675e9c8165bf 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3456,6 +3456,34 @@ void ScInterpreter::ScUnichar()
}
}
+bool ScInterpreter::SwitchToArrayRefList( ScMatrixRef& xResMat, SCSIZE nMatRows, double fCurrent,
+ const std::function<bool( double& fVectorResult, const double& fCurrent )>& AssignFunc )
+{
+ const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+ if (!p || !p->IsArrayResult())
+ return false;
+
+ if (!xResMat)
+ {
+ // Create and init all elements with current value.
+ assert(nMatRows > 0);
+ xResMat = GetNewMat( 1, nMatRows, true);
+ xResMat->FillDouble( fCurrent, 0,0, 0,nMatRows-1);
+ }
+ else
+ {
+ // Current value and values from vector are operands
+ // for each vector position.
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (AssignFunc( fVecRes, fCurrent))
+ xResMat->PutDouble( fVecRes, 0,i);
+ }
+ }
+ return true;
+}
+
void ScInterpreter::ScMin( bool bTextAsZero )
{
short nParamCount = GetByte();
@@ -3499,29 +3527,17 @@ void ScInterpreter::ScMin( bool bTextAsZero )
break;
case svRefList :
{
- const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
- if (p && p->IsArrayResult())
+ auto AssignFunc = []( double& fVecRes, double fMin )
{
- nRefArrayPos = nRefInList;
- if (!xResMat)
- {
- // Create and init all elements with current value.
- assert(nMatRows > 0);
- xResMat = GetNewMat( 1, nMatRows, true);
- xResMat->FillDouble( nMin, 0,0, 0,nMatRows-1);
- }
- else
+ if (fVecRes > fMin)
{
- // Current value and values from vector are operands
- // for each vector position.
- for (SCSIZE i=0; i < nMatRows; ++i)
- {
- double fVecRes = xResMat->GetDouble(0,i);
- if (fVecRes > nMin)
- xResMat->PutDouble( nMin, 0,i);
- }
+ fVecRes = fMin;
+ return true;
}
- }
+ return false;
+ };
+ if (SwitchToArrayRefList( xResMat, nMatRows, nMin, AssignFunc))
+ nRefArrayPos = nRefInList;
}
SAL_FALLTHROUGH;
case svDoubleRef :
@@ -3666,29 +3682,17 @@ void ScInterpreter::ScMax( bool bTextAsZero )
break;
case svRefList :
{
- const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
- if (p && p->IsArrayResult())
+ auto AssignFunc = []( double& fVecRes, double fMax )
{
- nRefArrayPos = nRefInList;
- if (!xResMat)
+ if (fVecRes < fMax)
{
- // Create and init all elements with current value.
- assert(nMatRows > 0);
- xResMat = GetNewMat( 1, nMatRows, true);
- xResMat->FillDouble( nMax, 0,0, 0,nMatRows-1);
+ fVecRes = fMax;
+ return true;
}
- else
- {
- // Current value and values from vector are operands
- // for each vector position.
- for (SCSIZE i=0; i < nMatRows; ++i)
- {
- double fVecRes = xResMat->GetDouble(0,i);
- if (fVecRes < nMax)
- xResMat->PutDouble( nMax, 0,i);
- }
- }
- }
+ return false;
+ };
+ if (SwitchToArrayRefList( xResMat, nMatRows, nMax, AssignFunc))
+ nRefArrayPos = nRefInList;
}
SAL_FALLTHROUGH;
case svDoubleRef :
commit 667e0625090f084b8d9ae5a885b6b4624766ed6c
Author: Eike Rathke <erack at redhat.com>
Date: Sat May 20 23:06:38 2017 +0200
Unit test for SUBTOTAL MIN,MAX with array of references, tdf#58874
Change-Id: I116b236066f28e3442f644544e789e1dbc2ff88a
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index c2b46cec85ae..92f93722c531 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -7922,11 +7922,29 @@ void Test::testFuncRefListArraySUBTOTAL()
aMark.SelectOneTable(0);
m_pDoc->InsertMatrixFormula(1, 6, 1, 8, aMark, "=SUBTOTAL(9;OFFSET(A1;ROW(1:3);0;2))");
ScAddress aPos(1,6,0);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A2:A3 failed", 6.0, m_pDoc->GetValue(aPos));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL SUM for A2:A3 failed", 6.0, m_pDoc->GetValue(aPos));
aPos.IncRow();
- CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A3:A4 failed", 12.0, m_pDoc->GetValue(aPos));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL SUM for A3:A4 failed", 12.0, m_pDoc->GetValue(aPos));
aPos.IncRow();
- CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A4:A5 failed", 24.0, m_pDoc->GetValue(aPos));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL SUM for A4:A5 failed", 24.0, m_pDoc->GetValue(aPos));
+
+ // Matrix in C7:C9, individual MIN of A2:A3, A3:A4 and A4:A5
+ m_pDoc->InsertMatrixFormula(2, 6, 2, 8, aMark, "=SUBTOTAL(5;OFFSET(A1;ROW(1:3);0;2))");
+ aPos.Set(2,6,0);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MIN for A2:A3 failed", 2.0, m_pDoc->GetValue(aPos));
+ aPos.IncRow();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MIN for A3:A4 failed", 4.0, m_pDoc->GetValue(aPos));
+ aPos.IncRow();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MIN for A4:A5 failed", 8.0, m_pDoc->GetValue(aPos));
+
+ // Matrix in D7:D9, individual MAX of A2:A3, A3:A4 and A4:A5
+ m_pDoc->InsertMatrixFormula(3, 6, 3, 8, aMark, "=SUBTOTAL(4;OFFSET(A1;ROW(1:3);0;2))");
+ aPos.Set(3,6,0);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MAX for A2:A3 failed", 4.0, m_pDoc->GetValue(aPos));
+ aPos.IncRow();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MAX for A3:A4 failed", 8.0, m_pDoc->GetValue(aPos));
+ aPos.IncRow();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MAX for A4:A5 failed", 16.0, m_pDoc->GetValue(aPos));
m_pDoc->DeleteTab(0);
}
commit c41b82203ef54a74bd0693e29f65617d0e158a06
Author: Eike Rathke <erack at redhat.com>
Date: Sat May 20 23:05:33 2017 +0200
Handle MIN and MAX with arrays of references, tdf#58874
Change-Id: I24c9f3078f60e14e64f1e1e3910963dfe0a38d77
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 7417e54b8ca3..bf8b9dc77c00 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3461,6 +3461,9 @@ void ScInterpreter::ScMin( bool bTextAsZero )
short nParamCount = GetByte();
if (!MustHaveParamCountMin( nParamCount, 1))
return;
+ const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
+ ScMatrixRef xResMat;
+ size_t nRefArrayPos = std::numeric_limits<size_t>::max();
double nMin = ::std::numeric_limits<double>::max();
double nVal = 0.0;
ScAddress aAdr;
@@ -3494,9 +3497,35 @@ void ScInterpreter::ScMin( bool bTextAsZero )
}
}
break;
- case svDoubleRef :
case svRefList :
{
+ const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+ if (p && p->IsArrayResult())
+ {
+ nRefArrayPos = nRefInList;
+ if (!xResMat)
+ {
+ // Create and init all elements with current value.
+ assert(nMatRows > 0);
+ xResMat = GetNewMat( 1, nMatRows, true);
+ xResMat->FillDouble( nMin, 0,0, 0,nMatRows-1);
+ }
+ else
+ {
+ // Current value and values from vector are operands
+ // for each vector position.
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (fVecRes > nMin)
+ xResMat->PutDouble( nMin, 0,i);
+ }
+ }
+ }
+ }
+ SAL_FALLTHROUGH;
+ case svDoubleRef :
+ {
FormulaError nErr = FormulaError::NONE;
PopDoubleRef( aRange, nParamCount, nRefInList);
ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
@@ -3512,6 +3541,18 @@ void ScInterpreter::ScMin( bool bTextAsZero )
}
SetError(nErr);
}
+ if (nRefArrayPos != std::numeric_limits<size_t>::max())
+ {
+ // Update vector element with current value.
+ double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
+ if (fVecRes > nMin)
+ xResMat->PutDouble( nMin, 0,nRefArrayPos);
+
+ // Reset.
+ nMin = std::numeric_limits<double>::max();
+ nVal = 0.0;
+ nRefArrayPos = std::numeric_limits<size_t>::max();
+ }
}
break;
case svMatrix :
@@ -3545,10 +3586,41 @@ void ScInterpreter::ScMin( bool bTextAsZero )
SetError(FormulaError::IllegalParameter);
}
}
- if ( nVal < nMin )
- PushDouble(0.0);
+
+ if (xResMat)
+ {
+ // Include value of last non-references-array type and calculate final result.
+ if (nMin < std::numeric_limits<double>::max())
+ {
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (fVecRes > nMin)
+ xResMat->PutDouble( nMin, 0,i);
+ }
+ }
+ else
+ {
+ /* TODO: the awkward "no value is minimum 0.0" is likely the case
+ * if a value is numeric_limits::max. Still, that could be a valid
+ * minimum value as well, but nVal and nMin had been reset after
+ * the last svRefList.. so we may lie here. */
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (fVecRes == std::numeric_limits<double>::max())
+ xResMat->PutDouble( 0.0, 0,i);
+ }
+ }
+ PushMatrix( xResMat);
+ }
else
- PushDouble(nMin);
+ {
+ if ( nVal < nMin )
+ PushDouble(0.0); // zero or only empty arguments
+ else
+ PushDouble(nMin);
+ }
}
void ScInterpreter::ScMax( bool bTextAsZero )
@@ -3556,7 +3628,10 @@ void ScInterpreter::ScMax( bool bTextAsZero )
short nParamCount = GetByte();
if (!MustHaveParamCountMin( nParamCount, 1))
return;
- double nMax = -(::std::numeric_limits<double>::max());
+ const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
+ ScMatrixRef xResMat;
+ size_t nRefArrayPos = std::numeric_limits<size_t>::max();
+ double nMax = std::numeric_limits<double>::lowest();
double nVal = 0.0;
ScAddress aAdr;
ScRange aRange;
@@ -3589,9 +3664,35 @@ void ScInterpreter::ScMax( bool bTextAsZero )
}
}
break;
- case svDoubleRef :
case svRefList :
{
+ const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+ if (p && p->IsArrayResult())
+ {
+ nRefArrayPos = nRefInList;
+ if (!xResMat)
+ {
+ // Create and init all elements with current value.
+ assert(nMatRows > 0);
+ xResMat = GetNewMat( 1, nMatRows, true);
+ xResMat->FillDouble( nMax, 0,0, 0,nMatRows-1);
+ }
+ else
+ {
+ // Current value and values from vector are operands
+ // for each vector position.
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (fVecRes < nMax)
+ xResMat->PutDouble( nMax, 0,i);
+ }
+ }
+ }
+ }
+ SAL_FALLTHROUGH;
+ case svDoubleRef :
+ {
FormulaError nErr = FormulaError::NONE;
PopDoubleRef( aRange, nParamCount, nRefInList);
ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
@@ -3607,6 +3708,18 @@ void ScInterpreter::ScMax( bool bTextAsZero )
}
SetError(nErr);
}
+ if (nRefArrayPos != std::numeric_limits<size_t>::max())
+ {
+ // Update vector element with current value.
+ double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
+ if (fVecRes < nMax)
+ xResMat->PutDouble( nMax, 0,nRefArrayPos);
+
+ // Reset.
+ nMax = std::numeric_limits<double>::lowest();
+ nVal = 0.0;
+ nRefArrayPos = std::numeric_limits<size_t>::max();
+ }
}
break;
case svMatrix :
@@ -3640,10 +3753,41 @@ void ScInterpreter::ScMax( bool bTextAsZero )
SetError(FormulaError::IllegalParameter);
}
}
- if ( nVal > nMax )
- PushDouble(0.0);
+
+ if (xResMat)
+ {
+ // Include value of last non-references-array type and calculate final result.
+ if (nMax > std::numeric_limits<double>::lowest())
+ {
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (fVecRes < nMax)
+ xResMat->PutDouble( nMax, 0,i);
+ }
+ }
+ else
+ {
+ /* TODO: the awkward "no value is maximum 0.0" is likely the case
+ * if a value is numeric_limits::lowest. Still, that could be a
+ * valid maximum value as well, but nVal and nMax had been reset
+ * after the last svRefList.. so we may lie here. */
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (fVecRes == -std::numeric_limits<double>::max())
+ xResMat->PutDouble( 0.0, 0,i);
+ }
+ }
+ PushMatrix( xResMat);
+ }
else
- PushDouble(nMax);
+ {
+ if ( nVal > nMax )
+ PushDouble(0.0); // zero or only empty arguments
+ else
+ PushDouble(nMax);
+ }
}
void ScInterpreter::GetStVarParams( double& rVal, double& rValCount, bool bTextAsZero )
commit 5236e847191bbc3fb47a630bec5dbe8ed65679d7
Author: Eike Rathke <erack at redhat.com>
Date: Sat May 20 22:08:12 2017 +0200
const nMatRows, tdf#58874
Change-Id: Ic9e11ed6b8890fe9d3db4b3a9b4d1d8d50838b2e
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index d0cb8a14b82f..35004f2846bc 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -504,7 +504,7 @@ static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uL
void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
{
short nParamCount = GetByte();
- SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
+ const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
ScMatrixRef xResMat, xResCount;
double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
double fVal = 0.0;
commit 17dd13922c01a864e5124afc97c9b19f0e29b44c
Author: Eike Rathke <erack at redhat.com>
Date: Sat May 20 21:30:41 2017 +0200
Factor out to ScInterpreter::GetRefListArrayMaxSize(), tdf#58874
Change-Id: Ie08c37ff66faaaba8f8945503e3d212943d324d7
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 9ddf9e2c1900..3586d21c317f 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -568,6 +568,9 @@ void ScUnicode();
void ScUnichar();
void ScMin( bool bTextAsZero = false );
void ScMax( bool bTextAsZero = false );
+/** Check for array of references to determine the maximum size of a return
+ column vector if in array context. */
+size_t GetRefListArrayMaxSize( short nParamCount );
void IterateParameters( ScIterFunc, bool bTextAsZero = false );
void ScSumSQ();
void ScSum();
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 0b36b129b48f..d0cb8a14b82f 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -459,6 +459,24 @@ void IterateMatrix(
}
}
+size_t ScInterpreter::GetRefListArrayMaxSize( short nParamCount )
+{
+ size_t nSize = 0;
+ if (bMatrixFormula || pCur->IsInForceArray())
+ {
+ for (short i=1; i <= nParamCount; ++i)
+ {
+ if (GetStackType(i) == svRefList)
+ {
+ const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
+ if (p && p->IsArrayResult() && p->GetRefList()->size() > nSize)
+ nSize = p->GetRefList()->size();
+ }
+ }
+ }
+ return nSize;
+}
+
static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount )
{
switch( eFunc )
@@ -486,21 +504,7 @@ static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uL
void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
{
short nParamCount = GetByte();
- SCSIZE nMatRows = 0;
- if (bMatrixFormula || pCur->IsInForceArray())
- {
- // Check for arrays of references to determine the maximum size of a
- // return column vector.
- for (short i=1; i <= nParamCount; ++i)
- {
- if (GetStackType(i) == svRefList)
- {
- const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
- if (p && p->IsArrayResult() && p->GetRefList()->size() > nMatRows)
- nMatRows = p->GetRefList()->size();
- }
- }
- }
+ SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
ScMatrixRef xResMat, xResCount;
double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
double fVal = 0.0;
commit 1e70dedee1c7be912e4aaa2ff12b046dbd364a86
Author: Eike Rathke <erack at redhat.com>
Date: Sat May 20 21:29:30 2017 +0200
Add unit test for SUBTOTAL over reference list in array context, tdf#58874
Change-Id: I82752c035f6551d3136dc06331ff8745ba959463
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 5d1def66c7c7..d36ed7ddd2a5 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -212,6 +212,7 @@ public:
void testFuncLCM();
void testFuncSUMSQ();
void testFuncMDETERM();
+ void testFuncRefListArraySUBTOTAL();
void testMatConcat();
void testMatConcatReplication();
void testRefR1C1WholeCol();
@@ -620,6 +621,7 @@ public:
CPPUNIT_TEST(testFuncLCM);
CPPUNIT_TEST(testFuncSUMSQ);
CPPUNIT_TEST(testFuncMDETERM);
+ CPPUNIT_TEST(testFuncRefListArraySUBTOTAL);
CPPUNIT_TEST(testMatConcat);
CPPUNIT_TEST(testMatConcatReplication);
CPPUNIT_TEST(testExternalRef);
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 7c58bcb51522..c2b46cec85ae 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -7904,4 +7904,31 @@ void Test::testFuncRowsHidden()
m_pDoc->DeleteTab(0);
}
+// Test SUBTOTAL with reference lists in array context.
+void Test::testFuncRefListArraySUBTOTAL()
+{
+ sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+ m_pDoc->InsertTab(0, "Test");
+
+ m_pDoc->SetValue(0,0,0, 1.0); // A1
+ m_pDoc->SetValue(0,1,0, 2.0); // A2
+ m_pDoc->SetValue(0,2,0, 4.0); // A3
+ m_pDoc->SetValue(0,3,0, 8.0); // A4
+ m_pDoc->SetValue(0,4,0, 16.0); // A5
+ m_pDoc->SetValue(0,5,0, 32.0); // A6
+
+ // Matrix in B7:B9, individual SUM of A2:A3, A3:A4 and A4:A5
+ ScMarkData aMark;
+ aMark.SelectOneTable(0);
+ m_pDoc->InsertMatrixFormula(1, 6, 1, 8, aMark, "=SUBTOTAL(9;OFFSET(A1;ROW(1:3);0;2))");
+ ScAddress aPos(1,6,0);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A2:A3 failed", 6.0, m_pDoc->GetValue(aPos));
+ aPos.IncRow();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A3:A4 failed", 12.0, m_pDoc->GetValue(aPos));
+ aPos.IncRow();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A4:A5 failed", 24.0, m_pDoc->GetValue(aPos));
+
+ m_pDoc->DeleteTab(0);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit d9ba325bf1fd4e8f5557f34e5af6502107be5207
Author: Eike Rathke <erack at redhat.com>
Date: Sat May 20 21:14:31 2017 +0200
Use SetValue() instead of SetString()
Change-Id: I9d1f9be14d69006126a2c72b7c4cfbfb24b3cfe8
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 223b88dd1f2f..7c58bcb51522 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -7837,7 +7837,7 @@ void Test::testIntersectionOpExcel()
// Vertical cell range covering C2.
pGlobalNames->insert( new ScRangeData( m_pDoc, "vert", "$C$1:$C$3"));
// Data in C2.
- m_pDoc->SetString(2,1,0,"1");
+ m_pDoc->SetValue(2,1,0, 1.0);
m_pDoc->SetGrammar(FormulaGrammar::GRAM_ENGLISH_XL_A1);
commit 91bdd41bb0092e7ed9ef4e5b782650be3cfd9440
Author: Eike Rathke <erack at redhat.com>
Date: Sat May 20 20:09:01 2017 +0200
Handle reference list as array in IterateParameters(), tdf#58874
This in array context now returns the expexted array for an expression like
=SUBTOTAL(9,OFFSET(A1,ROW(1:3),0,2))
where OFFSET returns an array (svRefList) of references, here
A2:A3
A3:A4
A4:A5
and SUBTOTAL(9,...) sums each of the references independently to return an
array of three sums.
Currently works with SUM, COUNT, COUNT2, AVERAGE, PRODUCT and SUMSQ.
MAX and MIN are not handle in IterateParameters() and need an extra
implementation, or rather move them into IterateParameters() as well?
Change-Id: I03b7d1cccf78c1a831348106432126aec8d1f519
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 72c82e9474a7..0b36b129b48f 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -459,9 +459,49 @@ void IterateMatrix(
}
}
+static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount )
+{
+ switch( eFunc )
+ {
+ case ifSUM:
+ fRes = ::rtl::math::approxAdd( fRes, fMem );
+ break;
+ case ifAVERAGE:
+ fRes = sc::div( ::rtl::math::approxAdd( fRes, fMem ), nCount);
+ break;
+ case ifCOUNT2:
+ case ifCOUNT:
+ fRes = nCount;
+ break;
+ case ifPRODUCT:
+ if ( !nCount )
+ fRes = 0.0;
+ break;
+ default:
+ ; // nothing
+ }
+ return fRes;
+}
+
void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
{
short nParamCount = GetByte();
+ SCSIZE nMatRows = 0;
+ if (bMatrixFormula || pCur->IsInForceArray())
+ {
+ // Check for arrays of references to determine the maximum size of a
+ // return column vector.
+ for (short i=1; i <= nParamCount; ++i)
+ {
+ if (GetStackType(i) == svRefList)
+ {
+ const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
+ if (p && p->IsArrayResult() && p->GetRefList()->size() > nMatRows)
+ nMatRows = p->GetRefList()->size();
+ }
+ }
+ }
+ ScMatrixRef xResMat, xResCount;
double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
double fVal = 0.0;
double fMem = 0.0; // first numeric value != 0.0
@@ -469,6 +509,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
ScAddress aAdr;
ScRange aRange;
size_t nRefInList = 0;
+ size_t nRefArrayPos = std::numeric_limits<size_t>::max();
if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
nGlobalError = FormulaError::NONE;
@@ -678,9 +719,55 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
}
}
break;
- case svDoubleRef :
case svRefList :
{
+ const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+ if (p && p->IsArrayResult())
+ {
+ nRefArrayPos = nRefInList;
+ if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
+ {
+ fRes = rtl::math::approxAdd( fRes, fMem);
+ fMem = 0.0;
+ }
+ // The "one value to all references of an array" seems to
+ // be what Excel does if there are other types than just
+ // arrays of references.
+ if (!xResMat)
+ {
+ // Create and init all elements with current value.
+ assert(nMatRows > 0);
+ xResMat = GetNewMat( 1, nMatRows, true);
+ xResMat->FillDouble( fRes, 0,0, 0,nMatRows-1);
+ if (eFunc != ifSUM)
+ {
+ xResCount = GetNewMat( 1, nMatRows, true);
+ xResCount->FillDouble( nCount, 0,0, 0,nMatRows-1);
+ }
+ }
+ else
+ {
+ // Current value and values from vector are operands
+ // for each vector position.
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ if (xResCount)
+ xResCount->PutDouble( xResCount->GetDouble(0,i) + nCount, 0,i);
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (eFunc == ifPRODUCT)
+ fVecRes *= fRes;
+ else
+ fVecRes += fRes;
+ xResMat->PutDouble( fVecRes, 0,i);
+ }
+ }
+ fRes = ((eFunc == ifPRODUCT) ? 1.0 : 0.0);
+ nCount = 0;
+ }
+ }
+ SAL_FALLTHROUGH;
+ case svDoubleRef :
+ {
PopDoubleRef( aRange, nParamCount, nRefInList);
if (nGlobalError == FormulaError::NoRef)
{
@@ -835,6 +922,27 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
SetError( nErr );
}
}
+ if (nRefArrayPos != std::numeric_limits<size_t>::max())
+ {
+ // Update vector element with current value.
+ if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
+ {
+ fRes = rtl::math::approxAdd( fRes, fMem);
+ fMem = 0.0;
+ }
+ if (xResCount)
+ xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos);
+ double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
+ if (eFunc == ifPRODUCT)
+ fVecRes *= fRes;
+ else
+ fVecRes += fRes;
+ xResMat->PutDouble( fVecRes, 0,nRefArrayPos);
+ // Reset.
+ fRes = ((eFunc == ifPRODUCT) ? 1.0 : 0.0);
+ nCount = 0;
+ nRefArrayPos = std::numeric_limits<size_t>::max();
+ }
}
break;
case svExternalDoubleRef:
@@ -874,21 +982,33 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
SetError(FormulaError::IllegalParameter);
}
}
- switch( eFunc )
- {
- case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
- case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
- case ifCOUNT2:
- case ifCOUNT: fRes = nCount; break;
- case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
- default: ; // nothing
- }
+
// A boolean return type makes no sense on sums et al.
// Counts are always numbers.
if( nFuncFmtType == css::util::NumberFormat::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 )
nFuncFmtType = css::util::NumberFormat::NUMBER;
- PushDouble( fRes);
+ if (xResMat)
+ {
+ // Include value of last non-references-array type and calculate final result.
+ for (SCSIZE i=0; i < nMatRows; ++i)
+ {
+ if (xResCount)
+ nCount += xResCount->GetDouble(0,i);
+ double fVecRes = xResMat->GetDouble(0,i);
+ if (eFunc == ifPRODUCT)
+ fVecRes *= fRes;
+ else
+ fVecRes += fRes;
+ fVecRes = lcl_IterResult( eFunc, fVecRes, fMem, nCount);
+ xResMat->PutDouble( fVecRes, 0,i);
+ }
+ PushMatrix( xResMat);
+ }
+ else
+ {
+ PushDouble( lcl_IterResult( eFunc, fRes, fMem, nCount));
+ }
}
void ScInterpreter::ScSumSQ()
commit f6703ce85f9399b94958601ed6623865b205c5fb
Author: Eike Rathke <erack at redhat.com>
Date: Fri May 19 22:48:24 2017 +0200
Change IterateParameters to push token instead of returning double, tdf#58874
Change-Id: Ib256d99126116379b27fc246dedf0fac2efb8c02
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 902fde9e1376..9ddf9e2c1900 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -568,7 +568,7 @@ void ScUnicode();
void ScUnichar();
void ScMin( bool bTextAsZero = false );
void ScMax( bool bTextAsZero = false );
-double IterateParameters( ScIterFunc, bool bTextAsZero = false );
+void IterateParameters( ScIterFunc, bool bTextAsZero = false );
void ScSumSQ();
void ScSum();
void ScProduct();
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 31448ee48f6e..72c82e9474a7 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -459,7 +459,7 @@ void IterateMatrix(
}
}
-double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
+void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
{
short nParamCount = GetByte();
double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
@@ -614,7 +614,10 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
{
PopSingleRef( aAdr );
if (nGlobalError == FormulaError::NoRef)
- return 0.0;
+ {
+ PushError( FormulaError::NoRef);
+ return;
+ }
if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
@@ -680,7 +683,10 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
{
PopDoubleRef( aRange, nParamCount, nRefInList);
if (nGlobalError == FormulaError::NoRef)
- return 0.0;
+ {
+ PushError( FormulaError::NoRef);
+ return;
+ }
if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
@@ -717,8 +723,8 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
FormulaError nErr = aAction.getError();
if ( nErr != FormulaError::NONE )
{
- SetError( nErr );
- return fRes;
+ PushError( nErr );
+ return;
}
fRes += aAction.getSum();
@@ -881,37 +887,38 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
// Counts are always numbers.
if( nFuncFmtType == css::util::NumberFormat::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 )
nFuncFmtType = css::util::NumberFormat::NUMBER;
- return fRes;
+
+ PushDouble( fRes);
}
void ScInterpreter::ScSumSQ()
{
- PushDouble( IterateParameters( ifSUMSQ ) );
+ IterateParameters( ifSUMSQ );
}
void ScInterpreter::ScSum()
{
- PushDouble( IterateParameters( ifSUM ) );
+ IterateParameters( ifSUM );
}
void ScInterpreter::ScProduct()
{
- PushDouble( IterateParameters( ifPRODUCT ) );
+ IterateParameters( ifPRODUCT );
}
void ScInterpreter::ScAverage( bool bTextAsZero )
{
- PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
+ IterateParameters( ifAVERAGE, bTextAsZero );
}
void ScInterpreter::ScCount()
{
- PushDouble( IterateParameters( ifCOUNT ) );
+ IterateParameters( ifCOUNT );
}
void ScInterpreter::ScCount2()
{
- PushDouble( IterateParameters( ifCOUNT2 ) );
+ IterateParameters( ifCOUNT2 );
}
void ScInterpreter::ScRawSubtract()
commit c9bff2c2e64823504baa8a4b5e20a88866ba0a71
Author: Eike Rathke <erack at redhat.com>
Date: Fri May 19 22:28:37 2017 +0200
Get rid of some unneccessary formula:: namespace
Change-Id: Icd30167589b507c3f83a31dbb5c0eb473ab6580e
diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
index 8937e666c865..ea3145b3a5c0 100644
--- a/sc/source/core/tool/interpr3.cxx
+++ b/sc/source/core/tool/interpr3.cxx
@@ -2471,7 +2471,7 @@ void ScInterpreter::ScZTest()
double rValCount = 0.0;
switch (GetStackType())
{
- case formula::svDouble :
+ case svDouble :
{
fVal = GetDouble();
fSum += fVal;
@@ -2494,7 +2494,7 @@ void ScInterpreter::ScZTest()
}
break;
case svRefList :
- case formula::svDoubleRef :
+ case svDoubleRef :
{
short nParam = 1;
size_t nRefInList = 0;
@@ -2912,7 +2912,7 @@ void ScInterpreter::ScHarMean()
{
switch (GetStackType())
{
- case formula::svDouble :
+ case svDouble :
{
double x = GetDouble();
if (x > 0.0)
@@ -2941,7 +2941,7 @@ void ScInterpreter::ScHarMean()
}
break;
}
- case formula::svDoubleRef :
+ case svDoubleRef :
case svRefList :
{
FormulaError nErr = FormulaError::NONE;
@@ -3034,7 +3034,7 @@ void ScInterpreter::ScGeoMean()
{
switch (GetStackType())
{
- case formula::svDouble :
+ case svDouble :
{
double x = GetDouble();
if (x > 0.0)
@@ -3063,7 +3063,7 @@ void ScInterpreter::ScGeoMean()
}
break;
}
- case formula::svDoubleRef :
+ case svDoubleRef :
case svRefList :
{
FormulaError nErr = FormulaError::NONE;
@@ -3175,7 +3175,7 @@ bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::
{
switch (GetStackType())
{
- case formula::svDouble :
+ case svDouble :
{
fVal = GetDouble();
fSum += fVal;
@@ -3196,7 +3196,7 @@ bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::
}
}
break;
- case formula::svDoubleRef :
+ case svDoubleRef :
case svRefList :
{
PopDoubleRef( aRange, nParamCount, nRefInList);
@@ -3663,7 +3663,7 @@ void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double
const StackVar eStackType = GetStackType();
switch (eStackType)
{
- case formula::svDouble :
+ case svDouble :
rArray.push_back( PopDouble());
break;
case svSingleRef :
@@ -3674,7 +3674,7 @@ void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double
rArray.push_back(GetCellValue(aAdr, aCell));
}
break;
- case formula::svDoubleRef :
+ case svDoubleRef :
case svRefList :
{
PopDoubleRef( aRange, nParam, nRefInList);
@@ -3946,7 +3946,7 @@ void ScInterpreter::ScAveDev()
{
switch (GetStackType())
{
- case formula::svDouble :
+ case svDouble :
rVal += GetDouble();
rValCount++;
break;
@@ -3961,7 +3961,7 @@ void ScInterpreter::ScAveDev()
}
}
break;
- case formula::svDoubleRef :
+ case svDoubleRef :
case svRefList :
{
FormulaError nErr = FormulaError::NONE;
@@ -4029,7 +4029,7 @@ void ScInterpreter::ScAveDev()
{
switch (GetStackType())
{
- case formula::svDouble :
+ case svDouble :
rVal += fabs(GetDouble() - nMiddle);
break;
case svSingleRef :
@@ -4040,7 +4040,7 @@ void ScInterpreter::ScAveDev()
rVal += fabs(GetCellValue(aAdr, aCell) - nMiddle);
}
break;
- case formula::svDoubleRef :
+ case svDoubleRef :
case svRefList :
{
FormulaError nErr = FormulaError::NONE;
@@ -4278,7 +4278,7 @@ void ScInterpreter::ScRSQ()
{
switch (GetStackType())
{
- case formula::svDouble:
+ case svDouble:
{
double fVal = PopDouble();
PushDouble( fVal * fVal);
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index c42f0f4545d3..31448ee48f6e 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -564,7 +564,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
StackVar eType = pToken->GetType();
if (eFunc == ifCOUNT2)
{
- if ( eType != formula::svEmptyCell &&
+ if ( eType != svEmptyCell &&
( ( pToken->GetOpCode() != ocSubTotal &&
pToken->GetOpCode() != ocAggregate ) ||
( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) ) )
@@ -572,7 +572,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
if (nGlobalError != FormulaError::NONE)
nGlobalError = FormulaError::NONE;
}
- else if (eType == formula::svDouble)
+ else if (eType == svDouble)
{
nCount++;
fVal = pToken->GetDouble();
@@ -602,7 +602,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
default: ; // nothing
}
}
- else if (bTextAsZero && eType == formula::svString)
+ else if (bTextAsZero && eType == svString)
{
nCount++;
if ( eFunc == ifPRODUCT )
commit b45a7ed1e687f7c54f16f6ab65b85ab3d945af68
Author: Eike Rathke <erack at redhat.com>
Date: Fri May 19 22:13:28 2017 +0200
Do not force return value to double in SUBTOTAL and AGGREGATE, tdf#58874
Change-Id: I305adfb97022f353dde6aab4e234faff0fdfb904
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 3cca0b101f15..7417e54b8ca3 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -6725,9 +6725,9 @@ void ScInterpreter::ScSubTotal()
}
mnSubTotalFlags = SubtotalFlags::NONE;
// Get rid of the 1st (fished) parameter.
- double nVal = GetDouble();
+ FormulaConstTokenRef xRef( PopToken());
Pop();
- PushDouble( nVal );
+ PushTokenRef( xRef);
}
}
@@ -6806,11 +6806,11 @@ void ScInterpreter::ScAggregate()
}
mnSubTotalFlags = SubtotalFlags::NONE;
}
- double nVal = GetDouble();
+ FormulaConstTokenRef xRef( PopToken());
// Get rid of the 1st and 2nd (fished) parameters.
Pop();
Pop();
- PushDouble( nVal );
+ PushTokenRef( xRef);
}
}
commit 27caf863d4dc06dd8cc09f5e4836d40f59ee9faf
Author: Eike Rathke <erack at redhat.com>
Date: Fri May 19 22:11:15 2017 +0200
Mention validation with xmllint
Change-Id: I03af05e51084a438109c2e200faa8d5e5b4f2c74
diff --git a/i18npool/source/localedata/data/locale.dtd b/i18npool/source/localedata/data/locale.dtd
index 2898ee4bb04e..377df12b9bb8 100644
--- a/i18npool/source/localedata/data/locale.dtd
+++ b/i18npool/source/localedata/data/locale.dtd
@@ -26,15 +26,23 @@
ATTENTION! PLEASE! HEADS UP! IMPORTANT!
===========================================================================
- Please validate your locale data contribution using a validating parser. A
- validating parser, for example, may be found at
+ Please validate your locale data contribution.
+
+ A quick validation check can be done if you have xmllint installed and the
+ current locale.dtd file at hand, you can download the locale.dtd file from
+ https://cgit.freedesktop.org/libreoffice/core/plain/i18npool/source/localedata/data/locale.dtd
+
+ xmllint --dtdvalid locale.dtd --noout your_data.xml
+
+
+ Second, using a validating parser. A validating parser, for example, may be found at
http://unicode.org/cldr/data/tools/java/org/unicode/cldr/util/XMLValidator.java
Compile it into a class-jar and call it in the
i18npool/source/localedata/data/ directory:
java -cp <your_path>/XMLValidator.jar org.unicode.cldr.util.XMLValidator your_data.xml
- A second possibility is:
+ A third possibility is:
- temporarily (!) change the DOCTYPE of your file to read (all on one line)
<!DOCTYPE Locale SYSTEM "http://cgit.freedesktop.org/libreoffice/core/plain/i18npool/source/localedata/data/locale.dtd">
commit b086633566cbcc5e73add5d195ce0ab207ea8f7c
Author: Eike Rathke <erack at redhat.com>
Date: Fri May 19 21:44:17 2017 +0200
Create RefList at JumpMatrix if current function returns Reference, tdf#58874
Change-Id: I8fcdbc743c614857ee298b3d9c730ab64477dd8c
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 29f51d6326a1..3cca0b101f15 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -581,6 +581,7 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
break;
case svSingleRef:
{
+ FormulaConstTokenRef xRef = pStack[sp-1];
ScAddress aAdr;
PopSingleRef( aAdr );
if ( nGlobalError != FormulaError::NONE )
@@ -619,10 +620,21 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
pJumpMatrix->PutResultString(aStr, nC, nR);
}
}
+
+ formula::ParamClass eReturnType = ScParameterClassification::GetParameterType( pCur, SAL_MAX_UINT16);
+ if (eReturnType == ParamClass::Reference)
+ {
+ /* TODO: What about error handling and do we actually
+ * need the result matrix above at all in this case? */
+ ScComplexRefData aRef;
+ aRef.Ref1 = aRef.Ref2 = *(xRef->GetSingleRef());
+ pJumpMatrix->GetRefList().push_back( aRef);
+ }
}
break;
case svDoubleRef:
{ // upper left plus offset within matrix
+ FormulaConstTokenRef xRef = pStack[sp-1];
double fVal;
ScRange aRange;
PopDoubleRef( aRange );
@@ -690,6 +702,14 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
lcl_AdjustJumpMatrix( pJumpMatrix, nParmCols, nParmRows );
}
+
+ formula::ParamClass eReturnType = ScParameterClassification::GetParameterType( pCur, SAL_MAX_UINT16);
+ if (eReturnType == ParamClass::Reference)
+ {
+ /* TODO: What about error handling and do we actually
+ * need the result matrix above at all in this case? */
+ pJumpMatrix->GetRefList().push_back( *(xRef->GetDoubleRef()));
+ }
}
break;
case svMatrix:
@@ -780,17 +800,33 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
}
if ( !bCont )
{ // we're done with it, throw away jump matrix, keep result
- ScMatrix* pResMat = pJumpMatrix->GetResultMatrix();
- pJumpMatrix = nullptr;
- Pop();
- PushMatrix( pResMat );
- // Remove jump matrix from map and remember result matrix in case it
- // could be reused in another path of the same condition.
- if (pTokenMatrixMap)
- {
- pTokenMatrixMap->erase( pCur);
- pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
- pStack[sp-1]));
+ formula::ParamClass eReturnType = ScParameterClassification::GetParameterType( pCur, SAL_MAX_UINT16);
+ if (eReturnType == ParamClass::Reference)
+ {
+ FormulaTokenRef xRef = new ScRefListToken(true);
+ *(xRef->GetRefList()) = pJumpMatrix->GetRefList();
+ pJumpMatrix = nullptr;
+ Pop();
+ PushTokenRef( xRef);
+ if (pTokenMatrixMap)
+ {
+ pTokenMatrixMap->erase( pCur);
+ // There's no result matrix to remember in this case.
+ }
+ }
+ else
+ {
+ ScMatrix* pResMat = pJumpMatrix->GetResultMatrix();
+ pJumpMatrix = nullptr;
+ Pop();
+ PushMatrix( pResMat );
+ // Remove jump matrix from map and remember result matrix in case it
+ // could be reused in another path of the same condition.
+ if (pTokenMatrixMap)
+ {
+ pTokenMatrixMap->erase( pCur);
+ pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur, pStack[sp-1]));
+ }
}
return true;
}
commit 3a3064fcb4778b050398d98598d6ed61e8298134
Author: Eike Rathke <erack at redhat.com>
Date: Fri May 19 20:21:03 2017 +0200
Introduce ScRefListToken::mbArrayResult for reference results, tdf#58874
Change-Id: Icd077a82ab0c951667a6566d5c5d47084c46d20d
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index 7c082010ea93..8d561af85760 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -265,11 +265,15 @@ class ScRefListToken : public formula::FormulaToken
{
private:
ScRefList aRefList;
+ bool mbArrayResult; // whether RefList is an array result
public:
ScRefListToken() :
- FormulaToken( formula::svRefList ) {}
+ FormulaToken( formula::svRefList ), mbArrayResult(false) {}
+ explicit ScRefListToken( bool bArrayResult ) :
+ FormulaToken( formula::svRefList ), mbArrayResult( bArrayResult ) {}
ScRefListToken( const ScRefListToken & r ) :
- FormulaToken( r ), aRefList( r.aRefList ) {}
+ FormulaToken( r ), aRefList( r.aRefList ), mbArrayResult( r.mbArrayResult ) {}
+ bool IsArrayResult() const;
virtual const ScRefList* GetRefList() const override;
virtual ScRefList* GetRefList() override;
virtual bool operator==( const formula::FormulaToken& rToken ) const override;
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 512fecc7f83f..ea2060d8c7a2 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -683,9 +683,12 @@ bool ScDoubleRefToken::operator==( const FormulaToken& r ) const
const ScRefList* ScRefListToken::GetRefList() const { return &aRefList; }
ScRefList* ScRefListToken::GetRefList() { return &aRefList; }
+ bool ScRefListToken::IsArrayResult() const { return mbArrayResult; }
bool ScRefListToken::operator==( const FormulaToken& r ) const
{
- return FormulaToken::operator==( r ) && &aRefList == r.GetRefList();
+ const ScRefListToken* p;
+ return FormulaToken::operator==( r ) && &aRefList == r.GetRefList() &&
+ ((p = dynamic_cast<const ScRefListToken*>(&r)) != nullptr) && mbArrayResult == p->IsArrayResult();
}
ScMatrixToken::ScMatrixToken( const ScMatrixRef& p ) :
commit 6a569fd47e3665b0aaec397ace0346938bb3b4bf
Author: Eike Rathke <erack at redhat.com>
Date: Fri May 19 19:20:27 2017 +0200
Introduce ScJumpMatrix::mvRefList for array of reference results, tdf#58874
Change-Id: I478ddbcd951b386b8d4cbb38059b904af7c79703
diff --git a/sc/source/core/inc/jumpmatrix.hxx b/sc/source/core/inc/jumpmatrix.hxx
index 94b8dc1737aa..1c61b330108d 100644
--- a/sc/source/core/inc/jumpmatrix.hxx
+++ b/sc/source/core/inc/jumpmatrix.hxx
@@ -26,6 +26,7 @@
#include <vector>
#include "types.hxx"
#include "address.hxx"
+#include "token.hxx"
typedef ::std::vector< const formula::FormulaToken*> ScTokenVec;
@@ -58,6 +59,7 @@ class ScJumpMatrix
{
std::vector<ScJumpMatrixEntry> mvJump; // the jumps
ScMatrixRef pMat; // the results
+ ScRefList mvRefList; // array of references result, if any
ScTokenVec* pParams; // parameter stack
SCSIZE nCols;
SCSIZE nRows;
@@ -108,6 +110,7 @@ public:
bool Next( SCSIZE& rCol, SCSIZE& rRow );
void GetResMatDimensions( SCSIZE& rCols, SCSIZE& rRows );
void SetNewResMat( SCSIZE nNewCols, SCSIZE nNewRows );
+ ScRefList& GetRefList();
void PutResultDouble( double fVal, SCSIZE nC, SCSIZE nR );
void PutResultString( const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR );
diff --git a/sc/source/core/tool/jumpmatrix.cxx b/sc/source/core/tool/jumpmatrix.cxx
index 760f89735db6..cc7455f42a5d 100644
--- a/sc/source/core/tool/jumpmatrix.cxx
+++ b/sc/source/core/tool/jumpmatrix.cxx
@@ -176,6 +176,11 @@ bool ScJumpMatrix::HasResultMatrix() const
return pMat.get() != nullptr;
}
+ScRefList& ScJumpMatrix::GetRefList()
+{
+ return mvRefList;
+}
+
void ScJumpMatrix::FlushBufferOtherThan( ScJumpMatrix::BufferType eType, SCSIZE nC, SCSIZE nR )
{
if (!mvBufferDoubles.empty() &&
More information about the Libreoffice-commits
mailing list