xref: /core/sc/source/core/tool/scmatrix.cxx (revision 5a75414d)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
29 
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>
36 
37 #include <memory>
38 #include <mutex>
39 #include <utility>
40 #include <vector>
41 #include <limits>
42 
43 #include <mdds/multi_type_matrix.hpp>
44 #include <mdds/multi_type_vector/types.hpp>
45 
46 #if DEBUG_MATRIX
47 #include <iostream>
48 using std::cout;
49 using std::endl;
50 #endif
51 
52 using ::std::pair;
53 using ::std::advance;
54 
55 namespace {
56 
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.
60  */
61 struct matrix_traits
62 {
63     typedef sc::string_block string_element_block;
64     typedef sc::uint16_block integer_element_block;
65 };
66 
67 struct matrix_flag_traits
68 {
69     typedef sc::string_block string_element_block;
70     typedef mdds::mtv::uint8_element_block integer_element_block;
71 };
72 
73 }
74 
75 typedef mdds::multi_type_matrix<matrix_traits> MatrixImplType;
76 typedef mdds::multi_type_matrix<matrix_flag_traits> MatrixFlagImplType;
77 
78 namespace {
79 
convertStringToValue(ScInterpreter * pErrorInterpreter,const OUString & rStr)80 double convertStringToValue( ScInterpreter* pErrorInterpreter, const OUString& rStr )
81 {
82     if (pErrorInterpreter)
83     {
84         FormulaError nError = FormulaError::NONE;
85         SvNumFormatType nCurFmtType = SvNumFormatType::ALL;
86         double fValue = pErrorInterpreter->ConvertStringToValue( rStr, nError, nCurFmtType);
87         if (nError != FormulaError::NONE)
88         {
89             pErrorInterpreter->SetError( nError);
90             return CreateDoubleError( nError);
91         }
92         return fValue;
93     }
94     return CreateDoubleError( FormulaError::NoValue);
95 }
96 
97 struct ElemEqualZero
98 {
operator ()__anon8faf888b0211::ElemEqualZero99     double operator() (double val) const
100     {
101         if (!std::isfinite(val))
102             return val;
103         return val == 0.0 ? 1.0 : 0.0;
104     }
105 };
106 
107 struct ElemNotEqualZero
108 {
operator ()__anon8faf888b0211::ElemNotEqualZero109     double operator() (double val) const
110     {
111         if (!std::isfinite(val))
112             return val;
113         return val != 0.0 ? 1.0 : 0.0;
114     }
115 };
116 
117 struct ElemGreaterZero
118 {
operator ()__anon8faf888b0211::ElemGreaterZero119     double operator() (double val) const
120     {
121         if (!std::isfinite(val))
122             return val;
123         return val > 0.0 ? 1.0 : 0.0;
124     }
125 };
126 
127 struct ElemLessZero
128 {
operator ()__anon8faf888b0211::ElemLessZero129     double operator() (double val) const
130     {
131         if (!std::isfinite(val))
132             return val;
133         return val < 0.0 ? 1.0 : 0.0;
134     }
135 };
136 
137 struct ElemGreaterEqualZero
138 {
operator ()__anon8faf888b0211::ElemGreaterEqualZero139     double operator() (double val) const
140     {
141         if (!std::isfinite(val))
142             return val;
143         return val >= 0.0 ? 1.0 : 0.0;
144     }
145 };
146 
147 struct ElemLessEqualZero
148 {
operator ()__anon8faf888b0211::ElemLessEqualZero149     double operator() (double val) const
150     {
151         if (!std::isfinite(val))
152             return val;
153         return val <= 0.0 ? 1.0 : 0.0;
154     }
155 };
156 
157 template<typename Comp>
158 class CompareMatrixElemFunc
159 {
160     static Comp maComp;
161 
162     std::vector<double> maNewMatValues;     // double instead of bool to transport error values
163     size_t mnRow;
164     size_t mnCol;
165 public:
CompareMatrixElemFunc(size_t nRow,size_t nCol)166     CompareMatrixElemFunc( size_t nRow, size_t nCol ) : mnRow(nRow), mnCol(nCol)
167     {
168         maNewMatValues.reserve(nRow*nCol);
169     }
170 
171     CompareMatrixElemFunc( const CompareMatrixElemFunc& ) = delete;
172     CompareMatrixElemFunc& operator= ( const CompareMatrixElemFunc& ) = delete;
173 
174     CompareMatrixElemFunc( CompareMatrixElemFunc&& ) = default;
175     CompareMatrixElemFunc& operator= ( CompareMatrixElemFunc&& ) = default;
176 
operator ()(const MatrixImplType::element_block_node_type & node)177     void operator() (const MatrixImplType::element_block_node_type& node)
178     {
179         switch (node.type)
180         {
181             case mdds::mtm::element_numeric:
182             {
183                 typedef MatrixImplType::numeric_block_type block_type;
184 
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)
188                 {
189                     double fVal = *it;
190                     maNewMatValues.push_back(maComp(fVal));
191                 }
192             }
193             break;
194             case mdds::mtm::element_boolean:
195             {
196                 typedef MatrixImplType::boolean_block_type block_type;
197 
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)
201                 {
202                     double fVal = *it ? 1.0 : 0.0;
203                     maNewMatValues.push_back(maComp(fVal));
204                 }
205             }
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);
212         }
213     }
214 
swap(MatrixImplType & rMat)215     void swap( MatrixImplType& rMat )
216     {
217         MatrixImplType aNewMat(mnRow, mnCol, maNewMatValues.begin(), maNewMatValues.end());
218         rMat.swap(aNewMat);
219     }
220 };
221 
222 template<typename Comp>
223 Comp CompareMatrixElemFunc<Comp>::maComp;
224 
225 }
226 
227 typedef uint8_t TMatFlag;
228 const TMatFlag SC_MATFLAG_EMPTYRESULT = 1;
229 const TMatFlag SC_MATFLAG_EMPTYPATH   = 2;
230 
231 class ScMatrixImpl
232 {
233     MatrixImplType maMat;
234     MatrixFlagImplType maMatFlag;
235     ScInterpreter* pErrorInterpreter;
236 
237 public:
238     ScMatrixImpl(const ScMatrixImpl&) = delete;
239     const ScMatrixImpl& operator=(const ScMatrixImpl&) = delete;
240 
241     ScMatrixImpl(SCSIZE nC, SCSIZE nR);
242     ScMatrixImpl(SCSIZE nC, SCSIZE nR, double fInitVal);
243 
244     ScMatrixImpl( size_t nC, size_t nR, const std::vector<double>& rInitVals );
245 
246     ~ScMatrixImpl();
247 
248     void Clear();
249     void Resize(SCSIZE nC, SCSIZE nR);
250     void Resize(SCSIZE nC, SCSIZE nR, double fVal);
251     void SetErrorInterpreter( ScInterpreter* p);
GetErrorInterpreter() const252     ScInterpreter* GetErrorInterpreter() const { return pErrorInterpreter; }
253 
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;
260 
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);
265 
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);
270 
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;
296 
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;
314 
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;
321 
322     double GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const;
323     double GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const;
324     double GetGcd() const;
325     double GetLcm() const;
326 
327     ScMatrixRef CompareMatrix( sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const;
328 
329     void GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const;
330     void MergeDoubleArrayMultiply( std::vector<double>& rArray ) const;
331 
332     template<typename T>
333     void ApplyOperation(T aOp, ScMatrixImpl& rMat);
334 
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;
339 
340     template<typename T, typename tRes>
341     ScMatrix::IterateResultMultiple<tRes> ApplyCollectOperation(const std::vector<T>& aOp);
342 
343     void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
344             ScInterpreterContext& rContext, svl::SharedStringPool& rPool);
345 
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;
355 
356 #if DEBUG_MATRIX
357     void Dump() const;
358 #endif
359 
360 private:
361     void CalcPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const;
362     void CalcTransPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const;
363 };
364 
365 static std::once_flag bElementsMaxFetched;
366 static std::atomic<size_t> nElementsMax;
367 
368 /** The maximum number of elements a matrix or the pool may have at runtime.
369 
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.
375  */
GetElementsMax(size_t nMemory)376 static size_t GetElementsMax( size_t nMemory )
377 {
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;
384 
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);
393 }
394 
ScMatrixImpl(SCSIZE nC,SCSIZE nR)395 ScMatrixImpl::ScMatrixImpl(SCSIZE nC, SCSIZE nR) :
396     maMat(nR, nC), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
397 {
398     nElementsMax -= GetElementCount();
399 }
400 
ScMatrixImpl(SCSIZE nC,SCSIZE nR,double fInitVal)401 ScMatrixImpl::ScMatrixImpl(SCSIZE nC, SCSIZE nR, double fInitVal) :
402     maMat(nR, nC, fInitVal), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
403 {
404     nElementsMax -= GetElementCount();
405 }
406 
ScMatrixImpl(size_t nC,size_t nR,const std::vector<double> & rInitVals)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)
409 {
410     nElementsMax -= GetElementCount();
411 }
412 
~ScMatrixImpl()413 ScMatrixImpl::~ScMatrixImpl()
414 {
415     nElementsMax += GetElementCount();
416     suppress_fun_call_w_exception(Clear());
417 }
418 
Clear()419 void ScMatrixImpl::Clear()
420 {
421     suppress_fun_call_w_exception(maMat.clear());
422     maMatFlag.clear();
423 }
424 
Resize(SCSIZE nC,SCSIZE nR)425 void ScMatrixImpl::Resize(SCSIZE nC, SCSIZE nR)
426 {
427     nElementsMax += GetElementCount();
428     if (ScMatrix::IsSizeAllocatable( nC, nR))
429     {
430         maMat.resize(nR, nC);
431         maMatFlag.resize(nR, nC);
432     }
433     else
434     {
435         // Invalid matrix size, allocate 1x1 matrix with error value.
436         maMat.resize(1, 1, CreateDoubleError( FormulaError::MatrixSize));
437         maMatFlag.resize(1, 1);
438     }
439     nElementsMax -= GetElementCount();
440 }
441 
Resize(SCSIZE nC,SCSIZE nR,double fVal)442 void ScMatrixImpl::Resize(SCSIZE nC, SCSIZE nR, double fVal)
443 {
444     nElementsMax += GetElementCount();
445     if (ScMatrix::IsSizeAllocatable( nC, nR))
446     {
447         maMat.resize(nR, nC, fVal);
448         maMatFlag.resize(nR, nC);
449     }
450     else
451     {
452         // Invalid matrix size, allocate 1x1 matrix with error value.
453         maMat.resize(1, 1, CreateDoubleError( FormulaError::StackOverflow));
454         maMatFlag.resize(1, 1);
455     }
456     nElementsMax -= GetElementCount();
457 }
458 
SetErrorInterpreter(ScInterpreter * p)459 void ScMatrixImpl::SetErrorInterpreter( ScInterpreter* p)
460 {
461     pErrorInterpreter = p;
462 }
463 
GetDimensions(SCSIZE & rC,SCSIZE & rR) const464 void ScMatrixImpl::GetDimensions( SCSIZE& rC, SCSIZE& rR) const
465 {
466     MatrixImplType::size_pair_type aSize = maMat.size();
467     rR = aSize.row;
468     rC = aSize.column;
469 }
470 
GetElementCount() const471 SCSIZE ScMatrixImpl::GetElementCount() const
472 {
473     MatrixImplType::size_pair_type aSize = maMat.size();
474     return aSize.row * aSize.column;
475 }
476 
ValidColRow(SCSIZE nC,SCSIZE nR) const477 bool ScMatrixImpl::ValidColRow( SCSIZE nC, SCSIZE nR) const
478 {
479     MatrixImplType::size_pair_type aSize = maMat.size();
480     return nR < aSize.row && nC < aSize.column;
481 }
482 
ValidColRowReplicated(SCSIZE & rC,SCSIZE & rR) const483 bool ScMatrixImpl::ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const
484 {
485     MatrixImplType::size_pair_type aSize = maMat.size();
486     if (aSize.column == 1 && aSize.row == 1)
487     {
488         rC = 0;
489         rR = 0;
490         return true;
491     }
492     else if (aSize.column == 1 && rR < aSize.row)
493     {
494         // single column matrix.
495         rC = 0;
496         return true;
497     }
498     else if (aSize.row == 1 && rC < aSize.column)
499     {
500         // single row matrix.
501         rR = 0;
502         return true;
503     }
504     return false;
505 }
506 
ValidColRowOrReplicated(SCSIZE & rC,SCSIZE & rR) const507 bool ScMatrixImpl::ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const
508 {
509     return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
510 }
511 
SetErrorAtInterpreter(FormulaError nError) const512 void ScMatrixImpl::SetErrorAtInterpreter( FormulaError nError ) const
513 {
514     if ( pErrorInterpreter )
515         pErrorInterpreter->SetError( nError);
516 }
517 
PutDouble(double fVal,SCSIZE nC,SCSIZE nR)518 void ScMatrixImpl::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
519 {
520     if (ValidColRow( nC, nR))
521         maMat.set(nR, nC, fVal);
522     else
523     {
524         OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
525     }
526 }
527 
PutDouble(const double * pArray,size_t nLen,SCSIZE nC,SCSIZE nR)528 void ScMatrixImpl::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
529 {
530     if (ValidColRow( nC, nR))
531         maMat.set(nR, nC, pArray, pArray + nLen);
532     else
533     {
534         OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
535     }
536 }
537 
PutDouble(double fVal,SCSIZE nIndex)538 void ScMatrixImpl::PutDouble( double fVal, SCSIZE nIndex)
539 {
540     SCSIZE nC, nR;
541     CalcPosition(nIndex, nC, nR);
542     PutDouble(fVal, nC, nR);
543 }
544 
PutDoubleTrans(double fVal,SCSIZE nIndex)545 void ScMatrixImpl::PutDoubleTrans(double fVal, SCSIZE nIndex)
546 {
547     SCSIZE nC, nR;
548     CalcTransPosition(nIndex, nC, nR);
549     PutDouble(fVal, nC, nR);
550 }
551 
PutString(const svl::SharedString & rStr,SCSIZE nC,SCSIZE nR)552 void ScMatrixImpl::PutString(const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR)
553 {
554     if (ValidColRow( nC, nR))
555         maMat.set(nR, nC, rStr);
556     else
557     {
558         OSL_FAIL("ScMatrixImpl::PutString: dimension error");
559     }
560 }
561 
PutString(const svl::SharedString * pArray,size_t nLen,SCSIZE nC,SCSIZE nR)562 void ScMatrixImpl::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
563 {
564     if (ValidColRow( nC, nR))
565         maMat.set(nR, nC, pArray, pArray + nLen);
566     else
567     {
568         OSL_FAIL("ScMatrixImpl::PutString: dimension error");
569     }
570 }
571 
PutString(const svl::SharedString & rStr,SCSIZE nIndex)572 void ScMatrixImpl::PutString(const svl::SharedString& rStr, SCSIZE nIndex)
573 {
574     SCSIZE nC, nR;
575     CalcPosition(nIndex, nC, nR);
576     PutString(rStr, nC, nR);
577 }
578 
PutStringTrans(const svl::SharedString & rStr,SCSIZE nIndex)579 void ScMatrixImpl::PutStringTrans(const svl::SharedString& rStr, SCSIZE nIndex)
580 {
581     SCSIZE nC, nR;
582     CalcTransPosition(nIndex, nC, nR);
583     PutString(rStr, nC, nR);
584 }
585 
PutEmpty(SCSIZE nC,SCSIZE nR)586 void ScMatrixImpl::PutEmpty(SCSIZE nC, SCSIZE nR)
587 {
588     if (ValidColRow( nC, nR))
589     {
590         maMat.set_empty(nR, nC);
591         maMatFlag.set_empty(nR, nC);
592     }
593     else
594     {
595         OSL_FAIL("ScMatrixImpl::PutEmpty: dimension error");
596     }
597 }
598 
PutEmpty(SCSIZE nIndex)599 void ScMatrixImpl::PutEmpty(SCSIZE nIndex)
600 {
601     SCSIZE nC, nR;
602     CalcPosition(nIndex, nC, nR);
603     PutEmpty(nC, nR);
604 }
605 
PutEmptyTrans(SCSIZE nIndex)606 void ScMatrixImpl::PutEmptyTrans(SCSIZE nIndex)
607 {
608     SCSIZE nC, nR;
609     CalcTransPosition(nIndex, nC, nR);
610     PutEmpty(nC, nR);
611 }
612 
PutEmptyPath(SCSIZE nC,SCSIZE nR)613 void ScMatrixImpl::PutEmptyPath(SCSIZE nC, SCSIZE nR)
614 {
615     if (ValidColRow( nC, nR))
616     {
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
626     }
627     else
628     {
629         OSL_FAIL("ScMatrixImpl::PutEmptyPath: dimension error");
630     }
631 }
632 
PutError(FormulaError nErrorCode,SCSIZE nC,SCSIZE nR)633 void ScMatrixImpl::PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR )
634 {
635     maMat.set(nR, nC, CreateDoubleError(nErrorCode));
636 }
637 
PutBoolean(bool bVal,SCSIZE nC,SCSIZE nR)638 void ScMatrixImpl::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
639 {
640     if (ValidColRow( nC, nR))
641         maMat.set(nR, nC, bVal);
642     else
643     {
644         OSL_FAIL("ScMatrixImpl::PutBoolean: dimension error");
645     }
646 }
647 
GetError(SCSIZE nC,SCSIZE nR) const648 FormulaError ScMatrixImpl::GetError( SCSIZE nC, SCSIZE nR) const
649 {
650     if (ValidColRowOrReplicated( nC, nR ))
651     {
652         double fVal = maMat.get_numeric(nR, nC);
653         return GetDoubleErrorValue(fVal);
654     }
655     else
656     {
657         OSL_FAIL("ScMatrixImpl::GetError: dimension error");
658         return FormulaError::NoValue;
659     }
660 }
661 
GetDouble(SCSIZE nC,SCSIZE nR) const662 double ScMatrixImpl::GetDouble(SCSIZE nC, SCSIZE nR) const
663 {
664     if (ValidColRowOrReplicated( nC, nR ))
665     {
666         double fVal = maMat.get_numeric(nR, nC);
667         if ( pErrorInterpreter )
668         {
669             FormulaError nError = GetDoubleErrorValue(fVal);
670             if ( nError != FormulaError::NONE )
671                 SetErrorAtInterpreter( nError);
672         }
673         return fVal;
674     }
675     else
676     {
677         OSL_FAIL("ScMatrixImpl::GetDouble: dimension error");
678         return CreateDoubleError( FormulaError::NoValue);
679     }
680 }
681 
GetDouble(SCSIZE nIndex) const682 double ScMatrixImpl::GetDouble( SCSIZE nIndex) const
683 {
684     SCSIZE nC, nR;
685     CalcPosition(nIndex, nC, nR);
686     return GetDouble(nC, nR);
687 }
688 
GetDoubleWithStringConversion(SCSIZE nC,SCSIZE nR) const689 double ScMatrixImpl::GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
690 {
691     ScMatrixValue aMatVal = Get(nC, nR);
692     if (aMatVal.nType == ScMatValType::String)
693         return convertStringToValue( pErrorInterpreter, aMatVal.aStr.getString());
694     return aMatVal.fVal;
695 }
696 
GetString(SCSIZE nC,SCSIZE nR) const697 svl::SharedString ScMatrixImpl::GetString(SCSIZE nC, SCSIZE nR) const
698 {
699     if (ValidColRowOrReplicated( nC, nR ))
700     {
701         return GetString(maMat.position(nR, nC));
702     }
703     else
704     {
705         OSL_FAIL("ScMatrixImpl::GetString: dimension error");
706     }
707     return svl::SharedString::getEmptyString();
708 }
709 
GetString(const MatrixImplType::const_position_type & rPos) const710 svl::SharedString ScMatrixImpl::GetString(const MatrixImplType::const_position_type& rPos) const
711 {
712     double fErr = 0.0;
713     switch (maMat.get_type(rPos))
714     {
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");
725     }
726     SetErrorAtInterpreter(GetDoubleErrorValue(fErr));
727     return svl::SharedString::getEmptyString();
728 }
729 
GetString(SCSIZE nIndex) const730 svl::SharedString ScMatrixImpl::GetString( SCSIZE nIndex) const
731 {
732     SCSIZE nC, nR;
733     CalcPosition(nIndex, nC, nR);
734     return GetString(nC, nR);
735 }
736 
GetString(ScInterpreterContext & rContext,SCSIZE nC,SCSIZE nR) const737 svl::SharedString ScMatrixImpl::GetString( ScInterpreterContext& rContext, SCSIZE nC, SCSIZE nR) const
738 {
739     if (!ValidColRowOrReplicated( nC, nR ))
740     {
741         OSL_FAIL("ScMatrixImpl::GetString: dimension error");
742         return svl::SharedString::getEmptyString();
743     }
744 
745     double fVal = 0.0;
746     MatrixImplType::const_position_type aPos = maMat.position(nR, nC);
747     switch (maMat.get_type(aPos))
748     {
749         case mdds::mtm::element_string:
750             return maMat.get_string(aPos);
751         case mdds::mtm::element_empty:
752         {
753             if (maMatFlag.get<uint8_t>(nR, nC) != SC_MATFLAG_EMPTYPATH)
754                 // not an empty path.
755                 return svl::SharedString::getEmptyString();
756 
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
764         }
765         case mdds::mtm::element_numeric:
766         case mdds::mtm::element_boolean:
767             fVal = maMat.get_numeric(aPos);
768         break;
769         default:
770             ;
771     }
772 
773     FormulaError nError = GetDoubleErrorValue(fVal);
774     if (nError != FormulaError::NONE)
775     {
776         SetErrorAtInterpreter( nError);
777         return svl::SharedString( ScGlobal::GetErrorString( nError));   // string not interned
778     }
779 
780     sal_uInt32 nKey = rContext.NFGetStandardFormat( SvNumFormatType::NUMBER,
781             ScGlobal::eLnge);
782     OUString aStr;
783     rContext.NFGetInputLineString( fVal, nKey, aStr);
784     return svl::SharedString( aStr);    // string not interned
785 }
786 
Get(SCSIZE nC,SCSIZE nR) const787 ScMatrixValue ScMatrixImpl::Get(SCSIZE nC, SCSIZE nR) const
788 {
789     ScMatrixValue aVal;
790     if (ValidColRowOrReplicated(nC, nR))
791     {
792         MatrixImplType::const_position_type aPos = maMat.position(nR, nC);
793         mdds::mtm::element_t eType = maMat.get_type(aPos);
794         switch (eType)
795         {
796             case mdds::mtm::element_boolean:
797                 aVal.nType = ScMatValType::Boolean;
798                 aVal.fVal = double(maMat.get_boolean(aPos));
799             break;
800             case mdds::mtm::element_numeric:
801                 aVal.nType = ScMatValType::Value;
802                 aVal.fVal = maMat.get_numeric(aPos);
803             break;
804             case mdds::mtm::element_string:
805                 aVal.nType = ScMatValType::String;
806                 aVal.aStr = maMat.get_string(aPos);
807             break;
808             case mdds::mtm::element_empty:
809                 /* TODO: do we need to pass the differentiation of 'empty' and
810                  * 'empty result' to the outer world anywhere? */
811                 switch (maMatFlag.get_type(nR, nC))
812                 {
813                     case mdds::mtm::element_empty:
814                         aVal.nType = ScMatValType::Empty;
815                     break;
816                     case mdds::mtm::element_integer:
817                         aVal.nType = maMatFlag.get<uint8_t>(nR, nC)
818                             == SC_MATFLAG_EMPTYPATH ? ScMatValType::EmptyPath : ScMatValType::Empty;
819                     break;
820                     default:
821                         assert(false);
822                 }
823                 aVal.fVal = 0.0;
824             break;
825             default:
826                 ;
827         }
828     }
829     else
830     {
831         OSL_FAIL("ScMatrixImpl::Get: dimension error");
832     }
833     return aVal;
834 }
835 
IsStringOrEmpty(SCSIZE nIndex) const836 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nIndex ) const
837 {
838     SCSIZE nC, nR;
839     CalcPosition(nIndex, nC, nR);
840     return IsStringOrEmpty(nC, nR);
841 }
842 
IsStringOrEmpty(SCSIZE nC,SCSIZE nR) const843 bool ScMatrixImpl::IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const
844 {
845     if (!ValidColRowOrReplicated( nC, nR ))
846         return false;
847 
848     switch (maMat.get_type(nR, nC))
849     {
850         case mdds::mtm::element_empty:
851         case mdds::mtm::element_string:
852             return true;
853         default:
854             ;
855     }
856     return false;
857 }
858 
IsEmpty(SCSIZE nC,SCSIZE nR) const859 bool ScMatrixImpl::IsEmpty( SCSIZE nC, SCSIZE nR ) const
860 {
861     if (!ValidColRowOrReplicated( nC, nR ))
862         return false;
863 
864     // Flag must indicate an 'empty' or 'empty cell' or 'empty result' element,
865     // but not an 'empty path' element.
866     return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
867         maMatFlag.get_integer(nR, nC) != SC_MATFLAG_EMPTYPATH;
868 }
869 
IsEmptyCell(SCSIZE nC,SCSIZE nR) const870 bool ScMatrixImpl::IsEmptyCell( SCSIZE nC, SCSIZE nR ) const
871 {
872     if (!ValidColRowOrReplicated( nC, nR ))
873         return false;
874 
875     // Flag must indicate an 'empty cell' element instead of an
876     // 'empty' or 'empty result' or 'empty path' element.
877     return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
878         maMatFlag.get_type(nR, nC) == mdds::mtm::element_empty;
879 }
880 
IsEmptyResult(SCSIZE nC,SCSIZE nR) const881 bool ScMatrixImpl::IsEmptyResult( SCSIZE nC, SCSIZE nR ) const
882 {
883     if (!ValidColRowOrReplicated( nC, nR ))
884         return false;
885 
886     // Flag must indicate an 'empty result' element instead of an
887     // 'empty' or 'empty cell' or 'empty path' element.
888     return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
889         maMatFlag.get_integer(nR, nC) == SC_MATFLAG_EMPTYRESULT;
890 }
891 
IsEmptyPath(SCSIZE nC,SCSIZE nR) const892 bool ScMatrixImpl::IsEmptyPath( SCSIZE nC, SCSIZE nR ) const
893 {
894     // Flag must indicate an 'empty path' element.
895     if (ValidColRowOrReplicated( nC, nR ))
896         return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
897             maMatFlag.get_integer(nR, nC) == SC_MATFLAG_EMPTYPATH;
898     else
899         return true;
900 }
901 
IsValue(SCSIZE nIndex) const902 bool ScMatrixImpl::IsValue( SCSIZE nIndex ) const
903 {
904     SCSIZE nC, nR;
905     CalcPosition(nIndex, nC, nR);
906     return IsValue(nC, nR);
907 }
908 
IsValue(SCSIZE nC,SCSIZE nR) const909 bool ScMatrixImpl::IsValue( SCSIZE nC, SCSIZE nR ) const
910 {
911     if (!ValidColRowOrReplicated( nC, nR ))
912         return false;
913 
914     switch (maMat.get_type(nR, nC))
915     {
916         case mdds::mtm::element_boolean:
917         case mdds::mtm::element_numeric:
918             return true;
919         default:
920             ;
921     }
922     return false;
923 }
924 
IsValueOrEmpty(SCSIZE nC,SCSIZE nR) const925 bool ScMatrixImpl::IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const
926 {
927     if (!ValidColRowOrReplicated( nC, nR ))
928         return false;
929 
930     switch (maMat.get_type(nR, nC))
931     {
932         case mdds::mtm::element_boolean:
933         case mdds::mtm::element_numeric:
934         case mdds::mtm::element_empty:
935             return true;
936         default:
937             ;
938     }
939     return false;
940 }
941 
IsBoolean(SCSIZE nC,SCSIZE nR) const942 bool ScMatrixImpl::IsBoolean( SCSIZE nC, SCSIZE nR ) const
943 {
944     if (!ValidColRowOrReplicated( nC, nR ))
945         return false;
946 
947     return maMat.get_type(nR, nC) == mdds::mtm::element_boolean;
948 }
949 
IsNumeric() const950 bool ScMatrixImpl::IsNumeric() const
951 {
952     return maMat.numeric();
953 }
954 
MatCopy(ScMatrixImpl & mRes) const955 void ScMatrixImpl::MatCopy(ScMatrixImpl& mRes) const
956 {
957     if (maMat.size().row > mRes.maMat.size().row || maMat.size().column > mRes.maMat.size().column)
958     {
959         // destination matrix is not large enough.
960         OSL_FAIL("ScMatrixImpl::MatCopy: dimension error");
961         return;
962     }
963 
964     mRes.maMat.copy(maMat);
965 }
966 
MatTrans(ScMatrixImpl & mRes) const967 void ScMatrixImpl::MatTrans(ScMatrixImpl& mRes) const
968 {
969     mRes.maMat = maMat;
970     mRes.maMat.transpose();
971 }
972 
FillDouble(double fVal,SCSIZE nC1,SCSIZE nR1,SCSIZE nC2,SCSIZE nR2)973 void ScMatrixImpl::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
974 {
975     if (ValidColRow( nC1, nR1) && ValidColRow( nC2, nR2))
976     {
977         for (SCSIZE j = nC1; j <= nC2; ++j)
978         {
979             // Passing value array is much faster.
980             std::vector<double> aVals(nR2-nR1+1, fVal);
981             maMat.set(nR1, j, aVals.begin(), aVals.end());
982         }
983     }
984     else
985     {
986         OSL_FAIL("ScMatrixImpl::FillDouble: dimension error");
987     }
988 }
989 
PutDoubleVector(const::std::vector<double> & rVec,SCSIZE nC,SCSIZE nR)990 void ScMatrixImpl::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
991 {
992     if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
993     {
994         maMat.set(nR, nC, rVec.begin(), rVec.end());
995     }
996     else
997     {
998         OSL_FAIL("ScMatrixImpl::PutDoubleVector: dimension error");
999     }
1000 }
1001 
PutStringVector(const::std::vector<svl::SharedString> & rVec,SCSIZE nC,SCSIZE nR)1002 void ScMatrixImpl::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
1003 {
1004     if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
1005     {
1006         maMat.set(nR, nC, rVec.begin(), rVec.end());
1007     }
1008     else
1009     {
1010         OSL_FAIL("ScMatrixImpl::PutStringVector: dimension error");
1011     }
1012 }
1013 
PutEmptyVector(SCSIZE nCount,SCSIZE nC,SCSIZE nR)1014 void ScMatrixImpl::PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
1015 {
1016     if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
1017     {
1018         maMat.set_empty(nR, nC, nCount);
1019         // Flag to indicate that this is 'empty', not 'empty result' or 'empty path'.
1020         maMatFlag.set_empty(nR, nC, nCount);
1021     }
1022     else
1023     {
1024         OSL_FAIL("ScMatrixImpl::PutEmptyVector: dimension error");
1025     }
1026 }
1027 
PutEmptyResultVector(SCSIZE nCount,SCSIZE nC,SCSIZE nR)1028 void ScMatrixImpl::PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
1029 {
1030     if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
1031     {
1032         maMat.set_empty(nR, nC, nCount);
1033         // Flag to indicate that this is 'empty result', not 'empty' or 'empty path'.
1034         std::vector<uint8_t> aVals(nCount, SC_MATFLAG_EMPTYRESULT);
1035         maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
1036     }
1037     else
1038     {
1039         OSL_FAIL("ScMatrixImpl::PutEmptyResultVector: dimension error");
1040     }
1041 }
1042 
PutEmptyPathVector(SCSIZE nCount,SCSIZE nC,SCSIZE nR)1043 void ScMatrixImpl::PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
1044 {
1045     if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
1046     {
1047         maMat.set_empty(nR, nC, nCount);
1048         // Flag to indicate 'empty path'.
1049         std::vector<uint8_t> aVals(nCount, SC_MATFLAG_EMPTYPATH);
1050         maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
1051     }
1052     else
1053     {
1054         OSL_FAIL("ScMatrixImpl::PutEmptyPathVector: dimension error");
1055     }
1056 }
1057 
CompareEqual()1058 void ScMatrixImpl::CompareEqual()
1059 {
1060     MatrixImplType::size_pair_type aSize = maMat.size();
1061     CompareMatrixElemFunc<ElemEqualZero> aFunc(aSize.row, aSize.column);
1062     aFunc = maMat.walk(std::move(aFunc));
1063     aFunc.swap(maMat);
1064 }
1065 
CompareNotEqual()1066 void ScMatrixImpl::CompareNotEqual()
1067 {
1068     MatrixImplType::size_pair_type aSize = maMat.size();
1069     CompareMatrixElemFunc<ElemNotEqualZero> aFunc(aSize.row, aSize.column);
1070     aFunc = maMat.walk(std::move(aFunc));
1071     aFunc.swap(maMat);
1072 }
1073 
CompareLess()1074 void ScMatrixImpl::CompareLess()
1075 {
1076     MatrixImplType::size_pair_type aSize = maMat.size();
1077     CompareMatrixElemFunc<ElemLessZero> aFunc(aSize.row, aSize.column);
1078     aFunc = maMat.walk(std::move(aFunc));
1079     aFunc.swap(maMat);
1080 }
1081 
CompareGreater()1082 void ScMatrixImpl::CompareGreater()
1083 {
1084     MatrixImplType::size_pair_type aSize = maMat.size();
1085     CompareMatrixElemFunc<ElemGreaterZero> aFunc(aSize.row, aSize.column);
1086     aFunc = maMat.walk(std::move(aFunc));
1087     aFunc.swap(maMat);
1088 }
1089 
CompareLessEqual()1090 void ScMatrixImpl::CompareLessEqual()
1091 {
1092     MatrixImplType::size_pair_type aSize = maMat.size();
1093     CompareMatrixElemFunc<ElemLessEqualZero> aFunc(aSize.row, aSize.column);
1094     aFunc = maMat.walk(std::move(aFunc));
1095     aFunc.swap(maMat);
1096 }
1097 
CompareGreaterEqual()1098 void ScMatrixImpl::CompareGreaterEqual()
1099 {
1100     MatrixImplType::size_pair_type aSize = maMat.size();
1101     CompareMatrixElemFunc<ElemGreaterEqualZero> aFunc(aSize.row, aSize.column);
1102     aFunc = maMat.walk(std::move(aFunc));
1103     aFunc.swap(maMat);
1104 }
1105 
1106 namespace {
1107 
1108 struct AndEvaluator
1109 {
1110     bool mbResult;
operate__anon8faf888b0311::AndEvaluator1111     void operate(double fVal) { mbResult &= (fVal != 0.0); }
result__anon8faf888b0311::AndEvaluator1112     bool result() const { return mbResult; }
AndEvaluator__anon8faf888b0311::AndEvaluator1113     AndEvaluator() : mbResult(true) {}
1114 };
1115 
1116 struct OrEvaluator
1117 {
1118     bool mbResult;
operate__anon8faf888b0311::OrEvaluator1119     void operate(double fVal) { mbResult |= (fVal != 0.0); }
result__anon8faf888b0311::OrEvaluator1120     bool result() const { return mbResult; }
OrEvaluator__anon8faf888b0311::OrEvaluator1121     OrEvaluator() : mbResult(false) {}
1122 };
1123 
1124 struct XorEvaluator
1125 {
1126     bool mbResult;
operate__anon8faf888b0311::XorEvaluator1127     void operate(double fVal) { mbResult ^= (fVal != 0.0); }
result__anon8faf888b0311::XorEvaluator1128     bool result() const { return mbResult; }
XorEvaluator__anon8faf888b0311::XorEvaluator1129     XorEvaluator() : mbResult(false) {}
1130 };
1131 
1132 // Do not short circuit logical operations, in case there are error values
1133 // these need to be propagated even if the result was determined earlier.
1134 template <typename Evaluator>
EvalMatrix(const MatrixImplType & rMat)1135 double EvalMatrix(const MatrixImplType& rMat)
1136 {
1137     Evaluator aEval;
1138     size_t nRows = rMat.size().row, nCols = rMat.size().column;
1139     for (size_t i = 0; i < nRows; ++i)
1140     {
1141         for (size_t j = 0; j < nCols; ++j)
1142         {
1143             MatrixImplType::const_position_type aPos = rMat.position(i, j);
1144             mdds::mtm::element_t eType = rMat.get_type(aPos);
1145             if (eType != mdds::mtm::element_numeric && eType != mdds::mtm::element_boolean)
1146                 // assuming a CompareMat this is an error
1147                 return CreateDoubleError(FormulaError::IllegalArgument);
1148 
1149             double fVal = rMat.get_numeric(aPos);
1150             if (!std::isfinite(fVal))
1151                 // DoubleError
1152                 return fVal;
1153 
1154             aEval.operate(fVal);
1155         }
1156     }
1157     return aEval.result();
1158 }
1159 
1160 }
1161 
And() const1162 double ScMatrixImpl::And() const
1163 {
1164     // All elements must be of value type.
1165     // True only if all the elements have non-zero values.
1166     return EvalMatrix<AndEvaluator>(maMat);
1167 }
1168 
Or() const1169 double ScMatrixImpl::Or() const
1170 {
1171     // All elements must be of value type.
1172     // True if at least one element has a non-zero value.
1173     return EvalMatrix<OrEvaluator>(maMat);
1174 }
1175 
Xor() const1176 double ScMatrixImpl::Xor() const
1177 {
1178     // All elements must be of value type.
1179     // True if an odd number of elements have a non-zero value.
1180     return EvalMatrix<XorEvaluator>(maMat);
1181 }
1182 
1183 namespace {
1184 
1185 template<typename Op, typename tRes>
1186 class WalkElementBlocks
1187 {
1188     Op maOp;
1189     ScMatrix::IterateResult<tRes> maRes;
1190     bool mbTextAsZero:1;
1191     bool mbIgnoreErrorValues:1;
1192 public:
WalkElementBlocks(bool bTextAsZero,bool bIgnoreErrorValues)1193     WalkElementBlocks(bool bTextAsZero, bool bIgnoreErrorValues) :
1194         maRes(Op::InitVal, 0),
1195         mbTextAsZero(bTextAsZero), mbIgnoreErrorValues(bIgnoreErrorValues)
1196     {}
1197 
getResult() const1198     const ScMatrix::IterateResult<tRes>& getResult() const { return maRes; }
1199 
operator ()(const MatrixImplType::element_block_node_type & node)1200     void operator() (const MatrixImplType::element_block_node_type& node)
1201     {
1202         switch (node.type)
1203         {
1204             case mdds::mtm::element_numeric:
1205             {
1206                 typedef MatrixImplType::numeric_block_type block_type;
1207 
1208                 size_t nIgnored = 0;
1209                 block_type::const_iterator it = block_type::begin(*node.data);
1210                 block_type::const_iterator itEnd = block_type::end(*node.data);
1211                 for (; it != itEnd; ++it)
1212                 {
1213                     if (mbIgnoreErrorValues && !std::isfinite(*it))
1214                     {
1215                         ++nIgnored;
1216                         continue;
1217                     }
1218                     maOp(maRes.maAccumulator, *it);
1219                 }
1220                 maRes.mnCount += node.size - nIgnored;
1221             }
1222             break;
1223             case mdds::mtm::element_boolean:
1224             {
1225                 typedef MatrixImplType::boolean_block_type block_type;
1226 
1227                 block_type::const_iterator it = block_type::begin(*node.data);
1228                 block_type::const_iterator itEnd = block_type::end(*node.data);
1229                 for (; it != itEnd; ++it)
1230                 {
1231                     maOp(maRes.maAccumulator, *it);
1232                 }
1233                 maRes.mnCount += node.size;
1234             }
1235             break;
1236             case mdds::mtm::element_string:
1237                 if (mbTextAsZero)
1238                     maRes.mnCount += node.size;
1239             break;
1240             case mdds::mtm::element_empty:
1241             default:
1242                 ;
1243         }
1244     }
1245 };
1246 
1247 template<typename Op, typename tRes>
1248 class WalkElementBlocksMultipleValues
1249 {
1250     const std::vector<Op>* mpOp;
1251     ScMatrix::IterateResultMultiple<tRes> maRes;
1252 public:
WalkElementBlocksMultipleValues(const std::vector<Op> & aOp)1253     WalkElementBlocksMultipleValues(const std::vector<Op>& aOp) :
1254         mpOp(&aOp), maRes(0)
1255     {
1256         for (const auto& rpOp : *mpOp)
1257             maRes.maAccumulator.emplace_back(rpOp.mInitVal);
1258     }
1259 
1260     WalkElementBlocksMultipleValues( const WalkElementBlocksMultipleValues& ) = delete;
1261     WalkElementBlocksMultipleValues& operator= ( const WalkElementBlocksMultipleValues& ) = delete;
1262 
WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues && r)1263     WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues&& r) noexcept
1264     : mpOp(r.mpOp), maRes(r.maRes.mnCount)
1265     {
1266         maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1267     }
1268 
operator =(WalkElementBlocksMultipleValues && r)1269     WalkElementBlocksMultipleValues& operator=(WalkElementBlocksMultipleValues&& r) noexcept
1270     {
1271         mpOp = r.mpOp;
1272         maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1273         maRes.mnCount = r.maRes.mnCount;
1274         return *this;
1275     }
1276 
getResult() const1277     const ScMatrix::IterateResultMultiple<tRes>& getResult() const { return maRes; }
1278 
operator ()(const MatrixImplType::element_block_node_type & node)1279     void operator() (const MatrixImplType::element_block_node_type& node)
1280     {
1281         switch (node.type)
1282         {
1283             case mdds::mtm::element_numeric:
1284             {
1285                 typedef MatrixImplType::numeric_block_type block_type;
1286 
1287                 block_type::const_iterator it = block_type::begin(*node.data);
1288                 block_type::const_iterator itEnd = block_type::end(*node.data);
1289                 for (; it != itEnd; ++it)
1290                 {
1291                     for (size_t i = 0u; i < mpOp->size(); ++i)
1292                         (*mpOp)[i](maRes.maAccumulator[i], *it);
1293                 }
1294                 maRes.mnCount += node.size;
1295             }
1296             break;
1297             case mdds::mtm::element_boolean:
1298             {
1299                 typedef MatrixImplType::boolean_block_type block_type;
1300 
1301                 block_type::const_iterator it = block_type::begin(*node.data);
1302                 block_type::const_iterator itEnd = block_type::end(*node.data);
1303                 for (; it != itEnd; ++it)
1304                 {
1305                     for (size_t i = 0u; i < mpOp->size(); ++i)
1306                         (*mpOp)[i](maRes.maAccumulator[i], *it);
1307                 }
1308                 maRes.mnCount += node.size;
1309             }
1310             break;
1311             case mdds::mtm::element_string:
1312             case mdds::mtm::element_empty:
1313             default:
1314                 ;
1315         }
1316     }
1317 };
1318 
1319 class CountElements
1320 {
1321     size_t mnCount;
1322     bool mbCountString;
1323     bool mbCountErrors;
1324     bool mbIgnoreEmptyStrings;
1325 public:
CountElements(bool bCountString,bool bCountErrors,bool bIgnoreEmptyStrings)1326     explicit CountElements(bool bCountString, bool bCountErrors, bool bIgnoreEmptyStrings) :
1327         mnCount(0), mbCountString(bCountString), mbCountErrors(bCountErrors),
1328         mbIgnoreEmptyStrings(bIgnoreEmptyStrings) {}
1329 
getCount() const1330     size_t getCount() const { return mnCount; }
1331 
operator ()(const MatrixImplType::element_block_node_type & node)1332     void operator() (const MatrixImplType::element_block_node_type& node)
1333     {
1334         switch (node.type)
1335         {
1336             case mdds::mtm::element_numeric:
1337                 mnCount += node.size;
1338                 if (!mbCountErrors)
1339                 {
1340                     typedef MatrixImplType::numeric_block_type block_type;
1341 
1342                     block_type::const_iterator it = block_type::begin(*node.data);
1343                     block_type::const_iterator itEnd = block_type::end(*node.data);
1344                     for (; it != itEnd; ++it)
1345                     {
1346                         if (!std::isfinite(*it))
1347                             --mnCount;
1348                     }
1349                 }
1350             break;
1351             case mdds::mtm::element_boolean:
1352                 mnCount += node.size;
1353             break;
1354             case mdds::mtm::element_string:
1355                 if (mbCountString)
1356                 {
1357                     mnCount += node.size;
1358                     if (mbIgnoreEmptyStrings)
1359                     {
1360                         typedef MatrixImplType::string_block_type block_type;
1361 
1362                         block_type::const_iterator it = block_type::begin(*node.data);
1363                         block_type::const_iterator itEnd = block_type::end(*node.data);
1364                         for (; it != itEnd; ++it)
1365                         {
1366                             if (it->isEmpty())
1367                                 --mnCount;
1368                         }
1369                     }
1370                 }
1371             break;
1372             case mdds::mtm::element_empty:
1373             default:
1374                 ;
1375         }
1376     }
1377 };
1378 
1379 const size_t ResultNotSet = std::numeric_limits<size_t>::max();
1380 
1381 template<typename Type>
1382 class WalkAndMatchElements
1383 {
1384     Type maMatchValue;
1385     size_t mnStartIndex;
1386     size_t mnStopIndex;
1387     size_t mnResult;
1388     size_t mnIndex;
1389 
1390 public:
WalkAndMatchElements(Type aMatchValue,const MatrixImplType::size_pair_type & aSize,size_t nCol1,size_t nCol2)1391     WalkAndMatchElements(Type aMatchValue, const MatrixImplType::size_pair_type& aSize, size_t nCol1, size_t nCol2) :
1392         maMatchValue(std::move(aMatchValue)),
1393         mnStartIndex( nCol1 * aSize.row ),
1394         mnStopIndex( (nCol2 + 1) * aSize.row ),
1395         mnResult(ResultNotSet),
1396         mnIndex(0)
1397     {
1398         assert( nCol1 < aSize.column && nCol2 < aSize.column);
1399     }
1400 
getMatching() const1401     size_t getMatching() const { return mnResult; }
1402 
getRemainingCount() const1403     size_t getRemainingCount() const
1404     {
1405         return mnIndex < mnStopIndex ? mnStopIndex - mnIndex : 0;
1406     }
1407 
1408     size_t compare(const MatrixImplType::element_block_node_type& node) const;
1409 
operator ()(const MatrixImplType::element_block_node_type & node)1410     void operator() (const MatrixImplType::element_block_node_type& node)
1411     {
1412         // early exit if match already found
1413         if (mnResult != ResultNotSet)
1414             return;
1415 
1416         // limit lookup to the requested columns
1417         if (mnStartIndex <= mnIndex && getRemainingCount() > 0)
1418         {
1419             mnResult = compare(node);
1420         }
1421 
1422         mnIndex += node.size;
1423     }
1424 };
1425 
1426 template<>
compare(const MatrixImplType::element_block_node_type & node) const1427 size_t WalkAndMatchElements<double>::compare(const MatrixImplType::element_block_node_type& node) const
1428 {
1429     size_t nCount = 0;
1430     switch (node.type)
1431     {
1432         case mdds::mtm::element_numeric:
1433         {
1434             typedef MatrixImplType::numeric_block_type block_type;
1435 
1436             block_type::const_iterator it = block_type::begin(*node.data);
1437             block_type::const_iterator itEnd = block_type::end(*node.data);
1438             const size_t nRemaining = getRemainingCount();
1439             for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1440             {
1441                 if (*it == maMatchValue)
1442                 {
1443                     return mnIndex + nCount;
1444                 }
1445             }
1446             break;
1447         }
1448         case mdds::mtm::element_boolean:
1449         {
1450             typedef MatrixImplType::boolean_block_type block_type;
1451 
1452             block_type::const_iterator it = block_type::begin(*node.data);
1453             block_type::const_iterator itEnd = block_type::end(*node.data);
1454             const size_t nRemaining = getRemainingCount();
1455             for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1456             {
1457                 if (int(*it) == maMatchValue)
1458                 {
1459                     return mnIndex + nCount;
1460                 }
1461             }
1462             break;
1463         }
1464         break;
1465         case mdds::mtm::element_string:
1466         case mdds::mtm::element_empty:
1467         default:
1468             ;
1469     }
1470     return ResultNotSet;
1471 }
1472 
1473 template<>
compare(const MatrixImplType::element_block_node_type & node) const1474 size_t WalkAndMatchElements<svl::SharedString>::compare(const MatrixImplType::element_block_node_type& node) const
1475 {
1476     switch (node.type)
1477     {
1478         case mdds::mtm::element_string:
1479         {
1480             size_t nCount = 0;
1481             typedef MatrixImplType::string_block_type block_type;
1482 
1483             block_type::const_iterator it = block_type::begin(*node.data);
1484             block_type::const_iterator itEnd = block_type::end(*node.data);
1485             const size_t nRemaining = getRemainingCount();
1486             for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1487             {
1488                 if (it->getDataIgnoreCase() == maMatchValue.getDataIgnoreCase())
1489                 {
1490                     return mnIndex + nCount;
1491                 }
1492             }
1493             break;
1494         }
1495         case mdds::mtm::element_boolean:
1496         case mdds::mtm::element_numeric:
1497         case mdds::mtm::element_empty:
1498         default:
1499             ;
1500     }
1501     return ResultNotSet;
1502 }
1503 
1504 struct MaxOp
1505 {
init__anon8faf888b0411::MaxOp1506     static double init() { return -std::numeric_limits<double>::max(); }
compare__anon8faf888b0411::MaxOp1507     static double compare(double left, double right)
1508     {
1509         if (!std::isfinite(left))
1510             return left;
1511         if (!std::isfinite(right))
1512             return right;
1513         return std::max(left, right);
1514     }
1515 
boolValue__anon8faf888b0411::MaxOp1516     static double boolValue(
1517         MatrixImplType::boolean_block_type::const_iterator it,
1518         const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1519     {
1520         // If the array has at least one true value, the maximum value is 1.
1521         it = std::find(it, itEnd, true);
1522         return it == itEnd ? 0.0 : 1.0;
1523     }
1524 };
1525 
1526 struct MinOp
1527 {
init__anon8faf888b0411::MinOp1528     static double init() { return std::numeric_limits<double>::max(); }
compare__anon8faf888b0411::MinOp1529     static double compare(double left, double right)
1530     {
1531         if (!std::isfinite(left))
1532             return left;
1533         if (!std::isfinite(right))
1534             return right;
1535         return std::min(left, right);
1536     }
1537 
boolValue__anon8faf888b0411::MinOp1538     static double boolValue(
1539         MatrixImplType::boolean_block_type::const_iterator it,
1540         const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1541     {
1542         // If the array has at least one false value, the minimum value is 0.
1543         it = std::find(it, itEnd, false);
1544         return it == itEnd ? 1.0 : 0.0;
1545     }
1546 };
1547 
1548 struct Lcm
1549 {
init__anon8faf888b0411::Lcm1550     static double init() { return 1.0; }
calculate__anon8faf888b0411::Lcm1551     static double calculate(double fx,double fy)
1552     {
1553         return (fx*fy)/ScInterpreter::ScGetGCD(fx,fy);
1554     }
1555 
boolValue__anon8faf888b0411::Lcm1556     static double boolValue(
1557             MatrixImplType::boolean_block_type::const_iterator it,
1558             const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1559     {
1560         // If the array has at least one false value, the minimum value is 0.
1561         it = std::find(it, itEnd, false);
1562         return it == itEnd ? 1.0 : 0.0;
1563     }
1564 };
1565 
1566 struct Gcd
1567 {
init__anon8faf888b0411::Gcd1568     static double init() { return 0.0; }
calculate__anon8faf888b0411::Gcd1569     static double calculate(double fx,double fy)
1570     {
1571         return ScInterpreter::ScGetGCD(fx,fy);
1572     }
1573 
boolValue__anon8faf888b0411::Gcd1574     static double boolValue(
1575             MatrixImplType::boolean_block_type::const_iterator it,
1576             const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1577     {
1578         // If the array has at least one true value, the gcdResult is 1.
1579         it = std::find(it, itEnd, true);
1580         return it == itEnd ? 0.0 : 1.0;
1581     }
1582 };
1583 
1584 template<typename Op>
1585 class CalcMaxMinValue
1586 {
1587     double mfVal;
1588     bool mbTextAsZero;
1589     bool mbIgnoreErrorValues;
1590     bool mbHasValue;
1591 public:
CalcMaxMinValue(bool bTextAsZero,bool bIgnoreErrorValues)1592     CalcMaxMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) :
1593         mfVal(Op::init()),
1594         mbTextAsZero(bTextAsZero),
1595         mbIgnoreErrorValues(bIgnoreErrorValues),
1596         mbHasValue(false) {}
1597 
getValue() const1598     double getValue() const { return mbHasValue ? mfVal : 0.0; }
1599 
operator ()(const MatrixImplType::element_block_node_type & node)1600     void operator() (const MatrixImplType::element_block_node_type& node)
1601     {
1602 
1603         switch (node.type)
1604         {
1605             case mdds::mtm::element_numeric:
1606             {
1607                 typedef MatrixImplType::numeric_block_type block_type;
1608 
1609                 block_type::const_iterator it = block_type::begin(*node.data);
1610                 block_type::const_iterator itEnd = block_type::end(*node.data);
1611                 if (mbIgnoreErrorValues)
1612                 {
1613                     for (; it != itEnd; ++it)
1614                     {
1615                         if (std::isfinite(*it))
1616                             mfVal = Op::compare(mfVal, *it);
1617                     }
1618                 }
1619                 else
1620                 {
1621                     for (; it != itEnd; ++it)
1622                         mfVal = Op::compare(mfVal, *it);
1623                 }
1624 
1625                 mbHasValue = true;
1626             }
1627             break;
1628             case mdds::mtm::element_boolean:
1629             {
1630                 typedef MatrixImplType::boolean_block_type block_type;
1631 
1632                 block_type::const_iterator it = block_type::begin(*node.data);
1633                 block_type::const_iterator itEnd = block_type::end(*node.data);
1634                 double fVal = Op::boolValue(it, itEnd);
1635                 mfVal = Op::compare(mfVal, fVal);
1636                 mbHasValue = true;
1637             }
1638             break;
1639             case mdds::mtm::element_string:
1640             case mdds::mtm::element_empty:
1641             {
1642                 // empty elements are treated as empty strings.
1643                 if (mbTextAsZero)
1644                 {
1645                     mfVal = Op::compare(mfVal, 0.0);
1646                     mbHasValue = true;
1647                 }
1648             }
1649             break;
1650             default:
1651                 ;
1652         }
1653     }
1654 };
1655 
1656 template<typename Op>
1657 class CalcGcdLcm
1658 {
1659     double mfval;
1660 
1661 public:
CalcGcdLcm()1662     CalcGcdLcm() : mfval(Op::init()) {}
1663 
getResult() const1664     double getResult() const { return mfval; }
1665 
operator ()(const MatrixImplType::element_block_node_type & node)1666     void operator() ( const MatrixImplType::element_block_node_type& node )
1667     {
1668         switch (node.type)
1669         {
1670             case mdds::mtm::element_numeric:
1671                 {
1672                     typedef MatrixImplType::numeric_block_type block_type;
1673                     block_type::const_iterator it = block_type::begin(*node.data);
1674                     block_type::const_iterator itEnd = block_type::end(*node.data);
1675 
1676                     for ( ; it != itEnd; ++it)
1677                     {
1678                         if (*it < 0.0)
1679                             mfval = CreateDoubleError(FormulaError::IllegalArgument);
1680                         else
1681                             mfval = ::rtl::math::approxFloor( Op::calculate(*it,mfval));
1682                     }
1683                 }
1684             break;
1685             case mdds::mtm::element_boolean:
1686                 {
1687                     typedef MatrixImplType::boolean_block_type block_type;
1688                     block_type::const_iterator it = block_type::begin(*node.data);
1689                     block_type::const_iterator itEnd = block_type::end(*node.data);
1690 
1691                     mfval = Op::boolValue(it, itEnd);
1692                 }
1693             break;
1694             case mdds::mtm::element_empty:
1695             case mdds::mtm::element_string:
1696                 {
1697                     mfval = CreateDoubleError(FormulaError::IllegalArgument);
1698                 }
1699             break;
1700             default:
1701                 ;
1702         }
1703     }
1704 };
1705 
evaluate(double fVal,ScQueryOp eOp)1706 double evaluate( double fVal, ScQueryOp eOp )
1707 {
1708     if (!std::isfinite(fVal))
1709         return fVal;
1710 
1711     switch (eOp)
1712     {
1713         case SC_EQUAL:
1714             return fVal == 0.0 ? 1.0 : 0.0;
1715         case SC_LESS:
1716             return fVal < 0.0 ? 1.0 : 0.0;
1717         case SC_GREATER:
1718             return fVal > 0.0 ? 1.0 : 0.0;
1719         case SC_LESS_EQUAL:
1720             return fVal <= 0.0 ? 1.0 : 0.0;
1721         case SC_GREATER_EQUAL:
1722             return fVal >= 0.0 ? 1.0 : 0.0;
1723         case SC_NOT_EQUAL:
1724             return fVal != 0.0 ? 1.0 : 0.0;
1725         default:
1726             ;
1727     }
1728 
1729     SAL_WARN("sc.core",  "evaluate: unhandled comparison operator: " << static_cast<int>(eOp));
1730     return CreateDoubleError( FormulaError::UnknownState);
1731 }
1732 
1733 class CompareMatrixFunc
1734 {
1735     sc::Compare& mrComp;
1736     size_t mnMatPos;
1737     sc::CompareOptions* mpOptions;
1738     std::vector<double> maResValues;    // double instead of bool to transport error values
1739 
compare()1740     void compare()
1741     {
1742         double fVal = sc::CompareFunc( mrComp, mpOptions);
1743         maResValues.push_back(evaluate(fVal, mrComp.meOp));
1744     }
1745 
1746 public:
CompareMatrixFunc(size_t nResSize,sc::Compare & rComp,size_t nMatPos,sc::CompareOptions * pOptions)1747     CompareMatrixFunc( size_t nResSize, sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) :
1748         mrComp(rComp), mnMatPos(nMatPos), mpOptions(pOptions)
1749     {
1750         maResValues.reserve(nResSize);
1751     }
1752 
1753     CompareMatrixFunc( const CompareMatrixFunc& ) = delete;
1754     CompareMatrixFunc& operator= ( const CompareMatrixFunc& ) = delete;
1755 
CompareMatrixFunc(CompareMatrixFunc && r)1756     CompareMatrixFunc(CompareMatrixFunc&& r) noexcept :
1757         mrComp(r.mrComp),
1758         mnMatPos(r.mnMatPos),
1759         mpOptions(r.mpOptions),
1760         maResValues(std::move(r.maResValues)) {}
1761 
operator =(CompareMatrixFunc && r)1762     CompareMatrixFunc& operator=(CompareMatrixFunc&& r) noexcept
1763     {
1764         mrComp = r.mrComp;
1765         mnMatPos = r.mnMatPos;
1766         mpOptions = r.mpOptions;
1767         maResValues = std::move(r.maResValues);
1768         return *this;
1769     }
1770 
operator ()(const MatrixImplType::element_block_node_type & node)1771     void operator() (const MatrixImplType::element_block_node_type& node)
1772     {
1773         sc::Compare::Cell& rCell = mrComp.maCells[mnMatPos];
1774 
1775         switch (node.type)
1776         {
1777             case mdds::mtm::element_numeric:
1778             {
1779                 typedef MatrixImplType::numeric_block_type block_type;
1780 
1781                 block_type::const_iterator it = block_type::begin(*node.data);
1782                 block_type::const_iterator itEnd = block_type::end(*node.data);
1783                 for (; it != itEnd; ++it)
1784                 {
1785                     rCell.mbValue = true;
1786                     rCell.mbEmpty = false;
1787                     rCell.mfValue = *it;
1788                     compare();
1789                 }
1790             }
1791             break;
1792             case mdds::mtm::element_boolean:
1793             {
1794                 typedef MatrixImplType::boolean_block_type block_type;
1795 
1796                 block_type::const_iterator it = block_type::begin(*node.data);
1797                 block_type::const_iterator itEnd = block_type::end(*node.data);
1798                 for (; it != itEnd; ++it)
1799                 {
1800                     rCell.mbValue = true;
1801                     rCell.mbEmpty = false;
1802                     rCell.mfValue = double(*it);
1803                     compare();
1804                 }
1805             }
1806             break;
1807             case mdds::mtm::element_string:
1808             {
1809                 typedef MatrixImplType::string_block_type block_type;
1810 
1811                 block_type::const_iterator it = block_type::begin(*node.data);
1812                 block_type::const_iterator itEnd = block_type::end(*node.data);
1813                 for (; it != itEnd; ++it)
1814                 {
1815                     const svl::SharedString& rStr = *it;
1816                     rCell.mbValue = false;
1817                     rCell.mbEmpty = false;
1818                     rCell.maStr = rStr;
1819                     compare();
1820                 }
1821             }
1822             break;
1823             case mdds::mtm::element_empty:
1824             {
1825                 rCell.mbValue = false;
1826                 rCell.mbEmpty = true;
1827                 rCell.maStr = svl::SharedString::getEmptyString();
1828                 for (size_t i = 0; i < node.size; ++i)
1829                     compare();
1830             }
1831             break;
1832             default:
1833                 ;
1834         }
1835     }
1836 
getValues() const1837     const std::vector<double>& getValues() const
1838     {
1839         return maResValues;
1840     }
1841 };
1842 
1843 /**
1844  * Left-hand side is a matrix while the right-hand side is a numeric value.
1845  */
1846 class CompareMatrixToNumericFunc
1847 {
1848     sc::Compare& mrComp;
1849     double mfRightValue;
1850     sc::CompareOptions* mpOptions;
1851     std::vector<double> maResValues;    // double instead of bool to transport error values
1852 
compare()1853     void compare()
1854     {
1855         double fVal = sc::CompareFunc(mrComp.maCells[0], mfRightValue, mpOptions);
1856         maResValues.push_back(evaluate(fVal, mrComp.meOp));
1857     }
1858 
compareLeftNumeric(double fLeftVal)1859     void compareLeftNumeric( double fLeftVal )
1860     {
1861         double fVal = sc::CompareFunc(fLeftVal, mfRightValue);
1862         maResValues.push_back(evaluate(fVal, mrComp.meOp));
1863     }
1864 
compareLeftEmpty(size_t nSize)1865     void compareLeftEmpty( size_t nSize )
1866     {
1867         double fVal = sc::CompareEmptyToNumericFunc(mfRightValue);
1868         bool bRes = evaluate(fVal, mrComp.meOp);
1869         maResValues.resize(maResValues.size() + nSize, bRes ? 1.0 : 0.0);
1870     }
1871 
1872 public:
CompareMatrixToNumericFunc(size_t nResSize,sc::Compare & rComp,double fRightValue,sc::CompareOptions * pOptions)1873     CompareMatrixToNumericFunc( size_t nResSize, sc::Compare& rComp, double fRightValue, sc::CompareOptions* pOptions ) :
1874         mrComp(rComp), mfRightValue(fRightValue), mpOptions(pOptions)
1875     {
1876         maResValues.reserve(nResSize);
1877     }
1878 
1879     CompareMatrixToNumericFunc( const CompareMatrixToNumericFunc& ) = delete;
1880     CompareMatrixToNumericFunc& operator= ( const CompareMatrixToNumericFunc& ) = delete;
1881 
CompareMatrixToNumericFunc(CompareMatrixToNumericFunc && r)1882     CompareMatrixToNumericFunc(CompareMatrixToNumericFunc&& r) noexcept :
1883         mrComp(r.mrComp),
1884         mfRightValue(r.mfRightValue),
1885         mpOptions(r.mpOptions),
1886         maResValues(std::move(r.maResValues)) {}
1887 
operator =(CompareMatrixToNumericFunc && r)1888     CompareMatrixToNumericFunc& operator=(CompareMatrixToNumericFunc&& r) noexcept
1889     {
1890         mrComp = r.mrComp;
1891         mfRightValue = r.mfRightValue;
1892         mpOptions = r.mpOptions;
1893         maResValues = std::move(r.maResValues);
1894         return *this;
1895     }
1896 
operator ()(const MatrixImplType::element_block_node_type & node)1897     void operator() (const MatrixImplType::element_block_node_type& node)
1898     {
1899         switch (node.type)
1900         {
1901             case mdds::mtm::element_numeric:
1902             {
1903                 typedef MatrixImplType::numeric_block_type block_type;
1904 
1905                 block_type::const_iterator it = block_type::begin(*node.data);
1906                 block_type::const_iterator itEnd = block_type::end(*node.data);
1907                 for (; it != itEnd; ++it)
1908                     compareLeftNumeric(*it);
1909             }
1910             break;
1911             case mdds::mtm::element_boolean:
1912             {
1913                 typedef MatrixImplType::boolean_block_type block_type;
1914 
1915                 block_type::const_iterator it = block_type::begin(*node.data);
1916                 block_type::const_iterator itEnd = block_type::end(*node.data);
1917                 for (; it != itEnd; ++it)
1918                     compareLeftNumeric(double(*it));
1919             }
1920             break;
1921             case mdds::mtm::element_string:
1922             {
1923                 typedef MatrixImplType::string_block_type block_type;
1924 
1925                 block_type::const_iterator it = block_type::begin(*node.data);
1926                 block_type::const_iterator itEnd = block_type::end(*node.data);
1927                 for (; it != itEnd; ++it)
1928                 {
1929                     const svl::SharedString& rStr = *it;
1930                     sc::Compare::Cell& rCell = mrComp.maCells[0];
1931                     rCell.mbValue = false;
1932                     rCell.mbEmpty = false;
1933                     rCell.maStr = rStr;
1934                     compare();
1935                 }
1936             }
1937             break;
1938             case mdds::mtm::element_empty:
1939                 compareLeftEmpty(node.size);
1940             break;
1941             default:
1942                 ;
1943         }
1944     }
1945 
getValues() const1946     const std::vector<double>& getValues() const
1947     {
1948         return maResValues;
1949     }
1950 };
1951 
1952 class ToDoubleArray
1953 {
1954     std::vector<double> maArray;
1955     std::vector<double>::iterator miPos;
1956     double mfNaN;
1957     bool mbEmptyAsZero;
1958 
moveArray(ToDoubleArray & r)1959     void moveArray( ToDoubleArray& r )
1960     {
1961         // Re-create the iterator from the new array after the array has been
1962         // moved, to ensure that the iterator points to a valid array
1963         // position.
1964         size_t n = std::distance(r.maArray.begin(), r.miPos);
1965         maArray = std::move(r.maArray);
1966         miPos = maArray.begin();
1967         std::advance(miPos, n);
1968     }
1969 
1970 public:
ToDoubleArray(size_t nSize,bool bEmptyAsZero)1971     ToDoubleArray( size_t nSize, bool bEmptyAsZero ) :
1972         maArray(nSize, 0.0), miPos(maArray.begin()), mbEmptyAsZero(bEmptyAsZero)
1973     {
1974         mfNaN = CreateDoubleError( FormulaError::ElementNaN);
1975     }
1976 
1977     ToDoubleArray( const ToDoubleArray& ) = delete;
1978     ToDoubleArray& operator= ( const ToDoubleArray& ) = delete;
1979 
ToDoubleArray(ToDoubleArray && r)1980     ToDoubleArray(ToDoubleArray&& r) noexcept :
1981         mfNaN(r.mfNaN), mbEmptyAsZero(r.mbEmptyAsZero)
1982     {
1983         moveArray(r);
1984     }
1985 
operator =(ToDoubleArray && r)1986     ToDoubleArray& operator=(ToDoubleArray&& r) noexcept
1987     {
1988         mfNaN = r.mfNaN;
1989         mbEmptyAsZero = r.mbEmptyAsZero;
1990         moveArray(r);
1991         return *this;
1992     }
1993 
operator ()(const MatrixImplType::element_block_node_type & node)1994     void operator() (const MatrixImplType::element_block_node_type& node)
1995     {
1996         using namespace mdds::mtv;
1997 
1998         switch (node.type)
1999         {
2000             case mdds::mtm::element_numeric:
2001             {
2002                 double_element_block::const_iterator it = double_element_block::begin(*node.data);
2003                 double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
2004                 for (; it != itEnd; ++it, ++miPos)
2005                     *miPos = *it;
2006             }
2007             break;
2008             case mdds::mtm::element_boolean:
2009             {
2010                 boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
2011                 boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
2012                 for (; it != itEnd; ++it, ++miPos)
2013                     *miPos = *it ? 1.0 : 0.0;
2014             }
2015             break;
2016             case mdds::mtm::element_string:
2017             {
2018                 for (size_t i = 0; i < node.size; ++i, ++miPos)
2019                     *miPos = mfNaN;
2020             }
2021             break;
2022             case mdds::mtm::element_empty:
2023             {
2024                 if (mbEmptyAsZero)
2025                 {
2026                     std::advance(miPos, node.size);
2027                     return;
2028                 }
2029 
2030                 for (size_t i = 0; i < node.size; ++i, ++miPos)
2031                     *miPos = mfNaN;
2032             }
2033             break;
2034             default:
2035                 ;
2036         }
2037     }
2038 
swap(std::vector<double> & rOther)2039     void swap(std::vector<double>& rOther)
2040     {
2041         maArray.swap(rOther);
2042     }
2043 };
2044 
2045 struct ArrayMul
2046 {
operator ()__anon8faf888b0411::ArrayMul2047     double operator() (const double& lhs, const double& rhs) const
2048     {
2049         return lhs * rhs;
2050     }
2051 };
2052 
2053 template<typename Op>
2054 class MergeDoubleArrayFunc
2055 {
2056     std::vector<double>::iterator miPos;
2057     double mfNaN;
2058 public:
MergeDoubleArrayFunc(std::vector<double> & rArray)2059     MergeDoubleArrayFunc(std::vector<double>& rArray) : miPos(rArray.begin())
2060     {
2061         mfNaN = CreateDoubleError( FormulaError::ElementNaN);
2062     }
2063 
2064     MergeDoubleArrayFunc( const MergeDoubleArrayFunc& ) = delete;
2065     MergeDoubleArrayFunc& operator= ( const MergeDoubleArrayFunc& ) = delete;
2066 
2067     MergeDoubleArrayFunc( MergeDoubleArrayFunc&& ) = default;
2068     MergeDoubleArrayFunc& operator= ( MergeDoubleArrayFunc&& ) = default;
2069 
operator ()(const MatrixImplType::element_block_node_type & node)2070     void operator() (const MatrixImplType::element_block_node_type& node)
2071     {
2072         using namespace mdds::mtv;
2073         static const Op op;
2074 
2075         switch (node.type)
2076         {
2077             case mdds::mtm::element_numeric:
2078             {
2079                 double_element_block::const_iterator it = double_element_block::begin(*node.data);
2080                 double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
2081                 for (; it != itEnd; ++it, ++miPos)
2082                 {
2083                     if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2084                         continue;
2085 
2086                     *miPos = op(*miPos, *it);
2087                 }
2088             }
2089             break;
2090             case mdds::mtm::element_boolean:
2091             {
2092                 boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
2093                 boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
2094                 for (; it != itEnd; ++it, ++miPos)
2095                 {
2096                     if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2097                         continue;
2098 
2099                     *miPos = op(*miPos, *it ? 1.0 : 0.0);
2100                 }
2101             }
2102             break;
2103             case mdds::mtm::element_string:
2104             {
2105                 for (size_t i = 0; i < node.size; ++i, ++miPos)
2106                     *miPos = mfNaN;
2107             }
2108             break;
2109             case mdds::mtm::element_empty:
2110             {
2111                 // Empty element is equivalent of having a numeric value of 0.0.
2112                 for (size_t i = 0; i < node.size; ++i, ++miPos)
2113                 {
2114                     if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2115                         continue;
2116 
2117                     *miPos = op(*miPos, 0.0);
2118                 }
2119             }
2120             break;
2121             default:
2122                 ;
2123         }
2124     }
2125 };
2126 
2127 }
2128 
2129 namespace {
2130 
2131 template<typename TOp, typename tRes>
GetValueWithCount(bool bTextAsZero,bool bIgnoreErrorValues,const MatrixImplType & maMat)2132 ScMatrix::IterateResult<tRes> GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorValues, const MatrixImplType& maMat)
2133 {
2134     WalkElementBlocks<TOp, tRes> aFunc(bTextAsZero, bIgnoreErrorValues);
2135     aFunc = maMat.walk(aFunc);
2136     return aFunc.getResult();
2137 }
2138 
2139 }
2140 
Sum(bool bTextAsZero,bool bIgnoreErrorValues) const2141 ScMatrix::KahanIterateResult ScMatrixImpl::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
2142 {
2143     return GetValueWithCount<sc::op::Sum, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2144 }
2145 
SumSquare(bool bTextAsZero,bool bIgnoreErrorValues) const2146 ScMatrix::KahanIterateResult ScMatrixImpl::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
2147 {
2148     return GetValueWithCount<sc::op::SumSquare, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2149 }
2150 
Product(bool bTextAsZero,bool bIgnoreErrorValues) const2151 ScMatrix::DoubleIterateResult ScMatrixImpl::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
2152 {
2153     return GetValueWithCount<sc::op::Product, double>(bTextAsZero, bIgnoreErrorValues, maMat);
2154 }
2155 
Count(bool bCountStrings,bool bCountErrors,bool bIgnoreEmptyStrings) const2156 size_t ScMatrixImpl::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
2157 {
2158     CountElements aFunc(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
2159     aFunc = maMat.walk(aFunc);
2160     return aFunc.getCount();
2161 }
2162 
MatchDoubleInColumns(double fValue,size_t nCol1,size_t nCol2) const2163 size_t ScMatrixImpl::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
2164 {
2165     WalkAndMatchElements<double> aFunc(fValue, maMat.size(), nCol1, nCol2);
2166     aFunc = maMat.walk(aFunc);
2167     return aFunc.getMatching();
2168 }
2169 
MatchStringInColumns(const svl::SharedString & rStr,size_t nCol1,size_t nCol2) const2170 size_t ScMatrixImpl::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
2171 {
2172     WalkAndMatchElements<svl::SharedString> aFunc(rStr, maMat.size(), nCol1, nCol2);
2173     aFunc = maMat.walk(aFunc);
2174     return aFunc.getMatching();
2175 }
2176 
GetMaxValue(bool bTextAsZero,bool bIgnoreErrorValues) const2177 double ScMatrixImpl::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2178 {
2179     CalcMaxMinValue<MaxOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2180     aFunc = maMat.walk(aFunc);
2181     return aFunc.getValue();
2182 }
2183 
GetMinValue(bool bTextAsZero,bool bIgnoreErrorValues) const2184 double ScMatrixImpl::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2185 {
2186     CalcMaxMinValue<MinOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2187     aFunc = maMat.walk(aFunc);
2188     return aFunc.getValue();
2189 }
2190 
GetGcd() const2191 double ScMatrixImpl::GetGcd() const
2192 {
2193     CalcGcdLcm<Gcd> aFunc;
2194     aFunc = maMat.walk(aFunc);
2195     return aFunc.getResult();
2196 }
2197 
GetLcm() const2198 double ScMatrixImpl::GetLcm() const
2199 {
2200     CalcGcdLcm<Lcm> aFunc;
2201     aFunc = maMat.walk(aFunc);
2202     return aFunc.getResult();
2203 }
2204 
CompareMatrix(sc::Compare & rComp,size_t nMatPos,sc::CompareOptions * pOptions) const2205 ScMatrixRef ScMatrixImpl::CompareMatrix(
2206     sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
2207 {
2208     MatrixImplType::size_pair_type aSize = maMat.size();
2209     size_t nSize = aSize.column * aSize.row;
2210     if (nMatPos == 0)
2211     {
2212         if (rComp.maCells[1].mbValue && !rComp.maCells[1].mbEmpty)
2213         {
2214             // Matrix on the left, and a numeric value on the right.  Use a
2215             // function object that has much less branching for much better
2216             // performance.
2217             CompareMatrixToNumericFunc aFunc(nSize, rComp, rComp.maCells[1].mfValue, pOptions);
2218             aFunc = maMat.walk(std::move(aFunc));
2219 
2220             // We assume the result matrix has the same dimension as this matrix.
2221             const std::vector<double>& rResVal = aFunc.getValues();
2222             assert (nSize == rResVal.size());
2223             if (nSize != rResVal.size())
2224                 return ScMatrixRef();
2225 
2226             return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2227         }
2228     }
2229 
2230     CompareMatrixFunc aFunc(nSize, rComp, nMatPos, pOptions);
2231     aFunc = maMat.walk(std::move(aFunc));
2232 
2233     // We assume the result matrix has the same dimension as this matrix.
2234     const std::vector<double>& rResVal = aFunc.getValues();
2235     assert (nSize == rResVal.size());
2236     if (nSize != rResVal.size())
2237         return ScMatrixRef();
2238 
2239     return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2240 }
2241 
GetDoubleArray(std::vector<double> & rArray,bool bEmptyAsZero) const2242 void ScMatrixImpl::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
2243 {
2244     MatrixImplType::size_pair_type aSize = maMat.size();
2245     ToDoubleArray aFunc(aSize.row*aSize.column, bEmptyAsZero);
2246     aFunc = maMat.walk(std::move(aFunc));
2247     aFunc.swap(rArray);
2248 }
2249 
MergeDoubleArrayMultiply(std::vector<double> & rArray) const2250 void ScMatrixImpl::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
2251 {
2252     MatrixImplType::size_pair_type aSize = maMat.size();
2253     size_t nSize = aSize.row*aSize.column;
2254     if (nSize != rArray.size())
2255         return;
2256 
2257     MergeDoubleArrayFunc<ArrayMul> aFunc(rArray);
2258     maMat.walk(std::move(aFunc));
2259 }
2260 
2261 namespace {
2262 
2263 template<typename T, typename U, typename return_type>
2264 struct wrapped_iterator
2265 {
2266     typedef ::std::bidirectional_iterator_tag iterator_category;
2267     typedef typename T::const_iterator::value_type old_value_type;
2268     typedef return_type value_type;
2269     typedef value_type* pointer;
2270     typedef value_type& reference;
2271     typedef typename T::const_iterator::difference_type difference_type;
2272 
2273     typename T::const_iterator it;
2274     mutable value_type val;
2275     U maOp;
2276 
2277 private:
2278 
calcVal__anon8faf888b0611::wrapped_iterator2279     value_type calcVal() const
2280     {
2281         return maOp(*it);
2282     }
2283 
2284 public:
2285 
wrapped_iterator__anon8faf888b0611::wrapped_iterator2286     wrapped_iterator(typename T::const_iterator  it_, U const & aOp):
2287         it(std::move(it_)),
2288         val(value_type()),
2289         maOp(aOp)
2290     {
2291     }
2292 
wrapped_iterator__anon8faf888b0611::wrapped_iterator2293     wrapped_iterator(const wrapped_iterator& r):
2294         it(r.it),
2295         val(r.val),
2296         maOp(r.maOp)
2297     {
2298     }
2299 
operator =__anon8faf888b0611::wrapped_iterator2300     wrapped_iterator& operator=(const wrapped_iterator& r)
2301     {
2302         it = r.it;
2303         return *this;
2304     }
2305 
operator ==__anon8faf888b0611::wrapped_iterator2306     bool operator==(const wrapped_iterator& r) const
2307     {
2308         return it == r.it;
2309     }
2310 
operator !=__anon8faf888b0611::wrapped_iterator2311     bool operator!=(const wrapped_iterator& r) const
2312     {
2313         return !operator==(r);
2314     }
2315 
operator ++__anon8faf888b0611::wrapped_iterator2316     wrapped_iterator& operator++()
2317     {
2318         ++it;
2319 
2320         return *this;
2321     }
2322 
operator --__anon8faf888b0611::wrapped_iterator2323     wrapped_iterator& operator--()
2324     {
2325         --it;
2326 
2327         return *this;
2328     }
2329 
operator *__anon8faf888b0611::wrapped_iterator2330     value_type& operator*() const
2331     {
2332         val = calcVal();
2333         return val;
2334     }
2335 
operator ->__anon8faf888b0611::wrapped_iterator2336     pointer operator->() const
2337     {
2338         val = calcVal();
2339         return &val;
2340     }
2341 };
2342 
2343 template<typename T, typename U, typename return_type>
2344 struct MatrixIteratorWrapper
2345 {
2346 private:
2347     typename T::const_iterator m_itBegin;
2348     typename T::const_iterator m_itEnd;
2349     U maOp;
2350 public:
MatrixIteratorWrapper__anon8faf888b0611::MatrixIteratorWrapper2351     MatrixIteratorWrapper(typename T::const_iterator itBegin, typename T::const_iterator itEnd, U const & aOp):
2352         m_itBegin(std::move(itBegin)),
2353         m_itEnd(std::move(itEnd)),
2354         maOp(aOp)
2355     {
2356     }
2357 
begin__anon8faf888b0611::MatrixIteratorWrapper2358     wrapped_iterator<T, U, return_type> begin()
2359     {
2360         return wrapped_iterator<T, U, return_type>(m_itBegin, maOp);
2361     }
2362 
end__anon8faf888b0611::MatrixIteratorWrapper2363     wrapped_iterator<T, U, return_type> end()
2364     {
2365         return wrapped_iterator<T, U, return_type>(m_itEnd, maOp);
2366     }
2367 };
2368 
increment_position(const MatrixImplType::position_type & pos,size_t n)2369 MatrixImplType::position_type increment_position(const MatrixImplType::position_type& pos, size_t n)
2370 {
2371     MatrixImplType::position_type ret = pos;
2372     do
2373     {
2374         if (ret.second + n < ret.first->size)
2375         {
2376             ret.second += n;
2377             break;
2378         }
2379         else
2380         {
2381             n -= (ret.first->size - ret.second);
2382             ++ret.first;
2383             ret.second = 0;
2384         }
2385     }
2386     while (n > 0);
2387     return ret;
2388 }
2389 
2390 template<typename T>
2391 struct MatrixOpWrapper
2392 {
2393 private:
2394     MatrixImplType& mrMat;
2395     MatrixImplType::position_type pos;
2396     const T* mpOp;
2397 
2398 public:
MatrixOpWrapper__anon8faf888b0611::MatrixOpWrapper2399     MatrixOpWrapper(MatrixImplType& rMat, const T& aOp):
2400         mrMat(rMat),
2401         pos(rMat.position(0,0)),
2402         mpOp(&aOp)
2403     {
2404     }
2405 
MatrixOpWrapper__anon8faf888b0611::MatrixOpWrapper2406     MatrixOpWrapper( const MatrixOpWrapper& r ) : mrMat(r.mrMat), pos(r.pos), mpOp(r.mpOp) {}
2407 
2408     MatrixOpWrapper& operator= ( const MatrixOpWrapper& r ) = default;
2409 
operator ()__anon8faf888b0611::MatrixOpWrapper2410     void operator()(const MatrixImplType::element_block_node_type& node)
2411     {
2412         switch (node.type)
2413         {
2414             case mdds::mtm::element_numeric:
2415             {
2416                 typedef MatrixImplType::numeric_block_type block_type;
2417 
2418                 block_type::const_iterator it = block_type::begin(*node.data);
2419                 block_type::const_iterator itEnd = block_type::end(*node.data);
2420                 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2421                 pos = mrMat.set(pos,aFunc.begin(), aFunc.end());
2422             }
2423             break;
2424             case mdds::mtm::element_boolean:
2425             {
2426                 typedef MatrixImplType::boolean_block_type block_type;
2427 
2428                 block_type::const_iterator it = block_type::begin(*node.data);
2429                 block_type::const_iterator itEnd = block_type::end(*node.data);
2430 
2431                 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2432                 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2433             }
2434             break;
2435             case mdds::mtm::element_string:
2436             {
2437                 typedef MatrixImplType::string_block_type block_type;
2438 
2439                 block_type::const_iterator it = block_type::begin(*node.data);
2440                 block_type::const_iterator itEnd = block_type::end(*node.data);
2441 
2442                 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2443                 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2444             }
2445             break;
2446             case mdds::mtm::element_empty:
2447             {
2448                 if (mpOp->useFunctionForEmpty())
2449                 {
2450                     std::vector<char> aVec(node.size);
2451                     MatrixIteratorWrapper<std::vector<char>, T, typename T::number_value_type>
2452                         aFunc(aVec.begin(), aVec.end(), *mpOp);
2453                     pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2454                 }
2455             }
2456             break;
2457             default:
2458                 ;
2459         }
2460         pos = increment_position(pos, node.size);
2461     }
2462 };
2463 
2464 }
2465 
2466 template<typename T>
ApplyOperation(T aOp,ScMatrixImpl & rMat)2467 void ScMatrixImpl::ApplyOperation(T aOp, ScMatrixImpl& rMat)
2468 {
2469     MatrixOpWrapper<T> aFunc(rMat.maMat, aOp);
2470     maMat.walk(aFunc);
2471 }
2472 
2473 template<typename T, typename tRes>
ApplyCollectOperation(const std::vector<T> & aOp)2474 ScMatrix::IterateResultMultiple<tRes> ScMatrixImpl::ApplyCollectOperation(const std::vector<T>& aOp)
2475 {
2476     WalkElementBlocksMultipleValues<T, tRes> aFunc(aOp);
2477     aFunc = maMat.walk(std::move(aFunc));
2478     return aFunc.getResult();
2479 }
2480 
2481 namespace {
2482 
2483 struct ElementBlock
2484 {
ElementBlock__anon8faf888b0711::ElementBlock2485     ElementBlock(size_t nRowSize,
2486             ScMatrix::DoubleOpFunction aDoubleFunc,
2487             ScMatrix::BoolOpFunction aBoolFunc,
2488             ScMatrix::StringOpFunction aStringFunc,
2489             ScMatrix::EmptyOpFunction aEmptyFunc):
2490         mnRowSize(nRowSize),
2491         mnRowPos(0),
2492         mnColPos(0),
2493         maDoubleFunc(std::move(aDoubleFunc)),
2494         maBoolFunc(std::move(aBoolFunc)),
2495         maStringFunc(std::move(aStringFunc)),
2496         maEmptyFunc(std::move(aEmptyFunc))
2497     {
2498     }
2499 
2500     size_t mnRowSize;
2501     size_t mnRowPos;
2502     size_t mnColPos;
2503 
2504     ScMatrix::DoubleOpFunction maDoubleFunc;
2505     ScMatrix::BoolOpFunction maBoolFunc;
2506     ScMatrix::StringOpFunction maStringFunc;
2507     ScMatrix::EmptyOpFunction maEmptyFunc;
2508 };
2509 
2510 class WalkElementBlockOperation
2511 {
2512 public:
2513 
WalkElementBlockOperation(ElementBlock & rElementBlock)2514     WalkElementBlockOperation(ElementBlock& rElementBlock)
2515         : mrElementBlock(rElementBlock)
2516     {
2517     }
2518 
operator ()(const MatrixImplType::element_block_node_type & node)2519     void operator()(const MatrixImplType::element_block_node_type& node)
2520     {
2521         switch (node.type)
2522         {
2523             case mdds::mtm::element_numeric:
2524             {
2525                 typedef MatrixImplType::numeric_block_type block_type;
2526 
2527                 block_type::const_iterator it = block_type::begin(*node.data);
2528                 std::advance(it, node.offset);
2529                 block_type::const_iterator itEnd = it;
2530                 std::advance(itEnd, node.size);
2531                 for (auto itr = it; itr != itEnd; ++itr)
2532                 {
2533                     mrElementBlock.maDoubleFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2534                     ++mrElementBlock.mnRowPos;
2535                     if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2536                     {
2537                         mrElementBlock.mnRowPos = 0;
2538                         ++mrElementBlock.mnColPos;
2539                     }
2540                 }
2541             }
2542             break;
2543             case mdds::mtm::element_string:
2544             {
2545                 typedef MatrixImplType::string_block_type block_type;
2546 
2547                 block_type::const_iterator it = block_type::begin(*node.data);
2548                 std::advance(it, node.offset);
2549                 block_type::const_iterator itEnd = it;
2550                 std::advance(itEnd, node.size);
2551                 for (auto itr = it; itr != itEnd; ++itr)
2552                 {
2553                     mrElementBlock.maStringFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2554                     ++mrElementBlock.mnRowPos;
2555                     if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2556                     {
2557                         mrElementBlock.mnRowPos = 0;
2558                         ++mrElementBlock.mnColPos;
2559                     }
2560                 }
2561             }
2562             break;
2563             case mdds::mtm::element_boolean:
2564             {
2565                 typedef MatrixImplType::boolean_block_type block_type;
2566 
2567                 block_type::const_iterator it = block_type::begin(*node.data);
2568                 std::advance(it, node.offset);
2569                 block_type::const_iterator itEnd = it;
2570                 std::advance(itEnd, node.size);
2571                 for (auto itr = it; itr != itEnd; ++itr)
2572                 {
2573                     mrElementBlock.maBoolFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2574                     ++mrElementBlock.mnRowPos;
2575                     if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2576                     {
2577                         mrElementBlock.mnRowPos = 0;
2578                         ++mrElementBlock.mnColPos;
2579                     }
2580                 }
2581             }
2582             break;
2583             case mdds::mtm::element_empty:
2584             {
2585                 for (size_t i=0; i < node.size; ++i)
2586                 {
2587                     mrElementBlock.maEmptyFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos);
2588                     ++mrElementBlock.mnRowPos;
2589                     if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2590                     {
2591                         mrElementBlock.mnRowPos = 0;
2592                         ++mrElementBlock.mnColPos;
2593                     }
2594                 }
2595             }
2596             break;
2597             case mdds::mtm::element_integer:
2598             {
2599                 SAL_WARN("sc.core","WalkElementBlockOperation - unhandled element_integer");
2600                 // No function (yet?), but advance row and column count.
2601                 mrElementBlock.mnColPos += node.size / mrElementBlock.mnRowSize;
2602                 mrElementBlock.mnRowPos += node.size % mrElementBlock.mnRowSize;
2603                 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2604                 {
2605                     mrElementBlock.mnRowPos = 0;
2606                     ++mrElementBlock.mnColPos;
2607                 }
2608             }
2609             break;
2610         }
2611     }
2612 
2613 private:
2614 
2615     ElementBlock& mrElementBlock;
2616 };
2617 
2618 }
2619 
ExecuteOperation(const std::pair<size_t,size_t> & rStartPos,const std::pair<size_t,size_t> & rEndPos,const ScMatrix::DoubleOpFunction & aDoubleFunc,const ScMatrix::BoolOpFunction & aBoolFunc,const ScMatrix::StringOpFunction & aStringFunc,const ScMatrix::EmptyOpFunction & aEmptyFunc) const2620 void ScMatrixImpl::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
2621         const std::pair<size_t, size_t>& rEndPos, const ScMatrix::DoubleOpFunction& aDoubleFunc,
2622         const ScMatrix::BoolOpFunction& aBoolFunc, const ScMatrix::StringOpFunction& aStringFunc,
2623         const ScMatrix::EmptyOpFunction& aEmptyFunc) const
2624 {
2625     ElementBlock aPayload(maMat.size().row, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2626     WalkElementBlockOperation aFunc(aPayload);
2627     maMat.walk(
2628         aFunc,
2629         MatrixImplType::size_pair_type(rStartPos.first, rStartPos.second),
2630         MatrixImplType::size_pair_type(rEndPos.first, rEndPos.second));
2631 }
2632 
2633 #if DEBUG_MATRIX
2634 
Dump() const2635 void ScMatrixImpl::Dump() const
2636 {
2637     cout << "-- matrix content" << endl;
2638     SCSIZE nCols, nRows;
2639     GetDimensions(nCols, nRows);
2640     for (SCSIZE nRow = 0; nRow < nRows; ++nRow)
2641     {
2642         for (SCSIZE nCol = 0; nCol < nCols; ++nCol)
2643         {
2644             cout << "  row=" << nRow << ", col=" << nCol << " : ";
2645             switch (maMat.get_type(nRow, nCol))
2646             {
2647                 case mdds::mtm::element_string:
2648                     cout << "string (" << maMat.get_string(nRow, nCol).getString() << ")";
2649                 break;
2650                 case mdds::mtm::element_numeric:
2651                     cout << "numeric (" << maMat.get_numeric(nRow, nCol) << ")";
2652                 break;
2653                 case mdds::mtm::element_boolean:
2654                     cout << "boolean (" << maMat.get_boolean(nRow, nCol) << ")";
2655                 break;
2656                 case mdds::mtm::element_empty:
2657                     cout << "empty";
2658                 break;
2659                 default:
2660                     ;
2661             }
2662 
2663             cout << endl;
2664         }
2665     }
2666 }
2667 #endif
2668 
CalcPosition(SCSIZE nIndex,SCSIZE & rC,SCSIZE & rR) const2669 void ScMatrixImpl::CalcPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const
2670 {
2671     SCSIZE nRowSize = maMat.size().row;
2672     SAL_WARN_IF( !nRowSize, "sc.core", "ScMatrixImpl::CalcPosition: 0 rows!");
2673     rC = nRowSize > 1 ? nIndex / nRowSize : nIndex;
2674     rR = nIndex - rC*nRowSize;
2675 }
2676 
CalcTransPosition(SCSIZE nIndex,SCSIZE & rC,SCSIZE & rR) const2677 void ScMatrixImpl::CalcTransPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const
2678 {
2679     SCSIZE nColSize = maMat.size().column;
2680     SAL_WARN_IF(!nColSize, "sc.core", "ScMatrixImpl::CalcPosition: 0 cols!");
2681     rR = nColSize > 1 ? nIndex / nColSize : nIndex;
2682     rC = nIndex - rR * nColSize;
2683 }
2684 
2685 namespace {
2686 
get_index(SCSIZE nMaxRow,size_t nRow,size_t nCol,size_t nRowOffset,size_t nColOffset)2687 size_t get_index(SCSIZE nMaxRow, size_t nRow, size_t nCol, size_t nRowOffset, size_t nColOffset)
2688 {
2689     return nMaxRow * (nCol + nColOffset) + nRow + nRowOffset;
2690 }
2691 
2692 }
2693 
MatConcat(SCSIZE nMaxCol,SCSIZE nMaxRow,const ScMatrixRef & xMat1,const ScMatrixRef & xMat2,ScInterpreterContext & rContext,svl::SharedStringPool & rStringPool)2694 void ScMatrixImpl::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
2695             ScInterpreterContext& rContext, svl::SharedStringPool& rStringPool)
2696 {
2697     SCSIZE nC1, nC2;
2698     SCSIZE nR1, nR2;
2699     xMat1->GetDimensions(nC1, nR1);
2700     xMat2->GetDimensions(nC2, nR2);
2701 
2702     sal_uInt32 nKey = rContext.NFGetStandardFormat( SvNumFormatType::NUMBER,
2703             ScGlobal::eLnge);
2704 
2705     std::vector<OUString> aString(nMaxCol * nMaxRow);
2706     std::vector<bool> aValid(nMaxCol * nMaxRow, true);
2707     std::vector<FormulaError> nErrors(nMaxCol * nMaxRow,FormulaError::NONE);
2708 
2709     size_t nRowOffset = 0;
2710     size_t nColOffset = 0;
2711     std::function<void(size_t, size_t, double)> aDoubleFunc =
2712         [&](size_t nRow, size_t nCol, double nVal)
2713         {
2714             FormulaError nErr = GetDoubleErrorValue(nVal);
2715             if (nErr != FormulaError::NONE)
2716             {
2717                 aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2718                 nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2719                 return;
2720             }
2721             OUString aStr;
2722             rContext.NFGetInputLineString( nVal, nKey, aStr);
2723             aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2724         };
2725 
2726     std::function<void(size_t, size_t, bool)> aBoolFunc =
2727         [&](size_t nRow, size_t nCol, bool nVal)
2728         {
2729             OUString aStr;
2730             rContext.NFGetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2731             aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2732         };
2733 
2734     std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc =
2735         [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2736         {
2737             aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString();
2738         };
2739 
2740     std::function<void(size_t, size_t)> aEmptyFunc =
2741         [](size_t /*nRow*/, size_t /*nCol*/)
2742         {
2743             // Nothing. Concatenating an empty string to an existing string.
2744         };
2745 
2746 
2747     if (nC1 == 1 || nR1 == 1)
2748     {
2749         size_t nRowRep = nR1 == 1 ? nMaxRow : 1;
2750         size_t nColRep = nC1 == 1 ? nMaxCol : 1;
2751 
2752         for (size_t i = 0; i < nRowRep; ++i)
2753         {
2754             nRowOffset = i;
2755             for (size_t j = 0; j < nColRep; ++j)
2756             {
2757                 nColOffset = j;
2758                 xMat1->ExecuteOperation(
2759                         std::pair<size_t, size_t>(0, 0),
2760                         std::pair<size_t, size_t>(std::min(nR1, nMaxRow) - 1, std::min(nC1, nMaxCol) - 1),
2761                         aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2762             }
2763         }
2764     }
2765     else
2766         xMat1->ExecuteOperation(
2767                 std::pair<size_t, size_t>(0, 0),
2768                 std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2769                 std::move(aDoubleFunc), std::move(aBoolFunc), std::move(aStringFunc), std::move(aEmptyFunc));
2770 
2771     std::vector<svl::SharedString> aSharedString(nMaxCol*nMaxRow);
2772 
2773     std::function<void(size_t, size_t, double)> aDoubleFunc2 =
2774         [&](size_t nRow, size_t nCol, double nVal)
2775         {
2776             FormulaError nErr = GetDoubleErrorValue(nVal);
2777             if (nErr != FormulaError::NONE)
2778             {
2779                 aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2780                 nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2781                 return;
2782             }
2783             OUString aStr;
2784             rContext.NFGetInputLineString( nVal, nKey, aStr);
2785             aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2786         };
2787 
2788     std::function<void(size_t, size_t, bool)> aBoolFunc2 =
2789         [&](size_t nRow, size_t nCol, bool nVal)
2790         {
2791             OUString aStr;
2792             rContext.NFGetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2793             aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2794         };
2795 
2796     std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc2 =
2797         [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2798         {
2799             aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2800                 rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString());
2801         };
2802 
2803     std::function<void(size_t, size_t)> aEmptyFunc2 =
2804         [&](size_t nRow, size_t nCol)
2805         {
2806             aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2807                 rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)]);
2808         };
2809 
2810     nRowOffset = 0;
2811     nColOffset = 0;
2812     if (nC2 == 1 || nR2 == 1)
2813     {
2814         size_t nRowRep = nR2 == 1 ? nMaxRow : 1;
2815         size_t nColRep = nC2 == 1 ? nMaxCol : 1;
2816 
2817         for (size_t i = 0; i < nRowRep; ++i)
2818         {
2819             nRowOffset = i;
2820             for (size_t j = 0; j < nColRep; ++j)
2821             {
2822                 nColOffset = j;
2823                 xMat2->ExecuteOperation(
2824                         std::pair<size_t, size_t>(0, 0),
2825                         std::pair<size_t, size_t>(std::min(nR2, nMaxRow) - 1, std::min(nC2, nMaxCol) - 1),
2826                         aDoubleFunc2, aBoolFunc2, aStringFunc2, aEmptyFunc2);
2827             }
2828         }
2829     }
2830     else
2831         xMat2->ExecuteOperation(
2832                 std::pair<size_t, size_t>(0, 0),
2833                 std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2834                 std::move(aDoubleFunc2), std::move(aBoolFunc2), std::move(aStringFunc2), std::move(aEmptyFunc2));
2835 
2836     aString.clear();
2837 
2838     MatrixImplType::position_type pos = maMat.position(0, 0);
2839     for (SCSIZE i = 0; i < nMaxCol; ++i)
2840     {
2841         for (SCSIZE j = 0; j < nMaxRow && i < nMaxCol; ++j)
2842         {
2843             if (aValid[nMaxRow * i + j])
2844             {
2845                 auto itr = aValid.begin();
2846                 std::advance(itr, nMaxRow * i + j);
2847                 auto itrEnd = std::find(itr, aValid.end(), false);
2848                 size_t nSteps = std::distance(itr, itrEnd);
2849                 auto itrStr = aSharedString.begin();
2850                 std::advance(itrStr, nMaxRow * i + j);
2851                 auto itrEndStr = itrStr;
2852                 std::advance(itrEndStr, nSteps);
2853                 pos = maMat.set(pos, itrStr, itrEndStr);
2854                 size_t nColSteps = nSteps / nMaxRow;
2855                 i += nColSteps;
2856                 j += nSteps % nMaxRow;
2857                 if (j >= nMaxRow)
2858                 {
2859                     j -= nMaxRow;
2860                     ++i;
2861                 }
2862             }
2863             else
2864             {
2865                 pos = maMat.set(pos, CreateDoubleError(nErrors[nMaxRow * i + j]));
2866             }
2867             pos = MatrixImplType::next_position(pos);
2868         }
2869     }
2870 }
2871 
IsValueOrEmpty(const MatrixImplType::const_position_type & rPos) const2872 bool ScMatrixImpl::IsValueOrEmpty( const MatrixImplType::const_position_type & rPos ) const
2873 {
2874     switch (maMat.get_type(rPos))
2875     {
2876         case mdds::mtm::element_boolean:
2877         case mdds::mtm::element_numeric:
2878         case mdds::mtm::element_empty:
2879             return true;
2880         default:
2881             ;
2882     }
2883     return false;
2884 }
2885 
GetDouble(const MatrixImplType::const_position_type & rPos) const2886 double ScMatrixImpl::GetDouble(const MatrixImplType::const_position_type & rPos) const
2887 {
2888     double fVal = maMat.get_numeric(rPos);
2889     if ( pErrorInterpreter )
2890     {
2891         FormulaError nError = GetDoubleErrorValue(fVal);
2892         if ( nError != FormulaError::NONE )
2893             SetErrorAtInterpreter( nError);
2894     }
2895     return fVal;
2896 }
2897 
GetErrorIfNotString(const MatrixImplType::const_position_type & rPos) const2898 FormulaError ScMatrixImpl::GetErrorIfNotString( const MatrixImplType::const_position_type & rPos ) const
2899 { return IsValue(rPos) ? GetError(rPos) : FormulaError::NONE; }
2900 
IsValue(const MatrixImplType::const_position_type & rPos) const2901 bool ScMatrixImpl::IsValue( const MatrixImplType::const_position_type & rPos ) const
2902 {
2903     switch (maMat.get_type(rPos))
2904     {
2905         case mdds::mtm::element_boolean:
2906         case mdds::mtm::element_numeric:
2907             return true;
2908         default:
2909             ;
2910     }
2911     return false;
2912 }
2913 
GetError(const MatrixImplType::const_position_type & rPos) const2914 FormulaError ScMatrixImpl::GetError(const MatrixImplType::const_position_type & rPos) const
2915 {
2916     double fVal = maMat.get_numeric(rPos);
2917     return GetDoubleErrorValue(fVal);
2918 }
2919 
IsStringOrEmpty(const MatrixImplType::const_position_type & rPos) const2920 bool ScMatrixImpl::IsStringOrEmpty(const MatrixImplType::const_position_type & rPos) const
2921 {
2922     switch (maMat.get_type(rPos))
2923     {
2924         case mdds::mtm::element_empty:
2925         case mdds::mtm::element_string:
2926             return true;
2927         default:
2928             ;
2929     }
2930     return false;
2931 }
2932 
ExecuteBinaryOp(SCSIZE nMaxCol,SCSIZE nMaxRow,const ScMatrix & rInputMat1,const ScMatrix & rInputMat2,ScInterpreter * pInterpreter,const ScMatrix::CalculateOpFunction & Op)2933 void ScMatrixImpl::ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
2934     ScInterpreter* pInterpreter, const ScMatrix::CalculateOpFunction& Op)
2935 {
2936     // Check output matrix size, otherwise output iterator logic will be wrong.
2937     assert(maMat.size().row == nMaxRow && maMat.size().column == nMaxCol
2938         && "the caller code should have sized the output matrix to the passed dimensions");
2939     auto & rMatImpl1 = *rInputMat1.pImpl;
2940     auto & rMatImpl2 = *rInputMat2.pImpl;
2941     // Check if we can do fast-path, where we have no replication or mis-matched matrix sizes.
2942     if (rMatImpl1.maMat.size() == rMatImpl2.maMat.size()
2943         && rMatImpl1.maMat.size() == maMat.size())
2944     {
2945         MatrixImplType::position_type aOutPos = maMat.position(0, 0);
2946         MatrixImplType::const_position_type aPos1 = rMatImpl1.maMat.position(0, 0);
2947         MatrixImplType::const_position_type aPos2 = rMatImpl2.maMat.position(0, 0);
2948         for (SCSIZE i = 0; i < nMaxCol; i++)
2949         {
2950             for (SCSIZE j = 0; j < nMaxRow; j++)
2951             {
2952                 bool bVal1 = rMatImpl1.IsValueOrEmpty(aPos1);
2953                 bool bVal2 = rMatImpl2.IsValueOrEmpty(aPos2);
2954                 FormulaError nErr;
2955                 if (bVal1 && bVal2)
2956                 {
2957                     double d = Op(rMatImpl1.GetDouble(aPos1), rMatImpl2.GetDouble(aPos2));
2958                     aOutPos = maMat.set(aOutPos, d);
2959                 }
2960                 else if (((nErr = rMatImpl1.GetErrorIfNotString(aPos1)) != FormulaError::NONE) ||
2961                          ((nErr = rMatImpl2.GetErrorIfNotString(aPos2)) != FormulaError::NONE))
2962                 {
2963                     aOutPos = maMat.set(aOutPos, CreateDoubleError(nErr));
2964                 }
2965                 else if ((!bVal1 && rMatImpl1.IsStringOrEmpty(aPos1)) ||
2966                          (!bVal2 && rMatImpl2.IsStringOrEmpty(aPos2)))
2967                 {
2968                     FormulaError nError1 = FormulaError::NONE;
2969                     SvNumFormatType nFmt1 = SvNumFormatType::ALL;
2970                     double fVal1 = (bVal1 ? rMatImpl1.GetDouble(aPos1) :
2971                             pInterpreter->ConvertStringToValue( rMatImpl1.GetString(aPos1).getString(), nError1, nFmt1));
2972 
2973                     FormulaError nError2 = FormulaError::NONE;
2974                     SvNumFormatType nFmt2 = SvNumFormatType::ALL;
2975                     double fVal2 = (bVal2 ? rMatImpl2.GetDouble(aPos2) :
2976                             pInterpreter->ConvertStringToValue( rMatImpl2.GetString(aPos2).getString(), nError2, nFmt2));
2977 
2978                     if (nError1 != FormulaError::NONE)
2979                         aOutPos = maMat.set(aOutPos, CreateDoubleError(nError1));
2980                     else if (nError2 != FormulaError::NONE)
2981                         aOutPos = maMat.set(aOutPos, CreateDoubleError(nError2));
2982                     else
2983                     {
2984                         double d = Op( fVal1, fVal2);
2985                         aOutPos = maMat.set(aOutPos, d);
2986                     }
2987                 }
2988                 else
2989                     aOutPos = maMat.set(aOutPos, CreateDoubleError(FormulaError::NoValue));
2990                 aPos1 = MatrixImplType::next_position(aPos1);
2991                 aPos2 = MatrixImplType::next_position(aPos2);
2992                 aOutPos = MatrixImplType::next_position(aOutPos);
2993             }
2994         }
2995     }
2996     else
2997     {
2998         // Noting that this block is very hard to optimise to use iterators, because various dodgy
2999         // array function usage relies on the semantics of some of the methods we call here.
3000         // (see unit test testDubiousArrayFormulasFODS).
3001         // These methods are inconsistent in their usage of ValidColRowReplicated() vs. ValidColRowOrReplicated()
3002         // which leads to some very odd results.
3003         MatrixImplType::position_type aOutPos = maMat.position(0, 0);
3004         for (SCSIZE i = 0; i < nMaxCol; i++)
3005         {
3006             for (SCSIZE j = 0; j < nMaxRow; j++)
3007             {
3008                 bool bVal1 = rInputMat1.IsValueOrEmpty(i,j);
3009                 bool bVal2 = rInputMat2.IsValueOrEmpty(i,j);
3010                 FormulaError nErr;
3011                 if (bVal1 && bVal2)
3012                 {
3013                     double d = Op(rInputMat1.GetDouble(i,j), rInputMat2.GetDouble(i,j));
3014                     aOutPos = maMat.set(aOutPos, d);
3015                 }
3016                 else if (((nErr = rInputMat1.GetErrorIfNotString(i,j)) != FormulaError::NONE) ||
3017                          ((nErr = rInputMat2.GetErrorIfNotString(i,j)) != FormulaError::NONE))
3018                 {
3019                     aOutPos = maMat.set(aOutPos, CreateDoubleError(nErr));
3020                 }
3021                 else if ((!bVal1 && rInputMat1.IsStringOrEmpty(i,j)) || (!bVal2 && rInputMat2.IsStringOrEmpty(i,j)))
3022                 {
3023                     FormulaError nError1 = FormulaError::NONE;
3024                     SvNumFormatType nFmt1 = SvNumFormatType::ALL;
3025                     double fVal1 = (bVal1 ? rInputMat1.GetDouble(i,j) :
3026                             pInterpreter->ConvertStringToValue( rInputMat1.GetString(i,j).getString(), nError1, nFmt1));
3027 
3028                     FormulaError nError2 = FormulaError::NONE;
3029                     SvNumFormatType nFmt2 = SvNumFormatType::ALL;
3030                     double fVal2 = (bVal2 ? rInputMat2.GetDouble(i,j) :
3031                             pInterpreter->ConvertStringToValue( rInputMat2.GetString(i,j).getString(), nError2, nFmt2));
3032 
3033                     if (nError1 != FormulaError::NONE)
3034                         aOutPos = maMat.set(aOutPos, CreateDoubleError(nError1));
3035                     else if (nError2 != FormulaError::NONE)
3036                         aOutPos = maMat.set(aOutPos, CreateDoubleError(nError2));
3037                     else
3038                     {
3039                         double d = Op( fVal1, fVal2);
3040                         aOutPos = maMat.set(aOutPos, d);
3041                     }
3042                 }
3043                 else
3044                     aOutPos = maMat.set(aOutPos, CreateDoubleError(FormulaError::NoValue));
3045                 aOutPos = MatrixImplType::next_position(aOutPos);
3046             }
3047         }
3048     }
3049 }
3050 
IncRef() const3051 void ScMatrix::IncRef() const
3052 {
3053     ++nRefCnt;
3054 }
3055 
DecRef() const3056 void ScMatrix::DecRef() const
3057 {
3058     --nRefCnt;
3059     if (nRefCnt == 0)
3060         delete this;
3061 }
3062 
IsSizeAllocatable(SCSIZE nC,SCSIZE nR)3063 bool ScMatrix::IsSizeAllocatable( SCSIZE nC, SCSIZE nR )
3064 {
3065     SAL_WARN_IF( !nC, "sc.core", "ScMatrix with 0 columns!");
3066     SAL_WARN_IF( !nR, "sc.core", "ScMatrix with 0 rows!");
3067     // 0-size matrix is valid, it could be resized later.
3068     if ((nC && !nR) || (!nC && nR))
3069     {
3070         SAL_WARN( "sc.core", "ScMatrix one-dimensional zero: " << nC << " columns * " << nR << " rows");
3071         return false;
3072     }
3073     if (!nC || !nR)
3074         return true;
3075 
3076     std::call_once(bElementsMaxFetched,
3077         []()
3078         {
3079             const char* pEnv = std::getenv("SC_MAX_MATRIX_ELEMENTS");
3080             if (pEnv)
3081             {
3082                 // Environment specifies the overall elements pool.
3083                 nElementsMax = std::atoi(pEnv);
3084             }
3085             else
3086             {
3087                 // GetElementsMax() uses an (~arbitrary) elements limit.
3088                 // The actual allocation depends on the types of individual matrix
3089                 // elements and is averaged for type double.
3090 #if SAL_TYPES_SIZEOFPOINTER < 8
3091                 // Assume 1GB memory could be consumed by matrices.
3092                 constexpr size_t nMemMax = 0x40000000;
3093 #else
3094                 // Assume 6GB memory could be consumed by matrices.
3095                 constexpr size_t nMemMax = 0x180000000;
3096 #endif
3097                 nElementsMax = GetElementsMax( nMemMax);
3098             }
3099         });
3100 
3101     if (nC > (nElementsMax / nR))
3102     {
3103         SAL_WARN( "sc.core", "ScMatrix overflow: " << nC << " columns * " << nR << " rows");
3104         return false;
3105     }
3106     return true;
3107 }
3108 
ScMatrix(SCSIZE nC,SCSIZE nR)3109 ScMatrix::ScMatrix( SCSIZE nC, SCSIZE nR) :
3110     nRefCnt(0), mbCloneIfConst(true)
3111 {
3112     if (ScMatrix::IsSizeAllocatable( nC, nR))
3113         pImpl.reset( new ScMatrixImpl( nC, nR));
3114     else
3115         // Invalid matrix size, allocate 1x1 matrix with error value.
3116         pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
3117 }
3118 
ScMatrix(SCSIZE nC,SCSIZE nR,double fInitVal)3119 ScMatrix::ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal) :
3120     nRefCnt(0), mbCloneIfConst(true)
3121 {
3122     if (ScMatrix::IsSizeAllocatable( nC, nR))
3123         pImpl.reset( new ScMatrixImpl( nC, nR, fInitVal));
3124     else
3125         // Invalid matrix size, allocate 1x1 matrix with error value.
3126         pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
3127 }
3128 
ScMatrix(size_t nC,size_t nR,const std::vector<double> & rInitVals)3129 ScMatrix::ScMatrix( size_t nC, size_t nR, const std::vector<double>& rInitVals ) :
3130     nRefCnt(0), mbCloneIfConst(true)
3131 {
3132     if (ScMatrix::IsSizeAllocatable( nC, nR))
3133         pImpl.reset( new ScMatrixImpl( nC, nR, rInitVals));
3134     else
3135         // Invalid matrix size, allocate 1x1 matrix with error value.
3136         pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
3137 }
3138 
~ScMatrix()3139 ScMatrix::~ScMatrix()
3140 {
3141 }
3142 
Clone() const3143 ScMatrix* ScMatrix::Clone() const
3144 {
3145     SCSIZE nC, nR;
3146     pImpl->GetDimensions(nC, nR);
3147     ScMatrix* pScMat = new ScMatrix(nC, nR);
3148     MatCopy(*pScMat);
3149     pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter());    // TODO: really?
3150     return pScMat;
3151 }
3152 
CloneIfConst()3153 ScMatrix* ScMatrix::CloneIfConst()
3154 {
3155     return mbCloneIfConst ? Clone() : this;
3156 }
3157 
SetMutable()3158 void ScMatrix::SetMutable()
3159 {
3160     mbCloneIfConst = false;
3161 }
3162 
SetImmutable() const3163 void ScMatrix::SetImmutable() const
3164 {
3165     mbCloneIfConst = true;
3166 }
3167 
Resize(SCSIZE nC,SCSIZE nR)3168 void ScMatrix::Resize( SCSIZE nC, SCSIZE nR)
3169 {
3170     pImpl->Resize(nC, nR);
3171 }
3172 
Resize(SCSIZE nC,SCSIZE nR,double fVal)3173 void ScMatrix::Resize(SCSIZE nC, SCSIZE nR, double fVal)
3174 {
3175     pImpl->Resize(nC, nR, fVal);
3176 }
3177 
CloneAndExtend(SCSIZE nNewCols,SCSIZE nNewRows) const3178 ScMatrix* ScMatrix::CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const
3179 {
3180     ScMatrix* pScMat = new ScMatrix(nNewCols, nNewRows);
3181     MatCopy(*pScMat);
3182     pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter());
3183     return pScMat;
3184 }
3185 
SetErrorInterpreter(ScInterpreter * p)3186 void ScMatrix::SetErrorInterpreter( ScInterpreter* p)
3187 {
3188     pImpl->SetErrorInterpreter(p);
3189 }
3190 
GetDimensions(SCSIZE & rC,SCSIZE & rR) const3191 void ScMatrix::GetDimensions( SCSIZE& rC, SCSIZE& rR) const
3192 {
3193     pImpl->GetDimensions(rC, rR);
3194 }
3195 
GetElementCount() const3196 SCSIZE ScMatrix::GetElementCount() const
3197 {
3198     return pImpl->GetElementCount();
3199 }
3200 
ValidColRow(SCSIZE nC,SCSIZE nR) const3201 bool ScMatrix::ValidColRow( SCSIZE nC, SCSIZE nR) const
3202 {
3203     return pImpl->ValidColRow(nC, nR);
3204 }
3205 
ValidColRowReplicated(SCSIZE & rC,SCSIZE & rR) const3206 bool ScMatrix::ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const
3207 {
3208     return pImpl->ValidColRowReplicated(rC, rR);
3209 }
3210 
ValidColRowOrReplicated(SCSIZE & rC,SCSIZE & rR) const3211 bool ScMatrix::ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const
3212 {
3213     return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
3214 }
3215 
PutDouble(double fVal,SCSIZE nC,SCSIZE nR)3216 void ScMatrix::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
3217 {
3218     pImpl->PutDouble(fVal, nC, nR);
3219 }
3220 
PutDouble(double fVal,SCSIZE nIndex)3221 void ScMatrix::PutDouble( double fVal, SCSIZE nIndex)
3222 {
3223     pImpl->PutDouble(fVal, nIndex);
3224 }
3225 
PutDoubleTrans(double fVal,SCSIZE nIndex)3226 void ScMatrix::PutDoubleTrans(double fVal, SCSIZE nIndex)
3227 {
3228     pImpl->PutDoubleTrans(fVal, nIndex);
3229 }
3230 
PutDouble(const double * pArray,size_t nLen,SCSIZE nC,SCSIZE nR)3231 void ScMatrix::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3232 {
3233     pImpl->PutDouble(pArray, nLen, nC, nR);
3234 }
3235 
PutString(const svl::SharedString & rStr,SCSIZE nC,SCSIZE nR)3236 void ScMatrix::PutString(const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR)
3237 {
3238     pImpl->PutString(rStr, nC, nR);
3239 }
3240 
PutString(const svl::SharedString & rStr,SCSIZE nIndex)3241 void ScMatrix::PutString(const svl::SharedString& rStr, SCSIZE nIndex)
3242 {
3243     pImpl->PutString(rStr, nIndex);
3244 }
3245 
PutStringTrans(const svl::SharedString & rStr,SCSIZE nIndex)3246 void ScMatrix::PutStringTrans(const svl::SharedString& rStr, SCSIZE nIndex)
3247 {
3248     pImpl->PutStringTrans(rStr, nIndex);
3249 }
3250 
PutString(const svl::SharedString * pArray,size_t nLen,SCSIZE nC,SCSIZE nR)3251 void ScMatrix::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3252 {
3253     pImpl->PutString(pArray, nLen, nC, nR);
3254 }
3255 
PutEmpty(SCSIZE nC,SCSIZE nR)3256 void ScMatrix::PutEmpty(SCSIZE nC, SCSIZE nR)
3257 {
3258     pImpl->PutEmpty(nC, nR);
3259 }
3260 
PutEmpty(SCSIZE nIndex)3261 void ScMatrix::PutEmpty(SCSIZE nIndex)
3262 {
3263     pImpl->PutEmpty(nIndex);
3264 }
3265 
PutEmptyTrans(SCSIZE nIndex)3266 void ScMatrix::PutEmptyTrans(SCSIZE nIndex)
3267 {
3268     pImpl->PutEmptyTrans(nIndex);
3269 }
3270 
PutEmptyPath(SCSIZE nC,SCSIZE nR)3271 void ScMatrix::PutEmptyPath(SCSIZE nC, SCSIZE nR)
3272 {
3273     pImpl->PutEmptyPath(nC, nR);
3274 }
3275 
PutError(FormulaError nErrorCode,SCSIZE nC,SCSIZE nR)3276 void ScMatrix::PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR )
3277 {
3278     pImpl->PutError(nErrorCode, nC, nR);
3279 }
3280 
PutBoolean(bool bVal,SCSIZE nC,SCSIZE nR)3281 void ScMatrix::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
3282 {
3283     pImpl->PutBoolean(bVal, nC, nR);
3284 }
3285 
GetError(SCSIZE nC,SCSIZE nR) const3286 FormulaError ScMatrix::GetError( SCSIZE nC, SCSIZE nR) const
3287 {
3288     return pImpl->GetError(nC, nR);
3289 }
3290 
GetDouble(SCSIZE nC,SCSIZE nR) const3291 double ScMatrix::GetDouble(SCSIZE nC, SCSIZE nR) const
3292 {
3293     return pImpl->GetDouble(nC, nR);
3294 }
3295 
GetDouble(SCSIZE nIndex) const3296 double ScMatrix::GetDouble( SCSIZE nIndex) const
3297 {
3298     return pImpl->GetDouble(nIndex);
3299 }
3300 
GetDoubleWithStringConversion(SCSIZE nC,SCSIZE nR) const3301 double ScMatrix::GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
3302 {
3303     return pImpl->GetDoubleWithStringConversion(nC, nR);
3304 }
3305 
GetString(SCSIZE nC,SCSIZE nR) const3306 svl::SharedString ScMatrix::GetString(SCSIZE nC, SCSIZE nR) const
3307 {
3308     return pImpl->GetString(nC, nR);
3309 }
3310 
GetString(SCSIZE nIndex) const3311 svl::SharedString ScMatrix::GetString( SCSIZE nIndex) const
3312 {
3313     return pImpl->GetString(nIndex);
3314 }
3315 
GetString(ScInterpreterContext & rContext,SCSIZE nC,SCSIZE nR) const3316 svl::SharedString ScMatrix::GetString( ScInterpreterContext& rContext, SCSIZE nC, SCSIZE nR) const
3317 {
3318     return pImpl->GetString(rContext, nC, nR);
3319 }
3320 
Get(SCSIZE nC,SCSIZE nR) const3321 ScMatrixValue ScMatrix::Get(SCSIZE nC, SCSIZE nR) const
3322 {
3323     return pImpl->Get(nC, nR);
3324 }
3325 
IsStringOrEmpty(SCSIZE nIndex) const3326 bool ScMatrix::IsStringOrEmpty( SCSIZE nIndex ) const
3327 {
3328     return pImpl->IsStringOrEmpty(nIndex);
3329 }
3330 
IsStringOrEmpty(SCSIZE nC,SCSIZE nR) const3331 bool ScMatrix::IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const
3332 {
3333     return pImpl->IsStringOrEmpty(nC, nR);
3334 }
3335 
IsEmpty(SCSIZE nC,SCSIZE nR) const3336 bool ScMatrix::IsEmpty( SCSIZE nC, SCSIZE nR ) const
3337 {
3338     return pImpl->IsEmpty(nC, nR);
3339 }
3340 
IsEmptyCell(SCSIZE nC,SCSIZE nR) const3341 bool ScMatrix::IsEmptyCell( SCSIZE nC, SCSIZE nR ) const
3342 {
3343     return pImpl->IsEmptyCell(nC, nR);
3344 }
3345 
IsEmptyResult(SCSIZE nC,SCSIZE nR) const3346 bool ScMatrix::IsEmptyResult( SCSIZE nC, SCSIZE nR ) const
3347 {
3348     return pImpl->IsEmptyResult(nC, nR);
3349 }
3350 
IsEmptyPath(SCSIZE nC,SCSIZE nR) const3351 bool ScMatrix::IsEmptyPath( SCSIZE nC, SCSIZE nR ) const
3352 {
3353     return pImpl->IsEmptyPath(nC, nR);
3354 }
3355 
IsValue(SCSIZE nIndex) const3356 bool ScMatrix::IsValue( SCSIZE nIndex ) const
3357 {
3358     return pImpl->IsValue(nIndex);
3359 }
3360 
IsValue(SCSIZE nC,SCSIZE nR) const3361 bool ScMatrix::IsValue( SCSIZE nC, SCSIZE nR ) const
3362 {
3363     return pImpl->IsValue(nC, nR);
3364 }
3365 
IsValueOrEmpty(SCSIZE nC,SCSIZE nR) const3366 bool ScMatrix::IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const
3367 {
3368     return pImpl->IsValueOrEmpty(nC, nR);
3369 }
3370 
IsBoolean(SCSIZE nC,SCSIZE nR) const3371 bool ScMatrix::IsBoolean( SCSIZE nC, SCSIZE nR ) const
3372 {
3373     return pImpl->IsBoolean(nC, nR);
3374 }
3375 
IsNumeric() const3376 bool ScMatrix::IsNumeric() const
3377 {
3378     return pImpl->IsNumeric();
3379 }
3380 
MatCopy(const ScMatrix & mRes) const3381 void ScMatrix::MatCopy(const ScMatrix& mRes) const
3382 {
3383     pImpl->MatCopy(*mRes.pImpl);
3384 }
3385 
MatTrans(const ScMatrix & mRes) const3386 void ScMatrix::MatTrans(const ScMatrix& mRes) const
3387 {
3388     pImpl->MatTrans(*mRes.pImpl);
3389 }
3390 
FillDouble(double fVal,SCSIZE nC1,SCSIZE nR1,SCSIZE nC2,SCSIZE nR2)3391 void ScMatrix::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
3392 {
3393     pImpl->FillDouble(fVal, nC1, nR1, nC2, nR2);
3394 }
3395 
PutDoubleVector(const::std::vector<double> & rVec,SCSIZE nC,SCSIZE nR)3396 void ScMatrix::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
3397 {
3398     pImpl->PutDoubleVector(rVec, nC, nR);
3399 }
3400 
PutStringVector(const::std::vector<svl::SharedString> & rVec,SCSIZE nC,SCSIZE nR)3401 void ScMatrix::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
3402 {
3403     pImpl->PutStringVector(rVec, nC, nR);
3404 }
3405 
PutEmptyVector(SCSIZE nCount,SCSIZE nC,SCSIZE nR)3406 void ScMatrix::PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
3407 {
3408     pImpl->PutEmptyVector(nCount, nC, nR);
3409 }
3410 
PutEmptyResultVector(SCSIZE nCount,SCSIZE nC,SCSIZE nR)3411 void ScMatrix::PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
3412 {
3413     pImpl->PutEmptyResultVector(nCount, nC, nR);
3414 }
3415 
PutEmptyPathVector(SCSIZE nCount,SCSIZE nC,SCSIZE nR)3416 void ScMatrix::PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR )
3417 {
3418     pImpl->PutEmptyPathVector(nCount, nC, nR);
3419 }
3420 
CompareEqual()3421 void ScMatrix::CompareEqual()
3422 {
3423     pImpl->CompareEqual();
3424 }
3425 
CompareNotEqual()3426 void ScMatrix::CompareNotEqual()
3427 {
3428     pImpl->CompareNotEqual();
3429 }
3430 
CompareLess()3431 void ScMatrix::CompareLess()
3432 {
3433     pImpl->CompareLess();
3434 }
3435 
CompareGreater()3436 void ScMatrix::CompareGreater()
3437 {
3438     pImpl->CompareGreater();
3439 }
3440 
CompareLessEqual()3441 void ScMatrix::CompareLessEqual()
3442 {
3443     pImpl->CompareLessEqual();
3444 }
3445 
CompareGreaterEqual()3446 void ScMatrix::CompareGreaterEqual()
3447 {
3448     pImpl->CompareGreaterEqual();
3449 }
3450 
And() const3451 double ScMatrix::And() const
3452 {
3453     return pImpl->And();
3454 }
3455 
Or() const3456 double ScMatrix::Or() const
3457 {
3458     return pImpl->Or();
3459 }
3460 
Xor() const3461 double ScMatrix::Xor() const
3462 {
3463     return pImpl->Xor();
3464 }
3465 
Sum(bool bTextAsZero,bool bIgnoreErrorValues) const3466 ScMatrix::KahanIterateResult ScMatrix::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
3467 {
3468     return pImpl->Sum(bTextAsZero, bIgnoreErrorValues);
3469 }
3470 
SumSquare(bool bTextAsZero,bool bIgnoreErrorValues) const3471 ScMatrix::KahanIterateResult ScMatrix::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
3472 {
3473     return pImpl->SumSquare(bTextAsZero, bIgnoreErrorValues);
3474 }
3475 
Product(bool bTextAsZero,bool bIgnoreErrorValues) const3476 ScMatrix::DoubleIterateResult ScMatrix::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
3477 {
3478     return pImpl->Product(bTextAsZero, bIgnoreErrorValues);
3479 }
3480 
Count(bool bCountStrings,bool bCountErrors,bool bIgnoreEmptyStrings) const3481 size_t ScMatrix::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
3482 {
3483     return pImpl->Count(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
3484 }
3485 
MatchDoubleInColumns(double fValue,size_t nCol1,size_t nCol2) const3486 size_t ScMatrix::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
3487 {
3488     return pImpl->MatchDoubleInColumns(fValue, nCol1, nCol2);
3489 }
3490 
MatchStringInColumns(const svl::SharedString & rStr,size_t nCol1,size_t nCol2) const3491 size_t ScMatrix::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
3492 {
3493     return pImpl->MatchStringInColumns(rStr, nCol1, nCol2);
3494 }
3495 
GetMaxValue(bool bTextAsZero,bool bIgnoreErrorValues) const3496 double ScMatrix::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3497 {
3498     return pImpl->GetMaxValue(bTextAsZero, bIgnoreErrorValues);
3499 }
3500 
GetMinValue(bool bTextAsZero,bool bIgnoreErrorValues) const3501 double ScMatrix::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3502 {
3503     return pImpl->GetMinValue(bTextAsZero, bIgnoreErrorValues);
3504 }
3505 
GetGcd() const3506 double ScMatrix::GetGcd() const
3507 {
3508     return pImpl->GetGcd();
3509 }
3510 
GetLcm() const3511 double ScMatrix::GetLcm() const
3512 {
3513     return pImpl->GetLcm();
3514 }
3515 
3516 
CompareMatrix(sc::Compare & rComp,size_t nMatPos,sc::CompareOptions * pOptions) const3517 ScMatrixRef ScMatrix::CompareMatrix(
3518     sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
3519 {
3520     return pImpl->CompareMatrix(rComp, nMatPos, pOptions);
3521 }
3522 
GetDoubleArray(std::vector<double> & rArray,bool bEmptyAsZero) const3523 void ScMatrix::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
3524 {
3525     pImpl->GetDoubleArray(rArray, bEmptyAsZero);
3526 }
3527 
MergeDoubleArrayMultiply(std::vector<double> & rArray) const3528 void ScMatrix::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
3529 {
3530     pImpl->MergeDoubleArrayMultiply(rArray);
3531 }
3532 
3533 namespace matop {
3534 
3535 namespace {
3536 
3537 /** A template for operations where operands are supposed to be numeric.
3538     A non-numeric (string) operand leads to the configured conversion to number
3539     method being called if in interpreter context and a FormulaError::NoValue DoubleError
3540     if conversion was not possible, else to an unconditional FormulaError::NoValue
3541     DoubleError.
3542     An empty operand evaluates to 0.
3543  */
3544 template<typename TOp>
3545 struct MatOp
3546 {
3547 private:
3548     TOp maOp;
3549     ScInterpreter* mpErrorInterpreter;
3550     double mfVal;
3551 
3552 public:
3553     typedef double number_value_type;
3554 
MatOpmatop::__anon8faf888b1211::MatOp3555     MatOp( TOp aOp, ScInterpreter* pErrorInterpreter,
3556             double fVal = 0.0 ):
3557         maOp(aOp),
3558         mpErrorInterpreter(pErrorInterpreter),
3559         mfVal(fVal)
3560     {
3561         if (mpErrorInterpreter)
3562         {
3563             FormulaError nErr = mpErrorInterpreter->GetError();
3564             if (nErr != FormulaError::NONE)
3565                 mfVal = CreateDoubleError( nErr);
3566         }
3567     }
3568 
operator ()matop::__anon8faf888b1211::MatOp3569     double operator()(double fVal) const
3570     {
3571         return maOp(fVal, mfVal);
3572     }
3573 
operator ()matop::__anon8faf888b1211::MatOp3574     double operator()(bool bVal) const
3575     {
3576         return maOp(static_cast<double>(bVal), mfVal);
3577     }
3578 
operator ()matop::__anon8faf888b1211::MatOp3579     double operator()(const svl::SharedString& rStr) const
3580     {
3581         return maOp( convertStringToValue( mpErrorInterpreter, rStr.getString()), mfVal);
3582     }
3583 
3584     /// the action for empty entries in a matrix
operator ()matop::__anon8faf888b1211::MatOp3585     double operator()(char) const
3586     {
3587         return maOp(0, mfVal);
3588     }
3589 
useFunctionForEmptymatop::__anon8faf888b1211::MatOp3590     static bool useFunctionForEmpty()
3591     {
3592         return true;
3593     }
3594 };
3595 
3596 }
3597 
3598 }
3599 
NotOp(const ScMatrix & rMat)3600 void ScMatrix::NotOp( const ScMatrix& rMat)
3601 {
3602     auto not_ = [](double a, double){return double(a == 0.0);};
3603     matop::MatOp<decltype(not_)> aOp(not_, pImpl->GetErrorInterpreter());
3604     pImpl->ApplyOperation(aOp, *rMat.pImpl);
3605 }
3606 
NegOp(const ScMatrix & rMat)3607 void ScMatrix::NegOp( const ScMatrix& rMat)
3608 {
3609     auto neg_ = [](double a, double){return -a;};
3610     matop::MatOp<decltype(neg_)> aOp(neg_, pImpl->GetErrorInterpreter());
3611     pImpl->ApplyOperation(aOp, *rMat.pImpl);
3612 }
3613 
AddOp(double fVal,const ScMatrix & rMat)3614 void ScMatrix::AddOp( double fVal, const ScMatrix& rMat)
3615 {
3616     auto add_ = [](double a, double b){return a + b;};
3617     matop::MatOp<decltype(add_)> aOp(add_, pImpl->GetErrorInterpreter(), fVal);
3618     pImpl->ApplyOperation(aOp, *rMat.pImpl);
3619 }
3620 
SubOp(bool bFlag,double fVal,const ScMatrix & rMat)3621 void ScMatrix::SubOp( bool bFlag, double fVal, const ScMatrix& rMat)
3622 {
3623     if (bFlag)
3624     {
3625         auto sub_ = [](double a, double b){return b - a;};
3626         matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3627         pImpl->ApplyOperation(aOp, *rMat.pImpl);
3628     }
3629     else
3630     {
3631         auto sub_ = [](double a, double b){return a - b;};
3632         matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3633         pImpl->ApplyOperation(aOp, *rMat.pImpl);
3634     }
3635 }
3636 
MulOp(double fVal,const ScMatrix & rMat)3637 void ScMatrix::MulOp( double fVal, const ScMatrix& rMat)
3638 {
3639     auto mul_ = [](double a, double b){return a * b;};
3640     matop::MatOp<decltype(mul_)> aOp(mul_, pImpl->GetErrorInterpreter(), fVal);
3641     pImpl->ApplyOperation(aOp, *rMat.pImpl);
3642 }
3643 
DivOp(bool bFlag,double fVal,const ScMatrix & rMat)3644 void ScMatrix::DivOp( bool bFlag, double fVal, const ScMatrix& rMat)
3645 {
3646     if (bFlag)
3647     {
3648         auto div_ = [](double a, double b){return sc::div(b, a);};
3649         matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3650         pImpl->ApplyOperation(aOp, *rMat.pImpl);
3651     }
3652     else
3653     {
3654         auto div_ = [](double a, double b){return sc::div(a, b);};
3655         matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3656         pImpl->ApplyOperation(aOp, *rMat.pImpl);
3657     }
3658 }
3659 
PowOp(bool bFlag,double fVal,const ScMatrix & rMat)3660 void ScMatrix::PowOp( bool bFlag, double fVal, const ScMatrix& rMat)
3661 {
3662     if (bFlag)
3663     {
3664         auto pow_ = [](double a, double b){return sc::power(b, a);};
3665         matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3666         pImpl->ApplyOperation(aOp, *rMat.pImpl);
3667     }
3668     else
3669     {
3670         auto pow_ = [](double a, double b){return sc::power(a, b);};
3671         matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3672         pImpl->ApplyOperation(aOp, *rMat.pImpl);
3673     }
3674 }
3675 
ExecuteOperation(const std::pair<size_t,size_t> & rStartPos,const std::pair<size_t,size_t> & rEndPos,DoubleOpFunction aDoubleFunc,BoolOpFunction aBoolFunc,StringOpFunction aStringFunc,EmptyOpFunction aEmptyFunc) const3676 void ScMatrix::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
3677         const std::pair<size_t, size_t>& rEndPos, DoubleOpFunction aDoubleFunc,
3678         BoolOpFunction aBoolFunc, StringOpFunction aStringFunc, EmptyOpFunction aEmptyFunc) const
3679 {
3680     pImpl->ExecuteOperation(rStartPos, rEndPos, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
3681 }
3682 
CollectKahan(const std::vector<sc::op::kOp> & aOp)3683 ScMatrix::KahanIterateResultMultiple ScMatrix::CollectKahan(const std::vector<sc::op::kOp>& aOp)
3684 {
3685     return pImpl->ApplyCollectOperation<sc::op::kOp, KahanSum>(aOp);
3686 }
3687 
3688 #if DEBUG_MATRIX
Dump() const3689 void ScMatrix::Dump() const
3690 {
3691     pImpl->Dump();
3692 }
3693 #endif
3694 
MatConcat(SCSIZE nMaxCol,SCSIZE nMaxRow,const ScMatrixRef & xMat1,const ScMatrixRef & xMat2,ScInterpreterContext & rContext,svl::SharedStringPool & rPool)3695 void ScMatrix::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow,
3696         const ScMatrixRef& xMat1, const ScMatrixRef& xMat2, ScInterpreterContext& rContext, svl::SharedStringPool& rPool)
3697 {
3698     pImpl->MatConcat(nMaxCol, nMaxRow, xMat1, xMat2, rContext, rPool);
3699 }
3700 
ExecuteBinaryOp(SCSIZE nMaxCol,SCSIZE nMaxRow,const ScMatrix & rInputMat1,const ScMatrix & rInputMat2,ScInterpreter * pInterpreter,const CalculateOpFunction & op)3701 void ScMatrix::ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
3702             ScInterpreter* pInterpreter, const CalculateOpFunction& op)
3703 {
3704     pImpl->ExecuteBinaryOp(nMaxCol, nMaxRow, rInputMat1, rInputMat2, pInterpreter, op);
3705 }
3706 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3707