diff options
Diffstat (limited to 'sc')
-rw-r--r-- | sc/Library_sc.mk | 1 | ||||
-rw-r--r-- | sc/inc/compare.hxx | 68 | ||||
-rw-r--r-- | sc/inc/scmatrix.hxx | 60 | ||||
-rw-r--r-- | sc/qa/unit/ucalc.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/inc/interpre.hxx | 12 | ||||
-rw-r--r-- | sc/source/core/tool/compare.cxx | 201 | ||||
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 265 | ||||
-rw-r--r-- | sc/source/core/tool/scmatrix.cxx | 303 |
8 files changed, 671 insertions, 241 deletions
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index f76032ac4648..3cd88dbb20a7 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -195,6 +195,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/tool/chartpos \ sc/source/core/tool/chgtrack \ sc/source/core/tool/chgviset \ + sc/source/core/tool/compare \ sc/source/core/tool/compiler \ sc/source/core/tool/consoli \ sc/source/core/tool/dbdata \ diff --git a/sc/inc/compare.hxx b/sc/inc/compare.hxx new file mode 100644 index 000000000000..307b5311a8e3 --- /dev/null +++ b/sc/inc/compare.hxx @@ -0,0 +1,68 @@ +/* -*- 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 . + */ + +#ifndef SC_COMPARE_HXX +#define SC_COMPARE_HXX + +#include "queryentry.hxx" + +#include "rtl/ustring.hxx" + +class ScDocument; + +namespace sc { + +struct Compare +{ + double nVal[2]; + OUString* pVal[2]; + bool bVal[2]; + bool bEmpty[2]; + + Compare( OUString* p1, OUString* p2 ) + { + pVal[0] = p1; + pVal[1] = p2; + bEmpty[0] = false; + bEmpty[1] = false; + } +}; + +struct CompareOptions +{ + ScQueryEntry aQueryEntry; + bool bRegEx; + bool bMatchWholeCell; + bool bIgnoreCase; + + CompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ); +private: + // Not implemented, prevent usage. + CompareOptions(); + CompareOptions( const CompareOptions & ); + CompareOptions& operator=( const CompareOptions & ); +}; + +double CompareFunc( bool bIgnoreCase, const Compare& rComp, CompareOptions* pOptions = NULL ); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/scmatrix.hxx b/sc/inc/scmatrix.hxx index b9975063e756..edd8cbdd41df 100644 --- a/sc/inc/scmatrix.hxx +++ b/sc/inc/scmatrix.hxx @@ -25,8 +25,10 @@ #include "formula/errorcodes.hxx" #include "scdllapi.h" #include <rtl/ustring.hxx> +#include "svl/sharedstring.hxx" #include <boost/intrusive_ptr.hpp> +#include <boost/interprocess/smart_ptr/unique_ptr.hpp> #define DEBUG_MATRIX 0 @@ -34,8 +36,6 @@ class ScInterpreter; class SvNumberFormatter; class ScMatrixImpl; -namespace svl { class SharedString; } - /** * Try NOT to use this struct. This struct should go away in a hopefully * not so distant futture. @@ -43,11 +43,11 @@ namespace svl { class SharedString; } struct ScMatrixValue { double fVal; - OUString aStr; + svl::SharedString aStr; ScMatValType nType; /// Only valid if ScMatrix methods indicate so! - const OUString& GetString() const { return aStr; } + OUString GetString() const { return aStr.getString(); } /// Only valid if ScMatrix methods indicate that this is no string! sal_uInt16 GetError() const { return GetDoubleErrorValue( fVal); } @@ -137,6 +137,31 @@ public: mfFirst(r.mfFirst), mfRest(r.mfRest), mnCount(r.mnCount) {} }; + struct Pos; + struct ConstPos; + + static void DeletePosition( const Pos* p ); + static void DeletePosition( const ConstPos* p ); + + struct PosDeleter : std::unary_function<const Pos*, void> + { + void operator() (const Pos* p) + { + DeletePosition(p); + } + }; + + struct ConstPosDeleter : std::unary_function<const ConstPos*, void> + { + void operator() (const ConstPos* p) + { + DeletePosition(p); + } + }; + + typedef boost::interprocess::unique_ptr<Pos, PosDeleter> PosRef; + typedef boost::interprocess::unique_ptr<ConstPos, PosDeleter> ConstPosRef; + /// The maximum number of elements a matrix may have at runtime. inline static size_t GetElementsMax() { @@ -289,6 +314,8 @@ public: /// @ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate /// an empty string! ScMatrixValue Get( SCSIZE nC, SCSIZE nR) const; + ScMatrixValue Get( const Pos& rPos ) const; + ScMatrixValue Get( const ConstPos& rPos ) const; /// @return <TRUE/> if string or empty or empty path, in fact non-value. sal_Bool IsString( SCSIZE nIndex ) const; @@ -317,6 +344,31 @@ public: /// @return <TRUE/> if entire matrix is numeric, including booleans, with no strings or empties sal_Bool IsNumeric() const; + Pos* GetPosition( size_t nC, size_t nR ); + ConstPos* GetConstPosition( size_t nC, size_t nR ) const; + + bool NextPosition( Pos& rPos ); + bool NextPosition( ConstPos& rPos ) const; + + bool IsValue( const Pos& rPos ) const; + bool IsValue( const ConstPos& rPos ) const; + + bool IsEmpty( const Pos& rPos ) const; + bool IsEmpty( const ConstPos& rPos ) const; + + double GetDouble( const Pos& rPos ) const; + double GetDouble( const ConstPos& rPos ) const; + + svl::SharedString GetString( const Pos& rPos ) const; + svl::SharedString GetString( const ConstPos& rPos ) const; + + void PutDouble( double fVal, Pos& rPos ); + void PutString( const svl::SharedString& rStr, Pos& rPos ); + void PutEmpty( Pos& rPos ); + void PutEmptyPath( Pos& rPos ); + void PutError( sal_uInt16 nErr, Pos& rPos ); + void PutBoolean( bool bVal, Pos& rPos ); + void MatTrans( ScMatrix& mRes) const; void MatCopy ( ScMatrix& mRes) const; diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index bdcbbd07b464..b38717082384 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -1458,7 +1458,7 @@ struct PartiallyFilledEmptyMatrix else if (nCol == 8 && nRow == 2) { CPPUNIT_ASSERT_MESSAGE("element is not of value type", rVal.nType == SC_MATVAL_STRING); - CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.aStr == "Test"); + CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.aStr.getString() == "Test"); } else if (nCol == 8 && nRow == 11) { 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); |