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