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