fdo#85258 differentiate between empty cell and empty result in matrix
Change-Id: I79259224e411f9c1a6e852623d9d49cf89a03c27
diff --git a/sc/inc/scmatrix.hxx b/sc/inc/scmatrix.hxx
index a5117be..6bcd8857 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 c206867..9b0b5ef 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 252d38d..326987e 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 c352ecb..af57384 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<bool>(nR, nC);
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<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);