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