Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / source / core / tool / scmatrix.cxx
blob9041e0fe1d3463678edf30ef4c7e240866288438
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
21 #include <global.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>
28 #include <math.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>
37 #include <memory>
38 #include <mutex>
39 #include <utility>
40 #include <vector>
41 #include <limits>
43 #include <mdds/multi_type_matrix.hpp>
44 #include <mdds/multi_type_vector/types.hpp>
46 #if DEBUG_MATRIX
47 #include <iostream>
48 using std::cout;
49 using std::endl;
50 #endif
52 using ::std::pair;
53 using ::std::advance;
55 namespace {
57 /**
58 * Custom string trait struct to tell mdds::multi_type_matrix about the
59 * custom string type and how to handle blocks storing them.
61 struct matrix_traits
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;
78 namespace {
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);
92 return fValue;
94 return CreateDoubleError( FormulaError::NoValue);
97 struct ElemEqualZero
99 double operator() (double val) const
101 if (!std::isfinite(val))
102 return val;
103 return val == 0.0 ? 1.0 : 0.0;
107 struct ElemNotEqualZero
109 double operator() (double val) const
111 if (!std::isfinite(val))
112 return val;
113 return val != 0.0 ? 1.0 : 0.0;
117 struct ElemGreaterZero
119 double operator() (double val) const
121 if (!std::isfinite(val))
122 return val;
123 return val > 0.0 ? 1.0 : 0.0;
127 struct ElemLessZero
129 double operator() (double val) const
131 if (!std::isfinite(val))
132 return val;
133 return val < 0.0 ? 1.0 : 0.0;
137 struct ElemGreaterEqualZero
139 double operator() (double val) const
141 if (!std::isfinite(val))
142 return val;
143 return val >= 0.0 ? 1.0 : 0.0;
147 struct ElemLessEqualZero
149 double operator() (double val) const
151 if (!std::isfinite(val))
152 return val;
153 return val <= 0.0 ? 1.0 : 0.0;
157 template<typename Comp>
158 class CompareMatrixElemFunc
160 static Comp maComp;
162 std::vector<double> maNewMatValues; // double instead of bool to transport error values
163 size_t mnRow;
164 size_t mnCol;
165 public:
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)
179 switch (node.type)
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)
189 double fVal = *it;
190 maNewMatValues.push_back(maComp(fVal));
193 break;
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));
206 break;
207 case mdds::mtm::element_string:
208 case mdds::mtm::element_empty:
209 default:
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());
218 rMat.swap(aNewMat);
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;
231 class ScMatrixImpl
233 MatrixImplType maMat;
234 MatrixFlagImplType maMatFlag;
235 ScInterpreter* pErrorInterpreter;
237 public:
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 );
246 ~ScMatrixImpl();
248 void Clear();
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 );
303 void CompareEqual();
304 void CompareNotEqual();
305 void CompareLess();
306 void CompareGreater();
307 void CompareLessEqual();
308 void CompareGreaterEqual();
309 double And() const;
310 double Or() const;
311 double Xor() const;
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;
330 template<typename T>
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;
354 #if DEBUG_MATRIX
355 void Dump() const;
356 #endif
358 private:
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.
368 @param nMemory
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
372 nElementsMax.
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;
380 if (nMemory)
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());
420 maMatFlag.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);
431 else
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);
448 else
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();
465 rR = aSize.row;
466 rC = aSize.column;
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)
486 rC = 0;
487 rR = 0;
488 return true;
490 else if (aSize.column == 1 && rR < aSize.row)
492 // single column matrix.
493 rC = 0;
494 return true;
496 else if (aSize.row == 1 && rC < aSize.column)
498 // single row matrix.
499 rR = 0;
500 return true;
502 return false;
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);
520 else
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);
530 else
532 OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
536 void ScMatrixImpl::PutDouble( double fVal, SCSIZE nIndex)
538 SCSIZE nC, nR;
539 CalcPosition(nIndex, nC, nR);
540 PutDouble(fVal, nC, nR);
543 void ScMatrixImpl::PutDoubleTrans(double fVal, SCSIZE nIndex)
545 SCSIZE nC, nR;
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);
554 else
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);
564 else
566 OSL_FAIL("ScMatrixImpl::PutString: dimension error");
570 void ScMatrixImpl::PutString(const svl::SharedString& rStr, SCSIZE nIndex)
572 SCSIZE nC, nR;
573 CalcPosition(nIndex, nC, nR);
574 PutString(rStr, nC, nR);
577 void ScMatrixImpl::PutStringTrans(const svl::SharedString& rStr, SCSIZE nIndex)
579 SCSIZE nC, nR;
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);
591 else
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"
605 #endif
606 maMatFlag.set(nR, nC, SC_MATFLAG_EMPTYPATH);
607 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 && __cplusplus == 202002L
608 #pragma GCC diagnostic pop
609 #endif
611 else
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);
626 else
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);
639 else
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);
657 return fVal;
659 else
661 OSL_FAIL("ScMatrixImpl::GetDouble: dimension error");
662 return CreateDoubleError( FormulaError::NoValue);
666 double ScMatrixImpl::GetDouble( SCSIZE nIndex) const
668 SCSIZE nC, nR;
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());
678 return aMatVal.fVal;
681 svl::SharedString ScMatrixImpl::GetString(SCSIZE nC, SCSIZE nR) const
683 if (ValidColRowOrReplicated( nC, nR ))
685 return GetString(maMat.position(nR, nC));
687 else
689 OSL_FAIL("ScMatrixImpl::GetString: dimension error");
691 return svl::SharedString::getEmptyString();
694 svl::SharedString ScMatrixImpl::GetString(const MatrixImplType::const_position_type& rPos) const
696 double fErr = 0.0;
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);
706 [[fallthrough]];
707 default:
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
716 SCSIZE nC, nR;
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();
729 double fVal = 0.0;
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,
743 ScGlobal::eLnge);
744 OUString aStr;
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);
752 break;
753 default:
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,
765 ScGlobal::eLnge);
766 OUString aStr;
767 rFormatter.GetInputLineString( fVal, nKey, aStr);
768 return svl::SharedString( aStr); // string not interned
771 ScMatrixValue ScMatrixImpl::Get(SCSIZE nC, SCSIZE nR) const
773 ScMatrixValue aVal;
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);
778 switch (eType)
780 case mdds::mtm::element_boolean:
781 aVal.nType = ScMatValType::Boolean;
782 aVal.fVal = double(maMat.get_boolean(aPos));
783 break;
784 case mdds::mtm::element_numeric:
785 aVal.nType = ScMatValType::Value;
786 aVal.fVal = maMat.get_numeric(aPos);
787 break;
788 case mdds::mtm::element_string:
789 aVal.nType = ScMatValType::String;
790 aVal.aStr = maMat.get_string(aPos);
791 break;
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;
799 break;
800 case mdds::mtm::element_integer:
801 aVal.nType = maMatFlag.get<uint8_t>(nR, nC)
802 == SC_MATFLAG_EMPTYPATH ? ScMatValType::EmptyPath : ScMatValType::Empty;
803 break;
804 default:
805 assert(false);
807 aVal.fVal = 0.0;
808 break;
809 default:
813 else
815 OSL_FAIL("ScMatrixImpl::Get: dimension error");
817 return aVal;
820 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nIndex ) const
822 SCSIZE nC, nR;
823 CalcPosition(nIndex, nC, nR);
824 return IsStringOrEmpty(nC, nR);
827 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const
829 if (!ValidColRowOrReplicated( nC, nR ))
830 return false;
832 switch (maMat.get_type(nR, nC))
834 case mdds::mtm::element_empty:
835 case mdds::mtm::element_string:
836 return true;
837 default:
840 return false;
843 bool ScMatrixImpl::IsEmpty( SCSIZE nC, SCSIZE nR ) const
845 if (!ValidColRowOrReplicated( nC, nR ))
846 return false;
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 ))
857 return false;
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 ))
868 return false;
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;
882 else
883 return true;
886 bool ScMatrixImpl::IsValue( SCSIZE nIndex ) const
888 SCSIZE nC, nR;
889 CalcPosition(nIndex, nC, nR);
890 return IsValue(nC, nR);
893 bool ScMatrixImpl::IsValue( SCSIZE nC, SCSIZE nR ) const
895 if (!ValidColRowOrReplicated( nC, nR ))
896 return false;
898 switch (maMat.get_type(nR, nC))
900 case mdds::mtm::element_boolean:
901 case mdds::mtm::element_numeric:
902 return true;
903 default:
906 return false;
909 bool ScMatrixImpl::IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const
911 if (!ValidColRowOrReplicated( nC, nR ))
912 return false;
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:
919 return true;
920 default:
923 return false;
926 bool ScMatrixImpl::IsBoolean( SCSIZE nC, SCSIZE nR ) const
928 if (!ValidColRowOrReplicated( nC, nR ))
929 return false;
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");
945 return;
948 mRes.maMat.copy(maMat);
951 void ScMatrixImpl::MatTrans(ScMatrixImpl& mRes) const
953 mRes.maMat = maMat;
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());
968 else
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());
980 else
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());
992 else
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);
1006 else
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());
1021 else
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());
1036 else
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));
1047 aFunc.swap(maMat);
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));
1055 aFunc.swap(maMat);
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));
1063 aFunc.swap(maMat);
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));
1071 aFunc.swap(maMat);
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));
1079 aFunc.swap(maMat);
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));
1087 aFunc.swap(maMat);
1090 namespace {
1092 struct AndEvaluator
1094 bool mbResult;
1095 void operate(double fVal) { mbResult &= (fVal != 0.0); }
1096 bool result() const { return mbResult; }
1097 AndEvaluator() : mbResult(true) {}
1100 struct OrEvaluator
1102 bool mbResult;
1103 void operate(double fVal) { mbResult |= (fVal != 0.0); }
1104 bool result() const { return mbResult; }
1105 OrEvaluator() : mbResult(false) {}
1108 struct XorEvaluator
1110 bool mbResult;
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)
1121 Evaluator aEval;
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))
1135 // DoubleError
1136 return 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);
1167 namespace {
1169 template<typename Op, typename tRes>
1170 class WalkElementBlocks
1172 Op maOp;
1173 ScMatrix::IterateResult<tRes> maRes;
1174 bool mbTextAsZero:1;
1175 bool mbIgnoreErrorValues:1;
1176 public:
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)
1186 switch (node.type)
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))
1199 ++nIgnored;
1200 continue;
1202 maOp(maRes.maAccumulator, *it);
1204 maRes.mnCount += node.size - nIgnored;
1206 break;
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;
1219 break;
1220 case mdds::mtm::element_string:
1221 if (mbTextAsZero)
1222 maRes.mnCount += node.size;
1223 break;
1224 case mdds::mtm::element_empty:
1225 default:
1231 template<typename Op, typename tRes>
1232 class WalkElementBlocksMultipleValues
1234 const std::vector<Op>* mpOp;
1235 ScMatrix::IterateResultMultiple<tRes> maRes;
1236 public:
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
1255 mpOp = r.mpOp;
1256 maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1257 maRes.mnCount = r.maRes.mnCount;
1258 return *this;
1261 const ScMatrix::IterateResultMultiple<tRes>& getResult() const { return maRes; }
1263 void operator() (const MatrixImplType::element_block_node_type& node)
1265 switch (node.type)
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;
1280 break;
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;
1294 break;
1295 case mdds::mtm::element_string:
1296 case mdds::mtm::element_empty:
1297 default:
1303 class CountElements
1305 size_t mnCount;
1306 bool mbCountString;
1307 bool mbCountErrors;
1308 bool mbIgnoreEmptyStrings;
1309 public:
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)
1318 switch (node.type)
1320 case mdds::mtm::element_numeric:
1321 mnCount += node.size;
1322 if (!mbCountErrors)
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))
1331 --mnCount;
1334 break;
1335 case mdds::mtm::element_boolean:
1336 mnCount += node.size;
1337 break;
1338 case mdds::mtm::element_string:
1339 if (mbCountString)
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)
1350 if (it->isEmpty())
1351 --mnCount;
1355 break;
1356 case mdds::mtm::element_empty:
1357 default:
1363 const size_t ResultNotSet = std::numeric_limits<size_t>::max();
1365 template<typename Type>
1366 class WalkAndMatchElements
1368 Type maMatchValue;
1369 size_t mnStartIndex;
1370 size_t mnStopIndex;
1371 size_t mnResult;
1372 size_t mnIndex;
1374 public:
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),
1380 mnIndex(0)
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)
1398 return;
1400 // limit lookup to the requested columns
1401 if (mnStartIndex <= mnIndex && getRemainingCount() > 0)
1403 mnResult = compare(node);
1406 mnIndex += node.size;
1410 template<>
1411 size_t WalkAndMatchElements<double>::compare(const MatrixImplType::element_block_node_type& node) const
1413 size_t nCount = 0;
1414 switch (node.type)
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;
1430 break;
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;
1446 break;
1448 break;
1449 case mdds::mtm::element_string:
1450 case mdds::mtm::element_empty:
1451 default:
1454 return ResultNotSet;
1457 template<>
1458 size_t WalkAndMatchElements<svl::SharedString>::compare(const MatrixImplType::element_block_node_type& node) const
1460 switch (node.type)
1462 case mdds::mtm::element_string:
1464 size_t nCount = 0;
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;
1477 break;
1479 case mdds::mtm::element_boolean:
1480 case mdds::mtm::element_numeric:
1481 case mdds::mtm::element_empty:
1482 default:
1485 return ResultNotSet;
1488 struct MaxOp
1490 static double init() { return -std::numeric_limits<double>::max(); }
1491 static double compare(double left, double right)
1493 if (!std::isfinite(left))
1494 return left;
1495 if (!std::isfinite(right))
1496 return 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;
1510 struct MinOp
1512 static double init() { return std::numeric_limits<double>::max(); }
1513 static double compare(double left, double right)
1515 if (!std::isfinite(left))
1516 return left;
1517 if (!std::isfinite(right))
1518 return 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;
1532 struct Lcm
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;
1550 struct Gcd
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
1571 double mfVal;
1572 bool mbTextAsZero;
1573 bool mbIgnoreErrorValues;
1574 bool mbHasValue;
1575 public:
1576 CalcMaxMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) :
1577 mfVal(Op::init()),
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)
1587 switch (node.type)
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);
1603 else
1605 for (; it != itEnd; ++it)
1606 mfVal = Op::compare(mfVal, *it);
1609 mbHasValue = true;
1611 break;
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);
1620 mbHasValue = true;
1622 break;
1623 case mdds::mtm::element_string:
1624 case mdds::mtm::element_empty:
1626 // empty elements are treated as empty strings.
1627 if (mbTextAsZero)
1629 mfVal = Op::compare(mfVal, 0.0);
1630 mbHasValue = true;
1633 break;
1634 default:
1640 template<typename Op>
1641 class CalcGcdLcm
1643 double mfval;
1645 public:
1646 CalcGcdLcm() : mfval(Op::init()) {}
1648 double getResult() const { return mfval; }
1650 void operator() ( const MatrixImplType::element_block_node_type& node )
1652 switch (node.type)
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)
1662 if (*it < 0.0)
1663 mfval = CreateDoubleError(FormulaError::IllegalArgument);
1664 else
1665 mfval = ::rtl::math::approxFloor( Op::calculate(*it,mfval));
1668 break;
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);
1677 break;
1678 case mdds::mtm::element_empty:
1679 case mdds::mtm::element_string:
1681 mfval = CreateDoubleError(FormulaError::IllegalArgument);
1683 break;
1684 default:
1690 double evaluate( double fVal, ScQueryOp eOp )
1692 if (!std::isfinite(fVal))
1693 return fVal;
1695 switch (eOp)
1697 case SC_EQUAL:
1698 return fVal == 0.0 ? 1.0 : 0.0;
1699 case SC_LESS:
1700 return fVal < 0.0 ? 1.0 : 0.0;
1701 case SC_GREATER:
1702 return fVal > 0.0 ? 1.0 : 0.0;
1703 case SC_LESS_EQUAL:
1704 return fVal <= 0.0 ? 1.0 : 0.0;
1705 case SC_GREATER_EQUAL:
1706 return fVal >= 0.0 ? 1.0 : 0.0;
1707 case SC_NOT_EQUAL:
1708 return fVal != 0.0 ? 1.0 : 0.0;
1709 default:
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;
1720 size_t mnMatPos;
1721 sc::CompareOptions* mpOptions;
1722 std::vector<double> maResValues; // double instead of bool to transport error values
1724 void compare()
1726 double fVal = sc::CompareFunc( mrComp, mpOptions);
1727 maResValues.push_back(evaluate(fVal, mrComp.meOp));
1730 public:
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 :
1741 mrComp(r.mrComp),
1742 mnMatPos(r.mnMatPos),
1743 mpOptions(r.mpOptions),
1744 maResValues(std::move(r.maResValues)) {}
1746 CompareMatrixFunc& operator=(CompareMatrixFunc&& r) noexcept
1748 mrComp = r.mrComp;
1749 mnMatPos = r.mnMatPos;
1750 mpOptions = r.mpOptions;
1751 maResValues = std::move(r.maResValues);
1752 return *this;
1755 void operator() (const MatrixImplType::element_block_node_type& node)
1757 sc::Compare::Cell& rCell = mrComp.maCells[mnMatPos];
1759 switch (node.type)
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;
1772 compare();
1775 break;
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);
1787 compare();
1790 break;
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;
1802 rCell.maStr = rStr;
1803 compare();
1806 break;
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)
1813 compare();
1815 break;
1816 default:
1821 const std::vector<double>& getValues() const
1823 return maResValues;
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
1837 void compare()
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);
1856 public:
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 :
1867 mrComp(r.mrComp),
1868 mfRightValue(r.mfRightValue),
1869 mpOptions(r.mpOptions),
1870 maResValues(std::move(r.maResValues)) {}
1872 CompareMatrixToNumericFunc& operator=(CompareMatrixToNumericFunc&& r) noexcept
1874 mrComp = r.mrComp;
1875 mfRightValue = r.mfRightValue;
1876 mpOptions = r.mpOptions;
1877 maResValues = std::move(r.maResValues);
1878 return *this;
1881 void operator() (const MatrixImplType::element_block_node_type& node)
1883 switch (node.type)
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);
1894 break;
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));
1904 break;
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;
1917 rCell.maStr = rStr;
1918 compare();
1921 break;
1922 case mdds::mtm::element_empty:
1923 compareLeftEmpty(node.size);
1924 break;
1925 default:
1930 const std::vector<double>& getValues() const
1932 return maResValues;
1936 class ToDoubleArray
1938 std::vector<double> maArray;
1939 std::vector<double>::iterator miPos;
1940 double mfNaN;
1941 bool mbEmptyAsZero;
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
1947 // position.
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);
1954 public:
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)
1967 moveArray(r);
1970 ToDoubleArray& operator=(ToDoubleArray&& r) noexcept
1972 mfNaN = r.mfNaN;
1973 mbEmptyAsZero = r.mbEmptyAsZero;
1974 moveArray(r);
1975 return *this;
1978 void operator() (const MatrixImplType::element_block_node_type& node)
1980 using namespace mdds::mtv;
1982 switch (node.type)
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)
1989 *miPos = *it;
1991 break;
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;
1999 break;
2000 case mdds::mtm::element_string:
2002 for (size_t i = 0; i < node.size; ++i, ++miPos)
2003 *miPos = mfNaN;
2005 break;
2006 case mdds::mtm::element_empty:
2008 if (mbEmptyAsZero)
2010 std::advance(miPos, node.size);
2011 return;
2014 for (size_t i = 0; i < node.size; ++i, ++miPos)
2015 *miPos = mfNaN;
2017 break;
2018 default:
2023 void swap(std::vector<double>& rOther)
2025 maArray.swap(rOther);
2029 struct ArrayMul
2031 double operator() (const double& lhs, const double& rhs) const
2033 return lhs * rhs;
2037 template<typename Op>
2038 class MergeDoubleArrayFunc
2040 std::vector<double>::iterator miPos;
2041 double mfNaN;
2042 public:
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;
2057 static const Op op;
2059 switch (node.type)
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)
2068 continue;
2070 *miPos = op(*miPos, *it);
2073 break;
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)
2081 continue;
2083 *miPos = op(*miPos, *it ? 1.0 : 0.0);
2086 break;
2087 case mdds::mtm::element_string:
2089 for (size_t i = 0; i < node.size; ++i, ++miPos)
2090 *miPos = mfNaN;
2092 break;
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)
2099 continue;
2101 *miPos = op(*miPos, 0.0);
2104 break;
2105 default:
2113 namespace {
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;
2194 if (nMatPos == 0)
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
2200 // performance.
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));
2231 aFunc.swap(rArray);
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())
2239 return;
2241 MergeDoubleArrayFunc<ArrayMul> aFunc(rArray);
2242 maMat.walk(std::move(aFunc));
2245 namespace {
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;
2259 U maOp;
2261 private:
2263 value_type calcVal() const
2265 return maOp(*it);
2268 public:
2270 wrapped_iterator(typename T::const_iterator it_, U const & aOp):
2271 it(std::move(it_)),
2272 val(value_type()),
2273 maOp(aOp)
2277 wrapped_iterator(const wrapped_iterator& r):
2278 it(r.it),
2279 val(r.val),
2280 maOp(r.maOp)
2284 wrapped_iterator& operator=(const wrapped_iterator& r)
2286 it = r.it;
2287 return *this;
2290 bool operator==(const wrapped_iterator& r) const
2292 return it == r.it;
2295 bool operator!=(const wrapped_iterator& r) const
2297 return !operator==(r);
2300 wrapped_iterator& operator++()
2302 ++it;
2304 return *this;
2307 wrapped_iterator& operator--()
2309 --it;
2311 return *this;
2314 value_type& operator*() const
2316 val = calcVal();
2317 return val;
2320 pointer operator->() const
2322 val = calcVal();
2323 return &val;
2327 template<typename T, typename U, typename return_type>
2328 struct MatrixIteratorWrapper
2330 private:
2331 typename T::const_iterator m_itBegin;
2332 typename T::const_iterator m_itEnd;
2333 U maOp;
2334 public:
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)),
2338 maOp(aOp)
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)
2360 ret.second += n;
2361 break;
2363 else
2365 n -= (ret.first->size - ret.second);
2366 ++ret.first;
2367 ret.second = 0;
2370 while (n > 0);
2371 return ret;
2374 template<typename T>
2375 struct MatrixOpWrapper
2377 private:
2378 MatrixImplType& mrMat;
2379 MatrixImplType::position_type pos;
2380 const T* mpOp;
2382 public:
2383 MatrixOpWrapper(MatrixImplType& rMat, const T& aOp):
2384 mrMat(rMat),
2385 pos(rMat.position(0,0)),
2386 mpOp(&aOp)
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)
2396 switch (node.type)
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());
2407 break;
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());
2418 break;
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());
2429 break;
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());
2440 break;
2441 default:
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);
2454 maMat.walk(aFunc);
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();
2465 namespace {
2467 struct ElementBlock
2469 ElementBlock(size_t nRowSize,
2470 ScMatrix::DoubleOpFunction aDoubleFunc,
2471 ScMatrix::BoolOpFunction aBoolFunc,
2472 ScMatrix::StringOpFunction aStringFunc,
2473 ScMatrix::EmptyOpFunction aEmptyFunc):
2474 mnRowSize(nRowSize),
2475 mnRowPos(0),
2476 mnColPos(0),
2477 maDoubleFunc(std::move(aDoubleFunc)),
2478 maBoolFunc(std::move(aBoolFunc)),
2479 maStringFunc(std::move(aStringFunc)),
2480 maEmptyFunc(std::move(aEmptyFunc))
2484 size_t mnRowSize;
2485 size_t mnRowPos;
2486 size_t mnColPos;
2488 ScMatrix::DoubleOpFunction maDoubleFunc;
2489 ScMatrix::BoolOpFunction maBoolFunc;
2490 ScMatrix::StringOpFunction maStringFunc;
2491 ScMatrix::EmptyOpFunction maEmptyFunc;
2494 class WalkElementBlockOperation
2496 public:
2498 WalkElementBlockOperation(ElementBlock& rElementBlock)
2499 : mrElementBlock(rElementBlock)
2503 void operator()(const MatrixImplType::element_block_node_type& node)
2505 switch (node.type)
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;
2526 break;
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;
2546 break;
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;
2566 break;
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;
2580 break;
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;
2593 break;
2597 private:
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);
2611 maMat.walk(
2612 aFunc,
2613 MatrixImplType::size_pair_type(rStartPos.first, rStartPos.second),
2614 MatrixImplType::size_pair_type(rEndPos.first, rEndPos.second));
2617 #if DEBUG_MATRIX
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() << ")";
2633 break;
2634 case mdds::mtm::element_numeric:
2635 cout << "numeric (" << maMat.get_numeric(nRow, nCol) << ")";
2636 break;
2637 case mdds::mtm::element_boolean:
2638 cout << "boolean (" << maMat.get_boolean(nRow, nCol) << ")";
2639 break;
2640 case mdds::mtm::element_empty:
2641 cout << "empty";
2642 break;
2643 default:
2647 cout << endl;
2651 #endif
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;
2669 namespace {
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)
2681 SCSIZE nC1, nC2;
2682 SCSIZE nR1, nR2;
2683 xMat1->GetDimensions(nC1, nR1);
2684 xMat2->GetDimensions(nC2, nR2);
2686 sal_uInt32 nKey = rFormatter.GetStandardFormat( SvNumFormatType::NUMBER,
2687 ScGlobal::eLnge);
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;
2703 return;
2705 OUString aStr;
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)
2713 OUString aStr;
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)
2738 nRowOffset = i;
2739 for (size_t j = 0; j < nColRep; ++j)
2741 nColOffset = 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);
2749 else
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;
2765 return;
2767 OUString aStr;
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)
2775 OUString aStr;
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)]);
2794 nRowOffset = 0;
2795 nColOffset = 0;
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)
2803 nRowOffset = i;
2804 for (size_t j = 0; j < nColRep; ++j)
2806 nColOffset = 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);
2814 else
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));
2820 aString.clear();
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;
2839 i += nColSteps;
2840 j += nSteps % nMaxRow;
2841 if (j >= nMaxRow)
2843 j -= nMaxRow;
2844 ++i;
2847 else
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:
2863 return true;
2864 default:
2867 return false;
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);
2879 return fVal;
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:
2891 return true;
2892 default:
2895 return false;
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:
2910 return true;
2911 default:
2914 return false;
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);
2938 FormulaError nErr;
2939 if (bVal1 && bVal2)
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));
2966 else
2968 double d = Op( fVal1, fVal2);
2969 aOutPos = maMat.set(aOutPos, d);
2972 else
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);
2980 else
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);
2994 FormulaError nErr;
2995 if (bVal1 && bVal2)
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));
3021 else
3023 double d = Op( fVal1, fVal2);
3024 aOutPos = maMat.set(aOutPos, d);
3027 else
3028 aOutPos = maMat.set(aOutPos, CreateDoubleError(FormulaError::NoValue));
3029 aOutPos = MatrixImplType::next_position(aOutPos);
3035 void ScMatrix::IncRef() const
3037 ++nRefCnt;
3040 void ScMatrix::DecRef() const
3042 --nRefCnt;
3043 if (nRefCnt == 0)
3044 delete this;
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");
3055 return false;
3057 if (!nC || !nR)
3058 return true;
3060 std::call_once(bElementsMaxFetched,
3061 []()
3063 const char* pEnv = std::getenv("SC_MAX_MATRIX_ELEMENTS");
3064 if (pEnv)
3066 // Environment specifies the overall elements pool.
3067 nElementsMax = std::atoi(pEnv);
3069 else
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;
3077 #else
3078 // Assume 6GB memory could be consumed by matrices.
3079 constexpr size_t nMemMax = 0x180000000;
3080 #endif
3081 nElementsMax = GetElementsMax( nMemMax);
3085 if (nC > (nElementsMax / nR))
3087 SAL_WARN( "sc.core", "ScMatrix overflow: " << nC << " columns * " << nR << " rows");
3088 return false;
3090 return true;
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));
3098 else
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));
3108 else
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));
3118 else
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
3129 SCSIZE nC, nR;
3130 pImpl->GetDimensions(nC, nR);
3131 ScMatrix* pScMat = new ScMatrix(nC, nR);
3132 MatCopy(*pScMat);
3133 pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter()); // TODO: really?
3134 return pScMat;
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);
3165 MatCopy(*pScMat);
3166 pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter());
3167 return pScMat;
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
3432 return pImpl->Or();
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);
3507 namespace matop {
3509 namespace {
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
3515 DoubleError.
3516 An empty operand evaluates to 0.
3518 template<typename TOp>
3519 struct MatOp
3521 private:
3522 TOp maOp;
3523 ScInterpreter* mpErrorInterpreter;
3524 double mfVal;
3526 public:
3527 typedef double number_value_type;
3529 MatOp( TOp aOp, ScInterpreter* pErrorInterpreter,
3530 double fVal = 0.0 ):
3531 maOp(aOp),
3532 mpErrorInterpreter(pErrorInterpreter),
3533 mfVal(fVal)
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()
3566 return true;
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)
3597 if (bFlag)
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);
3603 else
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)
3620 if (bFlag)
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);
3626 else
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)
3636 if (bFlag)
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);
3642 else
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);
3662 #if DEBUG_MATRIX
3663 void ScMatrix::Dump() const
3665 pImpl->Dump();
3667 #endif
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: */