summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2014-12-22 21:14:11 +0100
committerEike Rathke <erack@redhat.com>2014-12-22 21:17:18 +0100
commit069698de192ef7e8d3582398e4542c175cabb987 (patch)
treee8b1b45c7ae1828ae05ee18c35b2f0ff27cbb453
parent7bdf445a5a6932615d20b44e15df046dbec665e6 (diff)
fdo#85258 differentiate between empty cell and empty result in matrix
Change-Id: I79259224e411f9c1a6e852623d9d49cf89a03c27
-rw-r--r--sc/inc/scmatrix.hxx6
-rw-r--r--sc/source/core/data/column2.cxx27
-rw-r--r--sc/source/core/tool/interpr1.cxx4
-rw-r--r--sc/source/core/tool/scmatrix.cxx77
4 files changed, 93 insertions, 21 deletions
diff --git a/sc/inc/scmatrix.hxx b/sc/inc/scmatrix.hxx
index a5117bee3278..6bcd8857f1e0 100644
--- a/sc/inc/scmatrix.hxx
+++ b/sc/inc/scmatrix.hxx
@@ -278,6 +278,9 @@ public:
/** Put a column vector of empties, starting at row nR, must fit into dimensions. */
void PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
+ /** Put a column vector of empty results, starting at row nR, must fit into dimensions. */
+ void PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
+
/** Put a column vector of empty paths, starting at row nR, must fit into dimensions. */
void PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
@@ -322,6 +325,9 @@ public:
/// @return <TRUE/> if empty or empty path.
bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;
+ /// @return <TRUE/> if empty, not empty result or empty path.
+ bool IsEmptyCell( SCSIZE nC, SCSIZE nR ) const;
+
/// @return <TRUE/> if empty path.
bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const;
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index c2068671ed01..9b0b5efb358d 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2066,16 +2066,23 @@ namespace {
struct CellBucket
{
+ SCSIZE mnEmpValStart;
SCSIZE mnNumValStart;
SCSIZE mnStrValStart;
+ SCSIZE mnEmpValCount;
std::vector<double> maNumVals;
std::vector<svl::SharedString> maStrVals;
- CellBucket() : mnNumValStart(0), mnStrValStart(0) {}
+ CellBucket() : mnEmpValStart(0), mnNumValStart(0), mnStrValStart(0), mnEmpValCount(0) {}
void flush(ScMatrix& rMat, SCSIZE nCol)
{
- if (!maNumVals.empty())
+ if (mnEmpValCount)
+ {
+ rMat.PutEmptyResultVector(mnEmpValCount, nCol, mnEmpValStart);
+ reset();
+ }
+ else if (!maNumVals.empty())
{
const double* p = &maNumVals[0];
rMat.PutDouble(p, maNumVals.size(), nCol, mnNumValStart);
@@ -2091,7 +2098,8 @@ struct CellBucket
void reset()
{
- mnNumValStart = mnStrValStart = 0;
+ mnEmpValStart = mnNumValStart = mnStrValStart = 0;
+ mnEmpValCount = 0;
maNumVals.clear();
maStrVals.clear();
}
@@ -2163,7 +2171,18 @@ public:
if (rCell.IsEmpty())
{
- aBucket.flush(mrMat, mnMatCol);
+ if (aBucket.mnEmpValCount && nThisRow == nPrevRow + 1)
+ {
+ // Secondary empty results.
+ ++aBucket.mnEmpValCount;
+ }
+ else
+ {
+ // First empty result.
+ aBucket.flush(mrMat, mnMatCol);
+ aBucket.mnEmpValStart = nThisRow - mnTopRow;
+ ++aBucket.mnEmpValCount;
+ }
continue;
}
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 252d38d0e312..326987ecb926 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -1849,14 +1849,14 @@ void ScInterpreter::ScIsEmpty()
if ( !pMat )
; // nothing
else if ( !pJumpMatrix )
- nRes = pMat->IsEmpty( 0, 0) ? 1 : 0;
+ nRes = pMat->IsEmptyCell( 0, 0) ? 1 : 0;
else
{
SCSIZE nCols, nRows, nC, nR;
pMat->GetDimensions( nCols, nRows);
pJumpMatrix->GetPos( nC, nR);
if ( nC < nCols && nR < nRows )
- nRes = pMat->IsEmpty( nC, nR) ? 1 : 0;
+ nRes = pMat->IsEmptyCell( nC, nR) ? 1 : 0;
// else: false, not empty (which is what Xcl does)
}
}
diff --git a/sc/source/core/tool/scmatrix.cxx b/sc/source/core/tool/scmatrix.cxx
index c352ecb34ff9..af573846d1c3 100644
--- a/sc/source/core/tool/scmatrix.cxx
+++ b/sc/source/core/tool/scmatrix.cxx
@@ -194,6 +194,13 @@ _Comp CompareMatrixElemFunc<_Comp>::maComp;
}
+/* TODO: it would be good if mdds had get/set<sal_uInt8> additionally to
+ * get/set<bool>, we're abusing double here. */
+typedef double TMatFlag;
+const TMatFlag SC_MATFLAG_EMPTYCELL = 0.0;
+const TMatFlag SC_MATFLAG_EMPTYRESULT = 1.0;
+const TMatFlag SC_MATFLAG_EMPTYPATH = 2.0;
+
class ScMatrixImpl: private boost::noncopyable
{
MatrixImplType maMat;
@@ -246,6 +253,7 @@ public:
bool IsString( SCSIZE nIndex ) const;
bool IsString( SCSIZE nC, SCSIZE nR ) const;
bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;
+ bool IsEmptyCell( SCSIZE nC, SCSIZE nR ) const;
bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const;
bool IsValue( SCSIZE nIndex ) const;
bool IsValue( SCSIZE nC, SCSIZE nR ) const;
@@ -259,6 +267,7 @@ public:
void PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR );
void PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR );
void PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
+ void PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
void PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
void CompareEqual();
void CompareNotEqual();
@@ -298,7 +307,7 @@ private:
};
ScMatrixImpl::ScMatrixImpl(SCSIZE nC, SCSIZE nR) :
- maMat(nR, nC), maMatFlag(nR, nC), pErrorInterpreter(NULL), mbCloneIfConst(true) {}
+ maMat(nR, nC), maMatFlag(nR, nC, SC_MATFLAG_EMPTYCELL), pErrorInterpreter(NULL), mbCloneIfConst(true) {}
ScMatrixImpl::ScMatrixImpl(SCSIZE nC, SCSIZE nR, double fInitVal) :
maMat(nR, nC, fInitVal), maMatFlag(nR, nC), pErrorInterpreter(NULL), mbCloneIfConst(true) {}
@@ -452,7 +461,7 @@ void ScMatrixImpl::PutEmpty(SCSIZE nC, SCSIZE nR)
if (ValidColRow( nC, nR))
{
maMat.set_empty(nR, nC);
- maMatFlag.set(nR, nC, false); // zero flag to indicate that this is 'empty', not 'empty path'.
+ maMatFlag.set(nR, nC, SC_MATFLAG_EMPTYCELL);
}
else
{
@@ -465,7 +474,7 @@ void ScMatrixImpl::PutEmptyPath(SCSIZE nC, SCSIZE nR)
if (ValidColRow( nC, nR))
{
maMat.set_empty(nR, nC);
- maMatFlag.set(nR, nC, true); // non-zero flag to indicate empty 'path'.
+ maMatFlag.set(nR, nC, SC_MATFLAG_EMPTYPATH);
}
else
{
@@ -580,7 +589,7 @@ svl::SharedString ScMatrixImpl::GetString( SvNumberFormatter& rFormatter, SCSIZE
return maMat.get_string(aPos).getString();
case mdds::mtm::element_empty:
{
- if (!maMatFlag.get<bool>(nR, nC))
+ if (maMatFlag.get<TMatFlag>(nR, nC) != SC_MATFLAG_EMPTYPATH)
// not an empty path.
return svl::SharedString::getEmptyString();
@@ -636,8 +645,10 @@ ScMatrixValue ScMatrixImpl::Get(SCSIZE nC, SCSIZE nR) const
aVal.aStr = maMat.get_string(aPos);
break;
case mdds::mtm::element_empty:
- // Empty path equals empty plus flag.
- aVal.nType = maMatFlag.get<bool>(nR, nC) ? SC_MATVAL_EMPTYPATH : SC_MATVAL_EMPTY;
+ /* TODO: do we need to pass the differentiation of 'empty' and
+ * 'empty result' to the outer world anywhere? */
+ aVal.nType = maMatFlag.get<TMatFlag>(nR, nC) == SC_MATFLAG_EMPTYPATH ? SC_MATVAL_EMPTYPATH :
+ SC_MATVAL_EMPTY;
aVal.fVal = 0.0;
default:
;
@@ -673,17 +684,28 @@ bool ScMatrixImpl::IsString( SCSIZE nC, SCSIZE nR ) const
bool ScMatrixImpl::IsEmpty( SCSIZE nC, SCSIZE nR ) const
{
- // Flag must be zero for this to be an empty element, instead of being an
- // empty path element.
+ // Flag must indicate an empty element instead of an
+ // 'empty path' element.
+ ValidColRowReplicated( nC, nR );
+ return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
+ maMatFlag.get<TMatFlag>(nR, nC) != SC_MATFLAG_EMPTYPATH;
+}
+
+bool ScMatrixImpl::IsEmptyCell( SCSIZE nC, SCSIZE nR ) const
+{
+ // Flag must indicate an 'empty' element instead of an
+ // 'empty result' or 'empty path' element.
ValidColRowReplicated( nC, nR );
- return maMat.get_type(nR, nC) == mdds::mtm::element_empty && !maMatFlag.get<bool>(nR, nC);
+ return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
+ maMatFlag.get<TMatFlag>(nR, nC) == SC_MATFLAG_EMPTYCELL;
}
bool ScMatrixImpl::IsEmptyPath( SCSIZE nC, SCSIZE nR ) const
{
- // 'Empty path' is empty plus non-zero flag.
+ // Flag must indicate an 'empty path' element.
if (ValidColRowOrReplicated( nC, nR ))
- return maMat.get_type(nR, nC) == mdds::mtm::element_empty && maMatFlag.get<bool>(nR, nC);
+ return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
+ maMatFlag.get<TMatFlag>(nR, nC) == SC_MATFLAG_EMPTYPATH;
else
return true;
}
@@ -799,8 +821,8 @@ void ScMatrixImpl::PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
{
maMat.set_empty(nR, nC, nCount);
- // zero flag to indicate that this is 'empty', not 'empty path'.
- std::vector<bool> aVals(nCount, false);
+ // Flag to indicate that this is 'empty', not 'empty result' or 'empty path'.
+ std::vector<TMatFlag> aVals(nCount, SC_MATFLAG_EMPTYCELL);
maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
}
else
@@ -809,13 +831,28 @@ void ScMatrixImpl::PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
}
}
+void ScMatrixImpl::PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
+{
+ if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
+ {
+ maMat.set_empty(nR, nC, nCount);
+ // Flag to indicate that this is 'empty result', not 'empty' or 'empty path'.
+ std::vector<TMatFlag> aVals(nCount, SC_MATFLAG_EMPTYRESULT);
+ maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
+ }
+ else
+ {
+ OSL_FAIL("ScMatrixImpl::PutEmptyResultVector: dimension error");
+ }
+}
+
void ScMatrixImpl::PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
{
if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
{
maMat.set_empty(nR, nC, nCount);
- // non-zero flag to indicate empty 'path'.
- std::vector<bool> aVals(nCount, true);
+ // Flag to indicate 'empty path'.
+ std::vector<TMatFlag> aVals(nCount, SC_MATFLAG_EMPTYPATH);
maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
}
else
@@ -2281,6 +2318,11 @@ bool ScMatrix::IsEmpty( SCSIZE nC, SCSIZE nR ) const
return pImpl->IsEmpty(nC, nR);
}
+bool ScMatrix::IsEmptyCell( SCSIZE nC, SCSIZE nR ) const
+{
+ return pImpl->IsEmptyCell(nC, nR);
+}
+
bool ScMatrix::IsEmptyPath( SCSIZE nC, SCSIZE nR ) const
{
return pImpl->IsEmptyPath(nC, nR);
@@ -2341,6 +2383,11 @@ void ScMatrix::PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
pImpl->PutEmptyVector(nCount, nC, nR);
}
+void ScMatrix::PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
+{
+ pImpl->PutEmptyResultVector(nCount, nC, nR);
+}
+
void ScMatrix::PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
{
pImpl->PutEmptyPathVector(nCount, nC, nR);