summaryrefslogtreecommitdiff
path: root/sc/source/core
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core')
-rw-r--r--sc/source/core/inc/interpre.hxx12
-rw-r--r--sc/source/core/tool/compare.cxx201
-rw-r--r--sc/source/core/tool/interpr1.cxx265
-rw-r--r--sc/source/core/tool/scmatrix.cxx303
4 files changed, 545 insertions, 236 deletions
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 304f8415bc6c..11adc3496e11 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -42,8 +42,6 @@ struct ScQueryParam;
struct ScDBQueryParamBase;
struct ScQueryEntry;
-struct ScCompare;
-struct ScCompareOptions;
struct ScSingleRefData;
struct ScComplexRefData;
@@ -54,6 +52,8 @@ struct ScRefCellValue;
namespace sc {
struct RangeMatrix;
+struct Compare;
+struct CompareOptions;
}
@@ -382,16 +382,12 @@ void ScChoseJump();
// Returns true if last jump was executed and result matrix pushed.
bool JumpMatrix( short nStackLevel );
-/** @param pOptions
- NULL means case sensitivity document option is to be used!
- */
-double CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions = NULL );
double Compare();
/** @param pOptions
NULL means case sensitivity document option is to be used!
*/
-sc::RangeMatrix CompareMat( ScCompareOptions* pOptions = NULL );
-ScMatrixRef QueryMat( const ScMatrixRef& pMat, ScCompareOptions& rOptions );
+sc::RangeMatrix CompareMat( sc::CompareOptions* pOptions = NULL );
+ScMatrixRef QueryMat( const ScMatrixRef& pMat, sc::CompareOptions& rOptions );
void ScEqual();
void ScNotEqual();
void ScLess();
diff --git a/sc/source/core/tool/compare.cxx b/sc/source/core/tool/compare.cxx
new file mode 100644
index 000000000000..ece2ff209008
--- /dev/null
+++ b/sc/source/core/tool/compare.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "compare.hxx"
+
+#include "document.hxx"
+#include "docoptio.hxx"
+
+#include "unotools/textsearch.hxx"
+
+namespace sc {
+
+CompareOptions::CompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) :
+ aQueryEntry(rEntry),
+ bRegEx(bReg),
+ bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell()),
+ bIgnoreCase(true)
+{
+ bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
+ // Interpreter functions usually are case insensitive, except the simple
+ // comparison operators, for which these options aren't used. Override in
+ // struct if needed.
+}
+
+/** @param pOptions
+ NULL means case sensitivity document option is to be used!
+ */
+double CompareFunc( bool bIgnoreCase, const Compare& rComp, CompareOptions* pOptions )
+{
+ // Keep DoubleError if encountered
+ // #i40539# if bEmpty is set, bVal/nVal are uninitialized
+ if ( !rComp.bEmpty[0] && rComp.bVal[0] && !::rtl::math::isFinite( rComp.nVal[0]))
+ return rComp.nVal[0];
+ if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1]))
+ return rComp.nVal[1];
+
+ size_t nStringQuery = 0; // 0:=no, 1:=0, 2:=1
+ double fRes = 0;
+ if ( rComp.bEmpty[ 0 ] )
+ {
+ if ( rComp.bEmpty[ 1 ] )
+ ; // empty cell == empty cell, fRes 0
+ else if( rComp.bVal[ 1 ] )
+ {
+ if ( !::rtl::math::approxEqual( rComp.nVal[ 1 ], 0.0 ) )
+ {
+ if ( rComp.nVal[ 1 ] < 0.0 )
+ fRes = 1; // empty cell > -x
+ else
+ fRes = -1; // empty cell < x
+ }
+ // else: empty cell == 0.0
+ }
+ else
+ {
+ if ( !rComp.pVal[ 1 ]->isEmpty() )
+ fRes = -1; // empty cell < "..."
+ // else: empty cell == ""
+ }
+ }
+ else if ( rComp.bEmpty[ 1 ] )
+ {
+ if( rComp.bVal[ 0 ] )
+ {
+ if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], 0.0 ) )
+ {
+ if ( rComp.nVal[ 0 ] < 0.0 )
+ fRes = -1; // -x < empty cell
+ else
+ fRes = 1; // x > empty cell
+ }
+ // else: empty cell == 0.0
+ }
+ else
+ {
+ if ( !rComp.pVal[ 0 ]->isEmpty() )
+ fRes = 1; // "..." > empty cell
+ // else: "" == empty cell
+ }
+ }
+ else if( rComp.bVal[ 0 ] )
+ {
+ if( rComp.bVal[ 1 ] )
+ {
+ if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], rComp.nVal[ 1 ] ) )
+ {
+ if( rComp.nVal[ 0 ] - rComp.nVal[ 1 ] < 0 )
+ fRes = -1;
+ else
+ fRes = 1;
+ }
+ }
+ else
+ {
+ fRes = -1; // number is less than string
+ nStringQuery = 2; // 1+1
+ }
+ }
+ else if( rComp.bVal[ 1 ] )
+ {
+ fRes = 1; // string is greater than number
+ nStringQuery = 1; // 0+1
+ }
+ else
+ {
+ // Both strings.
+ if (pOptions)
+ {
+ // All similar to ScTable::ValidQuery(), *rComp.pVal[1] actually
+ // is/must be identical to *rEntry.pStr, which is essential for
+ // regex to work through GetSearchTextPtr().
+ ScQueryEntry& rEntry = pOptions->aQueryEntry;
+ OSL_ENSURE(rEntry.GetQueryItem().maString.getString().equals(*rComp.pVal[1]), "ScInterpreter::CompareFunc: broken options");
+ if (pOptions->bRegEx)
+ {
+ sal_Int32 nStart = 0;
+ sal_Int32 nStop = rComp.pVal[0]->getLength();
+ bool bMatch = rEntry.GetSearchTextPtr(
+ !pOptions->bIgnoreCase)->SearchForward( *rComp.pVal[0],
+ &nStart, &nStop);
+ if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rComp.pVal[0]->getLength()))
+ bMatch = false; // RegEx must match entire string.
+ fRes = (bMatch ? 0 : 1);
+ }
+ else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
+ {
+ ::utl::TransliterationWrapper* pTransliteration =
+ (pOptions->bIgnoreCase ? ScGlobal::GetpTransliteration() :
+ ScGlobal::GetCaseTransliteration());
+ bool bMatch;
+ if (pOptions->bMatchWholeCell)
+ bMatch = pTransliteration->isEqual( *rComp.pVal[0], *rComp.pVal[1]);
+ else
+ {
+ OUString aCell( pTransliteration->transliterate(
+ *rComp.pVal[0], ScGlobal::eLnge, 0,
+ rComp.pVal[0]->getLength(), NULL));
+ OUString aQuer( pTransliteration->transliterate(
+ *rComp.pVal[1], ScGlobal::eLnge, 0,
+ rComp.pVal[1]->getLength(), NULL));
+ bMatch = (aCell.indexOf( aQuer ) != -1);
+ }
+ fRes = (bMatch ? 0 : 1);
+ }
+ else if (pOptions->bIgnoreCase)
+ fRes = (double) ScGlobal::GetCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ else
+ fRes = (double) ScGlobal::GetCaseCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ }
+ else if (bIgnoreCase)
+ fRes = (double) ScGlobal::GetCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ else
+ fRes = (double) ScGlobal::GetCaseCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ }
+
+ if (nStringQuery && 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 = (*rComp.pVal[nStringQuery-1]) == rItem.maString.getString();
+ // match => fRes=0, else fRes=1
+ fRes = (rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual;
+ }
+ }
+ }
+
+ return fRes;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index f8b31f27c86e..3749dbda62bd 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -57,6 +57,7 @@
#include "queryparam.hxx"
#include "queryentry.hxx"
#include "tokenarray.hxx"
+#include "compare.hxx"
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
@@ -81,41 +82,6 @@ bool ScInterpreter::bGlobalStackInUse = false;
using namespace formula;
using ::std::auto_ptr;
-struct ScCompare
-{
- double nVal[2];
- OUString* pVal[2];
- bool bVal[2];
- bool bEmpty[2];
- ScCompare( OUString* p1, OUString* p2 )
- {
- pVal[ 0 ] = p1;
- pVal[ 1 ] = p2;
- bEmpty[0] = false;
- bEmpty[1] = false;
- }
-};
-
-struct ScCompareOptions
-{
- ScQueryEntry aQueryEntry;
- bool bRegEx;
- bool bMatchWholeCell;
- bool bIgnoreCase;
-
- ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg );
-private:
- // Not implemented, prevent usage.
- ScCompareOptions();
- ScCompareOptions( const ScCompareOptions & );
- ScCompareOptions& operator=( const ScCompareOptions & );
-};
-
-//-----------------------------------------------------------------------------
-// Functions
-//-----------------------------------------------------------------------------
-
-
void ScInterpreter::ScIfJump()
{
const short* pJump = pCur->GetJump();
@@ -823,180 +789,10 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
return false;
}
-
-ScCompareOptions::ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) :
- aQueryEntry(rEntry),
- bRegEx(bReg),
- bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell()),
- bIgnoreCase(true)
-{
- bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
- // Interpreter functions usually are case insensitive, except the simple
- // comparison operators, for which these options aren't used. Override in
- // struct if needed.
-}
-
-
-double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions )
-{
- // Keep DoubleError if encountered
- // #i40539# if bEmpty is set, bVal/nVal are uninitialized
- if ( !rComp.bEmpty[0] && rComp.bVal[0] && !::rtl::math::isFinite( rComp.nVal[0]))
- return rComp.nVal[0];
- if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1]))
- return rComp.nVal[1];
-
- size_t nStringQuery = 0; // 0:=no, 1:=0, 2:=1
- double fRes = 0;
- if ( rComp.bEmpty[ 0 ] )
- {
- if ( rComp.bEmpty[ 1 ] )
- ; // empty cell == empty cell, fRes 0
- else if( rComp.bVal[ 1 ] )
- {
- if ( !::rtl::math::approxEqual( rComp.nVal[ 1 ], 0.0 ) )
- {
- if ( rComp.nVal[ 1 ] < 0.0 )
- fRes = 1; // empty cell > -x
- else
- fRes = -1; // empty cell < x
- }
- // else: empty cell == 0.0
- }
- else
- {
- if ( !rComp.pVal[ 1 ]->isEmpty() )
- fRes = -1; // empty cell < "..."
- // else: empty cell == ""
- }
- }
- else if ( rComp.bEmpty[ 1 ] )
- {
- if( rComp.bVal[ 0 ] )
- {
- if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], 0.0 ) )
- {
- if ( rComp.nVal[ 0 ] < 0.0 )
- fRes = -1; // -x < empty cell
- else
- fRes = 1; // x > empty cell
- }
- // else: empty cell == 0.0
- }
- else
- {
- if ( !rComp.pVal[ 0 ]->isEmpty() )
- fRes = 1; // "..." > empty cell
- // else: "" == empty cell
- }
- }
- else if( rComp.bVal[ 0 ] )
- {
- if( rComp.bVal[ 1 ] )
- {
- if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], rComp.nVal[ 1 ] ) )
- {
- if( rComp.nVal[ 0 ] - rComp.nVal[ 1 ] < 0 )
- fRes = -1;
- else
- fRes = 1;
- }
- }
- else
- {
- fRes = -1; // number is less than string
- nStringQuery = 2; // 1+1
- }
- }
- else if( rComp.bVal[ 1 ] )
- {
- fRes = 1; // string is greater than number
- nStringQuery = 1; // 0+1
- }
- else
- {
- // Both strings.
- if (pOptions)
- {
- // All similar to ScTable::ValidQuery(), *rComp.pVal[1] actually
- // is/must be identical to *rEntry.pStr, which is essential for
- // regex to work through GetSearchTextPtr().
- ScQueryEntry& rEntry = pOptions->aQueryEntry;
- OSL_ENSURE(rEntry.GetQueryItem().maString.getString().equals(*rComp.pVal[1]), "ScInterpreter::CompareFunc: broken options");
- if (pOptions->bRegEx)
- {
- sal_Int32 nStart = 0;
- sal_Int32 nStop = rComp.pVal[0]->getLength();
- bool bMatch = rEntry.GetSearchTextPtr(
- !pOptions->bIgnoreCase)->SearchForward( *rComp.pVal[0],
- &nStart, &nStop);
- if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rComp.pVal[0]->getLength()))
- bMatch = false; // RegEx must match entire string.
- fRes = (bMatch ? 0 : 1);
- }
- else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
- {
- ::utl::TransliterationWrapper* pTransliteration =
- (pOptions->bIgnoreCase ? ScGlobal::GetpTransliteration() :
- ScGlobal::GetCaseTransliteration());
- bool bMatch;
- if (pOptions->bMatchWholeCell)
- bMatch = pTransliteration->isEqual( *rComp.pVal[0], *rComp.pVal[1]);
- else
- {
- OUString aCell( pTransliteration->transliterate(
- *rComp.pVal[0], ScGlobal::eLnge, 0,
- rComp.pVal[0]->getLength(), NULL));
- OUString aQuer( pTransliteration->transliterate(
- *rComp.pVal[1], ScGlobal::eLnge, 0,
- rComp.pVal[1]->getLength(), NULL));
- bMatch = (aCell.indexOf( aQuer ) != -1);
- }
- fRes = (bMatch ? 0 : 1);
- }
- else if (pOptions->bIgnoreCase)
- fRes = (double) ScGlobal::GetCollator()->compareString(
- *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
- else
- fRes = (double) ScGlobal::GetCaseCollator()->compareString(
- *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
- }
- else if (pDok->GetDocOptions().IsIgnoreCase())
- fRes = (double) ScGlobal::GetCollator()->compareString(
- *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
- else
- fRes = (double) ScGlobal::GetCaseCollator()->compareString(
- *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
- }
-
- if (nStringQuery && 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 = (*rComp.pVal[nStringQuery-1]) == rItem.maString.getString();
- // match => fRes=0, else fRes=1
- fRes = (rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual;
- }
- }
- }
-
- return fRes;
-}
-
-
double ScInterpreter::Compare()
{
OUString aVal1, aVal2;
- ScCompare aComp( &aVal1, &aVal2 );
+ sc::Compare aComp( &aVal1, &aVal2 );
for( short i = 1; i >= 0; i-- )
{
switch ( GetRawStackType() )
@@ -1078,14 +874,14 @@ double ScInterpreter::Compare()
if( nGlobalError )
return 0;
nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
- return CompareFunc( aComp );
+ return sc::CompareFunc(pDok->GetDocOptions().IsIgnoreCase(), aComp);
}
-sc::RangeMatrix ScInterpreter::CompareMat( ScCompareOptions* pOptions )
+sc::RangeMatrix ScInterpreter::CompareMat( sc::CompareOptions* pOptions )
{
OUString aVal1, aVal2;
- ScCompare aComp( &aVal1, &aVal2 );
+ sc::Compare aComp( &aVal1, &aVal2 );
sc::RangeMatrix aMat[2];
ScAddress aAdr;
for( short i = 1; i >= 0; i-- )
@@ -1178,7 +974,7 @@ sc::RangeMatrix ScInterpreter::CompareMat( ScCompareOptions* pOptions )
aComp.bEmpty[i] = false;
}
}
- aRes.mpMat->PutDouble(CompareFunc(aComp, pOptions), j, k);
+ aRes.mpMat->PutDouble(sc::CompareFunc(pDok->GetDocOptions().IsIgnoreCase(), aComp, pOptions), j, k);
}
else
aRes.mpMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NO_VALUE)), j, k);
@@ -1190,7 +986,7 @@ sc::RangeMatrix ScInterpreter::CompareMat( ScCompareOptions* pOptions )
short i = ( aMat[0].mpMat ? 0 : 1);
SCSIZE nC, nR;
aMat[i].mpMat->GetDimensions(nC, nR);
- aRes.mpMat = GetNewMat( nC, nR);
+ aRes.mpMat = GetNewMat(nC, nR, false);
if (!aRes.mpMat)
return aRes;
@@ -1201,25 +997,48 @@ sc::RangeMatrix ScInterpreter::CompareMat( ScCompareOptions* pOptions )
aRes.mnRow2 = aMat[i].mnRow2;
aRes.mnTab2 = aMat[i].mnTab2;
- for (SCSIZE j = 0; j < nC; ++j)
+ ScMatrix& rMat = *aMat[i].mpMat;
+ ScMatrix& rResMat = *aRes.mpMat;
+ ScMatrix::PosRef pMatPos(rMat.GetPosition(0, 0));
+ ScMatrixValue aVal;
+ std::vector<double> aResMatValues;
+ aResMatValues.reserve(nC*nR);
+ for (size_t j = 0, n = nC*nR; j < n; ++j)
{
- for (SCSIZE k = 0; k < nR; ++k)
+ aVal = rMat.Get(*pMatPos);
+ switch (aVal.nType)
{
- if (aMat[i].mpMat->IsValue(j, k))
+ case SC_MATVAL_VALUE:
+ case SC_MATVAL_BOOLEAN:
{
aComp.bVal[i] = true;
- aComp.nVal[i] = aMat[i].mpMat->GetDouble(j, k);
+ aComp.nVal[i] = aVal.fVal;
aComp.bEmpty[i] = false;
}
- else
+ break;
+ case SC_MATVAL_STRING:
{
aComp.bVal[i] = false;
- *aComp.pVal[i] = aMat[i].mpMat->GetString(j, k).getString();
- aComp.bEmpty[i] = aMat[i].mpMat->IsEmpty(j, k);
+ *aComp.pVal[i] = aVal.aStr.getString();
+ aComp.bEmpty[i] = false;
}
- aRes.mpMat->PutDouble(CompareFunc(aComp, pOptions), j, k);
+ break;
+ case SC_MATVAL_EMPTY:
+ case SC_MATVAL_EMPTYPATH:
+ {
+ aComp.bVal[i] = false;
+ *aComp.pVal[i] = svl::SharedString::getEmptyString().getString();
+ aComp.bEmpty[i] = aVal.nType == SC_MATVAL_EMPTY;
+ }
+ break;
+ default:
+ ;
}
+
+ aResMatValues.push_back(sc::CompareFunc(pDok->GetDocOptions().IsIgnoreCase(), aComp, pOptions));
+ rMat.NextPosition(*pMatPos);
}
+ rResMat.PutDouble(&aResMatValues[0], aResMatValues.size(), 0, 0);
}
}
nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
@@ -1227,7 +1046,7 @@ sc::RangeMatrix ScInterpreter::CompareMat( ScCompareOptions* pOptions )
}
-ScMatrixRef ScInterpreter::QueryMat( const ScMatrixRef& pMat, ScCompareOptions& rOptions )
+ScMatrixRef ScInterpreter::QueryMat( const ScMatrixRef& pMat, sc::CompareOptions& rOptions )
{
short nSaveCurFmtType = nCurFmtType;
short nSaveFuncFmtType = nFuncFmtType;
@@ -5139,7 +4958,7 @@ double ScInterpreter::IterateParametersIf( ScIterFuncIf eFunc )
if (pQueryMatrix)
{
// Never case-sensitive.
- ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
+ sc::CompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
if (nGlobalError || !pResultMatrix)
{
@@ -5434,7 +5253,7 @@ void ScInterpreter::ScCountIf()
if (pQueryMatrix)
{
// Never case-sensitive.
- ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
+ sc::CompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
if (nGlobalError || !pResultMatrix)
{
@@ -5690,7 +5509,7 @@ double ScInterpreter::IterateParametersIfs( ScIterFuncIfs eFunc )
if (pQueryMatrix)
{
// Never case-sensitive.
- ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
+ sc::CompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
if (nGlobalError || !pResultMatrix)
{
diff --git a/sc/source/core/tool/scmatrix.cxx b/sc/source/core/tool/scmatrix.cxx
index af824acb573c..4b3bbc3eba8a 100644
--- a/sc/source/core/tool/scmatrix.cxx
+++ b/sc/source/core/tool/scmatrix.cxx
@@ -64,10 +64,28 @@ struct custom_string_trait
typedef mdds::mtv::custom_block_func1<sc::string_block> element_block_func;
};
-namespace {
-
typedef mdds::multi_type_matrix<custom_string_trait> MatrixImplType;
+struct ScMatrix::Pos
+{
+ MatrixImplType::position_type maPos;
+ MatrixImplType::position_type maPosFlag;
+};
+
+struct ScMatrix::ConstPos
+{
+ MatrixImplType::const_position_type maPos;
+ MatrixImplType::const_position_type maPosFlag;
+
+ ConstPos() {}
+ ConstPos( const ScMatrix::ConstPos& r ) :
+ maPos(r.maPos), maPosFlag(r.maPosFlag) {}
+ ConstPos( const ScMatrix::Pos& r ) :
+ maPos(r.maPos), maPosFlag(r.maPosFlag) {}
+};
+
+namespace {
+
struct ElemEqualZero : public unary_function<double, bool>
{
bool operator() (double val) const
@@ -195,6 +213,7 @@ public:
svl::SharedString GetString( SCSIZE nIndex) const;
svl::SharedString GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const;
ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const;
+ ScMatrixValue Get( const ScMatrix::ConstPos& rPos ) const;
bool IsString( SCSIZE nIndex ) const;
bool IsString( SCSIZE nC, SCSIZE nR ) const;
bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;
@@ -204,6 +223,25 @@ public:
bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const;
bool IsBoolean( SCSIZE nC, SCSIZE nR ) const;
bool IsNumeric() const;
+
+ ScMatrix::Pos* GetPosition( size_t nC, size_t nR );
+ ScMatrix::ConstPos* GetConstPosition( size_t nC, size_t nR ) const;
+
+ bool NextPosition( ScMatrix::Pos& rPos );
+ bool NextPosition( ScMatrix::ConstPos& rPos ) const;
+
+ bool IsValue( const ScMatrix::ConstPos& rPos ) const;
+ bool IsEmpty( const ScMatrix::ConstPos& rPos ) const;
+ double GetDouble( const ScMatrix::ConstPos& rPos ) const;
+ svl::SharedString GetString( const ScMatrix::ConstPos& rPos ) const;
+
+ void PutDouble( double fVal, ScMatrix::Pos& rPos );
+ void PutString( const svl::SharedString& rStr, ScMatrix::Pos& rPos );
+ void PutEmpty( ScMatrix::Pos& rPos );
+ void PutEmptyPath( ScMatrix::Pos& rPos );
+ void PutError( sal_uInt16 nErr, ScMatrix::Pos& rPos );
+ void PutBoolean( bool bVal, ScMatrix::Pos& rPos );
+
void MatCopy(ScMatrixImpl& mRes) const;
void MatTrans(ScMatrixImpl& mRes) const;
void FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 );
@@ -482,7 +520,7 @@ svl::SharedString ScMatrixImpl::GetString(SCSIZE nC, SCSIZE nR) const
case mdds::mtm::element_string:
return maMat.get_string(aPos);
case mdds::mtm::element_empty:
- return svl::SharedString(EMPTY_OUSTRING);
+ return svl::SharedString::getEmptyString();
case mdds::mtm::element_numeric:
case mdds::mtm::element_boolean:
OSL_FAIL("ScMatrixImpl::GetString: access error, no string");
@@ -496,7 +534,7 @@ svl::SharedString ScMatrixImpl::GetString(SCSIZE nC, SCSIZE nR) const
{
OSL_FAIL("ScMatrixImpl::GetString: dimension error");
}
- return svl::SharedString(EMPTY_OUSTRING);
+ return svl::SharedString::getEmptyString();
}
svl::SharedString ScMatrixImpl::GetString( SCSIZE nIndex) const
@@ -575,7 +613,7 @@ ScMatrixValue ScMatrixImpl::Get(SCSIZE nC, SCSIZE nR) const
break;
case mdds::mtm::element_string:
aVal.nType = SC_MATVAL_STRING;
- aVal.aStr = maMat.get_string(aPos).getString();
+ aVal.aStr = maMat.get_string(aPos);
break;
case mdds::mtm::element_empty:
// Empty path equals empty plus flag.
@@ -592,6 +630,34 @@ ScMatrixValue ScMatrixImpl::Get(SCSIZE nC, SCSIZE nR) const
return aVal;
}
+ScMatrixValue ScMatrixImpl::Get( const ScMatrix::ConstPos& rPos ) const
+{
+ ScMatrixValue aVal;
+ mdds::mtm::element_t eType = maMat.get_type(rPos.maPos);
+ switch (eType)
+ {
+ case mdds::mtm::element_boolean:
+ aVal.nType = SC_MATVAL_BOOLEAN;
+ aVal.fVal = maMat.get_boolean(rPos.maPos);
+ break;
+ case mdds::mtm::element_numeric:
+ aVal.nType = SC_MATVAL_VALUE;
+ aVal.fVal = MatrixImplType::numeric_block_type::at(*rPos.maPos.first->data, rPos.maPos.second);
+ break;
+ case mdds::mtm::element_string:
+ aVal.nType = SC_MATVAL_STRING;
+ aVal.aStr = MatrixImplType::string_block_type::at(*rPos.maPos.first->data, rPos.maPos.second);
+ break;
+ case mdds::mtm::element_empty:
+ // Empty path equals empty plus flag.
+ aVal.nType = maMatFlag.get_boolean(rPos.maPosFlag) ? SC_MATVAL_EMPTYPATH : SC_MATVAL_EMPTY;
+ aVal.fVal = 0.0;
+ default:
+ ;
+ }
+ return aVal;
+}
+
bool ScMatrixImpl::IsString( SCSIZE nIndex ) const
{
SCSIZE nC, nR;
@@ -677,6 +743,123 @@ bool ScMatrixImpl::IsNumeric() const
return maMat.numeric();
}
+ScMatrix::Pos* ScMatrixImpl::GetPosition( size_t nC, size_t nR )
+{
+ ScMatrix::Pos* pRet = new ScMatrix::Pos;
+ pRet->maPos = maMat.position(nR, nC);
+ pRet->maPosFlag = maMatFlag.position(nR, nC);
+ return pRet;
+}
+
+ScMatrix::ConstPos* ScMatrixImpl::GetConstPosition( size_t nC, size_t nR ) const
+{
+ ScMatrix::ConstPos* pRet = new ScMatrix::ConstPos;
+ pRet->maPos = maMat.position(nR, nC);
+ pRet->maPosFlag = maMatFlag.position(nR, nC);
+ return pRet;
+}
+
+bool ScMatrixImpl::NextPosition( ScMatrix::Pos& rPos )
+{
+ rPos.maPos = MatrixImplType::next_position(rPos.maPos);
+ rPos.maPosFlag = MatrixImplType::next_position(rPos.maPosFlag);
+ return rPos.maPos != maMat.end_position();
+}
+
+bool ScMatrixImpl::NextPosition( ScMatrix::ConstPos& rPos ) const
+{
+ rPos.maPos = MatrixImplType::next_position(rPos.maPos);
+ rPos.maPosFlag = MatrixImplType::next_position(rPos.maPosFlag);
+ return rPos.maPos != maMat.end_position();
+}
+
+bool ScMatrixImpl::IsValue( const ScMatrix::ConstPos& rPos ) const
+{
+ switch (maMat.get_type(rPos.maPos))
+ {
+ case mdds::mtm::element_boolean:
+ case mdds::mtm::element_numeric:
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+bool ScMatrixImpl::IsEmpty( const ScMatrix::ConstPos& rPos ) const
+{
+ return maMat.get_type(rPos.maPos) == mdds::mtm::element_empty && !maMatFlag.get_boolean(rPos.maPosFlag);
+}
+
+double ScMatrixImpl::GetDouble( const ScMatrix::ConstPos& rPos ) const
+{
+ double fVal = maMat.get_numeric(rPos.maPos);
+ if (pErrorInterpreter)
+ {
+ sal_uInt16 nError = GetDoubleErrorValue(fVal);
+ if (nError)
+ SetErrorAtInterpreter( nError);
+ }
+ return fVal;
+}
+
+
+svl::SharedString ScMatrixImpl::GetString( const ScMatrix::ConstPos& rPos ) const
+{
+ double fErr = 0.0;
+ switch (maMat.get_type(rPos.maPos))
+ {
+ case mdds::mtm::element_string:
+ return maMat.get_string(rPos.maPos);
+ case mdds::mtm::element_empty:
+ return svl::SharedString::getEmptyString();
+ case mdds::mtm::element_numeric:
+ case mdds::mtm::element_boolean:
+ OSL_FAIL("ScMatrixImpl::GetString: access error, no string");
+ fErr = maMat.get_numeric(rPos.maPos);
+ default:
+ OSL_FAIL("ScMatrixImpl::GetString: access error, no string");
+ }
+
+ SetErrorAtInterpreter(GetDoubleErrorValue(fErr));
+ return svl::SharedString::getEmptyString();
+}
+
+void ScMatrixImpl::PutDouble( double fVal, ScMatrix::Pos& rPos )
+{
+ if (maMat.get_type(rPos.maPos) == mdds::mtm::element_numeric)
+ MatrixImplType::numeric_block_type::at(*rPos.maPos.first->data, rPos.maPos.second) = fVal;
+ else
+ rPos.maPos = maMat.set(rPos.maPos, fVal);
+}
+
+void ScMatrixImpl::PutString( const svl::SharedString& rStr, ScMatrix::Pos& rPos )
+{
+ rPos.maPos = maMat.set(rPos.maPos, rStr);
+}
+
+void ScMatrixImpl::PutEmpty( ScMatrix::Pos& rPos )
+{
+ rPos.maPos = maMat.set_empty(rPos.maPos);
+ rPos.maPosFlag = maMatFlag.set(rPos.maPosFlag, false); // zero flag to indicate that this is 'empty', not 'empty path'.
+}
+
+void ScMatrixImpl::PutEmptyPath( ScMatrix::Pos& rPos )
+{
+ rPos.maPos = maMat.set_empty(rPos.maPos);
+ rPos.maPosFlag = maMatFlag.set(rPos.maPosFlag, true); // non-zero flag to indicate empty 'path'.
+}
+
+void ScMatrixImpl::PutError( sal_uInt16 nErr, ScMatrix::Pos& rPos )
+{
+ rPos.maPos = maMat.set(rPos.maPos, CreateDoubleError(nErr));
+}
+
+void ScMatrixImpl::PutBoolean( bool bVal, ScMatrix::Pos& rPos )
+{
+ rPos.maPos = maMat.set(rPos.maPos, bVal);
+}
+
void ScMatrixImpl::MatCopy(ScMatrixImpl& mRes) const
{
if (maMat.size().row > mRes.maMat.size().row || maMat.size().column > mRes.maMat.size().column)
@@ -1568,6 +1751,16 @@ ScMatrixValue ScMatrix::Get(SCSIZE nC, SCSIZE nR) const
return pImpl->Get(nC, nR);
}
+ScMatrixValue ScMatrix::Get( const Pos& rPos ) const
+{
+ return pImpl->Get(rPos);
+}
+
+ScMatrixValue ScMatrix::Get( const ConstPos& rPos ) const
+{
+ return pImpl->Get(rPos);
+}
+
sal_Bool ScMatrix::IsString( SCSIZE nIndex ) const
{
return pImpl->IsString(nIndex);
@@ -1613,6 +1806,106 @@ sal_Bool ScMatrix::IsNumeric() const
return pImpl->IsNumeric();
}
+ScMatrix::Pos* ScMatrix::GetPosition( size_t nC, size_t nR )
+{
+ return pImpl->GetPosition(nC, nR);
+}
+
+ScMatrix::ConstPos* ScMatrix::GetConstPosition( size_t nC, size_t nR ) const
+{
+ return pImpl->GetConstPosition(nC, nR);
+}
+
+void ScMatrix::DeletePosition( const Pos* p )
+{
+ delete p;
+}
+
+void ScMatrix::DeletePosition( const ConstPos* p )
+{
+ delete p;
+}
+
+bool ScMatrix::NextPosition( Pos& rPos )
+{
+ return pImpl->NextPosition(rPos);
+}
+
+bool ScMatrix::NextPosition( ConstPos& rPos ) const
+{
+ return pImpl->NextPosition(rPos);
+}
+
+bool ScMatrix::IsValue( const Pos& rPos ) const
+{
+ return pImpl->IsValue(rPos);
+}
+
+bool ScMatrix::IsValue( const ConstPos& rPos ) const
+{
+ return pImpl->IsValue(rPos);
+}
+
+bool ScMatrix::IsEmpty( const Pos& rPos ) const
+{
+ return pImpl->IsEmpty(rPos);
+}
+
+bool ScMatrix::IsEmpty( const ConstPos& rPos ) const
+{
+ return pImpl->IsEmpty(rPos);
+}
+
+double ScMatrix::GetDouble( const Pos& rPos ) const
+{
+ return pImpl->GetDouble(rPos);
+}
+
+double ScMatrix::GetDouble( const ConstPos& rPos ) const
+{
+ return pImpl->GetDouble(rPos);
+}
+
+svl::SharedString ScMatrix::GetString( const Pos& rPos ) const
+{
+ return pImpl->GetString(rPos);
+}
+
+svl::SharedString ScMatrix::GetString( const ConstPos& rPos ) const
+{
+ return pImpl->GetString(rPos);
+}
+
+void ScMatrix::PutDouble( double fVal, Pos& rPos )
+{
+ pImpl->PutDouble(fVal, rPos);
+}
+
+void ScMatrix::PutString( const svl::SharedString& rStr, Pos& rPos )
+{
+ pImpl->PutString(rStr, rPos);
+}
+
+void ScMatrix::PutEmpty( Pos& rPos )
+{
+ pImpl->PutEmpty(rPos);
+}
+
+void ScMatrix::PutEmptyPath( Pos& rPos )
+{
+ pImpl->PutEmptyPath(rPos);
+}
+
+void ScMatrix::PutError( sal_uInt16 nErr, Pos& rPos )
+{
+ pImpl->PutError(nErr, rPos);
+}
+
+void ScMatrix::PutBoolean( bool bVal, Pos& rPos )
+{
+ pImpl->PutBoolean(bVal, rPos);
+}
+
void ScMatrix::MatCopy(ScMatrix& mRes) const
{
pImpl->MatCopy(*mRes.pImpl);