Line data Source code
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 : #ifndef INCLUDED_SC_INC_SCMATRIX_HXX
21 : #define INCLUDED_SC_INC_SCMATRIX_HXX
22 :
23 : #include "global.hxx"
24 : #include "types.hxx"
25 : #include <formula/errorcodes.hxx>
26 : #include "scdllapi.h"
27 : #include <rtl/ustring.hxx>
28 : #include <svl/sharedstring.hxx>
29 :
30 : #include <boost/intrusive_ptr.hpp>
31 : #include <boost/interprocess/smart_ptr/unique_ptr.hpp>
32 :
33 : #define DEBUG_MATRIX 0
34 :
35 : class ScInterpreter;
36 : class SvNumberFormatter;
37 : class ScMatrixImpl;
38 :
39 : namespace sc {
40 :
41 : struct Compare;
42 : struct CompareOptions;
43 :
44 : }
45 :
46 : /**
47 : * Try NOT to use this struct. This struct should go away in a hopefully
48 : * not so distant futture.
49 : */
50 705 : struct ScMatrixValue
51 : {
52 : double fVal;
53 : svl::SharedString aStr;
54 : ScMatValType nType;
55 :
56 : /// Only valid if ScMatrix methods indicate so!
57 12 : svl::SharedString GetString() const { return aStr; }
58 :
59 : /// Only valid if ScMatrix methods indicate that this is no string!
60 34 : sal_uInt16 GetError() const { return GetDoubleErrorValue( fVal); }
61 :
62 : /// Only valid if ScMatrix methods indicate that this is a boolean
63 0 : bool GetBoolean() const { return fVal != 0.0; }
64 :
65 705 : ScMatrixValue() : fVal(0.0), nType(SC_MATVAL_EMPTY) {}
66 :
67 : ScMatrixValue(const ScMatrixValue& r) :
68 : fVal(r.fVal), aStr(r.aStr), nType(r.nType) {}
69 :
70 0 : bool operator== (const ScMatrixValue& r) const
71 : {
72 0 : if (nType != r.nType)
73 0 : return false;
74 :
75 0 : switch (nType)
76 : {
77 : case SC_MATVAL_VALUE:
78 : case SC_MATVAL_BOOLEAN:
79 0 : return fVal == r.fVal;
80 : break;
81 : default:
82 : ;
83 : }
84 :
85 0 : return aStr == r.aStr;
86 : }
87 :
88 0 : bool operator!= (const ScMatrixValue& r) const
89 : {
90 0 : return !operator==(r);
91 : }
92 :
93 7 : ScMatrixValue& operator= (const ScMatrixValue& r)
94 : {
95 7 : if (this == &r)
96 0 : return *this;
97 :
98 7 : nType = r.nType;
99 7 : fVal = r.fVal;
100 7 : aStr = r.aStr;
101 7 : return *this;
102 : }
103 : };
104 :
105 : /**
106 : * Matrix data type that can store values of mixed types. Each element can
107 : * be one of the following types: numeric, string, boolean, empty, and empty
108 : * path.
109 : */
110 : class SC_DLLPUBLIC ScMatrix
111 : {
112 : friend class ScMatrixImpl;
113 :
114 : ScMatrixImpl* pImpl;
115 : mutable size_t nRefCnt; // reference count
116 :
117 : // only delete via Delete()
118 : ~ScMatrix();
119 :
120 : ScMatrix( const ScMatrix& ) SAL_DELETED_FUNCTION;
121 : ScMatrix& operator=( const ScMatrix&) SAL_DELETED_FUNCTION;
122 :
123 : public:
124 : enum Op { Add, Sub, Mul, Div };
125 :
126 : /**
127 : * When adding all numerical matrix elements for a scalar result such as
128 : * summation, the interpreter wants to separate the first non-zero value
129 : * with the rest of the summed values.
130 : *
131 : * TODO: Find out if we still need to do this. If not, we can re-write
132 : * ScInterpreter::IterateParameters() to make it simpler and remove this
133 : * struct.
134 : */
135 : struct IterateResult
136 : {
137 : double mfFirst;
138 : double mfRest;
139 : size_t mnCount;
140 :
141 14 : IterateResult(double fFirst, double fRest, size_t nCount) :
142 14 : mfFirst(fFirst), mfRest(fRest), mnCount(nCount) {}
143 :
144 14 : IterateResult(const IterateResult& r) :
145 14 : mfFirst(r.mfFirst), mfRest(r.mfRest), mnCount(r.mnCount) {}
146 : };
147 :
148 : /// The maximum number of elements a matrix may have at runtime.
149 224 : inline static size_t GetElementsMax()
150 : {
151 : // TODO: Fix me.
152 224 : return 0x08000000;
153 : #if 0
154 : // Roughly 125MB in total, divided by 8+1 per element => 14M elements.
155 : const size_t nMemMax = 0x08000000 / (sizeof(ScMatrixValue) + sizeof(ScMatValType));
156 : // With MAXROWCOUNT==65536 and 128 columns => 8M elements ~72MB.
157 : const size_t nArbitraryLimit = (size_t)MAXROWCOUNT * 128;
158 : // Stuffed with a million rows would limit this to 14 columns.
159 : return nMemMax < nArbitraryLimit ? nMemMax : nArbitraryLimit;
160 : #endif
161 : }
162 :
163 : /// Value or boolean.
164 29 : inline static bool IsValueType( ScMatValType nType )
165 : {
166 29 : return nType <= SC_MATVAL_BOOLEAN;
167 : }
168 :
169 : /// Boolean.
170 16 : inline static bool IsBooleanType( ScMatValType nType )
171 : {
172 16 : return nType == SC_MATVAL_BOOLEAN;
173 : }
174 :
175 : /// String, empty or empty path, but not value nor boolean.
176 154 : inline static bool IsNonValueType( ScMatValType nType )
177 : {
178 154 : return (nType & SC_MATVAL_NONVALUE) != 0;
179 : }
180 :
181 : /** String, but not empty or empty path or any other type.
182 : Not named IsStringType to prevent confusion because previously
183 : IsNonValueType was named IsStringType. */
184 3 : inline static bool IsRealStringType( ScMatValType nType )
185 : {
186 3 : return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_STRING;
187 : }
188 :
189 : /// Empty, but not empty path or any other type.
190 5 : inline static bool IsEmptyType( ScMatValType nType )
191 : {
192 5 : return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTY;
193 : }
194 :
195 : /// Empty path, but not empty or any other type.
196 5 : inline static bool IsEmptyPathType( ScMatValType nType )
197 : {
198 5 : return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTYPATH;
199 : }
200 :
201 : ScMatrix(SCSIZE nC, SCSIZE nR);
202 : ScMatrix(SCSIZE nC, SCSIZE nR, double fInitVal);
203 :
204 : ScMatrix( size_t nC, size_t nR, const std::vector<double>& rInitVals );
205 :
206 : /** Clone the matrix. */
207 : ScMatrix* Clone() const;
208 :
209 : /** Clone the matrix if mbCloneIfConst (immutable) is set, otherwise
210 : return _this_ matrix, to be assigned to a ScMatrixRef. */
211 : ScMatrix* CloneIfConst();
212 :
213 : /** Set the matrix to (im)mutable for CloneIfConst(), only the interpreter
214 : should do this and know the consequences. */
215 : void SetImmutable( bool bVal );
216 :
217 : /**
218 : * Resize the matrix to specified new dimension.
219 : */
220 : void Resize( SCSIZE nC, SCSIZE nR);
221 :
222 : void Resize(SCSIZE nC, SCSIZE nR, double fVal);
223 :
224 : /** Clone the matrix and extend it to the new size. nNewCols and nNewRows
225 : MUST be at least of the size of the original matrix. */
226 : ScMatrix* CloneAndExtend(SCSIZE nNewCols, SCSIZE nNewRows) const;
227 :
228 : void IncRef() const;
229 : void DecRef() const;
230 :
231 : void SetErrorInterpreter( ScInterpreter* p);
232 : void GetDimensions( SCSIZE& rC, SCSIZE& rR) const;
233 : SCSIZE GetElementCount() const;
234 : bool ValidColRow( SCSIZE nC, SCSIZE nR) const;
235 : SCSIZE CalcOffset( SCSIZE nC, SCSIZE nR) const;
236 :
237 : /** For a row vector or column vector, if the position does not point into
238 : the vector but is a valid column or row offset it is adapted such that
239 : it points to an element to be replicated, same column row 0 for a row
240 : vector, same row column 0 for a column vector. Else, for a 2D matrix,
241 : returns false.
242 : */
243 : bool ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const;
244 :
245 : /** Checks if the matrix position is within the matrix. If it is not, for a
246 : row vector or column vector the position is adapted such that it points
247 : to an element to be replicated, same column row 0 for a row vector,
248 : same row column 0 for a column vector. Else, for a 2D matrix and
249 : position not within matrix, returns false.
250 : */
251 : bool ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const;
252 :
253 : void PutDouble( double fVal, SCSIZE nC, SCSIZE nR);
254 : void PutDouble( double fVal, SCSIZE nIndex);
255 : void PutDouble(const double* pArray, size_t nLen, SCSIZE nC, SCSIZE nR);
256 :
257 : void PutString( const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR);
258 : void PutString( const svl::SharedString& rStr, SCSIZE nIndex);
259 : void PutString( const svl::SharedString* pArray, size_t nLen, SCSIZE nC, SCSIZE nR);
260 :
261 : void PutEmpty( SCSIZE nC, SCSIZE nR);
262 :
263 : /// Jump sal_False without path
264 : void PutEmptyPath( SCSIZE nC, SCSIZE nR);
265 : void PutError( sal_uInt16 nErrorCode, SCSIZE nC, SCSIZE nR );
266 : void PutBoolean( bool bVal, SCSIZE nC, SCSIZE nR);
267 :
268 : void FillDouble( double fVal,
269 : SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 );
270 :
271 : /** Put a column vector of doubles, starting at row nR, must fit into dimensions. */
272 : void PutDoubleVector( const ::std::vector< double > & rVec, SCSIZE nC, SCSIZE nR );
273 :
274 : /** Put a column vector of strings, starting at row nR, must fit into dimensions. */
275 : void PutStringVector( const ::std::vector< svl::SharedString > & rVec, SCSIZE nC, SCSIZE nR );
276 :
277 : /** Put a column vector of empties, starting at row nR, must fit into dimensions. */
278 : void PutEmptyVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
279 :
280 : /** Put a column vector of empty results, starting at row nR, must fit into dimensions. */
281 : void PutEmptyResultVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
282 :
283 : /** Put a column vector of empty paths, starting at row nR, must fit into dimensions. */
284 : void PutEmptyPathVector( SCSIZE nCount, SCSIZE nC, SCSIZE nR );
285 :
286 : /** May be used before obtaining the double value of an element to avoid
287 : passing its NAN around.
288 : @ATTENTION: MUST NOT be used if the element is a string!
289 : Use GetErrorIfNotString() instead if not sure.
290 : @returns 0 if no error, else one of err... constants */
291 : sal_uInt16 GetError( SCSIZE nC, SCSIZE nR) const;
292 :
293 : /** Use in ScInterpreter to obtain the error code, if any.
294 : @returns 0 if no error or string element, else one of err... constants */
295 0 : sal_uInt16 GetErrorIfNotString( SCSIZE nC, SCSIZE nR) const
296 0 : { return IsValue( nC, nR) ? GetError( nC, nR) : 0; }
297 :
298 : /// @return 0.0 if empty or empty path, else value or DoubleError.
299 : double GetDouble( SCSIZE nC, SCSIZE nR) const;
300 : /// @return 0.0 if empty or empty path, else value or DoubleError.
301 : double GetDouble( SCSIZE nIndex) const;
302 :
303 : /// @return empty string if empty or empty path, else string content.
304 : svl::SharedString GetString( SCSIZE nC, SCSIZE nR) const;
305 : /// @return empty string if empty or empty path, else string content.
306 : svl::SharedString GetString( SCSIZE nIndex) const;
307 :
308 : /** @returns the matrix element's string if one is present, otherwise the
309 : numerical value formatted as string, or in case of an error the error
310 : string is returned; an empty string for empty, a "FALSE" string for
311 : empty path. */
312 : svl::SharedString GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const;
313 :
314 : /// @ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate
315 : /// an empty string!
316 : ScMatrixValue Get( SCSIZE nC, SCSIZE nR) const;
317 :
318 : /// @return <TRUE/> if string or empty or empty path, in fact non-value.
319 : bool IsString( SCSIZE nIndex ) const;
320 :
321 : /// @return <TRUE/> if string or empty or empty path, in fact non-value.
322 : bool IsString( SCSIZE nC, SCSIZE nR ) const;
323 :
324 : /// @return <TRUE/> if empty or empty cell or empty result, not empty path.
325 : bool IsEmpty( SCSIZE nC, SCSIZE nR ) const;
326 :
327 : /// @return <TRUE/> if empty cell, not empty or empty result or empty path.
328 : bool IsEmptyCell( SCSIZE nC, SCSIZE nR ) const;
329 :
330 : /// @return <TRUE/> if empty result, not empty or empty cell or empty path.
331 : bool IsEmptyResult( SCSIZE nC, SCSIZE nR ) const;
332 :
333 : /// @return <TRUE/> if empty path, not empty or empty cell or empty result.
334 : bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const;
335 :
336 : /// @return <TRUE/> if value or boolean.
337 : bool IsValue( SCSIZE nIndex ) const;
338 :
339 : /// @return <TRUE/> if value or boolean.
340 : bool IsValue( SCSIZE nC, SCSIZE nR ) const;
341 :
342 : /// @return <TRUE/> if value or boolean or empty or empty path.
343 : bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const;
344 :
345 : /// @return <TRUE/> if boolean.
346 : bool IsBoolean( SCSIZE nC, SCSIZE nR ) const;
347 :
348 : /// @return <TRUE/> if entire matrix is numeric, including booleans, with no strings or empties
349 : bool IsNumeric() const;
350 :
351 : void MatTrans( ScMatrix& mRes) const;
352 : void MatCopy ( ScMatrix& mRes) const;
353 :
354 : // Convert ScInterpreter::CompareMat values (-1,0,1) to boolean values
355 : void CompareEqual();
356 : void CompareNotEqual();
357 : void CompareLess();
358 : void CompareGreater();
359 : void CompareLessEqual();
360 : void CompareGreaterEqual();
361 :
362 : double And() const; // logical AND of all matrix values, or NAN
363 : double Or() const; // logical OR of all matrix values, or NAN
364 : double Xor() const; // logical XOR of all matrix values, or NAN
365 :
366 : IterateResult Sum(bool bTextAsZero) const;
367 : IterateResult SumSquare(bool bTextAsZero) const;
368 : IterateResult Product(bool bTextAsZero) const;
369 : size_t Count(bool bCountStrings) const;
370 : size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const;
371 : size_t MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const;
372 :
373 : double GetMaxValue( bool bTextAsZero ) const;
374 : double GetMinValue( bool bTextAsZero ) const;
375 :
376 : ScMatrixRef CompareMatrix(
377 : sc::Compare& rComp, size_t nMatPos, sc::CompareOptions* pOptions = NULL ) const;
378 :
379 : /**
380 : * Convert the content of matrix into a linear array of numeric values.
381 : * String elements are mapped to NaN's and empty elements are mapped to
382 : * either NaN or zero values.
383 : *
384 : * @param bEmptyAsZero if true empty elements are mapped to zero values,
385 : * otherwise they become NaN values.
386 : */
387 : void GetDoubleArray( std::vector<double>& rArray, bool bEmptyAsZero = true ) const;
388 : void MergeDoubleArray( std::vector<double>& rArray, Op eOp ) const;
389 :
390 : void NotOp(ScMatrix& rMat);
391 : void NegOp(ScMatrix& rMat);
392 : void AddOp(double fVal, ScMatrix& rMat);
393 : void SubOp(bool bFlag, double fVal, ScMatrix& rMat);
394 : void MulOp(double fVal, ScMatrix& rMat);
395 : void DivOp(bool bFlag, double fVal, ScMatrix& rMat);
396 : void PowOp(bool bFlag, double fVal, ScMatrix& rMat);
397 :
398 : ScMatrix& operator+= ( const ScMatrix& r );
399 :
400 : #if DEBUG_MATRIX
401 : void Dump() const;
402 : #endif
403 : };
404 :
405 1978 : inline void intrusive_ptr_add_ref(const ScMatrix* p)
406 : {
407 1978 : p->IncRef();
408 1978 : }
409 :
410 1970 : inline void intrusive_ptr_release(const ScMatrix* p)
411 : {
412 1970 : p->DecRef();
413 1970 : }
414 :
415 : #endif // INCLUDED_SC_INC_SCMATRIX_HXX
416 :
417 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|