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