tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / tool / scmatrix.cxx
blob0f792203c66b829f51f329eb844778ee413732cc
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 PutEmpty(SCSIZE nIndex);
273 void PutEmptyTrans(SCSIZE nIndex);
274 void PutEmptyPath(SCSIZE nC, SCSIZE nR);
275 void PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR );
276 void PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR);
277 FormulaError GetError( SCSIZE nC, SCSIZE nR) const;
278 double GetDouble(SCSIZE nC, SCSIZE nR) const;
279 double GetDouble( SCSIZE nIndex) const;
280 double GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const;
281 svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const;
282 svl::SharedString GetString( SCSIZE nIndex) const;
283 svl::SharedString GetString( ScInterpreterContext& rContext, SCSIZE nC, SCSIZE nR) const;
284 ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const;
285 bool IsStringOrEmpty( SCSIZE nIndex ) const;
286 bool IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const;
287 bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;
288 bool IsEmptyCell( SCSIZE nC, SCSIZE nR ) const;
289 bool IsEmptyResult( SCSIZE nC, SCSIZE nR ) const;
290 bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const;
291 bool IsValue( SCSIZE nIndex ) const;
292 bool IsValue( SCSIZE nC, SCSIZE nR ) const;
293 bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const;
294 bool IsBoolean( SCSIZE nC, SCSIZE nR ) const;
295 bool IsNumeric() const;
297 void MatCopy(ScMatrixImpl& mRes) const;
298 void MatTrans(ScMatrixImpl& mRes) const;
299 void FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 );
300 void PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR );
301 void PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR );
302 void PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
303 void PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
304 void PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
305 void CompareEqual();
306 void CompareNotEqual();
307 void CompareLess();
308 void CompareGreater();
309 void CompareLessEqual();
310 void CompareGreaterEqual();
311 double And() const;
312 double Or() const;
313 double Xor() const;
315 ScMatrix::KahanIterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues ) const;
316 ScMatrix::KahanIterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues ) const;
317 ScMatrix::DoubleIterateResult Product( bool bTextAsZero, bool bIgnoreErrorValues ) const;
318 size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const;
319 size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const;
320 size_t MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const;
322 double GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const;
323 double GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const;
324 double GetGcd() const;
325 double GetLcm() const;
327 ScMatrixRef CompareMatrix( sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const;
329 void GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const;
330 void MergeDoubleArrayMultiply( std::vector<double>& rArray ) const;
332 template<typename T>
333 void ApplyOperation(T aOp, ScMatrixImpl& rMat);
335 void ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
336 const std::pair<size_t, size_t>& rEndPos, const ScMatrix::DoubleOpFunction& aDoubleFunc,
337 const ScMatrix::BoolOpFunction& aBoolFunc, const ScMatrix::StringOpFunction& aStringFunc,
338 const ScMatrix::EmptyOpFunction& aEmptyFunc) const;
340 template<typename T, typename tRes>
341 ScMatrix::IterateResultMultiple<tRes> ApplyCollectOperation(const std::vector<T>& aOp);
343 void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
344 ScInterpreterContext& rContext, svl::SharedStringPool& rPool);
346 void ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
347 ScInterpreter* pInterpreter, const ScMatrix::CalculateOpFunction& op);
348 bool IsValueOrEmpty( const MatrixImplType::const_position_type & rPos ) const;
349 double GetDouble( const MatrixImplType::const_position_type & rPos) const;
350 FormulaError GetErrorIfNotString( const MatrixImplType::const_position_type & rPos ) const;
351 bool IsValue( const MatrixImplType::const_position_type & rPos ) const;
352 FormulaError GetError(const MatrixImplType::const_position_type & rPos) const;
353 bool IsStringOrEmpty(const MatrixImplType::const_position_type & rPos) const;
354 svl::SharedString GetString(const MatrixImplType::const_position_type& rPos) const;
356 #if DEBUG_MATRIX
357 void Dump() const;
358 #endif
360 private:
361 void CalcPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const;
362 void CalcTransPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const;
365 static std::once_flag bElementsMaxFetched;
366 static std::atomic<size_t> nElementsMax;
368 /** The maximum number of elements a matrix or the pool may have at runtime.
370 @param nMemory
371 If 0, the arbitrary limit of one matrix is returned.
372 If >0, the given memory pool divided by the average size of a
373 matrix element is returned, which is used to initialize
374 nElementsMax.
376 static size_t GetElementsMax( size_t nMemory )
378 // Arbitrarily assuming 12 bytes per element, 8 bytes double plus
379 // overhead. Stored as an array in an mdds container it's less, but for
380 // strings or mixed matrix it can be much more...
381 constexpr size_t nPerElem = 12;
382 if (nMemory)
383 return nMemory / nPerElem;
385 // Arbitrarily assuming 1GB memory. Could be dynamic at some point.
386 constexpr size_t nMemMax = 0x40000000;
387 // With 1GB that's ~85M elements, or 85 whole columns.
388 constexpr size_t nElemMax = nMemMax / nPerElem;
389 // With MAXROWCOUNT==1048576 and 128 columns => 128M elements, 1.5GB
390 constexpr size_t nArbitraryLimit = size_t(MAXROWCOUNT) * 128;
391 // With the constant 1GB from above that's the actual value.
392 return std::min(nElemMax, nArbitraryLimit);
395 ScMatrixImpl::ScMatrixImpl(SCSIZE nC, SCSIZE nR) :
396 maMat(nR, nC), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
398 nElementsMax -= GetElementCount();
401 ScMatrixImpl::ScMatrixImpl(SCSIZE nC, SCSIZE nR, double fInitVal) :
402 maMat(nR, nC, fInitVal), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
404 nElementsMax -= GetElementCount();
407 ScMatrixImpl::ScMatrixImpl( size_t nC, size_t nR, const std::vector<double>& rInitVals ) :
408 maMat(nR, nC, rInitVals.begin(), rInitVals.end()), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
410 nElementsMax -= GetElementCount();
413 ScMatrixImpl::~ScMatrixImpl()
415 nElementsMax += GetElementCount();
416 suppress_fun_call_w_exception(Clear());
419 void ScMatrixImpl::Clear()
421 suppress_fun_call_w_exception(maMat.clear());
422 maMatFlag.clear();
425 void ScMatrixImpl::Resize(SCSIZE nC, SCSIZE nR)
427 nElementsMax += GetElementCount();
428 if (ScMatrix::IsSizeAllocatable( nC, nR))
430 maMat.resize(nR, nC);
431 maMatFlag.resize(nR, nC);
433 else
435 // Invalid matrix size, allocate 1x1 matrix with error value.
436 maMat.resize(1, 1, CreateDoubleError( FormulaError::MatrixSize));
437 maMatFlag.resize(1, 1);
439 nElementsMax -= GetElementCount();
442 void ScMatrixImpl::Resize(SCSIZE nC, SCSIZE nR, double fVal)
444 nElementsMax += GetElementCount();
445 if (ScMatrix::IsSizeAllocatable( nC, nR))
447 maMat.resize(nR, nC, fVal);
448 maMatFlag.resize(nR, nC);
450 else
452 // Invalid matrix size, allocate 1x1 matrix with error value.
453 maMat.resize(1, 1, CreateDoubleError( FormulaError::StackOverflow));
454 maMatFlag.resize(1, 1);
456 nElementsMax -= GetElementCount();
459 void ScMatrixImpl::SetErrorInterpreter( ScInterpreter* p)
461 pErrorInterpreter = p;
464 void ScMatrixImpl::GetDimensions( SCSIZE& rC, SCSIZE& rR) const
466 MatrixImplType::size_pair_type aSize = maMat.size();
467 rR = aSize.row;
468 rC = aSize.column;
471 SCSIZE ScMatrixImpl::GetElementCount() const
473 MatrixImplType::size_pair_type aSize = maMat.size();
474 return aSize.row * aSize.column;
477 bool ScMatrixImpl::ValidColRow( SCSIZE nC, SCSIZE nR) const
479 MatrixImplType::size_pair_type aSize = maMat.size();
480 return nR < aSize.row && nC < aSize.column;
483 bool ScMatrixImpl::ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const
485 MatrixImplType::size_pair_type aSize = maMat.size();
486 if (aSize.column == 1 && aSize.row == 1)
488 rC = 0;
489 rR = 0;
490 return true;
492 else if (aSize.column == 1 && rR < aSize.row)
494 // single column matrix.
495 rC = 0;
496 return true;
498 else if (aSize.row == 1 && rC < aSize.column)
500 // single row matrix.
501 rR = 0;
502 return true;
504 return false;
507 bool ScMatrixImpl::ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const
509 return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
512 void ScMatrixImpl::SetErrorAtInterpreter( FormulaError nError ) const
514 if ( pErrorInterpreter )
515 pErrorInterpreter->SetError( nError);
518 void ScMatrixImpl::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
520 if (ValidColRow( nC, nR))
521 maMat.set(nR, nC, fVal);
522 else
524 OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
528 void ScMatrixImpl::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
530 if (ValidColRow( nC, nR))
531 maMat.set(nR, nC, pArray, pArray + nLen);
532 else
534 OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
538 void ScMatrixImpl::PutDouble( double fVal, SCSIZE nIndex)
540 SCSIZE nC, nR;
541 CalcPosition(nIndex, nC, nR);
542 PutDouble(fVal, nC, nR);
545 void ScMatrixImpl::PutDoubleTrans(double fVal, SCSIZE nIndex)
547 SCSIZE nC, nR;
548 CalcTransPosition(nIndex, nC, nR);
549 PutDouble(fVal, nC, nR);
552 void ScMatrixImpl::PutString(const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR)
554 if (ValidColRow( nC, nR))
555 maMat.set(nR, nC, rStr);
556 else
558 OSL_FAIL("ScMatrixImpl::PutString: dimension error");
562 void ScMatrixImpl::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
564 if (ValidColRow( nC, nR))
565 maMat.set(nR, nC, pArray, pArray + nLen);
566 else
568 OSL_FAIL("ScMatrixImpl::PutString: dimension error");
572 void ScMatrixImpl::PutString(const svl::SharedString& rStr, SCSIZE nIndex)
574 SCSIZE nC, nR;
575 CalcPosition(nIndex, nC, nR);
576 PutString(rStr, nC, nR);
579 void ScMatrixImpl::PutStringTrans(const svl::SharedString& rStr, SCSIZE nIndex)
581 SCSIZE nC, nR;
582 CalcTransPosition(nIndex, nC, nR);
583 PutString(rStr, nC, nR);
586 void ScMatrixImpl::PutEmpty(SCSIZE nC, SCSIZE nR)
588 if (ValidColRow( nC, nR))
590 maMat.set_empty(nR, nC);
591 maMatFlag.set_empty(nR, nC);
593 else
595 OSL_FAIL("ScMatrixImpl::PutEmpty: dimension error");
599 void ScMatrixImpl::PutEmpty(SCSIZE nIndex)
601 SCSIZE nC, nR;
602 CalcPosition(nIndex, nC, nR);
603 PutEmpty(nC, nR);
606 void ScMatrixImpl::PutEmptyTrans(SCSIZE nIndex)
608 SCSIZE nC, nR;
609 CalcTransPosition(nIndex, nC, nR);
610 PutEmpty(nC, nR);
613 void ScMatrixImpl::PutEmptyPath(SCSIZE nC, SCSIZE nR)
615 if (ValidColRow( nC, nR))
617 maMat.set_empty(nR, nC);
618 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 && __cplusplus == 202002L
619 #pragma GCC diagnostic push
620 #pragma GCC diagnostic ignored "-Warray-bounds"
621 #endif
622 maMatFlag.set(nR, nC, SC_MATFLAG_EMPTYPATH);
623 #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 && __cplusplus == 202002L
624 #pragma GCC diagnostic pop
625 #endif
627 else
629 OSL_FAIL("ScMatrixImpl::PutEmptyPath: dimension error");
633 void ScMatrixImpl::PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR )
635 maMat.set(nR, nC, CreateDoubleError(nErrorCode));
638 void ScMatrixImpl::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
640 if (ValidColRow( nC, nR))
641 maMat.set(nR, nC, bVal);
642 else
644 OSL_FAIL("ScMatrixImpl::PutBoolean: dimension error");
648 FormulaError ScMatrixImpl::GetError( SCSIZE nC, SCSIZE nR) const
650 if (ValidColRowOrReplicated( nC, nR ))
652 double fVal = maMat.get_numeric(nR, nC);
653 return GetDoubleErrorValue(fVal);
655 else
657 OSL_FAIL("ScMatrixImpl::GetError: dimension error");
658 return FormulaError::NoValue;
662 double ScMatrixImpl::GetDouble(SCSIZE nC, SCSIZE nR) const
664 if (ValidColRowOrReplicated( nC, nR ))
666 double fVal = maMat.get_numeric(nR, nC);
667 if ( pErrorInterpreter )
669 FormulaError nError = GetDoubleErrorValue(fVal);
670 if ( nError != FormulaError::NONE )
671 SetErrorAtInterpreter( nError);
673 return fVal;
675 else
677 OSL_FAIL("ScMatrixImpl::GetDouble: dimension error");
678 return CreateDoubleError( FormulaError::NoValue);
682 double ScMatrixImpl::GetDouble( SCSIZE nIndex) const
684 SCSIZE nC, nR;
685 CalcPosition(nIndex, nC, nR);
686 return GetDouble(nC, nR);
689 double ScMatrixImpl::GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
691 ScMatrixValue aMatVal = Get(nC, nR);
692 if (aMatVal.nType == ScMatValType::String)
693 return convertStringToValue( pErrorInterpreter, aMatVal.aStr.getString());
694 return aMatVal.fVal;
697 svl::SharedString ScMatrixImpl::GetString(SCSIZE nC, SCSIZE nR) const
699 if (ValidColRowOrReplicated( nC, nR ))
701 return GetString(maMat.position(nR, nC));
703 else
705 OSL_FAIL("ScMatrixImpl::GetString: dimension error");
707 return svl::SharedString::getEmptyString();
710 svl::SharedString ScMatrixImpl::GetString(const MatrixImplType::const_position_type& rPos) const
712 double fErr = 0.0;
713 switch (maMat.get_type(rPos))
715 case mdds::mtm::element_string:
716 return maMat.get_string(rPos);
717 case mdds::mtm::element_empty:
718 return svl::SharedString::getEmptyString();
719 case mdds::mtm::element_numeric:
720 case mdds::mtm::element_boolean:
721 fErr = maMat.get_numeric(rPos);
722 [[fallthrough]];
723 default:
724 OSL_FAIL("ScMatrixImpl::GetString: access error, no string");
726 SetErrorAtInterpreter(GetDoubleErrorValue(fErr));
727 return svl::SharedString::getEmptyString();
730 svl::SharedString ScMatrixImpl::GetString( SCSIZE nIndex) const
732 SCSIZE nC, nR;
733 CalcPosition(nIndex, nC, nR);
734 return GetString(nC, nR);
737 svl::SharedString ScMatrixImpl::GetString( ScInterpreterContext& rContext, SCSIZE nC, SCSIZE nR) const
739 if (!ValidColRowOrReplicated( nC, nR ))
741 OSL_FAIL("ScMatrixImpl::GetString: dimension error");
742 return svl::SharedString::getEmptyString();
745 double fVal = 0.0;
746 MatrixImplType::const_position_type aPos = maMat.position(nR, nC);
747 switch (maMat.get_type(aPos))
749 case mdds::mtm::element_string:
750 return maMat.get_string(aPos);
751 case mdds::mtm::element_empty:
753 if (maMatFlag.get<uint8_t>(nR, nC) != SC_MATFLAG_EMPTYPATH)
754 // not an empty path.
755 return svl::SharedString::getEmptyString();
757 // result of empty FALSE jump path
758 sal_uInt32 nKey = rContext.NFGetStandardFormat( SvNumFormatType::LOGICAL,
759 ScGlobal::eLnge);
760 OUString aStr;
761 const Color* pColor = nullptr;
762 rContext.NFGetOutputString( 0.0, nKey, aStr, &pColor);
763 return svl::SharedString( aStr); // string not interned
765 case mdds::mtm::element_numeric:
766 case mdds::mtm::element_boolean:
767 fVal = maMat.get_numeric(aPos);
768 break;
769 default:
773 FormulaError nError = GetDoubleErrorValue(fVal);
774 if (nError != FormulaError::NONE)
776 SetErrorAtInterpreter( nError);
777 return svl::SharedString( ScGlobal::GetErrorString( nError)); // string not interned
780 sal_uInt32 nKey = rContext.NFGetStandardFormat( SvNumFormatType::NUMBER,
781 ScGlobal::eLnge);
782 return svl::SharedString(rContext.NFGetInputLineString( fVal, nKey )); // string not interned
785 ScMatrixValue ScMatrixImpl::Get(SCSIZE nC, SCSIZE nR) const
787 ScMatrixValue aVal;
788 if (ValidColRowOrReplicated(nC, nR))
790 MatrixImplType::const_position_type aPos = maMat.position(nR, nC);
791 mdds::mtm::element_t eType = maMat.get_type(aPos);
792 switch (eType)
794 case mdds::mtm::element_boolean:
795 aVal.nType = ScMatValType::Boolean;
796 aVal.fVal = double(maMat.get_boolean(aPos));
797 break;
798 case mdds::mtm::element_numeric:
799 aVal.nType = ScMatValType::Value;
800 aVal.fVal = maMat.get_numeric(aPos);
801 break;
802 case mdds::mtm::element_string:
803 aVal.nType = ScMatValType::String;
804 aVal.aStr = maMat.get_string(aPos);
805 break;
806 case mdds::mtm::element_empty:
807 /* TODO: do we need to pass the differentiation of 'empty' and
808 * 'empty result' to the outer world anywhere? */
809 switch (maMatFlag.get_type(nR, nC))
811 case mdds::mtm::element_empty:
812 aVal.nType = ScMatValType::Empty;
813 break;
814 case mdds::mtm::element_integer:
815 aVal.nType = maMatFlag.get<uint8_t>(nR, nC)
816 == SC_MATFLAG_EMPTYPATH ? ScMatValType::EmptyPath : ScMatValType::Empty;
817 break;
818 default:
819 assert(false);
821 aVal.fVal = 0.0;
822 break;
823 default:
827 else
829 OSL_FAIL("ScMatrixImpl::Get: dimension error");
831 return aVal;
834 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nIndex ) const
836 SCSIZE nC, nR;
837 CalcPosition(nIndex, nC, nR);
838 return IsStringOrEmpty(nC, nR);
841 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const
843 if (!ValidColRowOrReplicated( nC, nR ))
844 return false;
846 switch (maMat.get_type(nR, nC))
848 case mdds::mtm::element_empty:
849 case mdds::mtm::element_string:
850 return true;
851 default:
854 return false;
857 bool ScMatrixImpl::IsEmpty( SCSIZE nC, SCSIZE nR ) const
859 if (!ValidColRowOrReplicated( nC, nR ))
860 return false;
862 // Flag must indicate an 'empty' or 'empty cell' or 'empty result' element,
863 // but not an 'empty path' element.
864 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
865 maMatFlag.get_integer(nR, nC) != SC_MATFLAG_EMPTYPATH;
868 bool ScMatrixImpl::IsEmptyCell( SCSIZE nC, SCSIZE nR ) const
870 if (!ValidColRowOrReplicated( nC, nR ))
871 return false;
873 // Flag must indicate an 'empty cell' element instead of an
874 // 'empty' or 'empty result' or 'empty path' element.
875 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
876 maMatFlag.get_type(nR, nC) == mdds::mtm::element_empty;
879 bool ScMatrixImpl::IsEmptyResult( SCSIZE nC, SCSIZE nR ) const
881 if (!ValidColRowOrReplicated( nC, nR ))
882 return false;
884 // Flag must indicate an 'empty result' element instead of an
885 // 'empty' or 'empty cell' or 'empty path' element.
886 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
887 maMatFlag.get_integer(nR, nC) == SC_MATFLAG_EMPTYRESULT;
890 bool ScMatrixImpl::IsEmptyPath( SCSIZE nC, SCSIZE nR ) const
892 // Flag must indicate an 'empty path' element.
893 if (ValidColRowOrReplicated( nC, nR ))
894 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
895 maMatFlag.get_integer(nR, nC) == SC_MATFLAG_EMPTYPATH;
896 else
897 return true;
900 bool ScMatrixImpl::IsValue( SCSIZE nIndex ) const
902 SCSIZE nC, nR;
903 CalcPosition(nIndex, nC, nR);
904 return IsValue(nC, nR);
907 bool ScMatrixImpl::IsValue( SCSIZE nC, SCSIZE nR ) const
909 if (!ValidColRowOrReplicated( nC, nR ))
910 return false;
912 switch (maMat.get_type(nR, nC))
914 case mdds::mtm::element_boolean:
915 case mdds::mtm::element_numeric:
916 return true;
917 default:
920 return false;
923 bool ScMatrixImpl::IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const
925 if (!ValidColRowOrReplicated( nC, nR ))
926 return false;
928 switch (maMat.get_type(nR, nC))
930 case mdds::mtm::element_boolean:
931 case mdds::mtm::element_numeric:
932 case mdds::mtm::element_empty:
933 return true;
934 default:
937 return false;
940 bool ScMatrixImpl::IsBoolean( SCSIZE nC, SCSIZE nR ) const
942 if (!ValidColRowOrReplicated( nC, nR ))
943 return false;
945 return maMat.get_type(nR, nC) == mdds::mtm::element_boolean;
948 bool ScMatrixImpl::IsNumeric() const
950 return maMat.numeric();
953 void ScMatrixImpl::MatCopy(ScMatrixImpl& mRes) const
955 if (maMat.size().row > mRes.maMat.size().row || maMat.size().column > mRes.maMat.size().column)
957 // destination matrix is not large enough.
958 OSL_FAIL("ScMatrixImpl::MatCopy: dimension error");
959 return;
962 mRes.maMat.copy(maMat);
965 void ScMatrixImpl::MatTrans(ScMatrixImpl& mRes) const
967 mRes.maMat = maMat;
968 mRes.maMat.transpose();
971 void ScMatrixImpl::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
973 if (ValidColRow( nC1, nR1) && ValidColRow( nC2, nR2))
975 for (SCSIZE j = nC1; j <= nC2; ++j)
977 // Passing value array is much faster.
978 std::vector<double> aVals(nR2-nR1+1, fVal);
979 maMat.set(nR1, j, aVals.begin(), aVals.end());
982 else
984 OSL_FAIL("ScMatrixImpl::FillDouble: dimension error");
988 void ScMatrixImpl::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
990 if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
992 maMat.set(nR, nC, rVec.begin(), rVec.end());
994 else
996 OSL_FAIL("ScMatrixImpl::PutDoubleVector: dimension error");
1000 void ScMatrixImpl::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
1002 if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
1004 maMat.set(nR, nC, rVec.begin(), rVec.end());
1006 else
1008 OSL_FAIL("ScMatrixImpl::PutStringVector: dimension error");
1012 void ScMatrixImpl::PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
1014 if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
1016 maMat.set_empty(nR, nC, nCount);
1017 // Flag to indicate that this is 'empty', not 'empty result' or 'empty path'.
1018 maMatFlag.set_empty(nR, nC, nCount);
1020 else
1022 OSL_FAIL("ScMatrixImpl::PutEmptyVector: dimension error");
1026 void ScMatrixImpl::PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
1028 if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
1030 maMat.set_empty(nR, nC, nCount);
1031 // Flag to indicate that this is 'empty result', not 'empty' or 'empty path'.
1032 std::vector<uint8_t> aVals(nCount, SC_MATFLAG_EMPTYRESULT);
1033 maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
1035 else
1037 OSL_FAIL("ScMatrixImpl::PutEmptyResultVector: dimension error");
1041 void ScMatrixImpl::PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
1043 if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
1045 maMat.set_empty(nR, nC, nCount);
1046 // Flag to indicate 'empty path'.
1047 std::vector<uint8_t> aVals(nCount, SC_MATFLAG_EMPTYPATH);
1048 maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
1050 else
1052 OSL_FAIL("ScMatrixImpl::PutEmptyPathVector: dimension error");
1056 void ScMatrixImpl::CompareEqual()
1058 MatrixImplType::size_pair_type aSize = maMat.size();
1059 CompareMatrixElemFunc<ElemEqualZero> aFunc(aSize.row, aSize.column);
1060 aFunc = maMat.walk(std::move(aFunc));
1061 aFunc.swap(maMat);
1064 void ScMatrixImpl::CompareNotEqual()
1066 MatrixImplType::size_pair_type aSize = maMat.size();
1067 CompareMatrixElemFunc<ElemNotEqualZero> aFunc(aSize.row, aSize.column);
1068 aFunc = maMat.walk(std::move(aFunc));
1069 aFunc.swap(maMat);
1072 void ScMatrixImpl::CompareLess()
1074 MatrixImplType::size_pair_type aSize = maMat.size();
1075 CompareMatrixElemFunc<ElemLessZero> aFunc(aSize.row, aSize.column);
1076 aFunc = maMat.walk(std::move(aFunc));
1077 aFunc.swap(maMat);
1080 void ScMatrixImpl::CompareGreater()
1082 MatrixImplType::size_pair_type aSize = maMat.size();
1083 CompareMatrixElemFunc<ElemGreaterZero> aFunc(aSize.row, aSize.column);
1084 aFunc = maMat.walk(std::move(aFunc));
1085 aFunc.swap(maMat);
1088 void ScMatrixImpl::CompareLessEqual()
1090 MatrixImplType::size_pair_type aSize = maMat.size();
1091 CompareMatrixElemFunc<ElemLessEqualZero> aFunc(aSize.row, aSize.column);
1092 aFunc = maMat.walk(std::move(aFunc));
1093 aFunc.swap(maMat);
1096 void ScMatrixImpl::CompareGreaterEqual()
1098 MatrixImplType::size_pair_type aSize = maMat.size();
1099 CompareMatrixElemFunc<ElemGreaterEqualZero> aFunc(aSize.row, aSize.column);
1100 aFunc = maMat.walk(std::move(aFunc));
1101 aFunc.swap(maMat);
1104 namespace {
1106 struct AndEvaluator
1108 bool mbResult;
1109 void operate(double fVal) { mbResult &= (fVal != 0.0); }
1110 bool result() const { return mbResult; }
1111 AndEvaluator() : mbResult(true) {}
1114 struct OrEvaluator
1116 bool mbResult;
1117 void operate(double fVal) { mbResult |= (fVal != 0.0); }
1118 bool result() const { return mbResult; }
1119 OrEvaluator() : mbResult(false) {}
1122 struct XorEvaluator
1124 bool mbResult;
1125 void operate(double fVal) { mbResult ^= (fVal != 0.0); }
1126 bool result() const { return mbResult; }
1127 XorEvaluator() : mbResult(false) {}
1130 // Do not short circuit logical operations, in case there are error values
1131 // these need to be propagated even if the result was determined earlier.
1132 template <typename Evaluator>
1133 double EvalMatrix(const MatrixImplType& rMat)
1135 Evaluator aEval;
1136 size_t nRows = rMat.size().row, nCols = rMat.size().column;
1137 for (size_t i = 0; i < nRows; ++i)
1139 for (size_t j = 0; j < nCols; ++j)
1141 MatrixImplType::const_position_type aPos = rMat.position(i, j);
1142 mdds::mtm::element_t eType = rMat.get_type(aPos);
1143 if (eType != mdds::mtm::element_numeric && eType != mdds::mtm::element_boolean)
1144 // assuming a CompareMat this is an error
1145 return CreateDoubleError(FormulaError::IllegalArgument);
1147 double fVal = rMat.get_numeric(aPos);
1148 if (!std::isfinite(fVal))
1149 // DoubleError
1150 return fVal;
1152 aEval.operate(fVal);
1155 return aEval.result();
1160 double ScMatrixImpl::And() const
1162 // All elements must be of value type.
1163 // True only if all the elements have non-zero values.
1164 return EvalMatrix<AndEvaluator>(maMat);
1167 double ScMatrixImpl::Or() const
1169 // All elements must be of value type.
1170 // True if at least one element has a non-zero value.
1171 return EvalMatrix<OrEvaluator>(maMat);
1174 double ScMatrixImpl::Xor() const
1176 // All elements must be of value type.
1177 // True if an odd number of elements have a non-zero value.
1178 return EvalMatrix<XorEvaluator>(maMat);
1181 namespace {
1183 template<typename Op, typename tRes>
1184 class WalkElementBlocks
1186 Op maOp;
1187 ScMatrix::IterateResult<tRes> maRes;
1188 bool mbTextAsZero:1;
1189 bool mbIgnoreErrorValues:1;
1190 public:
1191 WalkElementBlocks(bool bTextAsZero, bool bIgnoreErrorValues) :
1192 maRes(Op::InitVal, 0),
1193 mbTextAsZero(bTextAsZero), mbIgnoreErrorValues(bIgnoreErrorValues)
1196 const ScMatrix::IterateResult<tRes>& getResult() const { return maRes; }
1198 void operator() (const MatrixImplType::element_block_node_type& node)
1200 switch (node.type)
1202 case mdds::mtm::element_numeric:
1204 typedef MatrixImplType::numeric_block_type block_type;
1206 size_t nIgnored = 0;
1207 block_type::const_iterator it = block_type::begin(*node.data);
1208 block_type::const_iterator itEnd = block_type::end(*node.data);
1209 for (; it != itEnd; ++it)
1211 if (mbIgnoreErrorValues && !std::isfinite(*it))
1213 ++nIgnored;
1214 continue;
1216 maOp(maRes.maAccumulator, *it);
1218 maRes.mnCount += node.size - nIgnored;
1220 break;
1221 case mdds::mtm::element_boolean:
1223 typedef MatrixImplType::boolean_block_type block_type;
1225 block_type::const_iterator it = block_type::begin(*node.data);
1226 block_type::const_iterator itEnd = block_type::end(*node.data);
1227 for (; it != itEnd; ++it)
1229 maOp(maRes.maAccumulator, *it);
1231 maRes.mnCount += node.size;
1233 break;
1234 case mdds::mtm::element_string:
1235 if (mbTextAsZero)
1236 maRes.mnCount += node.size;
1237 break;
1238 case mdds::mtm::element_empty:
1239 default:
1245 template<typename Op, typename tRes>
1246 class WalkElementBlocksMultipleValues
1248 const std::vector<Op>* mpOp;
1249 ScMatrix::IterateResultMultiple<tRes> maRes;
1250 public:
1251 WalkElementBlocksMultipleValues(const std::vector<Op>& aOp) :
1252 mpOp(&aOp), maRes(0)
1254 for (const auto& rpOp : *mpOp)
1255 maRes.maAccumulator.emplace_back(rpOp.mInitVal);
1258 WalkElementBlocksMultipleValues( const WalkElementBlocksMultipleValues& ) = delete;
1259 WalkElementBlocksMultipleValues& operator= ( const WalkElementBlocksMultipleValues& ) = delete;
1261 WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues&& r) noexcept
1262 : mpOp(r.mpOp), maRes(r.maRes.mnCount)
1264 maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1267 WalkElementBlocksMultipleValues& operator=(WalkElementBlocksMultipleValues&& r) noexcept
1269 mpOp = r.mpOp;
1270 maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1271 maRes.mnCount = r.maRes.mnCount;
1272 return *this;
1275 const ScMatrix::IterateResultMultiple<tRes>& getResult() const { return maRes; }
1277 void operator() (const MatrixImplType::element_block_node_type& node)
1279 switch (node.type)
1281 case mdds::mtm::element_numeric:
1283 typedef MatrixImplType::numeric_block_type block_type;
1285 block_type::const_iterator it = block_type::begin(*node.data);
1286 block_type::const_iterator itEnd = block_type::end(*node.data);
1287 for (; it != itEnd; ++it)
1289 for (size_t i = 0u; i < mpOp->size(); ++i)
1290 (*mpOp)[i](maRes.maAccumulator[i], *it);
1292 maRes.mnCount += node.size;
1294 break;
1295 case mdds::mtm::element_boolean:
1297 typedef MatrixImplType::boolean_block_type block_type;
1299 block_type::const_iterator it = block_type::begin(*node.data);
1300 block_type::const_iterator itEnd = block_type::end(*node.data);
1301 for (; it != itEnd; ++it)
1303 for (size_t i = 0u; i < mpOp->size(); ++i)
1304 (*mpOp)[i](maRes.maAccumulator[i], *it);
1306 maRes.mnCount += node.size;
1308 break;
1309 case mdds::mtm::element_string:
1310 case mdds::mtm::element_empty:
1311 default:
1317 class CountElements
1319 size_t mnCount;
1320 bool mbCountString;
1321 bool mbCountErrors;
1322 bool mbIgnoreEmptyStrings;
1323 public:
1324 explicit CountElements(bool bCountString, bool bCountErrors, bool bIgnoreEmptyStrings) :
1325 mnCount(0), mbCountString(bCountString), mbCountErrors(bCountErrors),
1326 mbIgnoreEmptyStrings(bIgnoreEmptyStrings) {}
1328 size_t getCount() const { return mnCount; }
1330 void operator() (const MatrixImplType::element_block_node_type& node)
1332 switch (node.type)
1334 case mdds::mtm::element_numeric:
1335 mnCount += node.size;
1336 if (!mbCountErrors)
1338 typedef MatrixImplType::numeric_block_type block_type;
1340 block_type::const_iterator it = block_type::begin(*node.data);
1341 block_type::const_iterator itEnd = block_type::end(*node.data);
1342 for (; it != itEnd; ++it)
1344 if (!std::isfinite(*it))
1345 --mnCount;
1348 break;
1349 case mdds::mtm::element_boolean:
1350 mnCount += node.size;
1351 break;
1352 case mdds::mtm::element_string:
1353 if (mbCountString)
1355 mnCount += node.size;
1356 if (mbIgnoreEmptyStrings)
1358 typedef MatrixImplType::string_block_type block_type;
1360 block_type::const_iterator it = block_type::begin(*node.data);
1361 block_type::const_iterator itEnd = block_type::end(*node.data);
1362 for (; it != itEnd; ++it)
1364 if (it->isEmpty())
1365 --mnCount;
1369 break;
1370 case mdds::mtm::element_empty:
1371 default:
1377 const size_t ResultNotSet = std::numeric_limits<size_t>::max();
1379 template<typename Type>
1380 class WalkAndMatchElements
1382 Type maMatchValue;
1383 size_t mnStartIndex;
1384 size_t mnStopIndex;
1385 size_t mnResult;
1386 size_t mnIndex;
1388 public:
1389 WalkAndMatchElements(Type aMatchValue, const MatrixImplType::size_pair_type& aSize, size_t nCol1, size_t nCol2) :
1390 maMatchValue(std::move(aMatchValue)),
1391 mnStartIndex( nCol1 * aSize.row ),
1392 mnStopIndex( (nCol2 + 1) * aSize.row ),
1393 mnResult(ResultNotSet),
1394 mnIndex(0)
1396 assert( nCol1 < aSize.column && nCol2 < aSize.column);
1399 size_t getMatching() const { return mnResult; }
1401 size_t getRemainingCount() const
1403 return mnIndex < mnStopIndex ? mnStopIndex - mnIndex : 0;
1406 size_t compare(const MatrixImplType::element_block_node_type& node) const;
1408 void operator() (const MatrixImplType::element_block_node_type& node)
1410 // early exit if match already found
1411 if (mnResult != ResultNotSet)
1412 return;
1414 // limit lookup to the requested columns
1415 if (mnStartIndex <= mnIndex && getRemainingCount() > 0)
1417 mnResult = compare(node);
1420 mnIndex += node.size;
1424 template<>
1425 size_t WalkAndMatchElements<double>::compare(const MatrixImplType::element_block_node_type& node) const
1427 size_t nCount = 0;
1428 switch (node.type)
1430 case mdds::mtm::element_numeric:
1432 typedef MatrixImplType::numeric_block_type block_type;
1434 block_type::const_iterator it = block_type::begin(*node.data);
1435 block_type::const_iterator itEnd = block_type::end(*node.data);
1436 const size_t nRemaining = getRemainingCount();
1437 for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1439 if (*it == maMatchValue)
1441 return mnIndex + nCount;
1444 break;
1446 case mdds::mtm::element_boolean:
1448 typedef MatrixImplType::boolean_block_type block_type;
1450 block_type::const_iterator it = block_type::begin(*node.data);
1451 block_type::const_iterator itEnd = block_type::end(*node.data);
1452 const size_t nRemaining = getRemainingCount();
1453 for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1455 if (int(*it) == maMatchValue)
1457 return mnIndex + nCount;
1460 break;
1462 break;
1463 case mdds::mtm::element_string:
1464 case mdds::mtm::element_empty:
1465 default:
1468 return ResultNotSet;
1471 template<>
1472 size_t WalkAndMatchElements<svl::SharedString>::compare(const MatrixImplType::element_block_node_type& node) const
1474 switch (node.type)
1476 case mdds::mtm::element_string:
1478 size_t nCount = 0;
1479 typedef MatrixImplType::string_block_type block_type;
1481 block_type::const_iterator it = block_type::begin(*node.data);
1482 block_type::const_iterator itEnd = block_type::end(*node.data);
1483 const size_t nRemaining = getRemainingCount();
1484 for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1486 if (it->getDataIgnoreCase() == maMatchValue.getDataIgnoreCase())
1488 return mnIndex + nCount;
1491 break;
1493 case mdds::mtm::element_boolean:
1494 case mdds::mtm::element_numeric:
1495 case mdds::mtm::element_empty:
1496 default:
1499 return ResultNotSet;
1502 struct MaxOp
1504 static double init() { return -std::numeric_limits<double>::max(); }
1505 static double compare(double left, double right)
1507 if (!std::isfinite(left))
1508 return left;
1509 if (!std::isfinite(right))
1510 return right;
1511 return std::max(left, right);
1514 static double boolValue(
1515 MatrixImplType::boolean_block_type::const_iterator it,
1516 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1518 // If the array has at least one true value, the maximum value is 1.
1519 it = std::find(it, itEnd, true);
1520 return it == itEnd ? 0.0 : 1.0;
1524 struct MinOp
1526 static double init() { return std::numeric_limits<double>::max(); }
1527 static double compare(double left, double right)
1529 if (!std::isfinite(left))
1530 return left;
1531 if (!std::isfinite(right))
1532 return right;
1533 return std::min(left, right);
1536 static double boolValue(
1537 MatrixImplType::boolean_block_type::const_iterator it,
1538 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1540 // If the array has at least one false value, the minimum value is 0.
1541 it = std::find(it, itEnd, false);
1542 return it == itEnd ? 1.0 : 0.0;
1546 struct Lcm
1548 static double init() { return 1.0; }
1549 static double calculate(double fx,double fy)
1551 return (fx*fy)/ScInterpreter::ScGetGCD(fx,fy);
1554 static double boolValue(
1555 MatrixImplType::boolean_block_type::const_iterator it,
1556 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1558 // If the array has at least one false value, the minimum value is 0.
1559 it = std::find(it, itEnd, false);
1560 return it == itEnd ? 1.0 : 0.0;
1564 struct Gcd
1566 static double init() { return 0.0; }
1567 static double calculate(double fx,double fy)
1569 return ScInterpreter::ScGetGCD(fx,fy);
1572 static double boolValue(
1573 MatrixImplType::boolean_block_type::const_iterator it,
1574 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1576 // If the array has at least one true value, the gcdResult is 1.
1577 it = std::find(it, itEnd, true);
1578 return it == itEnd ? 0.0 : 1.0;
1582 template<typename Op>
1583 class CalcMaxMinValue
1585 double mfVal;
1586 bool mbTextAsZero;
1587 bool mbIgnoreErrorValues;
1588 bool mbHasValue;
1589 public:
1590 CalcMaxMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) :
1591 mfVal(Op::init()),
1592 mbTextAsZero(bTextAsZero),
1593 mbIgnoreErrorValues(bIgnoreErrorValues),
1594 mbHasValue(false) {}
1596 double getValue() const { return mbHasValue ? mfVal : 0.0; }
1598 void operator() (const MatrixImplType::element_block_node_type& node)
1601 switch (node.type)
1603 case mdds::mtm::element_numeric:
1605 typedef MatrixImplType::numeric_block_type block_type;
1607 block_type::const_iterator it = block_type::begin(*node.data);
1608 block_type::const_iterator itEnd = block_type::end(*node.data);
1609 if (mbIgnoreErrorValues)
1611 for (; it != itEnd; ++it)
1613 if (std::isfinite(*it))
1614 mfVal = Op::compare(mfVal, *it);
1617 else
1619 for (; it != itEnd; ++it)
1620 mfVal = Op::compare(mfVal, *it);
1623 mbHasValue = true;
1625 break;
1626 case mdds::mtm::element_boolean:
1628 typedef MatrixImplType::boolean_block_type block_type;
1630 block_type::const_iterator it = block_type::begin(*node.data);
1631 block_type::const_iterator itEnd = block_type::end(*node.data);
1632 double fVal = Op::boolValue(it, itEnd);
1633 mfVal = Op::compare(mfVal, fVal);
1634 mbHasValue = true;
1636 break;
1637 case mdds::mtm::element_string:
1638 case mdds::mtm::element_empty:
1640 // empty elements are treated as empty strings.
1641 if (mbTextAsZero)
1643 mfVal = Op::compare(mfVal, 0.0);
1644 mbHasValue = true;
1647 break;
1648 default:
1654 template<typename Op>
1655 class CalcGcdLcm
1657 double mfval;
1659 public:
1660 CalcGcdLcm() : mfval(Op::init()) {}
1662 double getResult() const { return mfval; }
1664 void operator() ( const MatrixImplType::element_block_node_type& node )
1666 switch (node.type)
1668 case mdds::mtm::element_numeric:
1670 typedef MatrixImplType::numeric_block_type block_type;
1671 block_type::const_iterator it = block_type::begin(*node.data);
1672 block_type::const_iterator itEnd = block_type::end(*node.data);
1674 for ( ; it != itEnd; ++it)
1676 if (*it < 0.0)
1677 mfval = CreateDoubleError(FormulaError::IllegalArgument);
1678 else
1679 mfval = ::rtl::math::approxFloor( Op::calculate(*it,mfval));
1682 break;
1683 case mdds::mtm::element_boolean:
1685 typedef MatrixImplType::boolean_block_type block_type;
1686 block_type::const_iterator it = block_type::begin(*node.data);
1687 block_type::const_iterator itEnd = block_type::end(*node.data);
1689 mfval = Op::boolValue(it, itEnd);
1691 break;
1692 case mdds::mtm::element_empty:
1693 case mdds::mtm::element_string:
1695 mfval = CreateDoubleError(FormulaError::IllegalArgument);
1697 break;
1698 default:
1704 double evaluate( double fVal, ScQueryOp eOp )
1706 if (!std::isfinite(fVal))
1707 return fVal;
1709 switch (eOp)
1711 case SC_EQUAL:
1712 return fVal == 0.0 ? 1.0 : 0.0;
1713 case SC_LESS:
1714 return fVal < 0.0 ? 1.0 : 0.0;
1715 case SC_GREATER:
1716 return fVal > 0.0 ? 1.0 : 0.0;
1717 case SC_LESS_EQUAL:
1718 return fVal <= 0.0 ? 1.0 : 0.0;
1719 case SC_GREATER_EQUAL:
1720 return fVal >= 0.0 ? 1.0 : 0.0;
1721 case SC_NOT_EQUAL:
1722 return fVal != 0.0 ? 1.0 : 0.0;
1723 default:
1727 SAL_WARN("sc.core", "evaluate: unhandled comparison operator: " << static_cast<int>(eOp));
1728 return CreateDoubleError( FormulaError::UnknownState);
1731 class CompareMatrixFunc
1733 sc::Compare& mrComp;
1734 size_t mnMatPos;
1735 sc::CompareOptions* mpOptions;
1736 std::vector<double> maResValues; // double instead of bool to transport error values
1738 void compare()
1740 double fVal = sc::CompareFunc( mrComp, mpOptions);
1741 maResValues.push_back(evaluate(fVal, mrComp.meOp));
1744 public:
1745 CompareMatrixFunc( size_t nResSize, sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) :
1746 mrComp(rComp), mnMatPos(nMatPos), mpOptions(pOptions)
1748 maResValues.reserve(nResSize);
1751 CompareMatrixFunc( const CompareMatrixFunc& ) = delete;
1752 CompareMatrixFunc& operator= ( const CompareMatrixFunc& ) = delete;
1754 CompareMatrixFunc(CompareMatrixFunc&& r) noexcept :
1755 mrComp(r.mrComp),
1756 mnMatPos(r.mnMatPos),
1757 mpOptions(r.mpOptions),
1758 maResValues(std::move(r.maResValues)) {}
1760 CompareMatrixFunc& operator=(CompareMatrixFunc&& r) noexcept
1762 mrComp = r.mrComp;
1763 mnMatPos = r.mnMatPos;
1764 mpOptions = r.mpOptions;
1765 maResValues = std::move(r.maResValues);
1766 return *this;
1769 void operator() (const MatrixImplType::element_block_node_type& node)
1771 sc::Compare::Cell& rCell = mrComp.maCells[mnMatPos];
1773 switch (node.type)
1775 case mdds::mtm::element_numeric:
1777 typedef MatrixImplType::numeric_block_type block_type;
1779 block_type::const_iterator it = block_type::begin(*node.data);
1780 block_type::const_iterator itEnd = block_type::end(*node.data);
1781 for (; it != itEnd; ++it)
1783 rCell.mbValue = true;
1784 rCell.mbEmpty = false;
1785 rCell.mfValue = *it;
1786 compare();
1789 break;
1790 case mdds::mtm::element_boolean:
1792 typedef MatrixImplType::boolean_block_type block_type;
1794 block_type::const_iterator it = block_type::begin(*node.data);
1795 block_type::const_iterator itEnd = block_type::end(*node.data);
1796 for (; it != itEnd; ++it)
1798 rCell.mbValue = true;
1799 rCell.mbEmpty = false;
1800 rCell.mfValue = double(*it);
1801 compare();
1804 break;
1805 case mdds::mtm::element_string:
1807 typedef MatrixImplType::string_block_type block_type;
1809 block_type::const_iterator it = block_type::begin(*node.data);
1810 block_type::const_iterator itEnd = block_type::end(*node.data);
1811 for (; it != itEnd; ++it)
1813 const svl::SharedString& rStr = *it;
1814 rCell.mbValue = false;
1815 rCell.mbEmpty = false;
1816 rCell.maStr = rStr;
1817 compare();
1820 break;
1821 case mdds::mtm::element_empty:
1823 rCell.mbValue = false;
1824 rCell.mbEmpty = true;
1825 rCell.maStr = svl::SharedString::getEmptyString();
1826 for (size_t i = 0; i < node.size; ++i)
1827 compare();
1829 break;
1830 default:
1835 const std::vector<double>& getValues() const
1837 return maResValues;
1842 * Left-hand side is a matrix while the right-hand side is a numeric value.
1844 class CompareMatrixToNumericFunc
1846 sc::Compare& mrComp;
1847 double mfRightValue;
1848 sc::CompareOptions* mpOptions;
1849 std::vector<double> maResValues; // double instead of bool to transport error values
1851 void compare()
1853 double fVal = sc::CompareFunc(mrComp.maCells[0], mfRightValue, mpOptions);
1854 maResValues.push_back(evaluate(fVal, mrComp.meOp));
1857 void compareLeftNumeric( double fLeftVal )
1859 double fVal = sc::CompareFunc(fLeftVal, mfRightValue);
1860 maResValues.push_back(evaluate(fVal, mrComp.meOp));
1863 void compareLeftEmpty( size_t nSize )
1865 double fVal = sc::CompareEmptyToNumericFunc(mfRightValue);
1866 bool bRes = evaluate(fVal, mrComp.meOp);
1867 maResValues.resize(maResValues.size() + nSize, bRes ? 1.0 : 0.0);
1870 public:
1871 CompareMatrixToNumericFunc( size_t nResSize, sc::Compare& rComp, double fRightValue, sc::CompareOptions* pOptions ) :
1872 mrComp(rComp), mfRightValue(fRightValue), mpOptions(pOptions)
1874 maResValues.reserve(nResSize);
1877 CompareMatrixToNumericFunc( const CompareMatrixToNumericFunc& ) = delete;
1878 CompareMatrixToNumericFunc& operator= ( const CompareMatrixToNumericFunc& ) = delete;
1880 CompareMatrixToNumericFunc(CompareMatrixToNumericFunc&& r) noexcept :
1881 mrComp(r.mrComp),
1882 mfRightValue(r.mfRightValue),
1883 mpOptions(r.mpOptions),
1884 maResValues(std::move(r.maResValues)) {}
1886 CompareMatrixToNumericFunc& operator=(CompareMatrixToNumericFunc&& r) noexcept
1888 mrComp = r.mrComp;
1889 mfRightValue = r.mfRightValue;
1890 mpOptions = r.mpOptions;
1891 maResValues = std::move(r.maResValues);
1892 return *this;
1895 void operator() (const MatrixImplType::element_block_node_type& node)
1897 switch (node.type)
1899 case mdds::mtm::element_numeric:
1901 typedef MatrixImplType::numeric_block_type block_type;
1903 block_type::const_iterator it = block_type::begin(*node.data);
1904 block_type::const_iterator itEnd = block_type::end(*node.data);
1905 for (; it != itEnd; ++it)
1906 compareLeftNumeric(*it);
1908 break;
1909 case mdds::mtm::element_boolean:
1911 typedef MatrixImplType::boolean_block_type block_type;
1913 block_type::const_iterator it = block_type::begin(*node.data);
1914 block_type::const_iterator itEnd = block_type::end(*node.data);
1915 for (; it != itEnd; ++it)
1916 compareLeftNumeric(double(*it));
1918 break;
1919 case mdds::mtm::element_string:
1921 typedef MatrixImplType::string_block_type block_type;
1923 block_type::const_iterator it = block_type::begin(*node.data);
1924 block_type::const_iterator itEnd = block_type::end(*node.data);
1925 for (; it != itEnd; ++it)
1927 const svl::SharedString& rStr = *it;
1928 sc::Compare::Cell& rCell = mrComp.maCells[0];
1929 rCell.mbValue = false;
1930 rCell.mbEmpty = false;
1931 rCell.maStr = rStr;
1932 compare();
1935 break;
1936 case mdds::mtm::element_empty:
1937 compareLeftEmpty(node.size);
1938 break;
1939 default:
1944 const std::vector<double>& getValues() const
1946 return maResValues;
1950 class ToDoubleArray
1952 std::vector<double> maArray;
1953 std::vector<double>::iterator miPos;
1954 double mfNaN;
1955 bool mbEmptyAsZero;
1957 void moveArray( ToDoubleArray& r )
1959 // Re-create the iterator from the new array after the array has been
1960 // moved, to ensure that the iterator points to a valid array
1961 // position.
1962 size_t n = std::distance(r.maArray.begin(), r.miPos);
1963 maArray = std::move(r.maArray);
1964 miPos = maArray.begin();
1965 std::advance(miPos, n);
1968 public:
1969 ToDoubleArray( size_t nSize, bool bEmptyAsZero ) :
1970 maArray(nSize, 0.0), miPos(maArray.begin()), mbEmptyAsZero(bEmptyAsZero)
1972 mfNaN = CreateDoubleError( FormulaError::ElementNaN);
1975 ToDoubleArray( const ToDoubleArray& ) = delete;
1976 ToDoubleArray& operator= ( const ToDoubleArray& ) = delete;
1978 ToDoubleArray(ToDoubleArray&& r) noexcept :
1979 mfNaN(r.mfNaN), mbEmptyAsZero(r.mbEmptyAsZero)
1981 moveArray(r);
1984 ToDoubleArray& operator=(ToDoubleArray&& r) noexcept
1986 mfNaN = r.mfNaN;
1987 mbEmptyAsZero = r.mbEmptyAsZero;
1988 moveArray(r);
1989 return *this;
1992 void operator() (const MatrixImplType::element_block_node_type& node)
1994 using namespace mdds::mtv;
1996 switch (node.type)
1998 case mdds::mtm::element_numeric:
2000 double_element_block::const_iterator it = double_element_block::begin(*node.data);
2001 double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
2002 for (; it != itEnd; ++it, ++miPos)
2003 *miPos = *it;
2005 break;
2006 case mdds::mtm::element_boolean:
2008 boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
2009 boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
2010 for (; it != itEnd; ++it, ++miPos)
2011 *miPos = *it ? 1.0 : 0.0;
2013 break;
2014 case mdds::mtm::element_string:
2016 for (size_t i = 0; i < node.size; ++i, ++miPos)
2017 *miPos = mfNaN;
2019 break;
2020 case mdds::mtm::element_empty:
2022 if (mbEmptyAsZero)
2024 std::advance(miPos, node.size);
2025 return;
2028 for (size_t i = 0; i < node.size; ++i, ++miPos)
2029 *miPos = mfNaN;
2031 break;
2032 default:
2037 void swap(std::vector<double>& rOther)
2039 maArray.swap(rOther);
2043 struct ArrayMul
2045 double operator() (const double& lhs, const double& rhs) const
2047 return lhs * rhs;
2051 template<typename Op>
2052 class MergeDoubleArrayFunc
2054 std::vector<double>::iterator miPos;
2055 double mfNaN;
2056 public:
2057 MergeDoubleArrayFunc(std::vector<double>& rArray) : miPos(rArray.begin())
2059 mfNaN = CreateDoubleError( FormulaError::ElementNaN);
2062 MergeDoubleArrayFunc( const MergeDoubleArrayFunc& ) = delete;
2063 MergeDoubleArrayFunc& operator= ( const MergeDoubleArrayFunc& ) = delete;
2065 MergeDoubleArrayFunc( MergeDoubleArrayFunc&& ) = default;
2066 MergeDoubleArrayFunc& operator= ( MergeDoubleArrayFunc&& ) = default;
2068 void operator() (const MatrixImplType::element_block_node_type& node)
2070 using namespace mdds::mtv;
2071 static const Op op;
2073 switch (node.type)
2075 case mdds::mtm::element_numeric:
2077 double_element_block::const_iterator it = double_element_block::begin(*node.data);
2078 double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
2079 for (; it != itEnd; ++it, ++miPos)
2081 if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2082 continue;
2084 *miPos = op(*miPos, *it);
2087 break;
2088 case mdds::mtm::element_boolean:
2090 boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
2091 boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
2092 for (; it != itEnd; ++it, ++miPos)
2094 if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2095 continue;
2097 *miPos = op(*miPos, *it ? 1.0 : 0.0);
2100 break;
2101 case mdds::mtm::element_string:
2103 for (size_t i = 0; i < node.size; ++i, ++miPos)
2104 *miPos = mfNaN;
2106 break;
2107 case mdds::mtm::element_empty:
2109 // Empty element is equivalent of having a numeric value of 0.0.
2110 for (size_t i = 0; i < node.size; ++i, ++miPos)
2112 if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2113 continue;
2115 *miPos = op(*miPos, 0.0);
2118 break;
2119 default:
2127 namespace {
2129 template<typename TOp, typename tRes>
2130 ScMatrix::IterateResult<tRes> GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorValues, const MatrixImplType& maMat)
2132 WalkElementBlocks<TOp, tRes> aFunc(bTextAsZero, bIgnoreErrorValues);
2133 aFunc = maMat.walk(aFunc);
2134 return aFunc.getResult();
2139 ScMatrix::KahanIterateResult ScMatrixImpl::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
2141 return GetValueWithCount<sc::op::Sum, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2144 ScMatrix::KahanIterateResult ScMatrixImpl::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
2146 return GetValueWithCount<sc::op::SumSquare, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2149 ScMatrix::DoubleIterateResult ScMatrixImpl::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
2151 return GetValueWithCount<sc::op::Product, double>(bTextAsZero, bIgnoreErrorValues, maMat);
2154 size_t ScMatrixImpl::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
2156 CountElements aFunc(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
2157 aFunc = maMat.walk(aFunc);
2158 return aFunc.getCount();
2161 size_t ScMatrixImpl::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
2163 WalkAndMatchElements<double> aFunc(fValue, maMat.size(), nCol1, nCol2);
2164 aFunc = maMat.walk(aFunc);
2165 return aFunc.getMatching();
2168 size_t ScMatrixImpl::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
2170 WalkAndMatchElements<svl::SharedString> aFunc(rStr, maMat.size(), nCol1, nCol2);
2171 aFunc = maMat.walk(aFunc);
2172 return aFunc.getMatching();
2175 double ScMatrixImpl::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2177 CalcMaxMinValue<MaxOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2178 aFunc = maMat.walk(aFunc);
2179 return aFunc.getValue();
2182 double ScMatrixImpl::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2184 CalcMaxMinValue<MinOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2185 aFunc = maMat.walk(aFunc);
2186 return aFunc.getValue();
2189 double ScMatrixImpl::GetGcd() const
2191 CalcGcdLcm<Gcd> aFunc;
2192 aFunc = maMat.walk(aFunc);
2193 return aFunc.getResult();
2196 double ScMatrixImpl::GetLcm() const
2198 CalcGcdLcm<Lcm> aFunc;
2199 aFunc = maMat.walk(aFunc);
2200 return aFunc.getResult();
2203 ScMatrixRef ScMatrixImpl::CompareMatrix(
2204 sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
2206 MatrixImplType::size_pair_type aSize = maMat.size();
2207 size_t nSize = aSize.column * aSize.row;
2208 if (nMatPos == 0)
2210 if (rComp.maCells[1].mbValue && !rComp.maCells[1].mbEmpty)
2212 // Matrix on the left, and a numeric value on the right. Use a
2213 // function object that has much less branching for much better
2214 // performance.
2215 CompareMatrixToNumericFunc aFunc(nSize, rComp, rComp.maCells[1].mfValue, pOptions);
2216 aFunc = maMat.walk(std::move(aFunc));
2218 // We assume the result matrix has the same dimension as this matrix.
2219 const std::vector<double>& rResVal = aFunc.getValues();
2220 assert (nSize == rResVal.size());
2221 if (nSize != rResVal.size())
2222 return ScMatrixRef();
2224 return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2228 CompareMatrixFunc aFunc(nSize, rComp, nMatPos, pOptions);
2229 aFunc = maMat.walk(std::move(aFunc));
2231 // We assume the result matrix has the same dimension as this matrix.
2232 const std::vector<double>& rResVal = aFunc.getValues();
2233 assert (nSize == rResVal.size());
2234 if (nSize != rResVal.size())
2235 return ScMatrixRef();
2237 return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2240 void ScMatrixImpl::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
2242 MatrixImplType::size_pair_type aSize = maMat.size();
2243 ToDoubleArray aFunc(aSize.row*aSize.column, bEmptyAsZero);
2244 aFunc = maMat.walk(std::move(aFunc));
2245 aFunc.swap(rArray);
2248 void ScMatrixImpl::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
2250 MatrixImplType::size_pair_type aSize = maMat.size();
2251 size_t nSize = aSize.row*aSize.column;
2252 if (nSize != rArray.size())
2253 return;
2255 MergeDoubleArrayFunc<ArrayMul> aFunc(rArray);
2256 maMat.walk(std::move(aFunc));
2259 namespace {
2261 template<typename T, typename U, typename return_type>
2262 struct wrapped_iterator
2264 typedef ::std::bidirectional_iterator_tag iterator_category;
2265 typedef typename T::const_iterator::value_type old_value_type;
2266 typedef return_type value_type;
2267 typedef value_type* pointer;
2268 typedef value_type& reference;
2269 typedef typename T::const_iterator::difference_type difference_type;
2271 typename T::const_iterator it;
2272 mutable value_type val;
2273 U maOp;
2275 private:
2277 value_type calcVal() const
2279 return maOp(*it);
2282 public:
2284 wrapped_iterator(typename T::const_iterator it_, U const & aOp):
2285 it(std::move(it_)),
2286 val(value_type()),
2287 maOp(aOp)
2291 wrapped_iterator(const wrapped_iterator& r):
2292 it(r.it),
2293 val(r.val),
2294 maOp(r.maOp)
2298 wrapped_iterator& operator=(const wrapped_iterator& r)
2300 it = r.it;
2301 return *this;
2304 bool operator==(const wrapped_iterator& r) const
2306 return it == r.it;
2309 bool operator!=(const wrapped_iterator& r) const
2311 return !operator==(r);
2314 wrapped_iterator& operator++()
2316 ++it;
2318 return *this;
2321 wrapped_iterator& operator--()
2323 --it;
2325 return *this;
2328 value_type& operator*() const
2330 val = calcVal();
2331 return val;
2334 pointer operator->() const
2336 val = calcVal();
2337 return &val;
2341 template<typename T, typename U, typename return_type>
2342 struct MatrixIteratorWrapper
2344 private:
2345 typename T::const_iterator m_itBegin;
2346 typename T::const_iterator m_itEnd;
2347 U maOp;
2348 public:
2349 MatrixIteratorWrapper(typename T::const_iterator itBegin, typename T::const_iterator itEnd, U const & aOp):
2350 m_itBegin(std::move(itBegin)),
2351 m_itEnd(std::move(itEnd)),
2352 maOp(aOp)
2356 wrapped_iterator<T, U, return_type> begin()
2358 return wrapped_iterator<T, U, return_type>(m_itBegin, maOp);
2361 wrapped_iterator<T, U, return_type> end()
2363 return wrapped_iterator<T, U, return_type>(m_itEnd, maOp);
2367 MatrixImplType::position_type increment_position(const MatrixImplType::position_type& pos, size_t n)
2369 MatrixImplType::position_type ret = pos;
2372 if (ret.second + n < ret.first->size)
2374 ret.second += n;
2375 break;
2377 else
2379 n -= (ret.first->size - ret.second);
2380 ++ret.first;
2381 ret.second = 0;
2384 while (n > 0);
2385 return ret;
2388 template<typename T>
2389 struct MatrixOpWrapper
2391 private:
2392 MatrixImplType& mrMat;
2393 MatrixImplType::position_type pos;
2394 const T* mpOp;
2396 public:
2397 MatrixOpWrapper(MatrixImplType& rMat, const T& aOp):
2398 mrMat(rMat),
2399 pos(rMat.position(0,0)),
2400 mpOp(&aOp)
2404 MatrixOpWrapper( const MatrixOpWrapper& r ) : mrMat(r.mrMat), pos(r.pos), mpOp(r.mpOp) {}
2406 MatrixOpWrapper& operator= ( const MatrixOpWrapper& r ) = default;
2408 void operator()(const MatrixImplType::element_block_node_type& node)
2410 switch (node.type)
2412 case mdds::mtm::element_numeric:
2414 typedef MatrixImplType::numeric_block_type block_type;
2416 block_type::const_iterator it = block_type::begin(*node.data);
2417 block_type::const_iterator itEnd = block_type::end(*node.data);
2418 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2419 pos = mrMat.set(pos,aFunc.begin(), aFunc.end());
2421 break;
2422 case mdds::mtm::element_boolean:
2424 typedef MatrixImplType::boolean_block_type block_type;
2426 block_type::const_iterator it = block_type::begin(*node.data);
2427 block_type::const_iterator itEnd = block_type::end(*node.data);
2429 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2430 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2432 break;
2433 case mdds::mtm::element_string:
2435 typedef MatrixImplType::string_block_type block_type;
2437 block_type::const_iterator it = block_type::begin(*node.data);
2438 block_type::const_iterator itEnd = block_type::end(*node.data);
2440 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2441 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2443 break;
2444 case mdds::mtm::element_empty:
2446 if (mpOp->useFunctionForEmpty())
2448 std::vector<char> aVec(node.size);
2449 MatrixIteratorWrapper<std::vector<char>, T, typename T::number_value_type>
2450 aFunc(aVec.begin(), aVec.end(), *mpOp);
2451 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2454 break;
2455 default:
2458 pos = increment_position(pos, node.size);
2464 template<typename T>
2465 void ScMatrixImpl::ApplyOperation(T aOp, ScMatrixImpl& rMat)
2467 MatrixOpWrapper<T> aFunc(rMat.maMat, aOp);
2468 maMat.walk(aFunc);
2471 template<typename T, typename tRes>
2472 ScMatrix::IterateResultMultiple<tRes> ScMatrixImpl::ApplyCollectOperation(const std::vector<T>& aOp)
2474 WalkElementBlocksMultipleValues<T, tRes> aFunc(aOp);
2475 aFunc = maMat.walk(std::move(aFunc));
2476 return aFunc.getResult();
2479 namespace {
2481 struct ElementBlock
2483 ElementBlock(size_t nRowSize,
2484 ScMatrix::DoubleOpFunction aDoubleFunc,
2485 ScMatrix::BoolOpFunction aBoolFunc,
2486 ScMatrix::StringOpFunction aStringFunc,
2487 ScMatrix::EmptyOpFunction aEmptyFunc):
2488 mnRowSize(nRowSize),
2489 mnRowPos(0),
2490 mnColPos(0),
2491 maDoubleFunc(std::move(aDoubleFunc)),
2492 maBoolFunc(std::move(aBoolFunc)),
2493 maStringFunc(std::move(aStringFunc)),
2494 maEmptyFunc(std::move(aEmptyFunc))
2498 size_t mnRowSize;
2499 size_t mnRowPos;
2500 size_t mnColPos;
2502 ScMatrix::DoubleOpFunction maDoubleFunc;
2503 ScMatrix::BoolOpFunction maBoolFunc;
2504 ScMatrix::StringOpFunction maStringFunc;
2505 ScMatrix::EmptyOpFunction maEmptyFunc;
2508 class WalkElementBlockOperation
2510 public:
2512 WalkElementBlockOperation(ElementBlock& rElementBlock)
2513 : mrElementBlock(rElementBlock)
2517 void operator()(const MatrixImplType::element_block_node_type& node)
2519 switch (node.type)
2521 case mdds::mtm::element_numeric:
2523 typedef MatrixImplType::numeric_block_type block_type;
2525 block_type::const_iterator it = block_type::begin(*node.data);
2526 std::advance(it, node.offset);
2527 block_type::const_iterator itEnd = it;
2528 std::advance(itEnd, node.size);
2529 for (auto itr = it; itr != itEnd; ++itr)
2531 mrElementBlock.maDoubleFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2532 ++mrElementBlock.mnRowPos;
2533 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2535 mrElementBlock.mnRowPos = 0;
2536 ++mrElementBlock.mnColPos;
2540 break;
2541 case mdds::mtm::element_string:
2543 typedef MatrixImplType::string_block_type block_type;
2545 block_type::const_iterator it = block_type::begin(*node.data);
2546 std::advance(it, node.offset);
2547 block_type::const_iterator itEnd = it;
2548 std::advance(itEnd, node.size);
2549 for (auto itr = it; itr != itEnd; ++itr)
2551 mrElementBlock.maStringFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2552 ++mrElementBlock.mnRowPos;
2553 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2555 mrElementBlock.mnRowPos = 0;
2556 ++mrElementBlock.mnColPos;
2560 break;
2561 case mdds::mtm::element_boolean:
2563 typedef MatrixImplType::boolean_block_type block_type;
2565 block_type::const_iterator it = block_type::begin(*node.data);
2566 std::advance(it, node.offset);
2567 block_type::const_iterator itEnd = it;
2568 std::advance(itEnd, node.size);
2569 for (auto itr = it; itr != itEnd; ++itr)
2571 mrElementBlock.maBoolFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2572 ++mrElementBlock.mnRowPos;
2573 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2575 mrElementBlock.mnRowPos = 0;
2576 ++mrElementBlock.mnColPos;
2580 break;
2581 case mdds::mtm::element_empty:
2583 for (size_t i=0; i < node.size; ++i)
2585 mrElementBlock.maEmptyFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos);
2586 ++mrElementBlock.mnRowPos;
2587 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2589 mrElementBlock.mnRowPos = 0;
2590 ++mrElementBlock.mnColPos;
2594 break;
2595 case mdds::mtm::element_integer:
2597 SAL_WARN("sc.core","WalkElementBlockOperation - unhandled element_integer");
2598 // No function (yet?), but advance row and column count.
2599 mrElementBlock.mnColPos += node.size / mrElementBlock.mnRowSize;
2600 mrElementBlock.mnRowPos += node.size % mrElementBlock.mnRowSize;
2601 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2603 mrElementBlock.mnRowPos = 0;
2604 ++mrElementBlock.mnColPos;
2607 break;
2611 private:
2613 ElementBlock& mrElementBlock;
2618 void ScMatrixImpl::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
2619 const std::pair<size_t, size_t>& rEndPos, const ScMatrix::DoubleOpFunction& aDoubleFunc,
2620 const ScMatrix::BoolOpFunction& aBoolFunc, const ScMatrix::StringOpFunction& aStringFunc,
2621 const ScMatrix::EmptyOpFunction& aEmptyFunc) const
2623 ElementBlock aPayload(maMat.size().row, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2624 WalkElementBlockOperation aFunc(aPayload);
2625 maMat.walk(
2626 aFunc,
2627 MatrixImplType::size_pair_type(rStartPos.first, rStartPos.second),
2628 MatrixImplType::size_pair_type(rEndPos.first, rEndPos.second));
2631 #if DEBUG_MATRIX
2633 void ScMatrixImpl::Dump() const
2635 cout << "-- matrix content" << endl;
2636 SCSIZE nCols, nRows;
2637 GetDimensions(nCols, nRows);
2638 for (SCSIZE nRow = 0; nRow < nRows; ++nRow)
2640 for (SCSIZE nCol = 0; nCol < nCols; ++nCol)
2642 cout << " row=" << nRow << ", col=" << nCol << " : ";
2643 switch (maMat.get_type(nRow, nCol))
2645 case mdds::mtm::element_string:
2646 cout << "string (" << maMat.get_string(nRow, nCol).getString() << ")";
2647 break;
2648 case mdds::mtm::element_numeric:
2649 cout << "numeric (" << maMat.get_numeric(nRow, nCol) << ")";
2650 break;
2651 case mdds::mtm::element_boolean:
2652 cout << "boolean (" << maMat.get_boolean(nRow, nCol) << ")";
2653 break;
2654 case mdds::mtm::element_empty:
2655 cout << "empty";
2656 break;
2657 default:
2661 cout << endl;
2665 #endif
2667 void ScMatrixImpl::CalcPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const
2669 SCSIZE nRowSize = maMat.size().row;
2670 SAL_WARN_IF( !nRowSize, "sc.core", "ScMatrixImpl::CalcPosition: 0 rows!");
2671 rC = nRowSize > 1 ? nIndex / nRowSize : nIndex;
2672 rR = nIndex - rC*nRowSize;
2675 void ScMatrixImpl::CalcTransPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const
2677 SCSIZE nColSize = maMat.size().column;
2678 SAL_WARN_IF(!nColSize, "sc.core", "ScMatrixImpl::CalcPosition: 0 cols!");
2679 rR = nColSize > 1 ? nIndex / nColSize : nIndex;
2680 rC = nIndex - rR * nColSize;
2683 namespace {
2685 size_t get_index(SCSIZE nMaxRow, size_t nRow, size_t nCol, size_t nRowOffset, size_t nColOffset)
2687 return nMaxRow * (nCol + nColOffset) + nRow + nRowOffset;
2692 void ScMatrixImpl::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
2693 ScInterpreterContext& rContext, svl::SharedStringPool& rStringPool)
2695 SCSIZE nC1, nC2;
2696 SCSIZE nR1, nR2;
2697 xMat1->GetDimensions(nC1, nR1);
2698 xMat2->GetDimensions(nC2, nR2);
2700 sal_uInt32 nKey = rContext.NFGetStandardFormat( SvNumFormatType::NUMBER,
2701 ScGlobal::eLnge);
2703 std::vector<OUString> aString(nMaxCol * nMaxRow);
2704 std::vector<bool> aValid(nMaxCol * nMaxRow, true);
2705 std::vector<FormulaError> nErrors(nMaxCol * nMaxRow,FormulaError::NONE);
2707 size_t nRowOffset = 0;
2708 size_t nColOffset = 0;
2709 std::function<void(size_t, size_t, double)> aDoubleFunc =
2710 [&](size_t nRow, size_t nCol, double nVal)
2712 FormulaError nErr = GetDoubleErrorValue(nVal);
2713 if (nErr != FormulaError::NONE)
2715 aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2716 nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2717 return;
2719 OUString aStr = rContext.NFGetInputLineString( nVal, nKey );
2720 aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2723 std::function<void(size_t, size_t, bool)> aBoolFunc =
2724 [&](size_t nRow, size_t nCol, bool nVal)
2726 OUString aStr = rContext.NFGetInputLineString( nVal ? 1.0 : 0.0, nKey);
2727 aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2730 std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc =
2731 [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2733 aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString();
2736 std::function<void(size_t, size_t)> aEmptyFunc =
2737 [](size_t /*nRow*/, size_t /*nCol*/)
2739 // Nothing. Concatenating an empty string to an existing string.
2743 if (nC1 == 1 || nR1 == 1)
2745 size_t nRowRep = nR1 == 1 ? nMaxRow : 1;
2746 size_t nColRep = nC1 == 1 ? nMaxCol : 1;
2748 for (size_t i = 0; i < nRowRep; ++i)
2750 nRowOffset = i;
2751 for (size_t j = 0; j < nColRep; ++j)
2753 nColOffset = j;
2754 xMat1->ExecuteOperation(
2755 std::pair<size_t, size_t>(0, 0),
2756 std::pair<size_t, size_t>(std::min(nR1, nMaxRow) - 1, std::min(nC1, nMaxCol) - 1),
2757 aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2761 else
2762 xMat1->ExecuteOperation(
2763 std::pair<size_t, size_t>(0, 0),
2764 std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2765 std::move(aDoubleFunc), std::move(aBoolFunc), std::move(aStringFunc), std::move(aEmptyFunc));
2767 std::vector<svl::SharedString> aSharedString(nMaxCol*nMaxRow);
2769 std::function<void(size_t, size_t, double)> aDoubleFunc2 =
2770 [&](size_t nRow, size_t nCol, double nVal)
2772 FormulaError nErr = GetDoubleErrorValue(nVal);
2773 if (nErr != FormulaError::NONE)
2775 aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2776 nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2777 return;
2779 OUString aStr = rContext.NFGetInputLineString( nVal, nKey );
2780 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2783 std::function<void(size_t, size_t, bool)> aBoolFunc2 =
2784 [&](size_t nRow, size_t nCol, bool nVal)
2786 OUString aStr = rContext.NFGetInputLineString( nVal ? 1.0 : 0.0, nKey);
2787 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2790 std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc2 =
2791 [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2793 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2794 rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString());
2797 std::function<void(size_t, size_t)> aEmptyFunc2 =
2798 [&](size_t nRow, size_t nCol)
2800 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2801 rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)]);
2804 nRowOffset = 0;
2805 nColOffset = 0;
2806 if (nC2 == 1 || nR2 == 1)
2808 size_t nRowRep = nR2 == 1 ? nMaxRow : 1;
2809 size_t nColRep = nC2 == 1 ? nMaxCol : 1;
2811 for (size_t i = 0; i < nRowRep; ++i)
2813 nRowOffset = i;
2814 for (size_t j = 0; j < nColRep; ++j)
2816 nColOffset = j;
2817 xMat2->ExecuteOperation(
2818 std::pair<size_t, size_t>(0, 0),
2819 std::pair<size_t, size_t>(std::min(nR2, nMaxRow) - 1, std::min(nC2, nMaxCol) - 1),
2820 aDoubleFunc2, aBoolFunc2, aStringFunc2, aEmptyFunc2);
2824 else
2825 xMat2->ExecuteOperation(
2826 std::pair<size_t, size_t>(0, 0),
2827 std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2828 std::move(aDoubleFunc2), std::move(aBoolFunc2), std::move(aStringFunc2), std::move(aEmptyFunc2));
2830 aString.clear();
2832 MatrixImplType::position_type pos = maMat.position(0, 0);
2833 for (SCSIZE i = 0; i < nMaxCol; ++i)
2835 for (SCSIZE j = 0; j < nMaxRow && i < nMaxCol; ++j)
2837 if (aValid[nMaxRow * i + j])
2839 auto itr = aValid.begin();
2840 std::advance(itr, nMaxRow * i + j);
2841 auto itrEnd = std::find(itr, aValid.end(), false);
2842 size_t nSteps = std::distance(itr, itrEnd);
2843 auto itrStr = aSharedString.begin();
2844 std::advance(itrStr, nMaxRow * i + j);
2845 auto itrEndStr = itrStr;
2846 std::advance(itrEndStr, nSteps);
2847 pos = maMat.set(pos, itrStr, itrEndStr);
2848 size_t nColSteps = nSteps / nMaxRow;
2849 i += nColSteps;
2850 j += nSteps % nMaxRow;
2851 if (j >= nMaxRow)
2853 j -= nMaxRow;
2854 ++i;
2857 else
2859 pos = maMat.set(pos, CreateDoubleError(nErrors[nMaxRow * i + j]));
2861 pos = MatrixImplType::next_position(pos);
2866 bool ScMatrixImpl::IsValueOrEmpty( const MatrixImplType::const_position_type & rPos ) const
2868 switch (maMat.get_type(rPos))
2870 case mdds::mtm::element_boolean:
2871 case mdds::mtm::element_numeric:
2872 case mdds::mtm::element_empty:
2873 return true;
2874 default:
2877 return false;
2880 double ScMatrixImpl::GetDouble(const MatrixImplType::const_position_type & rPos) const
2882 double fVal = maMat.get_numeric(rPos);
2883 if ( pErrorInterpreter )
2885 FormulaError nError = GetDoubleErrorValue(fVal);
2886 if ( nError != FormulaError::NONE )
2887 SetErrorAtInterpreter( nError);
2889 return fVal;
2892 FormulaError ScMatrixImpl::GetErrorIfNotString( const MatrixImplType::const_position_type & rPos ) const
2893 { return IsValue(rPos) ? GetError(rPos) : FormulaError::NONE; }
2895 bool ScMatrixImpl::IsValue( const MatrixImplType::const_position_type & rPos ) const
2897 switch (maMat.get_type(rPos))
2899 case mdds::mtm::element_boolean:
2900 case mdds::mtm::element_numeric:
2901 return true;
2902 default:
2905 return false;
2908 FormulaError ScMatrixImpl::GetError(const MatrixImplType::const_position_type & rPos) const
2910 double fVal = maMat.get_numeric(rPos);
2911 return GetDoubleErrorValue(fVal);
2914 bool ScMatrixImpl::IsStringOrEmpty(const MatrixImplType::const_position_type & rPos) const
2916 switch (maMat.get_type(rPos))
2918 case mdds::mtm::element_empty:
2919 case mdds::mtm::element_string:
2920 return true;
2921 default:
2924 return false;
2927 void ScMatrixImpl::ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
2928 ScInterpreter* pInterpreter, const ScMatrix::CalculateOpFunction& Op)
2930 // Check output matrix size, otherwise output iterator logic will be wrong.
2931 assert(maMat.size().row == nMaxRow && maMat.size().column == nMaxCol
2932 && "the caller code should have sized the output matrix to the passed dimensions");
2933 auto & rMatImpl1 = *rInputMat1.pImpl;
2934 auto & rMatImpl2 = *rInputMat2.pImpl;
2935 // Check if we can do fast-path, where we have no replication or mis-matched matrix sizes.
2936 if (rMatImpl1.maMat.size() == rMatImpl2.maMat.size()
2937 && rMatImpl1.maMat.size() == maMat.size())
2939 MatrixImplType::position_type aOutPos = maMat.position(0, 0);
2940 MatrixImplType::const_position_type aPos1 = rMatImpl1.maMat.position(0, 0);
2941 MatrixImplType::const_position_type aPos2 = rMatImpl2.maMat.position(0, 0);
2942 for (SCSIZE i = 0; i < nMaxCol; i++)
2944 for (SCSIZE j = 0; j < nMaxRow; j++)
2946 bool bVal1 = rMatImpl1.IsValueOrEmpty(aPos1);
2947 bool bVal2 = rMatImpl2.IsValueOrEmpty(aPos2);
2948 FormulaError nErr;
2949 if (bVal1 && bVal2)
2951 double d = Op(rMatImpl1.GetDouble(aPos1), rMatImpl2.GetDouble(aPos2));
2952 aOutPos = maMat.set(aOutPos, d);
2954 else if (((nErr = rMatImpl1.GetErrorIfNotString(aPos1)) != FormulaError::NONE) ||
2955 ((nErr = rMatImpl2.GetErrorIfNotString(aPos2)) != FormulaError::NONE))
2957 aOutPos = maMat.set(aOutPos, CreateDoubleError(nErr));
2959 else if ((!bVal1 && rMatImpl1.IsStringOrEmpty(aPos1)) ||
2960 (!bVal2 && rMatImpl2.IsStringOrEmpty(aPos2)))
2962 FormulaError nError1 = FormulaError::NONE;
2963 SvNumFormatType nFmt1 = SvNumFormatType::ALL;
2964 double fVal1 = (bVal1 ? rMatImpl1.GetDouble(aPos1) :
2965 pInterpreter->ConvertStringToValue( rMatImpl1.GetString(aPos1).getString(), nError1, nFmt1));
2967 FormulaError nError2 = FormulaError::NONE;
2968 SvNumFormatType nFmt2 = SvNumFormatType::ALL;
2969 double fVal2 = (bVal2 ? rMatImpl2.GetDouble(aPos2) :
2970 pInterpreter->ConvertStringToValue( rMatImpl2.GetString(aPos2).getString(), nError2, nFmt2));
2972 if (nError1 != FormulaError::NONE)
2973 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError1));
2974 else if (nError2 != FormulaError::NONE)
2975 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError2));
2976 else
2978 double d = Op( fVal1, fVal2);
2979 aOutPos = maMat.set(aOutPos, d);
2982 else
2983 aOutPos = maMat.set(aOutPos, CreateDoubleError(FormulaError::NoValue));
2984 aPos1 = MatrixImplType::next_position(aPos1);
2985 aPos2 = MatrixImplType::next_position(aPos2);
2986 aOutPos = MatrixImplType::next_position(aOutPos);
2990 else
2992 // Noting that this block is very hard to optimise to use iterators, because various dodgy
2993 // array function usage relies on the semantics of some of the methods we call here.
2994 // (see unit test testDubiousArrayFormulasFODS).
2995 // These methods are inconsistent in their usage of ValidColRowReplicated() vs. ValidColRowOrReplicated()
2996 // which leads to some very odd results.
2997 MatrixImplType::position_type aOutPos = maMat.position(0, 0);
2998 for (SCSIZE i = 0; i < nMaxCol; i++)
3000 for (SCSIZE j = 0; j < nMaxRow; j++)
3002 bool bVal1 = rInputMat1.IsValueOrEmpty(i,j);
3003 bool bVal2 = rInputMat2.IsValueOrEmpty(i,j);
3004 FormulaError nErr;
3005 if (bVal1 && bVal2)
3007 double d = Op(rInputMat1.GetDouble(i,j), rInputMat2.GetDouble(i,j));
3008 aOutPos = maMat.set(aOutPos, d);
3010 else if (((nErr = rInputMat1.GetErrorIfNotString(i,j)) != FormulaError::NONE) ||
3011 ((nErr = rInputMat2.GetErrorIfNotString(i,j)) != FormulaError::NONE))
3013 aOutPos = maMat.set(aOutPos, CreateDoubleError(nErr));
3015 else if ((!bVal1 && rInputMat1.IsStringOrEmpty(i,j)) || (!bVal2 && rInputMat2.IsStringOrEmpty(i,j)))
3017 FormulaError nError1 = FormulaError::NONE;
3018 SvNumFormatType nFmt1 = SvNumFormatType::ALL;
3019 double fVal1 = (bVal1 ? rInputMat1.GetDouble(i,j) :
3020 pInterpreter->ConvertStringToValue( rInputMat1.GetString(i,j).getString(), nError1, nFmt1));
3022 FormulaError nError2 = FormulaError::NONE;
3023 SvNumFormatType nFmt2 = SvNumFormatType::ALL;
3024 double fVal2 = (bVal2 ? rInputMat2.GetDouble(i,j) :
3025 pInterpreter->ConvertStringToValue( rInputMat2.GetString(i,j).getString(), nError2, nFmt2));
3027 if (nError1 != FormulaError::NONE)
3028 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError1));
3029 else if (nError2 != FormulaError::NONE)
3030 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError2));
3031 else
3033 double d = Op( fVal1, fVal2);
3034 aOutPos = maMat.set(aOutPos, d);
3037 else
3038 aOutPos = maMat.set(aOutPos, CreateDoubleError(FormulaError::NoValue));
3039 aOutPos = MatrixImplType::next_position(aOutPos);
3045 void ScMatrix::IncRef() const
3047 ++nRefCnt;
3050 void ScMatrix::DecRef() const
3052 --nRefCnt;
3053 if (nRefCnt == 0)
3054 delete this;
3057 bool ScMatrix::IsSizeAllocatable( SCSIZE nC, SCSIZE nR )
3059 SAL_WARN_IF( !nC, "sc.core", "ScMatrix with 0 columns!");
3060 SAL_WARN_IF( !nR, "sc.core", "ScMatrix with 0 rows!");
3061 // 0-size matrix is valid, it could be resized later.
3062 if ((nC && !nR) || (!nC && nR))
3064 SAL_WARN( "sc.core", "ScMatrix one-dimensional zero: " << nC << " columns * " << nR << " rows");
3065 return false;
3067 if (!nC || !nR)
3068 return true;
3070 std::call_once(bElementsMaxFetched,
3071 []()
3073 const char* pEnv = std::getenv("SC_MAX_MATRIX_ELEMENTS");
3074 if (pEnv)
3076 // Environment specifies the overall elements pool.
3077 nElementsMax = std::atoi(pEnv);
3079 else
3081 // GetElementsMax() uses an (~arbitrary) elements limit.
3082 // The actual allocation depends on the types of individual matrix
3083 // elements and is averaged for type double.
3084 #if SAL_TYPES_SIZEOFPOINTER < 8
3085 // Assume 1GB memory could be consumed by matrices.
3086 constexpr size_t nMemMax = 0x40000000;
3087 #else
3088 // Assume 6GB memory could be consumed by matrices.
3089 constexpr size_t nMemMax = 0x180000000;
3090 #endif
3091 nElementsMax = GetElementsMax( nMemMax);
3095 if (nC > (nElementsMax / nR))
3097 SAL_WARN( "sc.core", "ScMatrix overflow: " << nC << " columns * " << nR << " rows");
3098 return false;
3100 return true;
3103 ScMatrix::ScMatrix( SCSIZE nC, SCSIZE nR) :
3104 nRefCnt(0), mbCloneIfConst(true)
3106 if (ScMatrix::IsSizeAllocatable( nC, nR))
3107 pImpl.reset( new ScMatrixImpl( nC, nR));
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(SCSIZE nC, SCSIZE nR, double fInitVal) :
3114 nRefCnt(0), mbCloneIfConst(true)
3116 if (ScMatrix::IsSizeAllocatable( nC, nR))
3117 pImpl.reset( new ScMatrixImpl( nC, nR, fInitVal));
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( size_t nC, size_t nR, const std::vector<double>& rInitVals ) :
3124 nRefCnt(0), mbCloneIfConst(true)
3126 if (ScMatrix::IsSizeAllocatable( nC, nR))
3127 pImpl.reset( new ScMatrixImpl( nC, nR, rInitVals));
3128 else
3129 // Invalid matrix size, allocate 1x1 matrix with error value.
3130 pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
3133 ScMatrix::~ScMatrix()
3137 ScMatrix* ScMatrix::Clone() const
3139 SCSIZE nC, nR;
3140 pImpl->GetDimensions(nC, nR);
3141 ScMatrix* pScMat = new ScMatrix(nC, nR);
3142 MatCopy(*pScMat);
3143 pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter()); // TODO: really?
3144 return pScMat;
3147 ScMatrix* ScMatrix::CloneIfConst()
3149 return mbCloneIfConst ? Clone() : this;
3152 void ScMatrix::SetMutable()
3154 mbCloneIfConst = false;
3157 void ScMatrix::SetImmutable() const
3159 mbCloneIfConst = true;
3162 void ScMatrix::Resize( SCSIZE nC, SCSIZE nR)
3164 pImpl->Resize(nC, nR);
3167 void ScMatrix::Resize(SCSIZE nC, SCSIZE nR, double fVal)
3169 pImpl->Resize(nC, nR, fVal);
3172 ScMatrix* ScMatrix::CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const
3174 ScMatrix* pScMat = new ScMatrix(nNewCols, nNewRows);
3175 MatCopy(*pScMat);
3176 pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter());
3177 return pScMat;
3180 void ScMatrix::SetErrorInterpreter( ScInterpreter* p)
3182 pImpl->SetErrorInterpreter(p);
3185 void ScMatrix::GetDimensions( SCSIZE& rC, SCSIZE& rR) const
3187 pImpl->GetDimensions(rC, rR);
3190 SCSIZE ScMatrix::GetElementCount() const
3192 return pImpl->GetElementCount();
3195 bool ScMatrix::ValidColRow( SCSIZE nC, SCSIZE nR) const
3197 return pImpl->ValidColRow(nC, nR);
3200 bool ScMatrix::ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const
3202 return pImpl->ValidColRowReplicated(rC, rR);
3205 bool ScMatrix::ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const
3207 return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
3210 void ScMatrix::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
3212 pImpl->PutDouble(fVal, nC, nR);
3215 void ScMatrix::PutDouble( double fVal, SCSIZE nIndex)
3217 pImpl->PutDouble(fVal, nIndex);
3220 void ScMatrix::PutDoubleTrans(double fVal, SCSIZE nIndex)
3222 pImpl->PutDoubleTrans(fVal, nIndex);
3225 void ScMatrix::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3227 pImpl->PutDouble(pArray, nLen, nC, nR);
3230 void ScMatrix::PutString(const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR)
3232 pImpl->PutString(rStr, nC, nR);
3235 void ScMatrix::PutString(const svl::SharedString& rStr, SCSIZE nIndex)
3237 pImpl->PutString(rStr, nIndex);
3240 void ScMatrix::PutStringTrans(const svl::SharedString& rStr, SCSIZE nIndex)
3242 pImpl->PutStringTrans(rStr, nIndex);
3245 void ScMatrix::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3247 pImpl->PutString(pArray, nLen, nC, nR);
3250 void ScMatrix::PutEmpty(SCSIZE nC, SCSIZE nR)
3252 pImpl->PutEmpty(nC, nR);
3255 void ScMatrix::PutEmpty(SCSIZE nIndex)
3257 pImpl->PutEmpty(nIndex);
3260 void ScMatrix::PutEmptyTrans(SCSIZE nIndex)
3262 pImpl->PutEmptyTrans(nIndex);
3265 void ScMatrix::PutEmptyPath(SCSIZE nC, SCSIZE nR)
3267 pImpl->PutEmptyPath(nC, nR);
3270 void ScMatrix::PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR )
3272 pImpl->PutError(nErrorCode, nC, nR);
3275 void ScMatrix::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
3277 pImpl->PutBoolean(bVal, nC, nR);
3280 FormulaError ScMatrix::GetError( SCSIZE nC, SCSIZE nR) const
3282 return pImpl->GetError(nC, nR);
3285 double ScMatrix::GetDouble(SCSIZE nC, SCSIZE nR) const
3287 return pImpl->GetDouble(nC, nR);
3290 double ScMatrix::GetDouble( SCSIZE nIndex) const
3292 return pImpl->GetDouble(nIndex);
3295 double ScMatrix::GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
3297 return pImpl->GetDoubleWithStringConversion(nC, nR);
3300 svl::SharedString ScMatrix::GetString(SCSIZE nC, SCSIZE nR) const
3302 return pImpl->GetString(nC, nR);
3305 svl::SharedString ScMatrix::GetString( SCSIZE nIndex) const
3307 return pImpl->GetString(nIndex);
3310 svl::SharedString ScMatrix::GetString( ScInterpreterContext& rContext, SCSIZE nC, SCSIZE nR) const
3312 return pImpl->GetString(rContext, nC, nR);
3315 ScMatrixValue ScMatrix::Get(SCSIZE nC, SCSIZE nR) const
3317 return pImpl->Get(nC, nR);
3320 bool ScMatrix::IsStringOrEmpty( SCSIZE nIndex ) const
3322 return pImpl->IsStringOrEmpty(nIndex);
3325 bool ScMatrix::IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const
3327 return pImpl->IsStringOrEmpty(nC, nR);
3330 bool ScMatrix::IsEmpty( SCSIZE nC, SCSIZE nR ) const
3332 return pImpl->IsEmpty(nC, nR);
3335 bool ScMatrix::IsEmptyCell( SCSIZE nC, SCSIZE nR ) const
3337 return pImpl->IsEmptyCell(nC, nR);
3340 bool ScMatrix::IsEmptyResult( SCSIZE nC, SCSIZE nR ) const
3342 return pImpl->IsEmptyResult(nC, nR);
3345 bool ScMatrix::IsEmptyPath( SCSIZE nC, SCSIZE nR ) const
3347 return pImpl->IsEmptyPath(nC, nR);
3350 bool ScMatrix::IsValue( SCSIZE nIndex ) const
3352 return pImpl->IsValue(nIndex);
3355 bool ScMatrix::IsValue( SCSIZE nC, SCSIZE nR ) const
3357 return pImpl->IsValue(nC, nR);
3360 bool ScMatrix::IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const
3362 return pImpl->IsValueOrEmpty(nC, nR);
3365 bool ScMatrix::IsBoolean( SCSIZE nC, SCSIZE nR ) const
3367 return pImpl->IsBoolean(nC, nR);
3370 bool ScMatrix::IsNumeric() const
3372 return pImpl->IsNumeric();
3375 void ScMatrix::MatCopy(const ScMatrix& mRes) const
3377 pImpl->MatCopy(*mRes.pImpl);
3380 void ScMatrix::MatTrans(const ScMatrix& mRes) const
3382 pImpl->MatTrans(*mRes.pImpl);
3385 void ScMatrix::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
3387 pImpl->FillDouble(fVal, nC1, nR1, nC2, nR2);
3390 void ScMatrix::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
3392 pImpl->PutDoubleVector(rVec, nC, nR);
3395 void ScMatrix::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
3397 pImpl->PutStringVector(rVec, nC, nR);
3400 void ScMatrix::PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
3402 pImpl->PutEmptyVector(nCount, nC, nR);
3405 void ScMatrix::PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
3407 pImpl->PutEmptyResultVector(nCount, nC, nR);
3410 void ScMatrix::PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
3412 pImpl->PutEmptyPathVector(nCount, nC, nR);
3415 void ScMatrix::CompareEqual()
3417 pImpl->CompareEqual();
3420 void ScMatrix::CompareNotEqual()
3422 pImpl->CompareNotEqual();
3425 void ScMatrix::CompareLess()
3427 pImpl->CompareLess();
3430 void ScMatrix::CompareGreater()
3432 pImpl->CompareGreater();
3435 void ScMatrix::CompareLessEqual()
3437 pImpl->CompareLessEqual();
3440 void ScMatrix::CompareGreaterEqual()
3442 pImpl->CompareGreaterEqual();
3445 double ScMatrix::And() const
3447 return pImpl->And();
3450 double ScMatrix::Or() const
3452 return pImpl->Or();
3455 double ScMatrix::Xor() const
3457 return pImpl->Xor();
3460 ScMatrix::KahanIterateResult ScMatrix::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
3462 return pImpl->Sum(bTextAsZero, bIgnoreErrorValues);
3465 ScMatrix::KahanIterateResult ScMatrix::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
3467 return pImpl->SumSquare(bTextAsZero, bIgnoreErrorValues);
3470 ScMatrix::DoubleIterateResult ScMatrix::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
3472 return pImpl->Product(bTextAsZero, bIgnoreErrorValues);
3475 size_t ScMatrix::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
3477 return pImpl->Count(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
3480 size_t ScMatrix::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
3482 return pImpl->MatchDoubleInColumns(fValue, nCol1, nCol2);
3485 size_t ScMatrix::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
3487 return pImpl->MatchStringInColumns(rStr, nCol1, nCol2);
3490 double ScMatrix::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3492 return pImpl->GetMaxValue(bTextAsZero, bIgnoreErrorValues);
3495 double ScMatrix::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3497 return pImpl->GetMinValue(bTextAsZero, bIgnoreErrorValues);
3500 double ScMatrix::GetGcd() const
3502 return pImpl->GetGcd();
3505 double ScMatrix::GetLcm() const
3507 return pImpl->GetLcm();
3511 ScMatrixRef ScMatrix::CompareMatrix(
3512 sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
3514 return pImpl->CompareMatrix(rComp, nMatPos, pOptions);
3517 void ScMatrix::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
3519 pImpl->GetDoubleArray(rArray, bEmptyAsZero);
3522 void ScMatrix::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
3524 pImpl->MergeDoubleArrayMultiply(rArray);
3527 namespace matop {
3529 namespace {
3531 /** A template for operations where operands are supposed to be numeric.
3532 A non-numeric (string) operand leads to the configured conversion to number
3533 method being called if in interpreter context and a FormulaError::NoValue DoubleError
3534 if conversion was not possible, else to an unconditional FormulaError::NoValue
3535 DoubleError.
3536 An empty operand evaluates to 0.
3538 template<typename TOp>
3539 struct MatOp
3541 private:
3542 TOp maOp;
3543 ScInterpreter* mpErrorInterpreter;
3544 double mfVal;
3546 public:
3547 typedef double number_value_type;
3549 MatOp( TOp aOp, ScInterpreter* pErrorInterpreter,
3550 double fVal = 0.0 ):
3551 maOp(aOp),
3552 mpErrorInterpreter(pErrorInterpreter),
3553 mfVal(fVal)
3555 if (mpErrorInterpreter)
3557 FormulaError nErr = mpErrorInterpreter->GetError();
3558 if (nErr != FormulaError::NONE)
3559 mfVal = CreateDoubleError( nErr);
3563 double operator()(double fVal) const
3565 return maOp(fVal, mfVal);
3568 double operator()(bool bVal) const
3570 return maOp(static_cast<double>(bVal), mfVal);
3573 double operator()(const svl::SharedString& rStr) const
3575 return maOp( convertStringToValue( mpErrorInterpreter, rStr.getString()), mfVal);
3578 /// the action for empty entries in a matrix
3579 double operator()(char) const
3581 return maOp(0, mfVal);
3584 static bool useFunctionForEmpty()
3586 return true;
3594 void ScMatrix::NotOp( const ScMatrix& rMat)
3596 auto not_ = [](double a, double){return double(a == 0.0);};
3597 matop::MatOp<decltype(not_)> aOp(not_, pImpl->GetErrorInterpreter());
3598 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3601 void ScMatrix::NegOp( const ScMatrix& rMat)
3603 auto neg_ = [](double a, double){return -a;};
3604 matop::MatOp<decltype(neg_)> aOp(neg_, pImpl->GetErrorInterpreter());
3605 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3608 void ScMatrix::AddOp( double fVal, const ScMatrix& rMat)
3610 auto add_ = [](double a, double b){return a + b;};
3611 matop::MatOp<decltype(add_)> aOp(add_, pImpl->GetErrorInterpreter(), fVal);
3612 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3615 void ScMatrix::SubOp( bool bFlag, double fVal, const ScMatrix& rMat)
3617 if (bFlag)
3619 auto sub_ = [](double a, double b){return b - a;};
3620 matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3621 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3623 else
3625 auto sub_ = [](double a, double b){return a - b;};
3626 matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3627 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3631 void ScMatrix::MulOp( double fVal, const ScMatrix& rMat)
3633 auto mul_ = [](double a, double b){return a * b;};
3634 matop::MatOp<decltype(mul_)> aOp(mul_, pImpl->GetErrorInterpreter(), fVal);
3635 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3638 void ScMatrix::DivOp( bool bFlag, double fVal, const ScMatrix& rMat)
3640 if (bFlag)
3642 auto div_ = [](double a, double b){return sc::div(b, a);};
3643 matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3644 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3646 else
3648 auto div_ = [](double a, double b){return sc::div(a, b);};
3649 matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3650 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3654 void ScMatrix::PowOp( bool bFlag, double fVal, const ScMatrix& rMat)
3656 if (bFlag)
3658 auto pow_ = [](double a, double b){return sc::power(b, a);};
3659 matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3660 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3662 else
3664 auto pow_ = [](double a, double b){return sc::power(a, b);};
3665 matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3666 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3670 void ScMatrix::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
3671 const std::pair<size_t, size_t>& rEndPos, DoubleOpFunction aDoubleFunc,
3672 BoolOpFunction aBoolFunc, StringOpFunction aStringFunc, EmptyOpFunction aEmptyFunc) const
3674 pImpl->ExecuteOperation(rStartPos, rEndPos, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
3677 ScMatrix::KahanIterateResultMultiple ScMatrix::CollectKahan(const std::vector<sc::op::kOp>& aOp)
3679 return pImpl->ApplyCollectOperation<sc::op::kOp, KahanSum>(aOp);
3682 #if DEBUG_MATRIX
3683 void ScMatrix::Dump() const
3685 pImpl->Dump();
3687 #endif
3689 void ScMatrix::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow,
3690 const ScMatrixRef& xMat1, const ScMatrixRef& xMat2, ScInterpreterContext& rContext, svl::SharedStringPool& rPool)
3692 pImpl->MatConcat(nMaxCol, nMaxRow, xMat1, xMat2, rContext, rPool);
3695 void ScMatrix::ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
3696 ScInterpreter* pInterpreter, const CalculateOpFunction& op)
3698 pImpl->ExecuteBinaryOp(nMaxCol, nMaxRow, rInputMat1, rInputMat2, pInterpreter, op);
3700 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */