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