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