summaryrefslogtreecommitdiff
path: root/sc/inc/scmatrix.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/inc/scmatrix.hxx')
-rw-r--r--sc/inc/scmatrix.hxx443
1 files changed, 443 insertions, 0 deletions
diff --git a/sc/inc/scmatrix.hxx b/sc/inc/scmatrix.hxx
new file mode 100644
index 000000000000..b788672aa715
--- /dev/null
+++ b/sc/inc/scmatrix.hxx
@@ -0,0 +1,443 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_MATRIX_HXX
+#define SC_MATRIX_HXX
+
+#include "global.hxx"
+#include "formula/intruref.hxx"
+#include "formula/errorcodes.hxx"
+#include <tools/string.hxx>
+#include "scdllapi.h"
+
+class SvStream;
+class ScInterpreter;
+class SvNumberFormatter;
+
+typedef BYTE ScMatValType;
+const ScMatValType SC_MATVAL_VALUE = 0x00;
+const ScMatValType SC_MATVAL_BOOLEAN = 0x01;
+const ScMatValType SC_MATVAL_STRING = 0x02;
+const ScMatValType SC_MATVAL_EMPTY = SC_MATVAL_STRING | 0x04; // STRING plus flag
+const ScMatValType SC_MATVAL_EMPTYPATH = SC_MATVAL_EMPTY | 0x08; // EMPTY plus flag
+const ScMatValType SC_MATVAL_NONVALUE = SC_MATVAL_EMPTYPATH; // mask of all non-value bits
+
+union ScMatrixValue
+{
+ double fVal;
+ String* pS;
+
+ /// Only valid if ScMatrix methods indicate so!
+ const String& GetString() const { return pS ? *pS : EMPTY_STRING; }
+
+ /// Only valid if ScMatrix methods indicate that this is no string!
+ USHORT GetError() const { return GetDoubleErrorValue( fVal); }
+
+ /// Only valid if ScMatrix methods indicate that this is a boolean
+ bool GetBoolean() const { return fVal != 0.; }
+};
+
+/** Matrix representation of double values and strings.
+
+ @ATTENTION: optimized for speed and double values.
+
+ <p> Matrix elements are NOT initialized after construction!
+
+ <p> All methods using an SCSIZE nIndex parameter and all Is...() methods do
+ NOT check the range for validity! However, the Put...() and Get...()
+ methods using nCol/nRow parameters do check the range.
+
+ <p> Methods using nCol/nRow parameters do replicate a single row vector if
+ nRow &gt; 0 and nCol &lt; nColCount, respectively a column vector if nCol
+ &gt; 0 and nRow &lt; nRowCount.
+
+ <p> GetString( SCSIZE nIndex ) does not check if there really is a string,
+ do this with IsString() first. GetString( SCSIZE nC, SCSIZE nR ) does check
+ it and returns and empty string if there is no string. Both GetDouble()
+ methods don't check for a string, do this with IsNumeric() or IsString() or
+ IsValue() first.
+
+ <p> The GetString( SvNumberFormatter&, ...) methods return the matrix
+ element's string if one is present, otherwise the numerical value is
+ formatted as a string, or in case of an error the error string is returned.
+
+ <p> PutDouble() does not reset an eventual string! Use
+ PutDoubleAndResetString() if that is wanted. Also the FillDouble...()
+ methods don't reset strings. As a consequence memory leaks may occur if
+ used wrong.
+ */
+class SC_DLLPUBLIC ScMatrix
+{
+ ScMatrixValue* pMat;
+ ScMatValType* mnValType;
+ ULONG mnNonValue; // how many strings and empties
+ ScInterpreter* pErrorInterpreter;
+ mutable ULONG nRefCnt; // reference count
+ SCSIZE nColCount;
+ SCSIZE nRowCount;
+ bool mbCloneIfConst; // Whether the matrix is cloned with a CloneIfConst() call.
+
+ void ResetIsString();
+ void DeleteIsString();
+ void CreateMatrix( SCSIZE nC, SCSIZE nR);
+ void Clear();
+
+ // pStr may be NULL, bFlag MUST NOT be 0
+ void PutStringEntry( const String* pStr, BYTE bFlag, SCSIZE nIndex );
+
+ // only delete via Delete()
+ ~ScMatrix();
+
+ // not implemented, prevent usage
+ ScMatrix( const ScMatrix& );
+ ScMatrix& operator=( const ScMatrix&);
+
+ void SetErrorAtInterpreter( USHORT nError) const;
+
+public:
+
+ /// The maximum number of elements a matrix may have at runtime.
+ inline static size_t GetElementsMax()
+ {
+ // Roughly 125MB in total, divided by 8+1 per element => 14M elements.
+ const size_t nMemMax = 0x08000000 / (sizeof(ScMatrixValue) + sizeof(ScMatValType));
+ // With MAXROWCOUNT==65536 and 128 columns => 8M elements ~72MB.
+ const size_t nArbitraryLimit = (size_t)MAXROWCOUNT * 128;
+ // Stuffed with a million rows would limit this to 14 columns.
+ return nMemMax < nArbitraryLimit ? nMemMax : nArbitraryLimit;
+ }
+
+ /// Value or boolean.
+ inline static bool IsValueType( ScMatValType nType )
+ {
+ return nType <= SC_MATVAL_BOOLEAN;
+ }
+
+ /// Boolean.
+ inline static bool IsBooleanType( ScMatValType nType )
+ {
+ return nType == SC_MATVAL_BOOLEAN;
+ }
+
+ /// String, empty or empty path, but not value nor boolean.
+ inline static bool IsNonValueType( ScMatValType nType )
+ {
+ return (nType & SC_MATVAL_NONVALUE) != 0;
+ }
+
+ /** String, but not empty or empty path or any other type.
+ Not named IsStringType to prevent confusion because previously
+ IsNonValueType was named IsStringType. */
+ inline static bool IsRealStringType( ScMatValType nType )
+ {
+ return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_STRING;
+ }
+
+ /// Empty, but not empty path or any other type.
+ inline static bool IsEmptyType( ScMatValType nType )
+ {
+ return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTY;
+ }
+
+ /// Empty path, but not empty or any other type.
+ inline static bool IsEmptyPathType( ScMatValType nType )
+ {
+ return (nType & SC_MATVAL_NONVALUE) == SC_MATVAL_EMPTYPATH;
+ }
+
+ /** If nC*nR results in more than GetElementsMax() entries, a 1x1 matrix is
+ created instead and a double error value (errStackOverflow) is set.
+ Compare nC and nR with a GetDimensions() call to check. */
+ ScMatrix( SCSIZE nC, SCSIZE nR) : nRefCnt(0), mbCloneIfConst(true) { CreateMatrix( nC, nR); }
+
+ /** Clone the matrix. */
+ ScMatrix* Clone() const;
+
+ /** Clone the matrix if mbCloneIfConst (immutable) is set, otherwise
+ return _this_ matrix, to be assigned to a ScMatrixRef. */
+ ScMatrix* CloneIfConst();
+
+ /** Set the matrix to (im)mutable for CloneIfConst(), only the interpreter
+ should do this and know the consequences. */
+ inline void SetImmutable( bool bVal ) { mbCloneIfConst = bVal; }
+
+ /**
+ * Resize the matrix to specified new dimension. Note that this operation
+ * clears all stored values.
+ */
+ void Resize( SCSIZE nC, SCSIZE nR);
+
+ /** Clone the matrix and extend it to the new size. nNewCols and nNewRows
+ MUST be at least of the size of the original matrix. */
+ ScMatrix* CloneAndExtend( SCSIZE nNewCols, SCSIZE nNewRows ) const;
+
+ /// Disable refcounting forever, may only be deleted via Delete() afterwards.
+ inline void SetEternalRef() { nRefCnt = ULONG_MAX; }
+ inline bool IsEternalRef() const { return nRefCnt == ULONG_MAX; }
+ inline void IncRef() const
+ {
+ if ( !IsEternalRef() )
+ ++nRefCnt;
+ }
+ inline void DecRef() const
+ {
+ if ( nRefCnt > 0 && !IsEternalRef() )
+ if ( --nRefCnt == 0 )
+ delete this;
+ }
+ inline void Delete()
+ {
+ if ( nRefCnt == 0 || IsEternalRef() )
+ delete this;
+ else
+ --nRefCnt;
+ }
+
+ void SetErrorInterpreter( ScInterpreter* p)
+ { pErrorInterpreter = p; }
+
+ ScMatrix( SvStream& rStream);
+ void Store( SvStream& rStream) const;
+
+ void GetDimensions( SCSIZE& rC, SCSIZE& rR) const
+ { rC = nColCount; rR = nRowCount; };
+ SCSIZE GetElementCount() const
+ { return nColCount * nRowCount; }
+ inline bool ValidColRow( SCSIZE nC, SCSIZE nR) const
+ { return nC < nColCount && nR < nRowCount; }
+ inline SCSIZE CalcOffset( SCSIZE nC, SCSIZE nR) const
+ { return nC * nRowCount + nR; }
+
+ /** For a row vector or column vector, if the position does not point into
+ the vector but is a valid column or row offset it is adapted such that
+ it points to an element to be replicated, same column row 0 for a row
+ vector, same row column 0 for a column vector. Else, for a 2D matrix,
+ returns false.
+ */
+ inline bool ValidColRowReplicated( SCSIZE & rC, SCSIZE & rR ) const
+ {
+ if (nColCount == 1 && nRowCount == 1)
+ {
+ rC = 0;
+ rR = 0;
+ return true;
+ }
+ else if (nColCount == 1 && rR < nRowCount)
+ {
+ rC = 0;
+ return true;
+ }
+ else if (nRowCount == 1 && rC < nColCount)
+ {
+ rR = 0;
+ return true;
+ }
+ return false;
+ }
+
+ /** Checks if the matrix position is within the matrix. If it is not, for a
+ row vector or column vector the position is adapted such that it points
+ to an element to be replicated, same column row 0 for a row vector,
+ same row column 0 for a column vector. Else, for a 2D matrix and
+ position not within matrix, returns false.
+ */
+ inline bool ValidColRowOrReplicated( SCSIZE & rC, SCSIZE & rR ) const
+ {
+ return ValidColRow( rC, rR) || ValidColRowReplicated( rC, rR);
+ }
+
+
+ void PutDouble( double fVal, SCSIZE nC, SCSIZE nR);
+ void PutDouble( double fVal, SCSIZE nIndex)
+ { pMat[nIndex].fVal = fVal; }
+ void PutString( const String& rStr, SCSIZE nC, SCSIZE nR);
+ void PutString( const String& rStr, SCSIZE nIndex);
+ void PutEmpty( SCSIZE nC, SCSIZE nR);
+ void PutEmpty( SCSIZE nIndex);
+ /// Jump FALSE without path
+ void PutEmptyPath( SCSIZE nC, SCSIZE nR);
+ void PutEmptyPath( SCSIZE nIndex);
+ void PutError( USHORT nErrorCode, SCSIZE nC, SCSIZE nR )
+ { PutDouble( CreateDoubleError( nErrorCode ), nC, nR ); }
+ void PutError( USHORT nErrorCode, SCSIZE nIndex )
+ { PutDouble( CreateDoubleError( nErrorCode ), nIndex ); }
+ void PutBoolean( bool bVal, SCSIZE nC, SCSIZE nR);
+ void PutBoolean( bool bVal, SCSIZE nIndex);
+
+ void FillDouble( double fVal,
+ SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 );
+
+ /** May be used before obtaining the double value of an element to avoid
+ passing its NAN around.
+ @ATTENTION: MUST NOT be used if the element is a string!
+ Use GetErrorIfNotString() instead if not sure.
+ @returns 0 if no error, else one of err... constants */
+ USHORT GetError( SCSIZE nC, SCSIZE nR) const;
+ USHORT GetError( SCSIZE nIndex) const
+ { return pMat[nIndex].GetError(); }
+
+ /** Use in ScInterpreter to obtain the error code, if any.
+ @returns 0 if no error or string element, else one of err... constants */
+ USHORT GetErrorIfNotString( SCSIZE nC, SCSIZE nR) const
+ { return IsValue( nC, nR) ? GetError( nC, nR) : 0; }
+ USHORT GetErrorIfNotString( SCSIZE nIndex) const
+ { return IsValue( nIndex) ? GetError( nIndex) : 0; }
+
+ /// @return 0.0 if empty or empty path, else value or DoubleError.
+ double GetDouble( SCSIZE nC, SCSIZE nR) const;
+ /// @return 0.0 if empty or empty path, else value or DoubleError.
+ double GetDouble( SCSIZE nIndex) const
+ {
+ if ( pErrorInterpreter )
+ {
+ USHORT nError = GetDoubleErrorValue( pMat[nIndex].fVal);
+ if ( nError )
+ SetErrorAtInterpreter( nError);
+ }
+ return pMat[nIndex].fVal;
+ }
+
+ /// @return empty string if empty or empty path, else string content.
+ const String& GetString( SCSIZE nC, SCSIZE nR) const;
+ /// @return empty string if empty or empty path, else string content.
+ const String& GetString( SCSIZE nIndex) const
+ { return pMat[nIndex].GetString(); }
+
+ /** @returns the matrix element's string if one is present, otherwise the
+ numerical value formatted as string, or in case of an error the error
+ string is returned; an empty string for empty, a "FALSE" string for
+ empty path. */
+ String GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const;
+ String GetString( SvNumberFormatter& rFormatter, SCSIZE nIndex) const;
+
+ /// @ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate
+ /// an empty string!
+ const ScMatrixValue* Get( SCSIZE nC, SCSIZE nR, ScMatValType& nType) const;
+
+ /// @return <TRUE/> if string or empty or empty path, in fact non-value.
+ BOOL IsString( SCSIZE nIndex ) const
+ { return mnValType && IsNonValueType( mnValType[nIndex]); }
+
+ /// @return <TRUE/> if string or empty or empty path, in fact non-value.
+ BOOL IsString( SCSIZE nC, SCSIZE nR ) const
+ {
+ ValidColRowReplicated( nC, nR );
+ return mnValType && IsNonValueType( mnValType[ nC * nRowCount + nR ]);
+ }
+
+ /// @return <TRUE/> if empty or empty path.
+ BOOL IsEmpty( SCSIZE nIndex ) const
+ { return mnValType && ((mnValType[nIndex] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); }
+
+ /// @return <TRUE/> if empty or empty path.
+ BOOL IsEmpty( SCSIZE nC, SCSIZE nR ) const
+ {
+ ValidColRowReplicated( nC, nR );
+ return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY);
+ }
+
+ /// @return <TRUE/> if empty path.
+ BOOL IsEmptyPath( SCSIZE nC, SCSIZE nR ) const
+ {
+ ValidColRowReplicated( nC, nR );
+ return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTYPATH) == SC_MATVAL_EMPTYPATH);
+ }
+
+ /// @return <TRUE/> if empty path.
+ BOOL IsEmptyPath( SCSIZE nIndex ) const
+ { return mnValType && ((mnValType[nIndex] & SC_MATVAL_EMPTYPATH) == SC_MATVAL_EMPTYPATH); }
+
+ /// @return <TRUE/> if value or boolean.
+ BOOL IsValue( SCSIZE nIndex ) const
+ { return !mnValType || IsValueType( mnValType[nIndex]); }
+
+ /// @return <TRUE/> if value or boolean.
+ BOOL IsValue( SCSIZE nC, SCSIZE nR ) const
+ {
+ ValidColRowReplicated( nC, nR );
+ return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]);
+ }
+
+ /// @return <TRUE/> if value or boolean or empty or empty path.
+ BOOL IsValueOrEmpty( SCSIZE nIndex ) const
+ { return !mnValType || IsValueType( mnValType[nIndex] ) ||
+ ((mnValType[nIndex] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); }
+
+ /// @return <TRUE/> if value or boolean or empty or empty path.
+ BOOL IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const
+ {
+ ValidColRowReplicated( nC, nR );
+ return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]) ||
+ ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTY) ==
+ SC_MATVAL_EMPTY);
+ }
+
+ /// @return <TRUE/> if boolean.
+ BOOL IsBoolean( SCSIZE nIndex ) const
+ { return mnValType && IsBooleanType( mnValType[nIndex]); }
+
+ /// @return <TRUE/> if boolean.
+ BOOL IsBoolean( SCSIZE nC, SCSIZE nR ) const
+ {
+ ValidColRowReplicated( nC, nR );
+ return mnValType && IsBooleanType( mnValType[ nC * nRowCount + nR ]);
+ }
+
+ /// @return <TRUE/> if entire matrix is numeric, including booleans, with no strings or empties
+ BOOL IsNumeric() const
+ { return 0 == mnNonValue; }
+
+ void MatTrans( ScMatrix& mRes) const;
+ void MatCopy ( ScMatrix& mRes) const;
+
+//UNUSED2009-05 /** Copy upper left of this matrix to mRes matrix.
+//UNUSED2009-05 This matrix's dimensions must be greater or equal to the mRes matrix
+//UNUSED2009-05 dimensions.
+//UNUSED2009-05 */
+//UNUSED2009-05 void MatCopyUpperLeft( ScMatrix& mRes) const;
+
+ // Convert ScInterpreter::CompareMat values (-1,0,1) to boolean values
+ void CompareEqual();
+ void CompareNotEqual();
+ void CompareLess();
+ void CompareGreater();
+ void CompareLessEqual();
+ void CompareGreaterEqual();
+
+ double And(); // logical AND of all matrix values, or NAN
+ double Or(); // logical OR of all matrix values, or NAN
+
+ // All other matrix functions MatMult, MInv, ... are in ScInterpreter
+ // to be numerically safe.
+};
+
+
+typedef formula::SimpleIntrusiveReference< class ScMatrix > ScMatrixRef;
+typedef formula::SimpleIntrusiveReference< const class ScMatrix > ScConstMatrixRef;
+
+
+#endif // SC_MATRIX_HXX