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 PutEmptyPath(SCSIZE nC
, SCSIZE nR
);
273 void PutError( FormulaError nErrorCode
, SCSIZE nC
, SCSIZE nR
);
274 void PutBoolean(bool bVal
, SCSIZE nC
, SCSIZE nR
);
275 FormulaError
GetError( SCSIZE nC
, SCSIZE nR
) const;
276 double GetDouble(SCSIZE nC
, SCSIZE nR
) const;
277 double GetDouble( SCSIZE nIndex
) const;
278 double GetDoubleWithStringConversion(SCSIZE nC
, SCSIZE nR
) const;
279 svl::SharedString
GetString(SCSIZE nC
, SCSIZE nR
) const;
280 svl::SharedString
GetString( SCSIZE nIndex
) const;
281 svl::SharedString
GetString( SvNumberFormatter
& rFormatter
, SCSIZE nC
, SCSIZE nR
) const;
282 ScMatrixValue
Get(SCSIZE nC
, SCSIZE nR
) const;
283 bool IsStringOrEmpty( SCSIZE nIndex
) const;
284 bool IsStringOrEmpty( SCSIZE nC
, SCSIZE nR
) const;
285 bool IsEmpty( SCSIZE nC
, SCSIZE nR
) const;
286 bool IsEmptyCell( SCSIZE nC
, SCSIZE nR
) const;
287 bool IsEmptyResult( SCSIZE nC
, SCSIZE nR
) const;
288 bool IsEmptyPath( SCSIZE nC
, SCSIZE nR
) const;
289 bool IsValue( SCSIZE nIndex
) const;
290 bool IsValue( SCSIZE nC
, SCSIZE nR
) const;
291 bool IsValueOrEmpty( SCSIZE nC
, SCSIZE nR
) const;
292 bool IsBoolean( SCSIZE nC
, SCSIZE nR
) const;
293 bool IsNumeric() const;
295 void MatCopy(ScMatrixImpl
& mRes
) const;
296 void MatTrans(ScMatrixImpl
& mRes
) const;
297 void FillDouble( double fVal
, SCSIZE nC1
, SCSIZE nR1
, SCSIZE nC2
, SCSIZE nR2
);
298 void PutDoubleVector( const ::std::vector
< double > & rVec
, SCSIZE nC
, SCSIZE nR
);
299 void PutStringVector( const ::std::vector
< svl::SharedString
> & rVec
, SCSIZE nC
, SCSIZE nR
);
300 void PutEmptyVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
);
301 void PutEmptyResultVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
);
302 void PutEmptyPathVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
);
304 void CompareNotEqual();
306 void CompareGreater();
307 void CompareLessEqual();
308 void CompareGreaterEqual();
313 ScMatrix::KahanIterateResult
Sum( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
314 ScMatrix::KahanIterateResult
SumSquare( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
315 ScMatrix::DoubleIterateResult
Product( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
316 size_t Count(bool bCountStrings
, bool bCountErrors
, bool bIgnoreEmptyStrings
) const;
317 size_t MatchDoubleInColumns(double fValue
, size_t nCol1
, size_t nCol2
) const;
318 size_t MatchStringInColumns(const svl::SharedString
& rStr
, size_t nCol1
, size_t nCol2
) const;
320 double GetMaxValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
321 double GetMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const;
322 double GetGcd() const;
323 double GetLcm() const;
325 ScMatrixRef
CompareMatrix( sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) const;
327 void GetDoubleArray( std::vector
<double>& rArray
, bool bEmptyAsZero
) const;
328 void MergeDoubleArrayMultiply( std::vector
<double>& rArray
) const;
331 void ApplyOperation(T aOp
, ScMatrixImpl
& rMat
);
333 void ExecuteOperation(const std::pair
<size_t, size_t>& rStartPos
,
334 const std::pair
<size_t, size_t>& rEndPos
, const ScMatrix::DoubleOpFunction
& aDoubleFunc
,
335 const ScMatrix::BoolOpFunction
& aBoolFunc
, const ScMatrix::StringOpFunction
& aStringFunc
,
336 const ScMatrix::EmptyOpFunction
& aEmptyFunc
) const;
338 template<typename T
, typename tRes
>
339 ScMatrix::IterateResultMultiple
<tRes
> ApplyCollectOperation(const std::vector
<T
>& aOp
);
341 void MatConcat(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrixRef
& xMat1
, const ScMatrixRef
& xMat2
,
342 SvNumberFormatter
& rFormatter
, svl::SharedStringPool
& rPool
);
344 void ExecuteBinaryOp(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrix
& rInputMat1
, const ScMatrix
& rInputMat2
,
345 ScInterpreter
* pInterpreter
, ScMatrix::CalculateOpFunction op
);
346 bool IsValueOrEmpty( const MatrixImplType::const_position_type
& rPos
) const;
347 double GetDouble( const MatrixImplType::const_position_type
& rPos
) const;
348 FormulaError
GetErrorIfNotString( const MatrixImplType::const_position_type
& rPos
) const;
349 bool IsValue( const MatrixImplType::const_position_type
& rPos
) const;
350 FormulaError
GetError(const MatrixImplType::const_position_type
& rPos
) const;
351 bool IsStringOrEmpty(const MatrixImplType::const_position_type
& rPos
) const;
352 svl::SharedString
GetString(const MatrixImplType::const_position_type
& rPos
) const;
359 void CalcPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const;
360 void CalcTransPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const;
363 static std::once_flag bElementsMaxFetched
;
364 static std::atomic
<size_t> nElementsMax
;
366 /** The maximum number of elements a matrix or the pool may have at runtime.
369 If 0, the arbitrary limit of one matrix is returned.
370 If >0, the given memory pool divided by the average size of a
371 matrix element is returned, which is used to initialize
374 static size_t GetElementsMax( size_t nMemory
)
376 // Arbitrarily assuming 12 bytes per element, 8 bytes double plus
377 // overhead. Stored as an array in an mdds container it's less, but for
378 // strings or mixed matrix it can be much more...
379 constexpr size_t nPerElem
= 12;
381 return nMemory
/ nPerElem
;
383 // Arbitrarily assuming 1GB memory. Could be dynamic at some point.
384 constexpr size_t nMemMax
= 0x40000000;
385 // With 1GB that's ~85M elements, or 85 whole columns.
386 constexpr size_t nElemMax
= nMemMax
/ nPerElem
;
387 // With MAXROWCOUNT==1048576 and 128 columns => 128M elements, 1.5GB
388 constexpr size_t nArbitraryLimit
= size_t(MAXROWCOUNT
) * 128;
389 // With the constant 1GB from above that's the actual value.
390 return std::min(nElemMax
, nArbitraryLimit
);
393 ScMatrixImpl::ScMatrixImpl(SCSIZE nC
, SCSIZE nR
) :
394 maMat(nR
, nC
), maMatFlag(nR
, nC
), pErrorInterpreter(nullptr)
396 nElementsMax
-= GetElementCount();
399 ScMatrixImpl::ScMatrixImpl(SCSIZE nC
, SCSIZE nR
, double fInitVal
) :
400 maMat(nR
, nC
, fInitVal
), maMatFlag(nR
, nC
), pErrorInterpreter(nullptr)
402 nElementsMax
-= GetElementCount();
405 ScMatrixImpl::ScMatrixImpl( size_t nC
, size_t nR
, const std::vector
<double>& rInitVals
) :
406 maMat(nR
, nC
, rInitVals
.begin(), rInitVals
.end()), maMatFlag(nR
, nC
), pErrorInterpreter(nullptr)
408 nElementsMax
-= GetElementCount();
411 ScMatrixImpl::~ScMatrixImpl()
413 nElementsMax
+= GetElementCount();
414 suppress_fun_call_w_exception(Clear());
417 void ScMatrixImpl::Clear()
419 suppress_fun_call_w_exception(maMat
.clear());
423 void ScMatrixImpl::Resize(SCSIZE nC
, SCSIZE nR
)
425 nElementsMax
+= GetElementCount();
426 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
428 maMat
.resize(nR
, nC
);
429 maMatFlag
.resize(nR
, nC
);
433 // Invalid matrix size, allocate 1x1 matrix with error value.
434 maMat
.resize(1, 1, CreateDoubleError( FormulaError::MatrixSize
));
435 maMatFlag
.resize(1, 1);
437 nElementsMax
-= GetElementCount();
440 void ScMatrixImpl::Resize(SCSIZE nC
, SCSIZE nR
, double fVal
)
442 nElementsMax
+= GetElementCount();
443 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
445 maMat
.resize(nR
, nC
, fVal
);
446 maMatFlag
.resize(nR
, nC
);
450 // Invalid matrix size, allocate 1x1 matrix with error value.
451 maMat
.resize(1, 1, CreateDoubleError( FormulaError::StackOverflow
));
452 maMatFlag
.resize(1, 1);
454 nElementsMax
-= GetElementCount();
457 void ScMatrixImpl::SetErrorInterpreter( ScInterpreter
* p
)
459 pErrorInterpreter
= p
;
462 void ScMatrixImpl::GetDimensions( SCSIZE
& rC
, SCSIZE
& rR
) const
464 MatrixImplType::size_pair_type aSize
= maMat
.size();
469 SCSIZE
ScMatrixImpl::GetElementCount() const
471 MatrixImplType::size_pair_type aSize
= maMat
.size();
472 return aSize
.row
* aSize
.column
;
475 bool ScMatrixImpl::ValidColRow( SCSIZE nC
, SCSIZE nR
) const
477 MatrixImplType::size_pair_type aSize
= maMat
.size();
478 return nR
< aSize
.row
&& nC
< aSize
.column
;
481 bool ScMatrixImpl::ValidColRowReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
483 MatrixImplType::size_pair_type aSize
= maMat
.size();
484 if (aSize
.column
== 1 && aSize
.row
== 1)
490 else if (aSize
.column
== 1 && rR
< aSize
.row
)
492 // single column matrix.
496 else if (aSize
.row
== 1 && rC
< aSize
.column
)
498 // single row matrix.
505 bool ScMatrixImpl::ValidColRowOrReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
507 return ValidColRow( rC
, rR
) || ValidColRowReplicated( rC
, rR
);
510 void ScMatrixImpl::SetErrorAtInterpreter( FormulaError nError
) const
512 if ( pErrorInterpreter
)
513 pErrorInterpreter
->SetError( nError
);
516 void ScMatrixImpl::PutDouble(double fVal
, SCSIZE nC
, SCSIZE nR
)
518 if (ValidColRow( nC
, nR
))
519 maMat
.set(nR
, nC
, fVal
);
522 OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
526 void ScMatrixImpl::PutDouble(const double* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
528 if (ValidColRow( nC
, nR
))
529 maMat
.set(nR
, nC
, pArray
, pArray
+ nLen
);
532 OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
536 void ScMatrixImpl::PutDouble( double fVal
, SCSIZE nIndex
)
539 CalcPosition(nIndex
, nC
, nR
);
540 PutDouble(fVal
, nC
, nR
);
543 void ScMatrixImpl::PutDoubleTrans(double fVal
, SCSIZE nIndex
)
546 CalcTransPosition(nIndex
, nC
, nR
);
547 PutDouble(fVal
, nC
, nR
);
550 void ScMatrixImpl::PutString(const svl::SharedString
& rStr
, SCSIZE nC
, SCSIZE nR
)
552 if (ValidColRow( nC
, nR
))
553 maMat
.set(nR
, nC
, rStr
);
556 OSL_FAIL("ScMatrixImpl::PutString: dimension error");
560 void ScMatrixImpl::PutString(const svl::SharedString
* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
562 if (ValidColRow( nC
, nR
))
563 maMat
.set(nR
, nC
, pArray
, pArray
+ nLen
);
566 OSL_FAIL("ScMatrixImpl::PutString: dimension error");
570 void ScMatrixImpl::PutString(const svl::SharedString
& rStr
, SCSIZE nIndex
)
573 CalcPosition(nIndex
, nC
, nR
);
574 PutString(rStr
, nC
, nR
);
577 void ScMatrixImpl::PutStringTrans(const svl::SharedString
& rStr
, SCSIZE nIndex
)
580 CalcTransPosition(nIndex
, nC
, nR
);
581 PutString(rStr
, nC
, nR
);
584 void ScMatrixImpl::PutEmpty(SCSIZE nC
, SCSIZE nR
)
586 if (ValidColRow( nC
, nR
))
588 maMat
.set_empty(nR
, nC
);
589 maMatFlag
.set_empty(nR
, nC
);
593 OSL_FAIL("ScMatrixImpl::PutEmpty: dimension error");
597 void ScMatrixImpl::PutEmptyPath(SCSIZE nC
, SCSIZE nR
)
599 if (ValidColRow( nC
, nR
))
601 maMat
.set_empty(nR
, nC
);
602 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 && __cplusplus == 202002L
603 #pragma GCC diagnostic push
604 #pragma GCC diagnostic ignored "-Warray-bounds"
606 maMatFlag
.set(nR
, nC
, SC_MATFLAG_EMPTYPATH
);
607 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 && __cplusplus == 202002L
608 #pragma GCC diagnostic pop
613 OSL_FAIL("ScMatrixImpl::PutEmptyPath: dimension error");
617 void ScMatrixImpl::PutError( FormulaError nErrorCode
, SCSIZE nC
, SCSIZE nR
)
619 maMat
.set(nR
, nC
, CreateDoubleError(nErrorCode
));
622 void ScMatrixImpl::PutBoolean(bool bVal
, SCSIZE nC
, SCSIZE nR
)
624 if (ValidColRow( nC
, nR
))
625 maMat
.set(nR
, nC
, bVal
);
628 OSL_FAIL("ScMatrixImpl::PutBoolean: dimension error");
632 FormulaError
ScMatrixImpl::GetError( SCSIZE nC
, SCSIZE nR
) const
634 if (ValidColRowOrReplicated( nC
, nR
))
636 double fVal
= maMat
.get_numeric(nR
, nC
);
637 return GetDoubleErrorValue(fVal
);
641 OSL_FAIL("ScMatrixImpl::GetError: dimension error");
642 return FormulaError::NoValue
;
646 double ScMatrixImpl::GetDouble(SCSIZE nC
, SCSIZE nR
) const
648 if (ValidColRowOrReplicated( nC
, nR
))
650 double fVal
= maMat
.get_numeric(nR
, nC
);
651 if ( pErrorInterpreter
)
653 FormulaError nError
= GetDoubleErrorValue(fVal
);
654 if ( nError
!= FormulaError::NONE
)
655 SetErrorAtInterpreter( nError
);
661 OSL_FAIL("ScMatrixImpl::GetDouble: dimension error");
662 return CreateDoubleError( FormulaError::NoValue
);
666 double ScMatrixImpl::GetDouble( SCSIZE nIndex
) const
669 CalcPosition(nIndex
, nC
, nR
);
670 return GetDouble(nC
, nR
);
673 double ScMatrixImpl::GetDoubleWithStringConversion(SCSIZE nC
, SCSIZE nR
) const
675 ScMatrixValue aMatVal
= Get(nC
, nR
);
676 if (aMatVal
.nType
== ScMatValType::String
)
677 return convertStringToValue( pErrorInterpreter
, aMatVal
.aStr
.getString());
681 svl::SharedString
ScMatrixImpl::GetString(SCSIZE nC
, SCSIZE nR
) const
683 if (ValidColRowOrReplicated( nC
, nR
))
685 return GetString(maMat
.position(nR
, nC
));
689 OSL_FAIL("ScMatrixImpl::GetString: dimension error");
691 return svl::SharedString::getEmptyString();
694 svl::SharedString
ScMatrixImpl::GetString(const MatrixImplType::const_position_type
& rPos
) const
697 switch (maMat
.get_type(rPos
))
699 case mdds::mtm::element_string
:
700 return maMat
.get_string(rPos
);
701 case mdds::mtm::element_empty
:
702 return svl::SharedString::getEmptyString();
703 case mdds::mtm::element_numeric
:
704 case mdds::mtm::element_boolean
:
705 fErr
= maMat
.get_numeric(rPos
);
708 OSL_FAIL("ScMatrixImpl::GetString: access error, no string");
710 SetErrorAtInterpreter(GetDoubleErrorValue(fErr
));
711 return svl::SharedString::getEmptyString();
714 svl::SharedString
ScMatrixImpl::GetString( SCSIZE nIndex
) const
717 CalcPosition(nIndex
, nC
, nR
);
718 return GetString(nC
, nR
);
721 svl::SharedString
ScMatrixImpl::GetString( SvNumberFormatter
& rFormatter
, SCSIZE nC
, SCSIZE nR
) const
723 if (!ValidColRowOrReplicated( nC
, nR
))
725 OSL_FAIL("ScMatrixImpl::GetString: dimension error");
726 return svl::SharedString::getEmptyString();
730 MatrixImplType::const_position_type aPos
= maMat
.position(nR
, nC
);
731 switch (maMat
.get_type(aPos
))
733 case mdds::mtm::element_string
:
734 return maMat
.get_string(aPos
);
735 case mdds::mtm::element_empty
:
737 if (maMatFlag
.get
<uint8_t>(nR
, nC
) != SC_MATFLAG_EMPTYPATH
)
738 // not an empty path.
739 return svl::SharedString::getEmptyString();
741 // result of empty FALSE jump path
742 sal_uInt32 nKey
= rFormatter
.GetStandardFormat( SvNumFormatType::LOGICAL
,
745 const Color
* pColor
= nullptr;
746 rFormatter
.GetOutputString( 0.0, nKey
, aStr
, &pColor
);
747 return svl::SharedString( aStr
); // string not interned
749 case mdds::mtm::element_numeric
:
750 case mdds::mtm::element_boolean
:
751 fVal
= maMat
.get_numeric(aPos
);
757 FormulaError nError
= GetDoubleErrorValue(fVal
);
758 if (nError
!= FormulaError::NONE
)
760 SetErrorAtInterpreter( nError
);
761 return svl::SharedString( ScGlobal::GetErrorString( nError
)); // string not interned
764 sal_uInt32 nKey
= rFormatter
.GetStandardFormat( SvNumFormatType::NUMBER
,
767 rFormatter
.GetInputLineString( fVal
, nKey
, aStr
);
768 return svl::SharedString( aStr
); // string not interned
771 ScMatrixValue
ScMatrixImpl::Get(SCSIZE nC
, SCSIZE nR
) const
774 if (ValidColRowOrReplicated(nC
, nR
))
776 MatrixImplType::const_position_type aPos
= maMat
.position(nR
, nC
);
777 mdds::mtm::element_t eType
= maMat
.get_type(aPos
);
780 case mdds::mtm::element_boolean
:
781 aVal
.nType
= ScMatValType::Boolean
;
782 aVal
.fVal
= double(maMat
.get_boolean(aPos
));
784 case mdds::mtm::element_numeric
:
785 aVal
.nType
= ScMatValType::Value
;
786 aVal
.fVal
= maMat
.get_numeric(aPos
);
788 case mdds::mtm::element_string
:
789 aVal
.nType
= ScMatValType::String
;
790 aVal
.aStr
= maMat
.get_string(aPos
);
792 case mdds::mtm::element_empty
:
793 /* TODO: do we need to pass the differentiation of 'empty' and
794 * 'empty result' to the outer world anywhere? */
795 switch (maMatFlag
.get_type(nR
, nC
))
797 case mdds::mtm::element_empty
:
798 aVal
.nType
= ScMatValType::Empty
;
800 case mdds::mtm::element_integer
:
801 aVal
.nType
= maMatFlag
.get
<uint8_t>(nR
, nC
)
802 == SC_MATFLAG_EMPTYPATH
? ScMatValType::EmptyPath
: ScMatValType::Empty
;
815 OSL_FAIL("ScMatrixImpl::Get: dimension error");
820 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nIndex
) const
823 CalcPosition(nIndex
, nC
, nR
);
824 return IsStringOrEmpty(nC
, nR
);
827 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nC
, SCSIZE nR
) const
829 if (!ValidColRowOrReplicated( nC
, nR
))
832 switch (maMat
.get_type(nR
, nC
))
834 case mdds::mtm::element_empty
:
835 case mdds::mtm::element_string
:
843 bool ScMatrixImpl::IsEmpty( SCSIZE nC
, SCSIZE nR
) const
845 if (!ValidColRowOrReplicated( nC
, nR
))
848 // Flag must indicate an 'empty' or 'empty cell' or 'empty result' element,
849 // but not an 'empty path' element.
850 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
851 maMatFlag
.get_integer(nR
, nC
) != SC_MATFLAG_EMPTYPATH
;
854 bool ScMatrixImpl::IsEmptyCell( SCSIZE nC
, SCSIZE nR
) const
856 if (!ValidColRowOrReplicated( nC
, nR
))
859 // Flag must indicate an 'empty cell' element instead of an
860 // 'empty' or 'empty result' or 'empty path' element.
861 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
862 maMatFlag
.get_type(nR
, nC
) == mdds::mtm::element_empty
;
865 bool ScMatrixImpl::IsEmptyResult( SCSIZE nC
, SCSIZE nR
) const
867 if (!ValidColRowOrReplicated( nC
, nR
))
870 // Flag must indicate an 'empty result' element instead of an
871 // 'empty' or 'empty cell' or 'empty path' element.
872 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
873 maMatFlag
.get_integer(nR
, nC
) == SC_MATFLAG_EMPTYRESULT
;
876 bool ScMatrixImpl::IsEmptyPath( SCSIZE nC
, SCSIZE nR
) const
878 // Flag must indicate an 'empty path' element.
879 if (ValidColRowOrReplicated( nC
, nR
))
880 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_empty
&&
881 maMatFlag
.get_integer(nR
, nC
) == SC_MATFLAG_EMPTYPATH
;
886 bool ScMatrixImpl::IsValue( SCSIZE nIndex
) const
889 CalcPosition(nIndex
, nC
, nR
);
890 return IsValue(nC
, nR
);
893 bool ScMatrixImpl::IsValue( SCSIZE nC
, SCSIZE nR
) const
895 if (!ValidColRowOrReplicated( nC
, nR
))
898 switch (maMat
.get_type(nR
, nC
))
900 case mdds::mtm::element_boolean
:
901 case mdds::mtm::element_numeric
:
909 bool ScMatrixImpl::IsValueOrEmpty( SCSIZE nC
, SCSIZE nR
) const
911 if (!ValidColRowOrReplicated( nC
, nR
))
914 switch (maMat
.get_type(nR
, nC
))
916 case mdds::mtm::element_boolean
:
917 case mdds::mtm::element_numeric
:
918 case mdds::mtm::element_empty
:
926 bool ScMatrixImpl::IsBoolean( SCSIZE nC
, SCSIZE nR
) const
928 if (!ValidColRowOrReplicated( nC
, nR
))
931 return maMat
.get_type(nR
, nC
) == mdds::mtm::element_boolean
;
934 bool ScMatrixImpl::IsNumeric() const
936 return maMat
.numeric();
939 void ScMatrixImpl::MatCopy(ScMatrixImpl
& mRes
) const
941 if (maMat
.size().row
> mRes
.maMat
.size().row
|| maMat
.size().column
> mRes
.maMat
.size().column
)
943 // destination matrix is not large enough.
944 OSL_FAIL("ScMatrixImpl::MatCopy: dimension error");
948 mRes
.maMat
.copy(maMat
);
951 void ScMatrixImpl::MatTrans(ScMatrixImpl
& mRes
) const
954 mRes
.maMat
.transpose();
957 void ScMatrixImpl::FillDouble( double fVal
, SCSIZE nC1
, SCSIZE nR1
, SCSIZE nC2
, SCSIZE nR2
)
959 if (ValidColRow( nC1
, nR1
) && ValidColRow( nC2
, nR2
))
961 for (SCSIZE j
= nC1
; j
<= nC2
; ++j
)
963 // Passing value array is much faster.
964 std::vector
<double> aVals(nR2
-nR1
+1, fVal
);
965 maMat
.set(nR1
, j
, aVals
.begin(), aVals
.end());
970 OSL_FAIL("ScMatrixImpl::FillDouble: dimension error");
974 void ScMatrixImpl::PutDoubleVector( const ::std::vector
< double > & rVec
, SCSIZE nC
, SCSIZE nR
)
976 if (!rVec
.empty() && ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ rVec
.size() - 1))
978 maMat
.set(nR
, nC
, rVec
.begin(), rVec
.end());
982 OSL_FAIL("ScMatrixImpl::PutDoubleVector: dimension error");
986 void ScMatrixImpl::PutStringVector( const ::std::vector
< svl::SharedString
> & rVec
, SCSIZE nC
, SCSIZE nR
)
988 if (!rVec
.empty() && ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ rVec
.size() - 1))
990 maMat
.set(nR
, nC
, rVec
.begin(), rVec
.end());
994 OSL_FAIL("ScMatrixImpl::PutStringVector: dimension error");
998 void ScMatrixImpl::PutEmptyVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
1000 if (nCount
&& ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ nCount
- 1))
1002 maMat
.set_empty(nR
, nC
, nCount
);
1003 // Flag to indicate that this is 'empty', not 'empty result' or 'empty path'.
1004 maMatFlag
.set_empty(nR
, nC
, nCount
);
1008 OSL_FAIL("ScMatrixImpl::PutEmptyVector: dimension error");
1012 void ScMatrixImpl::PutEmptyResultVector( 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 result', not 'empty' or 'empty path'.
1018 std::vector
<uint8_t> aVals(nCount
, SC_MATFLAG_EMPTYRESULT
);
1019 maMatFlag
.set(nR
, nC
, aVals
.begin(), aVals
.end());
1023 OSL_FAIL("ScMatrixImpl::PutEmptyResultVector: dimension error");
1027 void ScMatrixImpl::PutEmptyPathVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
1029 if (nCount
&& ValidColRow( nC
, nR
) && ValidColRow( nC
, nR
+ nCount
- 1))
1031 maMat
.set_empty(nR
, nC
, nCount
);
1032 // Flag to indicate 'empty path'.
1033 std::vector
<uint8_t> aVals(nCount
, SC_MATFLAG_EMPTYPATH
);
1034 maMatFlag
.set(nR
, nC
, aVals
.begin(), aVals
.end());
1038 OSL_FAIL("ScMatrixImpl::PutEmptyPathVector: dimension error");
1042 void ScMatrixImpl::CompareEqual()
1044 MatrixImplType::size_pair_type aSize
= maMat
.size();
1045 CompareMatrixElemFunc
<ElemEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1046 aFunc
= maMat
.walk(std::move(aFunc
));
1050 void ScMatrixImpl::CompareNotEqual()
1052 MatrixImplType::size_pair_type aSize
= maMat
.size();
1053 CompareMatrixElemFunc
<ElemNotEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1054 aFunc
= maMat
.walk(std::move(aFunc
));
1058 void ScMatrixImpl::CompareLess()
1060 MatrixImplType::size_pair_type aSize
= maMat
.size();
1061 CompareMatrixElemFunc
<ElemLessZero
> aFunc(aSize
.row
, aSize
.column
);
1062 aFunc
= maMat
.walk(std::move(aFunc
));
1066 void ScMatrixImpl::CompareGreater()
1068 MatrixImplType::size_pair_type aSize
= maMat
.size();
1069 CompareMatrixElemFunc
<ElemGreaterZero
> aFunc(aSize
.row
, aSize
.column
);
1070 aFunc
= maMat
.walk(std::move(aFunc
));
1074 void ScMatrixImpl::CompareLessEqual()
1076 MatrixImplType::size_pair_type aSize
= maMat
.size();
1077 CompareMatrixElemFunc
<ElemLessEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1078 aFunc
= maMat
.walk(std::move(aFunc
));
1082 void ScMatrixImpl::CompareGreaterEqual()
1084 MatrixImplType::size_pair_type aSize
= maMat
.size();
1085 CompareMatrixElemFunc
<ElemGreaterEqualZero
> aFunc(aSize
.row
, aSize
.column
);
1086 aFunc
= maMat
.walk(std::move(aFunc
));
1095 void operate(double fVal
) { mbResult
&= (fVal
!= 0.0); }
1096 bool result() const { return mbResult
; }
1097 AndEvaluator() : mbResult(true) {}
1103 void operate(double fVal
) { mbResult
|= (fVal
!= 0.0); }
1104 bool result() const { return mbResult
; }
1105 OrEvaluator() : mbResult(false) {}
1111 void operate(double fVal
) { mbResult
^= (fVal
!= 0.0); }
1112 bool result() const { return mbResult
; }
1113 XorEvaluator() : mbResult(false) {}
1116 // Do not short circuit logical operations, in case there are error values
1117 // these need to be propagated even if the result was determined earlier.
1118 template <typename Evaluator
>
1119 double EvalMatrix(const MatrixImplType
& rMat
)
1122 size_t nRows
= rMat
.size().row
, nCols
= rMat
.size().column
;
1123 for (size_t i
= 0; i
< nRows
; ++i
)
1125 for (size_t j
= 0; j
< nCols
; ++j
)
1127 MatrixImplType::const_position_type aPos
= rMat
.position(i
, j
);
1128 mdds::mtm::element_t eType
= rMat
.get_type(aPos
);
1129 if (eType
!= mdds::mtm::element_numeric
&& eType
!= mdds::mtm::element_boolean
)
1130 // assuming a CompareMat this is an error
1131 return CreateDoubleError(FormulaError::IllegalArgument
);
1133 double fVal
= rMat
.get_numeric(aPos
);
1134 if (!std::isfinite(fVal
))
1138 aEval
.operate(fVal
);
1141 return aEval
.result();
1146 double ScMatrixImpl::And() const
1148 // All elements must be of value type.
1149 // True only if all the elements have non-zero values.
1150 return EvalMatrix
<AndEvaluator
>(maMat
);
1153 double ScMatrixImpl::Or() const
1155 // All elements must be of value type.
1156 // True if at least one element has a non-zero value.
1157 return EvalMatrix
<OrEvaluator
>(maMat
);
1160 double ScMatrixImpl::Xor() const
1162 // All elements must be of value type.
1163 // True if an odd number of elements have a non-zero value.
1164 return EvalMatrix
<XorEvaluator
>(maMat
);
1169 template<typename Op
, typename tRes
>
1170 class WalkElementBlocks
1173 ScMatrix::IterateResult
<tRes
> maRes
;
1174 bool mbTextAsZero
:1;
1175 bool mbIgnoreErrorValues
:1;
1177 WalkElementBlocks(bool bTextAsZero
, bool bIgnoreErrorValues
) :
1178 maRes(Op::InitVal
, 0),
1179 mbTextAsZero(bTextAsZero
), mbIgnoreErrorValues(bIgnoreErrorValues
)
1182 const ScMatrix::IterateResult
<tRes
>& getResult() const { return maRes
; }
1184 void operator() (const MatrixImplType::element_block_node_type
& node
)
1188 case mdds::mtm::element_numeric
:
1190 typedef MatrixImplType::numeric_block_type block_type
;
1192 size_t nIgnored
= 0;
1193 block_type::const_iterator it
= block_type::begin(*node
.data
);
1194 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1195 for (; it
!= itEnd
; ++it
)
1197 if (mbIgnoreErrorValues
&& !std::isfinite(*it
))
1202 maOp(maRes
.maAccumulator
, *it
);
1204 maRes
.mnCount
+= node
.size
- nIgnored
;
1207 case mdds::mtm::element_boolean
:
1209 typedef MatrixImplType::boolean_block_type block_type
;
1211 block_type::const_iterator it
= block_type::begin(*node
.data
);
1212 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1213 for (; it
!= itEnd
; ++it
)
1215 maOp(maRes
.maAccumulator
, *it
);
1217 maRes
.mnCount
+= node
.size
;
1220 case mdds::mtm::element_string
:
1222 maRes
.mnCount
+= node
.size
;
1224 case mdds::mtm::element_empty
:
1231 template<typename Op
, typename tRes
>
1232 class WalkElementBlocksMultipleValues
1234 const std::vector
<Op
>* mpOp
;
1235 ScMatrix::IterateResultMultiple
<tRes
> maRes
;
1237 WalkElementBlocksMultipleValues(const std::vector
<Op
>& aOp
) :
1238 mpOp(&aOp
), maRes(0)
1240 for (const auto& rpOp
: *mpOp
)
1241 maRes
.maAccumulator
.emplace_back(rpOp
.mInitVal
);
1244 WalkElementBlocksMultipleValues( const WalkElementBlocksMultipleValues
& ) = delete;
1245 WalkElementBlocksMultipleValues
& operator= ( const WalkElementBlocksMultipleValues
& ) = delete;
1247 WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues
&& r
) noexcept
1248 : mpOp(r
.mpOp
), maRes(r
.maRes
.mnCount
)
1250 maRes
.maAccumulator
= std::move(r
.maRes
.maAccumulator
);
1253 WalkElementBlocksMultipleValues
& operator=(WalkElementBlocksMultipleValues
&& r
) noexcept
1256 maRes
.maAccumulator
= std::move(r
.maRes
.maAccumulator
);
1257 maRes
.mnCount
= r
.maRes
.mnCount
;
1261 const ScMatrix::IterateResultMultiple
<tRes
>& getResult() const { return maRes
; }
1263 void operator() (const MatrixImplType::element_block_node_type
& node
)
1267 case mdds::mtm::element_numeric
:
1269 typedef MatrixImplType::numeric_block_type block_type
;
1271 block_type::const_iterator it
= block_type::begin(*node
.data
);
1272 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1273 for (; it
!= itEnd
; ++it
)
1275 for (size_t i
= 0u; i
< mpOp
->size(); ++i
)
1276 (*mpOp
)[i
](maRes
.maAccumulator
[i
], *it
);
1278 maRes
.mnCount
+= node
.size
;
1281 case mdds::mtm::element_boolean
:
1283 typedef MatrixImplType::boolean_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_string
:
1296 case mdds::mtm::element_empty
:
1308 bool mbIgnoreEmptyStrings
;
1310 explicit CountElements(bool bCountString
, bool bCountErrors
, bool bIgnoreEmptyStrings
) :
1311 mnCount(0), mbCountString(bCountString
), mbCountErrors(bCountErrors
),
1312 mbIgnoreEmptyStrings(bIgnoreEmptyStrings
) {}
1314 size_t getCount() const { return mnCount
; }
1316 void operator() (const MatrixImplType::element_block_node_type
& node
)
1320 case mdds::mtm::element_numeric
:
1321 mnCount
+= node
.size
;
1324 typedef MatrixImplType::numeric_block_type block_type
;
1326 block_type::const_iterator it
= block_type::begin(*node
.data
);
1327 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1328 for (; it
!= itEnd
; ++it
)
1330 if (!std::isfinite(*it
))
1335 case mdds::mtm::element_boolean
:
1336 mnCount
+= node
.size
;
1338 case mdds::mtm::element_string
:
1341 mnCount
+= node
.size
;
1342 if (mbIgnoreEmptyStrings
)
1344 typedef MatrixImplType::string_block_type block_type
;
1346 block_type::const_iterator it
= block_type::begin(*node
.data
);
1347 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1348 for (; it
!= itEnd
; ++it
)
1356 case mdds::mtm::element_empty
:
1363 const size_t ResultNotSet
= std::numeric_limits
<size_t>::max();
1365 template<typename Type
>
1366 class WalkAndMatchElements
1369 size_t mnStartIndex
;
1375 WalkAndMatchElements(Type aMatchValue
, const MatrixImplType::size_pair_type
& aSize
, size_t nCol1
, size_t nCol2
) :
1376 maMatchValue(std::move(aMatchValue
)),
1377 mnStartIndex( nCol1
* aSize
.row
),
1378 mnStopIndex( (nCol2
+ 1) * aSize
.row
),
1379 mnResult(ResultNotSet
),
1382 assert( nCol1
< aSize
.column
&& nCol2
< aSize
.column
);
1385 size_t getMatching() const { return mnResult
; }
1387 size_t getRemainingCount() const
1389 return mnIndex
< mnStopIndex
? mnStopIndex
- mnIndex
: 0;
1392 size_t compare(const MatrixImplType::element_block_node_type
& node
) const;
1394 void operator() (const MatrixImplType::element_block_node_type
& node
)
1396 // early exit if match already found
1397 if (mnResult
!= ResultNotSet
)
1400 // limit lookup to the requested columns
1401 if (mnStartIndex
<= mnIndex
&& getRemainingCount() > 0)
1403 mnResult
= compare(node
);
1406 mnIndex
+= node
.size
;
1411 size_t WalkAndMatchElements
<double>::compare(const MatrixImplType::element_block_node_type
& node
) const
1416 case mdds::mtm::element_numeric
:
1418 typedef MatrixImplType::numeric_block_type block_type
;
1420 block_type::const_iterator it
= block_type::begin(*node
.data
);
1421 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1422 const size_t nRemaining
= getRemainingCount();
1423 for (; it
!= itEnd
&& nCount
< nRemaining
; ++it
, ++nCount
)
1425 if (*it
== maMatchValue
)
1427 return mnIndex
+ nCount
;
1432 case mdds::mtm::element_boolean
:
1434 typedef MatrixImplType::boolean_block_type block_type
;
1436 block_type::const_iterator it
= block_type::begin(*node
.data
);
1437 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1438 const size_t nRemaining
= getRemainingCount();
1439 for (; it
!= itEnd
&& nCount
< nRemaining
; ++it
, ++nCount
)
1441 if (int(*it
) == maMatchValue
)
1443 return mnIndex
+ nCount
;
1449 case mdds::mtm::element_string
:
1450 case mdds::mtm::element_empty
:
1454 return ResultNotSet
;
1458 size_t WalkAndMatchElements
<svl::SharedString
>::compare(const MatrixImplType::element_block_node_type
& node
) const
1462 case mdds::mtm::element_string
:
1465 typedef MatrixImplType::string_block_type block_type
;
1467 block_type::const_iterator it
= block_type::begin(*node
.data
);
1468 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1469 const size_t nRemaining
= getRemainingCount();
1470 for (; it
!= itEnd
&& nCount
< nRemaining
; ++it
, ++nCount
)
1472 if (it
->getDataIgnoreCase() == maMatchValue
.getDataIgnoreCase())
1474 return mnIndex
+ nCount
;
1479 case mdds::mtm::element_boolean
:
1480 case mdds::mtm::element_numeric
:
1481 case mdds::mtm::element_empty
:
1485 return ResultNotSet
;
1490 static double init() { return -std::numeric_limits
<double>::max(); }
1491 static double compare(double left
, double right
)
1493 if (!std::isfinite(left
))
1495 if (!std::isfinite(right
))
1497 return std::max(left
, right
);
1500 static double boolValue(
1501 MatrixImplType::boolean_block_type::const_iterator it
,
1502 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1504 // If the array has at least one true value, the maximum value is 1.
1505 it
= std::find(it
, itEnd
, true);
1506 return it
== itEnd
? 0.0 : 1.0;
1512 static double init() { return std::numeric_limits
<double>::max(); }
1513 static double compare(double left
, double right
)
1515 if (!std::isfinite(left
))
1517 if (!std::isfinite(right
))
1519 return std::min(left
, right
);
1522 static double boolValue(
1523 MatrixImplType::boolean_block_type::const_iterator it
,
1524 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1526 // If the array has at least one false value, the minimum value is 0.
1527 it
= std::find(it
, itEnd
, false);
1528 return it
== itEnd
? 1.0 : 0.0;
1534 static double init() { return 1.0; }
1535 static double calculate(double fx
,double fy
)
1537 return (fx
*fy
)/ScInterpreter::ScGetGCD(fx
,fy
);
1540 static double boolValue(
1541 MatrixImplType::boolean_block_type::const_iterator it
,
1542 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1544 // If the array has at least one false value, the minimum value is 0.
1545 it
= std::find(it
, itEnd
, false);
1546 return it
== itEnd
? 1.0 : 0.0;
1552 static double init() { return 0.0; }
1553 static double calculate(double fx
,double fy
)
1555 return ScInterpreter::ScGetGCD(fx
,fy
);
1558 static double boolValue(
1559 MatrixImplType::boolean_block_type::const_iterator it
,
1560 const MatrixImplType::boolean_block_type::const_iterator
& itEnd
)
1562 // If the array has at least one true value, the gcdResult is 1.
1563 it
= std::find(it
, itEnd
, true);
1564 return it
== itEnd
? 0.0 : 1.0;
1568 template<typename Op
>
1569 class CalcMaxMinValue
1573 bool mbIgnoreErrorValues
;
1576 CalcMaxMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) :
1578 mbTextAsZero(bTextAsZero
),
1579 mbIgnoreErrorValues(bIgnoreErrorValues
),
1580 mbHasValue(false) {}
1582 double getValue() const { return mbHasValue
? mfVal
: 0.0; }
1584 void operator() (const MatrixImplType::element_block_node_type
& node
)
1589 case mdds::mtm::element_numeric
:
1591 typedef MatrixImplType::numeric_block_type block_type
;
1593 block_type::const_iterator it
= block_type::begin(*node
.data
);
1594 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1595 if (mbIgnoreErrorValues
)
1597 for (; it
!= itEnd
; ++it
)
1599 if (std::isfinite(*it
))
1600 mfVal
= Op::compare(mfVal
, *it
);
1605 for (; it
!= itEnd
; ++it
)
1606 mfVal
= Op::compare(mfVal
, *it
);
1612 case mdds::mtm::element_boolean
:
1614 typedef MatrixImplType::boolean_block_type block_type
;
1616 block_type::const_iterator it
= block_type::begin(*node
.data
);
1617 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1618 double fVal
= Op::boolValue(it
, itEnd
);
1619 mfVal
= Op::compare(mfVal
, fVal
);
1623 case mdds::mtm::element_string
:
1624 case mdds::mtm::element_empty
:
1626 // empty elements are treated as empty strings.
1629 mfVal
= Op::compare(mfVal
, 0.0);
1640 template<typename Op
>
1646 CalcGcdLcm() : mfval(Op::init()) {}
1648 double getResult() const { return mfval
; }
1650 void operator() ( const MatrixImplType::element_block_node_type
& node
)
1654 case mdds::mtm::element_numeric
:
1656 typedef MatrixImplType::numeric_block_type block_type
;
1657 block_type::const_iterator it
= block_type::begin(*node
.data
);
1658 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1660 for ( ; it
!= itEnd
; ++it
)
1663 mfval
= CreateDoubleError(FormulaError::IllegalArgument
);
1665 mfval
= ::rtl::math::approxFloor( Op::calculate(*it
,mfval
));
1669 case mdds::mtm::element_boolean
:
1671 typedef MatrixImplType::boolean_block_type block_type
;
1672 block_type::const_iterator it
= block_type::begin(*node
.data
);
1673 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1675 mfval
= Op::boolValue(it
, itEnd
);
1678 case mdds::mtm::element_empty
:
1679 case mdds::mtm::element_string
:
1681 mfval
= CreateDoubleError(FormulaError::IllegalArgument
);
1690 double evaluate( double fVal
, ScQueryOp eOp
)
1692 if (!std::isfinite(fVal
))
1698 return fVal
== 0.0 ? 1.0 : 0.0;
1700 return fVal
< 0.0 ? 1.0 : 0.0;
1702 return fVal
> 0.0 ? 1.0 : 0.0;
1704 return fVal
<= 0.0 ? 1.0 : 0.0;
1705 case SC_GREATER_EQUAL
:
1706 return fVal
>= 0.0 ? 1.0 : 0.0;
1708 return fVal
!= 0.0 ? 1.0 : 0.0;
1713 SAL_WARN("sc.core", "evaluate: unhandled comparison operator: " << static_cast<int>(eOp
));
1714 return CreateDoubleError( FormulaError::UnknownState
);
1717 class CompareMatrixFunc
1719 sc::Compare
& mrComp
;
1721 sc::CompareOptions
* mpOptions
;
1722 std::vector
<double> maResValues
; // double instead of bool to transport error values
1726 double fVal
= sc::CompareFunc( mrComp
, mpOptions
);
1727 maResValues
.push_back(evaluate(fVal
, mrComp
.meOp
));
1731 CompareMatrixFunc( size_t nResSize
, sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) :
1732 mrComp(rComp
), mnMatPos(nMatPos
), mpOptions(pOptions
)
1734 maResValues
.reserve(nResSize
);
1737 CompareMatrixFunc( const CompareMatrixFunc
& ) = delete;
1738 CompareMatrixFunc
& operator= ( const CompareMatrixFunc
& ) = delete;
1740 CompareMatrixFunc(CompareMatrixFunc
&& r
) noexcept
:
1742 mnMatPos(r
.mnMatPos
),
1743 mpOptions(r
.mpOptions
),
1744 maResValues(std::move(r
.maResValues
)) {}
1746 CompareMatrixFunc
& operator=(CompareMatrixFunc
&& r
) noexcept
1749 mnMatPos
= r
.mnMatPos
;
1750 mpOptions
= r
.mpOptions
;
1751 maResValues
= std::move(r
.maResValues
);
1755 void operator() (const MatrixImplType::element_block_node_type
& node
)
1757 sc::Compare::Cell
& rCell
= mrComp
.maCells
[mnMatPos
];
1761 case mdds::mtm::element_numeric
:
1763 typedef MatrixImplType::numeric_block_type block_type
;
1765 block_type::const_iterator it
= block_type::begin(*node
.data
);
1766 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1767 for (; it
!= itEnd
; ++it
)
1769 rCell
.mbValue
= true;
1770 rCell
.mbEmpty
= false;
1771 rCell
.mfValue
= *it
;
1776 case mdds::mtm::element_boolean
:
1778 typedef MatrixImplType::boolean_block_type block_type
;
1780 block_type::const_iterator it
= block_type::begin(*node
.data
);
1781 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1782 for (; it
!= itEnd
; ++it
)
1784 rCell
.mbValue
= true;
1785 rCell
.mbEmpty
= false;
1786 rCell
.mfValue
= double(*it
);
1791 case mdds::mtm::element_string
:
1793 typedef MatrixImplType::string_block_type block_type
;
1795 block_type::const_iterator it
= block_type::begin(*node
.data
);
1796 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1797 for (; it
!= itEnd
; ++it
)
1799 const svl::SharedString
& rStr
= *it
;
1800 rCell
.mbValue
= false;
1801 rCell
.mbEmpty
= false;
1807 case mdds::mtm::element_empty
:
1809 rCell
.mbValue
= false;
1810 rCell
.mbEmpty
= true;
1811 rCell
.maStr
= svl::SharedString::getEmptyString();
1812 for (size_t i
= 0; i
< node
.size
; ++i
)
1821 const std::vector
<double>& getValues() const
1828 * Left-hand side is a matrix while the right-hand side is a numeric value.
1830 class CompareMatrixToNumericFunc
1832 sc::Compare
& mrComp
;
1833 double mfRightValue
;
1834 sc::CompareOptions
* mpOptions
;
1835 std::vector
<double> maResValues
; // double instead of bool to transport error values
1839 double fVal
= sc::CompareFunc(mrComp
.maCells
[0], mfRightValue
, mpOptions
);
1840 maResValues
.push_back(evaluate(fVal
, mrComp
.meOp
));
1843 void compareLeftNumeric( double fLeftVal
)
1845 double fVal
= sc::CompareFunc(fLeftVal
, mfRightValue
);
1846 maResValues
.push_back(evaluate(fVal
, mrComp
.meOp
));
1849 void compareLeftEmpty( size_t nSize
)
1851 double fVal
= sc::CompareEmptyToNumericFunc(mfRightValue
);
1852 bool bRes
= evaluate(fVal
, mrComp
.meOp
);
1853 maResValues
.resize(maResValues
.size() + nSize
, bRes
? 1.0 : 0.0);
1857 CompareMatrixToNumericFunc( size_t nResSize
, sc::Compare
& rComp
, double fRightValue
, sc::CompareOptions
* pOptions
) :
1858 mrComp(rComp
), mfRightValue(fRightValue
), mpOptions(pOptions
)
1860 maResValues
.reserve(nResSize
);
1863 CompareMatrixToNumericFunc( const CompareMatrixToNumericFunc
& ) = delete;
1864 CompareMatrixToNumericFunc
& operator= ( const CompareMatrixToNumericFunc
& ) = delete;
1866 CompareMatrixToNumericFunc(CompareMatrixToNumericFunc
&& r
) noexcept
:
1868 mfRightValue(r
.mfRightValue
),
1869 mpOptions(r
.mpOptions
),
1870 maResValues(std::move(r
.maResValues
)) {}
1872 CompareMatrixToNumericFunc
& operator=(CompareMatrixToNumericFunc
&& r
) noexcept
1875 mfRightValue
= r
.mfRightValue
;
1876 mpOptions
= r
.mpOptions
;
1877 maResValues
= std::move(r
.maResValues
);
1881 void operator() (const MatrixImplType::element_block_node_type
& node
)
1885 case mdds::mtm::element_numeric
:
1887 typedef MatrixImplType::numeric_block_type block_type
;
1889 block_type::const_iterator it
= block_type::begin(*node
.data
);
1890 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1891 for (; it
!= itEnd
; ++it
)
1892 compareLeftNumeric(*it
);
1895 case mdds::mtm::element_boolean
:
1897 typedef MatrixImplType::boolean_block_type block_type
;
1899 block_type::const_iterator it
= block_type::begin(*node
.data
);
1900 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1901 for (; it
!= itEnd
; ++it
)
1902 compareLeftNumeric(double(*it
));
1905 case mdds::mtm::element_string
:
1907 typedef MatrixImplType::string_block_type block_type
;
1909 block_type::const_iterator it
= block_type::begin(*node
.data
);
1910 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
1911 for (; it
!= itEnd
; ++it
)
1913 const svl::SharedString
& rStr
= *it
;
1914 sc::Compare::Cell
& rCell
= mrComp
.maCells
[0];
1915 rCell
.mbValue
= false;
1916 rCell
.mbEmpty
= false;
1922 case mdds::mtm::element_empty
:
1923 compareLeftEmpty(node
.size
);
1930 const std::vector
<double>& getValues() const
1938 std::vector
<double> maArray
;
1939 std::vector
<double>::iterator miPos
;
1943 void moveArray( ToDoubleArray
& r
)
1945 // Re-create the iterator from the new array after the array has been
1946 // moved, to ensure that the iterator points to a valid array
1948 size_t n
= std::distance(r
.maArray
.begin(), r
.miPos
);
1949 maArray
= std::move(r
.maArray
);
1950 miPos
= maArray
.begin();
1951 std::advance(miPos
, n
);
1955 ToDoubleArray( size_t nSize
, bool bEmptyAsZero
) :
1956 maArray(nSize
, 0.0), miPos(maArray
.begin()), mbEmptyAsZero(bEmptyAsZero
)
1958 mfNaN
= CreateDoubleError( FormulaError::ElementNaN
);
1961 ToDoubleArray( const ToDoubleArray
& ) = delete;
1962 ToDoubleArray
& operator= ( const ToDoubleArray
& ) = delete;
1964 ToDoubleArray(ToDoubleArray
&& r
) noexcept
:
1965 mfNaN(r
.mfNaN
), mbEmptyAsZero(r
.mbEmptyAsZero
)
1970 ToDoubleArray
& operator=(ToDoubleArray
&& r
) noexcept
1973 mbEmptyAsZero
= r
.mbEmptyAsZero
;
1978 void operator() (const MatrixImplType::element_block_node_type
& node
)
1980 using namespace mdds::mtv
;
1984 case mdds::mtm::element_numeric
:
1986 double_element_block::const_iterator it
= double_element_block::begin(*node
.data
);
1987 double_element_block::const_iterator itEnd
= double_element_block::end(*node
.data
);
1988 for (; it
!= itEnd
; ++it
, ++miPos
)
1992 case mdds::mtm::element_boolean
:
1994 boolean_element_block::const_iterator it
= boolean_element_block::begin(*node
.data
);
1995 boolean_element_block::const_iterator itEnd
= boolean_element_block::end(*node
.data
);
1996 for (; it
!= itEnd
; ++it
, ++miPos
)
1997 *miPos
= *it
? 1.0 : 0.0;
2000 case mdds::mtm::element_string
:
2002 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2006 case mdds::mtm::element_empty
:
2010 std::advance(miPos
, node
.size
);
2014 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2023 void swap(std::vector
<double>& rOther
)
2025 maArray
.swap(rOther
);
2031 double operator() (const double& lhs
, const double& rhs
) const
2037 template<typename Op
>
2038 class MergeDoubleArrayFunc
2040 std::vector
<double>::iterator miPos
;
2043 MergeDoubleArrayFunc(std::vector
<double>& rArray
) : miPos(rArray
.begin())
2045 mfNaN
= CreateDoubleError( FormulaError::ElementNaN
);
2048 MergeDoubleArrayFunc( const MergeDoubleArrayFunc
& ) = delete;
2049 MergeDoubleArrayFunc
& operator= ( const MergeDoubleArrayFunc
& ) = delete;
2051 MergeDoubleArrayFunc( MergeDoubleArrayFunc
&& ) = default;
2052 MergeDoubleArrayFunc
& operator= ( MergeDoubleArrayFunc
&& ) = default;
2054 void operator() (const MatrixImplType::element_block_node_type
& node
)
2056 using namespace mdds::mtv
;
2061 case mdds::mtm::element_numeric
:
2063 double_element_block::const_iterator it
= double_element_block::begin(*node
.data
);
2064 double_element_block::const_iterator itEnd
= double_element_block::end(*node
.data
);
2065 for (; it
!= itEnd
; ++it
, ++miPos
)
2067 if (GetDoubleErrorValue(*miPos
) == FormulaError::ElementNaN
)
2070 *miPos
= op(*miPos
, *it
);
2074 case mdds::mtm::element_boolean
:
2076 boolean_element_block::const_iterator it
= boolean_element_block::begin(*node
.data
);
2077 boolean_element_block::const_iterator itEnd
= boolean_element_block::end(*node
.data
);
2078 for (; it
!= itEnd
; ++it
, ++miPos
)
2080 if (GetDoubleErrorValue(*miPos
) == FormulaError::ElementNaN
)
2083 *miPos
= op(*miPos
, *it
? 1.0 : 0.0);
2087 case mdds::mtm::element_string
:
2089 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2093 case mdds::mtm::element_empty
:
2095 // Empty element is equivalent of having a numeric value of 0.0.
2096 for (size_t i
= 0; i
< node
.size
; ++i
, ++miPos
)
2098 if (GetDoubleErrorValue(*miPos
) == FormulaError::ElementNaN
)
2101 *miPos
= op(*miPos
, 0.0);
2115 template<typename TOp
, typename tRes
>
2116 ScMatrix::IterateResult
<tRes
> GetValueWithCount(bool bTextAsZero
, bool bIgnoreErrorValues
, const MatrixImplType
& maMat
)
2118 WalkElementBlocks
<TOp
, tRes
> aFunc(bTextAsZero
, bIgnoreErrorValues
);
2119 aFunc
= maMat
.walk(aFunc
);
2120 return aFunc
.getResult();
2125 ScMatrix::KahanIterateResult
ScMatrixImpl::Sum(bool bTextAsZero
, bool bIgnoreErrorValues
) const
2127 return GetValueWithCount
<sc::op::Sum
, KahanSum
>(bTextAsZero
, bIgnoreErrorValues
, maMat
);
2130 ScMatrix::KahanIterateResult
ScMatrixImpl::SumSquare(bool bTextAsZero
, bool bIgnoreErrorValues
) const
2132 return GetValueWithCount
<sc::op::SumSquare
, KahanSum
>(bTextAsZero
, bIgnoreErrorValues
, maMat
);
2135 ScMatrix::DoubleIterateResult
ScMatrixImpl::Product(bool bTextAsZero
, bool bIgnoreErrorValues
) const
2137 return GetValueWithCount
<sc::op::Product
, double>(bTextAsZero
, bIgnoreErrorValues
, maMat
);
2140 size_t ScMatrixImpl::Count(bool bCountStrings
, bool bCountErrors
, bool bIgnoreEmptyStrings
) const
2142 CountElements
aFunc(bCountStrings
, bCountErrors
, bIgnoreEmptyStrings
);
2143 aFunc
= maMat
.walk(aFunc
);
2144 return aFunc
.getCount();
2147 size_t ScMatrixImpl::MatchDoubleInColumns(double fValue
, size_t nCol1
, size_t nCol2
) const
2149 WalkAndMatchElements
<double> aFunc(fValue
, maMat
.size(), nCol1
, nCol2
);
2150 aFunc
= maMat
.walk(aFunc
);
2151 return aFunc
.getMatching();
2154 size_t ScMatrixImpl::MatchStringInColumns(const svl::SharedString
& rStr
, size_t nCol1
, size_t nCol2
) const
2156 WalkAndMatchElements
<svl::SharedString
> aFunc(rStr
, maMat
.size(), nCol1
, nCol2
);
2157 aFunc
= maMat
.walk(aFunc
);
2158 return aFunc
.getMatching();
2161 double ScMatrixImpl::GetMaxValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
2163 CalcMaxMinValue
<MaxOp
> aFunc(bTextAsZero
, bIgnoreErrorValues
);
2164 aFunc
= maMat
.walk(aFunc
);
2165 return aFunc
.getValue();
2168 double ScMatrixImpl::GetMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
2170 CalcMaxMinValue
<MinOp
> aFunc(bTextAsZero
, bIgnoreErrorValues
);
2171 aFunc
= maMat
.walk(aFunc
);
2172 return aFunc
.getValue();
2175 double ScMatrixImpl::GetGcd() const
2177 CalcGcdLcm
<Gcd
> aFunc
;
2178 aFunc
= maMat
.walk(aFunc
);
2179 return aFunc
.getResult();
2182 double ScMatrixImpl::GetLcm() const
2184 CalcGcdLcm
<Lcm
> aFunc
;
2185 aFunc
= maMat
.walk(aFunc
);
2186 return aFunc
.getResult();
2189 ScMatrixRef
ScMatrixImpl::CompareMatrix(
2190 sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) const
2192 MatrixImplType::size_pair_type aSize
= maMat
.size();
2193 size_t nSize
= aSize
.column
* aSize
.row
;
2196 if (rComp
.maCells
[1].mbValue
&& !rComp
.maCells
[1].mbEmpty
)
2198 // Matrix on the left, and a numeric value on the right. Use a
2199 // function object that has much less branching for much better
2201 CompareMatrixToNumericFunc
aFunc(nSize
, rComp
, rComp
.maCells
[1].mfValue
, pOptions
);
2202 aFunc
= maMat
.walk(std::move(aFunc
));
2204 // We assume the result matrix has the same dimension as this matrix.
2205 const std::vector
<double>& rResVal
= aFunc
.getValues();
2206 assert (nSize
== rResVal
.size());
2207 if (nSize
!= rResVal
.size())
2208 return ScMatrixRef();
2210 return ScMatrixRef(new ScMatrix(aSize
.column
, aSize
.row
, rResVal
));
2214 CompareMatrixFunc
aFunc(nSize
, rComp
, nMatPos
, pOptions
);
2215 aFunc
= maMat
.walk(std::move(aFunc
));
2217 // We assume the result matrix has the same dimension as this matrix.
2218 const std::vector
<double>& rResVal
= aFunc
.getValues();
2219 assert (nSize
== rResVal
.size());
2220 if (nSize
!= rResVal
.size())
2221 return ScMatrixRef();
2223 return ScMatrixRef(new ScMatrix(aSize
.column
, aSize
.row
, rResVal
));
2226 void ScMatrixImpl::GetDoubleArray( std::vector
<double>& rArray
, bool bEmptyAsZero
) const
2228 MatrixImplType::size_pair_type aSize
= maMat
.size();
2229 ToDoubleArray
aFunc(aSize
.row
*aSize
.column
, bEmptyAsZero
);
2230 aFunc
= maMat
.walk(std::move(aFunc
));
2234 void ScMatrixImpl::MergeDoubleArrayMultiply( std::vector
<double>& rArray
) const
2236 MatrixImplType::size_pair_type aSize
= maMat
.size();
2237 size_t nSize
= aSize
.row
*aSize
.column
;
2238 if (nSize
!= rArray
.size())
2241 MergeDoubleArrayFunc
<ArrayMul
> aFunc(rArray
);
2242 maMat
.walk(std::move(aFunc
));
2247 template<typename T
, typename U
, typename return_type
>
2248 struct wrapped_iterator
2250 typedef ::std::bidirectional_iterator_tag iterator_category
;
2251 typedef typename
T::const_iterator::value_type old_value_type
;
2252 typedef return_type value_type
;
2253 typedef value_type
* pointer
;
2254 typedef value_type
& reference
;
2255 typedef typename
T::const_iterator::difference_type difference_type
;
2257 typename
T::const_iterator it
;
2258 mutable value_type val
;
2263 value_type
calcVal() const
2270 wrapped_iterator(typename
T::const_iterator it_
, U
const & aOp
):
2277 wrapped_iterator(const wrapped_iterator
& r
):
2284 wrapped_iterator
& operator=(const wrapped_iterator
& r
)
2290 bool operator==(const wrapped_iterator
& r
) const
2295 bool operator!=(const wrapped_iterator
& r
) const
2297 return !operator==(r
);
2300 wrapped_iterator
& operator++()
2307 wrapped_iterator
& operator--()
2314 value_type
& operator*() const
2320 pointer
operator->() const
2327 template<typename T
, typename U
, typename return_type
>
2328 struct MatrixIteratorWrapper
2331 typename
T::const_iterator m_itBegin
;
2332 typename
T::const_iterator m_itEnd
;
2335 MatrixIteratorWrapper(typename
T::const_iterator itBegin
, typename
T::const_iterator itEnd
, U
const & aOp
):
2336 m_itBegin(std::move(itBegin
)),
2337 m_itEnd(std::move(itEnd
)),
2342 wrapped_iterator
<T
, U
, return_type
> begin()
2344 return wrapped_iterator
<T
, U
, return_type
>(m_itBegin
, maOp
);
2347 wrapped_iterator
<T
, U
, return_type
> end()
2349 return wrapped_iterator
<T
, U
, return_type
>(m_itEnd
, maOp
);
2353 MatrixImplType::position_type
increment_position(const MatrixImplType::position_type
& pos
, size_t n
)
2355 MatrixImplType::position_type ret
= pos
;
2358 if (ret
.second
+ n
< ret
.first
->size
)
2365 n
-= (ret
.first
->size
- ret
.second
);
2374 template<typename T
>
2375 struct MatrixOpWrapper
2378 MatrixImplType
& mrMat
;
2379 MatrixImplType::position_type pos
;
2383 MatrixOpWrapper(MatrixImplType
& rMat
, const T
& aOp
):
2385 pos(rMat
.position(0,0)),
2390 MatrixOpWrapper( const MatrixOpWrapper
& r
) : mrMat(r
.mrMat
), pos(r
.pos
), mpOp(r
.mpOp
) {}
2392 MatrixOpWrapper
& operator= ( const MatrixOpWrapper
& r
) = default;
2394 void operator()(const MatrixImplType::element_block_node_type
& node
)
2398 case mdds::mtm::element_numeric
:
2400 typedef MatrixImplType::numeric_block_type block_type
;
2402 block_type::const_iterator it
= block_type::begin(*node
.data
);
2403 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
2404 MatrixIteratorWrapper
<block_type
, T
, typename
T::number_value_type
> aFunc(it
, itEnd
, *mpOp
);
2405 pos
= mrMat
.set(pos
,aFunc
.begin(), aFunc
.end());
2408 case mdds::mtm::element_boolean
:
2410 typedef MatrixImplType::boolean_block_type block_type
;
2412 block_type::const_iterator it
= block_type::begin(*node
.data
);
2413 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
2415 MatrixIteratorWrapper
<block_type
, T
, typename
T::number_value_type
> aFunc(it
, itEnd
, *mpOp
);
2416 pos
= mrMat
.set(pos
, aFunc
.begin(), aFunc
.end());
2419 case mdds::mtm::element_string
:
2421 typedef MatrixImplType::string_block_type block_type
;
2423 block_type::const_iterator it
= block_type::begin(*node
.data
);
2424 block_type::const_iterator itEnd
= block_type::end(*node
.data
);
2426 MatrixIteratorWrapper
<block_type
, T
, typename
T::number_value_type
> aFunc(it
, itEnd
, *mpOp
);
2427 pos
= mrMat
.set(pos
, aFunc
.begin(), aFunc
.end());
2430 case mdds::mtm::element_empty
:
2432 if (mpOp
->useFunctionForEmpty())
2434 std::vector
<char> aVec(node
.size
);
2435 MatrixIteratorWrapper
<std::vector
<char>, T
, typename
T::number_value_type
>
2436 aFunc(aVec
.begin(), aVec
.end(), *mpOp
);
2437 pos
= mrMat
.set(pos
, aFunc
.begin(), aFunc
.end());
2444 pos
= increment_position(pos
, node
.size
);
2450 template<typename T
>
2451 void ScMatrixImpl::ApplyOperation(T aOp
, ScMatrixImpl
& rMat
)
2453 MatrixOpWrapper
<T
> aFunc(rMat
.maMat
, aOp
);
2457 template<typename T
, typename tRes
>
2458 ScMatrix::IterateResultMultiple
<tRes
> ScMatrixImpl::ApplyCollectOperation(const std::vector
<T
>& aOp
)
2460 WalkElementBlocksMultipleValues
<T
, tRes
> aFunc(aOp
);
2461 aFunc
= maMat
.walk(std::move(aFunc
));
2462 return aFunc
.getResult();
2469 ElementBlock(size_t nRowSize
,
2470 ScMatrix::DoubleOpFunction aDoubleFunc
,
2471 ScMatrix::BoolOpFunction aBoolFunc
,
2472 ScMatrix::StringOpFunction aStringFunc
,
2473 ScMatrix::EmptyOpFunction aEmptyFunc
):
2474 mnRowSize(nRowSize
),
2477 maDoubleFunc(std::move(aDoubleFunc
)),
2478 maBoolFunc(std::move(aBoolFunc
)),
2479 maStringFunc(std::move(aStringFunc
)),
2480 maEmptyFunc(std::move(aEmptyFunc
))
2488 ScMatrix::DoubleOpFunction maDoubleFunc
;
2489 ScMatrix::BoolOpFunction maBoolFunc
;
2490 ScMatrix::StringOpFunction maStringFunc
;
2491 ScMatrix::EmptyOpFunction maEmptyFunc
;
2494 class WalkElementBlockOperation
2498 WalkElementBlockOperation(ElementBlock
& rElementBlock
)
2499 : mrElementBlock(rElementBlock
)
2503 void operator()(const MatrixImplType::element_block_node_type
& node
)
2507 case mdds::mtm::element_numeric
:
2509 typedef MatrixImplType::numeric_block_type block_type
;
2511 block_type::const_iterator it
= block_type::begin(*node
.data
);
2512 std::advance(it
, node
.offset
);
2513 block_type::const_iterator itEnd
= it
;
2514 std::advance(itEnd
, node
.size
);
2515 for (auto itr
= it
; itr
!= itEnd
; ++itr
)
2517 mrElementBlock
.maDoubleFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
, *itr
);
2518 ++mrElementBlock
.mnRowPos
;
2519 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2521 mrElementBlock
.mnRowPos
= 0;
2522 ++mrElementBlock
.mnColPos
;
2527 case mdds::mtm::element_string
:
2529 typedef MatrixImplType::string_block_type block_type
;
2531 block_type::const_iterator it
= block_type::begin(*node
.data
);
2532 std::advance(it
, node
.offset
);
2533 block_type::const_iterator itEnd
= it
;
2534 std::advance(itEnd
, node
.size
);
2535 for (auto itr
= it
; itr
!= itEnd
; ++itr
)
2537 mrElementBlock
.maStringFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
, *itr
);
2538 ++mrElementBlock
.mnRowPos
;
2539 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2541 mrElementBlock
.mnRowPos
= 0;
2542 ++mrElementBlock
.mnColPos
;
2547 case mdds::mtm::element_boolean
:
2549 typedef MatrixImplType::boolean_block_type block_type
;
2551 block_type::const_iterator it
= block_type::begin(*node
.data
);
2552 std::advance(it
, node
.offset
);
2553 block_type::const_iterator itEnd
= it
;
2554 std::advance(itEnd
, node
.size
);
2555 for (auto itr
= it
; itr
!= itEnd
; ++itr
)
2557 mrElementBlock
.maBoolFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
, *itr
);
2558 ++mrElementBlock
.mnRowPos
;
2559 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2561 mrElementBlock
.mnRowPos
= 0;
2562 ++mrElementBlock
.mnColPos
;
2567 case mdds::mtm::element_empty
:
2569 for (size_t i
=0; i
< node
.size
; ++i
)
2571 mrElementBlock
.maEmptyFunc(mrElementBlock
.mnRowPos
, mrElementBlock
.mnColPos
);
2572 ++mrElementBlock
.mnRowPos
;
2573 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2575 mrElementBlock
.mnRowPos
= 0;
2576 ++mrElementBlock
.mnColPos
;
2581 case mdds::mtm::element_integer
:
2583 SAL_WARN("sc.core","WalkElementBlockOperation - unhandled element_integer");
2584 // No function (yet?), but advance row and column count.
2585 mrElementBlock
.mnColPos
+= node
.size
/ mrElementBlock
.mnRowSize
;
2586 mrElementBlock
.mnRowPos
+= node
.size
% mrElementBlock
.mnRowSize
;
2587 if (mrElementBlock
.mnRowPos
>= mrElementBlock
.mnRowSize
)
2589 mrElementBlock
.mnRowPos
= 0;
2590 ++mrElementBlock
.mnColPos
;
2599 ElementBlock
& mrElementBlock
;
2604 void ScMatrixImpl::ExecuteOperation(const std::pair
<size_t, size_t>& rStartPos
,
2605 const std::pair
<size_t, size_t>& rEndPos
, const ScMatrix::DoubleOpFunction
& aDoubleFunc
,
2606 const ScMatrix::BoolOpFunction
& aBoolFunc
, const ScMatrix::StringOpFunction
& aStringFunc
,
2607 const ScMatrix::EmptyOpFunction
& aEmptyFunc
) const
2609 ElementBlock
aPayload(maMat
.size().row
, aDoubleFunc
, aBoolFunc
, aStringFunc
, aEmptyFunc
);
2610 WalkElementBlockOperation
aFunc(aPayload
);
2613 MatrixImplType::size_pair_type(rStartPos
.first
, rStartPos
.second
),
2614 MatrixImplType::size_pair_type(rEndPos
.first
, rEndPos
.second
));
2619 void ScMatrixImpl::Dump() const
2621 cout
<< "-- matrix content" << endl
;
2622 SCSIZE nCols
, nRows
;
2623 GetDimensions(nCols
, nRows
);
2624 for (SCSIZE nRow
= 0; nRow
< nRows
; ++nRow
)
2626 for (SCSIZE nCol
= 0; nCol
< nCols
; ++nCol
)
2628 cout
<< " row=" << nRow
<< ", col=" << nCol
<< " : ";
2629 switch (maMat
.get_type(nRow
, nCol
))
2631 case mdds::mtm::element_string
:
2632 cout
<< "string (" << maMat
.get_string(nRow
, nCol
).getString() << ")";
2634 case mdds::mtm::element_numeric
:
2635 cout
<< "numeric (" << maMat
.get_numeric(nRow
, nCol
) << ")";
2637 case mdds::mtm::element_boolean
:
2638 cout
<< "boolean (" << maMat
.get_boolean(nRow
, nCol
) << ")";
2640 case mdds::mtm::element_empty
:
2653 void ScMatrixImpl::CalcPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const
2655 SCSIZE nRowSize
= maMat
.size().row
;
2656 SAL_WARN_IF( !nRowSize
, "sc.core", "ScMatrixImpl::CalcPosition: 0 rows!");
2657 rC
= nRowSize
> 1 ? nIndex
/ nRowSize
: nIndex
;
2658 rR
= nIndex
- rC
*nRowSize
;
2661 void ScMatrixImpl::CalcTransPosition(SCSIZE nIndex
, SCSIZE
& rC
, SCSIZE
& rR
) const
2663 SCSIZE nColSize
= maMat
.size().column
;
2664 SAL_WARN_IF(!nColSize
, "sc.core", "ScMatrixImpl::CalcPosition: 0 cols!");
2665 rR
= nColSize
> 1 ? nIndex
/ nColSize
: nIndex
;
2666 rC
= nIndex
- rR
* nColSize
;
2671 size_t get_index(SCSIZE nMaxRow
, size_t nRow
, size_t nCol
, size_t nRowOffset
, size_t nColOffset
)
2673 return nMaxRow
* (nCol
+ nColOffset
) + nRow
+ nRowOffset
;
2678 void ScMatrixImpl::MatConcat(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrixRef
& xMat1
, const ScMatrixRef
& xMat2
,
2679 SvNumberFormatter
& rFormatter
, svl::SharedStringPool
& rStringPool
)
2683 xMat1
->GetDimensions(nC1
, nR1
);
2684 xMat2
->GetDimensions(nC2
, nR2
);
2686 sal_uInt32 nKey
= rFormatter
.GetStandardFormat( SvNumFormatType::NUMBER
,
2689 std::vector
<OUString
> aString(nMaxCol
* nMaxRow
);
2690 std::vector
<bool> aValid(nMaxCol
* nMaxRow
, true);
2691 std::vector
<FormulaError
> nErrors(nMaxCol
* nMaxRow
,FormulaError::NONE
);
2693 size_t nRowOffset
= 0;
2694 size_t nColOffset
= 0;
2695 std::function
<void(size_t, size_t, double)> aDoubleFunc
=
2696 [&](size_t nRow
, size_t nCol
, double nVal
)
2698 FormulaError nErr
= GetDoubleErrorValue(nVal
);
2699 if (nErr
!= FormulaError::NONE
)
2701 aValid
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = false;
2702 nErrors
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = nErr
;
2706 rFormatter
.GetInputLineString( nVal
, nKey
, aStr
);
2707 aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
;
2710 std::function
<void(size_t, size_t, bool)> aBoolFunc
=
2711 [&](size_t nRow
, size_t nCol
, bool nVal
)
2714 rFormatter
.GetInputLineString( nVal
? 1.0 : 0.0, nKey
, aStr
);
2715 aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
;
2718 std::function
<void(size_t, size_t, const svl::SharedString
&)> aStringFunc
=
2719 [&](size_t nRow
, size_t nCol
, const svl::SharedString
& aStr
)
2721 aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
.getString();
2724 std::function
<void(size_t, size_t)> aEmptyFunc
=
2725 [](size_t /*nRow*/, size_t /*nCol*/)
2727 // Nothing. Concatenating an empty string to an existing string.
2731 if (nC1
== 1 || nR1
== 1)
2733 size_t nRowRep
= nR1
== 1 ? nMaxRow
: 1;
2734 size_t nColRep
= nC1
== 1 ? nMaxCol
: 1;
2736 for (size_t i
= 0; i
< nRowRep
; ++i
)
2739 for (size_t j
= 0; j
< nColRep
; ++j
)
2742 xMat1
->ExecuteOperation(
2743 std::pair
<size_t, size_t>(0, 0),
2744 std::pair
<size_t, size_t>(std::min(nR1
, nMaxRow
) - 1, std::min(nC1
, nMaxCol
) - 1),
2745 aDoubleFunc
, aBoolFunc
, aStringFunc
, aEmptyFunc
);
2750 xMat1
->ExecuteOperation(
2751 std::pair
<size_t, size_t>(0, 0),
2752 std::pair
<size_t, size_t>(nMaxRow
- 1, nMaxCol
- 1),
2753 std::move(aDoubleFunc
), std::move(aBoolFunc
), std::move(aStringFunc
), std::move(aEmptyFunc
));
2755 std::vector
<svl::SharedString
> aSharedString(nMaxCol
*nMaxRow
);
2757 std::function
<void(size_t, size_t, double)> aDoubleFunc2
=
2758 [&](size_t nRow
, size_t nCol
, double nVal
)
2760 FormulaError nErr
= GetDoubleErrorValue(nVal
);
2761 if (nErr
!= FormulaError::NONE
)
2763 aValid
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = false;
2764 nErrors
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = nErr
;
2768 rFormatter
.GetInputLineString( nVal
, nKey
, aStr
);
2769 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
);
2772 std::function
<void(size_t, size_t, bool)> aBoolFunc2
=
2773 [&](size_t nRow
, size_t nCol
, bool nVal
)
2776 rFormatter
.GetInputLineString( nVal
? 1.0 : 0.0, nKey
, aStr
);
2777 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] = rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
);
2780 std::function
<void(size_t, size_t, const svl::SharedString
&)> aStringFunc2
=
2781 [&](size_t nRow
, size_t nCol
, const svl::SharedString
& aStr
)
2783 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] =
2784 rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] + aStr
.getString());
2787 std::function
<void(size_t, size_t)> aEmptyFunc2
=
2788 [&](size_t nRow
, size_t nCol
)
2790 aSharedString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)] =
2791 rStringPool
.intern(aString
[get_index(nMaxRow
, nRow
, nCol
, nRowOffset
, nColOffset
)]);
2796 if (nC2
== 1 || nR2
== 1)
2798 size_t nRowRep
= nR2
== 1 ? nMaxRow
: 1;
2799 size_t nColRep
= nC2
== 1 ? nMaxCol
: 1;
2801 for (size_t i
= 0; i
< nRowRep
; ++i
)
2804 for (size_t j
= 0; j
< nColRep
; ++j
)
2807 xMat2
->ExecuteOperation(
2808 std::pair
<size_t, size_t>(0, 0),
2809 std::pair
<size_t, size_t>(std::min(nR2
, nMaxRow
) - 1, std::min(nC2
, nMaxCol
) - 1),
2810 aDoubleFunc2
, aBoolFunc2
, aStringFunc2
, aEmptyFunc2
);
2815 xMat2
->ExecuteOperation(
2816 std::pair
<size_t, size_t>(0, 0),
2817 std::pair
<size_t, size_t>(nMaxRow
- 1, nMaxCol
- 1),
2818 std::move(aDoubleFunc2
), std::move(aBoolFunc2
), std::move(aStringFunc2
), std::move(aEmptyFunc2
));
2822 MatrixImplType::position_type pos
= maMat
.position(0, 0);
2823 for (SCSIZE i
= 0; i
< nMaxCol
; ++i
)
2825 for (SCSIZE j
= 0; j
< nMaxRow
&& i
< nMaxCol
; ++j
)
2827 if (aValid
[nMaxRow
* i
+ j
])
2829 auto itr
= aValid
.begin();
2830 std::advance(itr
, nMaxRow
* i
+ j
);
2831 auto itrEnd
= std::find(itr
, aValid
.end(), false);
2832 size_t nSteps
= std::distance(itr
, itrEnd
);
2833 auto itrStr
= aSharedString
.begin();
2834 std::advance(itrStr
, nMaxRow
* i
+ j
);
2835 auto itrEndStr
= itrStr
;
2836 std::advance(itrEndStr
, nSteps
);
2837 pos
= maMat
.set(pos
, itrStr
, itrEndStr
);
2838 size_t nColSteps
= nSteps
/ nMaxRow
;
2840 j
+= nSteps
% nMaxRow
;
2849 pos
= maMat
.set(pos
, CreateDoubleError(nErrors
[nMaxRow
* i
+ j
]));
2851 pos
= MatrixImplType::next_position(pos
);
2856 bool ScMatrixImpl::IsValueOrEmpty( const MatrixImplType::const_position_type
& rPos
) const
2858 switch (maMat
.get_type(rPos
))
2860 case mdds::mtm::element_boolean
:
2861 case mdds::mtm::element_numeric
:
2862 case mdds::mtm::element_empty
:
2870 double ScMatrixImpl::GetDouble(const MatrixImplType::const_position_type
& rPos
) const
2872 double fVal
= maMat
.get_numeric(rPos
);
2873 if ( pErrorInterpreter
)
2875 FormulaError nError
= GetDoubleErrorValue(fVal
);
2876 if ( nError
!= FormulaError::NONE
)
2877 SetErrorAtInterpreter( nError
);
2882 FormulaError
ScMatrixImpl::GetErrorIfNotString( const MatrixImplType::const_position_type
& rPos
) const
2883 { return IsValue(rPos
) ? GetError(rPos
) : FormulaError::NONE
; }
2885 bool ScMatrixImpl::IsValue( const MatrixImplType::const_position_type
& rPos
) const
2887 switch (maMat
.get_type(rPos
))
2889 case mdds::mtm::element_boolean
:
2890 case mdds::mtm::element_numeric
:
2898 FormulaError
ScMatrixImpl::GetError(const MatrixImplType::const_position_type
& rPos
) const
2900 double fVal
= maMat
.get_numeric(rPos
);
2901 return GetDoubleErrorValue(fVal
);
2904 bool ScMatrixImpl::IsStringOrEmpty(const MatrixImplType::const_position_type
& rPos
) const
2906 switch (maMat
.get_type(rPos
))
2908 case mdds::mtm::element_empty
:
2909 case mdds::mtm::element_string
:
2917 void ScMatrixImpl::ExecuteBinaryOp(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrix
& rInputMat1
, const ScMatrix
& rInputMat2
,
2918 ScInterpreter
* pInterpreter
, ScMatrix::CalculateOpFunction Op
)
2920 // Check output matrix size, otherwise output iterator logic will be wrong.
2921 assert(maMat
.size().row
== nMaxRow
&& maMat
.size().column
== nMaxCol
2922 && "the caller code should have sized the output matrix to the passed dimensions");
2923 auto & rMatImpl1
= *rInputMat1
.pImpl
;
2924 auto & rMatImpl2
= *rInputMat2
.pImpl
;
2925 // Check if we can do fast-path, where we have no replication or mis-matched matrix sizes.
2926 if (rMatImpl1
.maMat
.size() == rMatImpl2
.maMat
.size()
2927 && rMatImpl1
.maMat
.size() == maMat
.size())
2929 MatrixImplType::position_type aOutPos
= maMat
.position(0, 0);
2930 MatrixImplType::const_position_type aPos1
= rMatImpl1
.maMat
.position(0, 0);
2931 MatrixImplType::const_position_type aPos2
= rMatImpl2
.maMat
.position(0, 0);
2932 for (SCSIZE i
= 0; i
< nMaxCol
; i
++)
2934 for (SCSIZE j
= 0; j
< nMaxRow
; j
++)
2936 bool bVal1
= rMatImpl1
.IsValueOrEmpty(aPos1
);
2937 bool bVal2
= rMatImpl2
.IsValueOrEmpty(aPos2
);
2941 double d
= Op(rMatImpl1
.GetDouble(aPos1
), rMatImpl2
.GetDouble(aPos2
));
2942 aOutPos
= maMat
.set(aOutPos
, d
);
2944 else if (((nErr
= rMatImpl1
.GetErrorIfNotString(aPos1
)) != FormulaError::NONE
) ||
2945 ((nErr
= rMatImpl2
.GetErrorIfNotString(aPos2
)) != FormulaError::NONE
))
2947 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nErr
));
2949 else if ((!bVal1
&& rMatImpl1
.IsStringOrEmpty(aPos1
)) ||
2950 (!bVal2
&& rMatImpl2
.IsStringOrEmpty(aPos2
)))
2952 FormulaError nError1
= FormulaError::NONE
;
2953 SvNumFormatType nFmt1
= SvNumFormatType::ALL
;
2954 double fVal1
= (bVal1
? rMatImpl1
.GetDouble(aPos1
) :
2955 pInterpreter
->ConvertStringToValue( rMatImpl1
.GetString(aPos1
).getString(), nError1
, nFmt1
));
2957 FormulaError nError2
= FormulaError::NONE
;
2958 SvNumFormatType nFmt2
= SvNumFormatType::ALL
;
2959 double fVal2
= (bVal2
? rMatImpl2
.GetDouble(aPos2
) :
2960 pInterpreter
->ConvertStringToValue( rMatImpl2
.GetString(aPos2
).getString(), nError2
, nFmt2
));
2962 if (nError1
!= FormulaError::NONE
)
2963 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError1
));
2964 else if (nError2
!= FormulaError::NONE
)
2965 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError2
));
2968 double d
= Op( fVal1
, fVal2
);
2969 aOutPos
= maMat
.set(aOutPos
, d
);
2973 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(FormulaError::NoValue
));
2974 aPos1
= MatrixImplType::next_position(aPos1
);
2975 aPos2
= MatrixImplType::next_position(aPos2
);
2976 aOutPos
= MatrixImplType::next_position(aOutPos
);
2982 // Noting that this block is very hard to optimise to use iterators, because various dodgy
2983 // array function usage relies on the semantics of some of the methods we call here.
2984 // (see unit test testDubiousArrayFormulasFODS).
2985 // These methods are inconsistent in their usage of ValidColRowReplicated() vs. ValidColRowOrReplicated()
2986 // which leads to some very odd results.
2987 MatrixImplType::position_type aOutPos
= maMat
.position(0, 0);
2988 for (SCSIZE i
= 0; i
< nMaxCol
; i
++)
2990 for (SCSIZE j
= 0; j
< nMaxRow
; j
++)
2992 bool bVal1
= rInputMat1
.IsValueOrEmpty(i
,j
);
2993 bool bVal2
= rInputMat2
.IsValueOrEmpty(i
,j
);
2997 double d
= Op(rInputMat1
.GetDouble(i
,j
), rInputMat2
.GetDouble(i
,j
));
2998 aOutPos
= maMat
.set(aOutPos
, d
);
3000 else if (((nErr
= rInputMat1
.GetErrorIfNotString(i
,j
)) != FormulaError::NONE
) ||
3001 ((nErr
= rInputMat2
.GetErrorIfNotString(i
,j
)) != FormulaError::NONE
))
3003 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nErr
));
3005 else if ((!bVal1
&& rInputMat1
.IsStringOrEmpty(i
,j
)) || (!bVal2
&& rInputMat2
.IsStringOrEmpty(i
,j
)))
3007 FormulaError nError1
= FormulaError::NONE
;
3008 SvNumFormatType nFmt1
= SvNumFormatType::ALL
;
3009 double fVal1
= (bVal1
? rInputMat1
.GetDouble(i
,j
) :
3010 pInterpreter
->ConvertStringToValue( rInputMat1
.GetString(i
,j
).getString(), nError1
, nFmt1
));
3012 FormulaError nError2
= FormulaError::NONE
;
3013 SvNumFormatType nFmt2
= SvNumFormatType::ALL
;
3014 double fVal2
= (bVal2
? rInputMat2
.GetDouble(i
,j
) :
3015 pInterpreter
->ConvertStringToValue( rInputMat2
.GetString(i
,j
).getString(), nError2
, nFmt2
));
3017 if (nError1
!= FormulaError::NONE
)
3018 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError1
));
3019 else if (nError2
!= FormulaError::NONE
)
3020 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(nError2
));
3023 double d
= Op( fVal1
, fVal2
);
3024 aOutPos
= maMat
.set(aOutPos
, d
);
3028 aOutPos
= maMat
.set(aOutPos
, CreateDoubleError(FormulaError::NoValue
));
3029 aOutPos
= MatrixImplType::next_position(aOutPos
);
3035 void ScMatrix::IncRef() const
3040 void ScMatrix::DecRef() const
3047 bool ScMatrix::IsSizeAllocatable( SCSIZE nC
, SCSIZE nR
)
3049 SAL_WARN_IF( !nC
, "sc.core", "ScMatrix with 0 columns!");
3050 SAL_WARN_IF( !nR
, "sc.core", "ScMatrix with 0 rows!");
3051 // 0-size matrix is valid, it could be resized later.
3052 if ((nC
&& !nR
) || (!nC
&& nR
))
3054 SAL_WARN( "sc.core", "ScMatrix one-dimensional zero: " << nC
<< " columns * " << nR
<< " rows");
3060 std::call_once(bElementsMaxFetched
,
3063 const char* pEnv
= std::getenv("SC_MAX_MATRIX_ELEMENTS");
3066 // Environment specifies the overall elements pool.
3067 nElementsMax
= std::atoi(pEnv
);
3071 // GetElementsMax() uses an (~arbitrary) elements limit.
3072 // The actual allocation depends on the types of individual matrix
3073 // elements and is averaged for type double.
3074 #if SAL_TYPES_SIZEOFPOINTER < 8
3075 // Assume 1GB memory could be consumed by matrices.
3076 constexpr size_t nMemMax
= 0x40000000;
3078 // Assume 6GB memory could be consumed by matrices.
3079 constexpr size_t nMemMax
= 0x180000000;
3081 nElementsMax
= GetElementsMax( nMemMax
);
3085 if (nC
> (nElementsMax
/ nR
))
3087 SAL_WARN( "sc.core", "ScMatrix overflow: " << nC
<< " columns * " << nR
<< " rows");
3093 ScMatrix::ScMatrix( SCSIZE nC
, SCSIZE nR
) :
3094 nRefCnt(0), mbCloneIfConst(true)
3096 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
3097 pImpl
.reset( new ScMatrixImpl( nC
, nR
));
3099 // Invalid matrix size, allocate 1x1 matrix with error value.
3100 pImpl
.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize
)));
3103 ScMatrix::ScMatrix(SCSIZE nC
, SCSIZE nR
, double fInitVal
) :
3104 nRefCnt(0), mbCloneIfConst(true)
3106 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
3107 pImpl
.reset( new ScMatrixImpl( nC
, nR
, fInitVal
));
3109 // Invalid matrix size, allocate 1x1 matrix with error value.
3110 pImpl
.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize
)));
3113 ScMatrix::ScMatrix( size_t nC
, size_t nR
, const std::vector
<double>& rInitVals
) :
3114 nRefCnt(0), mbCloneIfConst(true)
3116 if (ScMatrix::IsSizeAllocatable( nC
, nR
))
3117 pImpl
.reset( new ScMatrixImpl( nC
, nR
, rInitVals
));
3119 // Invalid matrix size, allocate 1x1 matrix with error value.
3120 pImpl
.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize
)));
3123 ScMatrix::~ScMatrix()
3127 ScMatrix
* ScMatrix::Clone() const
3130 pImpl
->GetDimensions(nC
, nR
);
3131 ScMatrix
* pScMat
= new ScMatrix(nC
, nR
);
3133 pScMat
->SetErrorInterpreter(pImpl
->GetErrorInterpreter()); // TODO: really?
3137 ScMatrix
* ScMatrix::CloneIfConst()
3139 return mbCloneIfConst
? Clone() : this;
3142 void ScMatrix::SetMutable()
3144 mbCloneIfConst
= false;
3147 void ScMatrix::SetImmutable() const
3149 mbCloneIfConst
= true;
3152 void ScMatrix::Resize( SCSIZE nC
, SCSIZE nR
)
3154 pImpl
->Resize(nC
, nR
);
3157 void ScMatrix::Resize(SCSIZE nC
, SCSIZE nR
, double fVal
)
3159 pImpl
->Resize(nC
, nR
, fVal
);
3162 ScMatrix
* ScMatrix::CloneAndExtend(SCSIZE nNewCols
, SCSIZE nNewRows
) const
3164 ScMatrix
* pScMat
= new ScMatrix(nNewCols
, nNewRows
);
3166 pScMat
->SetErrorInterpreter(pImpl
->GetErrorInterpreter());
3170 void ScMatrix::SetErrorInterpreter( ScInterpreter
* p
)
3172 pImpl
->SetErrorInterpreter(p
);
3175 void ScMatrix::GetDimensions( SCSIZE
& rC
, SCSIZE
& rR
) const
3177 pImpl
->GetDimensions(rC
, rR
);
3180 SCSIZE
ScMatrix::GetElementCount() const
3182 return pImpl
->GetElementCount();
3185 bool ScMatrix::ValidColRow( SCSIZE nC
, SCSIZE nR
) const
3187 return pImpl
->ValidColRow(nC
, nR
);
3190 bool ScMatrix::ValidColRowReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
3192 return pImpl
->ValidColRowReplicated(rC
, rR
);
3195 bool ScMatrix::ValidColRowOrReplicated( SCSIZE
& rC
, SCSIZE
& rR
) const
3197 return ValidColRow( rC
, rR
) || ValidColRowReplicated( rC
, rR
);
3200 void ScMatrix::PutDouble(double fVal
, SCSIZE nC
, SCSIZE nR
)
3202 pImpl
->PutDouble(fVal
, nC
, nR
);
3205 void ScMatrix::PutDouble( double fVal
, SCSIZE nIndex
)
3207 pImpl
->PutDouble(fVal
, nIndex
);
3210 void ScMatrix::PutDoubleTrans(double fVal
, SCSIZE nIndex
)
3212 pImpl
->PutDoubleTrans(fVal
, nIndex
);
3215 void ScMatrix::PutDouble(const double* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
3217 pImpl
->PutDouble(pArray
, nLen
, nC
, nR
);
3220 void ScMatrix::PutString(const svl::SharedString
& rStr
, SCSIZE nC
, SCSIZE nR
)
3222 pImpl
->PutString(rStr
, nC
, nR
);
3225 void ScMatrix::PutString(const svl::SharedString
& rStr
, SCSIZE nIndex
)
3227 pImpl
->PutString(rStr
, nIndex
);
3230 void ScMatrix::PutStringTrans(const svl::SharedString
& rStr
, SCSIZE nIndex
)
3232 pImpl
->PutStringTrans(rStr
, nIndex
);
3235 void ScMatrix::PutString(const svl::SharedString
* pArray
, size_t nLen
, SCSIZE nC
, SCSIZE nR
)
3237 pImpl
->PutString(pArray
, nLen
, nC
, nR
);
3240 void ScMatrix::PutEmpty(SCSIZE nC
, SCSIZE nR
)
3242 pImpl
->PutEmpty(nC
, nR
);
3245 void ScMatrix::PutEmptyPath(SCSIZE nC
, SCSIZE nR
)
3247 pImpl
->PutEmptyPath(nC
, nR
);
3250 void ScMatrix::PutError( FormulaError nErrorCode
, SCSIZE nC
, SCSIZE nR
)
3252 pImpl
->PutError(nErrorCode
, nC
, nR
);
3255 void ScMatrix::PutBoolean(bool bVal
, SCSIZE nC
, SCSIZE nR
)
3257 pImpl
->PutBoolean(bVal
, nC
, nR
);
3260 FormulaError
ScMatrix::GetError( SCSIZE nC
, SCSIZE nR
) const
3262 return pImpl
->GetError(nC
, nR
);
3265 double ScMatrix::GetDouble(SCSIZE nC
, SCSIZE nR
) const
3267 return pImpl
->GetDouble(nC
, nR
);
3270 double ScMatrix::GetDouble( SCSIZE nIndex
) const
3272 return pImpl
->GetDouble(nIndex
);
3275 double ScMatrix::GetDoubleWithStringConversion(SCSIZE nC
, SCSIZE nR
) const
3277 return pImpl
->GetDoubleWithStringConversion(nC
, nR
);
3280 svl::SharedString
ScMatrix::GetString(SCSIZE nC
, SCSIZE nR
) const
3282 return pImpl
->GetString(nC
, nR
);
3285 svl::SharedString
ScMatrix::GetString( SCSIZE nIndex
) const
3287 return pImpl
->GetString(nIndex
);
3290 svl::SharedString
ScMatrix::GetString( SvNumberFormatter
& rFormatter
, SCSIZE nC
, SCSIZE nR
) const
3292 return pImpl
->GetString(rFormatter
, nC
, nR
);
3295 ScMatrixValue
ScMatrix::Get(SCSIZE nC
, SCSIZE nR
) const
3297 return pImpl
->Get(nC
, nR
);
3300 bool ScMatrix::IsStringOrEmpty( SCSIZE nIndex
) const
3302 return pImpl
->IsStringOrEmpty(nIndex
);
3305 bool ScMatrix::IsStringOrEmpty( SCSIZE nC
, SCSIZE nR
) const
3307 return pImpl
->IsStringOrEmpty(nC
, nR
);
3310 bool ScMatrix::IsEmpty( SCSIZE nC
, SCSIZE nR
) const
3312 return pImpl
->IsEmpty(nC
, nR
);
3315 bool ScMatrix::IsEmptyCell( SCSIZE nC
, SCSIZE nR
) const
3317 return pImpl
->IsEmptyCell(nC
, nR
);
3320 bool ScMatrix::IsEmptyResult( SCSIZE nC
, SCSIZE nR
) const
3322 return pImpl
->IsEmptyResult(nC
, nR
);
3325 bool ScMatrix::IsEmptyPath( SCSIZE nC
, SCSIZE nR
) const
3327 return pImpl
->IsEmptyPath(nC
, nR
);
3330 bool ScMatrix::IsValue( SCSIZE nIndex
) const
3332 return pImpl
->IsValue(nIndex
);
3335 bool ScMatrix::IsValue( SCSIZE nC
, SCSIZE nR
) const
3337 return pImpl
->IsValue(nC
, nR
);
3340 bool ScMatrix::IsValueOrEmpty( SCSIZE nC
, SCSIZE nR
) const
3342 return pImpl
->IsValueOrEmpty(nC
, nR
);
3345 bool ScMatrix::IsBoolean( SCSIZE nC
, SCSIZE nR
) const
3347 return pImpl
->IsBoolean(nC
, nR
);
3350 bool ScMatrix::IsNumeric() const
3352 return pImpl
->IsNumeric();
3355 void ScMatrix::MatCopy(const ScMatrix
& mRes
) const
3357 pImpl
->MatCopy(*mRes
.pImpl
);
3360 void ScMatrix::MatTrans(const ScMatrix
& mRes
) const
3362 pImpl
->MatTrans(*mRes
.pImpl
);
3365 void ScMatrix::FillDouble( double fVal
, SCSIZE nC1
, SCSIZE nR1
, SCSIZE nC2
, SCSIZE nR2
)
3367 pImpl
->FillDouble(fVal
, nC1
, nR1
, nC2
, nR2
);
3370 void ScMatrix::PutDoubleVector( const ::std::vector
< double > & rVec
, SCSIZE nC
, SCSIZE nR
)
3372 pImpl
->PutDoubleVector(rVec
, nC
, nR
);
3375 void ScMatrix::PutStringVector( const ::std::vector
< svl::SharedString
> & rVec
, SCSIZE nC
, SCSIZE nR
)
3377 pImpl
->PutStringVector(rVec
, nC
, nR
);
3380 void ScMatrix::PutEmptyVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
3382 pImpl
->PutEmptyVector(nCount
, nC
, nR
);
3385 void ScMatrix::PutEmptyResultVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
3387 pImpl
->PutEmptyResultVector(nCount
, nC
, nR
);
3390 void ScMatrix::PutEmptyPathVector( SCSIZE nCount
, SCSIZE nC
, SCSIZE nR
)
3392 pImpl
->PutEmptyPathVector(nCount
, nC
, nR
);
3395 void ScMatrix::CompareEqual()
3397 pImpl
->CompareEqual();
3400 void ScMatrix::CompareNotEqual()
3402 pImpl
->CompareNotEqual();
3405 void ScMatrix::CompareLess()
3407 pImpl
->CompareLess();
3410 void ScMatrix::CompareGreater()
3412 pImpl
->CompareGreater();
3415 void ScMatrix::CompareLessEqual()
3417 pImpl
->CompareLessEqual();
3420 void ScMatrix::CompareGreaterEqual()
3422 pImpl
->CompareGreaterEqual();
3425 double ScMatrix::And() const
3427 return pImpl
->And();
3430 double ScMatrix::Or() const
3435 double ScMatrix::Xor() const
3437 return pImpl
->Xor();
3440 ScMatrix::KahanIterateResult
ScMatrix::Sum(bool bTextAsZero
, bool bIgnoreErrorValues
) const
3442 return pImpl
->Sum(bTextAsZero
, bIgnoreErrorValues
);
3445 ScMatrix::KahanIterateResult
ScMatrix::SumSquare(bool bTextAsZero
, bool bIgnoreErrorValues
) const
3447 return pImpl
->SumSquare(bTextAsZero
, bIgnoreErrorValues
);
3450 ScMatrix::DoubleIterateResult
ScMatrix::Product(bool bTextAsZero
, bool bIgnoreErrorValues
) const
3452 return pImpl
->Product(bTextAsZero
, bIgnoreErrorValues
);
3455 size_t ScMatrix::Count(bool bCountStrings
, bool bCountErrors
, bool bIgnoreEmptyStrings
) const
3457 return pImpl
->Count(bCountStrings
, bCountErrors
, bIgnoreEmptyStrings
);
3460 size_t ScMatrix::MatchDoubleInColumns(double fValue
, size_t nCol1
, size_t nCol2
) const
3462 return pImpl
->MatchDoubleInColumns(fValue
, nCol1
, nCol2
);
3465 size_t ScMatrix::MatchStringInColumns(const svl::SharedString
& rStr
, size_t nCol1
, size_t nCol2
) const
3467 return pImpl
->MatchStringInColumns(rStr
, nCol1
, nCol2
);
3470 double ScMatrix::GetMaxValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
3472 return pImpl
->GetMaxValue(bTextAsZero
, bIgnoreErrorValues
);
3475 double ScMatrix::GetMinValue( bool bTextAsZero
, bool bIgnoreErrorValues
) const
3477 return pImpl
->GetMinValue(bTextAsZero
, bIgnoreErrorValues
);
3480 double ScMatrix::GetGcd() const
3482 return pImpl
->GetGcd();
3485 double ScMatrix::GetLcm() const
3487 return pImpl
->GetLcm();
3491 ScMatrixRef
ScMatrix::CompareMatrix(
3492 sc::Compare
& rComp
, size_t nMatPos
, sc::CompareOptions
* pOptions
) const
3494 return pImpl
->CompareMatrix(rComp
, nMatPos
, pOptions
);
3497 void ScMatrix::GetDoubleArray( std::vector
<double>& rArray
, bool bEmptyAsZero
) const
3499 pImpl
->GetDoubleArray(rArray
, bEmptyAsZero
);
3502 void ScMatrix::MergeDoubleArrayMultiply( std::vector
<double>& rArray
) const
3504 pImpl
->MergeDoubleArrayMultiply(rArray
);
3511 /** A template for operations where operands are supposed to be numeric.
3512 A non-numeric (string) operand leads to the configured conversion to number
3513 method being called if in interpreter context and a FormulaError::NoValue DoubleError
3514 if conversion was not possible, else to an unconditional FormulaError::NoValue
3516 An empty operand evaluates to 0.
3518 template<typename TOp
>
3523 ScInterpreter
* mpErrorInterpreter
;
3527 typedef double number_value_type
;
3529 MatOp( TOp aOp
, ScInterpreter
* pErrorInterpreter
,
3530 double fVal
= 0.0 ):
3532 mpErrorInterpreter(pErrorInterpreter
),
3535 if (mpErrorInterpreter
)
3537 FormulaError nErr
= mpErrorInterpreter
->GetError();
3538 if (nErr
!= FormulaError::NONE
)
3539 mfVal
= CreateDoubleError( nErr
);
3543 double operator()(double fVal
) const
3545 return maOp(fVal
, mfVal
);
3548 double operator()(bool bVal
) const
3550 return maOp(static_cast<double>(bVal
), mfVal
);
3553 double operator()(const svl::SharedString
& rStr
) const
3555 return maOp( convertStringToValue( mpErrorInterpreter
, rStr
.getString()), mfVal
);
3558 /// the action for empty entries in a matrix
3559 double operator()(char) const
3561 return maOp(0, mfVal
);
3564 static bool useFunctionForEmpty()
3574 void ScMatrix::NotOp( const ScMatrix
& rMat
)
3576 auto not_
= [](double a
, double){return double(a
== 0.0);};
3577 matop::MatOp
<decltype(not_
)> aOp(not_
, pImpl
->GetErrorInterpreter());
3578 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3581 void ScMatrix::NegOp( const ScMatrix
& rMat
)
3583 auto neg_
= [](double a
, double){return -a
;};
3584 matop::MatOp
<decltype(neg_
)> aOp(neg_
, pImpl
->GetErrorInterpreter());
3585 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3588 void ScMatrix::AddOp( double fVal
, const ScMatrix
& rMat
)
3590 auto add_
= [](double a
, double b
){return a
+ b
;};
3591 matop::MatOp
<decltype(add_
)> aOp(add_
, pImpl
->GetErrorInterpreter(), fVal
);
3592 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3595 void ScMatrix::SubOp( bool bFlag
, double fVal
, const ScMatrix
& rMat
)
3599 auto sub_
= [](double a
, double b
){return b
- a
;};
3600 matop::MatOp
<decltype(sub_
)> aOp(sub_
, pImpl
->GetErrorInterpreter(), fVal
);
3601 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3605 auto sub_
= [](double a
, double b
){return a
- b
;};
3606 matop::MatOp
<decltype(sub_
)> aOp(sub_
, pImpl
->GetErrorInterpreter(), fVal
);
3607 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3611 void ScMatrix::MulOp( double fVal
, const ScMatrix
& rMat
)
3613 auto mul_
= [](double a
, double b
){return a
* b
;};
3614 matop::MatOp
<decltype(mul_
)> aOp(mul_
, pImpl
->GetErrorInterpreter(), fVal
);
3615 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3618 void ScMatrix::DivOp( bool bFlag
, double fVal
, const ScMatrix
& rMat
)
3622 auto div_
= [](double a
, double b
){return sc::div(b
, a
);};
3623 matop::MatOp
<decltype(div_
)> aOp(div_
, pImpl
->GetErrorInterpreter(), fVal
);
3624 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3628 auto div_
= [](double a
, double b
){return sc::div(a
, b
);};
3629 matop::MatOp
<decltype(div_
)> aOp(div_
, pImpl
->GetErrorInterpreter(), fVal
);
3630 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3634 void ScMatrix::PowOp( bool bFlag
, double fVal
, const ScMatrix
& rMat
)
3638 auto pow_
= [](double a
, double b
){return sc::power(b
, a
);};
3639 matop::MatOp
<decltype(pow_
)> aOp(pow_
, pImpl
->GetErrorInterpreter(), fVal
);
3640 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3644 auto pow_
= [](double a
, double b
){return sc::power(a
, b
);};
3645 matop::MatOp
<decltype(pow_
)> aOp(pow_
, pImpl
->GetErrorInterpreter(), fVal
);
3646 pImpl
->ApplyOperation(aOp
, *rMat
.pImpl
);
3650 void ScMatrix::ExecuteOperation(const std::pair
<size_t, size_t>& rStartPos
,
3651 const std::pair
<size_t, size_t>& rEndPos
, DoubleOpFunction aDoubleFunc
,
3652 BoolOpFunction aBoolFunc
, StringOpFunction aStringFunc
, EmptyOpFunction aEmptyFunc
) const
3654 pImpl
->ExecuteOperation(rStartPos
, rEndPos
, aDoubleFunc
, aBoolFunc
, aStringFunc
, aEmptyFunc
);
3657 ScMatrix::KahanIterateResultMultiple
ScMatrix::CollectKahan(const std::vector
<sc::op::kOp
>& aOp
)
3659 return pImpl
->ApplyCollectOperation
<sc::op::kOp
, KahanSum
>(aOp
);
3663 void ScMatrix::Dump() const
3669 void ScMatrix::MatConcat(SCSIZE nMaxCol
, SCSIZE nMaxRow
,
3670 const ScMatrixRef
& xMat1
, const ScMatrixRef
& xMat2
, SvNumberFormatter
& rFormatter
, svl::SharedStringPool
& rPool
)
3672 pImpl
->MatConcat(nMaxCol
, nMaxRow
, xMat1
, xMat2
, rFormatter
, rPool
);
3675 void ScMatrix::ExecuteBinaryOp(SCSIZE nMaxCol
, SCSIZE nMaxRow
, const ScMatrix
& rInputMat1
, const ScMatrix
& rInputMat2
,
3676 ScInterpreter
* pInterpreter
, CalculateOpFunction op
)
3678 pImpl
->ExecuteBinaryOp(nMaxCol
, nMaxRow
, rInputMat1
, rInputMat2
, pInterpreter
, op
);
3680 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */