Kaydet (Commit) 426708e7 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Reduce branching in CompareMatrix(). This makes a big difference.

Change-Id: I391e889a50864ae002e85d636b767d7c6f187a23
üst 013abfd2
......@@ -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 );
}
......
......@@ -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: */
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment