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