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