summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2013-10-20 13:14:55 -0400
committerKohei Yoshida <kohei.yoshida@collabora.com>2013-10-20 13:44:43 -0400
commit426708e70807e052aca2ec16314c103b1d2a0439 (patch)
treea39b1475913c7d21cb330333cb26668fcf7983b9
parent013abfd29b125f8a049691c064bdae1db4d5880f (diff)
Reduce branching in CompareMatrix(). This makes a big difference.
Change-Id: I391e889a50864ae002e85d636b767d7c6f187a23
-rw-r--r--sc/inc/compare.hxx3
-rw-r--r--sc/source/core/tool/compare.cxx149
-rw-r--r--sc/source/core/tool/scmatrix.cxx161
3 files changed, 288 insertions, 25 deletions
diff --git a/sc/inc/compare.hxx b/sc/inc/compare.hxx
index f428d9057f46..5f9e1585ca28 100644
--- a/sc/inc/compare.hxx
+++ b/sc/inc/compare.hxx
@@ -66,6 +66,9 @@ private:
NULL means case sensitivity document option is to be used!
*/
double CompareFunc( const Compare::Cell& rCell1, const Compare::Cell& rCell2, bool bIgnoreCase, CompareOptions* pOptions = NULL );
+double CompareFunc( double fCell1, const Compare::Cell& rCell2, CompareOptions* pOptions = NULL );
+double CompareFunc( const Compare::Cell& rCell1, double fCell2, CompareOptions* pOptions = NULL );
+double CompareFunc( double fCell1, double fCell2 );
}
diff --git a/sc/source/core/tool/compare.cxx b/sc/source/core/tool/compare.cxx
index d935d51db472..a876fb1686c4 100644
--- a/sc/source/core/tool/compare.cxx
+++ b/sc/source/core/tool/compare.cxx
@@ -208,6 +208,155 @@ double CompareFunc( const Compare::Cell& rCell1, const Compare::Cell& rCell2, bo
return fRes;
}
+double CompareFunc( double fCell1, const Compare::Cell& rCell2, CompareOptions* pOptions )
+{
+ // Keep DoubleError if encountered
+ // #i40539# if bEmpty is set, bVal/nVal are uninitialized
+ if (!rtl::math::isFinite(fCell1))
+ return fCell1;
+ if (!rCell2.mbEmpty && rCell2.mbValue && !rtl::math::isFinite(rCell2.mfValue))
+ return rCell2.mfValue;
+
+ bool bStringQuery = false;
+ double fRes = 0;
+ if (rCell2.mbEmpty)
+ {
+ if (fCell1 != 0.0)
+ {
+ if (fCell1 < 0.0)
+ fRes = -1; // -x < empty cell
+ else
+ fRes = 1; // x > empty cell
+ }
+ // else: empty cell == 0.0
+ }
+ else
+ {
+ if (rCell2.mbValue)
+ {
+ if (!rtl::math::approxEqual(fCell1, rCell2.mfValue))
+ {
+ if (fCell1 - rCell2.mfValue < 0)
+ fRes = -1;
+ else
+ fRes = 1;
+ }
+ }
+ else
+ {
+ fRes = -1; // number is less than string
+ bStringQuery = true;
+ }
+ }
+
+ if (bStringQuery && pOptions)
+ {
+ const ScQueryEntry& rEntry = pOptions->aQueryEntry;
+ const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ if (!rItems.empty())
+ {
+ const ScQueryEntry::Item& rItem = rItems[0];
+ if (rItem.meType != ScQueryEntry::ByString && !rItem.maString.isEmpty() &&
+ (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL))
+ {
+ // As in ScTable::ValidQuery() match a numeric string for a
+ // number query that originated from a string, e.g. in SUMIF
+ // and COUNTIF. Transliteration is not needed here.
+ bool bEqual = rCell2.maStr == rItem.maString;
+
+ // match => fRes=0, else fRes=1
+ fRes = (rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual;
+ }
+ }
+ }
+
+ return fRes;
+}
+
+double CompareFunc( const Compare::Cell& rCell1, double fCell2, CompareOptions* pOptions )
+{
+ // Keep DoubleError if encountered
+ // #i40539# if bEmpty is set, bVal/nVal are uninitialized
+ if (!rCell1.mbEmpty && rCell1.mbValue && !rtl::math::isFinite(rCell1.mfValue))
+ return rCell1.mfValue;
+ if (!rtl::math::isFinite(fCell2))
+ return fCell2;
+
+ bool bStringQuery = false;
+ double fRes = 0;
+ if (rCell1.mbEmpty)
+ {
+ if (fCell2 != 0.0)
+ {
+ if (fCell2 < 0.0)
+ fRes = 1; // empty cell > -x
+ else
+ fRes = -1; // empty cell < x
+ }
+ // else: empty cell == 0.0
+ }
+ else if (rCell1.mbValue)
+ {
+ if (!rtl::math::approxEqual(rCell1.mfValue, fCell2))
+ {
+ if (rCell1.mfValue - fCell2 < 0)
+ fRes = -1;
+ else
+ fRes = 1;
+ }
+ }
+ else
+ {
+ fRes = 1; // string is greater than number
+ bStringQuery = true;
+ }
+
+ if (bStringQuery && pOptions)
+ {
+ const ScQueryEntry& rEntry = pOptions->aQueryEntry;
+ const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ if (!rItems.empty())
+ {
+ const ScQueryEntry::Item& rItem = rItems[0];
+ if (rItem.meType != ScQueryEntry::ByString && !rItem.maString.isEmpty() &&
+ (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL))
+ {
+ // As in ScTable::ValidQuery() match a numeric string for a
+ // number query that originated from a string, e.g. in SUMIF
+ // and COUNTIF. Transliteration is not needed here.
+ bool bEqual = rCell1.maStr == rItem.maString;
+
+ // match => fRes=0, else fRes=1
+ fRes = (rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual;
+ }
+ }
+ }
+
+ return fRes;
+}
+
+double CompareFunc( double fCell1, double fCell2 )
+{
+ // Keep DoubleError if encountered
+ // #i40539# if bEmpty is set, bVal/nVal are uninitialized
+ if (!rtl::math::isFinite(fCell1))
+ return fCell1;
+ if (!rtl::math::isFinite(fCell2))
+ return fCell2;
+
+ double fRes = 0.0;
+
+ if (!rtl::math::approxEqual(fCell1, fCell2))
+ {
+ if (fCell1 - fCell2 < 0.0)
+ fRes = -1;
+ else
+ fRes = 1;
+ }
+
+ return fRes;
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/scmatrix.cxx b/sc/source/core/tool/scmatrix.cxx
index 89730bd4a01e..a195a4ff8087 100644
--- a/sc/source/core/tool/scmatrix.cxx
+++ b/sc/source/core/tool/scmatrix.cxx
@@ -1218,6 +1218,34 @@ public:
}
};
+inline bool evaluate( double fVal, ScQueryOp eOp )
+{
+ switch (eOp)
+ {
+ case SC_EQUAL:
+ return fVal == 0.0;
+ case SC_LESS:
+ return fVal < 0.0;
+ case SC_GREATER:
+ return fVal > 0.0;
+ break;
+ case SC_LESS_EQUAL:
+ return fVal <= 0.0;
+ break;
+ case SC_GREATER_EQUAL:
+ return fVal >= 0.0;
+ break;
+ case SC_NOT_EQUAL:
+ return fVal != 0.0;
+ break;
+ default:
+ ;
+ }
+
+ OSL_TRACE( "evaluate: unhandled comparison operator: %d", (int)eOp);
+ return false;
+}
+
class CompareMatrixFunc : std::unary_function<MatrixImplType::element_block_type, void>
{
sc::Compare& mrComp;
@@ -1228,31 +1256,7 @@ class CompareMatrixFunc : std::unary_function<MatrixImplType::element_block_type
void compare()
{
double fVal = sc::CompareFunc(mrComp.maCells[0], mrComp.maCells[1], mrComp.mbIgnoreCase, mpOptions);
- bool bRes = false;
- switch (mrComp.meOp)
- {
- case SC_EQUAL:
- bRes = fVal == 0.0;
- break;
- case SC_LESS:
- bRes = fVal < 0.0;
- break;
- case SC_GREATER:
- bRes = fVal > 0.0;
- break;
- case SC_LESS_EQUAL:
- bRes = fVal <= 0.0;
- break;
- case SC_GREATER_EQUAL:
- bRes = fVal >= 0.0;
- break;
- case SC_NOT_EQUAL:
- bRes = fVal != 0.0;
- break;
- default:
- OSL_TRACE( "CompareMatrixFunc: unhandled comparison operator: %d", (int)mrComp.meOp);
- }
- maResValues.push_back(bRes);
+ maResValues.push_back(evaluate(fVal, mrComp.meOp));
}
public:
@@ -1333,6 +1337,96 @@ public:
}
};
+/**
+ * Left-hand side is a matrix while the right-hand side is a numeric value.
+ */
+class CompareMatrixToNumericFunc : std::unary_function<MatrixImplType::element_block_type, void>
+{
+ sc::Compare& mrComp;
+ double mfRightValue;
+ sc::CompareOptions* mpOptions;
+ std::vector<bool> maResValues;
+
+ void compare()
+ {
+ double fVal = sc::CompareFunc(mrComp.maCells[0], mfRightValue, mpOptions);
+ maResValues.push_back(evaluate(fVal, mrComp.meOp));
+ }
+
+ void compareLeftNumeric( double fLeftVal )
+ {
+ double fVal = sc::CompareFunc(fLeftVal, mfRightValue);
+ maResValues.push_back(evaluate(fVal, mrComp.meOp));
+ }
+
+public:
+ CompareMatrixToNumericFunc( size_t nResSize, sc::Compare& rComp, double fRightValue, sc::CompareOptions* pOptions ) :
+ mrComp(rComp), mfRightValue(fRightValue), mpOptions(pOptions)
+ {
+ maResValues.reserve(nResSize);
+ }
+
+ void operator() (const MatrixImplType::element_block_node_type& node)
+ {
+ sc::Compare::Cell& rCell = mrComp.maCells[0];
+
+ switch (node.type)
+ {
+ case mdds::mtm::element_numeric:
+ {
+ typedef MatrixImplType::numeric_block_type block_type;
+
+ block_type::const_iterator it = block_type::begin(*node.data);
+ block_type::const_iterator itEnd = block_type::end(*node.data);
+ for (; it != itEnd; ++it)
+ compareLeftNumeric(*it);
+ }
+ break;
+ case mdds::mtm::element_boolean:
+ {
+ typedef MatrixImplType::boolean_block_type block_type;
+
+ block_type::const_iterator it = block_type::begin(*node.data);
+ block_type::const_iterator itEnd = block_type::end(*node.data);
+ for (; it != itEnd; ++it)
+ compareLeftNumeric(*it);
+ }
+ break;
+ case mdds::mtm::element_string:
+ {
+ typedef MatrixImplType::string_block_type block_type;
+
+ block_type::const_iterator it = block_type::begin(*node.data);
+ block_type::const_iterator itEnd = block_type::end(*node.data);
+ for (; it != itEnd; ++it)
+ {
+ const svl::SharedString& rStr = *it;
+ rCell.mbValue = false;
+ rCell.mbEmpty = false;
+ rCell.maStr = rStr;
+ compare();
+ }
+ }
+ break;
+ case mdds::mtm::element_empty:
+ {
+ rCell.mbValue = false;
+ rCell.mbEmpty = true;
+ rCell.maStr = svl::SharedString::getEmptyString();
+ for (size_t i = 0; i < node.size; ++i)
+ compare();
+ }
+ default:
+ ;
+ }
+ }
+
+ const std::vector<bool>& getValues() const
+ {
+ return maResValues;
+ }
+};
+
class ToDoubleArray : std::unary_function<MatrixImplType::element_block_type, void>
{
std::vector<double> maArray;
@@ -1529,6 +1623,23 @@ ScMatrixRef ScMatrixImpl::CompareMatrix(
{
MatrixImplType::size_pair_type aSize = maMat.size();
size_t nSize = aSize.column * aSize.row;
+ if (nMatPos == 0)
+ {
+ if (rComp.maCells[1].mbValue && !rComp.maCells[1].mbEmpty)
+ {
+ // Matrix on the left, and a numeric value on the right.
+ CompareMatrixToNumericFunc aFunc(nSize, rComp, rComp.maCells[1].mfValue, pOptions);
+ maMat.walk(aFunc);
+
+ // We assume the result matrix has the same dimension as this matrix.
+ const std::vector<bool>& rResVal = aFunc.getValues();
+ if (nSize != rResVal.size())
+ ScMatrixRef();
+
+ return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
+ }
+ }
+
CompareMatrixFunc aFunc(nSize, rComp, nMatPos, pOptions);
maMat.walk(aFunc);