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::KahanIterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues ) const;
306  ScMatrix::KahanIterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues ) const;
307  ScMatrix::DoubleIterateResult 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, typename tRes>
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, typename tRes>
1111 class WalkElementBlocks
1112 {
1113  Op maOp;
1115  bool mbTextAsZero:1;
1116  bool mbIgnoreErrorValues:1;
1117 public:
1118  WalkElementBlocks(bool bTextAsZero, bool bIgnoreErrorValues) :
1119  maRes(Op::InitVal, 0),
1120  mbTextAsZero(bTextAsZero), mbIgnoreErrorValues(bIgnoreErrorValues)
1121  {}
1122 
1123  const ScMatrix::IterateResult<tRes>& getResult() const { return maRes; }
1124 
1125  void operator() (const MatrixImplType::element_block_node_type& node)
1126  {
1127  switch (node.type)
1128  {
1129  case mdds::mtm::element_numeric:
1130  {
1131  typedef MatrixImplType::numeric_block_type block_type;
1132 
1133  size_t nIgnored = 0;
1134  block_type::const_iterator it = block_type::begin(*node.data);
1135  block_type::const_iterator itEnd = block_type::end(*node.data);
1136  for (; it != itEnd; ++it)
1137  {
1138  if (mbIgnoreErrorValues && !std::isfinite(*it))
1139  {
1140  ++nIgnored;
1141  continue;
1142  }
1143  maOp(maRes.maAccumulator, *it);
1144  }
1145  maRes.mnCount += node.size - nIgnored;
1146  }
1147  break;
1148  case mdds::mtm::element_boolean:
1149  {
1150  typedef MatrixImplType::boolean_block_type block_type;
1151 
1152  block_type::const_iterator it = block_type::begin(*node.data);
1153  block_type::const_iterator itEnd = block_type::end(*node.data);
1154  for (; it != itEnd; ++it)
1155  {
1156  maOp(maRes.maAccumulator, *it);
1157  }
1158  maRes.mnCount += node.size;
1159  }
1160  break;
1161  case mdds::mtm::element_string:
1162  if (mbTextAsZero)
1163  maRes.mnCount += node.size;
1164  break;
1165  case mdds::mtm::element_empty:
1166  default:
1167  ;
1168  }
1169  }
1170 };
1171 
1172 template<typename Op, typename tRes>
1173 class WalkElementBlocksMultipleValues
1174 {
1175  const std::vector<Op>* mpOp;
1177 public:
1178  WalkElementBlocksMultipleValues(const std::vector<Op>& aOp) :
1179  mpOp(&aOp), maRes(0)
1180  {
1181  for (const auto& rpOp : *mpOp)
1182  maRes.maAccumulator.emplace_back(rpOp.mInitVal);
1183  }
1184 
1185  WalkElementBlocksMultipleValues( const WalkElementBlocksMultipleValues& ) = delete;
1186  WalkElementBlocksMultipleValues& operator= ( const WalkElementBlocksMultipleValues& ) = delete;
1187 
1188  WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues&& r) noexcept
1189  : mpOp(r.mpOp), maRes(r.maRes.mnCount)
1190  {
1191  maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1192  }
1193 
1194  WalkElementBlocksMultipleValues& operator=(WalkElementBlocksMultipleValues&& r) noexcept
1195  {
1196  mpOp = r.mpOp;
1197  maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1198  maRes.mnCount = r.maRes.mnCount;
1199  return *this;
1200  }
1201 
1202  const ScMatrix::IterateResultMultiple<tRes>& getResult() const { return maRes; }
1203 
1204  void operator() (const MatrixImplType::element_block_node_type& node)
1205  {
1206  switch (node.type)
1207  {
1208  case mdds::mtm::element_numeric:
1209  {
1210  typedef MatrixImplType::numeric_block_type block_type;
1211 
1212  block_type::const_iterator it = block_type::begin(*node.data);
1213  block_type::const_iterator itEnd = block_type::end(*node.data);
1214  for (; it != itEnd; ++it)
1215  {
1216  for (size_t i = 0u; i < mpOp->size(); ++i)
1217  (*mpOp)[i](maRes.maAccumulator[i], *it);
1218  }
1219  maRes.mnCount += node.size;
1220  }
1221  break;
1222  case mdds::mtm::element_boolean:
1223  {
1224  typedef MatrixImplType::boolean_block_type block_type;
1225 
1226  block_type::const_iterator it = block_type::begin(*node.data);
1227  block_type::const_iterator itEnd = block_type::end(*node.data);
1228  for (; it != itEnd; ++it)
1229  {
1230  for (size_t i = 0u; i < mpOp->size(); ++i)
1231  (*mpOp)[i](maRes.maAccumulator[i], *it);
1232  }
1233  maRes.mnCount += node.size;
1234  }
1235  break;
1236  case mdds::mtm::element_string:
1237  case mdds::mtm::element_empty:
1238  default:
1239  ;
1240  }
1241  }
1242 };
1243 
1244 class CountElements
1245 {
1246  size_t mnCount;
1247  bool mbCountString;
1248  bool mbCountErrors;
1249  bool mbIgnoreEmptyStrings;
1250 public:
1251  explicit CountElements(bool bCountString, bool bCountErrors, bool bIgnoreEmptyStrings) :
1252  mnCount(0), mbCountString(bCountString), mbCountErrors(bCountErrors),
1253  mbIgnoreEmptyStrings(bIgnoreEmptyStrings) {}
1254 
1255  size_t getCount() const { return mnCount; }
1256 
1257  void operator() (const MatrixImplType::element_block_node_type& node)
1258  {
1259  switch (node.type)
1260  {
1261  case mdds::mtm::element_numeric:
1262  mnCount += node.size;
1263  if (!mbCountErrors)
1264  {
1265  typedef MatrixImplType::numeric_block_type block_type;
1266 
1267  block_type::const_iterator it = block_type::begin(*node.data);
1268  block_type::const_iterator itEnd = block_type::end(*node.data);
1269  for (; it != itEnd; ++it)
1270  {
1271  if (!std::isfinite(*it))
1272  --mnCount;
1273  }
1274  }
1275  break;
1276  case mdds::mtm::element_boolean:
1277  mnCount += node.size;
1278  break;
1279  case mdds::mtm::element_string:
1280  if (mbCountString)
1281  {
1282  mnCount += node.size;
1283  if (mbIgnoreEmptyStrings)
1284  {
1285  typedef MatrixImplType::string_block_type block_type;
1286 
1287  block_type::const_iterator it = block_type::begin(*node.data);
1288  block_type::const_iterator itEnd = block_type::end(*node.data);
1289  for (; it != itEnd; ++it)
1290  {
1291  if (it->isEmpty())
1292  --mnCount;
1293  }
1294  }
1295  }
1296  break;
1297  case mdds::mtm::element_empty:
1298  default:
1299  ;
1300  }
1301  }
1302 };
1303 
1304 const size_t ResultNotSet = std::numeric_limits<size_t>::max();
1305 
1306 template<typename Type>
1307 class WalkAndMatchElements
1308 {
1309  Type maMatchValue;
1310  size_t mnStartIndex;
1311  size_t mnStopIndex;
1312  size_t mnResult;
1313  size_t mnIndex;
1314 
1315 public:
1316  WalkAndMatchElements(Type aMatchValue, const MatrixImplType::size_pair_type& aSize, size_t nCol1, size_t nCol2) :
1317  maMatchValue(aMatchValue),
1318  mnStartIndex( nCol1 * aSize.row ),
1319  mnStopIndex( (nCol2 + 1) * aSize.row ),
1320  mnResult(ResultNotSet),
1321  mnIndex(0)
1322  {
1323  assert( nCol1 < aSize.column && nCol2 < aSize.column);
1324  }
1325 
1326  size_t getMatching() const { return mnResult; }
1327 
1328  size_t getRemainingCount() const
1329  {
1330  return mnIndex < mnStopIndex ? mnStopIndex - mnIndex : 0;
1331  }
1332 
1333  size_t compare(const MatrixImplType::element_block_node_type& node) const;
1334 
1335  void operator() (const MatrixImplType::element_block_node_type& node)
1336  {
1337  // early exit if match already found
1338  if (mnResult != ResultNotSet)
1339  return;
1340 
1341  // limit lookup to the requested columns
1342  if (mnStartIndex <= mnIndex && getRemainingCount() > 0)
1343  {
1344  mnResult = compare(node);
1345  }
1346 
1347  mnIndex += node.size;
1348  }
1349 };
1350 
1351 template<>
1352 size_t WalkAndMatchElements<double>::compare(const MatrixImplType::element_block_node_type& node) const
1353 {
1354  size_t nCount = 0;
1355  switch (node.type)
1356  {
1357  case mdds::mtm::element_numeric:
1358  {
1359  typedef MatrixImplType::numeric_block_type block_type;
1360 
1361  block_type::const_iterator it = block_type::begin(*node.data);
1362  block_type::const_iterator itEnd = block_type::end(*node.data);
1363  const size_t nRemaining = getRemainingCount();
1364  for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1365  {
1366  if (*it == maMatchValue)
1367  {
1368  return mnIndex + nCount;
1369  }
1370  }
1371  break;
1372  }
1373  case mdds::mtm::element_boolean:
1374  {
1375  typedef MatrixImplType::boolean_block_type block_type;
1376 
1377  block_type::const_iterator it = block_type::begin(*node.data);
1378  block_type::const_iterator itEnd = block_type::end(*node.data);
1379  const size_t nRemaining = getRemainingCount();
1380  for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1381  {
1382  if (int(*it) == maMatchValue)
1383  {
1384  return mnIndex + nCount;
1385  }
1386  }
1387  break;
1388  }
1389  break;
1390  case mdds::mtm::element_string:
1391  case mdds::mtm::element_empty:
1392  default:
1393  ;
1394  }
1395  return ResultNotSet;
1396 }
1397 
1398 template<>
1399 size_t WalkAndMatchElements<svl::SharedString>::compare(const MatrixImplType::element_block_node_type& node) const
1400 {
1401  switch (node.type)
1402  {
1403  case mdds::mtm::element_string:
1404  {
1405  size_t nCount = 0;
1406  typedef MatrixImplType::string_block_type block_type;
1407 
1408  block_type::const_iterator it = block_type::begin(*node.data);
1409  block_type::const_iterator itEnd = block_type::end(*node.data);
1410  const size_t nRemaining = getRemainingCount();
1411  for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1412  {
1413  if (it->getDataIgnoreCase() == maMatchValue.getDataIgnoreCase())
1414  {
1415  return mnIndex + nCount;
1416  }
1417  }
1418  break;
1419  }
1420  case mdds::mtm::element_boolean:
1421  case mdds::mtm::element_numeric:
1422  case mdds::mtm::element_empty:
1423  default:
1424  ;
1425  }
1426  return ResultNotSet;
1427 }
1428 
1429 struct MaxOp
1430 {
1431  static double init() { return -std::numeric_limits<double>::max(); }
1432  static double compare(double left, double right)
1433  {
1434  if (!std::isfinite(left))
1435  return left;
1436  if (!std::isfinite(right))
1437  return right;
1438  return std::max(left, right);
1439  }
1440 
1441  static double boolValue(
1442  MatrixImplType::boolean_block_type::const_iterator it,
1443  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1444  {
1445  // If the array has at least one true value, the maximum value is 1.
1446  it = std::find(it, itEnd, true);
1447  return it == itEnd ? 0.0 : 1.0;
1448  }
1449 };
1450 
1451 struct MinOp
1452 {
1453  static double init() { return std::numeric_limits<double>::max(); }
1454  static double compare(double left, double right)
1455  {
1456  if (!std::isfinite(left))
1457  return left;
1458  if (!std::isfinite(right))
1459  return right;
1460  return std::min(left, right);
1461  }
1462 
1463  static double boolValue(
1464  MatrixImplType::boolean_block_type::const_iterator it,
1465  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1466  {
1467  // If the array has at least one false value, the minimum value is 0.
1468  it = std::find(it, itEnd, false);
1469  return it == itEnd ? 1.0 : 0.0;
1470  }
1471 };
1472 
1473 struct Lcm
1474 {
1475  static double init() { return 1.0; }
1476  static double calculate(double fx,double fy)
1477  {
1478  return (fx*fy)/ScInterpreter::ScGetGCD(fx,fy);
1479  }
1480 
1481  static double boolValue(
1482  MatrixImplType::boolean_block_type::const_iterator it,
1483  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1484  {
1485  // If the array has at least one false value, the minimum value is 0.
1486  it = std::find(it, itEnd, false);
1487  return it == itEnd ? 1.0 : 0.0;
1488  }
1489 };
1490 
1491 struct Gcd
1492 {
1493  static double init() { return 0.0; }
1494  static double calculate(double fx,double fy)
1495  {
1496  return ScInterpreter::ScGetGCD(fx,fy);
1497  }
1498 
1499  static double boolValue(
1500  MatrixImplType::boolean_block_type::const_iterator it,
1501  const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1502  {
1503  // If the array has at least one true value, the gcdResult is 1.
1504  it = std::find(it, itEnd, true);
1505  return it == itEnd ? 0.0 : 1.0;
1506  }
1507 };
1508 
1509 template<typename Op>
1510 class CalcMaxMinValue
1511 {
1512  double mfVal;
1513  bool mbTextAsZero;
1514  bool mbIgnoreErrorValues;
1515  bool mbHasValue;
1516 public:
1517  CalcMaxMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) :
1518  mfVal(Op::init()),
1519  mbTextAsZero(bTextAsZero),
1520  mbIgnoreErrorValues(bIgnoreErrorValues),
1521  mbHasValue(false) {}
1522 
1523  double getValue() const { return mbHasValue ? mfVal : 0.0; }
1524 
1525  void operator() (const MatrixImplType::element_block_node_type& node)
1526  {
1527 
1528  switch (node.type)
1529  {
1530  case mdds::mtm::element_numeric:
1531  {
1532  typedef MatrixImplType::numeric_block_type block_type;
1533 
1534  block_type::const_iterator it = block_type::begin(*node.data);
1535  block_type::const_iterator itEnd = block_type::end(*node.data);
1536  if (mbIgnoreErrorValues)
1537  {
1538  for (; it != itEnd; ++it)
1539  {
1540  if (std::isfinite(*it))
1541  mfVal = Op::compare(mfVal, *it);
1542  }
1543  }
1544  else
1545  {
1546  for (; it != itEnd; ++it)
1547  mfVal = Op::compare(mfVal, *it);
1548  }
1549 
1550  mbHasValue = true;
1551  }
1552  break;
1553  case mdds::mtm::element_boolean:
1554  {
1555  typedef MatrixImplType::boolean_block_type block_type;
1556 
1557  block_type::const_iterator it = block_type::begin(*node.data);
1558  block_type::const_iterator itEnd = block_type::end(*node.data);
1559  double fVal = Op::boolValue(it, itEnd);
1560  mfVal = Op::compare(mfVal, fVal);
1561  mbHasValue = true;
1562  }
1563  break;
1564  case mdds::mtm::element_string:
1565  case mdds::mtm::element_empty:
1566  {
1567  // empty elements are treated as empty strings.
1568  if (mbTextAsZero)
1569  {
1570  mfVal = Op::compare(mfVal, 0.0);
1571  mbHasValue = true;
1572  }
1573  }
1574  break;
1575  default:
1576  ;
1577  }
1578  }
1579 };
1580 
1581 template<typename Op>
1582 class CalcGcdLcm
1583 {
1584  double mfval;
1585 
1586 public:
1587  CalcGcdLcm() : mfval(Op::init()) {}
1588 
1589  double getResult() const { return mfval; }
1590 
1591  void operator() ( const MatrixImplType::element_block_node_type& node )
1592  {
1593  switch (node.type)
1594  {
1595  case mdds::mtm::element_numeric:
1596  {
1597  typedef MatrixImplType::numeric_block_type block_type;
1598  block_type::const_iterator it = block_type::begin(*node.data);
1599  block_type::const_iterator itEnd = block_type::end(*node.data);
1600 
1601  for ( ; it != itEnd; ++it)
1602  {
1603  if (*it < 0.0)
1604  mfval = CreateDoubleError(FormulaError::IllegalArgument);
1605  else
1606  mfval = ::rtl::math::approxFloor( Op::calculate(*it,mfval));
1607  }
1608  }
1609  break;
1610  case mdds::mtm::element_boolean:
1611  {
1612  typedef MatrixImplType::boolean_block_type block_type;
1613  block_type::const_iterator it = block_type::begin(*node.data);
1614  block_type::const_iterator itEnd = block_type::end(*node.data);
1615 
1616  mfval = Op::boolValue(it, itEnd);
1617  }
1618  break;
1619  case mdds::mtm::element_empty:
1620  case mdds::mtm::element_string:
1621  {
1622  mfval = CreateDoubleError(FormulaError::IllegalArgument);
1623  }
1624  break;
1625  default:
1626  ;
1627  }
1628  }
1629 };
1630 
1631 double evaluate( double fVal, ScQueryOp eOp )
1632 {
1633  if (!std::isfinite(fVal))
1634  return fVal;
1635 
1636  switch (eOp)
1637  {
1638  case SC_EQUAL:
1639  return fVal == 0.0 ? 1.0 : 0.0;
1640  case SC_LESS:
1641  return fVal < 0.0 ? 1.0 : 0.0;
1642  case SC_GREATER:
1643  return fVal > 0.0 ? 1.0 : 0.0;
1644  case SC_LESS_EQUAL:
1645  return fVal <= 0.0 ? 1.0 : 0.0;
1646  case SC_GREATER_EQUAL:
1647  return fVal >= 0.0 ? 1.0 : 0.0;
1648  case SC_NOT_EQUAL:
1649  return fVal != 0.0 ? 1.0 : 0.0;
1650  default:
1651  ;
1652  }
1653 
1654  SAL_WARN("sc.core", "evaluate: unhandled comparison operator: " << static_cast<int>(eOp));
1655  return CreateDoubleError( FormulaError::UnknownState);
1656 }
1657 
1658 class CompareMatrixFunc
1659 {
1660  sc::Compare& mrComp;
1661  size_t mnMatPos;
1662  sc::CompareOptions* mpOptions;
1663  std::vector<double> maResValues; // double instead of bool to transport error values
1664 
1665  void compare()
1666  {
1667  double fVal = sc::CompareFunc( mrComp, mpOptions);
1668  maResValues.push_back(evaluate(fVal, mrComp.meOp));
1669  }
1670 
1671 public:
1672  CompareMatrixFunc( size_t nResSize, sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) :
1673  mrComp(rComp), mnMatPos(nMatPos), mpOptions(pOptions)
1674  {
1675  maResValues.reserve(nResSize);
1676  }
1677 
1678  CompareMatrixFunc( const CompareMatrixFunc& ) = delete;
1679  CompareMatrixFunc& operator= ( const CompareMatrixFunc& ) = delete;
1680 
1681  CompareMatrixFunc(CompareMatrixFunc&& r) noexcept :
1682  mrComp(r.mrComp),
1683  mnMatPos(r.mnMatPos),
1684  mpOptions(r.mpOptions),
1685  maResValues(std::move(r.maResValues)) {}
1686 
1687  CompareMatrixFunc& operator=(CompareMatrixFunc&& r) noexcept
1688  {
1689  mrComp = r.mrComp;
1690  mnMatPos = r.mnMatPos;
1691  mpOptions = r.mpOptions;
1692  maResValues = std::move(r.maResValues);
1693  return *this;
1694  }
1695 
1696  void operator() (const MatrixImplType::element_block_node_type& node)
1697  {
1698  sc::Compare::Cell& rCell = mrComp.maCells[mnMatPos];
1699 
1700  switch (node.type)
1701  {
1702  case mdds::mtm::element_numeric:
1703  {
1704  typedef MatrixImplType::numeric_block_type block_type;
1705 
1706  block_type::const_iterator it = block_type::begin(*node.data);
1707  block_type::const_iterator itEnd = block_type::end(*node.data);
1708  for (; it != itEnd; ++it)
1709  {
1710  rCell.mbValue = true;
1711  rCell.mbEmpty = false;
1712  rCell.mfValue = *it;
1713  compare();
1714  }
1715  }
1716  break;
1717  case mdds::mtm::element_boolean:
1718  {
1719  typedef MatrixImplType::boolean_block_type block_type;
1720 
1721  block_type::const_iterator it = block_type::begin(*node.data);
1722  block_type::const_iterator itEnd = block_type::end(*node.data);
1723  for (; it != itEnd; ++it)
1724  {
1725  rCell.mbValue = true;
1726  rCell.mbEmpty = false;
1727  rCell.mfValue = double(*it);
1728  compare();
1729  }
1730  }
1731  break;
1732  case mdds::mtm::element_string:
1733  {
1734  typedef MatrixImplType::string_block_type block_type;
1735 
1736  block_type::const_iterator it = block_type::begin(*node.data);
1737  block_type::const_iterator itEnd = block_type::end(*node.data);
1738  for (; it != itEnd; ++it)
1739  {
1740  const svl::SharedString& rStr = *it;
1741  rCell.mbValue = false;
1742  rCell.mbEmpty = false;
1743  rCell.maStr = rStr;
1744  compare();
1745  }
1746  }
1747  break;
1748  case mdds::mtm::element_empty:
1749  {
1750  rCell.mbValue = false;
1751  rCell.mbEmpty = true;
1753  for (size_t i = 0; i < node.size; ++i)
1754  compare();
1755  }
1756  break;
1757  default:
1758  ;
1759  }
1760  }
1761 
1762  const std::vector<double>& getValues() const
1763  {
1764  return maResValues;
1765  }
1766 };
1767 
1771 class CompareMatrixToNumericFunc
1772 {
1773  sc::Compare& mrComp;
1774  double mfRightValue;
1775  sc::CompareOptions* mpOptions;
1776  std::vector<double> maResValues; // double instead of bool to transport error values
1777 
1778  void compare()
1779  {
1780  double fVal = sc::CompareFunc(mrComp.maCells[0], mfRightValue, mpOptions);
1781  maResValues.push_back(evaluate(fVal, mrComp.meOp));
1782  }
1783 
1784  void compareLeftNumeric( double fLeftVal )
1785  {
1786  double fVal = sc::CompareFunc(fLeftVal, mfRightValue);
1787  maResValues.push_back(evaluate(fVal, mrComp.meOp));
1788  }
1789 
1790  void compareLeftEmpty( size_t nSize )
1791  {
1792  double fVal = sc::CompareEmptyToNumericFunc(mfRightValue);
1793  bool bRes = evaluate(fVal, mrComp.meOp);
1794  maResValues.resize(maResValues.size() + nSize, bRes ? 1.0 : 0.0);
1795  }
1796 
1797 public:
1798  CompareMatrixToNumericFunc( size_t nResSize, sc::Compare& rComp, double fRightValue, sc::CompareOptions* pOptions ) :
1799  mrComp(rComp), mfRightValue(fRightValue), mpOptions(pOptions)
1800  {
1801  maResValues.reserve(nResSize);
1802  }
1803 
1804  CompareMatrixToNumericFunc( const CompareMatrixToNumericFunc& ) = delete;
1805  CompareMatrixToNumericFunc& operator= ( const CompareMatrixToNumericFunc& ) = delete;
1806 
1807  CompareMatrixToNumericFunc(CompareMatrixToNumericFunc&& r) noexcept :
1808  mrComp(r.mrComp),
1809  mfRightValue(r.mfRightValue),
1810  mpOptions(r.mpOptions),
1811  maResValues(std::move(r.maResValues)) {}
1812 
1813  CompareMatrixToNumericFunc& operator=(CompareMatrixToNumericFunc&& r) noexcept
1814  {
1815  mrComp = r.mrComp;
1816  mfRightValue = r.mfRightValue;
1817  mpOptions = r.mpOptions;
1818  maResValues = std::move(r.maResValues);
1819  return *this;
1820  }
1821 
1822  void operator() (const MatrixImplType::element_block_node_type& node)
1823  {
1824  switch (node.type)
1825  {
1826  case mdds::mtm::element_numeric:
1827  {
1828  typedef MatrixImplType::numeric_block_type block_type;
1829 
1830  block_type::const_iterator it = block_type::begin(*node.data);
1831  block_type::const_iterator itEnd = block_type::end(*node.data);
1832  for (; it != itEnd; ++it)
1833  compareLeftNumeric(*it);
1834  }
1835  break;
1836  case mdds::mtm::element_boolean:
1837  {
1838  typedef MatrixImplType::boolean_block_type block_type;
1839 
1840  block_type::const_iterator it = block_type::begin(*node.data);
1841  block_type::const_iterator itEnd = block_type::end(*node.data);
1842  for (; it != itEnd; ++it)
1843  compareLeftNumeric(double(*it));
1844  }
1845  break;
1846  case mdds::mtm::element_string:
1847  {
1848  typedef MatrixImplType::string_block_type block_type;
1849 
1850  block_type::const_iterator it = block_type::begin(*node.data);
1851  block_type::const_iterator itEnd = block_type::end(*node.data);
1852  for (; it != itEnd; ++it)
1853  {
1854  const svl::SharedString& rStr = *it;
1855  sc::Compare::Cell& rCell = mrComp.maCells[0];
1856  rCell.mbValue = false;
1857  rCell.mbEmpty = false;
1858  rCell.maStr = rStr;
1859  compare();
1860  }
1861  }
1862  break;
1863  case mdds::mtm::element_empty:
1864  compareLeftEmpty(node.size);
1865  break;
1866  default:
1867  ;
1868  }
1869  }
1870 
1871  const std::vector<double>& getValues() const
1872  {
1873  return maResValues;
1874  }
1875 };
1876 
1877 class ToDoubleArray
1878 {
1879  std::vector<double> maArray;
1880  std::vector<double>::iterator miPos;
1881  double mfNaN;
1882  bool mbEmptyAsZero;
1883 
1884  void moveArray( ToDoubleArray& r )
1885  {
1886  // Re-create the iterator from the new array after the array has been
1887  // moved, to ensure that the iterator points to a valid array
1888  // position.
1889  size_t n = std::distance(r.maArray.begin(), r.miPos);
1890  maArray = std::move(r.maArray);
1891  miPos = maArray.begin();
1892  std::advance(miPos, n);
1893  }
1894 
1895 public:
1896  ToDoubleArray( size_t nSize, bool bEmptyAsZero ) :
1897  maArray(nSize, 0.0), miPos(maArray.begin()), mbEmptyAsZero(bEmptyAsZero)
1898  {
1899  mfNaN = CreateDoubleError( FormulaError::ElementNaN);
1900  }
1901 
1902  ToDoubleArray( const ToDoubleArray& ) = delete;
1903  ToDoubleArray& operator= ( const ToDoubleArray& ) = delete;
1904 
1905  ToDoubleArray(ToDoubleArray&& r) noexcept :
1906  mfNaN(r.mfNaN), mbEmptyAsZero(r.mbEmptyAsZero)
1907  {
1908  moveArray(r);
1909  }
1910 
1911  ToDoubleArray& operator=(ToDoubleArray&& r) noexcept
1912  {
1913  mfNaN = r.mfNaN;
1914  mbEmptyAsZero = r.mbEmptyAsZero;
1915  moveArray(r);
1916  return *this;
1917  }
1918 
1919  void operator() (const MatrixImplType::element_block_node_type& node)
1920  {
1921  using namespace mdds::mtv;
1922 
1923  switch (node.type)
1924  {
1925  case mdds::mtm::element_numeric:
1926  {
1927  double_element_block::const_iterator it = double_element_block::begin(*node.data);
1928  double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
1929  for (; it != itEnd; ++it, ++miPos)
1930  *miPos = *it;
1931  }
1932  break;
1933  case mdds::mtm::element_boolean:
1934  {
1935  boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
1936  boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
1937  for (; it != itEnd; ++it, ++miPos)
1938  *miPos = *it ? 1.0 : 0.0;
1939  }
1940  break;
1941  case mdds::mtm::element_string:
1942  {
1943  for (size_t i = 0; i < node.size; ++i, ++miPos)
1944  *miPos = mfNaN;
1945  }
1946  break;
1947  case mdds::mtm::element_empty:
1948  {
1949  if (mbEmptyAsZero)
1950  {
1951  std::advance(miPos, node.size);
1952  return;
1953  }
1954 
1955  for (size_t i = 0; i < node.size; ++i, ++miPos)
1956  *miPos = mfNaN;
1957  }
1958  break;
1959  default:
1960  ;
1961  }
1962  }
1963 
1964  void swap(std::vector<double>& rOther)
1965  {
1966  maArray.swap(rOther);
1967  }
1968 };
1969 
1970 struct ArrayMul
1971 {
1972  double operator() (const double& lhs, const double& rhs) const
1973  {
1974  return lhs * rhs;
1975  }
1976 };
1977 
1978 template<typename Op>
1979 class MergeDoubleArrayFunc
1980 {
1981  std::vector<double>::iterator miPos;
1982  double mfNaN;
1983 public:
1984  MergeDoubleArrayFunc(std::vector<double>& rArray) : miPos(rArray.begin())
1985  {
1986  mfNaN = CreateDoubleError( FormulaError::ElementNaN);
1987  }
1988 
1989  MergeDoubleArrayFunc( const MergeDoubleArrayFunc& ) = delete;
1990  MergeDoubleArrayFunc& operator= ( const MergeDoubleArrayFunc& ) = delete;
1991 
1992  MergeDoubleArrayFunc( MergeDoubleArrayFunc&& ) = default;
1993  MergeDoubleArrayFunc& operator= ( MergeDoubleArrayFunc&& ) = default;
1994 
1995  void operator() (const MatrixImplType::element_block_node_type& node)
1996  {
1997  using namespace mdds::mtv;
1998  static const Op op;
1999 
2000  switch (node.type)
2001  {
2002  case mdds::mtm::element_numeric:
2003  {
2004  double_element_block::const_iterator it = double_element_block::begin(*node.data);
2005  double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
2006  for (; it != itEnd; ++it, ++miPos)
2007  {
2008  if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2009  continue;
2010 
2011  *miPos = op(*miPos, *it);
2012  }
2013  }
2014  break;
2015  case mdds::mtm::element_boolean:
2016  {
2017  boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
2018  boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
2019  for (; it != itEnd; ++it, ++miPos)
2020  {
2021  if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2022  continue;
2023 
2024  *miPos = op(*miPos, *it ? 1.0 : 0.0);
2025  }
2026  }
2027  break;
2028  case mdds::mtm::element_string:
2029  {
2030  for (size_t i = 0; i < node.size; ++i, ++miPos)
2031  *miPos = mfNaN;
2032  }
2033  break;
2034  case mdds::mtm::element_empty:
2035  {
2036  // Empty element is equivalent of having a numeric value of 0.0.
2037  for (size_t i = 0; i < node.size; ++i, ++miPos)
2038  {
2039  if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2040  continue;
2041 
2042  *miPos = op(*miPos, 0.0);
2043  }
2044  }
2045  break;
2046  default:
2047  ;
2048  }
2049  }
2050 };
2051 
2052 }
2053 
2054 namespace {
2055 
2056 template<typename TOp, typename tRes>
2057 ScMatrix::IterateResult<tRes> GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorValues, const MatrixImplType& maMat)
2058 {
2059  WalkElementBlocks<TOp, tRes> aFunc(bTextAsZero, bIgnoreErrorValues);
2060  aFunc = maMat.walk(aFunc);
2061  return aFunc.getResult();
2062 }
2063 
2064 }
2065 
2066 ScMatrix::KahanIterateResult ScMatrixImpl::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
2067 {
2068  return GetValueWithCount<sc::op::Sum, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2069 }
2070 
2071 ScMatrix::KahanIterateResult ScMatrixImpl::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
2072 {
2073  return GetValueWithCount<sc::op::SumSquare, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2074 }
2075 
2076 ScMatrix::DoubleIterateResult ScMatrixImpl::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
2077 {
2078  return GetValueWithCount<sc::op::Product, double>(bTextAsZero, bIgnoreErrorValues, maMat);
2079 }
2080 
2081 size_t ScMatrixImpl::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
2082 {
2083  CountElements aFunc(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
2084  aFunc = maMat.walk(aFunc);
2085  return aFunc.getCount();
2086 }
2087 
2088 size_t ScMatrixImpl::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
2089 {
2090  WalkAndMatchElements<double> aFunc(fValue, maMat.size(), nCol1, nCol2);
2091  aFunc = maMat.walk(aFunc);
2092  return aFunc.getMatching();
2093 }
2094 
2095 size_t ScMatrixImpl::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
2096 {
2097  WalkAndMatchElements<svl::SharedString> aFunc(rStr, maMat.size(), nCol1, nCol2);
2098  aFunc = maMat.walk(aFunc);
2099  return aFunc.getMatching();
2100 }
2101 
2102 double ScMatrixImpl::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2103 {
2104  CalcMaxMinValue<MaxOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2105  aFunc = maMat.walk(aFunc);
2106  return aFunc.getValue();
2107 }
2108 
2109 double ScMatrixImpl::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2110 {
2111  CalcMaxMinValue<MinOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2112  aFunc = maMat.walk(aFunc);
2113  return aFunc.getValue();
2114 }
2115 
2116 double ScMatrixImpl::GetGcd() const
2117 {
2118  CalcGcdLcm<Gcd> aFunc;
2119  aFunc = maMat.walk(aFunc);
2120  return aFunc.getResult();
2121 }
2122 
2123 double ScMatrixImpl::GetLcm() const
2124 {
2125  CalcGcdLcm<Lcm> aFunc;
2126  aFunc = maMat.walk(aFunc);
2127  return aFunc.getResult();
2128 }
2129 
2131  sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
2132 {
2133  MatrixImplType::size_pair_type aSize = maMat.size();
2134  size_t nSize = aSize.column * aSize.row;
2135  if (nMatPos == 0)
2136  {
2137  if (rComp.maCells[1].mbValue && !rComp.maCells[1].mbEmpty)
2138  {
2139  // Matrix on the left, and a numeric value on the right. Use a
2140  // function object that has much less branching for much better
2141  // performance.
2142  CompareMatrixToNumericFunc aFunc(nSize, rComp, rComp.maCells[1].mfValue, pOptions);
2143  aFunc = maMat.walk(std::move(aFunc));
2144 
2145  // We assume the result matrix has the same dimension as this matrix.
2146  const std::vector<double>& rResVal = aFunc.getValues();
2147  assert (nSize == rResVal.size());
2148  if (nSize != rResVal.size())
2149  return ScMatrixRef();
2150 
2151  return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2152  }
2153  }
2154 
2155  CompareMatrixFunc aFunc(nSize, rComp, nMatPos, pOptions);
2156  aFunc = maMat.walk(std::move(aFunc));
2157 
2158  // We assume the result matrix has the same dimension as this matrix.
2159  const std::vector<double>& rResVal = aFunc.getValues();
2160  assert (nSize == rResVal.size());
2161  if (nSize != rResVal.size())
2162  return ScMatrixRef();
2163 
2164  return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2165 }
2166 
2167 void ScMatrixImpl::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
2168 {
2169  MatrixImplType::size_pair_type aSize = maMat.size();
2170  ToDoubleArray aFunc(aSize.row*aSize.column, bEmptyAsZero);
2171  aFunc = maMat.walk(std::move(aFunc));
2172  aFunc.swap(rArray);
2173 }
2174 
2175 void ScMatrixImpl::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
2176 {
2177  MatrixImplType::size_pair_type aSize = maMat.size();
2178  size_t nSize = aSize.row*aSize.column;
2179  if (nSize != rArray.size())
2180  return;
2181 
2182  MergeDoubleArrayFunc<ArrayMul> aFunc(rArray);
2183  maMat.walk(std::move(aFunc));
2184 }
2185 
2186 namespace {
2187 
2188 template<typename T, typename U, typename return_type>
2189 struct wrapped_iterator
2190 {
2191  typedef ::std::bidirectional_iterator_tag iterator_category;
2192  typedef typename T::const_iterator::value_type old_value_type;
2193  typedef return_type value_type;
2194  typedef value_type* pointer;
2195  typedef value_type& reference;
2196  typedef typename T::const_iterator::difference_type difference_type;
2197 
2198  typename T::const_iterator it;
2199  mutable value_type val;
2200  U maOp;
2201 
2202 private:
2203 
2204  value_type calcVal() const
2205  {
2206  return maOp(*it);
2207  }
2208 
2209 public:
2210 
2211  wrapped_iterator(typename T::const_iterator const & it_, U const & aOp):
2212  it(it_),
2213  val(value_type()),
2214  maOp(aOp)
2215  {
2216  }
2217 
2218  wrapped_iterator(const wrapped_iterator& r):
2219  it(r.it),
2220  val(r.val),
2221  maOp(r.maOp)
2222  {
2223  }
2224 
2225  wrapped_iterator& operator=(const wrapped_iterator& r)
2226  {
2227  it = r.it;
2228  return *this;
2229  }
2230 
2231  bool operator==(const wrapped_iterator& r) const
2232  {
2233  return it == r.it;
2234  }
2235 
2236  bool operator!=(const wrapped_iterator& r) const
2237  {
2238  return !operator==(r);
2239  }
2240 
2241  wrapped_iterator& operator++()
2242  {
2243  ++it;
2244 
2245  return *this;
2246  }
2247 
2248  wrapped_iterator& operator--()
2249  {
2250  --it;
2251 
2252  return *this;
2253  }
2254 
2255  value_type& operator*() const
2256  {
2257  val = calcVal();
2258  return val;
2259  }
2260 
2261  pointer operator->() const
2262  {
2263  val = calcVal();
2264  return &val;
2265  }
2266 };
2267 
2268 template<typename T, typename U, typename return_type>
2269 struct MatrixIteratorWrapper
2270 {
2271 private:
2272  typename T::const_iterator m_itBegin;
2273  typename T::const_iterator m_itEnd;
2274  U maOp;
2275 public:
2276  MatrixIteratorWrapper(typename T::const_iterator const & itBegin, typename T::const_iterator const & itEnd, U const & aOp):
2277  m_itBegin(itBegin),
2278  m_itEnd(itEnd),
2279  maOp(aOp)
2280  {
2281  }
2282 
2283  wrapped_iterator<T, U, return_type> begin()
2284  {
2285  return wrapped_iterator<T, U, return_type>(m_itBegin, maOp);
2286  }
2287 
2288  wrapped_iterator<T, U, return_type> end()
2289  {
2290  return wrapped_iterator<T, U, return_type>(m_itEnd, maOp);
2291  }
2292 };
2293 
2294 MatrixImplType::position_type increment_position(const MatrixImplType::position_type& pos, size_t n)
2295 {
2296  MatrixImplType::position_type ret = pos;
2297  do
2298  {
2299  if (ret.second + n < ret.first->size)
2300  {
2301  ret.second += n;
2302  break;
2303  }
2304  else
2305  {
2306  n -= (ret.first->size - ret.second);
2307  ++ret.first;
2308  ret.second = 0;
2309  }
2310  }
2311  while (n > 0);
2312  return ret;
2313 }
2314 
2315 template<typename T>
2316 struct MatrixOpWrapper
2317 {
2318 private:
2319  MatrixImplType& mrMat;
2320  MatrixImplType::position_type pos;
2321  const T* mpOp;
2322 
2323 public:
2324  MatrixOpWrapper(MatrixImplType& rMat, const T& aOp):
2325  mrMat(rMat),
2326  pos(rMat.position(0,0)),
2327  mpOp(&aOp)
2328  {
2329  }
2330 
2331  MatrixOpWrapper( const MatrixOpWrapper& r ) : mrMat(r.mrMat), pos(r.pos), mpOp(r.mpOp) {}
2332 
2333  MatrixOpWrapper& operator= ( const MatrixOpWrapper& r ) = default;
2334 
2335  void operator()(const MatrixImplType::element_block_node_type& node)
2336  {
2337  switch (node.type)
2338  {
2339  case mdds::mtm::element_numeric:
2340  {
2341  typedef MatrixImplType::numeric_block_type block_type;
2342 
2343  block_type::const_iterator it = block_type::begin(*node.data);
2344  block_type::const_iterator itEnd = block_type::end(*node.data);
2345  MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2346  pos = mrMat.set(pos,aFunc.begin(), aFunc.end());
2347  }
2348  break;
2349  case mdds::mtm::element_boolean:
2350  {
2351  typedef MatrixImplType::boolean_block_type block_type;
2352 
2353  block_type::const_iterator it = block_type::begin(*node.data);
2354  block_type::const_iterator itEnd = block_type::end(*node.data);
2355 
2356  MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2357  pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2358  }
2359  break;
2360  case mdds::mtm::element_string:
2361  {
2362  typedef MatrixImplType::string_block_type block_type;
2363 
2364  block_type::const_iterator it = block_type::begin(*node.data);
2365  block_type::const_iterator itEnd = block_type::end(*node.data);
2366 
2367  MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2368  pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2369  }
2370  break;
2371  case mdds::mtm::element_empty:
2372  {
2373  if (mpOp->useFunctionForEmpty())
2374  {
2375  std::vector<char> aVec(node.size);
2376  MatrixIteratorWrapper<std::vector<char>, T, typename T::number_value_type>
2377  aFunc(aVec.begin(), aVec.end(), *mpOp);
2378  pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2379  }
2380  }
2381  break;
2382  default:
2383  ;
2384  }
2385  pos = increment_position(pos, node.size);
2386  }
2387 };
2388 
2389 }
2390 
2391 template<typename T>
2393 {
2394  MatrixOpWrapper<T> aFunc(rMat.maMat, aOp);
2395  maMat.walk(aFunc);
2396 }
2397 
2398 template<typename T, typename tRes>
2400 {
2401  WalkElementBlocksMultipleValues<T, tRes> aFunc(aOp);
2402  aFunc = maMat.walk(std::move(aFunc));
2403  return aFunc.getResult();
2404 }
2405 
2406 namespace {
2407 
2408 struct ElementBlock
2409 {
2410  ElementBlock(size_t nRowSize,
2411  ScMatrix::DoubleOpFunction const & aDoubleFunc,
2412  ScMatrix::BoolOpFunction const & aBoolFunc,
2413  ScMatrix::StringOpFunction const & aStringFunc,
2414  ScMatrix::EmptyOpFunction const & aEmptyFunc):
2415  mnRowSize(nRowSize),
2416  mnRowPos(0),
2417  mnColPos(0),
2418  maDoubleFunc(aDoubleFunc),
2419  maBoolFunc(aBoolFunc),
2420  maStringFunc(aStringFunc),
2421  maEmptyFunc(aEmptyFunc)
2422  {
2423  }
2424 
2425  size_t mnRowSize;
2426  size_t mnRowPos;
2427  size_t mnColPos;
2428 
2429  ScMatrix::DoubleOpFunction maDoubleFunc;
2430  ScMatrix::BoolOpFunction maBoolFunc;
2431  ScMatrix::StringOpFunction maStringFunc;
2432  ScMatrix::EmptyOpFunction maEmptyFunc;
2433 };
2434 
2435 class WalkElementBlockOperation
2436 {
2437 public:
2438 
2439  WalkElementBlockOperation(ElementBlock& rElementBlock)
2440  : mrElementBlock(rElementBlock)
2441  {
2442  }
2443 
2444  void operator()(const MatrixImplType::element_block_node_type& node)
2445  {
2446  switch (node.type)
2447  {
2448  case mdds::mtm::element_numeric:
2449  {
2450  typedef MatrixImplType::numeric_block_type block_type;
2451 
2452  block_type::const_iterator it = block_type::begin(*node.data);
2453  std::advance(it, node.offset);
2454  block_type::const_iterator itEnd = it;
2455  std::advance(itEnd, node.size);
2456  for (auto itr = it; itr != itEnd; ++itr)
2457  {
2458  mrElementBlock.maDoubleFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2459  ++mrElementBlock.mnRowPos;
2460  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2461  {
2462  mrElementBlock.mnRowPos = 0;
2463  ++mrElementBlock.mnColPos;
2464  }
2465  }
2466  }
2467  break;
2468  case mdds::mtm::element_string:
2469  {
2470  typedef MatrixImplType::string_block_type block_type;
2471 
2472  block_type::const_iterator it = block_type::begin(*node.data);
2473  std::advance(it, node.offset);
2474  block_type::const_iterator itEnd = it;
2475  std::advance(itEnd, node.size);
2476  for (auto itr = it; itr != itEnd; ++itr)
2477  {
2478  mrElementBlock.maStringFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2479  ++mrElementBlock.mnRowPos;
2480  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2481  {
2482  mrElementBlock.mnRowPos = 0;
2483  ++mrElementBlock.mnColPos;
2484  }
2485  }
2486  }
2487  break;
2488  case mdds::mtm::element_boolean:
2489  {
2490  typedef MatrixImplType::boolean_block_type block_type;
2491 
2492  block_type::const_iterator it = block_type::begin(*node.data);
2493  std::advance(it, node.offset);
2494  block_type::const_iterator itEnd = it;
2495  std::advance(itEnd, node.size);
2496  for (auto itr = it; itr != itEnd; ++itr)
2497  {
2498  mrElementBlock.maBoolFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2499  ++mrElementBlock.mnRowPos;
2500  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2501  {
2502  mrElementBlock.mnRowPos = 0;
2503  ++mrElementBlock.mnColPos;
2504  }
2505  }
2506  }
2507  break;
2508  case mdds::mtm::element_empty:
2509  {
2510  for (size_t i=0; i < node.size; ++i)
2511  {
2512  mrElementBlock.maEmptyFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos);
2513  ++mrElementBlock.mnRowPos;
2514  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2515  {
2516  mrElementBlock.mnRowPos = 0;
2517  ++mrElementBlock.mnColPos;
2518  }
2519  }
2520  }
2521  break;
2522  case mdds::mtm::element_integer:
2523  {
2524  SAL_WARN("sc.core","WalkElementBlockOperation - unhandled element_integer");
2525  // No function (yet?), but advance row and column count.
2526  mrElementBlock.mnColPos += node.size / mrElementBlock.mnRowSize;
2527  mrElementBlock.mnRowPos += node.size % mrElementBlock.mnRowSize;
2528  if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2529  {
2530  mrElementBlock.mnRowPos = 0;
2531  ++mrElementBlock.mnColPos;
2532  }
2533  }
2534  break;
2535  }
2536  }
2537 
2538 private:
2539 
2540  ElementBlock& mrElementBlock;
2541 };
2542 
2543 }
2544 
2545 void ScMatrixImpl::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
2546  const std::pair<size_t, size_t>& rEndPos, const ScMatrix::DoubleOpFunction& aDoubleFunc,
2547  const ScMatrix::BoolOpFunction& aBoolFunc, const ScMatrix::StringOpFunction& aStringFunc,
2548  const ScMatrix::EmptyOpFunction& aEmptyFunc) const
2549 {
2550  ElementBlock aPayload(maMat.size().row, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2551  WalkElementBlockOperation aFunc(aPayload);
2552  maMat.walk(
2553  aFunc,
2554  MatrixImplType::size_pair_type(rStartPos.first, rStartPos.second),
2555  MatrixImplType::size_pair_type(rEndPos.first, rEndPos.second));
2556 }
2557 
2558 #if DEBUG_MATRIX
2559 
2560 void ScMatrixImpl::Dump() const
2561 {
2562  cout << "-- matrix content" << endl;
2563  SCSIZE nCols, nRows;
2564  GetDimensions(nCols, nRows);
2565  for (SCSIZE nRow = 0; nRow < nRows; ++nRow)
2566  {
2567  for (SCSIZE nCol = 0; nCol < nCols; ++nCol)
2568  {
2569  cout << " row=" << nRow << ", col=" << nCol << " : ";
2570  switch (maMat.get_type(nRow, nCol))
2571  {
2572  case mdds::mtm::element_string:
2573  cout << "string (" << maMat.get_string(nRow, nCol).getString() << ")";
2574  break;
2575  case mdds::mtm::element_numeric:
2576  cout << "numeric (" << maMat.get_numeric(nRow, nCol) << ")";
2577  break;
2578  case mdds::mtm::element_boolean:
2579  cout << "boolean (" << maMat.get_boolean(nRow, nCol) << ")";
2580  break;
2581  case mdds::mtm::element_empty:
2582  cout << "empty";
2583  break;
2584  default:
2585  ;
2586  }
2587 
2588  cout << endl;
2589  }
2590  }
2591 }
2592 #endif
2593 
2594 void ScMatrixImpl::CalcPosition(SCSIZE nIndex, SCSIZE& rC, SCSIZE& rR) const
2595 {
2596  SCSIZE nRowSize = maMat.size().row;
2597  SAL_WARN_IF( !nRowSize, "sc.core", "ScMatrixImpl::CalcPosition: 0 rows!");
2598  rC = nRowSize > 1 ? nIndex / nRowSize : nIndex;
2599  rR = nIndex - rC*nRowSize;
2600 }
2601 
2602 namespace {
2603 
2604 size_t get_index(SCSIZE nMaxRow, size_t nRow, size_t nCol, size_t nRowOffset, size_t nColOffset)
2605 {
2606  return nMaxRow * (nCol + nColOffset) + nRow + nRowOffset;
2607 }
2608 
2609 }
2610 
2611 void ScMatrixImpl::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
2612  SvNumberFormatter& rFormatter, svl::SharedStringPool& rStringPool)
2613 {
2614  SCSIZE nC1, nC2;
2615  SCSIZE nR1, nR2;
2616  xMat1->GetDimensions(nC1, nR1);
2617  xMat2->GetDimensions(nC2, nR2);
2618 
2619  sal_uInt32 nKey = rFormatter.GetStandardFormat( SvNumFormatType::NUMBER,
2620  ScGlobal::eLnge);
2621 
2622  std::vector<OUString> aString(nMaxCol * nMaxRow);
2623  std::vector<bool> aValid(nMaxCol * nMaxRow, true);
2624  std::vector<FormulaError> nErrors(nMaxCol * nMaxRow,FormulaError::NONE);
2625 
2626  size_t nRowOffset = 0;
2627  size_t nColOffset = 0;
2628  std::function<void(size_t, size_t, double)> aDoubleFunc =
2629  [&](size_t nRow, size_t nCol, double nVal)
2630  {
2631  FormulaError nErr = GetDoubleErrorValue(nVal);
2632  if (nErr != FormulaError::NONE)
2633  {
2634  aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2635  nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2636  return;
2637  }
2638  OUString aStr;
2639  rFormatter.GetInputLineString( nVal, nKey, aStr);
2640  aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2641  };
2642 
2643  std::function<void(size_t, size_t, bool)> aBoolFunc =
2644  [&](size_t nRow, size_t nCol, bool nVal)
2645  {
2646  OUString aStr;
2647  rFormatter.GetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2648  aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2649  };
2650 
2651  std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc =
2652  [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2653  {
2654  aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString();
2655  };
2656 
2657  std::function<void(size_t, size_t)> aEmptyFunc =
2658  [&](size_t /*nRow*/, size_t /*nCol*/)
2659  {
2660  // Nothing. Concatenating an empty string to an existing string.
2661  };
2662 
2663 
2664  if (nC1 == 1 || nR1 == 1)
2665  {
2666  size_t nRowRep = nR1 == 1 ? nMaxRow : 1;
2667  size_t nColRep = nC1 == 1 ? nMaxCol : 1;
2668 
2669  for (size_t i = 0; i < nRowRep; ++i)
2670  {
2671  nRowOffset = i;
2672  for (size_t j = 0; j < nColRep; ++j)
2673  {
2674  nColOffset = j;
2675  xMat1->ExecuteOperation(
2676  std::pair<size_t, size_t>(0, 0),
2677  std::pair<size_t, size_t>(std::min(nR1, nMaxRow) - 1, std::min(nC1, nMaxCol) - 1),
2678  aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2679  }
2680  }
2681  }
2682  else
2683  xMat1->ExecuteOperation(
2684  std::pair<size_t, size_t>(0, 0),
2685  std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2686  aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2687 
2688  std::vector<svl::SharedString> aSharedString(nMaxCol*nMaxRow);
2689 
2690  std::function<void(size_t, size_t, double)> aDoubleFunc2 =
2691  [&](size_t nRow, size_t nCol, double nVal)
2692  {
2693  FormulaError nErr = GetDoubleErrorValue(nVal);
2694  if (nErr != FormulaError::NONE)
2695  {
2696  aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2697  nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2698  return;
2699  }
2700  OUString aStr;
2701  rFormatter.GetInputLineString( nVal, nKey, aStr);
2702  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2703  };
2704 
2705  std::function<void(size_t, size_t, bool)> aBoolFunc2 =
2706  [&](size_t nRow, size_t nCol, bool nVal)
2707  {
2708  OUString aStr;
2709  rFormatter.GetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2710  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2711  };
2712 
2713  std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc2 =
2714  [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2715  {
2716  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2717  rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString());
2718  };
2719 
2720  std::function<void(size_t, size_t)> aEmptyFunc2 =
2721  [&](size_t nRow, size_t nCol)
2722  {
2723  aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2724  rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)]);
2725  };
2726 
2727  nRowOffset = 0;
2728  nColOffset = 0;
2729  if (nC2 == 1 || nR2 == 1)
2730  {
2731  size_t nRowRep = nR2 == 1 ? nMaxRow : 1;
2732  size_t nColRep = nC2 == 1 ? nMaxCol : 1;
2733 
2734  for (size_t i = 0; i < nRowRep; ++i)
2735  {
2736  nRowOffset = i;
2737  for (size_t j = 0; j < nColRep; ++j)
2738  {
2739  nColOffset = j;
2740  xMat2->ExecuteOperation(
2741  std::pair<size_t, size_t>(0, 0),
2742  std::pair<size_t, size_t>(std::min(nR2, nMaxRow) - 1, std::min(nC2, nMaxCol) - 1),
2743  aDoubleFunc2, aBoolFunc2, aStringFunc2, aEmptyFunc2);
2744  }
2745  }
2746  }
2747  else
2748  xMat2->ExecuteOperation(
2749  std::pair<size_t, size_t>(0, 0),
2750  std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2751  aDoubleFunc2, aBoolFunc2, aStringFunc2, aEmptyFunc2);
2752 
2753  aString.clear();
2754 
2755  MatrixImplType::position_type pos = maMat.position(0, 0);
2756  for (SCSIZE i = 0; i < nMaxCol; ++i)
2757  {
2758  for (SCSIZE j = 0; j < nMaxRow && i < nMaxCol; ++j)
2759  {
2760  if (aValid[nMaxRow * i + j])
2761  {
2762  auto itr = aValid.begin();
2763  std::advance(itr, nMaxRow * i + j);
2764  auto itrEnd = std::find(itr, aValid.end(), false);
2765  size_t nSteps = std::distance(itr, itrEnd);
2766  auto itrStr = aSharedString.begin();
2767  std::advance(itrStr, nMaxRow * i + j);
2768  auto itrEndStr = itrStr;
2769  std::advance(itrEndStr, nSteps);
2770  pos = maMat.set(pos, itrStr, itrEndStr);
2771  size_t nColSteps = nSteps / nMaxRow;
2772  i += nColSteps;
2773  j += nSteps % nMaxRow;
2774  if (j >= nMaxRow)
2775  {
2776  j -= nMaxRow;
2777  ++i;
2778  }
2779  }
2780  else
2781  {
2782  pos = maMat.set(pos, CreateDoubleError(nErrors[nMaxRow * i + j]));
2783  }
2784  pos = MatrixImplType::next_position(pos);
2785  }
2786  }
2787 }
2788 
2789 void ScMatrix::IncRef() const
2790 {
2791  ++nRefCnt;
2792 }
2793 
2794 void ScMatrix::DecRef() const
2795 {
2796  --nRefCnt;
2797  if (nRefCnt == 0)
2798  delete this;
2799 }
2800 
2802 {
2803  SAL_WARN_IF( !nC, "sc.core", "ScMatrix with 0 columns!");
2804  SAL_WARN_IF( !nR, "sc.core", "ScMatrix with 0 rows!");
2805  // 0-size matrix is valid, it could be resized later.
2806  if ((nC && !nR) || (!nC && nR))
2807  {
2808  SAL_WARN( "sc.core", "ScMatrix one-dimensional zero: " << nC << " columns * " << nR << " rows");
2809  return false;
2810  }
2811  if (!nC || !nR)
2812  return true;
2813 
2814  if (!bElementsMaxFetched)
2815  {
2816  const char* pEnv = std::getenv("SC_MAX_MATRIX_ELEMENTS");
2817  if (pEnv)
2818  {
2819  // Environment specifies the overall elements pool.
2820  nElementsMax = std::atoi(pEnv);
2821  }
2822  else
2823  {
2824  // GetElementsMax() uses an (~arbitrary) elements limit.
2825  // The actual allocation depends on the types of individual matrix
2826  // elements and is averaged for type double.
2827 #if SAL_TYPES_SIZEOFPOINTER < 8
2828  // Assume 1GB memory could be consumed by matrices.
2829  constexpr size_t nMemMax = 0x40000000;
2830 #else
2831  // Assume 6GB memory could be consumed by matrices.
2832  constexpr size_t nMemMax = 0x180000000;
2833 #endif
2834  nElementsMax = GetElementsMax( nMemMax);
2835  }
2836  bElementsMaxFetched = true;
2837  }
2838 
2839  if (nC > (nElementsMax / nR))
2840  {
2841  SAL_WARN( "sc.core", "ScMatrix overflow: " << nC << " columns * " << nR << " rows");
2842  return false;
2843  }
2844  return true;
2845 }
2846 
2848  nRefCnt(0), mbCloneIfConst(true)
2849 {
2850  if (ScMatrix::IsSizeAllocatable( nC, nR))
2851  pImpl.reset( new ScMatrixImpl( nC, nR));
2852  else
2853  // Invalid matrix size, allocate 1x1 matrix with error value.
2854  pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
2855 }
2856 
2857 ScMatrix::ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal) :
2858  nRefCnt(0), mbCloneIfConst(true)
2859 {
2860  if (ScMatrix::IsSizeAllocatable( nC, nR))
2861  pImpl.reset( new ScMatrixImpl( nC, nR, fInitVal));
2862  else
2863  // Invalid matrix size, allocate 1x1 matrix with error value.
2864  pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
2865 }
2866 
2867 ScMatrix::ScMatrix( size_t nC, size_t nR, const std::vector<double>& rInitVals ) :
2868  nRefCnt(0), mbCloneIfConst(true)
2869 {
2870  if (ScMatrix::IsSizeAllocatable( nC, nR))
2871  pImpl.reset( new ScMatrixImpl( nC, nR, rInitVals));
2872  else
2873  // Invalid matrix size, allocate 1x1 matrix with error value.
2874  pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
2875 }
2876 
2878 {
2879 }
2880 
2882 {
2883  SCSIZE nC, nR;
2884  pImpl->GetDimensions(nC, nR);
2885  ScMatrix* pScMat = new ScMatrix(nC, nR);
2886  MatCopy(*pScMat);
2887  pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter()); // TODO: really?
2888  return pScMat;
2889 }
2890 
2892 {
2893  return mbCloneIfConst ? Clone() : this;
2894 }
2895 
2897 {
2898  mbCloneIfConst = false;
2899 }
2900 
2902 {
2903  mbCloneIfConst = true;
2904 }
2905 
2907 {
2908  pImpl->Resize(nC, nR);
2909 }
2910 
2911 void ScMatrix::Resize(SCSIZE nC, SCSIZE nR, double fVal)
2912 {
2913  pImpl->Resize(nC, nR, fVal);
2914 }
2915 
2917 {
2918  ScMatrix* pScMat = new ScMatrix(nNewCols, nNewRows);
2919  MatCopy(*pScMat);
2920  pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter());
2921  return pScMat;
2922 }
2923 
2925 {
2926  pImpl->SetErrorInterpreter(p);
2927 }
2928 
2930 {
2931  pImpl->GetDimensions(rC, rR);
2932 }
2933 
2935 {
2936  return pImpl->GetElementCount();
2937 }
2938 
2940 {
2941  return pImpl->ValidColRow(nC, nR);
2942 }
2943 
2945 {
2946  return pImpl->ValidColRowReplicated(rC, rR);
2947 }
2948 
2950 {
2951  return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
2952 }
2953 
2954 void ScMatrix::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
2955 {
2956  pImpl->PutDouble(fVal, nC, nR);
2957 }
2958 
2959 void ScMatrix::PutDouble( double fVal, SCSIZE nIndex)
2960 {
2961  pImpl->PutDouble(fVal, nIndex);
2962 }
2963 
2964 void ScMatrix::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
2965 {
2966  pImpl->PutDouble(pArray, nLen, nC, nR);
2967 }
2968 
2970 {
2971  pImpl->PutString(rStr, nC, nR);
2972 }
2973 
2975 {
2976  pImpl->PutString(rStr, nIndex);
2977 }
2978 
2979 void ScMatrix::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
2980 {
2981  pImpl->PutString(pArray, nLen, nC, nR);
2982 }
2983 
2985 {
2986  pImpl->PutEmpty(nC, nR);
2987 }
2988 
2990 {
2991  pImpl->PutEmptyPath(nC, nR);
2992 }
2993 
2994 void ScMatrix::PutError( FormulaError nErrorCode, SCSIZE nC, SCSIZE nR )
2995 {
2996  pImpl->PutError(nErrorCode, nC, nR);
2997 }
2998 
2999 void ScMatrix::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
3000 {
3001  pImpl->PutBoolean(bVal, nC, nR);
3002 }
3003 
3005 {
3006  return pImpl->GetError(nC, nR);
3007 }
3008 
3009 double ScMatrix::GetDouble(SCSIZE nC, SCSIZE nR) const
3010 {
3011  return pImpl->GetDouble(nC, nR);
3012 }
3013 
3014 double ScMatrix::GetDouble( SCSIZE nIndex) const
3015 {
3016  return pImpl->GetDouble(nIndex);
3017 }
3018 
3020 {
3021  return pImpl->GetDoubleWithStringConversion(nC, nR);
3022 }
3023 
3025 {
3026  return pImpl->GetString(nC, nR);
3027 }
3028 
3030 {
3031  return pImpl->GetString(nIndex);
3032 }
3033 
3035 {
3036  return pImpl->GetString(rFormatter, nC, nR);
3037 }
3038 
3040 {
3041  return pImpl->Get(nC, nR);
3042 }
3043 
3044 bool ScMatrix::IsStringOrEmpty( SCSIZE nIndex ) const
3045 {
3046  return pImpl->IsStringOrEmpty(nIndex);
3047 }
3048 
3050 {
3051  return pImpl->IsStringOrEmpty(nC, nR);
3052 }
3053 
3054 bool ScMatrix::IsEmpty( SCSIZE nC, SCSIZE nR ) const
3055 {
3056  return pImpl->IsEmpty(nC, nR);
3057 }
3058 
3060 {
3061  return pImpl->IsEmptyCell(nC, nR);
3062 }
3063 
3065 {
3066  return pImpl->IsEmptyResult(nC, nR);
3067 }
3068 
3070 {
3071  return pImpl->IsEmptyPath(nC, nR);
3072 }
3073 
3074 bool ScMatrix::IsValue( SCSIZE nIndex ) const
3075 {
3076  return pImpl->IsValue(nIndex);
3077 }
3078 
3079 bool ScMatrix::IsValue( SCSIZE nC, SCSIZE nR ) const
3080 {
3081  return pImpl->IsValue(nC, nR);
3082 }
3083 
3085 {
3086  return pImpl->IsValueOrEmpty(nC, nR);
3087 }
3088 
3089 bool ScMatrix::IsBoolean( SCSIZE nC, SCSIZE nR ) const
3090 {
3091  return pImpl->IsBoolean(nC, nR);
3092 }
3093 
3095 {
3096  return pImpl->IsNumeric();
3097 }
3098 
3099 void ScMatrix::MatCopy(const ScMatrix& mRes) const
3100 {
3101  pImpl->MatCopy(*mRes.pImpl);
3102 }
3103 
3104 void ScMatrix::MatTrans(const ScMatrix& mRes) const
3105 {
3106  pImpl->MatTrans(*mRes.pImpl);
3107 }
3108 
3109 void ScMatrix::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
3110 {
3111  pImpl->FillDouble(fVal, nC1, nR1, nC2, nR2);
3112 }
3113 
3114 void ScMatrix::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
3115 {
3116  pImpl->PutDoubleVector(rVec, nC, nR);
3117 }
3118 
3119 void ScMatrix::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
3120 {
3121  pImpl->PutStringVector(rVec, nC, nR);
3122 }
3123 
3125 {
3126  pImpl->PutEmptyVector(nCount, nC, nR);
3127 }
3128 
3130 {
3131  pImpl->PutEmptyResultVector(nCount, nC, nR);
3132 }
3133 
3135 {
3136  pImpl->PutEmptyPathVector(nCount, nC, nR);
3137 }
3138 
3140 {
3141  pImpl->CompareEqual();
3142 }
3143 
3145 {
3146  pImpl->CompareNotEqual();
3147 }
3148 
3150 {
3151  pImpl->CompareLess();
3152 }
3153 
3155 {
3156  pImpl->CompareGreater();
3157 }
3158 
3160 {
3161  pImpl->CompareLessEqual();
3162 }
3163 
3165 {
3166  pImpl->CompareGreaterEqual();
3167 }
3168 
3169 double ScMatrix::And() const
3170 {
3171  return pImpl->And();
3172 }
3173 
3174 double ScMatrix::Or() const
3175 {
3176  return pImpl->Or();
3177 }
3178 
3179 double ScMatrix::Xor() const
3180 {
3181  return pImpl->Xor();
3182 }
3183 
3184 ScMatrix::KahanIterateResult ScMatrix::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
3185 {
3186  return pImpl->Sum(bTextAsZero, bIgnoreErrorValues);
3187 }
3188 
3189 ScMatrix::KahanIterateResult ScMatrix::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
3190 {
3191  return pImpl->SumSquare(bTextAsZero, bIgnoreErrorValues);
3192 }
3193 
3194 ScMatrix::DoubleIterateResult ScMatrix::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
3195 {
3196  return pImpl->Product(bTextAsZero, bIgnoreErrorValues);
3197 }
3198 
3199 size_t ScMatrix::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
3200 {
3201  return pImpl->Count(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
3202 }
3203 
3204 size_t ScMatrix::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
3205 {
3206  return pImpl->MatchDoubleInColumns(fValue, nCol1, nCol2);
3207 }
3208 
3209 size_t ScMatrix::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
3210 {
3211  return pImpl->MatchStringInColumns(rStr, nCol1, nCol2);
3212 }
3213 
3214 double ScMatrix::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3215 {
3216  return pImpl->GetMaxValue(bTextAsZero, bIgnoreErrorValues);
3217 }
3218 
3219 double ScMatrix::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3220 {
3221  return pImpl->GetMinValue(bTextAsZero, bIgnoreErrorValues);
3222 }
3223 
3224 double ScMatrix::GetGcd() const
3225 {
3226  return pImpl->GetGcd();
3227 }
3228 
3229 double ScMatrix::GetLcm() const
3230 {
3231  return pImpl->GetLcm();
3232 }
3233 
3234 
3236  sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
3237 {
3238  return pImpl->CompareMatrix(rComp, nMatPos, pOptions);
3239 }
3240 
3241 void ScMatrix::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
3242 {
3243  pImpl->GetDoubleArray(rArray, bEmptyAsZero);
3244 }
3245 
3246 void ScMatrix::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
3247 {
3248  pImpl->MergeDoubleArrayMultiply(rArray);
3249 }
3250 
3251 namespace matop {
3252 
3253 namespace {
3254 
3262 template<typename TOp>
3263 struct MatOp
3264 {
3265 private:
3266  TOp maOp;
3268  double mfVal;
3269 
3270 public:
3271  typedef double number_value_type;
3272 
3273  MatOp( TOp aOp, ScInterpreter* pErrorInterpreter,
3274  double fVal = 0.0 ):
3275  maOp(aOp),
3276  mpErrorInterpreter(pErrorInterpreter),
3277  mfVal(fVal)
3278  {
3279  if (mpErrorInterpreter)
3280  {
3281  FormulaError nErr = mpErrorInterpreter->GetError();
3282  if (nErr != FormulaError::NONE)
3283  mfVal = CreateDoubleError( nErr);
3284  }
3285  }
3286 
3287  double operator()(double fVal) const
3288  {
3289  return maOp(fVal, mfVal);
3290  }
3291 
3292  double operator()(bool bVal) const
3293  {
3294  return maOp(static_cast<double>(bVal), mfVal);
3295  }
3296 
3297  double operator()(const svl::SharedString& rStr) const
3298  {
3299  return maOp( convertStringToValue( mpErrorInterpreter, rStr.getString()), mfVal);
3300  }
3301 
3303  double operator()(char) const
3304  {
3305  return maOp(0, mfVal);
3306  }
3307 
3308  static bool useFunctionForEmpty()
3309  {
3310  return true;
3311  }
3312 };
3313 
3314 }
3315 
3316 }
3317 
3318 void ScMatrix::NotOp( const ScMatrix& rMat)
3319 {
3320  auto not_ = [](double a, double){return double(a == 0.0);};
3321  matop::MatOp<decltype(not_)> aOp(not_, pImpl->GetErrorInterpreter());
3322  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3323 }
3324 
3325 void ScMatrix::NegOp( const ScMatrix& rMat)
3326 {
3327  auto neg_ = [](double a, double){return -a;};
3328  matop::MatOp<decltype(neg_)> aOp(neg_, pImpl->GetErrorInterpreter());
3329  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3330 }
3331 
3332 void ScMatrix::AddOp( double fVal, const ScMatrix& rMat)
3333 {
3334  auto add_ = [](double a, double b){return a + b;};
3335  matop::MatOp<decltype(add_)> aOp(add_, pImpl->GetErrorInterpreter(), fVal);
3336  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3337 }
3338 
3339 void ScMatrix::SubOp( bool bFlag, double fVal, const ScMatrix& rMat)
3340 {
3341  if (bFlag)
3342  {
3343  auto sub_ = [](double a, double b){return b - a;};
3344  matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3345  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3346  }
3347  else
3348  {
3349  auto sub_ = [](double a, double b){return a - b;};
3350  matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3351  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3352  }
3353 }
3354 
3355 void ScMatrix::MulOp( double fVal, const ScMatrix& rMat)
3356 {
3357  auto mul_ = [](double a, double b){return a * b;};
3358  matop::MatOp<decltype(mul_)> aOp(mul_, pImpl->GetErrorInterpreter(), fVal);
3359  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3360 }
3361 
3362 void ScMatrix::DivOp( bool bFlag, double fVal, const ScMatrix& rMat)
3363 {
3364  if (bFlag)
3365  {
3366  auto div_ = [](double a, double b){return sc::div(b, a);};
3367  matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3368  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3369  }
3370  else
3371  {
3372  auto div_ = [](double a, double b){return sc::div(a, b);};
3373  matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3374  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3375  }
3376 }
3377 
3378 void ScMatrix::PowOp( bool bFlag, double fVal, const ScMatrix& rMat)
3379 {
3380  if (bFlag)
3381  {
3382  auto pow_ = [](double a, double b){return sc::power(b, a);};
3383  matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3384  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3385  }
3386  else
3387  {
3388  auto pow_ = [](double a, double b){return sc::power(a, b);};
3389  matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3390  pImpl->ApplyOperation(aOp, *rMat.pImpl);
3391  }
3392 }
3393 
3394 void ScMatrix::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
3395  const std::pair<size_t, size_t>& rEndPos, DoubleOpFunction aDoubleFunc,
3396  BoolOpFunction aBoolFunc, StringOpFunction aStringFunc, EmptyOpFunction aEmptyFunc) const
3397 {
3398  pImpl->ExecuteOperation(rStartPos, rEndPos, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
3399 }
3400 
3402 {
3403  return pImpl->ApplyCollectOperation<sc::op::kOp, KahanSum>(aOp);
3404 }
3405 
3406 #if DEBUG_MATRIX
3407 void ScMatrix::Dump() const
3408 {
3409  pImpl->Dump();
3410 }
3411 #endif
3412 
3413 void ScMatrix::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow,
3414  const ScMatrixRef& xMat1, const ScMatrixRef& xMat2, SvNumberFormatter& rFormatter, svl::SharedStringPool& rPool)
3415 {
3416  pImpl->MatConcat(nMaxCol, nMaxRow, xMat1, xMat2, rFormatter, rPool);
3417 }
3418 
3419 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool operator==(const XclFontData &rLeft, const XclFontData &rRight)
Definition: xlstyle.cxx:518
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:112
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:2949
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:2130
void SetErrorAtInterpreter(FormulaError nError) const
Definition: scmatrix.cxx:491
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:2939
SharedString intern(const OUString &rStr)
~ScMatrixImpl() COVERITY_NOEXCEPT_FALSE
Definition: scmatrix.cxx:392
bool operator!=(const XclExpString &rLeft, const XclExpString &rRight)
Definition: xestring.hxx:250
void PutEmptyResultVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:953
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:497
FormulaError GetError() const
Definition: interpre.hxx:1022
ScInterpreter * pErrorInterpreter
Definition: scmatrix.cxx:229
std::vector< tRes > maAccumulator
Definition: scmatrix.hxx:146
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:2954
double And() const
Definition: scmatrix.cxx:1087
void CompareGreaterEqual()
Definition: scmatrix.cxx:3164
ScMatrix::IterateResultMultiple< tRes > ApplyCollectOperation(const std::vector< T > &aOp)
Definition: scmatrix.cxx:2399
ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const
: If bString the ScMatrixValue->pS may still be NULL to indicate an empty string! ...
Definition: scmatrix.cxx:3039
Cell maCells[2]
Definition: compare.hxx:43
sal_Int64 n
void CompareLess()
Definition: scmatrix.cxx:3149
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:63
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:2167
void SubOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3339
friend class ScMatrixImpl
Definition: scmatrix.hxx:114
static const SharedString & getEmptyString()
size_t MatchStringInColumns(const svl::SharedString &rStr, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:2095
void MatCopy(const ScMatrix &mRes) const
Definition: scmatrix.cxx:3099
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:2989
SotClipboardFormatId & operator++(SotClipboardFormatId &eFormat)
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:2088
const ScMatrixImpl & operator=(const ScMatrixImpl &)=delete
void PutString(const svl::SharedString &rStr, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:2969
void AddOp(double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3332
Try NOT to use this struct.
Definition: scmatrix.hxx:52
size_t MatchStringInColumns(const svl::SharedString &rStr, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:3209
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:2984
ScMatrix::KahanIterateResult SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2071
void FillDouble(double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2)
Definition: scmatrix.cxx:3109
void DivOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3362
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3009
def position
double CompareFunc(const Compare &rComp, CompareOptions *pOptions)
Definition: compare.cxx:53
double fVal
Definition: scmatrix.hxx:54
This class provides LO with Kahan summation algorithm About this algorithm: https://en.wikipedia.org/wiki/Kahan_summation_algorithm For general purpose software we assume first order error is enough.
Definition: kahan.hxx:21
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:3214
double GetGcd() const
Definition: scmatrix.cxx:2116
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:44
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:3394
std::unique_ptr< ScMatrixImpl > pImpl
Definition: scmatrix.hxx:118
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:3134
void CompareEqual()
Definition: scmatrix.cxx:3139
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:3124
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:3204
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:3094
bool IsEmptyCell(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:805
double GetLcm() const
Definition: scmatrix.cxx:3229
KahanIterateResult Sum(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3184
::boost::intrusive_ptr< ScMatrix > ScMatrixRef
Definition: types.hxx:25
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:3044
FormulaError GetDoubleErrorValue(double fVal)
double mfVal
Definition: scmatrix.cxx:3268
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:69
double Or() const
Definition: scmatrix.cxx:3174
void DecRef() const
Definition: scmatrix.cxx:2794
std::function< void(size_t, size_t)> EmptyOpFunction
Definition: scmatrix.hxx:132
const SCROW MAXROWCOUNT
Definition: address.hxx:62
double And() const
Definition: scmatrix.cxx:3169
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:3129
void PowOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3378
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
void MergeDoubleArrayMultiply(std::vector< double > &rArray) const
Definition: scmatrix.cxx:2175
void Resize(SCSIZE nC, SCSIZE nR)
Resize the matrix to specified new dimension.
Definition: scmatrix.cxx:2906
double GetMaxValue(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2102
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:3114
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:3318
TOp maOp
Definition: scmatrix.cxx:3266
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:2916
svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3024
uno_Any a
double Xor() const
Definition: scmatrix.cxx:3179
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:3004
DoubleIterateResult Product(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3194
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2929
ScMatrixRef CompareMatrix(sc::Compare &rComp, size_t nMatPos, sc::CompareOptions *pOptions) const
Definition: scmatrix.cxx:3235
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:3089
void CompareGreaterEqual()
Definition: scmatrix.cxx:1023
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString, bool bFiltering=false)
mdds::multi_type_matrix< matrix_trait > MatrixImplType
Definition: scmatrix.cxx:68
ScMatrix::DoubleIterateResult Product(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2076
SvNumFormatType
void PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:2999
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:547
std::size_t mnCount
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:2944
KahanIterateResultMultiple CollectKahan(const std::vector< sc::op::kOp > &aOp)
Definition: scmatrix.cxx:3401
void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef &xMat1, const ScMatrixRef &xMat2, SvNumberFormatter &rFormatter, svl::SharedStringPool &rPool)
Definition: scmatrix.cxx:3413
ScMatrix * CloneIfConst()
Clone the matrix if mbCloneIfConst (immutable) is set, otherwise return this matrix, to be assigned to a ScMatrixRef.
Definition: scmatrix.cxx:2891
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:606
ScMatValType nType
Definition: scmatrix.hxx:56
Op_< std::function< void(double &, double)>, double > Op
enumrange< T >::Iterator end(enumrange< T >)
double GetGcd() const
Definition: scmatrix.cxx:3224
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:3104
double power(const double &fVal1, const double &fVal2)
Return pow(fVal1,fVal2) with error handling.
Definition: math.cxx:29
void PutDoubleVector(const ::std::vector< double > &rVec, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:915
void PutError(FormulaError nErrorCode, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:2994
double CreateDoubleError(FormulaError nErr)
void SetErrorInterpreter(ScInterpreter *p)
Definition: scmatrix.cxx:2924
ScInterpreter * mpErrorInterpreter
Definition: scmatrix.cxx:3267
bool ValidColRowOrReplicated(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:486
void IncRef() const
Definition: scmatrix.cxx:2789
svl::SharedString maStr
Definition: compare.hxx:36
std::function< void(size_t, size_t, double)> DoubleOpFunction
Definition: scmatrix.hxx:129
#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:2545
bool IsEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3054
void CompareNotEqual()
Definition: scmatrix.cxx:3144
void CompareLess()
Definition: scmatrix.cxx:999
ScMatrix::KahanIterateResult Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2066
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:45
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
std::function< void(size_t, size_t, svl::SharedString)> StringOpFunction
Definition: scmatrix.hxx:131
size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings=false) const
Definition: scmatrix.cxx:3199
void SetMutable()
Set the matrix to mutable for CloneIfConst(), only the interpreter should do this and know the conseq...
Definition: scmatrix.cxx:2896
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:3241
bool IsEmptyResult(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3064
void SetErrorInterpreter(ScInterpreter *p)
Definition: scmatrix.cxx:438
void CalcPosition(SCSIZE nIndex, SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2594
Iterator for executing one operation with the matrix data.
Definition: scmatrix.hxx:159
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:2881
double GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3019
FILE * init(int, char **)
ScQueryOp
Definition: global.hxx:818
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:55
double GetMinValue(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3219
void PutEmptyPath(SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:564
void CompareLessEqual()
Definition: scmatrix.cxx:3159
Any result
When adding all numerical matrix elements for a scalar result such as summation, the interpreter want...
Definition: scmatrix.hxx:144
Op_< std::function< void(KahanSum &, double)>, KahanSum > kOp
#define SAL_WARN(area, stream)
bool IsValueOrEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:854
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:3074
SCSIZE GetElementCount() const
Definition: scmatrix.cxx:2934
void PutEmptyPathVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:968
bool IsEmptyPath(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3069
sal_Int32 mnRow
bool mbCloneIfConst
Definition: scmatrix.hxx:117
void SetImmutable() const
Set the matrix to immutable for CloneIfConst(), only the interpreter should do this and know the cons...
Definition: scmatrix.cxx:2901
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:3119
void MulOp(double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3355
int mnIndex
void ApplyOperation(T aOp, ScMatrixImpl &rMat)
Definition: scmatrix.cxx:2392
bool IsEmptyCell(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3059
double GetMinValue(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2109
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:3325
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:775
void MergeDoubleArrayMultiply(std::vector< double > &rArray) const
Definition: scmatrix.cxx:3246
void PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:582
void CompareGreater()
Definition: scmatrix.cxx:3154
void SetError(FormulaError nError)
Definition: interpre.hxx:1015
aStr
std::function< void(size_t, size_t, bool)> BoolOpFunction
Definition: scmatrix.hxx:130
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
static OUString GetErrorString(FormulaError nErrNumber)
Definition: global.cxx:301
SbxDecimal::CmpResult compare(SAL_UNUSED_PARAMETER const SbxDecimal &, SAL_UNUSED_PARAMETER const SbxDecimal &)
double GetLcm() const
Definition: scmatrix.cxx:2123
bool IsValueOrEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3084
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
KahanIterateResult SumSquare(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3189
static double ScGetGCD(double fx, double fy)
Definition: interpr5.cxx:107
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:2801
void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef &xMat1, const ScMatrixRef &xMat2, SvNumberFormatter &rFormatter, svl::SharedStringPool &rPool)
Definition: scmatrix.cxx:2611
bool ValidColRowReplicated(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:462
size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
Definition: scmatrix.cxx:2081