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 ValidColRowReplicated( nC, nR );
806 switch (maMat.get_type(nR, nC))
807 {
808 case mdds::mtm::element_empty:
809 case mdds::mtm::element_string:
810 return true;
811 default:
812 ;
813 }
814 return false;
815}
816
818{
819 // Flag must indicate an 'empty' or 'empty cell' or 'empty result' element,
820 // but not an 'empty path' element.
821 ValidColRowReplicated( nC, nR );
822 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
823 maMatFlag.get_integer(nR, nC) != SC_MATFLAG_EMPTYPATH;
824}
825
827{
828 // Flag must indicate an 'empty cell' element instead of an
829 // 'empty' or 'empty result' or 'empty path' element.
830 ValidColRowReplicated( nC, nR );
831 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
832 maMatFlag.get_type(nR, nC) == mdds::mtm::element_empty;
833}
834
836{
837 // Flag must indicate an 'empty result' element instead of an
838 // 'empty' or 'empty cell' or 'empty path' element.
839 ValidColRowReplicated( nC, nR );
840 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
841 maMatFlag.get_integer(nR, nC) == SC_MATFLAG_EMPTYRESULT;
842}
843
845{
846 // Flag must indicate an 'empty path' element.
847 if (ValidColRowOrReplicated( nC, nR ))
848 return maMat.get_type(nR, nC) == mdds::mtm::element_empty &&
849 maMatFlag.get_integer(nR, nC) == SC_MATFLAG_EMPTYPATH;
850 else
851 return true;
852}
853
854bool ScMatrixImpl::IsValue( SCSIZE nIndex ) const
855{
856 SCSIZE nC, nR;
857 CalcPosition(nIndex, nC, nR);
858 return IsValue(nC, nR);
859}
860
862{
863 ValidColRowReplicated(nC, nR);
864 switch (maMat.get_type(nR, nC))
865 {
866 case mdds::mtm::element_boolean:
867 case mdds::mtm::element_numeric:
868 return true;
869 default:
870 ;
871 }
872 return false;
873}
874
876{
877 ValidColRowReplicated(nC, nR);
878 switch (maMat.get_type(nR, nC))
879 {
880 case mdds::mtm::element_boolean:
881 case mdds::mtm::element_numeric:
882 case mdds::mtm::element_empty:
883 return true;
884 default:
885 ;
886 }
887 return false;
888}
889
891{
892 ValidColRowReplicated( nC, nR );
893 return maMat.get_type(nR, nC) == mdds::mtm::element_boolean;
894}
895
897{
898 return maMat.numeric();
899}
900
902{
903 if (maMat.size().row > mRes.maMat.size().row || maMat.size().column > mRes.maMat.size().column)
904 {
905 // destination matrix is not large enough.
906 OSL_FAIL("ScMatrixImpl::MatCopy: dimension error");
907 return;
908 }
909
910 mRes.maMat.copy(maMat);
911}
912
914{
915 mRes.maMat = maMat;
916 mRes.maMat.transpose();
917}
918
919void ScMatrixImpl::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
920{
921 if (ValidColRow( nC1, nR1) && ValidColRow( nC2, nR2))
922 {
923 for (SCSIZE j = nC1; j <= nC2; ++j)
924 {
925 // Passing value array is much faster.
926 std::vector<double> aVals(nR2-nR1+1, fVal);
927 maMat.set(nR1, j, aVals.begin(), aVals.end());
928 }
929 }
930 else
931 {
932 OSL_FAIL("ScMatrixImpl::FillDouble: dimension error");
933 }
934}
935
936void ScMatrixImpl::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
937{
938 if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
939 {
940 maMat.set(nR, nC, rVec.begin(), rVec.end());
941 }
942 else
943 {
944 OSL_FAIL("ScMatrixImpl::PutDoubleVector: dimension error");
945 }
946}
947
948void ScMatrixImpl::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
949{
950 if (!rVec.empty() && ValidColRow( nC, nR) && ValidColRow( nC, nR + rVec.size() - 1))
951 {
952 maMat.set(nR, nC, rVec.begin(), rVec.end());
953 }
954 else
955 {
956 OSL_FAIL("ScMatrixImpl::PutStringVector: dimension error");
957 }
958}
959
961{
962 if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
963 {
964 maMat.set_empty(nR, nC, nCount);
965 // Flag to indicate that this is 'empty', not 'empty result' or 'empty path'.
966 maMatFlag.set_empty(nR, nC, nCount);
967 }
968 else
969 {
970 OSL_FAIL("ScMatrixImpl::PutEmptyVector: 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 result', not 'empty' or 'empty path'.
980 std::vector<uint8_t> aVals(nCount, SC_MATFLAG_EMPTYRESULT);
981 maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
982 }
983 else
984 {
985 OSL_FAIL("ScMatrixImpl::PutEmptyResultVector: dimension error");
986 }
987}
988
990{
991 if (nCount && ValidColRow( nC, nR) && ValidColRow( nC, nR + nCount - 1))
992 {
993 maMat.set_empty(nR, nC, nCount);
994 // Flag to indicate 'empty path'.
995 std::vector<uint8_t> aVals(nCount, SC_MATFLAG_EMPTYPATH);
996 maMatFlag.set(nR, nC, aVals.begin(), aVals.end());
997 }
998 else
999 {
1000 OSL_FAIL("ScMatrixImpl::PutEmptyPathVector: dimension error");
1001 }
1002}
1003
1005{
1006 MatrixImplType::size_pair_type aSize = maMat.size();
1007 CompareMatrixElemFunc<ElemEqualZero> aFunc(aSize.row, aSize.column);
1008 aFunc = maMat.walk(std::move(aFunc));
1009 aFunc.swap(maMat);
1010}
1011
1013{
1014 MatrixImplType::size_pair_type aSize = maMat.size();
1015 CompareMatrixElemFunc<ElemNotEqualZero> aFunc(aSize.row, aSize.column);
1016 aFunc = maMat.walk(std::move(aFunc));
1017 aFunc.swap(maMat);
1018}
1019
1021{
1022 MatrixImplType::size_pair_type aSize = maMat.size();
1023 CompareMatrixElemFunc<ElemLessZero> aFunc(aSize.row, aSize.column);
1024 aFunc = maMat.walk(std::move(aFunc));
1025 aFunc.swap(maMat);
1026}
1027
1029{
1030 MatrixImplType::size_pair_type aSize = maMat.size();
1031 CompareMatrixElemFunc<ElemGreaterZero> aFunc(aSize.row, aSize.column);
1032 aFunc = maMat.walk(std::move(aFunc));
1033 aFunc.swap(maMat);
1034}
1035
1037{
1038 MatrixImplType::size_pair_type aSize = maMat.size();
1039 CompareMatrixElemFunc<ElemLessEqualZero> aFunc(aSize.row, aSize.column);
1040 aFunc = maMat.walk(std::move(aFunc));
1041 aFunc.swap(maMat);
1042}
1043
1045{
1046 MatrixImplType::size_pair_type aSize = maMat.size();
1047 CompareMatrixElemFunc<ElemGreaterEqualZero> aFunc(aSize.row, aSize.column);
1048 aFunc = maMat.walk(std::move(aFunc));
1049 aFunc.swap(maMat);
1050}
1051
1052namespace {
1053
1054struct AndEvaluator
1055{
1056 bool mbResult;
1057 void operate(double fVal) { mbResult &= (fVal != 0.0); }
1058 bool result() const { return mbResult; }
1059 AndEvaluator() : mbResult(true) {}
1060};
1061
1062struct OrEvaluator
1063{
1064 bool mbResult;
1065 void operate(double fVal) { mbResult |= (fVal != 0.0); }
1066 bool result() const { return mbResult; }
1067 OrEvaluator() : mbResult(false) {}
1068};
1069
1070struct XorEvaluator
1071{
1072 bool mbResult;
1073 void operate(double fVal) { mbResult ^= (fVal != 0.0); }
1074 bool result() const { return mbResult; }
1075 XorEvaluator() : mbResult(false) {}
1076};
1077
1078// Do not short circuit logical operations, in case there are error values
1079// these need to be propagated even if the result was determined earlier.
1080template <typename Evaluator>
1081double EvalMatrix(const MatrixImplType& rMat)
1082{
1083 Evaluator aEval;
1084 size_t nRows = rMat.size().row, nCols = rMat.size().column;
1085 for (size_t i = 0; i < nRows; ++i)
1086 {
1087 for (size_t j = 0; j < nCols; ++j)
1088 {
1089 MatrixImplType::const_position_type aPos = rMat.position(i, j);
1090 mdds::mtm::element_t eType = rMat.get_type(aPos);
1091 if (eType != mdds::mtm::element_numeric && eType != mdds::mtm::element_boolean)
1092 // assuming a CompareMat this is an error
1093 return CreateDoubleError(FormulaError::IllegalArgument);
1094
1095 double fVal = rMat.get_numeric(aPos);
1096 if (!std::isfinite(fVal))
1097 // DoubleError
1098 return fVal;
1099
1100 aEval.operate(fVal);
1101 }
1102 }
1103 return aEval.result();
1104}
1105
1106}
1107
1108double ScMatrixImpl::And() const
1109{
1110 // All elements must be of value type.
1111 // True only if all the elements have non-zero values.
1112 return EvalMatrix<AndEvaluator>(maMat);
1113}
1114
1115double ScMatrixImpl::Or() const
1116{
1117 // All elements must be of value type.
1118 // True if at least one element has a non-zero value.
1119 return EvalMatrix<OrEvaluator>(maMat);
1120}
1121
1122double ScMatrixImpl::Xor() const
1123{
1124 // All elements must be of value type.
1125 // True if an odd number of elements have a non-zero value.
1126 return EvalMatrix<XorEvaluator>(maMat);
1127}
1128
1129namespace {
1130
1131template<typename Op, typename tRes>
1132class WalkElementBlocks
1133{
1134 Op maOp;
1136 bool mbTextAsZero:1;
1137 bool mbIgnoreErrorValues:1;
1138public:
1139 WalkElementBlocks(bool bTextAsZero, bool bIgnoreErrorValues) :
1140 maRes(Op::InitVal, 0),
1141 mbTextAsZero(bTextAsZero), mbIgnoreErrorValues(bIgnoreErrorValues)
1142 {}
1143
1144 const ScMatrix::IterateResult<tRes>& getResult() const { return maRes; }
1145
1146 void operator() (const MatrixImplType::element_block_node_type& node)
1147 {
1148 switch (node.type)
1149 {
1150 case mdds::mtm::element_numeric:
1151 {
1152 typedef MatrixImplType::numeric_block_type block_type;
1153
1154 size_t nIgnored = 0;
1155 block_type::const_iterator it = block_type::begin(*node.data);
1156 block_type::const_iterator itEnd = block_type::end(*node.data);
1157 for (; it != itEnd; ++it)
1158 {
1159 if (mbIgnoreErrorValues && !std::isfinite(*it))
1160 {
1161 ++nIgnored;
1162 continue;
1163 }
1164 maOp(maRes.maAccumulator, *it);
1165 }
1166 maRes.mnCount += node.size - nIgnored;
1167 }
1168 break;
1169 case mdds::mtm::element_boolean:
1170 {
1171 typedef MatrixImplType::boolean_block_type block_type;
1172
1173 block_type::const_iterator it = block_type::begin(*node.data);
1174 block_type::const_iterator itEnd = block_type::end(*node.data);
1175 for (; it != itEnd; ++it)
1176 {
1177 maOp(maRes.maAccumulator, *it);
1178 }
1179 maRes.mnCount += node.size;
1180 }
1181 break;
1182 case mdds::mtm::element_string:
1183 if (mbTextAsZero)
1184 maRes.mnCount += node.size;
1185 break;
1186 case mdds::mtm::element_empty:
1187 default:
1188 ;
1189 }
1190 }
1191};
1192
1193template<typename Op, typename tRes>
1194class WalkElementBlocksMultipleValues
1195{
1196 const std::vector<Op>* mpOp;
1198public:
1199 WalkElementBlocksMultipleValues(const std::vector<Op>& aOp) :
1200 mpOp(&aOp), maRes(0)
1201 {
1202 for (const auto& rpOp : *mpOp)
1203 maRes.maAccumulator.emplace_back(rpOp.mInitVal);
1204 }
1205
1206 WalkElementBlocksMultipleValues( const WalkElementBlocksMultipleValues& ) = delete;
1207 WalkElementBlocksMultipleValues& operator= ( const WalkElementBlocksMultipleValues& ) = delete;
1208
1209 WalkElementBlocksMultipleValues(WalkElementBlocksMultipleValues&& r) noexcept
1210 : mpOp(r.mpOp), maRes(r.maRes.mnCount)
1211 {
1212 maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1213 }
1214
1215 WalkElementBlocksMultipleValues& operator=(WalkElementBlocksMultipleValues&& r) noexcept
1216 {
1217 mpOp = r.mpOp;
1218 maRes.maAccumulator = std::move(r.maRes.maAccumulator);
1219 maRes.mnCount = r.maRes.mnCount;
1220 return *this;
1221 }
1222
1223 const ScMatrix::IterateResultMultiple<tRes>& getResult() const { return maRes; }
1224
1225 void operator() (const MatrixImplType::element_block_node_type& node)
1226 {
1227 switch (node.type)
1228 {
1229 case mdds::mtm::element_numeric:
1230 {
1231 typedef MatrixImplType::numeric_block_type block_type;
1232
1233 block_type::const_iterator it = block_type::begin(*node.data);
1234 block_type::const_iterator itEnd = block_type::end(*node.data);
1235 for (; it != itEnd; ++it)
1236 {
1237 for (size_t i = 0u; i < mpOp->size(); ++i)
1238 (*mpOp)[i](maRes.maAccumulator[i], *it);
1239 }
1240 maRes.mnCount += node.size;
1241 }
1242 break;
1243 case mdds::mtm::element_boolean:
1244 {
1245 typedef MatrixImplType::boolean_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_string:
1258 case mdds::mtm::element_empty:
1259 default:
1260 ;
1261 }
1262 }
1263};
1264
1265class CountElements
1266{
1267 size_t mnCount;
1268 bool mbCountString;
1269 bool mbCountErrors;
1270 bool mbIgnoreEmptyStrings;
1271public:
1272 explicit CountElements(bool bCountString, bool bCountErrors, bool bIgnoreEmptyStrings) :
1273 mnCount(0), mbCountString(bCountString), mbCountErrors(bCountErrors),
1274 mbIgnoreEmptyStrings(bIgnoreEmptyStrings) {}
1275
1276 size_t getCount() const { return mnCount; }
1277
1278 void operator() (const MatrixImplType::element_block_node_type& node)
1279 {
1280 switch (node.type)
1281 {
1282 case mdds::mtm::element_numeric:
1283 mnCount += node.size;
1284 if (!mbCountErrors)
1285 {
1286 typedef MatrixImplType::numeric_block_type block_type;
1287
1288 block_type::const_iterator it = block_type::begin(*node.data);
1289 block_type::const_iterator itEnd = block_type::end(*node.data);
1290 for (; it != itEnd; ++it)
1291 {
1292 if (!std::isfinite(*it))
1293 --mnCount;
1294 }
1295 }
1296 break;
1297 case mdds::mtm::element_boolean:
1298 mnCount += node.size;
1299 break;
1300 case mdds::mtm::element_string:
1301 if (mbCountString)
1302 {
1303 mnCount += node.size;
1304 if (mbIgnoreEmptyStrings)
1305 {
1306 typedef MatrixImplType::string_block_type block_type;
1307
1308 block_type::const_iterator it = block_type::begin(*node.data);
1309 block_type::const_iterator itEnd = block_type::end(*node.data);
1310 for (; it != itEnd; ++it)
1311 {
1312 if (it->isEmpty())
1313 --mnCount;
1314 }
1315 }
1316 }
1317 break;
1318 case mdds::mtm::element_empty:
1319 default:
1320 ;
1321 }
1322 }
1323};
1324
1325const size_t ResultNotSet = std::numeric_limits<size_t>::max();
1326
1327template<typename Type>
1328class WalkAndMatchElements
1329{
1330 Type maMatchValue;
1331 size_t mnStartIndex;
1332 size_t mnStopIndex;
1333 size_t mnResult;
1334 size_t mnIndex;
1335
1336public:
1337 WalkAndMatchElements(Type aMatchValue, const MatrixImplType::size_pair_type& aSize, size_t nCol1, size_t nCol2) :
1338 maMatchValue(std::move(aMatchValue)),
1339 mnStartIndex( nCol1 * aSize.row ),
1340 mnStopIndex( (nCol2 + 1) * aSize.row ),
1341 mnResult(ResultNotSet),
1342 mnIndex(0)
1343 {
1344 assert( nCol1 < aSize.column && nCol2 < aSize.column);
1345 }
1346
1347 size_t getMatching() const { return mnResult; }
1348
1349 size_t getRemainingCount() const
1350 {
1351 return mnIndex < mnStopIndex ? mnStopIndex - mnIndex : 0;
1352 }
1353
1354 size_t compare(const MatrixImplType::element_block_node_type& node) const;
1355
1356 void operator() (const MatrixImplType::element_block_node_type& node)
1357 {
1358 // early exit if match already found
1359 if (mnResult != ResultNotSet)
1360 return;
1361
1362 // limit lookup to the requested columns
1363 if (mnStartIndex <= mnIndex && getRemainingCount() > 0)
1364 {
1365 mnResult = compare(node);
1366 }
1367
1368 mnIndex += node.size;
1369 }
1370};
1371
1372template<>
1373size_t WalkAndMatchElements<double>::compare(const MatrixImplType::element_block_node_type& node) const
1374{
1375 size_t nCount = 0;
1376 switch (node.type)
1377 {
1378 case mdds::mtm::element_numeric:
1379 {
1380 typedef MatrixImplType::numeric_block_type block_type;
1381
1382 block_type::const_iterator it = block_type::begin(*node.data);
1383 block_type::const_iterator itEnd = block_type::end(*node.data);
1384 const size_t nRemaining = getRemainingCount();
1385 for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1386 {
1387 if (*it == maMatchValue)
1388 {
1389 return mnIndex + nCount;
1390 }
1391 }
1392 break;
1393 }
1394 case mdds::mtm::element_boolean:
1395 {
1396 typedef MatrixImplType::boolean_block_type block_type;
1397
1398 block_type::const_iterator it = block_type::begin(*node.data);
1399 block_type::const_iterator itEnd = block_type::end(*node.data);
1400 const size_t nRemaining = getRemainingCount();
1401 for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1402 {
1403 if (int(*it) == maMatchValue)
1404 {
1405 return mnIndex + nCount;
1406 }
1407 }
1408 break;
1409 }
1410 break;
1411 case mdds::mtm::element_string:
1412 case mdds::mtm::element_empty:
1413 default:
1414 ;
1415 }
1416 return ResultNotSet;
1417}
1418
1419template<>
1420size_t WalkAndMatchElements<svl::SharedString>::compare(const MatrixImplType::element_block_node_type& node) const
1421{
1422 switch (node.type)
1423 {
1424 case mdds::mtm::element_string:
1425 {
1426 size_t nCount = 0;
1427 typedef MatrixImplType::string_block_type block_type;
1428
1429 block_type::const_iterator it = block_type::begin(*node.data);
1430 block_type::const_iterator itEnd = block_type::end(*node.data);
1431 const size_t nRemaining = getRemainingCount();
1432 for (; it != itEnd && nCount < nRemaining; ++it, ++nCount)
1433 {
1434 if (it->getDataIgnoreCase() == maMatchValue.getDataIgnoreCase())
1435 {
1436 return mnIndex + nCount;
1437 }
1438 }
1439 break;
1440 }
1441 case mdds::mtm::element_boolean:
1442 case mdds::mtm::element_numeric:
1443 case mdds::mtm::element_empty:
1444 default:
1445 ;
1446 }
1447 return ResultNotSet;
1448}
1449
1450struct MaxOp
1451{
1452 static double init() { return -std::numeric_limits<double>::max(); }
1453 static double compare(double left, double right)
1454 {
1455 if (!std::isfinite(left))
1456 return left;
1457 if (!std::isfinite(right))
1458 return right;
1459 return std::max(left, right);
1460 }
1461
1462 static double boolValue(
1463 MatrixImplType::boolean_block_type::const_iterator it,
1464 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1465 {
1466 // If the array has at least one true value, the maximum value is 1.
1467 it = std::find(it, itEnd, true);
1468 return it == itEnd ? 0.0 : 1.0;
1469 }
1470};
1471
1472struct MinOp
1473{
1474 static double init() { return std::numeric_limits<double>::max(); }
1475 static double compare(double left, double right)
1476 {
1477 if (!std::isfinite(left))
1478 return left;
1479 if (!std::isfinite(right))
1480 return right;
1481 return std::min(left, right);
1482 }
1483
1484 static double boolValue(
1485 MatrixImplType::boolean_block_type::const_iterator it,
1486 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1487 {
1488 // If the array has at least one false value, the minimum value is 0.
1489 it = std::find(it, itEnd, false);
1490 return it == itEnd ? 1.0 : 0.0;
1491 }
1492};
1493
1494struct Lcm
1495{
1496 static double init() { return 1.0; }
1497 static double calculate(double fx,double fy)
1498 {
1499 return (fx*fy)/ScInterpreter::ScGetGCD(fx,fy);
1500 }
1501
1502 static double boolValue(
1503 MatrixImplType::boolean_block_type::const_iterator it,
1504 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1505 {
1506 // If the array has at least one false value, the minimum value is 0.
1507 it = std::find(it, itEnd, false);
1508 return it == itEnd ? 1.0 : 0.0;
1509 }
1510};
1511
1512struct Gcd
1513{
1514 static double init() { return 0.0; }
1515 static double calculate(double fx,double fy)
1516 {
1517 return ScInterpreter::ScGetGCD(fx,fy);
1518 }
1519
1520 static double boolValue(
1521 MatrixImplType::boolean_block_type::const_iterator it,
1522 const MatrixImplType::boolean_block_type::const_iterator& itEnd)
1523 {
1524 // If the array has at least one true value, the gcdResult is 1.
1525 it = std::find(it, itEnd, true);
1526 return it == itEnd ? 0.0 : 1.0;
1527 }
1528};
1529
1530template<typename Op>
1531class CalcMaxMinValue
1532{
1533 double mfVal;
1534 bool mbTextAsZero;
1535 bool mbIgnoreErrorValues;
1536 bool mbHasValue;
1537public:
1538 CalcMaxMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) :
1539 mfVal(Op::init()),
1540 mbTextAsZero(bTextAsZero),
1541 mbIgnoreErrorValues(bIgnoreErrorValues),
1542 mbHasValue(false) {}
1543
1544 double getValue() const { return mbHasValue ? mfVal : 0.0; }
1545
1546 void operator() (const MatrixImplType::element_block_node_type& node)
1547 {
1548
1549 switch (node.type)
1550 {
1551 case mdds::mtm::element_numeric:
1552 {
1553 typedef MatrixImplType::numeric_block_type block_type;
1554
1555 block_type::const_iterator it = block_type::begin(*node.data);
1556 block_type::const_iterator itEnd = block_type::end(*node.data);
1557 if (mbIgnoreErrorValues)
1558 {
1559 for (; it != itEnd; ++it)
1560 {
1561 if (std::isfinite(*it))
1562 mfVal = Op::compare(mfVal, *it);
1563 }
1564 }
1565 else
1566 {
1567 for (; it != itEnd; ++it)
1568 mfVal = Op::compare(mfVal, *it);
1569 }
1570
1571 mbHasValue = true;
1572 }
1573 break;
1574 case mdds::mtm::element_boolean:
1575 {
1576 typedef MatrixImplType::boolean_block_type block_type;
1577
1578 block_type::const_iterator it = block_type::begin(*node.data);
1579 block_type::const_iterator itEnd = block_type::end(*node.data);
1580 double fVal = Op::boolValue(it, itEnd);
1581 mfVal = Op::compare(mfVal, fVal);
1582 mbHasValue = true;
1583 }
1584 break;
1585 case mdds::mtm::element_string:
1586 case mdds::mtm::element_empty:
1587 {
1588 // empty elements are treated as empty strings.
1589 if (mbTextAsZero)
1590 {
1591 mfVal = Op::compare(mfVal, 0.0);
1592 mbHasValue = true;
1593 }
1594 }
1595 break;
1596 default:
1597 ;
1598 }
1599 }
1600};
1601
1602template<typename Op>
1603class CalcGcdLcm
1604{
1605 double mfval;
1606
1607public:
1608 CalcGcdLcm() : mfval(Op::init()) {}
1609
1610 double getResult() const { return mfval; }
1611
1612 void operator() ( const MatrixImplType::element_block_node_type& node )
1613 {
1614 switch (node.type)
1615 {
1616 case mdds::mtm::element_numeric:
1617 {
1618 typedef MatrixImplType::numeric_block_type block_type;
1619 block_type::const_iterator it = block_type::begin(*node.data);
1620 block_type::const_iterator itEnd = block_type::end(*node.data);
1621
1622 for ( ; it != itEnd; ++it)
1623 {
1624 if (*it < 0.0)
1625 mfval = CreateDoubleError(FormulaError::IllegalArgument);
1626 else
1627 mfval = ::rtl::math::approxFloor( Op::calculate(*it,mfval));
1628 }
1629 }
1630 break;
1631 case mdds::mtm::element_boolean:
1632 {
1633 typedef MatrixImplType::boolean_block_type block_type;
1634 block_type::const_iterator it = block_type::begin(*node.data);
1635 block_type::const_iterator itEnd = block_type::end(*node.data);
1636
1637 mfval = Op::boolValue(it, itEnd);
1638 }
1639 break;
1640 case mdds::mtm::element_empty:
1641 case mdds::mtm::element_string:
1642 {
1643 mfval = CreateDoubleError(FormulaError::IllegalArgument);
1644 }
1645 break;
1646 default:
1647 ;
1648 }
1649 }
1650};
1651
1652double evaluate( double fVal, ScQueryOp eOp )
1653{
1654 if (!std::isfinite(fVal))
1655 return fVal;
1656
1657 switch (eOp)
1658 {
1659 case SC_EQUAL:
1660 return fVal == 0.0 ? 1.0 : 0.0;
1661 case SC_LESS:
1662 return fVal < 0.0 ? 1.0 : 0.0;
1663 case SC_GREATER:
1664 return fVal > 0.0 ? 1.0 : 0.0;
1665 case SC_LESS_EQUAL:
1666 return fVal <= 0.0 ? 1.0 : 0.0;
1667 case SC_GREATER_EQUAL:
1668 return fVal >= 0.0 ? 1.0 : 0.0;
1669 case SC_NOT_EQUAL:
1670 return fVal != 0.0 ? 1.0 : 0.0;
1671 default:
1672 ;
1673 }
1674
1675 SAL_WARN("sc.core", "evaluate: unhandled comparison operator: " << static_cast<int>(eOp));
1676 return CreateDoubleError( FormulaError::UnknownState);
1677}
1678
1679class CompareMatrixFunc
1680{
1681 sc::Compare& mrComp;
1682 size_t mnMatPos;
1683 sc::CompareOptions* mpOptions;
1684 std::vector<double> maResValues; // double instead of bool to transport error values
1685
1686 void compare()
1687 {
1688 double fVal = sc::CompareFunc( mrComp, mpOptions);
1689 maResValues.push_back(evaluate(fVal, mrComp.meOp));
1690 }
1691
1692public:
1693 CompareMatrixFunc( size_t nResSize, sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) :
1694 mrComp(rComp), mnMatPos(nMatPos), mpOptions(pOptions)
1695 {
1696 maResValues.reserve(nResSize);
1697 }
1698
1699 CompareMatrixFunc( const CompareMatrixFunc& ) = delete;
1700 CompareMatrixFunc& operator= ( const CompareMatrixFunc& ) = delete;
1701
1702 CompareMatrixFunc(CompareMatrixFunc&& r) noexcept :
1703 mrComp(r.mrComp),
1704 mnMatPos(r.mnMatPos),
1705 mpOptions(r.mpOptions),
1706 maResValues(std::move(r.maResValues)) {}
1707
1708 CompareMatrixFunc& operator=(CompareMatrixFunc&& r) noexcept
1709 {
1710 mrComp = r.mrComp;
1711 mnMatPos = r.mnMatPos;
1712 mpOptions = r.mpOptions;
1713 maResValues = std::move(r.maResValues);
1714 return *this;
1715 }
1716
1717 void operator() (const MatrixImplType::element_block_node_type& node)
1718 {
1719 sc::Compare::Cell& rCell = mrComp.maCells[mnMatPos];
1720
1721 switch (node.type)
1722 {
1723 case mdds::mtm::element_numeric:
1724 {
1725 typedef MatrixImplType::numeric_block_type block_type;
1726
1727 block_type::const_iterator it = block_type::begin(*node.data);
1728 block_type::const_iterator itEnd = block_type::end(*node.data);
1729 for (; it != itEnd; ++it)
1730 {
1731 rCell.mbValue = true;
1732 rCell.mbEmpty = false;
1733 rCell.mfValue = *it;
1734 compare();
1735 }
1736 }
1737 break;
1738 case mdds::mtm::element_boolean:
1739 {
1740 typedef MatrixImplType::boolean_block_type block_type;
1741
1742 block_type::const_iterator it = block_type::begin(*node.data);
1743 block_type::const_iterator itEnd = block_type::end(*node.data);
1744 for (; it != itEnd; ++it)
1745 {
1746 rCell.mbValue = true;
1747 rCell.mbEmpty = false;
1748 rCell.mfValue = double(*it);
1749 compare();
1750 }
1751 }
1752 break;
1753 case mdds::mtm::element_string:
1754 {
1755 typedef MatrixImplType::string_block_type block_type;
1756
1757 block_type::const_iterator it = block_type::begin(*node.data);
1758 block_type::const_iterator itEnd = block_type::end(*node.data);
1759 for (; it != itEnd; ++it)
1760 {
1761 const svl::SharedString& rStr = *it;
1762 rCell.mbValue = false;
1763 rCell.mbEmpty = false;
1764 rCell.maStr = rStr;
1765 compare();
1766 }
1767 }
1768 break;
1769 case mdds::mtm::element_empty:
1770 {
1771 rCell.mbValue = false;
1772 rCell.mbEmpty = true;
1774 for (size_t i = 0; i < node.size; ++i)
1775 compare();
1776 }
1777 break;
1778 default:
1779 ;
1780 }
1781 }
1782
1783 const std::vector<double>& getValues() const
1784 {
1785 return maResValues;
1786 }
1787};
1788
1792class CompareMatrixToNumericFunc
1793{
1794 sc::Compare& mrComp;
1795 double mfRightValue;
1796 sc::CompareOptions* mpOptions;
1797 std::vector<double> maResValues; // double instead of bool to transport error values
1798
1799 void compare()
1800 {
1801 double fVal = sc::CompareFunc(mrComp.maCells[0], mfRightValue, mpOptions);
1802 maResValues.push_back(evaluate(fVal, mrComp.meOp));
1803 }
1804
1805 void compareLeftNumeric( double fLeftVal )
1806 {
1807 double fVal = sc::CompareFunc(fLeftVal, mfRightValue);
1808 maResValues.push_back(evaluate(fVal, mrComp.meOp));
1809 }
1810
1811 void compareLeftEmpty( size_t nSize )
1812 {
1813 double fVal = sc::CompareEmptyToNumericFunc(mfRightValue);
1814 bool bRes = evaluate(fVal, mrComp.meOp);
1815 maResValues.resize(maResValues.size() + nSize, bRes ? 1.0 : 0.0);
1816 }
1817
1818public:
1819 CompareMatrixToNumericFunc( size_t nResSize, sc::Compare& rComp, double fRightValue, sc::CompareOptions* pOptions ) :
1820 mrComp(rComp), mfRightValue(fRightValue), mpOptions(pOptions)
1821 {
1822 maResValues.reserve(nResSize);
1823 }
1824
1825 CompareMatrixToNumericFunc( const CompareMatrixToNumericFunc& ) = delete;
1826 CompareMatrixToNumericFunc& operator= ( const CompareMatrixToNumericFunc& ) = delete;
1827
1828 CompareMatrixToNumericFunc(CompareMatrixToNumericFunc&& r) noexcept :
1829 mrComp(r.mrComp),
1830 mfRightValue(r.mfRightValue),
1831 mpOptions(r.mpOptions),
1832 maResValues(std::move(r.maResValues)) {}
1833
1834 CompareMatrixToNumericFunc& operator=(CompareMatrixToNumericFunc&& r) noexcept
1835 {
1836 mrComp = r.mrComp;
1837 mfRightValue = r.mfRightValue;
1838 mpOptions = r.mpOptions;
1839 maResValues = std::move(r.maResValues);
1840 return *this;
1841 }
1842
1843 void operator() (const MatrixImplType::element_block_node_type& node)
1844 {
1845 switch (node.type)
1846 {
1847 case mdds::mtm::element_numeric:
1848 {
1849 typedef MatrixImplType::numeric_block_type block_type;
1850
1851 block_type::const_iterator it = block_type::begin(*node.data);
1852 block_type::const_iterator itEnd = block_type::end(*node.data);
1853 for (; it != itEnd; ++it)
1854 compareLeftNumeric(*it);
1855 }
1856 break;
1857 case mdds::mtm::element_boolean:
1858 {
1859 typedef MatrixImplType::boolean_block_type block_type;
1860
1861 block_type::const_iterator it = block_type::begin(*node.data);
1862 block_type::const_iterator itEnd = block_type::end(*node.data);
1863 for (; it != itEnd; ++it)
1864 compareLeftNumeric(double(*it));
1865 }
1866 break;
1867 case mdds::mtm::element_string:
1868 {
1869 typedef MatrixImplType::string_block_type block_type;
1870
1871 block_type::const_iterator it = block_type::begin(*node.data);
1872 block_type::const_iterator itEnd = block_type::end(*node.data);
1873 for (; it != itEnd; ++it)
1874 {
1875 const svl::SharedString& rStr = *it;
1876 sc::Compare::Cell& rCell = mrComp.maCells[0];
1877 rCell.mbValue = false;
1878 rCell.mbEmpty = false;
1879 rCell.maStr = rStr;
1880 compare();
1881 }
1882 }
1883 break;
1884 case mdds::mtm::element_empty:
1885 compareLeftEmpty(node.size);
1886 break;
1887 default:
1888 ;
1889 }
1890 }
1891
1892 const std::vector<double>& getValues() const
1893 {
1894 return maResValues;
1895 }
1896};
1897
1898class ToDoubleArray
1899{
1900 std::vector<double> maArray;
1901 std::vector<double>::iterator miPos;
1902 double mfNaN;
1903 bool mbEmptyAsZero;
1904
1905 void moveArray( ToDoubleArray& r )
1906 {
1907 // Re-create the iterator from the new array after the array has been
1908 // moved, to ensure that the iterator points to a valid array
1909 // position.
1910 size_t n = std::distance(r.maArray.begin(), r.miPos);
1911 maArray = std::move(r.maArray);
1912 miPos = maArray.begin();
1913 std::advance(miPos, n);
1914 }
1915
1916public:
1917 ToDoubleArray( size_t nSize, bool bEmptyAsZero ) :
1918 maArray(nSize, 0.0), miPos(maArray.begin()), mbEmptyAsZero(bEmptyAsZero)
1919 {
1920 mfNaN = CreateDoubleError( FormulaError::ElementNaN);
1921 }
1922
1923 ToDoubleArray( const ToDoubleArray& ) = delete;
1924 ToDoubleArray& operator= ( const ToDoubleArray& ) = delete;
1925
1926 ToDoubleArray(ToDoubleArray&& r) noexcept :
1927 mfNaN(r.mfNaN), mbEmptyAsZero(r.mbEmptyAsZero)
1928 {
1929 moveArray(r);
1930 }
1931
1932 ToDoubleArray& operator=(ToDoubleArray&& r) noexcept
1933 {
1934 mfNaN = r.mfNaN;
1935 mbEmptyAsZero = r.mbEmptyAsZero;
1936 moveArray(r);
1937 return *this;
1938 }
1939
1940 void operator() (const MatrixImplType::element_block_node_type& node)
1941 {
1942 using namespace mdds::mtv;
1943
1944 switch (node.type)
1945 {
1946 case mdds::mtm::element_numeric:
1947 {
1948 double_element_block::const_iterator it = double_element_block::begin(*node.data);
1949 double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
1950 for (; it != itEnd; ++it, ++miPos)
1951 *miPos = *it;
1952 }
1953 break;
1954 case mdds::mtm::element_boolean:
1955 {
1956 boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
1957 boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
1958 for (; it != itEnd; ++it, ++miPos)
1959 *miPos = *it ? 1.0 : 0.0;
1960 }
1961 break;
1962 case mdds::mtm::element_string:
1963 {
1964 for (size_t i = 0; i < node.size; ++i, ++miPos)
1965 *miPos = mfNaN;
1966 }
1967 break;
1968 case mdds::mtm::element_empty:
1969 {
1970 if (mbEmptyAsZero)
1971 {
1972 std::advance(miPos, node.size);
1973 return;
1974 }
1975
1976 for (size_t i = 0; i < node.size; ++i, ++miPos)
1977 *miPos = mfNaN;
1978 }
1979 break;
1980 default:
1981 ;
1982 }
1983 }
1984
1985 void swap(std::vector<double>& rOther)
1986 {
1987 maArray.swap(rOther);
1988 }
1989};
1990
1991struct ArrayMul
1992{
1993 double operator() (const double& lhs, const double& rhs) const
1994 {
1995 return lhs * rhs;
1996 }
1997};
1998
1999template<typename Op>
2000class MergeDoubleArrayFunc
2001{
2002 std::vector<double>::iterator miPos;
2003 double mfNaN;
2004public:
2005 MergeDoubleArrayFunc(std::vector<double>& rArray) : miPos(rArray.begin())
2006 {
2007 mfNaN = CreateDoubleError( FormulaError::ElementNaN);
2008 }
2009
2010 MergeDoubleArrayFunc( const MergeDoubleArrayFunc& ) = delete;
2011 MergeDoubleArrayFunc& operator= ( const MergeDoubleArrayFunc& ) = delete;
2012
2013 MergeDoubleArrayFunc( MergeDoubleArrayFunc&& ) = default;
2014 MergeDoubleArrayFunc& operator= ( MergeDoubleArrayFunc&& ) = default;
2015
2016 void operator() (const MatrixImplType::element_block_node_type& node)
2017 {
2018 using namespace mdds::mtv;
2019 static const Op op;
2020
2021 switch (node.type)
2022 {
2023 case mdds::mtm::element_numeric:
2024 {
2025 double_element_block::const_iterator it = double_element_block::begin(*node.data);
2026 double_element_block::const_iterator itEnd = double_element_block::end(*node.data);
2027 for (; it != itEnd; ++it, ++miPos)
2028 {
2029 if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2030 continue;
2031
2032 *miPos = op(*miPos, *it);
2033 }
2034 }
2035 break;
2036 case mdds::mtm::element_boolean:
2037 {
2038 boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data);
2039 boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data);
2040 for (; it != itEnd; ++it, ++miPos)
2041 {
2042 if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2043 continue;
2044
2045 *miPos = op(*miPos, *it ? 1.0 : 0.0);
2046 }
2047 }
2048 break;
2049 case mdds::mtm::element_string:
2050 {
2051 for (size_t i = 0; i < node.size; ++i, ++miPos)
2052 *miPos = mfNaN;
2053 }
2054 break;
2055 case mdds::mtm::element_empty:
2056 {
2057 // Empty element is equivalent of having a numeric value of 0.0.
2058 for (size_t i = 0; i < node.size; ++i, ++miPos)
2059 {
2060 if (GetDoubleErrorValue(*miPos) == FormulaError::ElementNaN)
2061 continue;
2062
2063 *miPos = op(*miPos, 0.0);
2064 }
2065 }
2066 break;
2067 default:
2068 ;
2069 }
2070 }
2071};
2072
2073}
2074
2075namespace {
2076
2077template<typename TOp, typename tRes>
2078ScMatrix::IterateResult<tRes> GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorValues, const MatrixImplType& maMat)
2079{
2080 WalkElementBlocks<TOp, tRes> aFunc(bTextAsZero, bIgnoreErrorValues);
2081 aFunc = maMat.walk(aFunc);
2082 return aFunc.getResult();
2083}
2084
2085}
2086
2087ScMatrix::KahanIterateResult ScMatrixImpl::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
2088{
2089 return GetValueWithCount<sc::op::Sum, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2090}
2091
2092ScMatrix::KahanIterateResult ScMatrixImpl::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
2093{
2094 return GetValueWithCount<sc::op::SumSquare, KahanSum>(bTextAsZero, bIgnoreErrorValues, maMat);
2095}
2096
2097ScMatrix::DoubleIterateResult ScMatrixImpl::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
2098{
2099 return GetValueWithCount<sc::op::Product, double>(bTextAsZero, bIgnoreErrorValues, maMat);
2100}
2101
2102size_t ScMatrixImpl::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
2103{
2104 CountElements aFunc(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
2105 aFunc = maMat.walk(aFunc);
2106 return aFunc.getCount();
2107}
2108
2109size_t ScMatrixImpl::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
2110{
2111 WalkAndMatchElements<double> aFunc(fValue, maMat.size(), nCol1, nCol2);
2112 aFunc = maMat.walk(aFunc);
2113 return aFunc.getMatching();
2114}
2115
2116size_t ScMatrixImpl::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
2117{
2118 WalkAndMatchElements<svl::SharedString> aFunc(rStr, maMat.size(), nCol1, nCol2);
2119 aFunc = maMat.walk(aFunc);
2120 return aFunc.getMatching();
2121}
2122
2123double ScMatrixImpl::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2124{
2125 CalcMaxMinValue<MaxOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2126 aFunc = maMat.walk(aFunc);
2127 return aFunc.getValue();
2128}
2129
2130double ScMatrixImpl::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
2131{
2132 CalcMaxMinValue<MinOp> aFunc(bTextAsZero, bIgnoreErrorValues);
2133 aFunc = maMat.walk(aFunc);
2134 return aFunc.getValue();
2135}
2136
2138{
2139 CalcGcdLcm<Gcd> aFunc;
2140 aFunc = maMat.walk(aFunc);
2141 return aFunc.getResult();
2142}
2143
2145{
2146 CalcGcdLcm<Lcm> aFunc;
2147 aFunc = maMat.walk(aFunc);
2148 return aFunc.getResult();
2149}
2150
2152 sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
2153{
2154 MatrixImplType::size_pair_type aSize = maMat.size();
2155 size_t nSize = aSize.column * aSize.row;
2156 if (nMatPos == 0)
2157 {
2158 if (rComp.maCells[1].mbValue && !rComp.maCells[1].mbEmpty)
2159 {
2160 // Matrix on the left, and a numeric value on the right. Use a
2161 // function object that has much less branching for much better
2162 // performance.
2163 CompareMatrixToNumericFunc aFunc(nSize, rComp, rComp.maCells[1].mfValue, pOptions);
2164 aFunc = maMat.walk(std::move(aFunc));
2165
2166 // We assume the result matrix has the same dimension as this matrix.
2167 const std::vector<double>& rResVal = aFunc.getValues();
2168 assert (nSize == rResVal.size());
2169 if (nSize != rResVal.size())
2170 return ScMatrixRef();
2171
2172 return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2173 }
2174 }
2175
2176 CompareMatrixFunc aFunc(nSize, rComp, nMatPos, pOptions);
2177 aFunc = maMat.walk(std::move(aFunc));
2178
2179 // We assume the result matrix has the same dimension as this matrix.
2180 const std::vector<double>& rResVal = aFunc.getValues();
2181 assert (nSize == rResVal.size());
2182 if (nSize != rResVal.size())
2183 return ScMatrixRef();
2184
2185 return ScMatrixRef(new ScMatrix(aSize.column, aSize.row, rResVal));
2186}
2187
2188void ScMatrixImpl::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
2189{
2190 MatrixImplType::size_pair_type aSize = maMat.size();
2191 ToDoubleArray aFunc(aSize.row*aSize.column, bEmptyAsZero);
2192 aFunc = maMat.walk(std::move(aFunc));
2193 aFunc.swap(rArray);
2194}
2195
2196void ScMatrixImpl::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
2197{
2198 MatrixImplType::size_pair_type aSize = maMat.size();
2199 size_t nSize = aSize.row*aSize.column;
2200 if (nSize != rArray.size())
2201 return;
2202
2203 MergeDoubleArrayFunc<ArrayMul> aFunc(rArray);
2204 maMat.walk(std::move(aFunc));
2205}
2206
2207namespace {
2208
2209template<typename T, typename U, typename return_type>
2210struct wrapped_iterator
2211{
2212 typedef ::std::bidirectional_iterator_tag iterator_category;
2213 typedef typename T::const_iterator::value_type old_value_type;
2214 typedef return_type value_type;
2215 typedef value_type* pointer;
2216 typedef value_type& reference;
2217 typedef typename T::const_iterator::difference_type difference_type;
2218
2219 typename T::const_iterator it;
2220 mutable value_type val;
2221 U maOp;
2222
2223private:
2224
2225 value_type calcVal() const
2226 {
2227 return maOp(*it);
2228 }
2229
2230public:
2231
2232 wrapped_iterator(typename T::const_iterator it_, U const & aOp):
2233 it(std::move(it_)),
2234 val(value_type()),
2235 maOp(aOp)
2236 {
2237 }
2238
2239 wrapped_iterator(const wrapped_iterator& r):
2240 it(r.it),
2241 val(r.val),
2242 maOp(r.maOp)
2243 {
2244 }
2245
2246 wrapped_iterator& operator=(const wrapped_iterator& r)
2247 {
2248 it = r.it;
2249 return *this;
2250 }
2251
2252 bool operator==(const wrapped_iterator& r) const
2253 {
2254 return it == r.it;
2255 }
2256
2257 bool operator!=(const wrapped_iterator& r) const
2258 {
2259 return !operator==(r);
2260 }
2261
2262 wrapped_iterator& operator++()
2263 {
2264 ++it;
2265
2266 return *this;
2267 }
2268
2269 wrapped_iterator& operator--()
2270 {
2271 --it;
2272
2273 return *this;
2274 }
2275
2276 value_type& operator*() const
2277 {
2278 val = calcVal();
2279 return val;
2280 }
2281
2282 pointer operator->() const
2283 {
2284 val = calcVal();
2285 return &val;
2286 }
2287};
2288
2289template<typename T, typename U, typename return_type>
2290struct MatrixIteratorWrapper
2291{
2292private:
2293 typename T::const_iterator m_itBegin;
2294 typename T::const_iterator m_itEnd;
2295 U maOp;
2296public:
2297 MatrixIteratorWrapper(typename T::const_iterator itBegin, typename T::const_iterator itEnd, U const & aOp):
2298 m_itBegin(std::move(itBegin)),
2299 m_itEnd(std::move(itEnd)),
2300 maOp(aOp)
2301 {
2302 }
2303
2304 wrapped_iterator<T, U, return_type> begin()
2305 {
2306 return wrapped_iterator<T, U, return_type>(m_itBegin, maOp);
2307 }
2308
2309 wrapped_iterator<T, U, return_type> end()
2310 {
2311 return wrapped_iterator<T, U, return_type>(m_itEnd, maOp);
2312 }
2313};
2314
2315MatrixImplType::position_type increment_position(const MatrixImplType::position_type& pos, size_t n)
2316{
2317 MatrixImplType::position_type ret = pos;
2318 do
2319 {
2320 if (ret.second + n < ret.first->size)
2321 {
2322 ret.second += n;
2323 break;
2324 }
2325 else
2326 {
2327 n -= (ret.first->size - ret.second);
2328 ++ret.first;
2329 ret.second = 0;
2330 }
2331 }
2332 while (n > 0);
2333 return ret;
2334}
2335
2336template<typename T>
2337struct MatrixOpWrapper
2338{
2339private:
2340 MatrixImplType& mrMat;
2341 MatrixImplType::position_type pos;
2342 const T* mpOp;
2343
2344public:
2345 MatrixOpWrapper(MatrixImplType& rMat, const T& aOp):
2346 mrMat(rMat),
2347 pos(rMat.position(0,0)),
2348 mpOp(&aOp)
2349 {
2350 }
2351
2352 MatrixOpWrapper( const MatrixOpWrapper& r ) : mrMat(r.mrMat), pos(r.pos), mpOp(r.mpOp) {}
2353
2354 MatrixOpWrapper& operator= ( const MatrixOpWrapper& r ) = default;
2355
2356 void operator()(const MatrixImplType::element_block_node_type& node)
2357 {
2358 switch (node.type)
2359 {
2360 case mdds::mtm::element_numeric:
2361 {
2362 typedef MatrixImplType::numeric_block_type block_type;
2363
2364 block_type::const_iterator it = block_type::begin(*node.data);
2365 block_type::const_iterator itEnd = block_type::end(*node.data);
2366 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2367 pos = mrMat.set(pos,aFunc.begin(), aFunc.end());
2368 }
2369 break;
2370 case mdds::mtm::element_boolean:
2371 {
2372 typedef MatrixImplType::boolean_block_type block_type;
2373
2374 block_type::const_iterator it = block_type::begin(*node.data);
2375 block_type::const_iterator itEnd = block_type::end(*node.data);
2376
2377 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2378 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2379 }
2380 break;
2381 case mdds::mtm::element_string:
2382 {
2383 typedef MatrixImplType::string_block_type block_type;
2384
2385 block_type::const_iterator it = block_type::begin(*node.data);
2386 block_type::const_iterator itEnd = block_type::end(*node.data);
2387
2388 MatrixIteratorWrapper<block_type, T, typename T::number_value_type> aFunc(it, itEnd, *mpOp);
2389 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2390 }
2391 break;
2392 case mdds::mtm::element_empty:
2393 {
2394 if (mpOp->useFunctionForEmpty())
2395 {
2396 std::vector<char> aVec(node.size);
2397 MatrixIteratorWrapper<std::vector<char>, T, typename T::number_value_type>
2398 aFunc(aVec.begin(), aVec.end(), *mpOp);
2399 pos = mrMat.set(pos, aFunc.begin(), aFunc.end());
2400 }
2401 }
2402 break;
2403 default:
2404 ;
2405 }
2406 pos = increment_position(pos, node.size);
2407 }
2408};
2409
2410}
2411
2412template<typename T>
2414{
2415 MatrixOpWrapper<T> aFunc(rMat.maMat, aOp);
2416 maMat.walk(aFunc);
2417}
2418
2419template<typename T, typename tRes>
2421{
2422 WalkElementBlocksMultipleValues<T, tRes> aFunc(aOp);
2423 aFunc = maMat.walk(std::move(aFunc));
2424 return aFunc.getResult();
2425}
2426
2427namespace {
2428
2429struct ElementBlock
2430{
2431 ElementBlock(size_t nRowSize,
2432 ScMatrix::DoubleOpFunction aDoubleFunc,
2433 ScMatrix::BoolOpFunction aBoolFunc,
2434 ScMatrix::StringOpFunction aStringFunc,
2435 ScMatrix::EmptyOpFunction aEmptyFunc):
2436 mnRowSize(nRowSize),
2437 mnRowPos(0),
2438 mnColPos(0),
2439 maDoubleFunc(std::move(aDoubleFunc)),
2440 maBoolFunc(std::move(aBoolFunc)),
2441 maStringFunc(std::move(aStringFunc)),
2442 maEmptyFunc(std::move(aEmptyFunc))
2443 {
2444 }
2445
2446 size_t mnRowSize;
2447 size_t mnRowPos;
2448 size_t mnColPos;
2449
2450 ScMatrix::DoubleOpFunction maDoubleFunc;
2451 ScMatrix::BoolOpFunction maBoolFunc;
2452 ScMatrix::StringOpFunction maStringFunc;
2453 ScMatrix::EmptyOpFunction maEmptyFunc;
2454};
2455
2456class WalkElementBlockOperation
2457{
2458public:
2459
2460 WalkElementBlockOperation(ElementBlock& rElementBlock)
2461 : mrElementBlock(rElementBlock)
2462 {
2463 }
2464
2465 void operator()(const MatrixImplType::element_block_node_type& node)
2466 {
2467 switch (node.type)
2468 {
2469 case mdds::mtm::element_numeric:
2470 {
2471 typedef MatrixImplType::numeric_block_type block_type;
2472
2473 block_type::const_iterator it = block_type::begin(*node.data);
2474 std::advance(it, node.offset);
2475 block_type::const_iterator itEnd = it;
2476 std::advance(itEnd, node.size);
2477 for (auto itr = it; itr != itEnd; ++itr)
2478 {
2479 mrElementBlock.maDoubleFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2480 ++mrElementBlock.mnRowPos;
2481 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2482 {
2483 mrElementBlock.mnRowPos = 0;
2484 ++mrElementBlock.mnColPos;
2485 }
2486 }
2487 }
2488 break;
2489 case mdds::mtm::element_string:
2490 {
2491 typedef MatrixImplType::string_block_type block_type;
2492
2493 block_type::const_iterator it = block_type::begin(*node.data);
2494 std::advance(it, node.offset);
2495 block_type::const_iterator itEnd = it;
2496 std::advance(itEnd, node.size);
2497 for (auto itr = it; itr != itEnd; ++itr)
2498 {
2499 mrElementBlock.maStringFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2500 ++mrElementBlock.mnRowPos;
2501 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2502 {
2503 mrElementBlock.mnRowPos = 0;
2504 ++mrElementBlock.mnColPos;
2505 }
2506 }
2507 }
2508 break;
2509 case mdds::mtm::element_boolean:
2510 {
2511 typedef MatrixImplType::boolean_block_type block_type;
2512
2513 block_type::const_iterator it = block_type::begin(*node.data);
2514 std::advance(it, node.offset);
2515 block_type::const_iterator itEnd = it;
2516 std::advance(itEnd, node.size);
2517 for (auto itr = it; itr != itEnd; ++itr)
2518 {
2519 mrElementBlock.maBoolFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos, *itr);
2520 ++mrElementBlock.mnRowPos;
2521 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2522 {
2523 mrElementBlock.mnRowPos = 0;
2524 ++mrElementBlock.mnColPos;
2525 }
2526 }
2527 }
2528 break;
2529 case mdds::mtm::element_empty:
2530 {
2531 for (size_t i=0; i < node.size; ++i)
2532 {
2533 mrElementBlock.maEmptyFunc(mrElementBlock.mnRowPos, mrElementBlock.mnColPos);
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_integer:
2544 {
2545 SAL_WARN("sc.core","WalkElementBlockOperation - unhandled element_integer");
2546 // No function (yet?), but advance row and column count.
2547 mrElementBlock.mnColPos += node.size / mrElementBlock.mnRowSize;
2548 mrElementBlock.mnRowPos += node.size % mrElementBlock.mnRowSize;
2549 if (mrElementBlock.mnRowPos >= mrElementBlock.mnRowSize)
2550 {
2551 mrElementBlock.mnRowPos = 0;
2552 ++mrElementBlock.mnColPos;
2553 }
2554 }
2555 break;
2556 }
2557 }
2558
2559private:
2560
2561 ElementBlock& mrElementBlock;
2562};
2563
2564}
2565
2566void ScMatrixImpl::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
2567 const std::pair<size_t, size_t>& rEndPos, const ScMatrix::DoubleOpFunction& aDoubleFunc,
2568 const ScMatrix::BoolOpFunction& aBoolFunc, const ScMatrix::StringOpFunction& aStringFunc,
2569 const ScMatrix::EmptyOpFunction& aEmptyFunc) const
2570{
2571 ElementBlock aPayload(maMat.size().row, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2572 WalkElementBlockOperation aFunc(aPayload);
2573 maMat.walk(
2574 aFunc,
2575 MatrixImplType::size_pair_type(rStartPos.first, rStartPos.second),
2576 MatrixImplType::size_pair_type(rEndPos.first, rEndPos.second));
2577}
2578
2579#if DEBUG_MATRIX
2580
2581void ScMatrixImpl::Dump() const
2582{
2583 cout << "-- matrix content" << endl;
2584 SCSIZE nCols, nRows;
2585 GetDimensions(nCols, nRows);
2586 for (SCSIZE nRow = 0; nRow < nRows; ++nRow)
2587 {
2588 for (SCSIZE nCol = 0; nCol < nCols; ++nCol)
2589 {
2590 cout << " row=" << nRow << ", col=" << nCol << " : ";
2591 switch (maMat.get_type(nRow, nCol))
2592 {
2593 case mdds::mtm::element_string:
2594 cout << "string (" << maMat.get_string(nRow, nCol).getString() << ")";
2595 break;
2596 case mdds::mtm::element_numeric:
2597 cout << "numeric (" << maMat.get_numeric(nRow, nCol) << ")";
2598 break;
2599 case mdds::mtm::element_boolean:
2600 cout << "boolean (" << maMat.get_boolean(nRow, nCol) << ")";
2601 break;
2602 case mdds::mtm::element_empty:
2603 cout << "empty";
2604 break;
2605 default:
2606 ;
2607 }
2608
2609 cout << endl;
2610 }
2611 }
2612}
2613#endif
2614
2616{
2617 SCSIZE nRowSize = maMat.size().row;
2618 SAL_WARN_IF( !nRowSize, "sc.core", "ScMatrixImpl::CalcPosition: 0 rows!");
2619 rC = nRowSize > 1 ? nIndex / nRowSize : nIndex;
2620 rR = nIndex - rC*nRowSize;
2621}
2622
2623namespace {
2624
2625size_t get_index(SCSIZE nMaxRow, size_t nRow, size_t nCol, size_t nRowOffset, size_t nColOffset)
2626{
2627 return nMaxRow * (nCol + nColOffset) + nRow + nRowOffset;
2628}
2629
2630}
2631
2632void ScMatrixImpl::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef& xMat1, const ScMatrixRef& xMat2,
2633 SvNumberFormatter& rFormatter, svl::SharedStringPool& rStringPool)
2634{
2635 SCSIZE nC1, nC2;
2636 SCSIZE nR1, nR2;
2637 xMat1->GetDimensions(nC1, nR1);
2638 xMat2->GetDimensions(nC2, nR2);
2639
2640 sal_uInt32 nKey = rFormatter.GetStandardFormat( SvNumFormatType::NUMBER,
2642
2643 std::vector<OUString> aString(nMaxCol * nMaxRow);
2644 std::vector<bool> aValid(nMaxCol * nMaxRow, true);
2645 std::vector<FormulaError> nErrors(nMaxCol * nMaxRow,FormulaError::NONE);
2646
2647 size_t nRowOffset = 0;
2648 size_t nColOffset = 0;
2649 std::function<void(size_t, size_t, double)> aDoubleFunc =
2650 [&](size_t nRow, size_t nCol, double nVal)
2651 {
2652 FormulaError nErr = GetDoubleErrorValue(nVal);
2653 if (nErr != FormulaError::NONE)
2654 {
2655 aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2656 nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2657 return;
2658 }
2659 OUString aStr;
2660 rFormatter.GetInputLineString( nVal, nKey, aStr);
2661 aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2662 };
2663
2664 std::function<void(size_t, size_t, bool)> aBoolFunc =
2665 [&](size_t nRow, size_t nCol, bool nVal)
2666 {
2667 OUString aStr;
2668 rFormatter.GetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2669 aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr;
2670 };
2671
2672 std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc =
2673 [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2674 {
2675 aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString();
2676 };
2677
2678 std::function<void(size_t, size_t)> aEmptyFunc =
2679 [](size_t /*nRow*/, size_t /*nCol*/)
2680 {
2681 // Nothing. Concatenating an empty string to an existing string.
2682 };
2683
2684
2685 if (nC1 == 1 || nR1 == 1)
2686 {
2687 size_t nRowRep = nR1 == 1 ? nMaxRow : 1;
2688 size_t nColRep = nC1 == 1 ? nMaxCol : 1;
2689
2690 for (size_t i = 0; i < nRowRep; ++i)
2691 {
2692 nRowOffset = i;
2693 for (size_t j = 0; j < nColRep; ++j)
2694 {
2695 nColOffset = j;
2696 xMat1->ExecuteOperation(
2697 std::pair<size_t, size_t>(0, 0),
2698 std::pair<size_t, size_t>(std::min(nR1, nMaxRow) - 1, std::min(nC1, nMaxCol) - 1),
2699 aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
2700 }
2701 }
2702 }
2703 else
2704 xMat1->ExecuteOperation(
2705 std::pair<size_t, size_t>(0, 0),
2706 std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2707 std::move(aDoubleFunc), std::move(aBoolFunc), std::move(aStringFunc), std::move(aEmptyFunc));
2708
2709 std::vector<svl::SharedString> aSharedString(nMaxCol*nMaxRow);
2710
2711 std::function<void(size_t, size_t, double)> aDoubleFunc2 =
2712 [&](size_t nRow, size_t nCol, double nVal)
2713 {
2714 FormulaError nErr = GetDoubleErrorValue(nVal);
2715 if (nErr != FormulaError::NONE)
2716 {
2717 aValid[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = false;
2718 nErrors[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = nErr;
2719 return;
2720 }
2721 OUString aStr;
2722 rFormatter.GetInputLineString( nVal, nKey, aStr);
2723 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2724 };
2725
2726 std::function<void(size_t, size_t, bool)> aBoolFunc2 =
2727 [&](size_t nRow, size_t nCol, bool nVal)
2728 {
2729 OUString aStr;
2730 rFormatter.GetInputLineString( nVal ? 1.0 : 0.0, nKey, aStr);
2731 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] = rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr);
2732 };
2733
2734 std::function<void(size_t, size_t, const svl::SharedString&)> aStringFunc2 =
2735 [&](size_t nRow, size_t nCol, const svl::SharedString& aStr)
2736 {
2737 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2738 rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] + aStr.getString());
2739 };
2740
2741 std::function<void(size_t, size_t)> aEmptyFunc2 =
2742 [&](size_t nRow, size_t nCol)
2743 {
2744 aSharedString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)] =
2745 rStringPool.intern(aString[get_index(nMaxRow, nRow, nCol, nRowOffset, nColOffset)]);
2746 };
2747
2748 nRowOffset = 0;
2749 nColOffset = 0;
2750 if (nC2 == 1 || nR2 == 1)
2751 {
2752 size_t nRowRep = nR2 == 1 ? nMaxRow : 1;
2753 size_t nColRep = nC2 == 1 ? nMaxCol : 1;
2754
2755 for (size_t i = 0; i < nRowRep; ++i)
2756 {
2757 nRowOffset = i;
2758 for (size_t j = 0; j < nColRep; ++j)
2759 {
2760 nColOffset = j;
2761 xMat2->ExecuteOperation(
2762 std::pair<size_t, size_t>(0, 0),
2763 std::pair<size_t, size_t>(std::min(nR2, nMaxRow) - 1, std::min(nC2, nMaxCol) - 1),
2764 aDoubleFunc2, aBoolFunc2, aStringFunc2, aEmptyFunc2);
2765 }
2766 }
2767 }
2768 else
2769 xMat2->ExecuteOperation(
2770 std::pair<size_t, size_t>(0, 0),
2771 std::pair<size_t, size_t>(nMaxRow - 1, nMaxCol - 1),
2772 std::move(aDoubleFunc2), std::move(aBoolFunc2), std::move(aStringFunc2), std::move(aEmptyFunc2));
2773
2774 aString.clear();
2775
2776 MatrixImplType::position_type pos = maMat.position(0, 0);
2777 for (SCSIZE i = 0; i < nMaxCol; ++i)
2778 {
2779 for (SCSIZE j = 0; j < nMaxRow && i < nMaxCol; ++j)
2780 {
2781 if (aValid[nMaxRow * i + j])
2782 {
2783 auto itr = aValid.begin();
2784 std::advance(itr, nMaxRow * i + j);
2785 auto itrEnd = std::find(itr, aValid.end(), false);
2786 size_t nSteps = std::distance(itr, itrEnd);
2787 auto itrStr = aSharedString.begin();
2788 std::advance(itrStr, nMaxRow * i + j);
2789 auto itrEndStr = itrStr;
2790 std::advance(itrEndStr, nSteps);
2791 pos = maMat.set(pos, itrStr, itrEndStr);
2792 size_t nColSteps = nSteps / nMaxRow;
2793 i += nColSteps;
2794 j += nSteps % nMaxRow;
2795 if (j >= nMaxRow)
2796 {
2797 j -= nMaxRow;
2798 ++i;
2799 }
2800 }
2801 else
2802 {
2803 pos = maMat.set(pos, CreateDoubleError(nErrors[nMaxRow * i + j]));
2804 }
2805 pos = MatrixImplType::next_position(pos);
2806 }
2807 }
2808}
2809
2810bool ScMatrixImpl::IsValueOrEmpty( const MatrixImplType::const_position_type & rPos ) const
2811{
2812 switch (maMat.get_type(rPos))
2813 {
2814 case mdds::mtm::element_boolean:
2815 case mdds::mtm::element_numeric:
2816 case mdds::mtm::element_empty:
2817 return true;
2818 default:
2819 ;
2820 }
2821 return false;
2822}
2823
2824double ScMatrixImpl::GetDouble(const MatrixImplType::const_position_type & rPos) const
2825{
2826 double fVal = maMat.get_numeric(rPos);
2827 if ( pErrorInterpreter )
2828 {
2829 FormulaError nError = GetDoubleErrorValue(fVal);
2830 if ( nError != FormulaError::NONE )
2831 SetErrorAtInterpreter( nError);
2832 }
2833 return fVal;
2834}
2835
2836FormulaError ScMatrixImpl::GetErrorIfNotString( const MatrixImplType::const_position_type & rPos ) const
2837{ return IsValue(rPos) ? GetError(rPos) : FormulaError::NONE; }
2838
2839bool ScMatrixImpl::IsValue( const MatrixImplType::const_position_type & rPos ) const
2840{
2841 switch (maMat.get_type(rPos))
2842 {
2843 case mdds::mtm::element_boolean:
2844 case mdds::mtm::element_numeric:
2845 return true;
2846 default:
2847 ;
2848 }
2849 return false;
2850}
2851
2852FormulaError ScMatrixImpl::GetError(const MatrixImplType::const_position_type & rPos) const
2853{
2854 double fVal = maMat.get_numeric(rPos);
2855 return GetDoubleErrorValue(fVal);
2856}
2857
2858bool ScMatrixImpl::IsStringOrEmpty(const MatrixImplType::const_position_type & rPos) const
2859{
2860 switch (maMat.get_type(rPos))
2861 {
2862 case mdds::mtm::element_empty:
2863 case mdds::mtm::element_string:
2864 return true;
2865 default:
2866 ;
2867 }
2868 return false;
2869}
2870
2871void ScMatrixImpl::ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
2873{
2874 // Check output matrix size, otherwise output iterator logic will be wrong.
2875 assert(maMat.size().row == nMaxRow && maMat.size().column == nMaxCol
2876 && "the caller code should have sized the output matrix to the passed dimensions");
2877 auto & rMatImpl1 = *rInputMat1.pImpl;
2878 auto & rMatImpl2 = *rInputMat2.pImpl;
2879 // Check if we can do fast-path, where we have no replication or mis-matched matrix sizes.
2880 if (rMatImpl1.maMat.size() == rMatImpl2.maMat.size()
2881 && rMatImpl1.maMat.size() == maMat.size())
2882 {
2883 MatrixImplType::position_type aOutPos = maMat.position(0, 0);
2884 MatrixImplType::const_position_type aPos1 = rMatImpl1.maMat.position(0, 0);
2885 MatrixImplType::const_position_type aPos2 = rMatImpl2.maMat.position(0, 0);
2886 for (SCSIZE i = 0; i < nMaxCol; i++)
2887 {
2888 for (SCSIZE j = 0; j < nMaxRow; j++)
2889 {
2890 bool bVal1 = rMatImpl1.IsValueOrEmpty(aPos1);
2891 bool bVal2 = rMatImpl2.IsValueOrEmpty(aPos2);
2892 FormulaError nErr;
2893 if (bVal1 && bVal2)
2894 {
2895 double d = Op(rMatImpl1.GetDouble(aPos1), rMatImpl2.GetDouble(aPos2));
2896 aOutPos = maMat.set(aOutPos, d);
2897 }
2898 else if (((nErr = rMatImpl1.GetErrorIfNotString(aPos1)) != FormulaError::NONE) ||
2899 ((nErr = rMatImpl2.GetErrorIfNotString(aPos2)) != FormulaError::NONE))
2900 {
2901 aOutPos = maMat.set(aOutPos, CreateDoubleError(nErr));
2902 }
2903 else if ((!bVal1 && rMatImpl1.IsStringOrEmpty(aPos1)) ||
2904 (!bVal2 && rMatImpl2.IsStringOrEmpty(aPos2)))
2905 {
2906 FormulaError nError1 = FormulaError::NONE;
2907 SvNumFormatType nFmt1 = SvNumFormatType::ALL;
2908 double fVal1 = (bVal1 ? rMatImpl1.GetDouble(aPos1) :
2909 pInterpreter->ConvertStringToValue( rMatImpl1.GetString(aPos1).getString(), nError1, nFmt1));
2910
2911 FormulaError nError2 = FormulaError::NONE;
2912 SvNumFormatType nFmt2 = SvNumFormatType::ALL;
2913 double fVal2 = (bVal2 ? rMatImpl2.GetDouble(aPos2) :
2914 pInterpreter->ConvertStringToValue( rMatImpl2.GetString(aPos2).getString(), nError2, nFmt2));
2915
2916 if (nError1 != FormulaError::NONE)
2917 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError1));
2918 else if (nError2 != FormulaError::NONE)
2919 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError2));
2920 else
2921 {
2922 double d = Op( fVal1, fVal2);
2923 aOutPos = maMat.set(aOutPos, d);
2924 }
2925 }
2926 else
2927 aOutPos = maMat.set(aOutPos, CreateDoubleError(FormulaError::NoValue));
2928 aPos1 = MatrixImplType::next_position(aPos1);
2929 aPos2 = MatrixImplType::next_position(aPos2);
2930 aOutPos = MatrixImplType::next_position(aOutPos);
2931 }
2932 }
2933 }
2934 else
2935 {
2936 // Noting that this block is very hard to optimise to use iterators, because various dodgy
2937 // array function usage relies on the semantics of some of the methods we call here.
2938 // (see unit test testDubiousArrayFormulasFODS).
2939 // These methods are inconsistent in their usage of ValidColRowReplicated() vs. ValidColRowOrReplicated()
2940 // which leads to some very odd results.
2941 MatrixImplType::position_type aOutPos = maMat.position(0, 0);
2942 for (SCSIZE i = 0; i < nMaxCol; i++)
2943 {
2944 for (SCSIZE j = 0; j < nMaxRow; j++)
2945 {
2946 bool bVal1 = rInputMat1.IsValueOrEmpty(i,j);
2947 bool bVal2 = rInputMat2.IsValueOrEmpty(i,j);
2948 FormulaError nErr;
2949 if (bVal1 && bVal2)
2950 {
2951 double d = Op(rInputMat1.GetDouble(i,j), rInputMat2.GetDouble(i,j));
2952 aOutPos = maMat.set(aOutPos, d);
2953 }
2954 else if (((nErr = rInputMat1.GetErrorIfNotString(i,j)) != FormulaError::NONE) ||
2955 ((nErr = rInputMat2.GetErrorIfNotString(i,j)) != FormulaError::NONE))
2956 {
2957 aOutPos = maMat.set(aOutPos, CreateDoubleError(nErr));
2958 }
2959 else if ((!bVal1 && rInputMat1.IsStringOrEmpty(i,j)) || (!bVal2 && rInputMat2.IsStringOrEmpty(i,j)))
2960 {
2961 FormulaError nError1 = FormulaError::NONE;
2962 SvNumFormatType nFmt1 = SvNumFormatType::ALL;
2963 double fVal1 = (bVal1 ? rInputMat1.GetDouble(i,j) :
2964 pInterpreter->ConvertStringToValue( rInputMat1.GetString(i,j).getString(), nError1, nFmt1));
2965
2966 FormulaError nError2 = FormulaError::NONE;
2967 SvNumFormatType nFmt2 = SvNumFormatType::ALL;
2968 double fVal2 = (bVal2 ? rInputMat2.GetDouble(i,j) :
2969 pInterpreter->ConvertStringToValue( rInputMat2.GetString(i,j).getString(), nError2, nFmt2));
2970
2971 if (nError1 != FormulaError::NONE)
2972 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError1));
2973 else if (nError2 != FormulaError::NONE)
2974 aOutPos = maMat.set(aOutPos, CreateDoubleError(nError2));
2975 else
2976 {
2977 double d = Op( fVal1, fVal2);
2978 aOutPos = maMat.set(aOutPos, d);
2979 }
2980 }
2981 else
2982 aOutPos = maMat.set(aOutPos, CreateDoubleError(FormulaError::NoValue));
2983 aOutPos = MatrixImplType::next_position(aOutPos);
2984 }
2985 }
2986 }
2987}
2988
2990{
2991 ++nRefCnt;
2992}
2993
2995{
2996 --nRefCnt;
2997 if (nRefCnt == 0)
2998 delete this;
2999}
3000
3002{
3003 SAL_WARN_IF( !nC, "sc.core", "ScMatrix with 0 columns!");
3004 SAL_WARN_IF( !nR, "sc.core", "ScMatrix with 0 rows!");
3005 // 0-size matrix is valid, it could be resized later.
3006 if ((nC && !nR) || (!nC && nR))
3007 {
3008 SAL_WARN( "sc.core", "ScMatrix one-dimensional zero: " << nC << " columns * " << nR << " rows");
3009 return false;
3010 }
3011 if (!nC || !nR)
3012 return true;
3013
3014 std::call_once(bElementsMaxFetched,
3015 []()
3016 {
3017 const char* pEnv = std::getenv("SC_MAX_MATRIX_ELEMENTS");
3018 if (pEnv)
3019 {
3020 // Environment specifies the overall elements pool.
3021 nElementsMax = std::atoi(pEnv);
3022 }
3023 else
3024 {
3025 // GetElementsMax() uses an (~arbitrary) elements limit.
3026 // The actual allocation depends on the types of individual matrix
3027 // elements and is averaged for type double.
3028#if SAL_TYPES_SIZEOFPOINTER < 8
3029 // Assume 1GB memory could be consumed by matrices.
3030 constexpr size_t nMemMax = 0x40000000;
3031#else
3032 // Assume 6GB memory could be consumed by matrices.
3033 constexpr size_t nMemMax = 0x180000000;
3034#endif
3035 nElementsMax = GetElementsMax( nMemMax);
3036 }
3037 });
3038
3039 if (nC > (nElementsMax / nR))
3040 {
3041 SAL_WARN( "sc.core", "ScMatrix overflow: " << nC << " columns * " << nR << " rows");
3042 return false;
3043 }
3044 return true;
3045}
3046
3048 nRefCnt(0), mbCloneIfConst(true)
3049{
3050 if (ScMatrix::IsSizeAllocatable( nC, nR))
3051 pImpl.reset( new ScMatrixImpl( nC, nR));
3052 else
3053 // Invalid matrix size, allocate 1x1 matrix with error value.
3054 pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
3055}
3056
3057ScMatrix::ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal) :
3058 nRefCnt(0), mbCloneIfConst(true)
3059{
3060 if (ScMatrix::IsSizeAllocatable( nC, nR))
3061 pImpl.reset( new ScMatrixImpl( nC, nR, fInitVal));
3062 else
3063 // Invalid matrix size, allocate 1x1 matrix with error value.
3064 pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
3065}
3066
3067ScMatrix::ScMatrix( size_t nC, size_t nR, const std::vector<double>& rInitVals ) :
3068 nRefCnt(0), mbCloneIfConst(true)
3069{
3070 if (ScMatrix::IsSizeAllocatable( nC, nR))
3071 pImpl.reset( new ScMatrixImpl( nC, nR, rInitVals));
3072 else
3073 // Invalid matrix size, allocate 1x1 matrix with error value.
3074 pImpl.reset( new ScMatrixImpl( 1,1, CreateDoubleError( FormulaError::MatrixSize)));
3075}
3076
3078{
3079}
3080
3082{
3083 SCSIZE nC, nR;
3084 pImpl->GetDimensions(nC, nR);
3085 ScMatrix* pScMat = new ScMatrix(nC, nR);
3086 MatCopy(*pScMat);
3087 pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter()); // TODO: really?
3088 return pScMat;
3089}
3090
3092{
3093 return mbCloneIfConst ? Clone() : this;
3094}
3095
3097{
3098 mbCloneIfConst = false;
3099}
3100
3102{
3103 mbCloneIfConst = true;
3104}
3105
3107{
3108 pImpl->Resize(nC, nR);
3109}
3110
3111void ScMatrix::Resize(SCSIZE nC, SCSIZE nR, double fVal)
3112{
3113 pImpl->Resize(nC, nR, fVal);
3114}
3115
3117{
3118 ScMatrix* pScMat = new ScMatrix(nNewCols, nNewRows);
3119 MatCopy(*pScMat);
3120 pScMat->SetErrorInterpreter(pImpl->GetErrorInterpreter());
3121 return pScMat;
3122}
3123
3125{
3126 pImpl->SetErrorInterpreter(p);
3127}
3128
3130{
3131 pImpl->GetDimensions(rC, rR);
3132}
3133
3135{
3136 return pImpl->GetElementCount();
3137}
3138
3140{
3141 return pImpl->ValidColRow(nC, nR);
3142}
3143
3145{
3146 return pImpl->ValidColRowReplicated(rC, rR);
3147}
3148
3150{
3151 return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
3152}
3153
3154void ScMatrix::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
3155{
3156 pImpl->PutDouble(fVal, nC, nR);
3157}
3158
3159void ScMatrix::PutDouble( double fVal, SCSIZE nIndex)
3160{
3161 pImpl->PutDouble(fVal, nIndex);
3162}
3163
3164void ScMatrix::PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3165{
3166 pImpl->PutDouble(pArray, nLen, nC, nR);
3167}
3168
3170{
3171 pImpl->PutString(rStr, nC, nR);
3172}
3173
3175{
3176 pImpl->PutString(rStr, nIndex);
3177}
3178
3179void ScMatrix::PutString(const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR)
3180{
3181 pImpl->PutString(pArray, nLen, nC, nR);
3182}
3183
3185{
3186 pImpl->PutEmpty(nC, nR);
3187}
3188
3190{
3191 pImpl->PutEmptyPath(nC, nR);
3192}
3193
3195{
3196 pImpl->PutError(nErrorCode, nC, nR);
3197}
3198
3199void ScMatrix::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
3200{
3201 pImpl->PutBoolean(bVal, nC, nR);
3202}
3203
3205{
3206 return pImpl->GetError(nC, nR);
3207}
3208
3210{
3211 return pImpl->GetDouble(nC, nR);
3212}
3213
3214double ScMatrix::GetDouble( SCSIZE nIndex) const
3215{
3216 return pImpl->GetDouble(nIndex);
3217}
3218
3220{
3221 return pImpl->GetDoubleWithStringConversion(nC, nR);
3222}
3223
3225{
3226 return pImpl->GetString(nC, nR);
3227}
3228
3230{
3231 return pImpl->GetString(nIndex);
3232}
3233
3235{
3236 return pImpl->GetString(rFormatter, nC, nR);
3237}
3238
3240{
3241 return pImpl->Get(nC, nR);
3242}
3243
3245{
3246 return pImpl->IsStringOrEmpty(nIndex);
3247}
3248
3250{
3251 return pImpl->IsStringOrEmpty(nC, nR);
3252}
3253
3254bool ScMatrix::IsEmpty( SCSIZE nC, SCSIZE nR ) const
3255{
3256 return pImpl->IsEmpty(nC, nR);
3257}
3258
3260{
3261 return pImpl->IsEmptyCell(nC, nR);
3262}
3263
3265{
3266 return pImpl->IsEmptyResult(nC, nR);
3267}
3268
3270{
3271 return pImpl->IsEmptyPath(nC, nR);
3272}
3273
3274bool ScMatrix::IsValue( SCSIZE nIndex ) const
3275{
3276 return pImpl->IsValue(nIndex);
3277}
3278
3279bool ScMatrix::IsValue( SCSIZE nC, SCSIZE nR ) const
3280{
3281 return pImpl->IsValue(nC, nR);
3282}
3283
3285{
3286 return pImpl->IsValueOrEmpty(nC, nR);
3287}
3288
3290{
3291 return pImpl->IsBoolean(nC, nR);
3292}
3293
3295{
3296 return pImpl->IsNumeric();
3297}
3298
3299void ScMatrix::MatCopy(const ScMatrix& mRes) const
3300{
3301 pImpl->MatCopy(*mRes.pImpl);
3302}
3303
3304void ScMatrix::MatTrans(const ScMatrix& mRes) const
3305{
3306 pImpl->MatTrans(*mRes.pImpl);
3307}
3308
3309void ScMatrix::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
3310{
3311 pImpl->FillDouble(fVal, nC1, nR1, nC2, nR2);
3312}
3313
3314void ScMatrix::PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR )
3315{
3316 pImpl->PutDoubleVector(rVec, nC, nR);
3317}
3318
3319void ScMatrix::PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR )
3320{
3321 pImpl->PutStringVector(rVec, nC, nR);
3322}
3323
3325{
3326 pImpl->PutEmptyVector(nCount, nC, nR);
3327}
3328
3330{
3331 pImpl->PutEmptyResultVector(nCount, nC, nR);
3332}
3333
3335{
3336 pImpl->PutEmptyPathVector(nCount, nC, nR);
3337}
3338
3340{
3341 pImpl->CompareEqual();
3342}
3343
3345{
3346 pImpl->CompareNotEqual();
3347}
3348
3350{
3351 pImpl->CompareLess();
3352}
3353
3355{
3356 pImpl->CompareGreater();
3357}
3358
3360{
3361 pImpl->CompareLessEqual();
3362}
3363
3365{
3366 pImpl->CompareGreaterEqual();
3367}
3368
3369double ScMatrix::And() const
3370{
3371 return pImpl->And();
3372}
3373
3374double ScMatrix::Or() const
3375{
3376 return pImpl->Or();
3377}
3378
3379double ScMatrix::Xor() const
3380{
3381 return pImpl->Xor();
3382}
3383
3384ScMatrix::KahanIterateResult ScMatrix::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
3385{
3386 return pImpl->Sum(bTextAsZero, bIgnoreErrorValues);
3387}
3388
3389ScMatrix::KahanIterateResult ScMatrix::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
3390{
3391 return pImpl->SumSquare(bTextAsZero, bIgnoreErrorValues);
3392}
3393
3394ScMatrix::DoubleIterateResult ScMatrix::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
3395{
3396 return pImpl->Product(bTextAsZero, bIgnoreErrorValues);
3397}
3398
3399size_t ScMatrix::Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const
3400{
3401 return pImpl->Count(bCountStrings, bCountErrors, bIgnoreEmptyStrings);
3402}
3403
3404size_t ScMatrix::MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
3405{
3406 return pImpl->MatchDoubleInColumns(fValue, nCol1, nCol2);
3407}
3408
3409size_t ScMatrix::MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const
3410{
3411 return pImpl->MatchStringInColumns(rStr, nCol1, nCol2);
3412}
3413
3414double ScMatrix::GetMaxValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3415{
3416 return pImpl->GetMaxValue(bTextAsZero, bIgnoreErrorValues);
3417}
3418
3419double ScMatrix::GetMinValue( bool bTextAsZero, bool bIgnoreErrorValues ) const
3420{
3421 return pImpl->GetMinValue(bTextAsZero, bIgnoreErrorValues);
3422}
3423
3424double ScMatrix::GetGcd() const
3425{
3426 return pImpl->GetGcd();
3427}
3428
3429double ScMatrix::GetLcm() const
3430{
3431 return pImpl->GetLcm();
3432}
3433
3434
3436 sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions ) const
3437{
3438 return pImpl->CompareMatrix(rComp, nMatPos, pOptions);
3439}
3440
3441void ScMatrix::GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero ) const
3442{
3443 pImpl->GetDoubleArray(rArray, bEmptyAsZero);
3444}
3445
3446void ScMatrix::MergeDoubleArrayMultiply( std::vector<double>& rArray ) const
3447{
3448 pImpl->MergeDoubleArrayMultiply(rArray);
3449}
3450
3451namespace matop {
3452
3453namespace {
3454
3462template<typename TOp>
3463struct MatOp
3464{
3465private:
3466 TOp maOp;
3468 double mfVal;
3469
3470public:
3471 typedef double number_value_type;
3472
3473 MatOp( TOp aOp, ScInterpreter* pErrorInterpreter,
3474 double fVal = 0.0 ):
3475 maOp(aOp),
3476 mpErrorInterpreter(pErrorInterpreter),
3477 mfVal(fVal)
3478 {
3480 {
3482 if (nErr != FormulaError::NONE)
3483 mfVal = CreateDoubleError( nErr);
3484 }
3485 }
3486
3487 double operator()(double fVal) const
3488 {
3489 return maOp(fVal, mfVal);
3490 }
3491
3492 double operator()(bool bVal) const
3493 {
3494 return maOp(static_cast<double>(bVal), mfVal);
3495 }
3496
3497 double operator()(const svl::SharedString& rStr) const
3498 {
3499 return maOp( convertStringToValue( mpErrorInterpreter, rStr.getString()), mfVal);
3500 }
3501
3503 double operator()(char) const
3504 {
3505 return maOp(0, mfVal);
3506 }
3507
3508 static bool useFunctionForEmpty()
3509 {
3510 return true;
3511 }
3512};
3513
3514}
3515
3516}
3517
3518void ScMatrix::NotOp( const ScMatrix& rMat)
3519{
3520 auto not_ = [](double a, double){return double(a == 0.0);};
3521 matop::MatOp<decltype(not_)> aOp(not_, pImpl->GetErrorInterpreter());
3522 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3523}
3524
3525void ScMatrix::NegOp( const ScMatrix& rMat)
3526{
3527 auto neg_ = [](double a, double){return -a;};
3528 matop::MatOp<decltype(neg_)> aOp(neg_, pImpl->GetErrorInterpreter());
3529 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3530}
3531
3532void ScMatrix::AddOp( double fVal, const ScMatrix& rMat)
3533{
3534 auto add_ = [](double a, double b){return a + b;};
3535 matop::MatOp<decltype(add_)> aOp(add_, pImpl->GetErrorInterpreter(), fVal);
3536 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3537}
3538
3539void ScMatrix::SubOp( bool bFlag, double fVal, const ScMatrix& rMat)
3540{
3541 if (bFlag)
3542 {
3543 auto sub_ = [](double a, double b){return b - a;};
3544 matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3545 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3546 }
3547 else
3548 {
3549 auto sub_ = [](double a, double b){return a - b;};
3550 matop::MatOp<decltype(sub_)> aOp(sub_, pImpl->GetErrorInterpreter(), fVal);
3551 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3552 }
3553}
3554
3555void ScMatrix::MulOp( double fVal, const ScMatrix& rMat)
3556{
3557 auto mul_ = [](double a, double b){return a * b;};
3558 matop::MatOp<decltype(mul_)> aOp(mul_, pImpl->GetErrorInterpreter(), fVal);
3559 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3560}
3561
3562void ScMatrix::DivOp( bool bFlag, double fVal, const ScMatrix& rMat)
3563{
3564 if (bFlag)
3565 {
3566 auto div_ = [](double a, double b){return sc::div(b, a);};
3567 matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3568 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3569 }
3570 else
3571 {
3572 auto div_ = [](double a, double b){return sc::div(a, b);};
3573 matop::MatOp<decltype(div_)> aOp(div_, pImpl->GetErrorInterpreter(), fVal);
3574 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3575 }
3576}
3577
3578void ScMatrix::PowOp( bool bFlag, double fVal, const ScMatrix& rMat)
3579{
3580 if (bFlag)
3581 {
3582 auto pow_ = [](double a, double b){return sc::power(b, a);};
3583 matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3584 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3585 }
3586 else
3587 {
3588 auto pow_ = [](double a, double b){return sc::power(a, b);};
3589 matop::MatOp<decltype(pow_)> aOp(pow_, pImpl->GetErrorInterpreter(), fVal);
3590 pImpl->ApplyOperation(aOp, *rMat.pImpl);
3591 }
3592}
3593
3594void ScMatrix::ExecuteOperation(const std::pair<size_t, size_t>& rStartPos,
3595 const std::pair<size_t, size_t>& rEndPos, DoubleOpFunction aDoubleFunc,
3596 BoolOpFunction aBoolFunc, StringOpFunction aStringFunc, EmptyOpFunction aEmptyFunc) const
3597{
3598 pImpl->ExecuteOperation(rStartPos, rEndPos, aDoubleFunc, aBoolFunc, aStringFunc, aEmptyFunc);
3599}
3600
3602{
3603 return pImpl->ApplyCollectOperation<sc::op::kOp, KahanSum>(aOp);
3604}
3605
3606#if DEBUG_MATRIX
3607void ScMatrix::Dump() const
3608{
3609 pImpl->Dump();
3610}
3611#endif
3612
3613void ScMatrix::MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow,
3614 const ScMatrixRef& xMat1, const ScMatrixRef& xMat2, SvNumberFormatter& rFormatter, svl::SharedStringPool& rPool)
3615{
3616 pImpl->MatConcat(nMaxCol, nMaxRow, xMat1, xMat2, rFormatter, rPool);
3617}
3618
3619void ScMatrix::ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix& rInputMat1, const ScMatrix& rInputMat2,
3620 ScInterpreter* pInterpreter, CalculateOpFunction op)
3621{
3622 pImpl->ExecuteBinaryOp(nMaxCol, nMaxRow, rInputMat1, rInputMat2, pInterpreter, op);
3623}
3624/* 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:559
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:93
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:2109
void PutEmptyVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:960
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:844
double GetMinValue(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2130
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:1012
double GetMaxValue(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2123
FormulaError GetError(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:608
double GetGcd() const
Definition: scmatrix.cxx:2137
double Or() const
Definition: scmatrix.cxx:1115
ScMatrix::IterateResultMultiple< tRes > ApplyCollectOperation(const std::vector< T > &aOp)
Definition: scmatrix.cxx:2420
void FillDouble(double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2)
Definition: scmatrix.cxx:919
ScMatrix::KahanIterateResult SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2092
void GetDoubleArray(std::vector< double > &rArray, bool bEmptyAsZero) const
Definition: scmatrix.cxx:2188
ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:747
void Clear()
Definition: scmatrix.cxx:414
void CompareGreaterEqual()
Definition: scmatrix.cxx:1044
bool IsEmptyResult(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:835
ScInterpreter * pErrorInterpreter
Definition: scmatrix.cxx:235
void MatCopy(ScMatrixImpl &mRes) const
Definition: scmatrix.cxx:901
void SetErrorInterpreter(ScInterpreter *p)
Definition: scmatrix.cxx:454
ScMatrix::KahanIterateResult Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2087
bool IsValueOrEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:875
ScMatrix::DoubleIterateResult Product(bool bTextAsZero, bool bIgnoreErrorValues) const
Definition: scmatrix.cxx:2097
void CompareGreater()
Definition: scmatrix.cxx:1028
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:2566
void CalcPosition(SCSIZE nIndex, SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2615
size_t MatchStringInColumns(const svl::SharedString &rStr, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:2116
void PutStringVector(const ::std::vector< svl::SharedString > &rVec, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:948
void ExecuteBinaryOp(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrix &rInputMat1, const ScMatrix &rInputMat2, ScInterpreter *pInterpreter, ScMatrix::CalculateOpFunction op)
Definition: scmatrix.cxx:2871
void CompareEqual()
Definition: scmatrix.cxx:1004
FormulaError GetErrorIfNotString(const MatrixImplType::const_position_type &rPos) const
Definition: scmatrix.cxx:2836
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:2151
MatrixFlagImplType maMatFlag
Definition: scmatrix.cxx:234
void PutDoubleVector(const ::std::vector< double > &rVec, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:936
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:890
double And() const
Definition: scmatrix.cxx:1108
bool ValidColRowReplicated(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:478
double GetLcm() const
Definition: scmatrix.cxx:2144
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:854
bool ValidColRowOrReplicated(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:502
bool IsEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:817
void PutEmptyPathVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:989
bool IsEmptyCell(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:826
bool IsNumeric() const
Definition: scmatrix.cxx:896
void PutString(const svl::SharedString &rStr, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:540
void MatTrans(ScMatrixImpl &mRes) const
Definition: scmatrix.cxx:913
void ApplyOperation(T aOp, ScMatrixImpl &rMat)
Definition: scmatrix.cxx:2413
ScInterpreter * GetErrorInterpreter() const
Definition: scmatrix.cxx:252
void MergeDoubleArrayMultiply(std::vector< double > &rArray) const
Definition: scmatrix.cxx:2196
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:1036
void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef &xMat1, const ScMatrixRef &xMat2, SvNumberFormatter &rFormatter, svl::SharedStringPool &rPool)
Definition: scmatrix.cxx:2632
void SetErrorAtInterpreter(FormulaError nError) const
Definition: scmatrix.cxx:507
double Xor() const
Definition: scmatrix.cxx:1122
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:974
void CompareLess()
Definition: scmatrix.cxx:1020
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:2102
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:3199
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:3239
void CompareLess()
Definition: scmatrix.cxx:3349
double GetLcm() const
Definition: scmatrix.cxx:3429
svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3224
void NotOp(const ScMatrix &rMat)
Definition: scmatrix.cxx:3518
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:3244
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:3424
void MatCopy(const ScMatrix &mRes) const
Definition: scmatrix.cxx:3299
bool IsEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3254
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:3314
std::function< void(size_t, size_t)> EmptyOpFunction
Definition: scmatrix.hxx:120
double Xor() const
Definition: scmatrix.cxx:3379
void NegOp(const ScMatrix &rMat)
Definition: scmatrix.cxx:3525
void PutString(const svl::SharedString &rStr, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3169
KahanIterateResult SumSquare(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3389
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:3309
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3289
void SetErrorInterpreter(ScInterpreter *p)
Definition: scmatrix.cxx:3124
ScMatrix * Clone() const
Clone the matrix.
Definition: scmatrix.cxx:3081
size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:3404
void SubOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3539
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3209
bool IsNumeric() const
Definition: scmatrix.cxx:3294
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:3594
SCSIZE GetElementCount() const
Definition: scmatrix.cxx:3134
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:3329
KahanIterateResult Sum(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3384
size_t nRefCnt
Definition: scmatrix.hxx:104
bool IsValueOrEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3284
void CompareEqual()
Definition: scmatrix.cxx:3339
void SetMutable()
Set the matrix to mutable for CloneIfConst(), only the interpreter should do this and know the conseq...
Definition: scmatrix.cxx:3096
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:3189
void AddOp(double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3532
double Or() const
Definition: scmatrix.cxx:3374
void MatConcat(SCSIZE nMaxCol, SCSIZE nMaxRow, const ScMatrixRef &xMat1, const ScMatrixRef &xMat2, SvNumberFormatter &rFormatter, svl::SharedStringPool &rPool)
Definition: scmatrix.cxx:3613
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:3204
void CompareNotEqual()
Definition: scmatrix.cxx:3344
void PutEmpty(SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3184
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:3334
void CompareLessEqual()
Definition: scmatrix.cxx:3359
void IncRef() const
Definition: scmatrix.cxx:2989
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:3001
void DecRef() const
Definition: scmatrix.cxx:2994
double And() const
Definition: scmatrix.cxx:3369
DoubleIterateResult Product(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3394
void MatTrans(const ScMatrix &mRes) const
Definition: scmatrix.cxx:3304
void CompareGreater()
Definition: scmatrix.cxx:3354
void MergeDoubleArrayMultiply(std::vector< double > &rArray) const
Definition: scmatrix.cxx:3446
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:3319
bool IsEmptyCell(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3259
bool mbCloneIfConst
Definition: scmatrix.hxx:105
void DivOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3562
void PowOp(bool bFlag, double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3578
double GetDoubleWithStringConversion(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3219
KahanIterateResultMultiple CollectKahan(const std::vector< sc::op::kOp > &aOp)
Definition: scmatrix.cxx:3601
void Resize(SCSIZE nC, SCSIZE nR)
Resize the matrix to specified new dimension.
Definition: scmatrix.cxx:3106
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:3144
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:3399
std::unique_ptr< ScMatrixImpl > pImpl
Definition: scmatrix.hxx:106
bool IsEmptyResult(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3264
bool ValidColRow(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3139
bool ValidColRowOrReplicated(SCSIZE &rC, SCSIZE &rR) const
Checks if the matrix position is within the matrix.
Definition: scmatrix.cxx:3149
ScMatrixRef CompareMatrix(sc::Compare &rComp, size_t nMatPos, sc::CompareOptions *pOptions) const
Definition: scmatrix.cxx:3435
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3154
void SetImmutable() const
Set the matrix to immutable for CloneIfConst(), only the interpreter should do this and know the cons...
Definition: scmatrix.cxx:3101
bool IsEmptyPath(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3269
double GetMinValue(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3419
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:3619
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:3441
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:3324
void CompareGreaterEqual()
Definition: scmatrix.cxx:3364
void MulOp(double fVal, const ScMatrix &rMat)
Definition: scmatrix.cxx:3555
void PutError(FormulaError nErrorCode, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3194
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:3129
size_t MatchStringInColumns(const svl::SharedString &rStr, size_t nCol1, size_t nCol2) const
Definition: scmatrix.cxx:3409
ScMatrix * CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const
Clone the matrix and extend it to the new size.
Definition: scmatrix.cxx:3116
ScMatrix * CloneIfConst()
Clone the matrix if mbCloneIfConst (immutable) is set, otherwise return this matrix,...
Definition: scmatrix.cxx:3091
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:3274
double GetMaxValue(bool bTextAsZero, bool bIgnoreErrorValues=false) const
Definition: scmatrix.cxx:3414
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:833
@ SC_LESS_EQUAL
Definition: global.hxx:837
@ SC_LESS
Definition: global.hxx:835
@ SC_GREATER_EQUAL
Definition: global.hxx:838
@ SC_GREATER
Definition: global.hxx:836
@ SC_EQUAL
Definition: global.hxx:834
@ SC_NOT_EQUAL
Definition: global.hxx:839
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:3466
mdds::multi_type_matrix< matrix_traits > MatrixImplType
Definition: scmatrix.cxx:75
double mfVal
Definition: scmatrix.cxx:3468
static std::once_flag bElementsMaxFetched
Definition: scmatrix.cxx:360
ScInterpreter * mpErrorInterpreter
Definition: scmatrix.cxx:3467
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:517
SvNumFormatType