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