summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2013-10-17 19:23:01 -0400
committerKohei Yoshida <kohei.yoshida@collabora.com>2013-10-18 23:22:41 -0400
commite09cedd92259d8fdb98a7591b46a813685f0df96 (patch)
treece3df7ef5fd361550b1b5fc2f4d85ca6030663be /sc
parent0b9b668502de35a5077477d7e47a8f1ca7969ba6 (diff)
Initial attempt to speed up matrix comparison.
And move the value compare code to somewhere public. I'll be using it from the ScMatrix internal. This change requires mdds 0.9.1 which is yet to be released. Change-Id: I942133c85b614b3404006fa38af111ace9361fd4
Diffstat (limited to 'sc')
-rw-r--r--sc/Library_sc.mk1
-rw-r--r--sc/inc/compare.hxx68
-rw-r--r--sc/inc/scmatrix.hxx60
-rw-r--r--sc/qa/unit/ucalc.cxx2
-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
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);