LibreOffice Module sc (master)  1
scmatrix.cxx
Go to the documentation of this file.
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/zforlist.hxx>
31 #include <svl/sharedstring.hxx>
32 #include <rtl/math.hxx>
33 #include <sal/log.hxx>
34 #include <osl/diagnose.h>
35 
36 #include <memory>
37 #include <vector>
38 #include <limits>
39 
40 #include <mdds/multi_type_matrix.hpp>
41 #include <mdds/multi_type_vector_types.hpp>
42 
43 #if DEBUG_MATRIX
44 #include <iostream>
45 using std::cout;
46 using std::endl;
47 #endif
48 
49 using ::std::pair;
50 using ::std::advance;
51 
52 namespace {
53 
58 struct matrix_trait
59 {
60  typedef sc::string_block string_element_block;
61  typedef sc::uint16_block integer_element_block;
62 
63  typedef mdds::mtv::custom_block_func1<sc::string_block> element_block_func;
64 };
65 
66 }
67 
68 typedef mdds::multi_type_matrix<matrix_trait> MatrixImplType;
69 
70 namespace {
71 
72 double convertStringToValue( ScInterpreter* pErrorInterpreter, const OUString& rStr )
73 {
74  if (pErrorInterpreter)
75  {
76  FormulaError nError = FormulaError::NONE;
77  SvNumFormatType nCurFmtType = SvNumFormatType::ALL;
78  double fValue = pErrorInterpreter->ConvertStringToValue( rStr, nError, nCurFmtType);
79  if (nError != FormulaError::NONE)
80  {
81  pErrorInterpreter->SetError( nError);
82  return CreateDoubleError( nError);
83  }
84  return fValue;
85  }
86  return CreateDoubleError( FormulaError::NoValue);
87 }
88 
89 struct ElemEqualZero
90 {
91  double operator() (double val) const
92  {
93  if (!std::isfinite(val))
94  return val;
95  return val == 0.0 ? 1.0 : 0.0;
96  }
97 };
98 
99 struct ElemNotEqualZero
100 {
101  double operator() (double val) const
102  {
103  if (!std::isfinite(val))
104  return val;
105  return val != 0.0 ? 1.0 : 0.0;
106  }
107 };
108 
109 struct ElemGreaterZero
110 {
111  double operator() (double val) const
112  {
113  if (!std::isfinite(val))
114  return val;
115  return val > 0.0 ? 1.0 : 0.0;
116  }
117 };
118 
119 struct ElemLessZero
120 {
121  double operator() (double val) const
122  {
123  if (!std::isfinite(val))
124  return val;
125  return val < 0.0 ? 1.0 : 0.0;
126  }
127 };
128 
129 struct ElemGreaterEqualZero
130 {
131  double operator() (double val) const
132  {
133  if (!std::isfinite(val))
134  return val;
135  return val >= 0.0 ? 1.0 : 0.0;
136  }
137 };
138 
139 struct ElemLessEqualZero
140 {
141  double operator() (double val) const
142  {
143  if (!std::isfinite(val))
144  return val;
145  return val <= 0.0 ? 1.0 : 0.0;
146  }
147 };
148 
149 template<typename Comp>
150 class CompareMatrixElemFunc
151 {
152  static Comp maComp;
153 
154  std::vector<double> maNewMatValues; // double instead of bool to transport error values
155  size_t mnRow;
156  size_t mnCol;
157 public:
158  CompareMatrixElemFunc( size_t nRow, size_t nCol ) : mnRow(nRow), mnCol(nCol)
159  {
160  maNewMatValues.reserve(nRow*nCol);
161  }
162 
163  CompareMatrixElemFunc( const CompareMatrixElemFunc& ) = delete;
164  CompareMatrixElemFunc& operator= ( const CompareMatrixElemFunc& ) = delete;
165 
166  CompareMatrixElemFunc( CompareMatrixElemFunc&& ) = default;
167  CompareMatrixElemFunc& operator= ( CompareMatrixElemFunc&& ) = default;
168 
169  void operator() (const MatrixImplType::element_block_node_type& node)
170  {
171  switch (node.type)
172  {
173  case mdds::mtm::element_numeric:
174  {
175  typedef MatrixImplType::numeric_block_type block_type;
176 
177  block_type::const_iterator it = block_type::begin(*node.data);
178  block_type::const_iterator itEnd = block_type::end(*node.data);
179  for (; it != itEnd; ++it)
180  {
181  double fVal = *it;
182  maNewMatValues.push_back(maComp(fVal));
183  }
184  }
185  break;
186  case mdds::mtm::element_boolean:
187  {
188  typedef MatrixImplType::boolean_block_type block_type;
189 
190  block_type::const_iterator it = block_type::begin(*node.data);
191  block_type::const_iterator itEnd = block_type::end(*node.data);
192  for (; it != itEnd; ++it)
193  {
194  double fVal = *it ? 1.0 : 0.0;
195  maNewMatValues.push_back(maComp(fVal));
196  }
197  }
198  break;
199  case mdds::mtm::element_string:
200  case mdds::mtm::element_empty:
201  default:
202  // Fill it with false.
203  maNewMatValues.resize(maNewMatValues.size() + node.size, 0.0);
204  }
205  }
206 
207  void swap( MatrixImplType& rMat )
208  {
209  MatrixImplType aNewMat(mnRow, mnCol, maNewMatValues.begin(), maNewMatValues.end());
210  rMat.swap(aNewMat);
211  }
212 };
213 
214 template<typename Comp>
215 Comp CompareMatrixElemFunc<Comp>::maComp;
216 
217 }
218 
219 /* TODO: it would be good if mdds had get/set<sal_uInt8> additionally to
220  * get/set<bool>, we're abusing double here. */
221 typedef double TMatFlag;
224 
226 {
230 
231 public:
232  ScMatrixImpl(const ScMatrixImpl&) = delete;
233  const ScMatrixImpl& operator=(const ScMatrixImpl&) = delete;
234 
235  ScMatrixImpl(SCSIZE nC, SCSIZE nR);
236  ScMatrixImpl(SCSIZE nC, SCSIZE nR, double fInitVal);
237 
238  ScMatrixImpl( size_t nC, size_t nR, const std::vector<double>& rInitVals );
239 
240  ~ScMatrixImpl() COVERITY_NOEXCEPT_FALSE;
241 
242  void Clear();
243  void Resize(SCSIZE nC, SCSIZE nR);
244  void Resize(SCSIZE nC, SCSIZE nR, double fVal);
247 
248  void GetDimensions( SCSIZE& rC, SCSIZE& rR) const;
249  SCSIZE GetElementCount() const;
250  bool ValidColRow( SCSIZE nC, SCSIZE nR) const;
251  bool ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const;
252  bool ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const;
253  void SetErrorAtInterpreter( FormulaError nError ) const;
254 
255  void PutDouble(double fVal, SCSIZE nC, SCSIZE nR);
256  void PutDouble( double fVal, SCSIZE nIndex);
257  void PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR);
258 
259  void PutString(const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR);
260  void PutString(const svl::SharedString& rStr, SCSIZE nIndex);
261  void PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR);
262 
263  void PutEmpty(SCSIZE nC, SCSIZE nR);
264  void PutEmptyPath(SCSIZE nC, SCSIZE nR);
265  void PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR );
266  void PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR);
267  FormulaError GetError( SCSIZE nC, SCSIZE nR) const;
268  double GetDouble(SCSIZE nC, SCSIZE nR) const;
269  double GetDouble( SCSIZE nIndex) const;
270  double GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const;
272  svl::SharedString GetString( SCSIZE nIndex) const;
273  svl::SharedString GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const;
274  ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const;
275  bool IsStringOrEmpty( SCSIZE nIndex ) const;
276  bool IsStringOrEmpty( SCSIZE nC, SCSIZE nR ) const;
277  bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;
278  bool IsEmptyCell( SCSIZE nC, SCSIZE nR ) const;
279  bool IsEmptyResult( SCSIZE nC, SCSIZE nR ) const;
280  bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const;
281  bool IsValue( SCSIZE nIndex ) const;
282  bool IsValue( SCSIZE nC, SCSIZE nR ) const;
283  bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const;
284  bool IsBoolean( SCSIZE nC, SCSIZE nR ) const;
285  bool IsNumeric() const;
286 
287  void MatCopy(ScMatrixImpl& mRes) const;
288  void MatTrans(ScMatrixImpl& mRes) const;
289  void FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 );
290  void PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR );
291  void PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR );
292  void PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
293  void PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
294  void PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
295  void CompareEqual();
296  void CompareNotEqual();
297  void CompareLess();
298  void CompareGreater();
299  void CompareLessEqual();
300  void CompareGreaterEqual();
301  double And() const;
302  double Or() const;
303  double Xor() const;
304 
305  ScMatrix::IterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues ) const;
306  ScMatrix::IterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues ) const;
307  ScMatrix::IterateResult Product( bool bTextAsZero, bool bIgnoreErrorValues ) const;
308  size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const;
309  size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const;
310  size_t MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const;
311 
312  double GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const;
313  double GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const;
314  double GetGcd() const;
315  double GetLcm() const;
316 
317  ScMatrixRef CompareMatrix( sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const;
318 
319  void GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const;
320  void MergeDoubleArrayMultiply( std::vector<double>& rArray ) const;
321 
322  template<typename T>
323  void ApplyOperation(T aOp, ScMatrixImpl& rMat);
324 
325  void ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
326  const std::pair<size_t, size_t>& rEndPos, const ScMatrix::DoubleOpFunction& aDoubleFunc,
327  const ScMatrix::BoolOpFunction& aBoolFunc, const ScMatrix::StringOpFunction& aStringFunc,
328  const ScMatrix::EmptyOpFunction& aEmptyFunc) const;
329 
330  template<typename T>
331  std::vector<ScMatrix::IterateResult> ApplyCollectOperation(const std::vector<T>& aOp);
332 
333  void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
334  SvNumberFormatter& rFormatter, svl::SharedStringPool& rPool);
335 
336 #if DEBUG_MATRIX
337  void Dump() const;
338 #endif
339 
340 private:
341  void CalcPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const;
342 };
343 
345 static size_t nElementsMax;
346 
355 static size_t GetElementsMax( size_t nMemory )
356 {
357  // Arbitrarily assuming 12 bytes per element, 8 bytes double plus
358  // overhead. Stored as an array in an mdds container it's less, but for
359  // strings or mixed matrix it can be much more...
360  constexpr size_t nPerElem = 12;
361  if (nMemory)
362  return nMemory / nPerElem;
363 
364  // Arbitrarily assuming 1GB memory. Could be dynamic at some point.
365  constexpr size_t nMemMax = 0x40000000;
366  // With 1GB that's ~85M elements, or 85 whole columns.
367  constexpr size_t nElemMax = nMemMax / nPerElem;
368  // With MAXROWCOUNT==1048576 and 128 columns => 128M elements, 1.5GB
369  constexpr size_t nArbitraryLimit = size_t(MAXROWCOUNT) * 128;
370  // With the constant 1GB from above that's the actual value.
371  return std::min(nElemMax, nArbitraryLimit);
372 }
373 
375  maMat(nR, nC), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
376 {
378 }
379 
380 ScMatrixImpl::ScMatrixImpl(SCSIZE nC, SCSIZE nR, double fInitVal) :
381  maMat(nR, nC, fInitVal), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
382 {
384 }
385 
386 ScMatrixImpl::ScMatrixImpl( size_t nC, size_t nR, const std::vector<double>& rInitVals ) :
387  maMat(nR, nC, rInitVals.begin(), rInitVals.end()), maMatFlag(nR, nC), pErrorInterpreter(nullptr)
388 {
390 }
391 
392 ScMatrixImpl::~ScMatrixImpl() COVERITY_NOEXCEPT_FALSE
393 {
395  Clear();
396 }
397 
399 {
400  maMat.clear();
401  maMatFlag.clear();
402 }
403 
405 {
407  if (ScMatrix::IsSizeAllocatable( nC, nR))
408  {
409  maMat.resize(nR, nC);
410  maMatFlag.resize(nR, nC);
411  }
412  else
413  {
414  // Invalid matrix size, allocate 1x1 matrix with error value.
415  maMat.resize(1, 1, CreateDoubleError( FormulaError::MatrixSize));
416  maMatFlag.resize(1, 1);
417  }
419 }
420 
421 void ScMatrixImpl::Resize(SCSIZE nC, SCSIZE nR, double fVal)
422 {
424  if (ScMatrix::IsSizeAllocatable( nC, nR))
425  {
426  maMat.resize(nR, nC, fVal);
427  maMatFlag.resize(nR, nC);
428  }
429  else
430  {
431  // Invalid matrix size, allocate 1x1 matrix with error value.
432  maMat.resize(1, 1, CreateDoubleError( FormulaError::StackOverflow));
433  maMatFlag.resize(1, 1);
434  }
436 }
437 
439 {
440  pErrorInterpreter = p;
441 }
442 
444 {
445  MatrixImplType::size_pair_type aSize = maMat.size();
446  rR = aSize.row;
447  rC = aSize.column;
448 }
449 
451 {
452  MatrixImplType::size_pair_type aSize = maMat.size();
453  return aSize.row * aSize.column;
454 }
455 
457 {
458  MatrixImplType::size_pair_type aSize = maMat.size();
459  return nR < aSize.row && nC < aSize.column;
460 }
461 
463 {
464  MatrixImplType::size_pair_type aSize = maMat.size();
465  if (aSize.column == 1 && aSize.row == 1)
466  {
467  rC = 0;
468  rR = 0;
469  return true;
470  }
471  else if (aSize.column == 1 && rR < aSize.row)
472  {
473  // single column matrix.
474  rC = 0;
475  return true;
476  }
477  else if (aSize.row == 1 && rC < aSize.column)
478  {
479  // single row matrix.
480  rR = 0;
481  return true;
482  }
483  return false;
484 }
485 
487 {
488  return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
489 }
490 
492 {
493  if ( pErrorInterpreter )
494  pErrorInterpreter->SetError( nError);
495 }
496 
497 void ScMatrixImpl::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
498 {
499  if (ValidColRow( nC, nR))
500  maMat.set(nR, nC, fVal);
501  else
502  {
503  OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
504  }
505 }
506 
507 void ScMatrixImpl::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
508 {
509  if (ValidColRow( nC, nR))
510  maMat.set(nR, nC, pArray, pArray + nLen);
511  else
512  {
513  OSL_FAIL("ScMatrixImpl::PutDouble: dimension error");
514  }
515 }
516 
517 void ScMatrixImpl::PutDouble( double fVal, SCSIZE nIndex)
518 {
519  SCSIZE nC, nR;
520  CalcPosition(nIndex, nC, nR);
521  PutDouble(fVal, nC, nR);
522 }
523 
525 {
526  if (ValidColRow( nC, nR))
527  maMat.set(nR, nC, rStr);
528  else
529  {
530  OSL_FAIL("ScMatrixImpl::PutString: dimension error");
531  }
532 }
533 
534 void ScMatrixImpl::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
535 {
536  if (ValidColRow( nC, nR))
537  maMat.set(nR, nC, pArray, pArray + nLen);
538  else
539  {
540  OSL_FAIL("ScMatrixImpl::PutString: dimension error");
541  }
542 }
543 
545 {
546  SCSIZE nC, nR;
547  CalcPosition(nIndex, nC, nR);
548  PutString(rStr, nC, nR);
549 }
550 
552 {
553  if (ValidColRow( nC, nR))
554  {
555  maMat.set_empty(nR, nC);
556  maMatFlag.set_empty(nR, nC);
557  }
558  else
559  {
560  OSL_FAIL("ScMatrixImpl::PutEmpty: dimension error");
561  }
562 }
563 
565 {
566  if (ValidColRow( nC, nR))
567  {
568  maMat.set_empty(nR, nC);
569  maMatFlag.set(nR, nC, SC_MATFLAG_EMPTYPATH);
570  }
571  else
572  {
573  OSL_FAIL("ScMatrixImpl::PutEmptyPath: dimension error");
574  }
575 }
576 
578 {
579  maMat.set(nR, nC, CreateDoubleError(nErrorCode));
580 }
581 
582 void ScMatrixImpl::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
583 {
584  if (ValidColRow( nC, nR))
585  maMat.set(nR, nC, bVal);
586  else
587  {
588  OSL_FAIL("ScMatrixImpl::PutBoolean: dimension error");
589  }
590 }
591 
593 {
594  if (ValidColRowOrReplicated( nC, nR ))
595  {
596  double fVal = maMat.get_numeric(nR, nC);
597  return GetDoubleErrorValue(fVal);
598  }
599  else
600  {
601  OSL_FAIL("ScMatrixImpl::GetError: dimension error");
602  return FormulaError::NoValue;
603  }
604 }
605 
607 {
608  if (ValidColRowOrReplicated( nC, nR ))
609  {
610  double fVal = maMat.get_numeric(nR, nC);
611  if ( pErrorInterpreter )
612  {
613  FormulaError nError = GetDoubleErrorValue(fVal);
614  if ( nError != FormulaError::NONE )
615  SetErrorAtInterpreter( nError);
616  }
617  return fVal;
618  }
619  else
620  {
621  OSL_FAIL("ScMatrixImpl::GetDouble: dimension error");
622  return CreateDoubleError( FormulaError::NoValue);
623  }
624 }
625 
626 double ScMatrixImpl::GetDouble( SCSIZE nIndex) const
627 {
628  SCSIZE nC, nR;
629  CalcPosition(nIndex, nC, nR);
630  return GetDouble(nC, nR);
631 }
632 
634 {
635  ScMatrixValue aMatVal = Get(nC, nR);
636  if (aMatVal.nType == ScMatValType::String)
637  return convertStringToValue( pErrorInterpreter, aMatVal.aStr.getString());
638  return aMatVal.fVal;
639 }
640 
642 {
643  if (ValidColRowOrReplicated( nC, nR ))
644  {
645  double fErr = 0.0;
646  MatrixImplType::const_position_type aPos = maMat.position(nR, nC);
647  switch (maMat.get_type(aPos))
648  {
649  case mdds::mtm::element_string:
650  return maMat.get_string(aPos);
651  case mdds::mtm::element_empty:
653  case mdds::mtm::element_numeric:
654  case mdds::mtm::element_boolean:
655  fErr = maMat.get_numeric(aPos);
656  [[fallthrough]];
657  default:
658  OSL_FAIL("ScMatrixImpl::GetString: access error, no string");
659  }
661  }
662  else
663  {
664  OSL_FAIL("ScMatrixImpl::GetString: dimension error");
665  }
667 }
668 
670 {
671  SCSIZE nC, nR;
672  CalcPosition(nIndex, nC, nR);
673  return GetString(nC, nR);
674 }
675 
677 {
678  if (!ValidColRowOrReplicated( nC, nR ))
679  {
680  OSL_FAIL("ScMatrixImpl::GetString: dimension error");
682  }
683 
684  double fVal = 0.0;
685  MatrixImplType::const_position_type aPos = maMat.position(nR, nC);
686  switch (maMat.get_type(aPos))
687  {
688  case mdds::mtm::element_string:
689  return maMat.get_string(aPos);
690  case mdds::mtm::element_empty:
691  {
692  if (maMatFlag.get_numeric(nR, nC) != SC_MATFLAG_EMPTYPATH)
693  // not an empty path.
695 
696  // result of empty FALSE jump path
697  sal_uInt32 nKey = rFormatter.GetStandardFormat( SvNumFormatType::LOGICAL,
699  OUString aStr;
700  const Color* pColor = nullptr;
701  rFormatter.GetOutputString( 0.0, nKey, aStr, &pColor);
702  return svl::SharedString( aStr); // string not interned
703  }
704  case mdds::mtm::element_numeric:
705  case mdds::mtm::element_boolean:
706  fVal = maMat.get_numeric(aPos);
707  break;
708  default:
709  ;
710  }
711 
712  FormulaError nError = GetDoubleErrorValue(fVal);
713  if (nError != FormulaError::NONE)
714  {
715  SetErrorAtInterpreter( nError);
716  return svl::SharedString( ScGlobal::GetErrorString( nError)); // string not interned
717  }
718 
719  sal_uInt32 nKey = rFormatter.GetStandardFormat( SvNumFormatType::NUMBER,
721  OUString aStr;
722  rFormatter.GetInputLineString( fVal, nKey, aStr);
723  return svl::SharedString( aStr); // string not interned
724 }
725 
727 {
728  ScMatrixValue aVal;
729  if (ValidColRowOrReplicated(nC, nR))
730  {
731  MatrixImplType::const_position_type aPos = maMat.position(nR, nC);
732  mdds::mtm::element_t eType = maMat.get_type(aPos);
733  switch (eType)
734  {
735  case mdds::mtm::element_boolean:
737  aVal.fVal = double(maMat.get_boolean(aPos));
738  break;
739  case mdds::mtm::element_numeric:
740  aVal.nType = ScMatValType::Value;
741  aVal.fVal = maMat.get_numeric(aPos);
742  break;
743  case mdds::mtm::element_string:
745  aVal.aStr = maMat.get_string(aPos);
746  break;
747  case mdds::mtm::element_empty:
748  /* TODO: do we need to pass the differentiation of 'empty' and
749  * 'empty result' to the outer world anywhere? */
750  switch (maMatFlag.get_type(nR, nC))
751  {
752  case mdds::mtm::element_empty:
753  aVal.nType = ScMatValType::Empty;
754  break;
755  case mdds::mtm::element_numeric:
756  aVal.nType = maMatFlag.get<TMatFlag>(nR, nC)
758  break;
759  default:
760  assert(false);
761  }
762  aVal.fVal = 0.0;
763  break;
764  default:
765  ;
766  }
767  }
768  else
769  {
770  OSL_FAIL("ScMatrixImpl::Get: dimension error");
771  }
772  return aVal;
773 }
774 
776 {
777  SCSIZE nC, nR;
778  CalcPosition(nIndex, nC, nR);
779  return IsStringOrEmpty(nC, nR);
780 }
781 
783 {
784  ValidColRowReplicated( nC, nR );
785  switch (maMat.get_type(nR, nC))
786  {
787  case mdds::mtm::element_empty:
788  case mdds::mtm::element_string:
789  return true;
790  default:
791  ;
792  }
793  return false;
794 }
795 
796 bool ScMatrixImpl::IsEmpty( SCSIZE nC, SCSIZE nR ) const
797 {
798  // Flag must indicate an 'empty' or 'empty cell' or 'empty result' element,
799  // but not an 'empty path' element.
800  ValidColRowReplicated( nC, nR );
801  return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
802  maMatFlag.get_numeric(nR, nC) != SC_MATFLAG_EMPTYPATH;
803 }
804 
806 {
807  // Flag must indicate an 'empty cell' element instead of an
808  // 'empty' or 'empty result' or 'empty path' element.
809  ValidColRowReplicated( nC, nR );
810  return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
811  maMatFlag.get_type(nR, nC) == mdds::mtm::element_empty;
812 }
813 
815 {
816  // Flag must indicate an 'empty result' element instead of an
817  // 'empty' or 'empty cell' or 'empty path' element.
818  ValidColRowReplicated( nC, nR );
819  return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
820  maMatFlag.get_numeric(nR, nC) == SC_MATFLAG_EMPTYRESULT;
821 }
822 
824 {
825  // Flag must indicate an 'empty path' element.
826  if (ValidColRowOrReplicated( nC, nR ))
827  return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
828  maMatFlag.get_numeric(nR, nC) == SC_MATFLAG_EMPTYPATH;
829  else
830  return true;
831 }
832 
833 bool ScMatrixImpl::IsValue( SCSIZE nIndex ) const
834 {
835  SCSIZE nC, nR;
836  CalcPosition(nIndex, nC, nR);
837  return IsValue(nC, nR);
838 }
839 
840 bool ScMatrixImpl::IsValue( SCSIZE nC, SCSIZE nR ) const
841 {
842  ValidColRowReplicated(nC, nR);
843  switch (maMat.get_type(nR, nC))
844  {
845  case mdds::mtm::element_boolean:
846  case mdds::mtm::element_numeric:
847  return true;
848  default:
849  ;
850  }
851  return false;
852 }
853 
855 {
856  ValidColRowReplicated(nC, nR);
857  switch (maMat.get_type(nR, nC))
858  {
859  case mdds::mtm::element_boolean:
860  case mdds::mtm::element_numeric:
861  case mdds::mtm::element_empty:
862  return true;
863  default:
864  ;
865  }
866  return false;
867 }
868 
870 {
871  ValidColRowReplicated( nC, nR );
872  return maMat.get_type(nR, nC) == mdds::mtm::element_boolean;
873 }
874 
876 {
877  return maMat.numeric();
878 }
879 
881 {
882  if (maMat.size().row > mRes.maMat.size().row || maMat.size().column > mRes.maMat.size().column)
883  {
884  // destination matrix is not large enough.
885  OSL_FAIL("ScMatrixImpl::MatCopy: dimension error");
886  return;
887  }
888 
889  mRes.maMat.copy(maMat);
890 }
891 
893 {
894  mRes.maMat = maMat;
895  mRes.maMat.transpose();
896 }
897 
898 void ScMatrixImpl::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
899 {
900  if (ValidColRow( nC1, nR1) && ValidColRow( nC2, nR2))
901  {
902  for (SCSIZE j = nC1; j <= nC2; ++j)
903  {
904  // Passing value array is much faster.
905  std::vector<double> aVals(nR2-nR1+1, fVal);
906  maMat.set(nR1, j, aVals.begin(), aVals.end());
907  }
908  }
909  else
910  {
911  OSL_FAIL("ScMatrixImpl::FillDouble: dimension error");
912  }
913 }
914 
915 void ScMatrixImpl::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
916 {
917  if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
918  {
919  maMat.set(nR, nC, rVec.begin(), rVec.end());
920  }
921  else
922  {
923  OSL_FAIL("ScMatrixImpl::PutDoubleVector: dimension error");
924  }
925 }
926 
927 void ScMatrixImpl::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
928 {
929  if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
930  {
931  maMat.set(nR, nC, rVec.begin(), rVec.end());
932  }
933  else
934  {
935  OSL_FAIL("ScMatrixImpl::PutStringVector: dimension error");
936  }
937 }
938 
940 {
941  if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
942  {
943  maMat.set_empty(nR, nC, nCount);
944  // Flag to indicate that this is 'empty', not 'empty result' or 'empty path'.
945  maMatFlag.set_empty(nR, nC, nCount);
946  }
947  else
948  {
949  OSL_FAIL("ScMatrixImpl::PutEmptyVector: dimension error");
950  }
951 }
952 
954 {
955  if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
956  {
957  maMat.set_empty(nR, nC, nCount);
958  // Flag to indicate that this is 'empty result', not 'empty' or 'empty path'.
959  std::vector<TMatFlag> aVals(nCount, SC_MATFLAG_EMPTYRESULT);
960  maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
961  }
962  else
963  {
964  OSL_FAIL("ScMatrixImpl::PutEmptyResultVector: dimension error");
965  }
966 }
967 
969 {
970  if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
971  {
972  maMat.set_empty(nR, nC, nCount);
973  // Flag to indicate 'empty path'.
974  std::vector<TMatFlag> aVals(nCount, SC_MATFLAG_EMPTYPATH);
975  maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
976  }
977  else
978  {
979  OSL_FAIL("ScMatrixImpl::PutEmptyPathVector: dimension error");
980  }
981 }
982 
984 {
985  MatrixImplType::size_pair_type aSize = maMat.size();
986  CompareMatrixElemFunc<ElemEqualZero> aFunc(aSize.row, aSize.column);
987  aFunc = maMat.walk(std::move(aFunc));
988  aFunc.swap(maMat);
989 }
990 
992 {
993  MatrixImplType::size_pair_type aSize = maMat.size();
994  CompareMatrixElemFunc<ElemNotEqualZero> aFunc(aSize.row, aSize.column);
995  aFunc = maMat.walk(std::move(aFunc));
996  aFunc.swap(maMat);
997 }
998 
1000 {
1001  MatrixImplType::size_pair_type aSize = maMat.size();
1002  CompareMatrixElemFunc<ElemLessZero> aFunc(aSize.row, aSize.column);
1003  aFunc = maMat.walk(std::move(aFunc));
1004  aFunc.swap(maMat);
1005 }
1006 
1008 {
1009  MatrixImplType::size_pair_type aSize = maMat.size();
1010  CompareMatrixElemFunc<ElemGreaterZero> aFunc(aSize.row, aSize.column);
1011  aFunc = maMat.walk(std::move(aFunc));
1012  aFunc.swap(maMat);
1013 }
1014 
1016 {
1017  MatrixImplType::size_pair_type aSize = maMat.size();
1018  CompareMatrixElemFunc<ElemLessEqualZero> aFunc(aSize.row, aSize.column);
1019  aFunc = maMat.walk(std::move(aFunc));
1020  aFunc.swap(maMat);
1021 }
1022 
1024 {
1025  MatrixImplType::size_pair_type aSize = maMat.size();
1026  CompareMatrixElemFunc<ElemGreaterEqualZero> aFunc(aSize.row, aSize.column);
1027  aFunc = maMat.walk(std::move(aFunc));
1028  aFunc.swap(maMat);
1029 }
1030 
1031 namespace {
1032 
1033 struct AndEvaluator
1034 {
1035  bool mbResult;
1036  void operate(double fVal) { mbResult &= (fVal != 0.0); }
1037  bool result() const { return mbResult; }
1038  AndEvaluator() : mbResult(true) {}
1039 };
1040 
1041 struct OrEvaluator
1042 {
1043  bool mbResult;
1044  void operate(double fVal) { mbResult |= (fVal != 0.0); }
1045  bool result() const { return mbResult; }
1046  OrEvaluator() : mbResult(false) {}
1047 };
1048 
1049 struct XorEvaluator
1050 {
1051  bool mbResult;
1052  void operate(double fVal) { mbResult ^= (fVal != 0.0); }
1053  bool result() const { return mbResult; }
1054  XorEvaluator() : mbResult(false) {}
1055 };
1056 
1057 // Do not short circuit logical operations, in case there are error values
1058 // these need to be propagated even if the result was determined earlier.
1059 template <typename Evaluator>
1060 double EvalMatrix(const MatrixImplType& rMat)
1061 {
1062  Evaluator aEval;
1063  size_t nRows = rMat.size().row, nCols = rMat.size().column;
1064  for (size_t i = 0; i < nRows; ++i)
1065  {
1066  for (size_t j = 0; j < nCols; ++j)
1067  {
1068  MatrixImplType::const_position_type aPos = rMat.position(i, j);
1069  mdds::mtm::element_t eType = rMat.get_type(aPos);
1070  if (eType != mdds::mtm::element_numeric && eType != mdds::mtm::element_boolean)
1071  // assuming a CompareMat this is an error
1072  return CreateDoubleError(FormulaError::IllegalArgument);
1073 
1074  double fVal = rMat.get_numeric(aPos);
1075  if (!std::isfinite(fVal))
1076  // DoubleError
1077  return fVal;
1078 
1079  aEval.operate(fVal);
1080  }
1081  }
1082  return aEval.result();
1083 }
1084 
1085 }
1086 
1087 double ScMatrixImpl::And() const
1088 {
1089  // All elements must be of value type.
1090  // True only if all the elements have non-zero values.
1091  return EvalMatrix<AndEvaluator>(maMat);
1092 }
1093 
1094 double ScMatrixImpl::Or() const
1095 {
1096  // All elements must be of value type.
1097  // True if at least one element has a non-zero value.
1098  return EvalMatrix<OrEvaluator>(maMat);
1099 }
1100 
1101 double ScMatrixImpl::Xor() const
1102 {
1103  // All elements must be of value type.
1104  // True if an odd number of elements have a non-zero value.
1105  return EvalMatrix<XorEvaluator>(maMat);
1106 }
1107 
1108 namespace {
1109 
1110 template<typename Op>
1111 class WalkElementBlocks
1112 {
1113  Op maOp;
1115  bool mbFirst:1;
1116  bool mbTextAsZero:1;
1117  bool mbIgnoreErrorValues:1;
1118 public:
1119  WalkElementBlocks(bool bTextAsZero, bool bIgnoreErrorValues) :
1120  maRes(Op::InitVal, Op::InitVal, 0), mbFirst(true),
1121  mbTextAsZero(bTextAsZero), mbIgnoreErrorValues(bIgnoreErrorValues)
1122  {}
1123 
1124  const ScMatrix::IterateResult& getResult() const { return maRes; }
1125 
1126  void operator() (const MatrixImplType::element_block_node_type& node)
1127  {
1128  switch (node.type)
1129  {
1130  case mdds::mtm::element_numeric:
1131  {
1132  typedef MatrixImplType::numeric_block_type block_type;
1133 
1134  size_t nIgnored = 0;
1135  block_type::const_iterator it = block_type::begin(*node.data);
1136  block_type::const_iterator itEnd = block_type::end(*node.data);
1137  for (; it != itEnd; ++it)
1138  {
1139  if (mbIgnoreErrorValues && !std::isfinite(*it))
1140  {
1141  ++nIgnored;
1142  continue;
1143  }
1144 
1145  if (mbFirst)
1146  {
1147  maOp(maRes.mfFirst, *it);
1148  mbFirst = false;
1149  }
1150  else
1151  {
1152  maOp(maRes.mfRest, *it);
1153  }
1154  }
1155  maRes.mnCount += node.size - nIgnored;
1156  }
1157  break;
1158  case mdds::mtm::element_boolean:
1159  {
1160  typedef MatrixImplType::boolean_block_type block_type;
1161 
1162  block_type::const_iterator it = block_type::begin(*node.data);
1163  block_type::const_iterator itEnd = block_type::end(*node.data);
1164  for (; it != itEnd; ++it)
1165  {
1166  if (mbFirst)
1167  {
1168  maOp(maRes.mfFirst, *it);
1169  mbFirst = false;
1170  }
1171  else
1172  {
1173  maOp(maRes.mfRest, *it);
1174  }
1175  }
1176  maRes.mnCount += node.size;
1177  }
1178  break;
1179  case mdds::mtm::element_string:
1180  if (mbTextAsZero)
1181  maRes.mnCount += node.size;
1182  break;
1183  case mdds::mtm::element_empty:
1184  default:
1185  ;
1186  }
1187  }
1188 };
1189 
1190 template<typename Op>
1191 class WalkElementBlocksMultipleValues
1192 {
1193  const std::vector<Op>* mpOp;
1194  std::vector<ScMatrix::IterateResult> maRes;
1195  bool mbFirst:1;
1196 public:
1197  WalkElementBlocksMultipleValues(const std::vector<Op>& aOp) :
1198  mpOp(&aOp), mbFirst(true)
1199  {
1200  for (const auto& rpOp : *mpOp)
1201  {
1202  maRes.emplace_back(rpOp.mInitVal, rpOp.mInitVal, 0);
1203  }
1204  maRes.emplace_back(0.0, 0.0, 0); // count
1205  }
1206 
1207  WalkElementBlocksMultipleValues( const WalkElementBlocksMultipleValues& ) = delete;
1208  WalkElementBlocksMultipleValues& operator= ( const WalkElementBlocksMultipleValues& ) = delete;
1209 
1210  WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues&& r) noexcept :
1211  mpOp(r.mpOp), maRes(std::move(r.maRes)), mbFirst(r.mbFirst) {}
1212 
1213  WalkElementBlocksMultipleValues& operator=(WalkElementBlocksMultipleValues&& r) noexcept
1214  {
1215  mpOp = r.mpOp;
1216  maRes = std::move(r.maRes);
1217  mbFirst = r.mbFirst;
1218  return *this;
1219  }
1220 
1221  const std::vector<ScMatrix::IterateResult>& getResult() const { return maRes; }
1222 
1223  void operator() (const MatrixImplType::element_block_node_type& node)
1224  {
1225  switch (node.type)
1226  {
1227  case mdds::mtm::element_numeric:
1228  {
1229  typedef MatrixImplType::numeric_block_type block_type;
1230 
1231  block_type::const_iterator it = block_type::begin(*node.data);
1232  block_type::const_iterator itEnd = block_type::end(*node.data);
1233  for (; it != itEnd; ++it)
1234  {
1235  if (mbFirst)
1236  {
1237  for (size_t i = 0u; i < mpOp->size(); ++i)
1238  {
1239  (*mpOp)[i](maRes[i].mfFirst, *it);
1240  }
1241  mbFirst = false;
1242  }
1243  else
1244  {
1245  for (size_t i = 0u; i < mpOp->size(); ++i)
1246  {
1247  (*mpOp)[i](maRes[i].mfRest, *it);
1248  }
1249  }
1250  }
1251  maRes.back().mnCount += node.size;
1252  }
1253  break;
1254  case mdds::mtm::element_boolean:
1255  {
1256  typedef MatrixImplType::boolean_block_type block_type;
1257 
1258  block_type::const_iterator it = block_type::begin(*node.data);
1259  block_type::const_iterator itEnd = block_type::end(*node.data);
1260  for (; it != itEnd; ++it)
1261  {
1262  if (mbFirst)
1263  {
1264  for (size_t i = 0u; i < mpOp->size(); ++i)
1265  {
1266  (*mpOp)[i](maRes[i].mfFirst, *it);
1267  }
1268  mbFirst = false;
1269  }
1270  else
1271  {
1272  for (size_t i = 0u; i < mpOp->size(); ++i)
1273  {
1274  (*mpOp)[i](maRes[i].mfRest, *it);
1275  }
1276  }
1277  }
1278  maRes.back().mnCount += node.size;
1279  }
1280  break;
1281  case mdds::mtm::element_string:
1282  case mdds::mtm::element_empty:
1283  default:
1284  ;
1285  }
1286  }
1287 };
1288 
1289 class CountElements
1290 {
1291  size_t mnCount;
1292  bool mbCountString;
1293  bool mbCountErrors;
1294  bool mbIgnoreEmptyStrings;
1295 public:
1296  explicit CountElements(bool bCountString, bool bCountErrors, bool bIgnoreEmptyStrings) :
1297  mnCount(0), mbCountString(bCountString), mbCountErrors(bCountErrors),
1298  mbIgnoreEmptyStrings(bIgnoreEmptyStrings) {}
1299 
1300  size_t getCount() const { return mnCount; }
1301 
1302  void operator() (const MatrixImplType::element_block_node_type& node)
1303  {
1304  switch (node.type)
1305  {
1306  case mdds::mtm::element_numeric:
1307  mnCount += node.size;
1308  if (!mbCountErrors)
1309  {
1310  typedef MatrixImplType::numeric_block_type block_type;
1311 
1312  block_type::const_iterator it = block_type::begin(*node.data);
1313  block_type::const_iterator itEnd = block_type::end(*node.data);
1314  for (; it != itEnd; ++it)
1315  {
1316  if (!std::isfinite(*it))
1317  --mnCount;
1318  }
1319  }
1320  break;
1321  case mdds::mtm::element_boolean:
1322  mnCount += node.size;
1323  break;
1324  case mdds::mtm::element_string:
1325  if (mbCountString)
1326  {
1327  mnCount += node.size;
1328  if (mbIgnoreEmptyStrings)
1329  {
1330  typedef MatrixImplType::string_block_type block_type;
1331 
1332  block_type::const_iterator it = block_type::begin(*node.data);
1333  block_type::const_iterator itEnd = block_type::end(*node.data);
1334  for (; it != itEnd; ++it)
1335  {
1336  if (it->isEmpty())
1337  --mnCount;
1338  }
1339  }
1340  }
1341  break;
1342  case mdds::mtm::element_empty:
1343  default:
1344  ;
1345  }
1346  }
1347 };
1348 
1349 const size_t ResultNotSet = std::numeric_limits<size_t>::max();
1350 
1351 template<typename Type>
1352 class WalkAndMatchElements
1353 {
1354  Type maMatchValue;
1355  size_t mnStartIndex;
1356  size_t mnStopIndex;
1357  size_t mnResult;
1358  size_t mnIndex;
1359 
1360 public:
1361  WalkAndMatchElements(Type aMatchValue, const MatrixImplType::size_pair_type& aSize, size_t nCol1, size_t nCol2) :
1362  maMatchValue(aMatchValue),
1363  mnStartIndex( nCol1 * aSize.row ),
1364  mnStopIndex( (nCol2 + 1) * aSize.row ),
1365  mnResult(ResultNotSet),
1366  mnIndex(0)
1367  {
1368  assert( nCol1 < aSize.column && nCol2 < aSize.column);
1369  }
1370 
1371  size_t getMatching() const { return mnResult; }
1372 
1373  size_t getRemainingCount() const
1374  {
1375  return mnIndex < mnStopIndex ? mnStopIndex - mnIndex : 0;
1376  }
1377 
1378  size_t compare(const MatrixImplType::element_block_node_type& node) const;
1379 
1380  void operator() (const MatrixImplType::element_block_node_type& node)
1381  {
1382  // early exit if match already found
1383  if (mnResult != ResultNotSet)
1384  return;
1385 
1386  // limit lookup to the requested columns
1387  if (mnStartIndex <= mnIndex && getRemainingCount() > 0)
1388  {
1389  mnResult = compare(node);
1390  }
1391 
1392  mnIndex += node.size;
1393  }
1394 };
1395 
1396 template<>
1397 size_t WalkAndMatchElements<double>::compare(const MatrixImplType::element_block_node_type& node) const
1398 {
1399  size_t nCount = 0;
1400  switch (node.type)
1401  {
1402  case mdds::mtm::element_numeric:
1403  {
1404  typedef MatrixImplType::numeric_block_type block_type;
1405 
1406  block_type::const_iterator it = block_type::begin(*node.data);
1407  block_type::const_iterator itEnd = block_type::end(*node.data);
1408  const size_t nRemaining = getRemainingCount();
1409  for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1410  {
1411  if (*it == maMatchValue)
1412  {
1413  return mnIndex + nCount;
1414  }
1415  }
1416  break;
1417  }
1418  case mdds::mtm::element_boolean:
1419  {
1420  typedef MatrixImplType::boolean_block_type block_type;
1421 
1422  block_type::const_iterator it = block_type::begin(*node.data);
1423  block_type::const_iterator itEnd = block_type::end(*node.data);
1424  const size_t nRemaining = getRemainingCount();
1425  for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1426  {
1427  if (int(*it) == maMatchValue)
1428  {
1429  return mnIndex + nCount;
1430  }
1431  }
1432  break;
1433  }
1434  break;
1435  case mdds::mtm::element_string:
1436  case mdds::mtm::element_empty:
1437  default:
1438  ;
1439  }
1440  return ResultNotSet;
1441 }
1442 
1443 template<>
1444 size_t WalkAndMatchElements<svl::SharedString>::compare(const MatrixImplType::element_block_node_type& node) const
1445 {
1446  switch (node.type)
1447  {
1448  case mdds::mtm::element_string:
1449  {
1450  size_t nCount = 0;
1451  typedef MatrixImplType::string_block_type block_type;
1452 
1453  block_type::const_iterator it = block_type::begin(*node.data);
1454  block_type::const_iterator itEnd = block_type::end(*node.data);
1455  const size_t nRemaining = getRemainingCount();
1456  for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1457  {
1458  if (it->getDataIgnoreCase() == maMatchValue.getDataIgnoreCase())
1459  {
1460  return mnIndex + nCount;
1461  }
1462  }
1463  break;
1464  }
1465  case mdds::mtm::element_boolean:
1466  case mdds::mtm::element_numeric:
1467  case mdds::mtm::element_empty:
1468  default:
1469  ;
1470  }
1471  return ResultNotSet;
1472 }
1473 
1474 struct MaxOp
1475 {
1476  static double init() { return -std::numeric_limits<double>::max(); }
1477  static double compare(double left, double right)
1478  {
1479  if (!std::isfinite(left))
1480  return left;
1481  if (!std::isfinite(right))
1482  return right;
1483  return std::max(left, right);
1484  }
1485 
1486  static double boolValue(
1487  MatrixImplType::boolean_block_type::const_iterator it,
1488  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1489  {
1490  // If the array has at least one true value, the maximum value is 1.
1491  it = std::find(it, itEnd, true);
1492  return it == itEnd ? 0.0 : 1.0;
1493  }
1494 };
1495 
1496 struct MinOp
1497 {
1498  static double init() { return std::numeric_limits<double>::max(); }
1499  static double compare(double left, double right)
1500  {
1501  if (!std::isfinite(left))
1502  return left;
1503  if (!std::isfinite(right))
1504  return right;
1505  return std::min(left, right);
1506  }
1507 
1508  static double boolValue(
1509  MatrixImplType::boolean_block_type::const_iterator it,
1510  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1511  {
1512  // If the array has at least one false value, the minimum value is 0.
1513  it = std::find(it, itEnd, false);
1514  return it == itEnd ? 1.0 : 0.0;
1515  }
1516 };
1517 
1518 struct Lcm
1519 {
1520  static double init() { return 1.0; }
1521  static double calculate(double fx,double fy)
1522  {
1523  return (fx*fy)/ScInterpreter::ScGetGCD(fx,fy);
1524  }
1525 
1526  static double boolValue(
1527  MatrixImplType::boolean_block_type::const_iterator it,
1528  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1529  {
1530  // If the array has at least one false value, the minimum value is 0.
1531  it = std::find(it, itEnd, false);
1532  return it == itEnd ? 1.0 : 0.0;
1533  }
1534 };
1535 
1536 struct Gcd
1537 {
1538  static double init() { return 0.0; }
1539  static double calculate(double fx,double fy)
1540  {
1541  return ScInterpreter::ScGetGCD(fx,fy);
1542  }
1543 
1544  static double boolValue(
1545  MatrixImplType::boolean_block_type::const_iterator it,
1546  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1547  {
1548  // If the array has at least one true value, the gcdResult is 1.
1549  it = std::find(it, itEnd, true);
1550  return it == itEnd ? 0.0 : 1.0;
1551  }
1552 };
1553 
1554 template<typename Op>
1555 class CalcMaxMinValue
1556 {
1557  double mfVal;
1558  bool mbTextAsZero;
1559  bool mbIgnoreErrorValues;
1560  bool mbHasValue;
1561 public:
1562  CalcMaxMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) :
1563  mfVal(Op::init()),
1564  mbTextAsZero(bTextAsZero),
1565  mbIgnoreErrorValues(bIgnoreErrorValues),
1566  mbHasValue(false) {}
1567 
1568  double getValue() const { return mbHasValue ? mfVal : 0.0; }
1569 
1570  void operator() (const MatrixImplType::element_block_node_type& node)
1571  {
1572 
1573  switch (node.type)
1574  {
1575  case mdds::mtm::element_numeric:
1576  {
1577  typedef MatrixImplType::numeric_block_type block_type;
1578 
1579  block_type::const_iterator it = block_type::begin(*node.data);
1580  block_type::const_iterator itEnd = block_type::end(*node.data);
1581  if (mbIgnoreErrorValues)
1582  {
1583  for (; it != itEnd; ++it)
1584  {
1585  if (std::isfinite(*it))
1586  mfVal = Op::compare(mfVal, *it);
1587  }
1588  }
1589  else
1590  {
1591  for (; it != itEnd; ++it)
1592  mfVal = Op::compare(mfVal, *it);
1593  }
1594 
1595  mbHasValue = true;
1596  }
1597  break;
1598  case mdds::mtm::element_boolean:
1599  {
1600  typedef MatrixImplType::boolean_block_type block_type;
1601 
1602  block_type::const_iterator it = block_type::begin(*node.data);
1603  block_type::const_iterator itEnd = block_type::end(*node.data);
1604  double fVal = Op::boolValue(it, itEnd);
1605  mfVal = Op::compare(mfVal, fVal);
1606  mbHasValue = true;
1607  }
1608  break;
1609  case mdds::mtm::element_string:
1610  case mdds::mtm::element_empty:
1611  {
1612  // empty elements are treated as empty strings.
1613  if (mbTextAsZero)
1614  {
1615  mfVal = Op::compare(mfVal, 0.0);
1616  mbHasValue = true;
1617  }
1618  }
1619  break;
1620  default:
1621  ;
1622  }
1623  }
1624 };
1625 
1626 template<typename Op>
1627 class CalcGcdLcm
1628 {
1629  double mfval;
1630 
1631 public:
1632  CalcGcdLcm() : mfval(Op::init()) {}
1633 
1634  double getResult() const { return mfval; }
1635 
1636  void operator() ( const MatrixImplType::element_block_node_type& node )
1637  {
1638  switch (node.type)
1639  {
1640  case mdds::mtm::element_numeric:
1641  {
1642  typedef MatrixImplType::numeric_block_type block_type;
1643  block_type::const_iterator it = block_type::begin(*node.data);
1644  block_type::const_iterator itEnd = block_type::end(*node.data);
1645 
1646  for ( ; it != itEnd; ++it)
1647  {
1648  if (*it < 0.0)
1649  mfval = CreateDoubleError(FormulaError::IllegalArgument);
1650  else
1651  mfval = ::rtl::math::approxFloor( Op::calculate(*it,mfval));
1652  }
1653  }
1654  break;
1655  case mdds::mtm::element_boolean:
1656  {
1657  typedef MatrixImplType::boolean_block_type block_type;
1658  block_type::const_iterator it = block_type::begin(*node.data);
1659  block_type::const_iterator itEnd = block_type::end(*node.data);
1660 
1661  mfval = Op::boolValue(it, itEnd);
1662  }
1663  break;
1664  case mdds::mtm::element_empty:
1665  case mdds::mtm::element_string:
1666  {
1667  mfval = CreateDoubleError(FormulaError::IllegalArgument);
1668  }
1669  break;
1670  default:
1671  ;
1672  }
1673  }
1674 };
1675 
1676 double evaluate( double fVal, ScQueryOp eOp )
1677 {
1678  if (!std::isfinite(fVal))
1679  return fVal;
1680 
1681  switch (eOp)
1682  {
1683  case SC_EQUAL:
1684  return fVal == 0.0 ? 1.0 : 0.0;
1685  case SC_LESS:
1686  return fVal < 0.0 ? 1.0 : 0.0;
1687  case SC_GREATER:
1688  return fVal > 0.0 ? 1.0 : 0.0;
1689  break;
1690  case SC_LESS_EQUAL:
1691  return fVal <= 0.0 ? 1.0 : 0.0;
1692  break;
1693  case SC_GREATER_EQUAL:
1694  return fVal >= 0.0 ? 1.0 : 0.0;
1695  break;
1696  case SC_NOT_EQUAL:
1697  return fVal != 0.0 ? 1.0 : 0.0;
1698  break;
1699  default:
1700  ;
1701  }
1702 
1703  SAL_WARN("sc.core", "evaluate: unhandled comparison operator: " << static_cast<int>(eOp));
1704  return CreateDoubleError( FormulaError::UnknownState);
1705 }
1706 
1707 class CompareMatrixFunc
1708 {
1709  sc::Compare& mrComp;
1710  size_t mnMatPos;
1711  sc::CompareOptions* mpOptions;
1712  std::vector<double> maResValues; // double instead of bool to transport error values
1713 
1714  void compare()
1715  {
1716  double fVal = sc::CompareFunc( mrComp, mpOptions);
1717  maResValues.push_back(evaluate(fVal, mrComp.meOp));
1718  }
1719 
1720 public:
1721  CompareMatrixFunc( size_t nResSize, sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) :
1722  mrComp(rComp), mnMatPos(nMatPos), mpOptions(pOptions)
1723  {
1724  maResValues.reserve(nResSize);
1725  }
1726 
1727  CompareMatrixFunc( const CompareMatrixFunc& ) = delete;
1728  CompareMatrixFunc& operator= ( const CompareMatrixFunc& ) = delete;
1729 
1730  CompareMatrixFunc(CompareMatrixFunc&& r) noexcept :
1731  mrComp(r.mrComp),
1732  mnMatPos(r.mnMatPos),
1733  mpOptions(r.mpOptions),
1734  maResValues(std::move(r.maResValues)) {}
1735 
1736  CompareMatrixFunc& operator=(CompareMatrixFunc&& r) noexcept
1737  {
1738  mrComp = r.mrComp;
1739  mnMatPos = r.mnMatPos;
1740  mpOptions = r.mpOptions;
1741  maResValues = std::move(r.maResValues);
1742  return *this;
1743  }
1744 
1745  void operator() (const MatrixImplType::element_block_node_type& node)
1746  {
1747  sc::Compare::Cell& rCell = mrComp.maCells[mnMatPos];
1748 
1749  switch (node.type)
1750  {
1751  case mdds::mtm::element_numeric:
1752  {
1753  typedef MatrixImplType::numeric_block_type block_type;
1754 
1755  block_type::const_iterator it = block_type::begin(*node.data);
1756  block_type::const_iterator itEnd = block_type::end(*node.data);
1757  for (; it != itEnd; ++it)
1758  {
1759  rCell.mbValue = true;
1760  rCell.mbEmpty = false;
1761  rCell.mfValue = *it;
1762  compare();
1763  }
1764  }
1765  break;
1766  case mdds::mtm::element_boolean:
1767  {
1768  typedef MatrixImplType::boolean_block_type block_type;
1769 
1770  block_type::const_iterator it = block_type::begin(*node.data);
1771  block_type::const_iterator itEnd = block_type::end(*node.data);
1772  for (; it != itEnd; ++it)
1773  {
1774  rCell.mbValue = true;
1775  rCell.mbEmpty = false;
1776  rCell.mfValue = double(*it);
1777  compare();
1778  }
1779  }
1780  break;
1781  case mdds::mtm::element_string:
1782  {
1783  typedef MatrixImplType::string_block_type block_type;
1784 
1785  block_type::const_iterator it = block_type::begin(*node.data);
1786  block_type::const_iterator itEnd = block_type::end(*node.data);
1787  for (; it != itEnd; ++it)
1788  {
1789  const svl::SharedString& rStr = *it;
1790  rCell.mbValue = false;
1791  rCell.mbEmpty = false;
1792  rCell.maStr = rStr;
1793  compare();
1794  }
1795  }
1796  break;
1797  case mdds::mtm::element_empty:
1798  {
1799  rCell.mbValue = false;
1800  rCell.mbEmpty = true;
1802  for (size_t i = 0; i < node.size; ++i)
1803  compare();
1804  }
1805  break;
1806  default:
1807  ;
1808  }
1809  }
1810 
1811  const std::vector<double>& getValues() const
1812  {
1813  return maResValues;
1814  }
1815 };
1816 
1820 class CompareMatrixToNumericFunc
1821 {
1822  sc::Compare& mrComp;
1823  double mfRightValue;
1824  sc::CompareOptions* mpOptions;
1825  std::vector<double> maResValues; // double instead of bool to transport error values
1826 
1827  void compare()
1828  {
1829  double fVal = sc::CompareFunc(mrComp.maCells[0], mfRightValue, mpOptions);
1830  maResValues.push_back(evaluate(fVal, mrComp.meOp));
1831  }
1832 
1833  void compareLeftNumeric( double fLeftVal )
1834  {
1835  double fVal = sc::CompareFunc(fLeftVal, mfRightValue);
1836  maResValues.push_back(evaluate(fVal, mrComp.meOp));
1837  }
1838 
1839  void compareLeftEmpty( size_t nSize )
1840  {
1841  double fVal = sc::CompareEmptyToNumericFunc(mfRightValue);
1842  bool bRes = evaluate(fVal, mrComp.meOp);
1843  maResValues.resize(maResValues.size() + nSize, bRes ? 1.0 : 0.0);
1844  }
1845 
1846 public:
1847  CompareMatrixToNumericFunc( size_t nResSize, sc::Compare& rComp, double fRightValue, sc::CompareOptions* pOptions ) :
1848  mrComp(rComp), mfRightValue(fRightValue), mpOptions(pOptions)
1849  {
1850  maResValues.reserve(nResSize);
1851  }
1852 
1853  CompareMatrixToNumericFunc( const CompareMatrixToNumericFunc& ) = delete;
1854  CompareMatrixToNumericFunc& operator= ( const CompareMatrixToNumericFunc& ) = delete;
1855 
1856  CompareMatrixToNumericFunc(CompareMatrixToNumericFunc&& r) noexcept :
1857  mrComp(r.mrComp),
1858  mfRightValue(r.mfRightValue),
1859  mpOptions(r.mpOptions),
1860  maResValues(std::move(r.maResValues)) {}
1861 
1862  CompareMatrixToNumericFunc& operator=(CompareMatrixToNumericFunc&& r) noexcept
1863  {
1864  mrComp = r.mrComp;
1865  mfRightValue = r.mfRightValue;
1866  mpOptions = r.mpOptions;
1867  maResValues = std::move(r.maResValues);
1868  return *this;
1869  }
1870 
1871  void operator() (const MatrixImplType::element_block_node_type& node)
1872  {
1873  switch (node.type)
1874  {
1875  case mdds::mtm::element_numeric:
1876  {
1877  typedef MatrixImplType::numeric_block_type block_type;
1878 
1879  block_type::const_iterator it = block_type::begin(*node.data);
1880  block_type::const_iterator itEnd = block_type::end(*node.data);
1881  for (; it != itEnd; ++it)
1882  compareLeftNumeric(*it);
1883  }
1884  break;
1885  case mdds::mtm::element_boolean:
1886  {
1887  typedef MatrixImplType::boolean_block_type block_type;
1888 
1889  block_type::const_iterator it = block_type::begin(*node.data);
1890  block_type::const_iterator itEnd = block_type::end(*node.data);
1891  for (; it != itEnd; ++it)
1892  compareLeftNumeric(double(*it));
1893  }
1894  break;
1895  case mdds::mtm::element_string:
1896  {
1897  typedef MatrixImplType::string_block_type block_type;
1898 
1899  block_type::const_iterator it = block_type::begin(*node.data);
1900  block_type::const_iterator itEnd = block_type::end(*node.data);
1901  for (; it != itEnd; ++it)
1902  {
1903  const svl::SharedString& rStr = *it;
1904  sc::Compare::Cell& rCell = mrComp.maCells[0];
1905  rCell.mbValue = false;
1906  rCell.mbEmpty = false;
1907  rCell.maStr = rStr;
1908  compare();
1909  }
1910  }
1911  break;
1912  case mdds::mtm::element_empty:
1913  compareLeftEmpty(node.size);
1914  break;
1915  default:
1916  ;
1917  }
1918  }
1919 
1920  const std::vector<double>& getValues() const
1921  {
1922  return maResValues;
1923  }
1924 };
1925 
1926 class ToDoubleArray
1927 {
1928  std::vector<double> maArray;
1929  std::vector<double>::iterator miPos;
1930  double mfNaN;
1931  bool mbEmptyAsZero;
1932 
1933  void moveArray( ToDoubleArray& r )
1934  {
1935  // Re-create the iterator from the new array after the array has been
1936  // moved, to ensure that the iterator points to a valid array
1937  // position.
1938  size_t n = std::distance(r.maArray.begin(), r.miPos);
1939  maArray = std::move(r.maArray);
1940  miPos = maArray.begin();
1941  std::advance(miPos, n);
1942  }
1943 
1944 public:
1945  ToDoubleArray( size_t nSize, bool bEmptyAsZero ) :
1946  maArray(nSize, 0.0), miPos(maArray.begin()), mbEmptyAsZero(bEmptyAsZero)
1947  {
1948  mfNaN = CreateDoubleError( FormulaError::ElementNaN);
1949  }
1950 
1951  ToDoubleArray( const ToDoubleArray& ) = delete;
1952  ToDoubleArray& operator= ( const ToDoubleArray& ) = delete;
1953 
1954  ToDoubleArray(ToDoubleArray&& r) noexcept :
1955  mfNaN(r.mfNaN), mbEmptyAsZero(r.mbEmptyAsZero)
1956  {
1957  moveArray(r);
1958  }
1959 
1960  ToDoubleArray& operator=(ToDoubleArray&& r) noexcept
1961  {
1962  mfNaN = r.mfNaN;
1963  mbEmptyAsZero = r.mbEmptyAsZero;
1964  moveArray(r);
1965  return *this;
1966  }
1967 
1968  void operator() (const MatrixImplType::element_block_node_type& node)
1969  {
1970  using namespace mdds::mtv;
1971 
1972  switch (node.type)
1973  {
1974  case mdds::mtm::element_numeric:
1975  {
1976  double_element_block::const_iterator it = double_element_block::begin(*node.data);
1977  double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
1978  for (; it != itEnd; ++it, ++miPos)
1979  *miPos = *it;
1980  }
1981  break;
1982  case mdds::mtm::element_boolean:
1983  {
1984  boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
1985  boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
1986  for (; it != itEnd; ++it, ++miPos)
1987  *miPos = *it ? 1.0 : 0.0;
1988  }
1989  break;
1990  case mdds::mtm::element_string:
1991  {
1992  for (size_t i = 0; i < node.size; ++i, ++miPos)
1993  *miPos = mfNaN;
1994  }
1995  break;
1996  case mdds::mtm::element_empty:
1997  {
1998  if (mbEmptyAsZero)
1999  {
2000  std::advance(miPos, node.size);
2001  return;
2002  }
2003 
2004  for (size_t i = 0; i < node.size; ++i, ++miPos)
2005  *miPos = mfNaN;
2006  }
2007  break;
2008  default:
2009  ;
2010  }
2011  }
2012 
2013  void swap(std::vector<double>& rOther)
2014  {
2015  maArray.swap(rOther);
2016  }
2017 };
2018 
2019 struct ArrayMul
2020 {
2021  double operator() (const double& lhs, const double& rhs) const
2022  {
2023  return lhs * rhs;
2024  }
2025 };
2026 
2027 template<typename Op>
2028 class MergeDoubleArrayFunc
2029 {
2030  std::vector<double>::iterator miPos;
2031  double mfNaN;
2032 public:
2033  MergeDoubleArrayFunc(std::vector<double>& rArray) : miPos(rArray.begin())
2034  {
2035  mfNaN = CreateDoubleError( FormulaError::ElementNaN);
2036  }
2037 
2038  MergeDoubleArrayFunc( const MergeDoubleArrayFunc& ) = delete;
2039  MergeDoubleArrayFunc& operator= ( const MergeDoubleArrayFunc& ) = delete;
2040 
2041  MergeDoubleArrayFunc( MergeDoubleArrayFunc&& ) = default;
2042  MergeDoubleArrayFunc& operator= ( MergeDoubleArrayFunc&& ) = default;
2043 
2044  void operator() (const MatrixImplType::element_block_node_type& node)
2045  {
2046  using namespace mdds::mtv;
2047  static const Op op;
2048 
2049  switch (node.type)
2050  {
2051  case mdds::mtm::element_numeric:
2052  {
2053  double_element_block::const_iterator it = double_element_block::begin(*node.data);
2054  double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
2055  for (; it != itEnd; ++it, ++miPos)
2056  {
2057  if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2058  continue;
2059 
2060  *miPos = op(*miPos, *it);
2061  }
2062  }
2063  break;
2064  case mdds::mtm::element_boolean:
2065  {
2066  boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
2067  boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
2068  for (; it != itEnd; ++it, ++miPos)
2069  {
2070  if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2071  continue;
2072 
2073  *miPos = op(*miPos, *it ? 1.0 : 0.0);
2074  }
2075  }
2076  break;
2077  case mdds::mtm::element_string:
2078  {
2079  for (size_t i = 0; i < node.size; ++i, ++miPos)
2080  *miPos = mfNaN;
2081  }
2082  break;
2083  case mdds::mtm::element_empty:
2084  {
2085  // Empty element is equivalent of having a numeric value of 0.0.
2086  for (size_t i = 0; i < node.size; ++i, ++miPos)
2087  {
2088  if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2089  continue;
2090 
2091  *miPos = op(*miPos, 0.0);
2092  }
2093  }
2094  break;
2095  default:
2096  ;
2097  }
2098  }
2099 };
2100 
2101 }
2102 
2103 namespace {
2104 
2105 template<typename TOp>
2106 ScMatrix::IterateResult GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorValues, const MatrixImplType& maMat)
2107 {
2108  WalkElementBlocks<TOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2109  aFunc = maMat.walk(aFunc);
2110  return aFunc.getResult();
2111 }
2112 
2113 }
2114 
2115 ScMatrix::IterateResult ScMatrixImpl::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
2116 {
2117  return GetValueWithCount<sc::op::Sum>(bTextAsZero, bIgnoreErrorValues, maMat);
2118 }
2119 
2120 ScMatrix::IterateResult ScMatrixImpl::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
2121 {
2122  return GetValueWithCount<sc::op::SumSquare>(bTextAsZero, bIgnoreErrorValues, maMat);
2123 }
2124 
2125 ScMatrix::IterateResult ScMatrixImpl::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
2126 {
2127  return GetValueWithCount<sc::op::Product>(bTextAsZero, bIgnoreErrorValues, maMat);
2128 }
2129 
2130 size_t ScMatrixImpl::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
2131 {
2132  CountElements aFunc(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
2133  aFunc = maMat.walk(aFunc);
2134  return aFunc.getCount();
2135 }
2136 
2137 size_t ScMatrixImpl::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
2138 {
2139  WalkAndMatchElements<double> aFunc(fValue, maMat.size(), nCol1, nCol2);
2140  aFunc = maMat.walk(aFunc);
2141  return aFunc.getMatching();
2142 }
2143 
2144 size_t ScMatrixImpl::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
2145 {
2146  WalkAndMatchElements<svl::SharedString> aFunc(rStr, maMat.size(), nCol1, nCol2);
2147  aFunc = maMat.walk(aFunc);
2148  return aFunc.getMatching();
2149 }
2150 
2151 double ScMatrixImpl::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2152 {
2153  CalcMaxMinValue<MaxOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2154  aFunc = maMat.walk(aFunc);
2155  return aFunc.getValue();
2156 }
2157 
2158 double ScMatrixImpl::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2159 {
2160  CalcMaxMinValue<MinOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2161  aFunc = maMat.walk(aFunc);
2162  return aFunc.getValue();
2163 }
2164 
2165 double ScMatrixImpl::GetGcd() const
2166 {
2167  CalcGcdLcm<Gcd> aFunc;
2168  aFunc = maMat.walk(aFunc);
2169  return aFunc.getResult();
2170 }
2171 
2172 double ScMatrixImpl::GetLcm() const
2173 {
2174  CalcGcdLcm<Lcm> aFunc;
2175  aFunc = maMat.walk(aFunc);
2176  return aFunc.getResult();
2177 }
2178 
2180  sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
2181 {
2182  MatrixImplType::size_pair_type aSize = maMat.size();
2183  size_t nSize = aSize.column * aSize.row;
2184  if (nMatPos == 0)
2185  {
2186  if (rComp.maCells[1].mbValue && !rComp.maCells[1].mbEmpty)
2187  {
2188  // Matrix on the left, and a numeric value on the right. Use a
2189  // function object that has much less branching for much better
2190  // performance.
2191  CompareMatrixToNumericFunc aFunc(nSize, rComp, rComp.maCells[1].mfValue, pOptions);
2192  aFunc = maMat.walk(std::move(aFunc));
2193 
2194  // We assume the result matrix has the same dimension as this matrix.
2195  const std::vector<double>& rResVal = aFunc.getValues();
2196  assert (nSize == rResVal.size());
2197  if (nSize != rResVal.size())
2198  return ScMatrixRef();
2199 
2200  return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2201  }
2202  }
2203 
2204  CompareMatrixFunc aFunc(nSize, rComp, nMatPos, pOptions);
2205  aFunc = maMat.walk(std::move(aFunc));
2206 
2207  // We assume the result matrix has the same dimension as this matrix.
2208  const std::vector<double>& rResVal = aFunc.getValues();
2209  assert (nSize == rResVal.size());
2210  if (nSize != rResVal.size())
2211  return ScMatrixRef();
2212 
2213  return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2214 }
2215 
2216 void ScMatrixImpl::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
2217 {
2218  MatrixImplType::size_pair_type aSize = maMat.size();
2219  ToDoubleArray aFunc(aSize.row*aSize.column, bEmptyAsZero);
2220  aFunc = maMat.walk(std::move(aFunc));
2221  aFunc.swap(rArray);
2222 }
2223 
2224 void ScMatrixImpl::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
2225 {
2226  MatrixImplType::size_pair_type aSize = maMat.size();
2227  size_t nSize = aSize.row*aSize.column;
2228  if (nSize != rArray.size())
2229  return;
2230 
2231  MergeDoubleArrayFunc<ArrayMul> aFunc(rArray);
2232  maMat.walk(std::move(aFunc));
2233 }
2234 
2235 namespace {
2236 
2237 template<typename T, typename U, typename return_type>
2238 struct wrapped_iterator
2239 {
2240  typedef ::std::bidirectional_iterator_tag iterator_category;
2241  typedef typename T::const_iterator::value_type old_value_type;
2242  typedef return_type value_type;
2243  typedef value_type* pointer;
2244  typedef value_type& reference;
2245  typedef typename T::const_iterator::difference_type difference_type;
2246 
2247  typename T::const_iterator it;
2248  mutable value_type val;
2249  U maOp;
2250 
2251 private:
2252 
2253  value_type calcVal() const
2254  {
2255  return maOp(*it);
2256  }
2257 
2258 public:
2259 
2260  wrapped_iterator(typename T::const_iterator const & it_, U const & aOp):
2261  it(it_),
2262  val(value_type()),
2263  maOp(aOp)
2264  {
2265  }
2266 
2267  wrapped_iterator(const wrapped_iterator& r):
2268  it(r.it),
2269  val(r.val),
2270  maOp(r.maOp)
2271  {
2272  }
2273 
2274  wrapped_iterator& operator=(const wrapped_iterator& r)
2275  {
2276  it = r.it;
2277  return *this;
2278  }
2279 
2280  bool operator==(const wrapped_iterator& r) const
2281  {
2282  return it == r.it;
2283  }
2284 
2285  bool operator!=(const wrapped_iterator& r) const
2286  {
2287  return !operator==(r);
2288  }
2289 
2290  wrapped_iterator& operator++()
2291  {
2292  ++it;
2293 
2294  return *this;
2295  }
2296 
2297  wrapped_iterator& operator--()
2298  {
2299  --it;
2300 
2301  return *this;
2302  }
2303 
2304  value_type& operator*() const
2305  {
2306  val = calcVal();
2307  return val;
2308  }
2309 
2310  pointer operator->() const
2311  {
2312  val = calcVal();
2313  return &val;
2314  }
2315 };
2316 
2317 template<typename T, typename U, typename return_type>
2318 struct MatrixIteratorWrapper
2319 {
2320 private:
2321  typename T::const_iterator m_itBegin;
2322  typename T::const_iterator m_itEnd;
2323  U maOp;
2324 public:
2325  MatrixIteratorWrapper(typename T::const_iterator const & itBegin, typename T::const_iterator const & itEnd, U const & aOp):
2326  m_itBegin(itBegin),
2327  m_itEnd(itEnd),
2328  maOp(aOp)
2329  {
2330  }
2331 
2332  wrapped_iterator<T, U, return_type> begin()
2333  {
2334  return wrapped_iterator<T, U, return_type>(m_itBegin, maOp);
2335  }
2336 
2337  wrapped_iterator<T, U, return_type> end()
2338  {
2339  return wrapped_iterator<T, U, return_type>(m_itEnd, maOp);
2340  }
2341 };
2342 
2343 MatrixImplType::position_type increment_position(const MatrixImplType::position_type& pos, size_t n)
2344 {
2345  MatrixImplType::position_type ret = pos;
2346  do
2347  {
2348  if (ret.second + n < ret.first->size)
2349  {
2350  ret.second += n;
2351  break;
2352  }
2353  else
2354  {
2355  n -= (ret.first->size - ret.second);
2356  ++ret.first;
2357  ret.second = 0;
2358  }
2359  }
2360  while (n > 0);
2361  return ret;
2362 }
2363 
2364 template<typename T>
2365 struct MatrixOpWrapper
2366 {
2367 private:
2368  MatrixImplType& mrMat;
2369  MatrixImplType::position_type pos;
2370  const T* mpOp;
2371 
2372 public:
2373  MatrixOpWrapper(MatrixImplType& rMat, const T& aOp):
2374  mrMat(rMat),
2375  pos(rMat.position(0,0)),
2376  mpOp(&aOp)
2377  {
2378  }
2379 
2380  MatrixOpWrapper( const MatrixOpWrapper& r ) : mrMat(r.mrMat), pos(r.pos), mpOp(r.mpOp) {}
2381 
2382  MatrixOpWrapper& operator= ( const MatrixOpWrapper& r ) = default;
2383 
2384  void operator()(const MatrixImplType::element_block_node_type& node)
2385  {
2386  switch (node.type)
2387  {
2388  case mdds::mtm::element_numeric:
2389  {
2390  typedef MatrixImplType::numeric_block_type block_type;
2391 
2392  block_type::const_iterator it = block_type::begin(*node.data);
2393  block_type::const_iterator itEnd = block_type::end(*node.data);
2394  MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2395  pos = mrMat.set(pos,aFunc.begin(), aFunc.end());
2396  }
2397  break;
2398  case mdds::mtm::element_boolean:
2399  {
2400  typedef MatrixImplType::boolean_block_type block_type;
2401 
2402  block_type::const_iterator it = block_type::begin(*node.data);
2403  block_type::const_iterator itEnd = block_type::end(*node.data);
2404 
2405  MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2406  pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2407  }
2408  break;
2409  case mdds::mtm::element_string:
2410  {
2411  typedef MatrixImplType::string_block_type block_type;
2412 
2413  block_type::const_iterator it = block_type::begin(*node.data);
2414  block_type::const_iterator itEnd = block_type::end(*node.data);
2415 
2416  MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2417  pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2418  }
2419  break;
2420  case mdds::mtm::element_empty:
2421  {
2422  if (mpOp->useFunctionForEmpty())
2423  {
2424  std::vector<char> aVec(node.size);
2425  MatrixIteratorWrapper<std::vector<char>, T, typename T::number_value_type>
2426  aFunc(aVec.begin(), aVec.end(), *mpOp);
2427  pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2428  }
2429  }
2430  break;
2431  default:
2432  ;
2433  }
2434  pos = increment_position(pos, node.size);
2435  }
2436 };
2437 
2438 }
2439 
2440 template<typename T>
2442 {
2443  MatrixOpWrapper<T> aFunc(rMat.maMat, aOp);
2444  maMat.walk(aFunc);
2445 }
2446 
2447 template<typename T>
2448 std::vector<ScMatrix::IterateResult> ScMatrixImpl::ApplyCollectOperation(const std::vector<T>& aOp)
2449 {
2450  WalkElementBlocksMultipleValues<T> aFunc(aOp);
2451  aFunc = maMat.walk(std::move(aFunc));
2452  return aFunc.getResult();
2453 }
2454 
2455 namespace {
2456 
2457 struct ElementBlock
2458 {
2459  ElementBlock(size_t nRowSize,
2460  ScMatrix::DoubleOpFunction const & aDoubleFunc,
2461  ScMatrix::BoolOpFunction const & aBoolFunc,
2462  ScMatrix::StringOpFunction const & aStringFunc,
2463  ScMatrix::EmptyOpFunction const & aEmptyFunc):
2464  mnRowSize(nRowSize),
2465  mnRowPos(0),
2466  mnColPos(0),
2467  maDoubleFunc(aDoubleFunc),
2468  maBoolFunc(aBoolFunc),
2469  maStringFunc(aStringFunc),
2470  maEmptyFunc(aEmptyFunc)
2471  {
2472  }
2473 
2474  size_t mnRowSize;
2475  size_t mnRowPos;
2476  size_t mnColPos;
2477 
2478  ScMatrix::DoubleOpFunction maDoubleFunc;
2479  ScMatrix::BoolOpFunction maBoolFunc;
2480  ScMatrix::StringOpFunction maStringFunc;
2481  ScMatrix::EmptyOpFunction maEmptyFunc;
2482 };
2483 
2484 class WalkElementBlockOperation
2485 {
2486 public:
2487 
2488  WalkElementBlockOperation(ElementBlock& rElementBlock)
2489  : mrElementBlock(rElementBlock)
2490  {
2491  }
2492 
2493  void operator()(const MatrixImplType::element_block_node_type& node)
2494  {
2495  switch (node.type)
2496  {
2497  case mdds::mtm::element_numeric:
2498  {
2499  typedef MatrixImplType::numeric_block_type block_type;
2500 
2501  block_type::const_iterator it = block_type::begin(*node.data);
2502  std::advance(it, node.offset);
2503  block_type::const_iterator itEnd = it;
2504  std::advance(itEnd, node.size);
2505  for (auto itr = it; itr != itEnd; ++itr)
2506  {
2507  mrElementBlock.maDoubleFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2508  ++mrElementBlock.mnRowPos;
2509  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2510  {
2511  mrElementBlock.mnRowPos = 0;
2512  ++mrElementBlock.mnColPos;
2513  }
2514  }
2515  }
2516  break;
2517  case mdds::mtm::element_string:
2518  {
2519  typedef MatrixImplType::string_block_type block_type;
2520 
2521  block_type::const_iterator it = block_type::begin(*node.data);
2522  std::advance(it, node.offset);
2523  block_type::const_iterator itEnd = it;
2524  std::advance(itEnd, node.size);
2525  for (auto itr = it; itr != itEnd; ++itr)
2526  {
2527  mrElementBlock.maStringFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2528  ++mrElementBlock.mnRowPos;
2529  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2530  {
2531  mrElementBlock.mnRowPos = 0;
2532  ++mrElementBlock.mnColPos;
2533  }
2534  }
2535  }
2536  break;
2537  case mdds::mtm::element_boolean:
2538  {
2539  typedef MatrixImplType::boolean_block_type block_type;
2540 
2541  block_type::const_iterator it = block_type::begin(*node.data);
2542  std::advance(it, node.offset);
2543  block_type::const_iterator itEnd = it;
2544  std::advance(itEnd, node.size);
2545  for (auto itr = it; itr != itEnd; ++itr)
2546  {
2547  mrElementBlock.maBoolFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2548  ++mrElementBlock.mnRowPos;
2549  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2550  {
2551  mrElementBlock.mnRowPos = 0;
2552  ++mrElementBlock.mnColPos;
2553  }
2554  }
2555  }
2556  break;
2557  case mdds::mtm::element_empty:
2558  {
2559  for (size_t i=0; i < node.size; ++i)
2560  {
2561  mrElementBlock.maEmptyFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos);
2562  ++mrElementBlock.mnRowPos;
2563  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2564  {
2565  mrElementBlock.mnRowPos = 0;
2566  ++mrElementBlock.mnColPos;
2567  }
2568  }
2569  }
2570  break;
2571  case mdds::mtm::element_integer:
2572  {
2573  SAL_WARN("sc.core","WalkElementBlockOperation - unhandled element_integer");
2574  // No function (yet?), but advance row and column count.
2575  mrElementBlock.mnColPos += node.size / mrElementBlock.mnRowSize;
2576  mrElementBlock.mnRowPos += node.size % mrElementBlock.mnRowSize;
2577  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2578  {
2579  mrElementBlock.mnRowPos = 0;
2580  ++mrElementBlock.mnColPos;
2581  }
2582  }
2583  break;
2584  }
2585  }
2586 
2587 private:
2588 
2589  ElementBlock& mrElementBlock;
2590 };
2591 
2592 }
2593 
2594 void ScMatrixImpl::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
2595  const std::pair<size_t, size_t>& rEndPos, const ScMatrix::DoubleOpFunction& aDoubleFunc,
2596  const ScMatrix::BoolOpFunction& aBoolFunc, const ScMatrix::StringOpFunction& aStringFunc,
2597  const ScMatrix::EmptyOpFunction& aEmptyFunc) const
2598 {
2599  ElementBlock aPayload(maMat.size().row, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2600  WalkElementBlockOperation aFunc(aPayload);
2601  maMat.walk(
2602  aFunc,
2603  MatrixImplType::size_pair_type(rStartPos.first, rStartPos.second),
2604  MatrixImplType::size_pair_type(rEndPos.first, rEndPos.second));
2605 }
2606 
2607 #if DEBUG_MATRIX
2608 
2609 void ScMatrixImpl::Dump() const
2610 {
2611  cout << "-- matrix content" << endl;
2612  SCSIZE nCols, nRows;
2613  GetDimensions(nCols, nRows);
2614  for (SCSIZE nRow = 0; nRow < nRows; ++nRow)
2615  {
2616  for (SCSIZE nCol = 0; nCol < nCols; ++nCol)
2617  {
2618  cout << " row=" << nRow << ", col=" << nCol << " : ";
2619  switch (maMat.get_type(nRow, nCol))
2620  {
2621  case mdds::mtm::element_string:
2622  cout << "string (" << maMat.get_string(nRow, nCol).getString() << ")";
2623  break;
2624  case mdds::mtm::element_numeric:
2625  cout << "numeric (" << maMat.get_numeric(nRow, nCol) << ")";
2626  break;
2627  case mdds::mtm::element_boolean:
2628  cout << "boolean (" << maMat.get_boolean(nRow, nCol) << ")";
2629  break;
2630  case mdds::mtm::element_empty:
2631  cout << "empty";
2632  break;
2633  default:
2634  ;
2635  }
2636 
2637  cout << endl;
2638  }
2639  }
2640 }
2641 #endif
2642 
2643 void ScMatrixImpl::CalcPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const
2644 {
2645  SCSIZE nRowSize = maMat.size().row;
2646  SAL_WARN_IF( !nRowSize, "sc.core", "ScMatrixImpl::CalcPosition: 0 rows!");
2647  rC = nRowSize > 1 ? nIndex / nRowSize : nIndex;
2648  rR = nIndex - rC*nRowSize;
2649 }
2650 
2651 namespace {
2652 
2653 size_t get_index(SCSIZE nMaxRow, size_t nRow, size_t nCol, size_t nRowOffset, size_t nColOffset)
2654 {
2655  return nMaxRow * (nCol + nColOffset) + nRow + nRowOffset;
2656 }
2657 
2658 }
2659 
2660 void ScMatrixImpl::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
2661  SvNumberFormatter& rFormatter, svl::SharedStringPool& rStringPool)
2662 {
2663  SCSIZE nC1, nC2;
2664  SCSIZE nR1, nR2;
2665  xMat1->GetDimensions(nC1, nR1);
2666  xMat2->GetDimensions(nC2, nR2);
2667 
2668  sal_uInt32 nKey = rFormatter.GetStandardFormat( SvNumFormatType::NUMBER,
2669  ScGlobal::eLnge);
2670 
2671  std::vector<OUString> aString(nMaxCol * nMaxRow);
2672  std::vector<bool> aValid(nMaxCol * nMaxRow, true);
2673  std::vector<FormulaError> nErrors(nMaxCol * nMaxRow,FormulaError::NONE);
2674 
2675  size_t nRowOffset = 0;
2676  size_t nColOffset = 0;
2677  std::function<void(size_t, size_t, double)> aDoubleFunc =
2678  [&](size_t nRow, size_t nCol, double nVal)
2679  {
2680  FormulaError nErr = GetDoubleErrorValue(nVal);
2681  if (nErr != FormulaError::NONE)
2682  {
2683  aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2684  nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2685  return;
2686  }
2687  OUString aStr;
2688  rFormatter.GetInputLineString( nVal, nKey, aStr);
2689  aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2690  };
2691 
2692  std::function<void(size_t, size_t, bool)> aBoolFunc =
2693  [&](size_t nRow, size_t nCol, bool nVal)
2694  {
2695  OUString aStr;
2696  rFormatter.GetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2697  aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2698  };
2699 
2700  std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc =
2701  [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2702  {
2703  aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString();
2704  };
2705 
2706  std::function<void(size_t, size_t)> aEmptyFunc =
2707  [&](size_t /*nRow*/, size_t /*nCol*/)
2708  {
2709  // Nothing. Concatenating an empty string to an existing string.
2710  };
2711 
2712 
2713  if (nC1 == 1 || nR1 == 1)
2714  {
2715  size_t nRowRep = nR1 == 1 ? nMaxRow : 1;
2716  size_t nColRep = nC1 == 1 ? nMaxCol : 1;
2717 
2718  for (size_t i = 0; i < nRowRep; ++i)
2719  {
2720  nRowOffset = i;
2721  for (size_t j = 0; j < nColRep; ++j)
2722  {
2723  nColOffset = j;
2724  xMat1->ExecuteOperation(
2725  std::pair<size_t, size_t>(0, 0),
2726  std::pair<size_t, size_t>(std::min(nR1, nMaxRow) - 1, std::min(nC1, nMaxCol) - 1),
2727  aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2728  }
2729  }
2730  }
2731  else
2732  xMat1->ExecuteOperation(
2733  std::pair<size_t, size_t>(0, 0),
2734  std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2735  aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2736 
2737  std::vector<svl::SharedString> aSharedString(nMaxCol*nMaxRow);
2738 
2739  std::function<void(size_t, size_t, double)> aDoubleFunc2 =
2740  [&](size_t nRow, size_t nCol, double nVal)
2741  {
2742  FormulaError nErr = GetDoubleErrorValue(nVal);
2743  if (nErr != FormulaError::NONE)
2744  {
2745  aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2746  nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2747  return;
2748  }
2749  OUString aStr;
2750  rFormatter.GetInputLineString( nVal, nKey, aStr);
2751  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2752  };
2753 
2754  std::function<void(size_t, size_t, bool)> aBoolFunc2 =
2755  [&](size_t nRow, size_t nCol, bool nVal)
2756  {
2757  OUString aStr;
2758  rFormatter.GetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2759  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2760  };
2761 
2762  std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc2 =
2763  [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2764  {
2765  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2766  rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString());
2767  };
2768 
2769  std::function<void(size_t, size_t)> aEmptyFunc2 =
2770  [&](size_t nRow, size_t nCol)
2771  {
2772  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2773  rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)]);
2774  };
2775 
2776  nRowOffset = 0;
2777  nColOffset = 0;
2778  if (nC2 == 1 || nR2 == 1)
2779  {
2780  size_t nRowRep = nR2 == 1 ? nMaxRow : 1;
2781  size_t nColRep = nC2 == 1 ? nMaxCol : 1;
2782 
2783  for (size_t i = 0; i < nRowRep; ++i)
2784  {
2785  nRowOffset = i;
2786  for (size_t j = 0; j < nColRep; ++j)
2787  {
2788  nColOffset = j;
2789  xMat2->ExecuteOperation(
2790  std::pair<size_t, size_t>(0, 0),
2791  std::pair<size_t, size_t>(std::min(nR2, nMaxRow) - 1, std::min(nC2, nMaxCol) - 1),
2792  aDoubleFunc2, aBoolFunc2, aStringFunc2, aEmptyFunc2);
2793  }
2794  }
2795  }
2796  else
2797  xMat2->ExecuteOperation(
2798  std::pair<size_t, size_t>(0, 0),
2799  std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2800  aDoubleFunc2, aBoolFunc2, aStringFunc2, aEmptyFunc2);
2801 
2802  aString.clear();
2803 
2804  MatrixImplType::position_type pos = maMat.position(0, 0);
2805  for (SCSIZE i = 0; i < nMaxCol; ++i)
2806  {
2807  for (SCSIZE j = 0; j < nMaxRow && i < nMaxCol; ++j)
2808  {
2809  if (aValid[nMaxRow * i + j])
2810  {
2811  auto itr = aValid.begin();
2812  std::advance(itr, nMaxRow * i + j);
2813  auto itrEnd = std::find(itr, aValid.end(), false);
2814  size_t nSteps = std::distance(itr, itrEnd);
2815  auto itrStr = aSharedString.begin();
2816  std::advance(itrStr, nMaxRow * i + j);
2817  auto itrEndStr = itrStr;
2818  std::advance(itrEndStr, nSteps);
2819  pos = maMat.set(pos, itrStr, itrEndStr);
2820  size_t nColSteps = nSteps / nMaxRow;
2821  i += nColSteps;
2822  j += nSteps % nMaxRow;
2823  if (j >= nMaxRow)
2824  {
2825  j -= nMaxRow;
2826  ++i;
2827  }
2828  }
2829  else
2830  {
2831  pos = maMat.set(pos, CreateDoubleError(nErrors[nMaxRow * i + j]));
2832  }
2833  pos = MatrixImplType::next_position(pos);
2834  }
2835  }
2836 }
2837 
2838 void ScMatrix::IncRef() const
2839 {
2840  ++nRefCnt;
2841 }
2842 
2843 void ScMatrix::DecRef() const
2844 {
2845  --nRefCnt;
2846  if (nRefCnt == 0)
2847  delete this;
2848 }
2849 
2851 {
2852  SAL_WARN_IF( !nC, "sc.core", "ScMatrix with 0 columns!");
2853  SAL_WARN_IF( !nR, "sc.core", "ScMatrix with 0 rows!");
2854  // 0-size matrix is valid, it could be resized later.
2855  if ((nC && !nR) || (!nC && nR))
2856  {
2857  SAL_WARN( "sc.core", "ScMatrix one-dimensional zero: " << nC << " columns * " << nR << " rows");
2858  return false;
2859  }
2860  if (!nC || !nR)
2861  return true;
2862 
2863  if (!bElementsMaxFetched)
2864  {
2865  const char* pEnv = std::getenv("SC_MAX_MATRIX_ELEMENTS");
2866  if (pEnv)
2867  {
2868  // Environment specifies the overall elements pool.
2869  nElementsMax = std::atoi(pEnv);
2870  }
2871  else
2872  {
2873  // GetElementsMax() uses an (~arbitrary) elements limit.
2874  // The actual allocation depends on the types of individual matrix
2875  // elements and is averaged for type double.
2876 #if SAL_TYPES_SIZEOFPOINTER < 8
2877  // Assume 1GB memory could be consumed by matrices.
2878  constexpr size_t nMemMax = 0x40000000;
2879 #else
2880  // Assume 6GB memory could be consumed by matrices.
2881  constexpr size_t nMemMax = 0x180000000;
2882 #endif
2883  nElementsMax = GetElementsMax( nMemMax);
2884  }
2885  bElementsMaxFetched = true;
2886  }
2887 
2888  if (nC > (nElementsMax / nR))
2889  {
2890  SAL_WARN( "sc.core", "ScMatrix overflow: " << nC << " columns * " << nR << " rows");
2891  return false;
2892  }
2893  return true;
2894 }
2895 
2897  nRefCnt(0), mbCloneIfConst(true)
2898 {
2899  if (ScMatrix::IsSizeAllocatable( nC, nR))
2900  pImpl.reset( new ScMatrixImpl( nC, nR));
2901  else
2902  // Invalid matrix size, allocate 1x1 matrix with error value.
2903  pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
2904 }
2905 
2906 ScMatrix::ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal) :
2907  nRefCnt(0), mbCloneIfConst(true)
2908 {
2909  if (ScMatrix::IsSizeAllocatable( nC, nR))
2910  pImpl.reset( new ScMatrixImpl( nC, nR, fInitVal));
2911  else
2912  // Invalid matrix size, allocate 1x1 matrix with error value.
2913  pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
2914 }
2915 
2916 ScMatrix::ScMatrix( size_t nC, size_t nR, const std::vector<double>& rInitVals ) :
2917  nRefCnt(0), mbCloneIfConst(true)
2918 {
2919  if (ScMatrix::IsSizeAllocatable( nC, nR))
2920  pImpl.reset( new ScMatrixImpl( nC, nR, rInitVals));
2921  else
2922  // Invalid matrix size, allocate 1x1 matrix with error value.
2923  pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
2924 }
2925 
2927 {
2928 }
2929 
2931 {
2932  SCSIZE nC, nR;
2933  pImpl->GetDimensions(nC, nR);
2934  ScMatrix* pScMat = new ScMatrix(nC, nR);
2935  MatCopy(*pScMat);
2936  pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter()); // TODO: really?
2937  return pScMat;
2938 }
2939 
2941 {
2942  return mbCloneIfConst ? Clone() : this;
2943 }
2944 
2946 {
2947  mbCloneIfConst = false;
2948 }
2949 
2951 {
2952  mbCloneIfConst = true;
2953 }
2954 
2956 {
2957  pImpl->Resize(nC, nR);
2958 }
2959 
2960 void ScMatrix::Resize(SCSIZE nC, SCSIZE nR, double fVal)
2961 {
2962  pImpl->Resize(nC, nR, fVal);
2963 }
2964 
2966 {
2967  ScMatrix* pScMat = new ScMatrix(nNewCols, nNewRows);
2968  MatCopy(*pScMat);
2969  pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter());
2970  return pScMat;
2971 }
2972 
2974 {
2975  pImpl->SetErrorInterpreter(p);
2976 }
2977 
2979 {
2980  pImpl->GetDimensions(rC, rR);
2981 }
2982 
2984 {
2985  return pImpl->GetElementCount();
2986 }
2987 
2989 {
2990  return pImpl->ValidColRow(nC, nR);
2991 }
2992 
2994 {
2995  return pImpl->ValidColRowReplicated(rC, rR);
2996 }
2997 
2999 {
3000  return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
3001 }
3002 
3003 void ScMatrix::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
3004 {
3005  pImpl->PutDouble(fVal, nC, nR);
3006 }
3007 
3008 void ScMatrix::PutDouble( double fVal, SCSIZE nIndex)
3009 {
3010  pImpl->PutDouble(fVal, nIndex);
3011 }
3012 
3013 void ScMatrix::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3014 {
3015  pImpl->PutDouble(pArray, nLen, nC, nR);
3016 }
3017 
3019 {
3020  pImpl->PutString(rStr, nC, nR);
3021 }
3022 
3024 {
3025  pImpl->PutString(rStr, nIndex);
3026 }
3027 
3028 void ScMatrix::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3029 {
3030  pImpl->PutString(pArray, nLen, nC, nR);
3031 }
3032 
3034 {
3035  pImpl->PutEmpty(nC, nR);
3036 }
3037 
3039 {
3040  pImpl->PutEmptyPath(nC, nR);
3041 }
3042 
3043 void ScMatrix::PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR )
3044 {
3045  pImpl->PutError(nErrorCode, nC, nR);
3046 }
3047 
3048 void ScMatrix::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
3049 {
3050  pImpl->PutBoolean(bVal, nC, nR);
3051 }
3052 
3054 {
3055  return pImpl->GetError(nC, nR);
3056 }
3057 
3058 double ScMatrix::GetDouble(SCSIZE nC, SCSIZE nR) const
3059 {
3060  return pImpl->GetDouble(nC, nR);
3061 }
3062 
3063 double ScMatrix::GetDouble( SCSIZE nIndex) const
3064 {
3065  return pImpl->GetDouble(nIndex);
3066 }
3067 
3069 {
3070  return pImpl->GetDoubleWithStringConversion(nC, nR);
3071 }
3072 
3074 {
3075  return pImpl->GetString(nC, nR);
3076 }
3077 
3079 {
3080  return pImpl->GetString(nIndex);
3081 }
3082 
3084 {
3085  return pImpl->GetString(rFormatter, nC, nR);
3086 }
3087 
3089 {
3090  return pImpl->Get(nC, nR);
3091 }
3092 
3093 bool ScMatrix::IsStringOrEmpty( SCSIZE nIndex ) const
3094 {
3095  return pImpl->IsStringOrEmpty(nIndex);
3096 }
3097 
3099 {
3100  return pImpl->IsStringOrEmpty(nC, nR);
3101 }
3102 
3103 bool ScMatrix::IsEmpty( SCSIZE nC, SCSIZE nR ) const
3104 {
3105  return pImpl->IsEmpty(nC, nR);
3106 }
3107 
3109 {
3110  return pImpl->IsEmptyCell(nC, nR);
3111 }
3112 
3114 {
3115  return pImpl->IsEmptyResult(nC, nR);
3116 }
3117 
3119 {
3120  return pImpl->IsEmptyPath(nC, nR);
3121 }
3122 
3123 bool ScMatrix::IsValue( SCSIZE nIndex ) const
3124 {
3125  return pImpl->IsValue(nIndex);
3126 }
3127 
3128 bool ScMatrix::IsValue( SCSIZE nC, SCSIZE nR ) const
3129 {
3130  return pImpl->IsValue(nC, nR);
3131 }
3132 
3134 {
3135  return pImpl->IsValueOrEmpty(nC, nR);
3136 }
3137 
3138 bool ScMatrix::IsBoolean( SCSIZE nC, SCSIZE nR ) const
3139 {
3140  return pImpl->IsBoolean(nC, nR);
3141 }
3142 
3144 {
3145  return pImpl->IsNumeric();
3146 }
3147 
3148 void ScMatrix::MatCopy(const ScMatrix& mRes) const
3149 {
3150  pImpl->MatCopy(*mRes.pImpl);
3151 }
3152 
3153 void ScMatrix::MatTrans(const ScMatrix& mRes) const
3154 {
3155  pImpl->MatTrans(*mRes.pImpl);
3156 }
3157 
3158 void ScMatrix::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
3159 {
3160  pImpl->FillDouble(fVal, nC1, nR1, nC2, nR2);
3161 }
3162 
3163 void ScMatrix::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
3164 {
3165  pImpl->PutDoubleVector(rVec, nC, nR);
3166 }
3167 
3168 void ScMatrix::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
3169 {
3170  pImpl->PutStringVector(rVec, nC, nR);
3171 }
3172 
3174 {
3175  pImpl->PutEmptyVector(nCount, nC, nR);
3176 }
3177 
3179 {
3180  pImpl->PutEmptyResultVector(nCount, nC, nR);
3181 }
3182 
3184 {
3185  pImpl->PutEmptyPathVector(nCount, nC, nR);
3186 }
3187 
3189 {
3190  pImpl->CompareEqual();
3191 }
3192 
3194 {
3195  pImpl->CompareNotEqual();
3196 }
3197 
3199 {
3200  pImpl->CompareLess();
3201 }
3202 
3204 {
3205  pImpl->CompareGreater();
3206 }
3207 
3209 {
3210  pImpl->CompareLessEqual();
3211 }
3212 
3214 {
3215  pImpl->CompareGreaterEqual();
3216 }
3217 
3218 double ScMatrix::And() const
3219 {
3220  return pImpl->And();
3221 }
3222 
3223 double ScMatrix::Or() const
3224 {
3225  return pImpl->Or();
3226 }
3227 
3228 double ScMatrix::Xor() const
3229 {
3230  return pImpl->Xor();
3231 }
3232 
3233 ScMatrix::IterateResult ScMatrix::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
3234 {
3235  return pImpl->Sum(bTextAsZero, bIgnoreErrorValues);
3236 }
3237 
3238 ScMatrix::IterateResult ScMatrix::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
3239 {
3240  return pImpl->SumSquare(bTextAsZero, bIgnoreErrorValues);
3241 }
3242 
3243 ScMatrix::IterateResult ScMatrix::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
3244 {
3245  return pImpl->Product(bTextAsZero, bIgnoreErrorValues);
3246 }
3247 
3248 size_t ScMatrix::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
3249 {
3250  return pImpl->Count(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
3251 }
3252 
3253 size_t ScMatrix::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
3254 {
3255  return pImpl->MatchDoubleInColumns(fValue, nCol1, nCol2);
3256 }
3257 
3258 size_t ScMatrix::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
3259 {
3260  return pImpl->MatchStringInColumns(rStr, nCol1, nCol2);
3261 }
3262 
3263 double ScMatrix::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3264 {
3265  return pImpl->GetMaxValue(bTextAsZero, bIgnoreErrorValues);
3266 }
3267 
3268 double ScMatrix::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3269 {
3270  return pImpl->GetMinValue(bTextAsZero, bIgnoreErrorValues);
3271 }
3272 
3273 double ScMatrix::GetGcd() const
3274 {
3275  return pImpl->GetGcd();
3276 }
3277 
3278 double ScMatrix::GetLcm() const
3279 {
3280  return pImpl->GetLcm();
3281 }
3282 
3283 
3285  sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
3286 {
3287  return pImpl->CompareMatrix(rComp, nMatPos, pOptions);
3288 }
3289 
3290 void ScMatrix::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
3291 {
3292  pImpl->GetDoubleArray(rArray, bEmptyAsZero);
3293 }
3294 
3295 void ScMatrix::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
3296 {
3297  pImpl->MergeDoubleArrayMultiply(rArray);
3298 }
3299 
3300 namespace matop {
3301 
3302 namespace {
3303 
3308 template <typename T, typename S>
3309 struct COp {};
3310 
3311 }
3312 
3313 template <typename T>
3314 struct COp<T, svl::SharedString>
3315 {
3316  const svl::SharedString& operator()(char, T /*aOp*/, double /*a*/, double /*b*/, const svl::SharedString& rString) const
3317  {
3318  return rString;
3319  }
3320 };
3321 
3322 template <typename T>
3323 struct COp<T, double>
3324 {
3325  double operator()(char, T aOp, double a, double b, const svl::SharedString& /*rString*/) const
3326  {
3327  return aOp( a, b);
3328  }
3329 };
3330 
3331 namespace {
3332 
3342 template<typename TOp, typename TEmptyRes=double, typename TRet=double>
3343 struct MatOp
3344 {
3345 private:
3346  TOp maOp;
3349  double mfVal;
3350  COp<TOp, TEmptyRes> maCOp;
3351 
3352 public:
3353  typedef TRet number_value_type;
3354 
3355  MatOp( TOp aOp, ScInterpreter* pErrorInterpreter,
3356  double fVal = 0.0, const svl::SharedString& rString = svl::SharedString() ):
3357  maOp(aOp),
3358  mpErrorInterpreter(pErrorInterpreter),
3359  maString(rString),
3360  mfVal(fVal)
3361  {
3362  if (mpErrorInterpreter)
3363  {
3364  FormulaError nErr = mpErrorInterpreter->GetError();
3365  if (nErr != FormulaError::NONE)
3366  mfVal = CreateDoubleError( nErr);
3367  }
3368  }
3369 
3370  TRet operator()(double fVal) const
3371  {
3372  return maOp(fVal, mfVal);
3373  }
3374 
3375  TRet operator()(bool bVal) const
3376  {
3377  return maOp(static_cast<double>(bVal), mfVal);
3378  }
3379 
3380  double operator()(const svl::SharedString& rStr) const
3381  {
3382  return maOp( convertStringToValue( mpErrorInterpreter, rStr.getString()), mfVal);
3383  }
3384 
3385  TEmptyRes operator()(char) const
3386  {
3387  return maCOp({}, maOp, 0, mfVal, maString);
3388  }
3389 
3390  static bool useFunctionForEmpty()
3391  {
3392  return true;
3393  }
3394 };
3395 
3396 }
3397 
3398 }
3399 
3400 void ScMatrix::NotOp( const ScMatrix& rMat)
3401 {
3402  auto not_ = [](double a, double){return double(a == 0.0);};
3403  matop::MatOp<decltype(not_), double> aOp(not_, pImpl->GetErrorInterpreter());
3404  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3405 }
3406 
3407 void ScMatrix::NegOp( const ScMatrix& rMat)
3408 {
3409  auto neg_ = [](double a, double){return -a;};
3410  matop::MatOp<decltype(neg_), double> aOp(neg_, pImpl->GetErrorInterpreter());
3411  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3412 }
3413 
3414 void ScMatrix::AddOp( double fVal, const ScMatrix& rMat)
3415 {
3416  auto add_ = [](double a, double b){return a + b;};
3417  matop::MatOp<decltype(add_)> aOp(add_, pImpl->GetErrorInterpreter(), fVal);
3418  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3419 }
3420 
3421 void ScMatrix::SubOp( bool bFlag, double fVal, const ScMatrix& rMat)
3422 {
3423  if (bFlag)
3424  {
3425  auto sub_ = [](double a, double b){return b - a;};
3426  matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3427  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3428  }
3429  else
3430  {
3431  auto sub_ = [](double a, double b){return a - b;};
3432  matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3433  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3434  }
3435 }
3436 
3437 void ScMatrix::MulOp( double fVal, const ScMatrix& rMat)
3438 {
3439  auto mul_ = [](double a, double b){return a * b;};
3440  matop::MatOp<decltype(mul_)> aOp(mul_, pImpl->GetErrorInterpreter(), fVal);
3441  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3442 }
3443 
3444 void ScMatrix::DivOp( bool bFlag, double fVal, const ScMatrix& rMat)
3445 {
3446  if (bFlag)
3447  {
3448  auto div_ = [](double a, double b){return sc::div(b, a);};
3449  matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3450  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3451  }
3452  else
3453  {
3454  auto div_ = [](double a, double b){return sc::div(a, b);};
3455  matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3456  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3457  }
3458 }
3459 
3460 void ScMatrix::PowOp( bool bFlag, double fVal, const ScMatrix& rMat)
3461 {
3462  if (bFlag)
3463  {
3464  auto pow_ = [](double a, double b){return sc::power(b, a);};
3465  matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3466  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3467  }
3468  else
3469  {
3470  auto pow_ = [](double a, double b){return sc::power(a, b);};
3471  matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3472  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3473  }
3474 }
3475 
3476 void ScMatrix::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
3477  const std::pair<size_t, size_t>& rEndPos, DoubleOpFunction aDoubleFunc,
3478  BoolOpFunction aBoolFunc, StringOpFunction aStringFunc, EmptyOpFunction aEmptyFunc) const
3479 {
3480  pImpl->ExecuteOperation(rStartPos, rEndPos, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
3481 }
3482 
3483 std::vector<ScMatrix::IterateResult> ScMatrix::Collect(const std::vector<sc::op::Op>& aOp)
3484 {
3485  return pImpl->ApplyCollectOperation(aOp);
3486 }
3487 
3488 #if DEBUG_MATRIX
3489 void ScMatrix::Dump() const
3490 {
3491  pImpl->Dump();
3492 }
3493 #endif
3494 
3495 void ScMatrix::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow,
3496  const ScMatrixRef& xMat1, const ScMatrixRef& xMat2, SvNumberFormatter& rFormatter, svl::SharedStringPool& rPool)
3497 {
3498  pImpl->MatConcat(nMaxCol, nMaxRow, xMat1, xMat2, rFormatter, rPool);
3499 }
3500 
3501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool operator==(const XclFontData &rLeft, const XclFontData &rRight)
Definition: xlstyle.cxx:517
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:113
void CompareLessEqual()
Definition: scmatrix.cxx:1015
bool ValidColRowOrReplicated(SCSIZE &rC, SCSIZE &rR) const
Checks if the matrix position is within the matrix.
Definition: scmatrix.cxx:2998
bool IsEmptyPath(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:823
Type
ScMatrixRef CompareMatrix(sc::Compare &rComp, size_t nMatPos, sc::CompareOptions *pOptions) const
Definition: scmatrix.cxx:2179
void SetErrorAtInterpreter(FormulaError nError) const
Definition: scmatrix.cxx:491
COp< TOp, TEmptyRes > maCOp
Definition: scmatrix.cxx:3350
static bool bElementsMaxFetched
Definition: scmatrix.cxx:344
void PutStringVector(const ::std::vector< svl::SharedString > &rVec, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:927
void MatTrans(ScMatrixImpl &mRes) const
Definition: scmatrix.cxx:892
OUString getString() const
bool ValidColRow(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:2988
SharedString intern(const OUString &rStr)
~ScMatrixImpl() COVERITY_NOEXCEPT_FALSE
Definition: scmatrix.cxx:392
std::vector< ScMatrix::IterateResult > ApplyCollectOperation(const std::vector< T > &aOp)
Definition: scmatrix.cxx:2448
bool operator!=(const XclExpString &rLeft, const XclExpString &rRight)
Definition: xestring.hxx:251
void PutEmptyResultVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:953
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:497
static SharedString getEmptyString()
FormulaError GetError() const
Definition: interpre.hxx:1026
ScInterpreter * pErrorInterpreter
Definition: scmatrix.cxx:229
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3003
double And() const
Definition: scmatrix.cxx:1087
void CompareGreaterEqual()
Definition: scmatrix.cxx:3213
ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const
: If bString the ScMatrixValue->pS may still be NULL to indicate an empty string! ...
Definition: scmatrix.cxx:3088
Cell maCells[2]
Definition: compare.hxx:44
svl::SharedString maString
Definition: scmatrix.cxx:3348
sal_Int64 n
void CompareLess()
Definition: scmatrix.cxx:3198
void Clear()
Definition: scmatrix.cxx:398
const TMatFlag SC_MATFLAG_EMPTYPATH
Definition: scmatrix.cxx:223
mdds::mtv::default_element_block< element_type_string, svl::SharedString > string_block
Definition: mtvelements.hxx:64
sal_Int32 mnCol
SCSIZE GetElementCount() const
Definition: scmatrix.cxx:450
const TMatFlag SC_MATFLAG_EMPTYRESULT
Definition: scmatrix.cxx:222
void GetDoubleArray(std::vector< double > &rArray, bool bEmptyAsZero) const
Definition: scmatrix.cxx:2216
void SubOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3421
friend class ScMatrixImpl
Definition: scmatrix.hxx:115
size_t MatchStringInColumns(const svl::SharedString &rStr, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:2144
void MatCopy(const ScMatrix &mRes) const
Definition: scmatrix.cxx:3148
ScMatrix(const ScMatrix &)=delete
svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:641
void PutEmptyPath(SCSIZE nC, SCSIZE nR)
Jump sal_False without path.
Definition: scmatrix.cxx:3038
SotClipboardFormatId & operator++(SotClipboardFormatId &eFormat)
IterateResult Sum(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3233
ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:726
size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:2137
const ScMatrixImpl & operator=(const ScMatrixImpl &)=delete
void PutString(const svl::SharedString &rStr, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3018
void AddOp(double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3414
Try NOT to use this struct.
Definition: scmatrix.hxx:53
size_t MatchStringInColumns(const svl::SharedString &rStr, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:3258
const svl::SharedString & operator()(char, T, double, double, const svl::SharedString &rString) const
Definition: scmatrix.cxx:3316
double CompareEmptyToNumericFunc(double fCell2)
Left cell is empty while the right cell is numeric.
Definition: compare.cxx:312
void PutEmpty(SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3033
void FillDouble(double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2)
Definition: scmatrix.cxx:3158
void DivOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3444
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3058
def position
double CompareFunc(const Compare &rComp, CompareOptions *pOptions)
Definition: compare.cxx:53
double fVal
Definition: scmatrix.hxx:55
Op_< std::function< void(double &, double)>> Op
void FillDouble(double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2)
Definition: scmatrix.cxx:898
double GetMaxValue(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3263
double GetGcd() const
Definition: scmatrix.cxx:2165
enumrange< T >::Iterator begin(enumrange< T >)
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:45
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
void 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) const
Definition: scmatrix.cxx:3476
std::unique_ptr< ScMatrixImpl > pImpl
Definition: scmatrix.hxx:119
void PutEmptyPathVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Put a column vector of empty paths, starting at row nR, must fit into dimensions. ...
Definition: scmatrix.cxx:3183
void CompareEqual()
Definition: scmatrix.cxx:3188
mdds::multi_type_matrix< matrix_trait > MatrixImplType
int nCount
void PutEmptyVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Put a column vector of empties, starting at row nR, must fit into dimensions.
Definition: scmatrix.cxx:3173
static size_t GetElementsMax(size_t nMemory)
The maximum number of elements a matrix or the pool may have at runtime.
Definition: scmatrix.cxx:355
size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:3253
sal_Int32 mnStartIndex
void CompareGreater()
Definition: scmatrix.cxx:1007
void MatCopy(ScMatrixImpl &mRes) const
Definition: scmatrix.cxx:880
bool ValidColRow(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:456
bool IsNumeric() const
Definition: scmatrix.cxx:3143
bool IsEmptyCell(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:805
double GetLcm() const
Definition: scmatrix.cxx:3278
::boost::intrusive_ptr< ScMatrix > ScMatrixRef
Definition: types.hxx:26
ScMatrix::IterateResult SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2120
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:3093
FormulaError GetDoubleErrorValue(double fVal)
double mfVal
Definition: scmatrix.cxx:3349
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:833
ScInterpreter * GetErrorInterpreter() const
Definition: scmatrix.cxx:246
double TMatFlag
Definition: scmatrix.cxx:221
mdds::mtv::uint16_element_block uint16_block
Definition: mtvelements.hxx:70
double Or() const
Definition: scmatrix.cxx:3223
void DecRef() const
Definition: scmatrix.cxx:2843
std::function< void(size_t, size_t)> EmptyOpFunction
Definition: scmatrix.hxx:133
const SCROW MAXROWCOUNT
Definition: address.hxx:63
ScMatrix::IterateResult Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2115
double And() const
Definition: scmatrix.cxx:3218
DocumentType eType
void PutEmptyResultVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Put a column vector of empty results, starting at row nR, must fit into dimensions.
Definition: scmatrix.cxx:3178
void PowOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3460
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
void MergeDoubleArrayMultiply(std::vector< double > &rArray) const
Definition: scmatrix.cxx:2224
void Resize(SCSIZE nC, SCSIZE nR)
Resize the matrix to specified new dimension.
Definition: scmatrix.cxx:2955
double GetMaxValue(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2151
void PutDoubleVector(const ::std::vector< double > &rVec, SCSIZE nC, SCSIZE nR)
Put a column vector of doubles, starting at row nR, must fit into dimensions.
Definition: scmatrix.cxx:3163
void PutString(const svl::SharedString &rStr, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:524
bool IsNumeric() const
Definition: scmatrix.cxx:875
double ConvertStringToValue(const OUString &)
Definition: interpr4.cxx:160
void NotOp(const ScMatrix &rMat)
Definition: scmatrix.cxx:3400
TOp maOp
Definition: scmatrix.cxx:3346
bool IsEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:796
int i
ScMatrix * CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const
Clone the matrix and extend it to the new size.
Definition: scmatrix.cxx:2965
svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3073
uno_Any a
double Xor() const
Definition: scmatrix.cxx:3228
double GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:633
FormulaError GetError(SCSIZE nC, SCSIZE nR) const
May be used before obtaining the double value of an element to avoid passing its NAN around...
Definition: scmatrix.cxx:3053
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2978
ScMatrixRef CompareMatrix(sc::Compare &rComp, size_t nMatPos, sc::CompareOptions *pOptions) const
Definition: scmatrix.cxx:3284
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:443
void CompareEqual()
Definition: scmatrix.cxx:983
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3138
void CompareGreaterEqual()
Definition: scmatrix.cxx:1023
mdds::multi_type_matrix< matrix_trait > MatrixImplType
Definition: scmatrix.cxx:68
SvNumFormatType
double operator()(char, T aOp, double a, double b, const svl::SharedString &) const
Definition: scmatrix.cxx:3325
void PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3048
double Xor() const
Definition: scmatrix.cxx:1101
css::beans::Optional< css::uno::Any > getValue(std::u16string_view id)
static SC_DLLPUBLIC LanguageType eLnge
Definition: global.hxx:549
std::size_t mnCount
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString)
bool ValidColRowReplicated(SCSIZE &rC, SCSIZE &rR) const
For a row vector or column vector, if the position does not point into the vector but is a valid colu...
Definition: scmatrix.cxx:2993
void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef &xMat1, const ScMatrixRef &xMat2, SvNumberFormatter &rFormatter, svl::SharedStringPool &rPool)
Definition: scmatrix.cxx:3495
ScMatrix * CloneIfConst()
Clone the matrix if mbCloneIfConst (immutable) is set, otherwise return this matrix, to be assigned to a ScMatrixRef.
Definition: scmatrix.cxx:2940
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:606
ScMatValType nType
Definition: scmatrix.hxx:57
enumrange< T >::Iterator end(enumrange< T >)
double GetGcd() const
Definition: scmatrix.cxx:3273
FormulaError
FormulaError GetError(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:592
static size_t nElementsMax
Definition: scmatrix.cxx:345
void MatTrans(const ScMatrix &mRes) const
Definition: scmatrix.cxx:3153
double power(const double &fVal1, const double &fVal2)
Return pow(fVal1,fVal2) with error handling.
Definition: math.cxx:29
IterateResult Product(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3243
void PutDoubleVector(const ::std::vector< double > &rVec, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:915
std::vector< ScMatrix::IterateResult > Collect(const std::vector< sc::op::Op > &aOp)
Definition: scmatrix.cxx:3483
void PutError(FormulaError nErrorCode, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3043
double CreateDoubleError(FormulaError nErr)
void SetErrorInterpreter(ScInterpreter *p)
Definition: scmatrix.cxx:2973
ScInterpreter * mpErrorInterpreter
Definition: scmatrix.cxx:3347
bool ValidColRowOrReplicated(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:486
void IncRef() const
Definition: scmatrix.cxx:2838
svl::SharedString maStr
Definition: compare.hxx:37
std::function< void(size_t, size_t, double)> DoubleOpFunction
Definition: scmatrix.hxx:130
#define SAL_WARN_IF(condition, area, stream)
MatrixImplType maMatFlag
Definition: scmatrix.cxx:228
void 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) const
Definition: scmatrix.cxx:2594
bool IsEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3103
void CompareNotEqual()
Definition: scmatrix.cxx:3193
void CompareLess()
Definition: scmatrix.cxx:999
void Resize(SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:404
SvStream & endl(SvStream &rStr)
bool IsEmptyResult(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:814
ScQueryOp meOp
Definition: compare.hxx:46
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
std::function< void(size_t, size_t, svl::SharedString)> StringOpFunction
Definition: scmatrix.hxx:132
size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings=false) const
Definition: scmatrix.cxx:3248
void SetMutable()
Set the matrix to mutable for CloneIfConst(), only the interpreter should do this and know the conseq...
Definition: scmatrix.cxx:2945
void GetDoubleArray(std::vector< double > &rArray, bool bEmptyAsZero=true) const
Convert the content of matrix into a linear array of numeric values.
Definition: scmatrix.cxx:3290
bool IsEmptyResult(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3113
void SetErrorInterpreter(ScInterpreter *p)
Definition: scmatrix.cxx:438
These need to be in global namespace just like their respective types are.
void CalcPosition(SCSIZE nIndex, SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2643
When adding all numerical matrix elements for a scalar result such as summation, the interpreter want...
Definition: scmatrix.hxx:144
MatrixImplType maMat
Definition: scmatrix.cxx:227
HSLColor operator*(double nFactor, const HSLColor &rRHS)
double Or() const
Definition: scmatrix.cxx:1094
ScMatrix * Clone() const
Clone the matrix.
Definition: scmatrix.cxx:2930
double GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3068
FILE * init(int, char **)
ScQueryOp
Definition: global.hxx:820
ScMatrix::IterateResult Product(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2125
void CompareNotEqual()
Definition: scmatrix.cxx:991
void PutEmpty(SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:551
void PutError(FormulaError nErrorCode, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:577
svl::SharedString aStr
Definition: scmatrix.hxx:56
double GetMinValue(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3268
void PutEmptyPath(SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:564
void CompareLessEqual()
Definition: scmatrix.cxx:3208
Any result
#define SAL_WARN(area, stream)
bool IsValueOrEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:854
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:3123
SCSIZE GetElementCount() const
Definition: scmatrix.cxx:2983
IterateResult SumSquare(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3238
void PutEmptyPathVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:968
bool IsEmptyPath(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3118
sal_Int32 mnRow
bool mbCloneIfConst
Definition: scmatrix.hxx:118
void SetImmutable() const
Set the matrix to immutable for CloneIfConst(), only the interpreter should do this and know the cons...
Definition: scmatrix.cxx:2950
void PutStringVector(const ::std::vector< svl::SharedString > &rVec, SCSIZE nC, SCSIZE nR)
Put a column vector of strings, starting at row nR, must fit into dimensions.
Definition: scmatrix.cxx:3168
void MulOp(double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3437
int mnIndex
void ApplyOperation(T aOp, ScMatrixImpl &rMat)
Definition: scmatrix.cxx:2441
bool IsEmptyCell(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3108
double GetMinValue(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2158
void PutEmptyVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:939
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:869
void NegOp(const ScMatrix &rMat)
Definition: scmatrix.cxx:3407
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:775
void MergeDoubleArrayMultiply(std::vector< double > &rArray) const
Definition: scmatrix.cxx:3295
void PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:582
void CompareGreater()
Definition: scmatrix.cxx:3203
void SetError(FormulaError nError)
Definition: interpre.hxx:1019
aStr
std::function< void(size_t, size_t, bool)> BoolOpFunction
Definition: scmatrix.hxx:131
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
static OUString GetErrorString(FormulaError nErrNumber)
Definition: global.cxx:300
SbxDecimal::CmpResult compare(SAL_UNUSED_PARAMETER const SbxDecimal &, SAL_UNUSED_PARAMETER const SbxDecimal &)
double GetLcm() const
Definition: scmatrix.cxx:2172
bool IsValueOrEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3133
double div(const double &fNumerator, const double &fDenominator)
Return fNumerator/fDenominator if fDenominator!=0 else #DIV/0! error coded into double.
Definition: math.hxx:31
static double ScGetGCD(double fx, double fy)
Definition: interpr5.cxx:108
ScMatrixImpl(const ScMatrixImpl &)=delete
static bool IsSizeAllocatable(SCSIZE nC, SCSIZE nR)
Checks nC or nR for zero and uses GetElementsMax() whether a matrix of the size of nC*nR could be all...
Definition: scmatrix.cxx:2850
void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef &xMat1, const ScMatrixRef &xMat2, SvNumberFormatter &rFormatter, svl::SharedStringPool &rPool)
Definition: scmatrix.cxx:2660
bool ValidColRowReplicated(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:462
size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
Definition: scmatrix.cxx:2130