1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #ifndef SC_MATRIX_HXX 25 #define SC_MATRIX_HXX 26 27 #include "global.hxx" 28 #include "formula/intruref.hxx" 29 #include "formula/errorcodes.hxx" 30 #include <tools/string.hxx> 31 #include "scdllapi.h" 32 33 class SvStream; 34 class ScInterpreter; 35 class SvNumberFormatter; 36 37 typedef sal_uInt8 ScMatValType; 38 const ScMatValType SC_MATVAL_VALUE = 0x00; 39 const ScMatValType SC_MATVAL_BOOLEAN = 0x01; 40 const ScMatValType SC_MATVAL_STRING = 0x02; 41 const ScMatValType SC_MATVAL_EMPTY = SC_MATVAL_STRING | 0x04; // STRING plus flag 42 const ScMatValType SC_MATVAL_EMPTYPATH = SC_MATVAL_EMPTY | 0x08; // EMPTY plus flag 43 const ScMatValType SC_MATVAL_NONVALUE = SC_MATVAL_EMPTYPATH; // mask of all non-value bits 44 45 union ScMatrixValue 46 { 47 double fVal; 48 String* pS; 49 50 /// Only valid if ScMatrix methods indicate so! GetString() const51 const String& GetString() const { return pS ? *pS : EMPTY_STRING; } 52 53 /// Only valid if ScMatrix methods indicate that this is no string! GetError() const54 sal_uInt16 GetError() const { return GetDoubleErrorValue( fVal); } 55 56 /// Only valid if ScMatrix methods indicate that this is a boolean GetBoolean() const57 bool GetBoolean() const { return fVal != 0.; } 58 }; 59 60 /** Matrix representation of double values and strings. 61 62 @ATTENTION: optimized for speed and double values. 63 64 <p> Matrix elements are NOT initialized after construction! 65 66 <p> All methods using an SCSIZE nIndex parameter and all Is...() methods do 67 NOT check the range for validity! However, the Put...() and Get...() 68 methods using nCol/nRow parameters do check the range. 69 70 <p> Methods using nCol/nRow parameters do replicate a single row vector if 71 nRow > 0 and nCol < nColCount, respectively a column vector if nCol 72 > 0 and nRow < nRowCount. 73 74 <p> GetString( SCSIZE nIndex ) does not check if there really is a string, 75 do this with IsString() first. GetString( SCSIZE nC, SCSIZE nR ) does check 76 it and returns and empty string if there is no string. Both GetDouble() 77 methods don't check for a string, do this with IsNumeric() or IsString() or 78 IsValue() first. 79 80 <p> The GetString( SvNumberFormatter&, ...) methods return the matrix 81 element's string if one is present, otherwise the numerical value is 82 formatted as a string, or in case of an error the error string is returned. 83 84 <p> PutDouble() does not reset an eventual string! Use 85 PutDoubleAndResetString() if that is wanted. Also the FillDouble...() 86 methods don't reset strings. As a consequence memory leaks may occur if 87 used wrong. 88 */ 89 class SC_DLLPUBLIC ScMatrix 90 { 91 ScMatrixValue* pMat; 92 ScMatValType* mnValType; 93 sal_uLong mnNonValue; // how many strings and empties 94 ScInterpreter* pErrorInterpreter; 95 mutable sal_uLong nRefCnt; // reference count 96 SCSIZE nColCount; 97 SCSIZE nRowCount; 98 bool mbCloneIfConst; // Whether the matrix is cloned with a CloneIfConst() call. 99 100 void ResetIsString(); 101 void DeleteIsString(); 102 void CreateMatrix( SCSIZE nC, SCSIZE nR); 103 void Clear(); 104 105 // pStr may be NULL, bFlag MUST NOT be 0 106 void PutStringEntry( const String* pStr, sal_uInt8 bFlag, SCSIZE nIndex ); 107 108 // only delete via Delete() 109 ~ScMatrix(); 110 111 // not implemented, prevent usage 112 ScMatrix( const ScMatrix& ); 113 ScMatrix& operator=( const ScMatrix&); 114 115 void SetErrorAtInterpreter( sal_uInt16 nError) const; 116 117 public: 118 119 /// The maximum number of elements a matrix may have at runtime. GetElementsMax()120 inline static size_t GetElementsMax() 121 { 122 // Roughly 125MB in total, divided by 8+1 per element => 14M elements. 123 const size_t nMemMax = 0x08000000 / (sizeof(ScMatrixValue) + sizeof(ScMatValType)); 124 // With MAXROWCOUNT==65536 and 128 columns => 8M elements ~72MB. 125 const size_t nArbitraryLimit = (size_t)MAXROWCOUNT * 128; 126 // Stuffed with a million rows would limit this to 14 columns. 127 return nMemMax < nArbitraryLimit ? nMemMax : nArbitraryLimit; 128 } 129 130 /// Value or boolean. IsValueType(ScMatValType nType)131 inline static bool IsValueType( ScMatValType nType ) 132 { 133 return nType <= SC_MATVAL_BOOLEAN; 134 } 135 136 /// Boolean. IsBooleanType(ScMatValType nType)137 inline static bool IsBooleanType( ScMatValType nType ) 138 { 139 return nType == SC_MATVAL_BOOLEAN; 140 } 141 142 /// String, empty or empty path, but not value nor boolean. IsNonValueType(ScMatValType nType)143 inline static bool IsNonValueType( ScMatValType nType ) 144 { 145 return (nType & SC_MATVAL_NONVALUE) != 0; 146 } 147 148 /** String, but not empty or empty path or any other type. 149 Not named IsStringType to prevent confusion because previously 150 IsNonValueType was named IsStringType. */ IsRealStringType(ScMatValType nType)151 inline static bool IsRealStringType( ScMatValType nType ) 152 { 153 return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_STRING; 154 } 155 156 /// Empty, but not empty path or any other type. IsEmptyType(ScMatValType nType)157 inline static bool IsEmptyType( ScMatValType nType ) 158 { 159 return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTY; 160 } 161 162 /// Empty path, but not empty or any other type. IsEmptyPathType(ScMatValType nType)163 inline static bool IsEmptyPathType( ScMatValType nType ) 164 { 165 return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTYPATH; 166 } 167 168 /** If nC*nR results in more than GetElementsMax() entries, a 1x1 matrix is 169 created instead and a double error value (errStackOverflow) is set. 170 Compare nC and nR with a GetDimensions() call to check. */ ScMatrix(SCSIZE nC,SCSIZE nR)171 ScMatrix( SCSIZE nC, SCSIZE nR) : nRefCnt(0), mbCloneIfConst(true) { CreateMatrix( nC, nR); } 172 173 /** Clone the matrix. */ 174 ScMatrix* Clone() const; 175 176 /** Clone the matrix if mbCloneIfConst (immutable) is set, otherwise 177 return _this_ matrix, to be assigned to a ScMatrixRef. */ 178 ScMatrix* CloneIfConst(); 179 180 /** Set the matrix to (im)mutable for CloneIfConst(), only the interpreter 181 should do this and know the consequences. */ SetImmutable(bool bVal)182 inline void SetImmutable( bool bVal ) { mbCloneIfConst = bVal; } 183 184 /** 185 * Resize the matrix to specified new dimension. Note that this operation 186 * clears all stored values. 187 */ 188 void Resize( SCSIZE nC, SCSIZE nR); 189 190 /** Clone the matrix and extend it to the new size. nNewCols and nNewRows 191 MUST be at least of the size of the original matrix. */ 192 ScMatrix* CloneAndExtend( SCSIZE nNewCols, SCSIZE nNewRows ) const; 193 194 /// Disable refcounting forever, may only be deleted via Delete() afterwards. SetEternalRef()195 inline void SetEternalRef() { nRefCnt = ULONG_MAX; } IsEternalRef() const196 inline bool IsEternalRef() const { return nRefCnt == ULONG_MAX; } IncRef() const197 inline void IncRef() const 198 { 199 if ( !IsEternalRef() ) 200 ++nRefCnt; 201 } DecRef() const202 inline void DecRef() const 203 { 204 if ( nRefCnt > 0 && !IsEternalRef() ) 205 if ( --nRefCnt == 0 ) 206 delete this; 207 } Delete()208 inline void Delete() 209 { 210 if ( nRefCnt == 0 || IsEternalRef() ) 211 delete this; 212 else 213 --nRefCnt; 214 } 215 SetErrorInterpreter(ScInterpreter * p)216 void SetErrorInterpreter( ScInterpreter* p) 217 { pErrorInterpreter = p; } 218 219 ScMatrix( SvStream& rStream); 220 void Store( SvStream& rStream) const; 221 GetDimensions(SCSIZE & rC,SCSIZE & rR) const222 void GetDimensions( SCSIZE& rC, SCSIZE& rR) const 223 { rC = nColCount; rR = nRowCount; }; GetElementCount() const224 SCSIZE GetElementCount() const 225 { return nColCount * nRowCount; } ValidColRow(SCSIZE nC,SCSIZE nR) const226 inline bool ValidColRow( SCSIZE nC, SCSIZE nR) const 227 { return nC < nColCount && nR < nRowCount; } CalcOffset(SCSIZE nC,SCSIZE nR) const228 inline SCSIZE CalcOffset( SCSIZE nC, SCSIZE nR) const 229 { return nC * nRowCount + nR; } 230 231 /** For a row vector or column vector, if the position does not point into 232 the vector but is a valid column or row offset it is adapted such that 233 it points to an element to be replicated, same column row 0 for a row 234 vector, same row column 0 for a column vector. Else, for a 2D matrix, 235 returns false. 236 */ ValidColRowReplicated(SCSIZE & rC,SCSIZE & rR) const237 inline bool ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const 238 { 239 if (nColCount == 1 && nRowCount == 1) 240 { 241 rC = 0; 242 rR = 0; 243 return true; 244 } 245 else if (nColCount == 1 && rR < nRowCount) 246 { 247 rC = 0; 248 return true; 249 } 250 else if (nRowCount == 1 && rC < nColCount) 251 { 252 rR = 0; 253 return true; 254 } 255 return false; 256 } 257 258 /** Checks if the matrix position is within the matrix. If it is not, for a 259 row vector or column vector the position is adapted such that it points 260 to an element to be replicated, same column row 0 for a row vector, 261 same row column 0 for a column vector. Else, for a 2D matrix and 262 position not within matrix, returns false. 263 */ ValidColRowOrReplicated(SCSIZE & rC,SCSIZE & rR) const264 inline bool ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const 265 { 266 return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR); 267 } 268 269 270 void PutDouble( double fVal, SCSIZE nC, SCSIZE nR); PutDouble(double fVal,SCSIZE nIndex)271 void PutDouble( double fVal, SCSIZE nIndex) 272 { pMat[nIndex].fVal = fVal; } 273 void PutString( const String& rStr, SCSIZE nC, SCSIZE nR); 274 void PutString( const String& rStr, SCSIZE nIndex); 275 void PutEmpty( SCSIZE nC, SCSIZE nR); 276 void PutEmpty( SCSIZE nIndex); 277 /// Jump sal_False without path 278 void PutEmptyPath( SCSIZE nC, SCSIZE nR); 279 void PutEmptyPath( SCSIZE nIndex); PutError(sal_uInt16 nErrorCode,SCSIZE nC,SCSIZE nR)280 void PutError( sal_uInt16 nErrorCode, SCSIZE nC, SCSIZE nR ) 281 { PutDouble( CreateDoubleError( nErrorCode ), nC, nR ); } PutError(sal_uInt16 nErrorCode,SCSIZE nIndex)282 void PutError( sal_uInt16 nErrorCode, SCSIZE nIndex ) 283 { PutDouble( CreateDoubleError( nErrorCode ), nIndex ); } 284 void PutBoolean( bool bVal, SCSIZE nC, SCSIZE nR); 285 void PutBoolean( bool bVal, SCSIZE nIndex); 286 287 void FillDouble( double fVal, 288 SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 ); 289 290 /** May be used before obtaining the double value of an element to avoid 291 passing its NAN around. 292 @ATTENTION: MUST NOT be used if the element is a string! 293 Use GetErrorIfNotString() instead if not sure. 294 @returns 0 if no error, else one of err... constants */ 295 sal_uInt16 GetError( SCSIZE nC, SCSIZE nR) const; GetError(SCSIZE nIndex) const296 sal_uInt16 GetError( SCSIZE nIndex) const 297 { return pMat[nIndex].GetError(); } 298 299 /** Use in ScInterpreter to obtain the error code, if any. 300 @returns 0 if no error or string element, else one of err... constants */ GetErrorIfNotString(SCSIZE nC,SCSIZE nR) const301 sal_uInt16 GetErrorIfNotString( SCSIZE nC, SCSIZE nR) const 302 { return IsValue( nC, nR) ? GetError( nC, nR) : 0; } GetErrorIfNotString(SCSIZE nIndex) const303 sal_uInt16 GetErrorIfNotString( SCSIZE nIndex) const 304 { return IsValue( nIndex) ? GetError( nIndex) : 0; } 305 306 /// @return 0.0 if empty or empty path, else value or DoubleError. 307 double GetDouble( SCSIZE nC, SCSIZE nR) const; 308 /// @return 0.0 if empty or empty path, else value or DoubleError. GetDouble(SCSIZE nIndex) const309 double GetDouble( SCSIZE nIndex) const 310 { 311 if ( pErrorInterpreter ) 312 { 313 sal_uInt16 nError = GetDoubleErrorValue( pMat[nIndex].fVal); 314 if ( nError ) 315 SetErrorAtInterpreter( nError); 316 } 317 return pMat[nIndex].fVal; 318 } 319 320 /// @return empty string if empty or empty path, else string content. 321 const String& GetString( SCSIZE nC, SCSIZE nR) const; 322 /// @return empty string if empty or empty path, else string content. GetString(SCSIZE nIndex) const323 const String& GetString( SCSIZE nIndex) const 324 { return pMat[nIndex].GetString(); } 325 326 /** @returns the matrix element's string if one is present, otherwise the 327 numerical value formatted as string, or in case of an error the error 328 string is returned; an empty string for empty, a "FALSE" string for 329 empty path. */ 330 String GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const; 331 String GetString( SvNumberFormatter& rFormatter, SCSIZE nIndex) const; 332 333 /// @ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate 334 /// an empty string! 335 const ScMatrixValue* Get( SCSIZE nC, SCSIZE nR, ScMatValType& nType) const; 336 337 /// @return <TRUE/> if string or empty or empty path, in fact non-value. IsString(SCSIZE nIndex) const338 sal_Bool IsString( SCSIZE nIndex ) const 339 { return mnValType && IsNonValueType( mnValType[nIndex]); } 340 341 /// @return <TRUE/> if string or empty or empty path, in fact non-value. IsString(SCSIZE nC,SCSIZE nR) const342 sal_Bool IsString( SCSIZE nC, SCSIZE nR ) const 343 { 344 ValidColRowReplicated( nC, nR ); 345 return mnValType && IsNonValueType( mnValType[ nC * nRowCount + nR ]); 346 } 347 348 /// @return <TRUE/> if empty or empty path. IsEmpty(SCSIZE nIndex) const349 sal_Bool IsEmpty( SCSIZE nIndex ) const 350 { return mnValType && ((mnValType[nIndex] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); } 351 352 /// @return <TRUE/> if empty or empty path. IsEmpty(SCSIZE nC,SCSIZE nR) const353 sal_Bool IsEmpty( SCSIZE nC, SCSIZE nR ) const 354 { 355 ValidColRowReplicated( nC, nR ); 356 return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); 357 } 358 359 /// @return <TRUE/> if empty path. IsEmptyPath(SCSIZE nC,SCSIZE nR) const360 sal_Bool IsEmptyPath( SCSIZE nC, SCSIZE nR ) const 361 { 362 ValidColRowReplicated( nC, nR ); 363 return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTYPATH) == SC_MATVAL_EMPTYPATH); 364 } 365 366 /// @return <TRUE/> if empty path. IsEmptyPath(SCSIZE nIndex) const367 sal_Bool IsEmptyPath( SCSIZE nIndex ) const 368 { return mnValType && ((mnValType[nIndex] & SC_MATVAL_EMPTYPATH) == SC_MATVAL_EMPTYPATH); } 369 370 /// @return <TRUE/> if value or boolean. IsValue(SCSIZE nIndex) const371 sal_Bool IsValue( SCSIZE nIndex ) const 372 { return !mnValType || IsValueType( mnValType[nIndex]); } 373 374 /// @return <TRUE/> if value or boolean. IsValue(SCSIZE nC,SCSIZE nR) const375 sal_Bool IsValue( SCSIZE nC, SCSIZE nR ) const 376 { 377 ValidColRowReplicated( nC, nR ); 378 return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]); 379 } 380 381 /// @return <TRUE/> if value or boolean or empty or empty path. IsValueOrEmpty(SCSIZE nIndex) const382 sal_Bool IsValueOrEmpty( SCSIZE nIndex ) const 383 { return !mnValType || IsValueType( mnValType[nIndex] ) || 384 ((mnValType[nIndex] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); } 385 386 /// @return <TRUE/> if value or boolean or empty or empty path. IsValueOrEmpty(SCSIZE nC,SCSIZE nR) const387 sal_Bool IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const 388 { 389 ValidColRowReplicated( nC, nR ); 390 return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]) || 391 ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTY) == 392 SC_MATVAL_EMPTY); 393 } 394 395 /// @return <TRUE/> if boolean. IsBoolean(SCSIZE nIndex) const396 sal_Bool IsBoolean( SCSIZE nIndex ) const 397 { return mnValType && IsBooleanType( mnValType[nIndex]); } 398 399 /// @return <TRUE/> if boolean. IsBoolean(SCSIZE nC,SCSIZE nR) const400 sal_Bool IsBoolean( SCSIZE nC, SCSIZE nR ) const 401 { 402 ValidColRowReplicated( nC, nR ); 403 return mnValType && IsBooleanType( mnValType[ nC * nRowCount + nR ]); 404 } 405 406 /// @return <TRUE/> if entire matrix is numeric, including booleans, with no strings or empties IsNumeric() const407 sal_Bool IsNumeric() const 408 { return 0 == mnNonValue; } 409 410 void MatTrans( ScMatrix& mRes) const; 411 void MatCopy ( ScMatrix& mRes) const; 412 413 //UNUSED2009-05 /** Copy upper left of this matrix to mRes matrix. 414 //UNUSED2009-05 This matrix's dimensions must be greater or equal to the mRes matrix 415 //UNUSED2009-05 dimensions. 416 //UNUSED2009-05 */ 417 //UNUSED2009-05 void MatCopyUpperLeft( ScMatrix& mRes) const; 418 419 // Convert ScInterpreter::CompareMat values (-1,0,1) to boolean values 420 void CompareEqual(); 421 void CompareNotEqual(); 422 void CompareLess(); 423 void CompareGreater(); 424 void CompareLessEqual(); 425 void CompareGreaterEqual(); 426 427 double And(); // logical AND of all matrix values, or NAN 428 double Or(); // logical OR of all matrix values, or NAN 429 double Xor(); // logical XOR of all matrix values, or NAN 430 431 // All other matrix functions MatMult, MInv, ... are in ScInterpreter 432 // to be numerically safe. 433 }; 434 435 436 typedef formula::SimpleIntrusiveReference< class ScMatrix > ScMatrixRef; 437 typedef formula::SimpleIntrusiveReference< const class ScMatrix > ScConstMatrixRef; 438 439 440 #endif // SC_MATRIX_HXX 441