1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scmatrix.hxx>
22 #include <address.hxx>
23 #include <formula/errorcodes.hxx>
24 #include <interpre.hxx>
25 #include <mtvelements.hxx>
26 #include <compare.hxx>
27 #include <matrixoperators.hxx>
30 #include <svl/numformat.hxx>
31 #include <svl/zforlist.hxx>
32 #include <svl/sharedstring.hxx>
33 #include <rtl/math.hxx>
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
43 #include <mdds/multi_type_matrix.hpp>
44 #include <mdds/multi_type_vector/types.hpp>
58 * Custom string trait struct to tell mdds::multi_type_matrix about the
59 * custom string type and how to handle blocks storing them.
63 typedef sc::string_block string_element_block
;
64 typedef sc::uint16_block integer_element_block
;
67 struct matrix_flag_traits
69 typedef sc::string_block string_element_block
;
70 typedef mdds::mtv::uint8_element_block integer_element_block
;
75 typedef mdds::multi_type_matrix
<matrix_traits
> MatrixImplType
;
76 typedef mdds::multi_type_matrix
<matrix_flag_traits
> MatrixFlagImplType
;
80 double convertStringToValue( ScInterpreter
* pErrorInterpreter
, const OUString
& rStr
)
82 if (pErrorInterpreter
)
84 FormulaError nError
= FormulaError::NONE
;
85 SvNumFormatType nCurFmtType
= SvNumFormatType::ALL
;
86 double fValue
= pErrorInterpreter
->ConvertStringToValue( rStr
, nError
, nCurFmtType
);
87 if (nError
!= FormulaError::NONE
)
89 pErrorInterpreter
->SetError( nError
);
90 return CreateDoubleError( nError
);
94 return CreateDoubleError( FormulaError::NoValue
);
99 double operator() (double val
) const
101 if (!std::isfinite(val
))
103 return val
== 0.0 ? 1.0 : 0.0;
107 struct ElemNotEqualZero
109 double operator() (double val
) const
111 if (!std::isfinite(val
))
113 return val
!= 0.0 ? 1.0 : 0.0;
117 struct ElemGreaterZero
119 double operator() (double val
) const
121 if (!std::isfinite(val
))
123 return val
> 0.0 ? 1.0 : 0.0;
129 double operator() (double val
) const
131 if (!std::isfinite(val
))
133 return val
< 0.0 ? 1.0 : 0.0;
137 struct ElemGreaterEqualZero
139 double operator() (double val
) const
141 if (!std::isfinite(val
))
143 return val
>= 0.0 ? 1.0 : 0.0;
147 struct ElemLessEqualZero
149 double operator() (double val
) const
151 if (!std::isfinite(val
))
153 return val
<= 0.0 ? 1.0 : 0.0;
157 template<typename Comp
>
158 class CompareMatrixElemFunc
162 std::vector
<double> maNewMatValues
; // double instead of bool to transport error values
166 CompareMatrixElemFunc( size_t nRow
, size_t nCol
) : mnRow(nRow
), mnCol(nCol
)
168 maNewMatValues
.reserve(nRow
*nCol
);
171 CompareMatrixElemFunc( const CompareMatrixElemFunc
& ) = delete;
172 CompareMatrixElemFunc
& operator= ( const CompareMatrixElemFunc
& ) = delete;
174 CompareMatrixElemFunc( CompareMatrixElemFunc
&& ) = default;
175 CompareMatrixElemFunc
& operator= ( CompareMatrixElemFunc
&& ) = default;
177 void operator() (const MatrixImplType::element_block_node_type
& node
)
181 case mdds::mtm::element_numeric
:
183 typedef MatrixImplType::numeric_block_type block_type
;
185 block_type::const_iterator it
= block_type::begin(*node
.data
);
186 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
187 for (; it
!= itEnd
; ++it
)
190 maNewMatValues
.push_back(maComp(fVal
));
194 case mdds::mtm::element_boolean
:
196 typedef MatrixImplType::boolean_block_type block_type
;
198 block_type::const_iterator it
= block_type::begin(*node
.data
);
199 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
200 for (; it
!= itEnd
; ++it
)
202 double fVal
= *it
? 1.0 : 0.0;
203 maNewMatValues
.push_back(maComp(fVal
));
207 case mdds::mtm::element_string
:
208 case mdds::mtm::element_empty
:
210 // Fill it with false.
211 maNewMatValues
.resize(maNewMatValues
.size() + node
.size
, 0.0);
215 void swap( MatrixImplType
& rMat
)
217 MatrixImplType
aNewMat(mnRow
, mnCol
, maNewMatValues
.begin(), maNewMatValues
.end());
222 template<typename Comp
>
223 Comp CompareMatrixElemFunc
<Comp
>::maComp
;
227 typedef uint8_t TMatFlag
;
228 const TMatFlag SC_MATFLAG_EMPTYRESULT
= 1;
229 const TMatFlag SC_MATFLAG_EMPTYPATH
= 2;
233 MatrixImplType maMat
;
234 MatrixFlagImplType maMatFlag
;
235 ScInterpreter
* pErrorInterpreter
;
238 ScMatrixImpl(const ScMatrixImpl
&) = delete;
239 const ScMatrixImpl
& operator=(const ScMatrixImpl
&) = delete;
241 ScMatrixImpl(SCSIZE nC
, SCSIZE nR
);
242 ScMatrixImpl(SCSIZE nC
, SCSIZE nR
, double fInitVal
);
244 ScMatrixImpl( size_t nC
, size_t nR
, const std::vector
<double>& rInitVals
);
249 void Resize(SCSIZE nC
, SCSIZE nR
);
250 void Resize(SCSIZE nC
, SCSIZE nR
, double fVal
);
251 void SetErrorInterpreter( ScInterpreter
* p
);
252 ScInterpreter
* GetErrorInterpreter() const { return pErrorInterpreter
; }
254 void GetDimensions( SCSIZE
& rC
, SCSIZE
& rR
) const;
255 SCSIZE
GetElementCount() const;
256 bool ValidColRow( SCSIZE nC
, SCSIZE nR
) const;
257 bool ValidColRowReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const;
258 bool ValidColRowOrReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const;
259 void SetErrorAtInterpreter( FormulaError nError
) const;
261 void PutDouble(double fVal
, SCSIZE nC
, SCSIZE nR
);
262 void PutDouble( double fVal
, SCSIZE nIndex
);
263 void PutDoubleTrans( double fVal
, SCSIZE nIndex
);
264 void PutDouble(const double* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
);
266 void PutString(const svl::SharedString
& rStr
, SCSIZE nC
, SCSIZE nR
);
267 void PutString(const svl::SharedString
& rStr
, SCSIZE nIndex
);
268 void PutStringTrans(const svl::SharedString
& rStr
, SCSIZE nIndex
);
269 void PutString(const svl::SharedString
* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
);
271 void PutEmpty(SCSIZE nC
, SCSIZE nR
);
272 void PutEmpty(SCSIZE nIndex
);
273 void PutEmptyTrans(SCSIZE nIndex
);
274 void PutEmptyPath(SCSIZE nC
, SCSIZE nR
);
275 void PutError( FormulaError nErrorCode
, SCSIZE nC
, SCSIZE nR
);
276 void PutBoolean(bool bVal
, SCSIZE nC
, SCSIZE nR
);
277 FormulaError
GetError( SCSIZE nC
, SCSIZE nR
) const;
278 double GetDouble(SCSIZE nC
, SCSIZE nR
) const;
279 double GetDouble( SCSIZE nIndex
) const;
280 double GetDoubleWithStringConversion(SCSIZE nC
, SCSIZE nR
) const;
281 svl::SharedString
GetString(SCSIZE nC
, SCSIZE nR
) const;
282 svl::SharedString
GetString( SCSIZE nIndex
) const;
283 svl::SharedString
GetString( ScInterpreterContext
& rContext
, SCSIZE nC
, SCSIZE nR
) const;
284 ScMatrixValue
Get(SCSIZE nC
, SCSIZE nR
) const;
285 bool IsStringOrEmpty( SCSIZE nIndex
) const;
286 bool IsStringOrEmpty( SCSIZE nC
, SCSIZE nR
) const;
287 bool IsEmpty( SCSIZE nC
, SCSIZE nR
) const;
288 bool IsEmptyCell( SCSIZE nC
, SCSIZE nR
) const;
289 bool IsEmptyResult( SCSIZE nC
, SCSIZE nR
) const;
290 bool IsEmptyPath( SCSIZE nC
, SCSIZE nR
) const;
291 bool IsValue( SCSIZE nIndex
) const;
292 bool IsValue( SCSIZE nC
, SCSIZE nR
) const;
293 bool IsValueOrEmpty( SCSIZE nC
, SCSIZE nR
) const;
294 bool IsBoolean( SCSIZE nC
, SCSIZE nR
) const;
295 bool IsNumeric() const;
297 void MatCopy(ScMatrixImpl
& mRes
) const;
298 void MatTrans(ScMatrixImpl
& mRes
) const;
299 void FillDouble( double fVal
, SCSIZE nC1
, SCSIZE nR1
, SCSIZE nC2
, SCSIZE nR2
);
300 void PutDoubleVector( const ::std::vector
< double > & rVec
, SCSIZE nC
, SCSIZE nR
);
301 void PutStringVector( const ::std::vector
< svl::SharedString
> & rVec
, SCSIZE nC
, SCSIZE nR
);
302 void PutEmptyVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
);
303 void PutEmptyResultVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
);
304 void PutEmptyPathVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
);
306 void CompareNotEqual();
308 void CompareGreater();
309 void CompareLessEqual();
310 void CompareGreaterEqual();
315 ScMatrix::KahanIterateResult
Sum( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
316 ScMatrix::KahanIterateResult
SumSquare( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
317 ScMatrix::DoubleIterateResult
Product( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
318 size_t Count(bool bCountStrings
, bool bCountErrors
, bool bIgnoreEmptyStrings
) const;
319 size_t MatchDoubleInColumns(double fValue
, size_t nCol1
, size_t nCol2
) const;
320 size_t MatchStringInColumns(const svl::SharedString
& rStr
, size_t nCol1
, size_t nCol2
) const;
322 double GetMaxValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
323 double GetMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
324 double GetGcd() const;
325 double GetLcm() const;
327 ScMatrixRef
CompareMatrix( sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) const;
329 void GetDoubleArray( std::vector
<double>& rArray
, bool bEmptyAsZero
) const;
330 void MergeDoubleArrayMultiply( std::vector
<double>& rArray
) const;
333 void ApplyOperation(T aOp
, ScMatrixImpl
& rMat
);
335 void ExecuteOperation(const std::pair
<size_t, size_t>& rStartPos
,
336 const std::pair
<size_t, size_t>& rEndPos
, const ScMatrix::DoubleOpFunction
& aDoubleFunc
,
337 const ScMatrix::BoolOpFunction
& aBoolFunc
, const ScMatrix::StringOpFunction
& aStringFunc
,
338 const ScMatrix::EmptyOpFunction
& aEmptyFunc
) const;
340 template<typename T
, typename tRes
>
341 ScMatrix::IterateResultMultiple
<tRes
> ApplyCollectOperation(const std::vector
<T
>& aOp
);
343 void MatConcat(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrixRef
& xMat1
, const ScMatrixRef
& xMat2
,
344 ScInterpreterContext
& rContext
, svl::SharedStringPool
& rPool
);
346 void ExecuteBinaryOp(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrix
& rInputMat1
, const ScMatrix
& rInputMat2
,
347 ScInterpreter
* pInterpreter
, const ScMatrix::CalculateOpFunction
& op
);
348 bool IsValueOrEmpty( const MatrixImplType::const_position_type
& rPos
) const;
349 double GetDouble( const MatrixImplType::const_position_type
& rPos
) const;
350 FormulaError
GetErrorIfNotString( const MatrixImplType::const_position_type
& rPos
) const;
351 bool IsValue( const MatrixImplType::const_position_type
& rPos
) const;
352 FormulaError
GetError(const MatrixImplType::const_position_type
& rPos
) const;
353 bool IsStringOrEmpty(const MatrixImplType::const_position_type
& rPos
) const;
354 svl::SharedString
GetString(const MatrixImplType::const_position_type
& rPos
) const;
361 void CalcPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const;
362 void CalcTransPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const;
365 static std::once_flag bElementsMaxFetched
;
366 static std::atomic
<size_t> nElementsMax
;
368 /** The maximum number of elements a matrix or the pool may have at runtime.
371 If 0, the arbitrary limit of one matrix is returned.
372 If >0, the given memory pool divided by the average size of a
373 matrix element is returned, which is used to initialize
376 static size_t GetElementsMax( size_t nMemory
)
378 // Arbitrarily assuming 12 bytes per element, 8 bytes double plus
379 // overhead. Stored as an array in an mdds container it's less, but for
380 // strings or mixed matrix it can be much more...
381 constexpr size_t nPerElem
= 12;
383 return nMemory
/ nPerElem
;
385 // Arbitrarily assuming 1GB memory. Could be dynamic at some point.
386 constexpr size_t nMemMax
= 0x40000000;
387 // With 1GB that's ~85M elements, or 85 whole columns.
388 constexpr size_t nElemMax
= nMemMax
/ nPerElem
;
389 // With MAXROWCOUNT==1048576 and 128 columns => 128M elements, 1.5GB
390 constexpr size_t nArbitraryLimit
= size_t(MAXROWCOUNT
) * 128;
391 // With the constant 1GB from above that's the actual value.
392 return std::min(nElemMax
, nArbitraryLimit
);
395 ScMatrixImpl::ScMatrixImpl(SCSIZE nC
, SCSIZE nR
) :
396 maMat(nR
, nC
), maMatFlag(nR
, nC
), pErrorInterpreter(nullptr)
398 nElementsMax
-= GetElementCount();
401 ScMatrixImpl::ScMatrixImpl(SCSIZE nC
, SCSIZE nR
, double fInitVal
) :
402 maMat(nR
, nC
, fInitVal
), maMatFlag(nR
, nC
), pErrorInterpreter(nullptr)
404 nElementsMax
-= GetElementCount();
407 ScMatrixImpl::ScMatrixImpl( size_t nC
, size_t nR
, const std::vector
<double>& rInitVals
) :
408 maMat(nR
, nC
, rInitVals
.begin(), rInitVals
.end()), maMatFlag(nR
, nC
), pErrorInterpreter(nullptr)
410 nElementsMax
-= GetElementCount();
413 ScMatrixImpl::~ScMatrixImpl()
415 nElementsMax
+= GetElementCount();
416 suppress_fun_call_w_exception(Clear());
419 void ScMatrixImpl::Clear()
421 suppress_fun_call_w_exception(maMat
.clear());
425 void ScMatrixImpl::Resize(SCSIZE nC
, SCSIZE nR
)
427 nElementsMax
+= GetElementCount();
428 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
430 maMat
.resize(nR
, nC
);
431 maMatFlag
.resize(nR
, nC
);
435 // Invalid matrix size, allocate 1x1 matrix with error value.
436 maMat
.resize(1, 1, CreateDoubleError( FormulaError::MatrixSize
));
437 maMatFlag
.resize(1, 1);
439 nElementsMax
-= GetElementCount();
442 void ScMatrixImpl::Resize(SCSIZE nC
, SCSIZE nR
, double fVal
)
444 nElementsMax
+= GetElementCount();
445 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
447 maMat
.resize(nR
, nC
, fVal
);
448 maMatFlag
.resize(nR
, nC
);
452 // Invalid matrix size, allocate 1x1 matrix with error value.
453 maMat
.resize(1, 1, CreateDoubleError( FormulaError::StackOverflow
));
454 maMatFlag
.resize(1, 1);
456 nElementsMax
-= GetElementCount();
459 void ScMatrixImpl::SetErrorInterpreter( ScInterpreter
* p
)
461 pErrorInterpreter
= p
;
464 void ScMatrixImpl::GetDimensions( SCSIZE
& rC
, SCSIZE
& rR
) const
466 MatrixImplType::size_pair_type aSize
= maMat
.size();
471 SCSIZE
ScMatrixImpl::GetElementCount() const
473 MatrixImplType::size_pair_type aSize
= maMat
.size();
474 return aSize
.row
* aSize
.column
;
477 bool ScMatrixImpl::ValidColRow( SCSIZE nC
, SCSIZE nR
) const
479 MatrixImplType::size_pair_type aSize
= maMat
.size();
480 return nR
< aSize
.row
&& nC
< aSize
.column
;
483 bool ScMatrixImpl::ValidColRowReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
485 MatrixImplType::size_pair_type aSize
= maMat
.size();
486 if (aSize
.column
== 1 && aSize
.row
== 1)
492 else if (aSize
.column
== 1 && rR
< aSize
.row
)
494 // single column matrix.
498 else if (aSize
.row
== 1 && rC
< aSize
.column
)
500 // single row matrix.
507 bool ScMatrixImpl::ValidColRowOrReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
509 return ValidColRow( rC
, rR
) || ValidColRowReplicated( rC
, rR
);
512 void ScMatrixImpl::SetErrorAtInterpreter( FormulaError nError
) const
514 if ( pErrorInterpreter
)
515 pErrorInterpreter
->SetError( nError
);
518 void ScMatrixImpl::PutDouble(double fVal
, SCSIZE nC
, SCSIZE nR
)
520 if (ValidColRow( nC
, nR
))
521 maMat
.set(nR
, nC
, fVal
);
524 OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
528 void ScMatrixImpl::PutDouble(const double* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
530 if (ValidColRow( nC
, nR
))
531 maMat
.set(nR
, nC
, pArray
, pArray
+ nLen
);
534 OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
538 void ScMatrixImpl::PutDouble( double fVal
, SCSIZE nIndex
)
541 CalcPosition(nIndex
, nC
, nR
);
542 PutDouble(fVal
, nC
, nR
);
545 void ScMatrixImpl::PutDoubleTrans(double fVal
, SCSIZE nIndex
)
548 CalcTransPosition(nIndex
, nC
, nR
);
549 PutDouble(fVal
, nC
, nR
);
552 void ScMatrixImpl::PutString(const svl::SharedString
& rStr
, SCSIZE nC
, SCSIZE nR
)
554 if (ValidColRow( nC
, nR
))
555 maMat
.set(nR
, nC
, rStr
);
558 OSL_FAIL("ScMatrixImpl::PutString: dimension error");
562 void ScMatrixImpl::PutString(const svl::SharedString
* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
564 if (ValidColRow( nC
, nR
))
565 maMat
.set(nR
, nC
, pArray
, pArray
+ nLen
);
568 OSL_FAIL("ScMatrixImpl::PutString: dimension error");
572 void ScMatrixImpl::PutString(const svl::SharedString
& rStr
, SCSIZE nIndex
)
575 CalcPosition(nIndex
, nC
, nR
);
576 PutString(rStr
, nC
, nR
);
579 void ScMatrixImpl::PutStringTrans(const svl::SharedString
& rStr
, SCSIZE nIndex
)
582 CalcTransPosition(nIndex
, nC
, nR
);
583 PutString(rStr
, nC
, nR
);
586 void ScMatrixImpl::PutEmpty(SCSIZE nC
, SCSIZE nR
)
588 if (ValidColRow( nC
, nR
))
590 maMat
.set_empty(nR
, nC
);
591 maMatFlag
.set_empty(nR
, nC
);
595 OSL_FAIL("ScMatrixImpl::PutEmpty: dimension error");
599 void ScMatrixImpl::PutEmpty(SCSIZE nIndex
)
602 CalcPosition(nIndex
, nC
, nR
);
606 void ScMatrixImpl::PutEmptyTrans(SCSIZE nIndex
)
609 CalcTransPosition(nIndex
, nC
, nR
);
613 void ScMatrixImpl::PutEmptyPath(SCSIZE nC
, SCSIZE nR
)
615 if (ValidColRow( nC
, nR
))
617 maMat
.set_empty(nR
, nC
);
618 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 && __cplusplus == 202002L
619 #pragma GCC diagnostic push
620 #pragma GCC diagnostic ignored "-Warray-bounds"
622 maMatFlag
.set(nR
, nC
, SC_MATFLAG_EMPTYPATH
);
623 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 && __cplusplus == 202002L
624 #pragma GCC diagnostic pop
629 OSL_FAIL("ScMatrixImpl::PutEmptyPath: dimension error");
633 void ScMatrixImpl::PutError( FormulaError nErrorCode
, SCSIZE nC
, SCSIZE nR
)
635 maMat
.set(nR
, nC
, CreateDoubleError(nErrorCode
));
638 void ScMatrixImpl::PutBoolean(bool bVal
, SCSIZE nC
, SCSIZE nR
)
640 if (ValidColRow( nC
, nR
))
641 maMat
.set(nR
, nC
, bVal
);
644 OSL_FAIL("ScMatrixImpl::PutBoolean: dimension error");
648 FormulaError
ScMatrixImpl::GetError( SCSIZE nC
, SCSIZE nR
) const
650 if (ValidColRowOrReplicated( nC
, nR
))
652 double fVal
= maMat
.get_numeric(nR
, nC
);
653 return GetDoubleErrorValue(fVal
);
657 OSL_FAIL("ScMatrixImpl::GetError: dimension error");
658 return FormulaError::NoValue
;
662 double ScMatrixImpl::GetDouble(SCSIZE nC
, SCSIZE nR
) const
664 if (ValidColRowOrReplicated( nC
, nR
))
666 double fVal
= maMat
.get_numeric(nR
, nC
);
667 if ( pErrorInterpreter
)
669 FormulaError nError
= GetDoubleErrorValue(fVal
);
670 if ( nError
!= FormulaError::NONE
)
671 SetErrorAtInterpreter( nError
);
677 OSL_FAIL("ScMatrixImpl::GetDouble: dimension error");
678 return CreateDoubleError( FormulaError::NoValue
);
682 double ScMatrixImpl::GetDouble( SCSIZE nIndex
) const
685 CalcPosition(nIndex
, nC
, nR
);
686 return GetDouble(nC
, nR
);
689 double ScMatrixImpl::GetDoubleWithStringConversion(SCSIZE nC
, SCSIZE nR
) const
691 ScMatrixValue aMatVal
= Get(nC
, nR
);
692 if (aMatVal
.nType
== ScMatValType::String
)
693 return convertStringToValue( pErrorInterpreter
, aMatVal
.aStr
.getString());
697 svl::SharedString
ScMatrixImpl::GetString(SCSIZE nC
, SCSIZE nR
) const
699 if (ValidColRowOrReplicated( nC
, nR
))
701 return GetString(maMat
.position(nR
, nC
));
705 OSL_FAIL("ScMatrixImpl::GetString: dimension error");
707 return svl::SharedString::getEmptyString();
710 svl::SharedString
ScMatrixImpl::GetString(const MatrixImplType::const_position_type
& rPos
) const
713 switch (maMat
.get_type(rPos
))
715 case mdds::mtm::element_string
:
716 return maMat
.get_string(rPos
);
717 case mdds::mtm::element_empty
:
718 return svl::SharedString::getEmptyString();
719 case mdds::mtm::element_numeric
:
720 case mdds::mtm::element_boolean
:
721 fErr
= maMat
.get_numeric(rPos
);
724 OSL_FAIL("ScMatrixImpl::GetString: access error, no string");
726 SetErrorAtInterpreter(GetDoubleErrorValue(fErr
));
727 return svl::SharedString::getEmptyString();
730 svl::SharedString
ScMatrixImpl::GetString( SCSIZE nIndex
) const
733 CalcPosition(nIndex
, nC
, nR
);
734 return GetString(nC
, nR
);
737 svl::SharedString
ScMatrixImpl::GetString( ScInterpreterContext
& rContext
, SCSIZE nC
, SCSIZE nR
) const
739 if (!ValidColRowOrReplicated( nC
, nR
))
741 OSL_FAIL("ScMatrixImpl::GetString: dimension error");
742 return svl::SharedString::getEmptyString();
746 MatrixImplType::const_position_type aPos
= maMat
.position(nR
, nC
);
747 switch (maMat
.get_type(aPos
))
749 case mdds::mtm::element_string
:
750 return maMat
.get_string(aPos
);
751 case mdds::mtm::element_empty
:
753 if (maMatFlag
.get
<uint8_t>(nR
, nC
) != SC_MATFLAG_EMPTYPATH
)
754 // not an empty path.
755 return svl::SharedString::getEmptyString();
757 // result of empty FALSE jump path
758 sal_uInt32 nKey
= rContext
.NFGetStandardFormat( SvNumFormatType::LOGICAL
,
761 const Color
* pColor
= nullptr;
762 rContext
.NFGetOutputString( 0.0, nKey
, aStr
, &pColor
);
763 return svl::SharedString( aStr
); // string not interned
765 case mdds::mtm::element_numeric
:
766 case mdds::mtm::element_boolean
:
767 fVal
= maMat
.get_numeric(aPos
);
773 FormulaError nError
= GetDoubleErrorValue(fVal
);
774 if (nError
!= FormulaError::NONE
)
776 SetErrorAtInterpreter( nError
);
777 return svl::SharedString( ScGlobal::GetErrorString( nError
)); // string not interned
780 sal_uInt32 nKey
= rContext
.NFGetStandardFormat( SvNumFormatType::NUMBER
,
782 return svl::SharedString(rContext
.NFGetInputLineString( fVal
, nKey
)); // string not interned
785 ScMatrixValue
ScMatrixImpl::Get(SCSIZE nC
, SCSIZE nR
) const
788 if (ValidColRowOrReplicated(nC
, nR
))
790 MatrixImplType::const_position_type aPos
= maMat
.position(nR
, nC
);
791 mdds::mtm::element_t eType
= maMat
.get_type(aPos
);
794 case mdds::mtm::element_boolean
:
795 aVal
.nType
= ScMatValType::Boolean
;
796 aVal
.fVal
= double(maMat
.get_boolean(aPos
));
798 case mdds::mtm::element_numeric
:
799 aVal
.nType
= ScMatValType::Value
;
800 aVal
.fVal
= maMat
.get_numeric(aPos
);
802 case mdds::mtm::element_string
:
803 aVal
.nType
= ScMatValType::String
;
804 aVal
.aStr
= maMat
.get_string(aPos
);
806 case mdds::mtm::element_empty
:
807 /* TODO: do we need to pass the differentiation of 'empty' and
808 * 'empty result' to the outer world anywhere? */
809 switch (maMatFlag
.get_type(nR
, nC
))
811 case mdds::mtm::element_empty
:
812 aVal
.nType
= ScMatValType::Empty
;
814 case mdds::mtm::element_integer
:
815 aVal
.nType
= maMatFlag
.get
<uint8_t>(nR
, nC
)
816 == SC_MATFLAG_EMPTYPATH
? ScMatValType::EmptyPath
: ScMatValType::Empty
;
829 OSL_FAIL("ScMatrixImpl::Get: dimension error");
834 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nIndex
) const
837 CalcPosition(nIndex
, nC
, nR
);
838 return IsStringOrEmpty(nC
, nR
);
841 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nC
, SCSIZE nR
) const
843 if (!ValidColRowOrReplicated( nC
, nR
))
846 switch (maMat
.get_type(nR
, nC
))
848 case mdds::mtm::element_empty
:
849 case mdds::mtm::element_string
:
857 bool ScMatrixImpl::IsEmpty( SCSIZE nC
, SCSIZE nR
) const
859 if (!ValidColRowOrReplicated( nC
, nR
))
862 // Flag must indicate an 'empty' or 'empty cell' or 'empty result' element,
863 // but not an 'empty path' element.
864 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
865 maMatFlag
.get_integer(nR
, nC
) != SC_MATFLAG_EMPTYPATH
;
868 bool ScMatrixImpl::IsEmptyCell( SCSIZE nC
, SCSIZE nR
) const
870 if (!ValidColRowOrReplicated( nC
, nR
))
873 // Flag must indicate an 'empty cell' element instead of an
874 // 'empty' or 'empty result' or 'empty path' element.
875 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
876 maMatFlag
.get_type(nR
, nC
) == mdds::mtm::element_empty
;
879 bool ScMatrixImpl::IsEmptyResult( SCSIZE nC
, SCSIZE nR
) const
881 if (!ValidColRowOrReplicated( nC
, nR
))
884 // Flag must indicate an 'empty result' element instead of an
885 // 'empty' or 'empty cell' or 'empty path' element.
886 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
887 maMatFlag
.get_integer(nR
, nC
) == SC_MATFLAG_EMPTYRESULT
;
890 bool ScMatrixImpl::IsEmptyPath( SCSIZE nC
, SCSIZE nR
) const
892 // Flag must indicate an 'empty path' element.
893 if (ValidColRowOrReplicated( nC
, nR
))
894 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
895 maMatFlag
.get_integer(nR
, nC
) == SC_MATFLAG_EMPTYPATH
;
900 bool ScMatrixImpl::IsValue( SCSIZE nIndex
) const
903 CalcPosition(nIndex
, nC
, nR
);
904 return IsValue(nC
, nR
);
907 bool ScMatrixImpl::IsValue( SCSIZE nC
, SCSIZE nR
) const
909 if (!ValidColRowOrReplicated( nC
, nR
))
912 switch (maMat
.get_type(nR
, nC
))
914 case mdds::mtm::element_boolean
:
915 case mdds::mtm::element_numeric
:
923 bool ScMatrixImpl::IsValueOrEmpty( SCSIZE nC
, SCSIZE nR
) const
925 if (!ValidColRowOrReplicated( nC
, nR
))
928 switch (maMat
.get_type(nR
, nC
))
930 case mdds::mtm::element_boolean
:
931 case mdds::mtm::element_numeric
:
932 case mdds::mtm::element_empty
:
940 bool ScMatrixImpl::IsBoolean( SCSIZE nC
, SCSIZE nR
) const
942 if (!ValidColRowOrReplicated( nC
, nR
))
945 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_boolean
;
948 bool ScMatrixImpl::IsNumeric() const
950 return maMat
.numeric();
953 void ScMatrixImpl::MatCopy(ScMatrixImpl
& mRes
) const
955 if (maMat
.size().row
> mRes
.maMat
.size().row
|| maMat
.size().column
> mRes
.maMat
.size().column
)
957 // destination matrix is not large enough.
958 OSL_FAIL("ScMatrixImpl::MatCopy: dimension error");
962 mRes
.maMat
.copy(maMat
);
965 void ScMatrixImpl::MatTrans(ScMatrixImpl
& mRes
) const
968 mRes
.maMat
.transpose();
971 void ScMatrixImpl::FillDouble( double fVal
, SCSIZE nC1
, SCSIZE nR1
, SCSIZE nC2
, SCSIZE nR2
)
973 if (ValidColRow( nC1
, nR1
) && ValidColRow( nC2
, nR2
))
975 for (SCSIZE j
= nC1
; j
<= nC2
; ++j
)
977 // Passing value array is much faster.
978 std::vector
<double> aVals(nR2
-nR1
+1, fVal
);
979 maMat
.set(nR1
, j
, aVals
.begin(), aVals
.end());
984 OSL_FAIL("ScMatrixImpl::FillDouble: dimension error");
988 void ScMatrixImpl::PutDoubleVector( const ::std::vector
< double > & rVec
, SCSIZE nC
, SCSIZE nR
)
990 if (!rVec
.empty() && ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ rVec
.size() - 1))
992 maMat
.set(nR
, nC
, rVec
.begin(), rVec
.end());
996 OSL_FAIL("ScMatrixImpl::PutDoubleVector: dimension error");
1000 void ScMatrixImpl::PutStringVector( const ::std::vector
< svl::SharedString
> & rVec
, SCSIZE nC
, SCSIZE nR
)
1002 if (!rVec
.empty() && ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ rVec
.size() - 1))
1004 maMat
.set(nR
, nC
, rVec
.begin(), rVec
.end());
1008 OSL_FAIL("ScMatrixImpl::PutStringVector: dimension error");
1012 void ScMatrixImpl::PutEmptyVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
1014 if (nCount
&& ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ nCount
- 1))
1016 maMat
.set_empty(nR
, nC
, nCount
);
1017 // Flag to indicate that this is 'empty', not 'empty result' or 'empty path'.
1018 maMatFlag
.set_empty(nR
, nC
, nCount
);
1022 OSL_FAIL("ScMatrixImpl::PutEmptyVector: dimension error");
1026 void ScMatrixImpl::PutEmptyResultVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
1028 if (nCount
&& ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ nCount
- 1))
1030 maMat
.set_empty(nR
, nC
, nCount
);
1031 // Flag to indicate that this is 'empty result', not 'empty' or 'empty path'.
1032 std::vector
<uint8_t> aVals(nCount
, SC_MATFLAG_EMPTYRESULT
);
1033 maMatFlag
.set(nR
, nC
, aVals
.begin(), aVals
.end());
1037 OSL_FAIL("ScMatrixImpl::PutEmptyResultVector: dimension error");
1041 void ScMatrixImpl::PutEmptyPathVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
1043 if (nCount
&& ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ nCount
- 1))
1045 maMat
.set_empty(nR
, nC
, nCount
);
1046 // Flag to indicate 'empty path'.
1047 std::vector
<uint8_t> aVals(nCount
, SC_MATFLAG_EMPTYPATH
);
1048 maMatFlag
.set(nR
, nC
, aVals
.begin(), aVals
.end());
1052 OSL_FAIL("ScMatrixImpl::PutEmptyPathVector: dimension error");
1056 void ScMatrixImpl::CompareEqual()
1058 MatrixImplType::size_pair_type aSize
= maMat
.size();
1059 CompareMatrixElemFunc
<ElemEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1060 aFunc
= maMat
.walk(std::move(aFunc
));
1064 void ScMatrixImpl::CompareNotEqual()
1066 MatrixImplType::size_pair_type aSize
= maMat
.size();
1067 CompareMatrixElemFunc
<ElemNotEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1068 aFunc
= maMat
.walk(std::move(aFunc
));
1072 void ScMatrixImpl::CompareLess()
1074 MatrixImplType::size_pair_type aSize
= maMat
.size();
1075 CompareMatrixElemFunc
<ElemLessZero
> aFunc(aSize
.row
, aSize
.column
);
1076 aFunc
= maMat
.walk(std::move(aFunc
));
1080 void ScMatrixImpl::CompareGreater()
1082 MatrixImplType::size_pair_type aSize
= maMat
.size();
1083 CompareMatrixElemFunc
<ElemGreaterZero
> aFunc(aSize
.row
, aSize
.column
);
1084 aFunc
= maMat
.walk(std::move(aFunc
));
1088 void ScMatrixImpl::CompareLessEqual()
1090 MatrixImplType::size_pair_type aSize
= maMat
.size();
1091 CompareMatrixElemFunc
<ElemLessEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1092 aFunc
= maMat
.walk(std::move(aFunc
));
1096 void ScMatrixImpl::CompareGreaterEqual()
1098 MatrixImplType::size_pair_type aSize
= maMat
.size();
1099 CompareMatrixElemFunc
<ElemGreaterEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1100 aFunc
= maMat
.walk(std::move(aFunc
));
1109 void operate(double fVal
) { mbResult
&= (fVal
!= 0.0); }
1110 bool result() const { return mbResult
; }
1111 AndEvaluator() : mbResult(true) {}
1117 void operate(double fVal
) { mbResult
|= (fVal
!= 0.0); }
1118 bool result() const { return mbResult
; }
1119 OrEvaluator() : mbResult(false) {}
1125 void operate(double fVal
) { mbResult
^= (fVal
!= 0.0); }
1126 bool result() const { return mbResult
; }
1127 XorEvaluator() : mbResult(false) {}
1130 // Do not short circuit logical operations, in case there are error values
1131 // these need to be propagated even if the result was determined earlier.
1132 template <typename Evaluator
>
1133 double EvalMatrix(const MatrixImplType
& rMat
)
1136 size_t nRows
= rMat
.size().row
, nCols
= rMat
.size().column
;
1137 for (size_t i
= 0; i
< nRows
; ++i
)
1139 for (size_t j
= 0; j
< nCols
; ++j
)
1141 MatrixImplType::const_position_type aPos
= rMat
.position(i
, j
);
1142 mdds::mtm::element_t eType
= rMat
.get_type(aPos
);
1143 if (eType
!= mdds::mtm::element_numeric
&& eType
!= mdds::mtm::element_boolean
)
1144 // assuming a CompareMat this is an error
1145 return CreateDoubleError(FormulaError::IllegalArgument
);
1147 double fVal
= rMat
.get_numeric(aPos
);
1148 if (!std::isfinite(fVal
))
1152 aEval
.operate(fVal
);
1155 return aEval
.result();
1160 double ScMatrixImpl::And() const
1162 // All elements must be of value type.
1163 // True only if all the elements have non-zero values.
1164 return EvalMatrix
<AndEvaluator
>(maMat
);
1167 double ScMatrixImpl::Or() const
1169 // All elements must be of value type.
1170 // True if at least one element has a non-zero value.
1171 return EvalMatrix
<OrEvaluator
>(maMat
);
1174 double ScMatrixImpl::Xor() const
1176 // All elements must be of value type.
1177 // True if an odd number of elements have a non-zero value.
1178 return EvalMatrix
<XorEvaluator
>(maMat
);
1183 template<typename Op
, typename tRes
>
1184 class WalkElementBlocks
1187 ScMatrix::IterateResult
<tRes
> maRes
;
1188 bool mbTextAsZero
:1;
1189 bool mbIgnoreErrorValues
:1;
1191 WalkElementBlocks(bool bTextAsZero
, bool bIgnoreErrorValues
) :
1192 maRes(Op::InitVal
, 0),
1193 mbTextAsZero(bTextAsZero
), mbIgnoreErrorValues(bIgnoreErrorValues
)
1196 const ScMatrix::IterateResult
<tRes
>& getResult() const { return maRes
; }
1198 void operator() (const MatrixImplType::element_block_node_type
& node
)
1202 case mdds::mtm::element_numeric
:
1204 typedef MatrixImplType::numeric_block_type block_type
;
1206 size_t nIgnored
= 0;
1207 block_type::const_iterator it
= block_type::begin(*node
.data
);
1208 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1209 for (; it
!= itEnd
; ++it
)
1211 if (mbIgnoreErrorValues
&& !std::isfinite(*it
))
1216 maOp(maRes
.maAccumulator
, *it
);
1218 maRes
.mnCount
+= node
.size
- nIgnored
;
1221 case mdds::mtm::element_boolean
:
1223 typedef MatrixImplType::boolean_block_type block_type
;
1225 block_type::const_iterator it
= block_type::begin(*node
.data
);
1226 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1227 for (; it
!= itEnd
; ++it
)
1229 maOp(maRes
.maAccumulator
, *it
);
1231 maRes
.mnCount
+= node
.size
;
1234 case mdds::mtm::element_string
:
1236 maRes
.mnCount
+= node
.size
;
1238 case mdds::mtm::element_empty
:
1245 template<typename Op
, typename tRes
>
1246 class WalkElementBlocksMultipleValues
1248 const std::vector
<Op
>* mpOp
;
1249 ScMatrix::IterateResultMultiple
<tRes
> maRes
;
1251 WalkElementBlocksMultipleValues(const std::vector
<Op
>& aOp
) :
1252 mpOp(&aOp
), maRes(0)
1254 for (const auto& rpOp
: *mpOp
)
1255 maRes
.maAccumulator
.emplace_back(rpOp
.mInitVal
);
1258 WalkElementBlocksMultipleValues( const WalkElementBlocksMultipleValues
& ) = delete;
1259 WalkElementBlocksMultipleValues
& operator= ( const WalkElementBlocksMultipleValues
& ) = delete;
1261 WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues
&& r
) noexcept
1262 : mpOp(r
.mpOp
), maRes(r
.maRes
.mnCount
)
1264 maRes
.maAccumulator
= std::move(r
.maRes
.maAccumulator
);
1267 WalkElementBlocksMultipleValues
& operator=(WalkElementBlocksMultipleValues
&& r
) noexcept
1270 maRes
.maAccumulator
= std::move(r
.maRes
.maAccumulator
);
1271 maRes
.mnCount
= r
.maRes
.mnCount
;
1275 const ScMatrix::IterateResultMultiple
<tRes
>& getResult() const { return maRes
; }
1277 void operator() (const MatrixImplType::element_block_node_type
& node
)
1281 case mdds::mtm::element_numeric
:
1283 typedef MatrixImplType::numeric_block_type block_type
;
1285 block_type::const_iterator it
= block_type::begin(*node
.data
);
1286 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1287 for (; it
!= itEnd
; ++it
)
1289 for (size_t i
= 0u; i
< mpOp
->size(); ++i
)
1290 (*mpOp
)[i
](maRes
.maAccumulator
[i
], *it
);
1292 maRes
.mnCount
+= node
.size
;
1295 case mdds::mtm::element_boolean
:
1297 typedef MatrixImplType::boolean_block_type block_type
;
1299 block_type::const_iterator it
= block_type::begin(*node
.data
);
1300 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1301 for (; it
!= itEnd
; ++it
)
1303 for (size_t i
= 0u; i
< mpOp
->size(); ++i
)
1304 (*mpOp
)[i
](maRes
.maAccumulator
[i
], *it
);
1306 maRes
.mnCount
+= node
.size
;
1309 case mdds::mtm::element_string
:
1310 case mdds::mtm::element_empty
:
1322 bool mbIgnoreEmptyStrings
;
1324 explicit CountElements(bool bCountString
, bool bCountErrors
, bool bIgnoreEmptyStrings
) :
1325 mnCount(0), mbCountString(bCountString
), mbCountErrors(bCountErrors
),
1326 mbIgnoreEmptyStrings(bIgnoreEmptyStrings
) {}
1328 size_t getCount() const { return mnCount
; }
1330 void operator() (const MatrixImplType::element_block_node_type
& node
)
1334 case mdds::mtm::element_numeric
:
1335 mnCount
+= node
.size
;
1338 typedef MatrixImplType::numeric_block_type block_type
;
1340 block_type::const_iterator it
= block_type::begin(*node
.data
);
1341 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1342 for (; it
!= itEnd
; ++it
)
1344 if (!std::isfinite(*it
))
1349 case mdds::mtm::element_boolean
:
1350 mnCount
+= node
.size
;
1352 case mdds::mtm::element_string
:
1355 mnCount
+= node
.size
;
1356 if (mbIgnoreEmptyStrings
)
1358 typedef MatrixImplType::string_block_type block_type
;
1360 block_type::const_iterator it
= block_type::begin(*node
.data
);
1361 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1362 for (; it
!= itEnd
; ++it
)
1370 case mdds::mtm::element_empty
:
1377 const size_t ResultNotSet
= std::numeric_limits
<size_t>::max();
1379 template<typename Type
>
1380 class WalkAndMatchElements
1383 size_t mnStartIndex
;
1389 WalkAndMatchElements(Type aMatchValue
, const MatrixImplType::size_pair_type
& aSize
, size_t nCol1
, size_t nCol2
) :
1390 maMatchValue(std::move(aMatchValue
)),
1391 mnStartIndex( nCol1
* aSize
.row
),
1392 mnStopIndex( (nCol2
+ 1) * aSize
.row
),
1393 mnResult(ResultNotSet
),
1396 assert( nCol1
< aSize
.column
&& nCol2
< aSize
.column
);
1399 size_t getMatching() const { return mnResult
; }
1401 size_t getRemainingCount() const
1403 return mnIndex
< mnStopIndex
? mnStopIndex
- mnIndex
: 0;
1406 size_t compare(const MatrixImplType::element_block_node_type
& node
) const;
1408 void operator() (const MatrixImplType::element_block_node_type
& node
)
1410 // early exit if match already found
1411 if (mnResult
!= ResultNotSet
)
1414 // limit lookup to the requested columns
1415 if (mnStartIndex
<= mnIndex
&& getRemainingCount() > 0)
1417 mnResult
= compare(node
);
1420 mnIndex
+= node
.size
;
1425 size_t WalkAndMatchElements
<double>::compare(const MatrixImplType::element_block_node_type
& node
) const
1430 case mdds::mtm::element_numeric
:
1432 typedef MatrixImplType::numeric_block_type block_type
;
1434 block_type::const_iterator it
= block_type::begin(*node
.data
);
1435 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1436 const size_t nRemaining
= getRemainingCount();
1437 for (; it
!= itEnd
&& nCount
< nRemaining
; ++it
, ++nCount
)
1439 if (*it
== maMatchValue
)
1441 return mnIndex
+ nCount
;
1446 case mdds::mtm::element_boolean
:
1448 typedef MatrixImplType::boolean_block_type block_type
;
1450 block_type::const_iterator it
= block_type::begin(*node
.data
);
1451 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1452 const size_t nRemaining
= getRemainingCount();
1453 for (; it
!= itEnd
&& nCount
< nRemaining
; ++it
, ++nCount
)
1455 if (int(*it
) == maMatchValue
)
1457 return mnIndex
+ nCount
;
1463 case mdds::mtm::element_string
:
1464 case mdds::mtm::element_empty
:
1468 return ResultNotSet
;
1472 size_t WalkAndMatchElements
<svl::SharedString
>::compare(const MatrixImplType::element_block_node_type
& node
) const
1476 case mdds::mtm::element_string
:
1479 typedef MatrixImplType::string_block_type block_type
;
1481 block_type::const_iterator it
= block_type::begin(*node
.data
);
1482 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1483 const size_t nRemaining
= getRemainingCount();
1484 for (; it
!= itEnd
&& nCount
< nRemaining
; ++it
, ++nCount
)
1486 if (it
->getDataIgnoreCase() == maMatchValue
.getDataIgnoreCase())
1488 return mnIndex
+ nCount
;
1493 case mdds::mtm::element_boolean
:
1494 case mdds::mtm::element_numeric
:
1495 case mdds::mtm::element_empty
:
1499 return ResultNotSet
;
1504 static double init() { return -std::numeric_limits
<double>::max(); }
1505 static double compare(double left
, double right
)
1507 if (!std::isfinite(left
))
1509 if (!std::isfinite(right
))
1511 return std::max(left
, right
);
1514 static double boolValue(
1515 MatrixImplType::boolean_block_type::const_iterator it
,
1516 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1518 // If the array has at least one true value, the maximum value is 1.
1519 it
= std::find(it
, itEnd
, true);
1520 return it
== itEnd
? 0.0 : 1.0;
1526 static double init() { return std::numeric_limits
<double>::max(); }
1527 static double compare(double left
, double right
)
1529 if (!std::isfinite(left
))
1531 if (!std::isfinite(right
))
1533 return std::min(left
, right
);
1536 static double boolValue(
1537 MatrixImplType::boolean_block_type::const_iterator it
,
1538 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1540 // If the array has at least one false value, the minimum value is 0.
1541 it
= std::find(it
, itEnd
, false);
1542 return it
== itEnd
? 1.0 : 0.0;
1548 static double init() { return 1.0; }
1549 static double calculate(double fx
,double fy
)
1551 return (fx
*fy
)/ScInterpreter::ScGetGCD(fx
,fy
);
1554 static double boolValue(
1555 MatrixImplType::boolean_block_type::const_iterator it
,
1556 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1558 // If the array has at least one false value, the minimum value is 0.
1559 it
= std::find(it
, itEnd
, false);
1560 return it
== itEnd
? 1.0 : 0.0;
1566 static double init() { return 0.0; }
1567 static double calculate(double fx
,double fy
)
1569 return ScInterpreter::ScGetGCD(fx
,fy
);
1572 static double boolValue(
1573 MatrixImplType::boolean_block_type::const_iterator it
,
1574 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1576 // If the array has at least one true value, the gcdResult is 1.
1577 it
= std::find(it
, itEnd
, true);
1578 return it
== itEnd
? 0.0 : 1.0;
1582 template<typename Op
>
1583 class CalcMaxMinValue
1587 bool mbIgnoreErrorValues
;
1590 CalcMaxMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) :
1592 mbTextAsZero(bTextAsZero
),
1593 mbIgnoreErrorValues(bIgnoreErrorValues
),
1594 mbHasValue(false) {}
1596 double getValue() const { return mbHasValue
? mfVal
: 0.0; }
1598 void operator() (const MatrixImplType::element_block_node_type
& node
)
1603 case mdds::mtm::element_numeric
:
1605 typedef MatrixImplType::numeric_block_type block_type
;
1607 block_type::const_iterator it
= block_type::begin(*node
.data
);
1608 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1609 if (mbIgnoreErrorValues
)
1611 for (; it
!= itEnd
; ++it
)
1613 if (std::isfinite(*it
))
1614 mfVal
= Op::compare(mfVal
, *it
);
1619 for (; it
!= itEnd
; ++it
)
1620 mfVal
= Op::compare(mfVal
, *it
);
1626 case mdds::mtm::element_boolean
:
1628 typedef MatrixImplType::boolean_block_type block_type
;
1630 block_type::const_iterator it
= block_type::begin(*node
.data
);
1631 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1632 double fVal
= Op::boolValue(it
, itEnd
);
1633 mfVal
= Op::compare(mfVal
, fVal
);
1637 case mdds::mtm::element_string
:
1638 case mdds::mtm::element_empty
:
1640 // empty elements are treated as empty strings.
1643 mfVal
= Op::compare(mfVal
, 0.0);
1654 template<typename Op
>
1660 CalcGcdLcm() : mfval(Op::init()) {}
1662 double getResult() const { return mfval
; }
1664 void operator() ( const MatrixImplType::element_block_node_type
& node
)
1668 case mdds::mtm::element_numeric
:
1670 typedef MatrixImplType::numeric_block_type block_type
;
1671 block_type::const_iterator it
= block_type::begin(*node
.data
);
1672 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1674 for ( ; it
!= itEnd
; ++it
)
1677 mfval
= CreateDoubleError(FormulaError::IllegalArgument
);
1679 mfval
= ::rtl::math::approxFloor( Op::calculate(*it
,mfval
));
1683 case mdds::mtm::element_boolean
:
1685 typedef MatrixImplType::boolean_block_type block_type
;
1686 block_type::const_iterator it
= block_type::begin(*node
.data
);
1687 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1689 mfval
= Op::boolValue(it
, itEnd
);
1692 case mdds::mtm::element_empty
:
1693 case mdds::mtm::element_string
:
1695 mfval
= CreateDoubleError(FormulaError::IllegalArgument
);
1704 double evaluate( double fVal
, ScQueryOp eOp
)
1706 if (!std::isfinite(fVal
))
1712 return fVal
== 0.0 ? 1.0 : 0.0;
1714 return fVal
< 0.0 ? 1.0 : 0.0;
1716 return fVal
> 0.0 ? 1.0 : 0.0;
1718 return fVal
<= 0.0 ? 1.0 : 0.0;
1719 case SC_GREATER_EQUAL
:
1720 return fVal
>= 0.0 ? 1.0 : 0.0;
1722 return fVal
!= 0.0 ? 1.0 : 0.0;
1727 SAL_WARN("sc.core", "evaluate: unhandled comparison operator: " << static_cast<int>(eOp
));
1728 return CreateDoubleError( FormulaError::UnknownState
);
1731 class CompareMatrixFunc
1733 sc::Compare
& mrComp
;
1735 sc::CompareOptions
* mpOptions
;
1736 std::vector
<double> maResValues
; // double instead of bool to transport error values
1740 double fVal
= sc::CompareFunc( mrComp
, mpOptions
);
1741 maResValues
.push_back(evaluate(fVal
, mrComp
.meOp
));
1745 CompareMatrixFunc( size_t nResSize
, sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) :
1746 mrComp(rComp
), mnMatPos(nMatPos
), mpOptions(pOptions
)
1748 maResValues
.reserve(nResSize
);
1751 CompareMatrixFunc( const CompareMatrixFunc
& ) = delete;
1752 CompareMatrixFunc
& operator= ( const CompareMatrixFunc
& ) = delete;
1754 CompareMatrixFunc(CompareMatrixFunc
&& r
) noexcept
:
1756 mnMatPos(r
.mnMatPos
),
1757 mpOptions(r
.mpOptions
),
1758 maResValues(std::move(r
.maResValues
)) {}
1760 CompareMatrixFunc
& operator=(CompareMatrixFunc
&& r
) noexcept
1763 mnMatPos
= r
.mnMatPos
;
1764 mpOptions
= r
.mpOptions
;
1765 maResValues
= std::move(r
.maResValues
);
1769 void operator() (const MatrixImplType::element_block_node_type
& node
)
1771 sc::Compare::Cell
& rCell
= mrComp
.maCells
[mnMatPos
];
1775 case mdds::mtm::element_numeric
:
1777 typedef MatrixImplType::numeric_block_type block_type
;
1779 block_type::const_iterator it
= block_type::begin(*node
.data
);
1780 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1781 for (; it
!= itEnd
; ++it
)
1783 rCell
.mbValue
= true;
1784 rCell
.mbEmpty
= false;
1785 rCell
.mfValue
= *it
;
1790 case mdds::mtm::element_boolean
:
1792 typedef MatrixImplType::boolean_block_type block_type
;
1794 block_type::const_iterator it
= block_type::begin(*node
.data
);
1795 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1796 for (; it
!= itEnd
; ++it
)
1798 rCell
.mbValue
= true;
1799 rCell
.mbEmpty
= false;
1800 rCell
.mfValue
= double(*it
);
1805 case mdds::mtm::element_string
:
1807 typedef MatrixImplType::string_block_type block_type
;
1809 block_type::const_iterator it
= block_type::begin(*node
.data
);
1810 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1811 for (; it
!= itEnd
; ++it
)
1813 const svl::SharedString
& rStr
= *it
;
1814 rCell
.mbValue
= false;
1815 rCell
.mbEmpty
= false;
1821 case mdds::mtm::element_empty
:
1823 rCell
.mbValue
= false;
1824 rCell
.mbEmpty
= true;
1825 rCell
.maStr
= svl::SharedString::getEmptyString();
1826 for (size_t i
= 0; i
< node
.size
; ++i
)
1835 const std::vector
<double>& getValues() const
1842 * Left-hand side is a matrix while the right-hand side is a numeric value.
1844 class CompareMatrixToNumericFunc
1846 sc::Compare
& mrComp
;
1847 double mfRightValue
;
1848 sc::CompareOptions
* mpOptions
;
1849 std::vector
<double> maResValues
; // double instead of bool to transport error values
1853 double fVal
= sc::CompareFunc(mrComp
.maCells
[0], mfRightValue
, mpOptions
);
1854 maResValues
.push_back(evaluate(fVal
, mrComp
.meOp
));
1857 void compareLeftNumeric( double fLeftVal
)
1859 double fVal
= sc::CompareFunc(fLeftVal
, mfRightValue
);
1860 maResValues
.push_back(evaluate(fVal
, mrComp
.meOp
));
1863 void compareLeftEmpty( size_t nSize
)
1865 double fVal
= sc::CompareEmptyToNumericFunc(mfRightValue
);
1866 bool bRes
= evaluate(fVal
, mrComp
.meOp
);
1867 maResValues
.resize(maResValues
.size() + nSize
, bRes
? 1.0 : 0.0);
1871 CompareMatrixToNumericFunc( size_t nResSize
, sc::Compare
& rComp
, double fRightValue
, sc::CompareOptions
* pOptions
) :
1872 mrComp(rComp
), mfRightValue(fRightValue
), mpOptions(pOptions
)
1874 maResValues
.reserve(nResSize
);
1877 CompareMatrixToNumericFunc( const CompareMatrixToNumericFunc
& ) = delete;
1878 CompareMatrixToNumericFunc
& operator= ( const CompareMatrixToNumericFunc
& ) = delete;
1880 CompareMatrixToNumericFunc(CompareMatrixToNumericFunc
&& r
) noexcept
:
1882 mfRightValue(r
.mfRightValue
),
1883 mpOptions(r
.mpOptions
),
1884 maResValues(std::move(r
.maResValues
)) {}
1886 CompareMatrixToNumericFunc
& operator=(CompareMatrixToNumericFunc
&& r
) noexcept
1889 mfRightValue
= r
.mfRightValue
;
1890 mpOptions
= r
.mpOptions
;
1891 maResValues
= std::move(r
.maResValues
);
1895 void operator() (const MatrixImplType::element_block_node_type
& node
)
1899 case mdds::mtm::element_numeric
:
1901 typedef MatrixImplType::numeric_block_type block_type
;
1903 block_type::const_iterator it
= block_type::begin(*node
.data
);
1904 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1905 for (; it
!= itEnd
; ++it
)
1906 compareLeftNumeric(*it
);
1909 case mdds::mtm::element_boolean
:
1911 typedef MatrixImplType::boolean_block_type block_type
;
1913 block_type::const_iterator it
= block_type::begin(*node
.data
);
1914 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1915 for (; it
!= itEnd
; ++it
)
1916 compareLeftNumeric(double(*it
));
1919 case mdds::mtm::element_string
:
1921 typedef MatrixImplType::string_block_type block_type
;
1923 block_type::const_iterator it
= block_type::begin(*node
.data
);
1924 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1925 for (; it
!= itEnd
; ++it
)
1927 const svl::SharedString
& rStr
= *it
;
1928 sc::Compare::Cell
& rCell
= mrComp
.maCells
[0];
1929 rCell
.mbValue
= false;
1930 rCell
.mbEmpty
= false;
1936 case mdds::mtm::element_empty
:
1937 compareLeftEmpty(node
.size
);
1944 const std::vector
<double>& getValues() const
1952 std::vector
<double> maArray
;
1953 std::vector
<double>::iterator miPos
;
1957 void moveArray( ToDoubleArray
& r
)
1959 // Re-create the iterator from the new array after the array has been
1960 // moved, to ensure that the iterator points to a valid array
1962 size_t n
= std::distance(r
.maArray
.begin(), r
.miPos
);
1963 maArray
= std::move(r
.maArray
);
1964 miPos
= maArray
.begin();
1965 std::advance(miPos
, n
);
1969 ToDoubleArray( size_t nSize
, bool bEmptyAsZero
) :
1970 maArray(nSize
, 0.0), miPos(maArray
.begin()), mbEmptyAsZero(bEmptyAsZero
)
1972 mfNaN
= CreateDoubleError( FormulaError::ElementNaN
);
1975 ToDoubleArray( const ToDoubleArray
& ) = delete;
1976 ToDoubleArray
& operator= ( const ToDoubleArray
& ) = delete;
1978 ToDoubleArray(ToDoubleArray
&& r
) noexcept
:
1979 mfNaN(r
.mfNaN
), mbEmptyAsZero(r
.mbEmptyAsZero
)
1984 ToDoubleArray
& operator=(ToDoubleArray
&& r
) noexcept
1987 mbEmptyAsZero
= r
.mbEmptyAsZero
;
1992 void operator() (const MatrixImplType::element_block_node_type
& node
)
1994 using namespace mdds::mtv
;
1998 case mdds::mtm::element_numeric
:
2000 double_element_block::const_iterator it
= double_element_block::begin(*node
.data
);
2001 double_element_block::const_iterator itEnd
= double_element_block::end(*node
.data
);
2002 for (; it
!= itEnd
; ++it
, ++miPos
)
2006 case mdds::mtm::element_boolean
:
2008 boolean_element_block::const_iterator it
= boolean_element_block::begin(*node
.data
);
2009 boolean_element_block::const_iterator itEnd
= boolean_element_block::end(*node
.data
);
2010 for (; it
!= itEnd
; ++it
, ++miPos
)
2011 *miPos
= *it
? 1.0 : 0.0;
2014 case mdds::mtm::element_string
:
2016 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2020 case mdds::mtm::element_empty
:
2024 std::advance(miPos
, node
.size
);
2028 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2037 void swap(std::vector
<double>& rOther
)
2039 maArray
.swap(rOther
);
2045 double operator() (const double& lhs
, const double& rhs
) const
2051 template<typename Op
>
2052 class MergeDoubleArrayFunc
2054 std::vector
<double>::iterator miPos
;
2057 MergeDoubleArrayFunc(std::vector
<double>& rArray
) : miPos(rArray
.begin())
2059 mfNaN
= CreateDoubleError( FormulaError::ElementNaN
);
2062 MergeDoubleArrayFunc( const MergeDoubleArrayFunc
& ) = delete;
2063 MergeDoubleArrayFunc
& operator= ( const MergeDoubleArrayFunc
& ) = delete;
2065 MergeDoubleArrayFunc( MergeDoubleArrayFunc
&& ) = default;
2066 MergeDoubleArrayFunc
& operator= ( MergeDoubleArrayFunc
&& ) = default;
2068 void operator() (const MatrixImplType::element_block_node_type
& node
)
2070 using namespace mdds::mtv
;
2075 case mdds::mtm::element_numeric
:
2077 double_element_block::const_iterator it
= double_element_block::begin(*node
.data
);
2078 double_element_block::const_iterator itEnd
= double_element_block::end(*node
.data
);
2079 for (; it
!= itEnd
; ++it
, ++miPos
)
2081 if (GetDoubleErrorValue(*miPos
) == FormulaError::ElementNaN
)
2084 *miPos
= op(*miPos
, *it
);
2088 case mdds::mtm::element_boolean
:
2090 boolean_element_block::const_iterator it
= boolean_element_block::begin(*node
.data
);
2091 boolean_element_block::const_iterator itEnd
= boolean_element_block::end(*node
.data
);
2092 for (; it
!= itEnd
; ++it
, ++miPos
)
2094 if (GetDoubleErrorValue(*miPos
) == FormulaError::ElementNaN
)
2097 *miPos
= op(*miPos
, *it
? 1.0 : 0.0);
2101 case mdds::mtm::element_string
:
2103 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2107 case mdds::mtm::element_empty
:
2109 // Empty element is equivalent of having a numeric value of 0.0.
2110 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2112 if (GetDoubleErrorValue(*miPos
) == FormulaError::ElementNaN
)
2115 *miPos
= op(*miPos
, 0.0);
2129 template<typename TOp
, typename tRes
>
2130 ScMatrix::IterateResult
<tRes
> GetValueWithCount(bool bTextAsZero
, bool bIgnoreErrorValues
, const MatrixImplType
& maMat
)
2132 WalkElementBlocks
<TOp
, tRes
> aFunc(bTextAsZero
, bIgnoreErrorValues
);
2133 aFunc
= maMat
.walk(aFunc
);
2134 return aFunc
.getResult();
2139 ScMatrix::KahanIterateResult
ScMatrixImpl::Sum(bool bTextAsZero
, bool bIgnoreErrorValues
) const
2141 return GetValueWithCount
<sc::op::Sum
, KahanSum
>(bTextAsZero
, bIgnoreErrorValues
, maMat
);
2144 ScMatrix::KahanIterateResult
ScMatrixImpl::SumSquare(bool bTextAsZero
, bool bIgnoreErrorValues
) const
2146 return GetValueWithCount
<sc::op::SumSquare
, KahanSum
>(bTextAsZero
, bIgnoreErrorValues
, maMat
);
2149 ScMatrix::DoubleIterateResult
ScMatrixImpl::Product(bool bTextAsZero
, bool bIgnoreErrorValues
) const
2151 return GetValueWithCount
<sc::op::Product
, double>(bTextAsZero
, bIgnoreErrorValues
, maMat
);
2154 size_t ScMatrixImpl::Count(bool bCountStrings
, bool bCountErrors
, bool bIgnoreEmptyStrings
) const
2156 CountElements
aFunc(bCountStrings
, bCountErrors
, bIgnoreEmptyStrings
);
2157 aFunc
= maMat
.walk(aFunc
);
2158 return aFunc
.getCount();
2161 size_t ScMatrixImpl::MatchDoubleInColumns(double fValue
, size_t nCol1
, size_t nCol2
) const
2163 WalkAndMatchElements
<double> aFunc(fValue
, maMat
.size(), nCol1
, nCol2
);
2164 aFunc
= maMat
.walk(aFunc
);
2165 return aFunc
.getMatching();
2168 size_t ScMatrixImpl::MatchStringInColumns(const svl::SharedString
& rStr
, size_t nCol1
, size_t nCol2
) const
2170 WalkAndMatchElements
<svl::SharedString
> aFunc(rStr
, maMat
.size(), nCol1
, nCol2
);
2171 aFunc
= maMat
.walk(aFunc
);
2172 return aFunc
.getMatching();
2175 double ScMatrixImpl::GetMaxValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
2177 CalcMaxMinValue
<MaxOp
> aFunc(bTextAsZero
, bIgnoreErrorValues
);
2178 aFunc
= maMat
.walk(aFunc
);
2179 return aFunc
.getValue();
2182 double ScMatrixImpl::GetMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
2184 CalcMaxMinValue
<MinOp
> aFunc(bTextAsZero
, bIgnoreErrorValues
);
2185 aFunc
= maMat
.walk(aFunc
);
2186 return aFunc
.getValue();
2189 double ScMatrixImpl::GetGcd() const
2191 CalcGcdLcm
<Gcd
> aFunc
;
2192 aFunc
= maMat
.walk(aFunc
);
2193 return aFunc
.getResult();
2196 double ScMatrixImpl::GetLcm() const
2198 CalcGcdLcm
<Lcm
> aFunc
;
2199 aFunc
= maMat
.walk(aFunc
);
2200 return aFunc
.getResult();
2203 ScMatrixRef
ScMatrixImpl::CompareMatrix(
2204 sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) const
2206 MatrixImplType::size_pair_type aSize
= maMat
.size();
2207 size_t nSize
= aSize
.column
* aSize
.row
;
2210 if (rComp
.maCells
[1].mbValue
&& !rComp
.maCells
[1].mbEmpty
)
2212 // Matrix on the left, and a numeric value on the right. Use a
2213 // function object that has much less branching for much better
2215 CompareMatrixToNumericFunc
aFunc(nSize
, rComp
, rComp
.maCells
[1].mfValue
, pOptions
);
2216 aFunc
= maMat
.walk(std::move(aFunc
));
2218 // We assume the result matrix has the same dimension as this matrix.
2219 const std::vector
<double>& rResVal
= aFunc
.getValues();
2220 assert (nSize
== rResVal
.size());
2221 if (nSize
!= rResVal
.size())
2222 return ScMatrixRef();
2224 return ScMatrixRef(new ScMatrix(aSize
.column
, aSize
.row
, rResVal
));
2228 CompareMatrixFunc
aFunc(nSize
, rComp
, nMatPos
, pOptions
);
2229 aFunc
= maMat
.walk(std::move(aFunc
));
2231 // We assume the result matrix has the same dimension as this matrix.
2232 const std::vector
<double>& rResVal
= aFunc
.getValues();
2233 assert (nSize
== rResVal
.size());
2234 if (nSize
!= rResVal
.size())
2235 return ScMatrixRef();
2237 return ScMatrixRef(new ScMatrix(aSize
.column
, aSize
.row
, rResVal
));
2240 void ScMatrixImpl::GetDoubleArray( std::vector
<double>& rArray
, bool bEmptyAsZero
) const
2242 MatrixImplType::size_pair_type aSize
= maMat
.size();
2243 ToDoubleArray
aFunc(aSize
.row
*aSize
.column
, bEmptyAsZero
);
2244 aFunc
= maMat
.walk(std::move(aFunc
));
2248 void ScMatrixImpl::MergeDoubleArrayMultiply( std::vector
<double>& rArray
) const
2250 MatrixImplType::size_pair_type aSize
= maMat
.size();
2251 size_t nSize
= aSize
.row
*aSize
.column
;
2252 if (nSize
!= rArray
.size())
2255 MergeDoubleArrayFunc
<ArrayMul
> aFunc(rArray
);
2256 maMat
.walk(std::move(aFunc
));
2261 template<typename T
, typename U
, typename return_type
>
2262 struct wrapped_iterator
2264 typedef ::std::bidirectional_iterator_tag iterator_category
;
2265 typedef typename
T::const_iterator::value_type old_value_type
;
2266 typedef return_type value_type
;
2267 typedef value_type
* pointer
;
2268 typedef value_type
& reference
;
2269 typedef typename
T::const_iterator::difference_type difference_type
;
2271 typename
T::const_iterator it
;
2272 mutable value_type val
;
2277 value_type
calcVal() const
2284 wrapped_iterator(typename
T::const_iterator it_
, U
const & aOp
):
2291 wrapped_iterator(const wrapped_iterator
& r
):
2298 wrapped_iterator
& operator=(const wrapped_iterator
& r
)
2304 bool operator==(const wrapped_iterator
& r
) const
2309 bool operator!=(const wrapped_iterator
& r
) const
2311 return !operator==(r
);
2314 wrapped_iterator
& operator++()
2321 wrapped_iterator
& operator--()
2328 value_type
& operator*() const
2334 pointer
operator->() const
2341 template<typename T
, typename U
, typename return_type
>
2342 struct MatrixIteratorWrapper
2345 typename
T::const_iterator m_itBegin
;
2346 typename
T::const_iterator m_itEnd
;
2349 MatrixIteratorWrapper(typename
T::const_iterator itBegin
, typename
T::const_iterator itEnd
, U
const & aOp
):
2350 m_itBegin(std::move(itBegin
)),
2351 m_itEnd(std::move(itEnd
)),
2356 wrapped_iterator
<T
, U
, return_type
> begin()
2358 return wrapped_iterator
<T
, U
, return_type
>(m_itBegin
, maOp
);
2361 wrapped_iterator
<T
, U
, return_type
> end()
2363 return wrapped_iterator
<T
, U
, return_type
>(m_itEnd
, maOp
);
2367 MatrixImplType::position_type
increment_position(const MatrixImplType::position_type
& pos
, size_t n
)
2369 MatrixImplType::position_type ret
= pos
;
2372 if (ret
.second
+ n
< ret
.first
->size
)
2379 n
-= (ret
.first
->size
- ret
.second
);
2388 template<typename T
>
2389 struct MatrixOpWrapper
2392 MatrixImplType
& mrMat
;
2393 MatrixImplType::position_type pos
;
2397 MatrixOpWrapper(MatrixImplType
& rMat
, const T
& aOp
):
2399 pos(rMat
.position(0,0)),
2404 MatrixOpWrapper( const MatrixOpWrapper
& r
) : mrMat(r
.mrMat
), pos(r
.pos
), mpOp(r
.mpOp
) {}
2406 MatrixOpWrapper
& operator= ( const MatrixOpWrapper
& r
) = default;
2408 void operator()(const MatrixImplType::element_block_node_type
& node
)
2412 case mdds::mtm::element_numeric
:
2414 typedef MatrixImplType::numeric_block_type block_type
;
2416 block_type::const_iterator it
= block_type::begin(*node
.data
);
2417 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
2418 MatrixIteratorWrapper
<block_type
, T
, typename
T::number_value_type
> aFunc(it
, itEnd
, *mpOp
);
2419 pos
= mrMat
.set(pos
,aFunc
.begin(), aFunc
.end());
2422 case mdds::mtm::element_boolean
:
2424 typedef MatrixImplType::boolean_block_type block_type
;
2426 block_type::const_iterator it
= block_type::begin(*node
.data
);
2427 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
2429 MatrixIteratorWrapper
<block_type
, T
, typename
T::number_value_type
> aFunc(it
, itEnd
, *mpOp
);
2430 pos
= mrMat
.set(pos
, aFunc
.begin(), aFunc
.end());
2433 case mdds::mtm::element_string
:
2435 typedef MatrixImplType::string_block_type block_type
;
2437 block_type::const_iterator it
= block_type::begin(*node
.data
);
2438 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
2440 MatrixIteratorWrapper
<block_type
, T
, typename
T::number_value_type
> aFunc(it
, itEnd
, *mpOp
);
2441 pos
= mrMat
.set(pos
, aFunc
.begin(), aFunc
.end());
2444 case mdds::mtm::element_empty
:
2446 if (mpOp
->useFunctionForEmpty())
2448 std::vector
<char> aVec(node
.size
);
2449 MatrixIteratorWrapper
<std::vector
<char>, T
, typename
T::number_value_type
>
2450 aFunc(aVec
.begin(), aVec
.end(), *mpOp
);
2451 pos
= mrMat
.set(pos
, aFunc
.begin(), aFunc
.end());
2458 pos
= increment_position(pos
, node
.size
);
2464 template<typename T
>
2465 void ScMatrixImpl::ApplyOperation(T aOp
, ScMatrixImpl
& rMat
)
2467 MatrixOpWrapper
<T
> aFunc(rMat
.maMat
, aOp
);
2471 template<typename T
, typename tRes
>
2472 ScMatrix::IterateResultMultiple
<tRes
> ScMatrixImpl::ApplyCollectOperation(const std::vector
<T
>& aOp
)
2474 WalkElementBlocksMultipleValues
<T
, tRes
> aFunc(aOp
);
2475 aFunc
= maMat
.walk(std::move(aFunc
));
2476 return aFunc
.getResult();
2483 ElementBlock(size_t nRowSize
,
2484 ScMatrix::DoubleOpFunction aDoubleFunc
,
2485 ScMatrix::BoolOpFunction aBoolFunc
,
2486 ScMatrix::StringOpFunction aStringFunc
,
2487 ScMatrix::EmptyOpFunction aEmptyFunc
):
2488 mnRowSize(nRowSize
),
2491 maDoubleFunc(std::move(aDoubleFunc
)),
2492 maBoolFunc(std::move(aBoolFunc
)),
2493 maStringFunc(std::move(aStringFunc
)),
2494 maEmptyFunc(std::move(aEmptyFunc
))
2502 ScMatrix::DoubleOpFunction maDoubleFunc
;
2503 ScMatrix::BoolOpFunction maBoolFunc
;
2504 ScMatrix::StringOpFunction maStringFunc
;
2505 ScMatrix::EmptyOpFunction maEmptyFunc
;
2508 class WalkElementBlockOperation
2512 WalkElementBlockOperation(ElementBlock
& rElementBlock
)
2513 : mrElementBlock(rElementBlock
)
2517 void operator()(const MatrixImplType::element_block_node_type
& node
)
2521 case mdds::mtm::element_numeric
:
2523 typedef MatrixImplType::numeric_block_type block_type
;
2525 block_type::const_iterator it
= block_type::begin(*node
.data
);
2526 std::advance(it
, node
.offset
);
2527 block_type::const_iterator itEnd
= it
;
2528 std::advance(itEnd
, node
.size
);
2529 for (auto itr
= it
; itr
!= itEnd
; ++itr
)
2531 mrElementBlock
.maDoubleFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
, *itr
);
2532 ++mrElementBlock
.mnRowPos
;
2533 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2535 mrElementBlock
.mnRowPos
= 0;
2536 ++mrElementBlock
.mnColPos
;
2541 case mdds::mtm::element_string
:
2543 typedef MatrixImplType::string_block_type block_type
;
2545 block_type::const_iterator it
= block_type::begin(*node
.data
);
2546 std::advance(it
, node
.offset
);
2547 block_type::const_iterator itEnd
= it
;
2548 std::advance(itEnd
, node
.size
);
2549 for (auto itr
= it
; itr
!= itEnd
; ++itr
)
2551 mrElementBlock
.maStringFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
, *itr
);
2552 ++mrElementBlock
.mnRowPos
;
2553 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2555 mrElementBlock
.mnRowPos
= 0;
2556 ++mrElementBlock
.mnColPos
;
2561 case mdds::mtm::element_boolean
:
2563 typedef MatrixImplType::boolean_block_type block_type
;
2565 block_type::const_iterator it
= block_type::begin(*node
.data
);
2566 std::advance(it
, node
.offset
);
2567 block_type::const_iterator itEnd
= it
;
2568 std::advance(itEnd
, node
.size
);
2569 for (auto itr
= it
; itr
!= itEnd
; ++itr
)
2571 mrElementBlock
.maBoolFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
, *itr
);
2572 ++mrElementBlock
.mnRowPos
;
2573 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2575 mrElementBlock
.mnRowPos
= 0;
2576 ++mrElementBlock
.mnColPos
;
2581 case mdds::mtm::element_empty
:
2583 for (size_t i
=0; i
< node
.size
; ++i
)
2585 mrElementBlock
.maEmptyFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
);
2586 ++mrElementBlock
.mnRowPos
;
2587 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2589 mrElementBlock
.mnRowPos
= 0;
2590 ++mrElementBlock
.mnColPos
;
2595 case mdds::mtm::element_integer
:
2597 SAL_WARN("sc.core","WalkElementBlockOperation - unhandled element_integer");
2598 // No function (yet?), but advance row and column count.
2599 mrElementBlock
.mnColPos
+= node
.size
/ mrElementBlock
.mnRowSize
;
2600 mrElementBlock
.mnRowPos
+= node
.size
% mrElementBlock
.mnRowSize
;
2601 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2603 mrElementBlock
.mnRowPos
= 0;
2604 ++mrElementBlock
.mnColPos
;
2613 ElementBlock
& mrElementBlock
;
2618 void ScMatrixImpl::ExecuteOperation(const std::pair
<size_t, size_t>& rStartPos
,
2619 const std::pair
<size_t, size_t>& rEndPos
, const ScMatrix::DoubleOpFunction
& aDoubleFunc
,
2620 const ScMatrix::BoolOpFunction
& aBoolFunc
, const ScMatrix::StringOpFunction
& aStringFunc
,
2621 const ScMatrix::EmptyOpFunction
& aEmptyFunc
) const
2623 ElementBlock
aPayload(maMat
.size().row
, aDoubleFunc
, aBoolFunc
, aStringFunc
, aEmptyFunc
);
2624 WalkElementBlockOperation
aFunc(aPayload
);
2627 MatrixImplType::size_pair_type(rStartPos
.first
, rStartPos
.second
),
2628 MatrixImplType::size_pair_type(rEndPos
.first
, rEndPos
.second
));
2633 void ScMatrixImpl::Dump() const
2635 cout
<< "-- matrix content" << endl
;
2636 SCSIZE nCols
, nRows
;
2637 GetDimensions(nCols
, nRows
);
2638 for (SCSIZE nRow
= 0; nRow
< nRows
; ++nRow
)
2640 for (SCSIZE nCol
= 0; nCol
< nCols
; ++nCol
)
2642 cout
<< " row=" << nRow
<< ", col=" << nCol
<< " : ";
2643 switch (maMat
.get_type(nRow
, nCol
))
2645 case mdds::mtm::element_string
:
2646 cout
<< "string (" << maMat
.get_string(nRow
, nCol
).getString() << ")";
2648 case mdds::mtm::element_numeric
:
2649 cout
<< "numeric (" << maMat
.get_numeric(nRow
, nCol
) << ")";
2651 case mdds::mtm::element_boolean
:
2652 cout
<< "boolean (" << maMat
.get_boolean(nRow
, nCol
) << ")";
2654 case mdds::mtm::element_empty
:
2667 void ScMatrixImpl::CalcPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const
2669 SCSIZE nRowSize
= maMat
.size().row
;
2670 SAL_WARN_IF( !nRowSize
, "sc.core", "ScMatrixImpl::CalcPosition: 0 rows!");
2671 rC
= nRowSize
> 1 ? nIndex
/ nRowSize
: nIndex
;
2672 rR
= nIndex
- rC
*nRowSize
;
2675 void ScMatrixImpl::CalcTransPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const
2677 SCSIZE nColSize
= maMat
.size().column
;
2678 SAL_WARN_IF(!nColSize
, "sc.core", "ScMatrixImpl::CalcPosition: 0 cols!");
2679 rR
= nColSize
> 1 ? nIndex
/ nColSize
: nIndex
;
2680 rC
= nIndex
- rR
* nColSize
;
2685 size_t get_index(SCSIZE nMaxRow
, size_t nRow
, size_t nCol
, size_t nRowOffset
, size_t nColOffset
)
2687 return nMaxRow
* (nCol
+ nColOffset
) + nRow
+ nRowOffset
;
2692 void ScMatrixImpl::MatConcat(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrixRef
& xMat1
, const ScMatrixRef
& xMat2
,
2693 ScInterpreterContext
& rContext
, svl::SharedStringPool
& rStringPool
)
2697 xMat1
->GetDimensions(nC1
, nR1
);
2698 xMat2
->GetDimensions(nC2
, nR2
);
2700 sal_uInt32 nKey
= rContext
.NFGetStandardFormat( SvNumFormatType::NUMBER
,
2703 std::vector
<OUString
> aString(nMaxCol
* nMaxRow
);
2704 std::vector
<bool> aValid(nMaxCol
* nMaxRow
, true);
2705 std::vector
<FormulaError
> nErrors(nMaxCol
* nMaxRow
,FormulaError::NONE
);
2707 size_t nRowOffset
= 0;
2708 size_t nColOffset
= 0;
2709 std::function
<void(size_t, size_t, double)> aDoubleFunc
=
2710 [&](size_t nRow
, size_t nCol
, double nVal
)
2712 FormulaError nErr
= GetDoubleErrorValue(nVal
);
2713 if (nErr
!= FormulaError::NONE
)
2715 aValid
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = false;
2716 nErrors
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = nErr
;
2719 OUString aStr
= rContext
.NFGetInputLineString( nVal
, nKey
);
2720 aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
;
2723 std::function
<void(size_t, size_t, bool)> aBoolFunc
=
2724 [&](size_t nRow
, size_t nCol
, bool nVal
)
2726 OUString aStr
= rContext
.NFGetInputLineString( nVal
? 1.0 : 0.0, nKey
);
2727 aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
;
2730 std::function
<void(size_t, size_t, const svl::SharedString
&)> aStringFunc
=
2731 [&](size_t nRow
, size_t nCol
, const svl::SharedString
& aStr
)
2733 aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
.getString();
2736 std::function
<void(size_t, size_t)> aEmptyFunc
=
2737 [](size_t /*nRow*/, size_t /*nCol*/)
2739 // Nothing. Concatenating an empty string to an existing string.
2743 if (nC1
== 1 || nR1
== 1)
2745 size_t nRowRep
= nR1
== 1 ? nMaxRow
: 1;
2746 size_t nColRep
= nC1
== 1 ? nMaxCol
: 1;
2748 for (size_t i
= 0; i
< nRowRep
; ++i
)
2751 for (size_t j
= 0; j
< nColRep
; ++j
)
2754 xMat1
->ExecuteOperation(
2755 std::pair
<size_t, size_t>(0, 0),
2756 std::pair
<size_t, size_t>(std::min(nR1
, nMaxRow
) - 1, std::min(nC1
, nMaxCol
) - 1),
2757 aDoubleFunc
, aBoolFunc
, aStringFunc
, aEmptyFunc
);
2762 xMat1
->ExecuteOperation(
2763 std::pair
<size_t, size_t>(0, 0),
2764 std::pair
<size_t, size_t>(nMaxRow
- 1, nMaxCol
- 1),
2765 std::move(aDoubleFunc
), std::move(aBoolFunc
), std::move(aStringFunc
), std::move(aEmptyFunc
));
2767 std::vector
<svl::SharedString
> aSharedString(nMaxCol
*nMaxRow
);
2769 std::function
<void(size_t, size_t, double)> aDoubleFunc2
=
2770 [&](size_t nRow
, size_t nCol
, double nVal
)
2772 FormulaError nErr
= GetDoubleErrorValue(nVal
);
2773 if (nErr
!= FormulaError::NONE
)
2775 aValid
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = false;
2776 nErrors
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = nErr
;
2779 OUString aStr
= rContext
.NFGetInputLineString( nVal
, nKey
);
2780 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
);
2783 std::function
<void(size_t, size_t, bool)> aBoolFunc2
=
2784 [&](size_t nRow
, size_t nCol
, bool nVal
)
2786 OUString aStr
= rContext
.NFGetInputLineString( nVal
? 1.0 : 0.0, nKey
);
2787 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
);
2790 std::function
<void(size_t, size_t, const svl::SharedString
&)> aStringFunc2
=
2791 [&](size_t nRow
, size_t nCol
, const svl::SharedString
& aStr
)
2793 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] =
2794 rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
.getString());
2797 std::function
<void(size_t, size_t)> aEmptyFunc2
=
2798 [&](size_t nRow
, size_t nCol
)
2800 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] =
2801 rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)]);
2806 if (nC2
== 1 || nR2
== 1)
2808 size_t nRowRep
= nR2
== 1 ? nMaxRow
: 1;
2809 size_t nColRep
= nC2
== 1 ? nMaxCol
: 1;
2811 for (size_t i
= 0; i
< nRowRep
; ++i
)
2814 for (size_t j
= 0; j
< nColRep
; ++j
)
2817 xMat2
->ExecuteOperation(
2818 std::pair
<size_t, size_t>(0, 0),
2819 std::pair
<size_t, size_t>(std::min(nR2
, nMaxRow
) - 1, std::min(nC2
, nMaxCol
) - 1),
2820 aDoubleFunc2
, aBoolFunc2
, aStringFunc2
, aEmptyFunc2
);
2825 xMat2
->ExecuteOperation(
2826 std::pair
<size_t, size_t>(0, 0),
2827 std::pair
<size_t, size_t>(nMaxRow
- 1, nMaxCol
- 1),
2828 std::move(aDoubleFunc2
), std::move(aBoolFunc2
), std::move(aStringFunc2
), std::move(aEmptyFunc2
));
2832 MatrixImplType::position_type pos
= maMat
.position(0, 0);
2833 for (SCSIZE i
= 0; i
< nMaxCol
; ++i
)
2835 for (SCSIZE j
= 0; j
< nMaxRow
&& i
< nMaxCol
; ++j
)
2837 if (aValid
[nMaxRow
* i
+ j
])
2839 auto itr
= aValid
.begin();
2840 std::advance(itr
, nMaxRow
* i
+ j
);
2841 auto itrEnd
= std::find(itr
, aValid
.end(), false);
2842 size_t nSteps
= std::distance(itr
, itrEnd
);
2843 auto itrStr
= aSharedString
.begin();
2844 std::advance(itrStr
, nMaxRow
* i
+ j
);
2845 auto itrEndStr
= itrStr
;
2846 std::advance(itrEndStr
, nSteps
);
2847 pos
= maMat
.set(pos
, itrStr
, itrEndStr
);
2848 size_t nColSteps
= nSteps
/ nMaxRow
;
2850 j
+= nSteps
% nMaxRow
;
2859 pos
= maMat
.set(pos
, CreateDoubleError(nErrors
[nMaxRow
* i
+ j
]));
2861 pos
= MatrixImplType::next_position(pos
);
2866 bool ScMatrixImpl::IsValueOrEmpty( const MatrixImplType::const_position_type
& rPos
) const
2868 switch (maMat
.get_type(rPos
))
2870 case mdds::mtm::element_boolean
:
2871 case mdds::mtm::element_numeric
:
2872 case mdds::mtm::element_empty
:
2880 double ScMatrixImpl::GetDouble(const MatrixImplType::const_position_type
& rPos
) const
2882 double fVal
= maMat
.get_numeric(rPos
);
2883 if ( pErrorInterpreter
)
2885 FormulaError nError
= GetDoubleErrorValue(fVal
);
2886 if ( nError
!= FormulaError::NONE
)
2887 SetErrorAtInterpreter( nError
);
2892 FormulaError
ScMatrixImpl::GetErrorIfNotString( const MatrixImplType::const_position_type
& rPos
) const
2893 { return IsValue(rPos
) ? GetError(rPos
) : FormulaError::NONE
; }
2895 bool ScMatrixImpl::IsValue( const MatrixImplType::const_position_type
& rPos
) const
2897 switch (maMat
.get_type(rPos
))
2899 case mdds::mtm::element_boolean
:
2900 case mdds::mtm::element_numeric
:
2908 FormulaError
ScMatrixImpl::GetError(const MatrixImplType::const_position_type
& rPos
) const
2910 double fVal
= maMat
.get_numeric(rPos
);
2911 return GetDoubleErrorValue(fVal
);
2914 bool ScMatrixImpl::IsStringOrEmpty(const MatrixImplType::const_position_type
& rPos
) const
2916 switch (maMat
.get_type(rPos
))
2918 case mdds::mtm::element_empty
:
2919 case mdds::mtm::element_string
:
2927 void ScMatrixImpl::ExecuteBinaryOp(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrix
& rInputMat1
, const ScMatrix
& rInputMat2
,
2928 ScInterpreter
* pInterpreter
, const ScMatrix::CalculateOpFunction
& Op
)
2930 // Check output matrix size, otherwise output iterator logic will be wrong.
2931 assert(maMat
.size().row
== nMaxRow
&& maMat
.size().column
== nMaxCol
2932 && "the caller code should have sized the output matrix to the passed dimensions");
2933 auto & rMatImpl1
= *rInputMat1
.pImpl
;
2934 auto & rMatImpl2
= *rInputMat2
.pImpl
;
2935 // Check if we can do fast-path, where we have no replication or mis-matched matrix sizes.
2936 if (rMatImpl1
.maMat
.size() == rMatImpl2
.maMat
.size()
2937 && rMatImpl1
.maMat
.size() == maMat
.size())
2939 MatrixImplType::position_type aOutPos
= maMat
.position(0, 0);
2940 MatrixImplType::const_position_type aPos1
= rMatImpl1
.maMat
.position(0, 0);
2941 MatrixImplType::const_position_type aPos2
= rMatImpl2
.maMat
.position(0, 0);
2942 for (SCSIZE i
= 0; i
< nMaxCol
; i
++)
2944 for (SCSIZE j
= 0; j
< nMaxRow
; j
++)
2946 bool bVal1
= rMatImpl1
.IsValueOrEmpty(aPos1
);
2947 bool bVal2
= rMatImpl2
.IsValueOrEmpty(aPos2
);
2951 double d
= Op(rMatImpl1
.GetDouble(aPos1
), rMatImpl2
.GetDouble(aPos2
));
2952 aOutPos
= maMat
.set(aOutPos
, d
);
2954 else if (((nErr
= rMatImpl1
.GetErrorIfNotString(aPos1
)) != FormulaError::NONE
) ||
2955 ((nErr
= rMatImpl2
.GetErrorIfNotString(aPos2
)) != FormulaError::NONE
))
2957 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nErr
));
2959 else if ((!bVal1
&& rMatImpl1
.IsStringOrEmpty(aPos1
)) ||
2960 (!bVal2
&& rMatImpl2
.IsStringOrEmpty(aPos2
)))
2962 FormulaError nError1
= FormulaError::NONE
;
2963 SvNumFormatType nFmt1
= SvNumFormatType::ALL
;
2964 double fVal1
= (bVal1
? rMatImpl1
.GetDouble(aPos1
) :
2965 pInterpreter
->ConvertStringToValue( rMatImpl1
.GetString(aPos1
).getString(), nError1
, nFmt1
));
2967 FormulaError nError2
= FormulaError::NONE
;
2968 SvNumFormatType nFmt2
= SvNumFormatType::ALL
;
2969 double fVal2
= (bVal2
? rMatImpl2
.GetDouble(aPos2
) :
2970 pInterpreter
->ConvertStringToValue( rMatImpl2
.GetString(aPos2
).getString(), nError2
, nFmt2
));
2972 if (nError1
!= FormulaError::NONE
)
2973 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError1
));
2974 else if (nError2
!= FormulaError::NONE
)
2975 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError2
));
2978 double d
= Op( fVal1
, fVal2
);
2979 aOutPos
= maMat
.set(aOutPos
, d
);
2983 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(FormulaError::NoValue
));
2984 aPos1
= MatrixImplType::next_position(aPos1
);
2985 aPos2
= MatrixImplType::next_position(aPos2
);
2986 aOutPos
= MatrixImplType::next_position(aOutPos
);
2992 // Noting that this block is very hard to optimise to use iterators, because various dodgy
2993 // array function usage relies on the semantics of some of the methods we call here.
2994 // (see unit test testDubiousArrayFormulasFODS).
2995 // These methods are inconsistent in their usage of ValidColRowReplicated() vs. ValidColRowOrReplicated()
2996 // which leads to some very odd results.
2997 MatrixImplType::position_type aOutPos
= maMat
.position(0, 0);
2998 for (SCSIZE i
= 0; i
< nMaxCol
; i
++)
3000 for (SCSIZE j
= 0; j
< nMaxRow
; j
++)
3002 bool bVal1
= rInputMat1
.IsValueOrEmpty(i
,j
);
3003 bool bVal2
= rInputMat2
.IsValueOrEmpty(i
,j
);
3007 double d
= Op(rInputMat1
.GetDouble(i
,j
), rInputMat2
.GetDouble(i
,j
));
3008 aOutPos
= maMat
.set(aOutPos
, d
);
3010 else if (((nErr
= rInputMat1
.GetErrorIfNotString(i
,j
)) != FormulaError::NONE
) ||
3011 ((nErr
= rInputMat2
.GetErrorIfNotString(i
,j
)) != FormulaError::NONE
))
3013 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nErr
));
3015 else if ((!bVal1
&& rInputMat1
.IsStringOrEmpty(i
,j
)) || (!bVal2
&& rInputMat2
.IsStringOrEmpty(i
,j
)))
3017 FormulaError nError1
= FormulaError::NONE
;
3018 SvNumFormatType nFmt1
= SvNumFormatType::ALL
;
3019 double fVal1
= (bVal1
? rInputMat1
.GetDouble(i
,j
) :
3020 pInterpreter
->ConvertStringToValue( rInputMat1
.GetString(i
,j
).getString(), nError1
, nFmt1
));
3022 FormulaError nError2
= FormulaError::NONE
;
3023 SvNumFormatType nFmt2
= SvNumFormatType::ALL
;
3024 double fVal2
= (bVal2
? rInputMat2
.GetDouble(i
,j
) :
3025 pInterpreter
->ConvertStringToValue( rInputMat2
.GetString(i
,j
).getString(), nError2
, nFmt2
));
3027 if (nError1
!= FormulaError::NONE
)
3028 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError1
));
3029 else if (nError2
!= FormulaError::NONE
)
3030 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError2
));
3033 double d
= Op( fVal1
, fVal2
);
3034 aOutPos
= maMat
.set(aOutPos
, d
);
3038 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(FormulaError::NoValue
));
3039 aOutPos
= MatrixImplType::next_position(aOutPos
);
3045 void ScMatrix::IncRef() const
3050 void ScMatrix::DecRef() const
3057 bool ScMatrix::IsSizeAllocatable( SCSIZE nC
, SCSIZE nR
)
3059 SAL_WARN_IF( !nC
, "sc.core", "ScMatrix with 0 columns!");
3060 SAL_WARN_IF( !nR
, "sc.core", "ScMatrix with 0 rows!");
3061 // 0-size matrix is valid, it could be resized later.
3062 if ((nC
&& !nR
) || (!nC
&& nR
))
3064 SAL_WARN( "sc.core", "ScMatrix one-dimensional zero: " << nC
<< " columns * " << nR
<< " rows");
3070 std::call_once(bElementsMaxFetched
,
3073 const char* pEnv
= std::getenv("SC_MAX_MATRIX_ELEMENTS");
3076 // Environment specifies the overall elements pool.
3077 nElementsMax
= std::atoi(pEnv
);
3081 // GetElementsMax() uses an (~arbitrary) elements limit.
3082 // The actual allocation depends on the types of individual matrix
3083 // elements and is averaged for type double.
3084 #if SAL_TYPES_SIZEOFPOINTER < 8
3085 // Assume 1GB memory could be consumed by matrices.
3086 constexpr size_t nMemMax
= 0x40000000;
3088 // Assume 6GB memory could be consumed by matrices.
3089 constexpr size_t nMemMax
= 0x180000000;
3091 nElementsMax
= GetElementsMax( nMemMax
);
3095 if (nC
> (nElementsMax
/ nR
))
3097 SAL_WARN( "sc.core", "ScMatrix overflow: " << nC
<< " columns * " << nR
<< " rows");
3103 ScMatrix::ScMatrix( SCSIZE nC
, SCSIZE nR
) :
3104 nRefCnt(0), mbCloneIfConst(true)
3106 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
3107 pImpl
.reset( new ScMatrixImpl( nC
, nR
));
3109 // Invalid matrix size, allocate 1x1 matrix with error value.
3110 pImpl
.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize
)));
3113 ScMatrix::ScMatrix(SCSIZE nC
, SCSIZE nR
, double fInitVal
) :
3114 nRefCnt(0), mbCloneIfConst(true)
3116 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
3117 pImpl
.reset( new ScMatrixImpl( nC
, nR
, fInitVal
));
3119 // Invalid matrix size, allocate 1x1 matrix with error value.
3120 pImpl
.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize
)));
3123 ScMatrix::ScMatrix( size_t nC
, size_t nR
, const std::vector
<double>& rInitVals
) :
3124 nRefCnt(0), mbCloneIfConst(true)
3126 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
3127 pImpl
.reset( new ScMatrixImpl( nC
, nR
, rInitVals
));
3129 // Invalid matrix size, allocate 1x1 matrix with error value.
3130 pImpl
.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize
)));
3133 ScMatrix::~ScMatrix()
3137 ScMatrix
* ScMatrix::Clone() const
3140 pImpl
->GetDimensions(nC
, nR
);
3141 ScMatrix
* pScMat
= new ScMatrix(nC
, nR
);
3143 pScMat
->SetErrorInterpreter(pImpl
->GetErrorInterpreter()); // TODO: really?
3147 ScMatrix
* ScMatrix::CloneIfConst()
3149 return mbCloneIfConst
? Clone() : this;
3152 void ScMatrix::SetMutable()
3154 mbCloneIfConst
= false;
3157 void ScMatrix::SetImmutable() const
3159 mbCloneIfConst
= true;
3162 void ScMatrix::Resize( SCSIZE nC
, SCSIZE nR
)
3164 pImpl
->Resize(nC
, nR
);
3167 void ScMatrix::Resize(SCSIZE nC
, SCSIZE nR
, double fVal
)
3169 pImpl
->Resize(nC
, nR
, fVal
);
3172 ScMatrix
* ScMatrix::CloneAndExtend(SCSIZE nNewCols
, SCSIZE nNewRows
) const
3174 ScMatrix
* pScMat
= new ScMatrix(nNewCols
, nNewRows
);
3176 pScMat
->SetErrorInterpreter(pImpl
->GetErrorInterpreter());
3180 void ScMatrix::SetErrorInterpreter( ScInterpreter
* p
)
3182 pImpl
->SetErrorInterpreter(p
);
3185 void ScMatrix::GetDimensions( SCSIZE
& rC
, SCSIZE
& rR
) const
3187 pImpl
->GetDimensions(rC
, rR
);
3190 SCSIZE
ScMatrix::GetElementCount() const
3192 return pImpl
->GetElementCount();
3195 bool ScMatrix::ValidColRow( SCSIZE nC
, SCSIZE nR
) const
3197 return pImpl
->ValidColRow(nC
, nR
);
3200 bool ScMatrix::ValidColRowReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
3202 return pImpl
->ValidColRowReplicated(rC
, rR
);
3205 bool ScMatrix::ValidColRowOrReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
3207 return ValidColRow( rC
, rR
) || ValidColRowReplicated( rC
, rR
);
3210 void ScMatrix::PutDouble(double fVal
, SCSIZE nC
, SCSIZE nR
)
3212 pImpl
->PutDouble(fVal
, nC
, nR
);
3215 void ScMatrix::PutDouble( double fVal
, SCSIZE nIndex
)
3217 pImpl
->PutDouble(fVal
, nIndex
);
3220 void ScMatrix::PutDoubleTrans(double fVal
, SCSIZE nIndex
)
3222 pImpl
->PutDoubleTrans(fVal
, nIndex
);
3225 void ScMatrix::PutDouble(const double* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
3227 pImpl
->PutDouble(pArray
, nLen
, nC
, nR
);
3230 void ScMatrix::PutString(const svl::SharedString
& rStr
, SCSIZE nC
, SCSIZE nR
)
3232 pImpl
->PutString(rStr
, nC
, nR
);
3235 void ScMatrix::PutString(const svl::SharedString
& rStr
, SCSIZE nIndex
)
3237 pImpl
->PutString(rStr
, nIndex
);
3240 void ScMatrix::PutStringTrans(const svl::SharedString
& rStr
, SCSIZE nIndex
)
3242 pImpl
->PutStringTrans(rStr
, nIndex
);
3245 void ScMatrix::PutString(const svl::SharedString
* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
3247 pImpl
->PutString(pArray
, nLen
, nC
, nR
);
3250 void ScMatrix::PutEmpty(SCSIZE nC
, SCSIZE nR
)
3252 pImpl
->PutEmpty(nC
, nR
);
3255 void ScMatrix::PutEmpty(SCSIZE nIndex
)
3257 pImpl
->PutEmpty(nIndex
);
3260 void ScMatrix::PutEmptyTrans(SCSIZE nIndex
)
3262 pImpl
->PutEmptyTrans(nIndex
);
3265 void ScMatrix::PutEmptyPath(SCSIZE nC
, SCSIZE nR
)
3267 pImpl
->PutEmptyPath(nC
, nR
);
3270 void ScMatrix::PutError( FormulaError nErrorCode
, SCSIZE nC
, SCSIZE nR
)
3272 pImpl
->PutError(nErrorCode
, nC
, nR
);
3275 void ScMatrix::PutBoolean(bool bVal
, SCSIZE nC
, SCSIZE nR
)
3277 pImpl
->PutBoolean(bVal
, nC
, nR
);
3280 FormulaError
ScMatrix::GetError( SCSIZE nC
, SCSIZE nR
) const
3282 return pImpl
->GetError(nC
, nR
);
3285 double ScMatrix::GetDouble(SCSIZE nC
, SCSIZE nR
) const
3287 return pImpl
->GetDouble(nC
, nR
);
3290 double ScMatrix::GetDouble( SCSIZE nIndex
) const
3292 return pImpl
->GetDouble(nIndex
);
3295 double ScMatrix::GetDoubleWithStringConversion(SCSIZE nC
, SCSIZE nR
) const
3297 return pImpl
->GetDoubleWithStringConversion(nC
, nR
);
3300 svl::SharedString
ScMatrix::GetString(SCSIZE nC
, SCSIZE nR
) const
3302 return pImpl
->GetString(nC
, nR
);
3305 svl::SharedString
ScMatrix::GetString( SCSIZE nIndex
) const
3307 return pImpl
->GetString(nIndex
);
3310 svl::SharedString
ScMatrix::GetString( ScInterpreterContext
& rContext
, SCSIZE nC
, SCSIZE nR
) const
3312 return pImpl
->GetString(rContext
, nC
, nR
);
3315 ScMatrixValue
ScMatrix::Get(SCSIZE nC
, SCSIZE nR
) const
3317 return pImpl
->Get(nC
, nR
);
3320 bool ScMatrix::IsStringOrEmpty( SCSIZE nIndex
) const
3322 return pImpl
->IsStringOrEmpty(nIndex
);
3325 bool ScMatrix::IsStringOrEmpty( SCSIZE nC
, SCSIZE nR
) const
3327 return pImpl
->IsStringOrEmpty(nC
, nR
);
3330 bool ScMatrix::IsEmpty( SCSIZE nC
, SCSIZE nR
) const
3332 return pImpl
->IsEmpty(nC
, nR
);
3335 bool ScMatrix::IsEmptyCell( SCSIZE nC
, SCSIZE nR
) const
3337 return pImpl
->IsEmptyCell(nC
, nR
);
3340 bool ScMatrix::IsEmptyResult( SCSIZE nC
, SCSIZE nR
) const
3342 return pImpl
->IsEmptyResult(nC
, nR
);
3345 bool ScMatrix::IsEmptyPath( SCSIZE nC
, SCSIZE nR
) const
3347 return pImpl
->IsEmptyPath(nC
, nR
);
3350 bool ScMatrix::IsValue( SCSIZE nIndex
) const
3352 return pImpl
->IsValue(nIndex
);
3355 bool ScMatrix::IsValue( SCSIZE nC
, SCSIZE nR
) const
3357 return pImpl
->IsValue(nC
, nR
);
3360 bool ScMatrix::IsValueOrEmpty( SCSIZE nC
, SCSIZE nR
) const
3362 return pImpl
->IsValueOrEmpty(nC
, nR
);
3365 bool ScMatrix::IsBoolean( SCSIZE nC
, SCSIZE nR
) const
3367 return pImpl
->IsBoolean(nC
, nR
);
3370 bool ScMatrix::IsNumeric() const
3372 return pImpl
->IsNumeric();
3375 void ScMatrix::MatCopy(const ScMatrix
& mRes
) const
3377 pImpl
->MatCopy(*mRes
.pImpl
);
3380 void ScMatrix::MatTrans(const ScMatrix
& mRes
) const
3382 pImpl
->MatTrans(*mRes
.pImpl
);
3385 void ScMatrix::FillDouble( double fVal
, SCSIZE nC1
, SCSIZE nR1
, SCSIZE nC2
, SCSIZE nR2
)
3387 pImpl
->FillDouble(fVal
, nC1
, nR1
, nC2
, nR2
);
3390 void ScMatrix::PutDoubleVector( const ::std::vector
< double > & rVec
, SCSIZE nC
, SCSIZE nR
)
3392 pImpl
->PutDoubleVector(rVec
, nC
, nR
);
3395 void ScMatrix::PutStringVector( const ::std::vector
< svl::SharedString
> & rVec
, SCSIZE nC
, SCSIZE nR
)
3397 pImpl
->PutStringVector(rVec
, nC
, nR
);
3400 void ScMatrix::PutEmptyVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
3402 pImpl
->PutEmptyVector(nCount
, nC
, nR
);
3405 void ScMatrix::PutEmptyResultVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
3407 pImpl
->PutEmptyResultVector(nCount
, nC
, nR
);
3410 void ScMatrix::PutEmptyPathVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
3412 pImpl
->PutEmptyPathVector(nCount
, nC
, nR
);
3415 void ScMatrix::CompareEqual()
3417 pImpl
->CompareEqual();
3420 void ScMatrix::CompareNotEqual()
3422 pImpl
->CompareNotEqual();
3425 void ScMatrix::CompareLess()
3427 pImpl
->CompareLess();
3430 void ScMatrix::CompareGreater()
3432 pImpl
->CompareGreater();
3435 void ScMatrix::CompareLessEqual()
3437 pImpl
->CompareLessEqual();
3440 void ScMatrix::CompareGreaterEqual()
3442 pImpl
->CompareGreaterEqual();
3445 double ScMatrix::And() const
3447 return pImpl
->And();
3450 double ScMatrix::Or() const
3455 double ScMatrix::Xor() const
3457 return pImpl
->Xor();
3460 ScMatrix::KahanIterateResult
ScMatrix::Sum(bool bTextAsZero
, bool bIgnoreErrorValues
) const
3462 return pImpl
->Sum(bTextAsZero
, bIgnoreErrorValues
);
3465 ScMatrix::KahanIterateResult
ScMatrix::SumSquare(bool bTextAsZero
, bool bIgnoreErrorValues
) const
3467 return pImpl
->SumSquare(bTextAsZero
, bIgnoreErrorValues
);
3470 ScMatrix::DoubleIterateResult
ScMatrix::Product(bool bTextAsZero
, bool bIgnoreErrorValues
) const
3472 return pImpl
->Product(bTextAsZero
, bIgnoreErrorValues
);
3475 size_t ScMatrix::Count(bool bCountStrings
, bool bCountErrors
, bool bIgnoreEmptyStrings
) const
3477 return pImpl
->Count(bCountStrings
, bCountErrors
, bIgnoreEmptyStrings
);
3480 size_t ScMatrix::MatchDoubleInColumns(double fValue
, size_t nCol1
, size_t nCol2
) const
3482 return pImpl
->MatchDoubleInColumns(fValue
, nCol1
, nCol2
);
3485 size_t ScMatrix::MatchStringInColumns(const svl::SharedString
& rStr
, size_t nCol1
, size_t nCol2
) const
3487 return pImpl
->MatchStringInColumns(rStr
, nCol1
, nCol2
);
3490 double ScMatrix::GetMaxValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
3492 return pImpl
->GetMaxValue(bTextAsZero
, bIgnoreErrorValues
);
3495 double ScMatrix::GetMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
3497 return pImpl
->GetMinValue(bTextAsZero
, bIgnoreErrorValues
);
3500 double ScMatrix::GetGcd() const
3502 return pImpl
->GetGcd();
3505 double ScMatrix::GetLcm() const
3507 return pImpl
->GetLcm();
3511 ScMatrixRef
ScMatrix::CompareMatrix(
3512 sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) const
3514 return pImpl
->CompareMatrix(rComp
, nMatPos
, pOptions
);
3517 void ScMatrix::GetDoubleArray( std::vector
<double>& rArray
, bool bEmptyAsZero
) const
3519 pImpl
->GetDoubleArray(rArray
, bEmptyAsZero
);
3522 void ScMatrix::MergeDoubleArrayMultiply( std::vector
<double>& rArray
) const
3524 pImpl
->MergeDoubleArrayMultiply(rArray
);
3531 /** A template for operations where operands are supposed to be numeric.
3532 A non-numeric (string) operand leads to the configured conversion to number
3533 method being called if in interpreter context and a FormulaError::NoValue DoubleError
3534 if conversion was not possible, else to an unconditional FormulaError::NoValue
3536 An empty operand evaluates to 0.
3538 template<typename TOp
>
3543 ScInterpreter
* mpErrorInterpreter
;
3547 typedef double number_value_type
;
3549 MatOp( TOp aOp
, ScInterpreter
* pErrorInterpreter
,
3550 double fVal
= 0.0 ):
3552 mpErrorInterpreter(pErrorInterpreter
),
3555 if (mpErrorInterpreter
)
3557 FormulaError nErr
= mpErrorInterpreter
->GetError();
3558 if (nErr
!= FormulaError::NONE
)
3559 mfVal
= CreateDoubleError( nErr
);
3563 double operator()(double fVal
) const
3565 return maOp(fVal
, mfVal
);
3568 double operator()(bool bVal
) const
3570 return maOp(static_cast<double>(bVal
), mfVal
);
3573 double operator()(const svl::SharedString
& rStr
) const
3575 return maOp( convertStringToValue( mpErrorInterpreter
, rStr
.getString()), mfVal
);
3578 /// the action for empty entries in a matrix
3579 double operator()(char) const
3581 return maOp(0, mfVal
);
3584 static bool useFunctionForEmpty()
3594 void ScMatrix::NotOp( const ScMatrix
& rMat
)
3596 auto not_
= [](double a
, double){return double(a
== 0.0);};
3597 matop::MatOp
<decltype(not_
)> aOp(not_
, pImpl
->GetErrorInterpreter());
3598 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3601 void ScMatrix::NegOp( const ScMatrix
& rMat
)
3603 auto neg_
= [](double a
, double){return -a
;};
3604 matop::MatOp
<decltype(neg_
)> aOp(neg_
, pImpl
->GetErrorInterpreter());
3605 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3608 void ScMatrix::AddOp( double fVal
, const ScMatrix
& rMat
)
3610 auto add_
= [](double a
, double b
){return a
+ b
;};
3611 matop::MatOp
<decltype(add_
)> aOp(add_
, pImpl
->GetErrorInterpreter(), fVal
);
3612 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3615 void ScMatrix::SubOp( bool bFlag
, double fVal
, const ScMatrix
& rMat
)
3619 auto sub_
= [](double a
, double b
){return b
- a
;};
3620 matop::MatOp
<decltype(sub_
)> aOp(sub_
, pImpl
->GetErrorInterpreter(), fVal
);
3621 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3625 auto sub_
= [](double a
, double b
){return a
- b
;};
3626 matop::MatOp
<decltype(sub_
)> aOp(sub_
, pImpl
->GetErrorInterpreter(), fVal
);
3627 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3631 void ScMatrix::MulOp( double fVal
, const ScMatrix
& rMat
)
3633 auto mul_
= [](double a
, double b
){return a
* b
;};
3634 matop::MatOp
<decltype(mul_
)> aOp(mul_
, pImpl
->GetErrorInterpreter(), fVal
);
3635 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3638 void ScMatrix::DivOp( bool bFlag
, double fVal
, const ScMatrix
& rMat
)
3642 auto div_
= [](double a
, double b
){return sc::div(b
, a
);};
3643 matop::MatOp
<decltype(div_
)> aOp(div_
, pImpl
->GetErrorInterpreter(), fVal
);
3644 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3648 auto div_
= [](double a
, double b
){return sc::div(a
, b
);};
3649 matop::MatOp
<decltype(div_
)> aOp(div_
, pImpl
->GetErrorInterpreter(), fVal
);
3650 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3654 void ScMatrix::PowOp( bool bFlag
, double fVal
, const ScMatrix
& rMat
)
3658 auto pow_
= [](double a
, double b
){return sc::power(b
, a
);};
3659 matop::MatOp
<decltype(pow_
)> aOp(pow_
, pImpl
->GetErrorInterpreter(), fVal
);
3660 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3664 auto pow_
= [](double a
, double b
){return sc::power(a
, b
);};
3665 matop::MatOp
<decltype(pow_
)> aOp(pow_
, pImpl
->GetErrorInterpreter(), fVal
);
3666 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3670 void ScMatrix::ExecuteOperation(const std::pair
<size_t, size_t>& rStartPos
,
3671 const std::pair
<size_t, size_t>& rEndPos
, DoubleOpFunction aDoubleFunc
,
3672 BoolOpFunction aBoolFunc
, StringOpFunction aStringFunc
, EmptyOpFunction aEmptyFunc
) const
3674 pImpl
->ExecuteOperation(rStartPos
, rEndPos
, aDoubleFunc
, aBoolFunc
, aStringFunc
, aEmptyFunc
);
3677 ScMatrix::KahanIterateResultMultiple
ScMatrix::CollectKahan(const std::vector
<sc::op::kOp
>& aOp
)
3679 return pImpl
->ApplyCollectOperation
<sc::op::kOp
, KahanSum
>(aOp
);
3683 void ScMatrix::Dump() const
3689 void ScMatrix::MatConcat(SCSIZE nMaxCol
, SCSIZE nMaxRow
,
3690 const ScMatrixRef
& xMat1
, const ScMatrixRef
& xMat2
, ScInterpreterContext
& rContext
, svl::SharedStringPool
& rPool
)
3692 pImpl
->MatConcat(nMaxCol
, nMaxRow
, xMat1
, xMat2
, rContext
, rPool
);
3695 void ScMatrix::ExecuteBinaryOp(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrix
& rInputMat1
, const ScMatrix
& rInputMat2
,
3696 ScInterpreter
* pInterpreter
, const CalculateOpFunction
& op
)
3698 pImpl
->ExecuteBinaryOp(nMaxCol
, nMaxRow
, rInputMat1
, rInputMat2
, pInterpreter
, op
);
3700 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */