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