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