diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2013-10-20 13:14:55 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@collabora.com> | 2013-10-20 13:44:43 -0400 |
commit | 426708e70807e052aca2ec16314c103b1d2a0439 (patch) | |
tree | a39b1475913c7d21cb330333cb26668fcf7983b9 | |
parent | 013abfd29b125f8a049691c064bdae1db4d5880f (diff) |
Reduce branching in CompareMatrix(). This makes a big difference.
Change-Id: I391e889a50864ae002e85d636b767d7c6f187a23
-rw-r--r-- | sc/inc/compare.hxx | 3 | ||||
-rw-r--r-- | sc/source/core/tool/compare.cxx | 149 | ||||
-rw-r--r-- | sc/source/core/tool/scmatrix.cxx | 161 |
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); |