Index: inc/scmatrix.hxx =================================================================== RCS file: /cvs/sc/sc/inc/scmatrix.hxx,v retrieving revision 1.11 diff -p -u -r1.11 scmatrix.hxx --- inc/scmatrix.hxx 10 Apr 2008 18:51:53 -0000 1.11 +++ inc/scmatrix.hxx 27 Aug 2008 11:58:16 -0000 @@ -66,27 +66,32 @@ union ScMatrixValue @ATTENTION: optimized for speed and double values. - Matrix elements are NOT initialized after construction! +

Matrix elements are NOT initialized after construction! - 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.

+

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. + +

Methods using nCol/nRow parameters do replicate a single row vector if + nRow > 0 and nCol < nColCount, respectively a column vector if nCol + > 0 and nRow < nRowCount. - GetString( SCSIZE nIndex ) does not check if there really is a string, do - this with IsString() first. GetString( SCSIZE nC, SCSIZE nR ) does check +

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.

+ methods don't check for a string, do this with IsNumeric() or IsString() or + IsValue() first. - 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. +

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. - PutDouble() does not reset an eventual string! Use +

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 ScMatrix { ScMatrixValue* pMat; @@ -115,7 +120,7 @@ class ScMatrix public: - /// The maximum number of elements a matrix may have at runtime + /// The maximum number of elements a matrix may have at runtime. inline static size_t GetElementsMax() { const size_t nMemMax = (((size_t)(~0))-64) / sizeof(ScMatrixValue); @@ -157,9 +162,15 @@ public: 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) { CreateMatrix( nC, nR); } + + /** Clone the matrix. */ ScMatrix* Clone() const; - /// disable refcounting forever, may only be deleted via Delete() afterwards + /** 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 @@ -196,6 +207,45 @@ public: 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; } @@ -262,32 +312,61 @@ public: /// @return if string or empty BOOL IsString( SCSIZE nIndex ) const { return mnValType && IsStringType( mnValType[nIndex]); } + /// @return if string or empty BOOL IsString( SCSIZE nC, SCSIZE nR ) const - { return mnValType && IsStringType( mnValType[ nC * nRowCount + nR ]); } + { + ValidColRowReplicated( nC, nR ); + return mnValType && IsStringType( mnValType[ nC * nRowCount + nR ]); + } + BOOL IsEmpty( SCSIZE nIndex ) const { return mnValType && ((mnValType[nIndex] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); } + BOOL IsEmptyPath( SCSIZE nC, SCSIZE nR ) const - { return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTYPATH) == SC_MATVAL_EMPTYPATH); } + { + ValidColRowReplicated( nC, nR ); + return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTYPATH) == SC_MATVAL_EMPTYPATH); + } + BOOL IsEmptyPath( SCSIZE nIndex ) const { return mnValType && ((mnValType[nIndex] & SC_MATVAL_EMPTYPATH) == SC_MATVAL_EMPTYPATH); } + BOOL IsEmpty( SCSIZE nC, SCSIZE nR ) const - { return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); } + { + ValidColRowReplicated( nC, nR ); + return mnValType && ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); + } + BOOL IsValue( SCSIZE nIndex ) const { return !mnValType || IsValueType( mnValType[nIndex]); } + BOOL IsValue( SCSIZE nC, SCSIZE nR ) const - { return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]); } + { + ValidColRowReplicated( nC, nR ); + return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]); + } + BOOL IsValueOrEmpty( SCSIZE nIndex ) const { return !mnValType || IsValueType( mnValType[nIndex] ) || ((mnValType[nIndex] & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY); } + BOOL IsValueOrEmpty( SCSIZE nC, SCSIZE nR ) const - { return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]) || + { + ValidColRowReplicated( nC, nR ); + return !mnValType || IsValueType( mnValType[ nC * nRowCount + nR ]) || ((mnValType[ nC * nRowCount + nR ] & SC_MATVAL_EMPTY) == - SC_MATVAL_EMPTY); } + SC_MATVAL_EMPTY); + } + BOOL IsBoolean( SCSIZE nIndex ) const { return mnValType && IsBooleanType( mnValType[nIndex]); } + BOOL IsBoolean( SCSIZE nC, SCSIZE nR ) const - { return mnValType && IsBooleanType( mnValType[ nC * nRowCount + nR ]); } + { + ValidColRowReplicated( nC, nR ); + return mnValType && IsBooleanType( mnValType[ nC * nRowCount + nR ]); + } /// @return if entire matrix is numeric, including booleans, with no strings or empties BOOL IsNumeric() const @@ -295,9 +374,11 @@ public: void MatTrans( ScMatrix& mRes) const; void MatCopy ( ScMatrix& mRes) const; + /** Copy upper left of this matrix to mRes matrix. - This matrix's dimensions must be greater than the mRes matrix - dimensions. */ + This matrix's dimensions must be greater or equal to the mRes matrix + dimensions. + */ void MatCopyUpperLeft( ScMatrix& mRes) const; // Convert ScInterpreter::CompareMat values (-1,0,1) to boolean values @@ -320,17 +401,4 @@ typedef ScSimpleIntrusiveReference< clas typedef ScSimpleIntrusiveReference< const class ScMatrix > ScConstMatrixRef; -// Old values as used up to SO52. -// The overall elements count had to be <= SC_MAX_MAT_DIM * SC_MAX_MAT_DIM. -// Don't use except maybe for file format compatibility. -// In any other case use ScMatrix::GetElementsMax() instead. -#ifdef WIN -#define SC_OLD_MAX_MAT_DIM 64 -#else -#define SC_OLD_MAX_MAT_DIM 128 -#endif -#define SC_OLD_MAX_MAT_ELEMENTS ((SC_OLD_MAX_MAT_DIM) * (SC_OLD_MAX_MAT_DIM)) - - -#endif - +#endif // SC_MATRIX_HXX Index: source/core/inc/jumpmatrix.hxx =================================================================== RCS file: /cvs/sc/sc/source/core/inc/jumpmatrix.hxx,v retrieving revision 1.6 diff -p -u -r1.6 jumpmatrix.hxx --- source/core/inc/jumpmatrix.hxx 10 Apr 2008 19:40:01 -0000 1.6 +++ source/core/inc/jumpmatrix.hxx 27 Aug 2008 11:58:17 -0000 @@ -73,6 +73,8 @@ class ScJumpMatrix SCSIZE nRows; SCSIZE nCurCol; SCSIZE nCurRow; + SCSIZE nResMatCols; + SCSIZE nResMatRows; bool bStarted; // not implemented, prevent usage @@ -88,6 +90,8 @@ public: , nRows( nRowsP ) , nCurCol( 0 ) , nCurRow( 0 ) + , nResMatCols( nColsP ) + , nResMatRows( nRowsP ) , bStarted( false ) { // Initialize result matrix in case of @@ -128,6 +132,21 @@ public: short& rStart, short& rNext, short& rStop ) const { + if (nCols == 1 && nRows == 1) + { + nCol = 0; + nRow = 0; + } + else if (nCols == 1 && nRow < nRows) + nCol = 0; + else if (nRows == 1 && nCol < nCols) + nRow = 0; + else if (nCols <= nCol || nRows <= nRow) + { + DBG_ERROR("ScJumpMatrix::GetJump: dimension error"); + nCol = 0; + nRow = 0; + } pJump[ (ULONG)nCol * nRows + nRow ]. GetJump( rBool, rStart, rNext, rStop); } @@ -160,14 +179,45 @@ public: } else { - if ( ++nCurRow >= nRows ) + if ( ++nCurRow >= nResMatRows ) { nCurRow = 0; ++nCurCol; } } GetPos( rCol, rRow ); - return nCurCol < nCols; + return nCurCol < nResMatCols; + } + void GetResMatDimensions( SCSIZE& rCols, SCSIZE& rRows ) + { + rCols = nResMatCols; + rRows = nResMatRows; + } + void SetNewResMat( SCSIZE nNewCols, SCSIZE nNewRows ) + { + if ( nNewCols > nResMatCols || nNewRows > nResMatRows ) + { + pMat = pMat->CloneAndExtend( nNewCols, nNewRows ); + if ( nResMatCols < nNewCols ) + { + pMat->FillDouble( CreateDoubleError( + NOTAVAILABLE), nResMatCols, 0, nNewCols-1, + nResMatRows-1); + } + if ( nResMatRows < nNewRows ) + { + pMat->FillDouble( CreateDoubleError( + NOTAVAILABLE), 0, nResMatRows, nNewCols-1, + nNewRows-1); + } + if ( nRows == 1 && nCurCol != 0 ) + { + nCurCol = 0; + nCurRow = nResMatRows - 1; + } + nResMatCols = nNewCols; + nResMatRows = nNewRows; + } } }; Index: source/core/tool/interpr1.cxx =================================================================== RCS file: /cvs/sc/sc/source/core/tool/interpr1.cxx,v retrieving revision 1.60 diff -p -u -r1.60 interpr1.cxx --- source/core/tool/interpr1.cxx 8 Jul 2008 07:20:44 -0000 1.60 +++ source/core/tool/interpr1.cxx 27 Aug 2008 11:58:18 -0000 @@ -309,6 +309,37 @@ void ScInterpreter::ScChoseJump() } +void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, ScMatrixRef& pResMat, SCSIZE nParmCols, SCSIZE nParmRows ) +{ + SCSIZE nJumpCols, nJumpRows; + SCSIZE nResCols, nResRows; + SCSIZE nAdjustCols, nAdjustRows; + pJumpM->GetDimensions( nJumpCols, nJumpRows ); + pJumpM->GetResMatDimensions( nResCols, nResRows ); + if (( nJumpCols == 1 && nParmCols > nResCols ) || + ( nJumpRows == 1 && nParmRows > nResRows )) + { + if ( nJumpCols == 1 && nJumpRows == 1 ) + { + nAdjustCols = nParmCols > nResCols ? nParmCols : nResCols; + nAdjustRows = nParmRows > nResRows ? nParmRows : nResRows; + } + else if ( nJumpCols == 1 ) + { + nAdjustCols = nParmCols; + nAdjustRows = nResRows; + } + else + { + nAdjustCols = nResCols; + nAdjustRows = nParmRows; + } + pJumpM->SetNewResMat( nAdjustCols, nAdjustRows ); + pResMat = pJumpM->GetResultMatrix(); + } +} + + bool ScInterpreter::JumpMatrix( short nStackLevel ) { pJumpMatrix = pStack[sp-nStackLevel]->GetJumpMatrix(); @@ -404,52 +435,69 @@ bool ScInterpreter::JumpMatrix( short nS double fVal; ScRange aRange; PopDoubleRef( aRange ); - ScAddress& rAdr = aRange.aStart; - ULONG nCol = (ULONG)rAdr.Col() + nC; - ULONG nRow = (ULONG)rAdr.Row() + nR; if ( nGlobalError ) { fVal = CreateDoubleError( nGlobalError ); nGlobalError = 0; pResMat->PutDouble( fVal, nC, nR ); } - else if ( nCol > static_cast(aRange.aEnd.Col()) || - nRow > static_cast(aRange.aEnd.Row())) - { - fVal = CreateDoubleError( errNoValue ); - pResMat->PutDouble( fVal, nC, nR ); - } else { - rAdr.SetCol( static_cast(nCol) ); - rAdr.SetRow( static_cast(nRow) ); - ScBaseCell* pCell = GetCell( rAdr ); - if (HasCellEmptyData( pCell)) - pResMat->PutEmpty( nC, nR ); - else if (HasCellValueData( pCell)) + // Do not modify the original range because we use it + // to adjust the size of the result matrix if necessary. + ScAddress aAdr( aRange.aStart); + ULONG nCol = (ULONG)aAdr.Col() + nC; + ULONG nRow = (ULONG)aAdr.Row() + nR; + if ((nCol > static_cast(aRange.aEnd.Col()) && + aRange.aEnd.Col() != aRange.aStart.Col()) + || (nRow > static_cast(aRange.aEnd.Row()) && + aRange.aEnd.Row() != aRange.aStart.Row())) { - double fCellVal = GetCellValue( rAdr, pCell); - if ( nGlobalError ) - { - fCellVal = CreateDoubleError( - nGlobalError); - nGlobalError = 0; - } - pResMat->PutDouble( fCellVal, nC, nR ); + fVal = CreateDoubleError( NOTAVAILABLE ); + pResMat->PutDouble( fVal, nC, nR ); } else { - String aStr; - GetCellString( aStr, pCell ); - if ( nGlobalError ) + // Replicate column and/or row of a vector if it is + // one. Note that this could be a range reference + // that in fact consists of only one cell, e.g. A1:A1 + if (aRange.aEnd.Col() == aRange.aStart.Col()) + nCol = aRange.aStart.Col(); + if (aRange.aEnd.Row() == aRange.aStart.Row()) + nRow = aRange.aStart.Row(); + aAdr.SetCol( static_cast(nCol) ); + aAdr.SetRow( static_cast(nRow) ); + ScBaseCell* pCell = GetCell( aAdr ); + if (HasCellEmptyData( pCell)) + pResMat->PutEmpty( nC, nR ); + else if (HasCellValueData( pCell)) { - pResMat->PutDouble( CreateDoubleError( - nGlobalError), nC, nR); - nGlobalError = 0; + double fCellVal = GetCellValue( aAdr, pCell); + if ( nGlobalError ) + { + fCellVal = CreateDoubleError( + nGlobalError); + nGlobalError = 0; + } + pResMat->PutDouble( fCellVal, nC, nR ); } else - pResMat->PutString( aStr, nC, nR ); + { + String aStr; + GetCellString( aStr, pCell ); + if ( nGlobalError ) + { + pResMat->PutDouble( CreateDoubleError( + nGlobalError), nC, nR); + nGlobalError = 0; + } + else + pResMat->PutString( aStr, nC, nR ); + } } + SCSIZE nParmCols = aRange.aEnd.Col() - aRange.aStart.Col() + 1; + SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1; + lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nParmCols, nParmRows ); } } break; @@ -472,9 +520,10 @@ bool ScInterpreter::JumpMatrix( short nS { SCSIZE nCols, nRows; pMat->GetDimensions( nCols, nRows ); - if ( nCols <= nC || nRows <= nR ) + if ((nCols <= nC && nCols != 1) || + (nRows <= nR && nRows != 1)) { - fVal = CreateDoubleError( errNoValue ); + fVal = CreateDoubleError( NOTAVAILABLE ); pResMat->PutDouble( fVal, nC, nR ); } else @@ -492,6 +541,7 @@ bool ScInterpreter::JumpMatrix( short nS pResMat->PutString( rStr, nC, nR ); } } + lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nCols, nRows ); } } break; @@ -775,7 +825,9 @@ ScMatrixRef ScInterpreter::CompareMat() { for ( SCSIZE k=0; kValidColRowOrReplicated( nCol, nRow ) && + pMat[1]->ValidColRowOrReplicated( nCol, nRow )) { for ( short i=1; i>=0; i-- ) { Index: source/core/tool/interpr5.cxx =================================================================== RCS file: /cvs/sc/sc/source/core/tool/interpr5.cxx,v retrieving revision 1.33 diff -p -u -r1.33 interpr5.cxx --- source/core/tool/interpr5.cxx 21 Jul 2008 12:03:30 -0000 1.33 +++ source/core/tool/interpr5.cxx 27 Aug 2008 11:58:18 -0000 @@ -1032,6 +1032,23 @@ void ScInterpreter::ScMatTrans() } } + +/** Minimum extent of one result matrix dimension. + For a row or column vector to be replicated the larger matrix dimension is + returned, else the smaller dimension. + */ +inline SCSIZE lcl_GetMinExtent( SCSIZE n1, SCSIZE n2 ) +{ + if (n1 == 1) + return n2; + else if (n2 == 1) + return n1; + else if (n1 < n2) + return n1; + else + return n2; +} + ScMatrixRef ScInterpreter::MatAdd(ScMatrix* pMat1, ScMatrix* pMat2) { SCSIZE nC1, nC2, nMinC; @@ -1039,14 +1056,8 @@ ScMatrixRef ScInterpreter::MatAdd(ScMatr SCSIZE i, j; pMat1->GetDimensions(nC1, nR1); pMat2->GetDimensions(nC2, nR2); - if (nC1 < nC2) - nMinC = nC1; - else - nMinC = nC2; - if (nR1 < nR2) - nMinR = nR1; - else - nMinR = nR2; + nMinC = lcl_GetMinExtent( nC1, nC2); + nMinR = lcl_GetMinExtent( nR1, nR2); ScMatrixRef xResMat = GetNewMat(nMinC, nMinR); if (xResMat) { @@ -1074,14 +1085,8 @@ ScMatrixRef ScInterpreter::MatSub(ScMatr SCSIZE i, j; pMat1->GetDimensions(nC1, nR1); pMat2->GetDimensions(nC2, nR2); - if (nC1 < nC2) - nMinC = nC1; - else - nMinC = nC2; - if (nR1 < nR2) - nMinR = nR1; - else - nMinR = nR2; + nMinC = lcl_GetMinExtent( nC1, nC2); + nMinR = lcl_GetMinExtent( nR1, nR2); ScMatrixRef xResMat = GetNewMat(nMinC, nMinR); if (xResMat) { @@ -1109,14 +1114,8 @@ ScMatrixRef ScInterpreter::MatMul(ScMatr SCSIZE i, j; pMat1->GetDimensions(nC1, nR1); pMat2->GetDimensions(nC2, nR2); - if (nC1 < nC2) - nMinC = nC1; - else - nMinC = nC2; - if (nR1 < nR2) - nMinR = nR1; - else - nMinR = nR2; + nMinC = lcl_GetMinExtent( nC1, nC2); + nMinR = lcl_GetMinExtent( nR1, nR2); ScMatrixRef xResMat = GetNewMat(nMinC, nMinR); if (xResMat) { @@ -1144,14 +1143,8 @@ ScMatrixRef ScInterpreter::MatDiv(ScMatr SCSIZE i, j; pMat1->GetDimensions(nC1, nR1); pMat2->GetDimensions(nC2, nR2); - if (nC1 < nC2) - nMinC = nC1; - else - nMinC = nC2; - if (nR1 < nR2) - nMinR = nR1; - else - nMinR = nR2; + nMinC = lcl_GetMinExtent( nC1, nC2); + nMinR = lcl_GetMinExtent( nR1, nR2); ScMatrixRef xResMat = GetNewMat(nMinC, nMinR); if (xResMat) { @@ -1180,14 +1173,8 @@ ScMatrixRef ScInterpreter::MatPow(ScMatr SCSIZE i, j; pMat1->GetDimensions(nC1, nR1); pMat2->GetDimensions(nC2, nR2); - if (nC1 < nC2) - nMinC = nC1; - else - nMinC = nC2; - if (nR1 < nR2) - nMinR = nR1; - else - nMinR = nR2; + nMinC = lcl_GetMinExtent( nC1, nC2); + nMinR = lcl_GetMinExtent( nR1, nR2); ScMatrixRef xResMat = GetNewMat(nMinC, nMinR); if (xResMat) { @@ -1215,14 +1202,8 @@ ScMatrixRef ScInterpreter::MatConcat(ScM SCSIZE i, j; pMat1->GetDimensions(nC1, nR1); pMat2->GetDimensions(nC2, nR2); - if (nC1 < nC2) - nMinC = nC1; - else - nMinC = nC2; - if (nR1 < nR2) - nMinR = nR1; - else - nMinR = nR2; + nMinC = lcl_GetMinExtent( nC1, nC2); + nMinR = lcl_GetMinExtent( nR1, nR2); ScMatrixRef xResMat = GetNewMat(nMinC, nMinR); if (xResMat) { @@ -3693,11 +3674,13 @@ void ScInterpreter::ScMatRef() const ScMatrix* pMat = pCell->GetMatrix(); if( pMat ) { - SCSIZE nCl, nRw; - pMat->GetDimensions( nCl, nRw ); + SCSIZE nCols, nRows; + pMat->GetDimensions( nCols, nRows ); SCSIZE nC = static_cast(aPos.Col() - aAdr.Col()); SCSIZE nR = static_cast(aPos.Row() - aAdr.Row()); - if (nC < nCl && nR < nRw) + if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1)) + PushNA(); + else { ScMatValType nMatValType; const ScMatrixValue* pMatVal = pMat->Get( nC, nR, nMatValType); @@ -3724,8 +3707,6 @@ void ScInterpreter::ScMatRef() nFuncFmtIndex = nCurFmtIndex; } } - else - PushNA(); } else { Index: source/core/tool/scmatrix.cxx =================================================================== RCS file: /cvs/sc/sc/source/core/tool/scmatrix.cxx,v retrieving revision 1.17 diff -p -u -r1.17 scmatrix.cxx --- source/core/tool/scmatrix.cxx 10 Apr 2008 20:01:15 -0000 1.17 +++ source/core/tool/scmatrix.cxx 27 Aug 2008 11:58:18 -0000 @@ -78,6 +78,14 @@ ScMatrix* ScMatrix::Clone() const return pScMat; } +ScMatrix* ScMatrix::CloneAndExtend( SCSIZE nNewCols, SCSIZE nNewRows ) const +{ + ScMatrix* pScMat = new ScMatrix( nNewCols, nNewRows); + MatCopy(*pScMat); + pScMat->SetErrorInterpreter( pErrorInterpreter); + return pScMat; +} + void ScMatrix::SetErrorAtInterpreter( USHORT nError ) const { if ( pErrorInterpreter ) @@ -399,29 +407,29 @@ void ScMatrix::PutBoolean( bool bVal, SC USHORT ScMatrix::GetError( SCSIZE nC, SCSIZE nR) const { - if (ValidColRow( nC, nR)) + if (ValidColRowOrReplicated( nC, nR )) return GetError( CalcOffset( nC, nR) ); else { DBG_ERRORFILE("ScMatrix::GetError: dimension error"); - return 0; // TODO: do we want an error instead? + return errNoValue; } } double ScMatrix::GetDouble(SCSIZE nC, SCSIZE nR) const { - if (ValidColRow( nC, nR)) + if (ValidColRowOrReplicated( nC, nR )) return GetDouble( CalcOffset( nC, nR) ); else { DBG_ERRORFILE("ScMatrix::GetDouble: dimension error"); - return 0.0; + return CreateDoubleError( errNoValue); } } const String& ScMatrix::GetString(SCSIZE nC, SCSIZE nR) const { - if (ValidColRow( nC, nR)) + if (ValidColRowOrReplicated( nC, nR )) { SCSIZE nIndex = CalcOffset( nC, nR); if ( IsString( nIndex ) ) @@ -474,7 +482,7 @@ String ScMatrix::GetString( SvNumberForm String ScMatrix::GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const { - if (ValidColRow( nC, nR)) + if (ValidColRowOrReplicated( nC, nR )) { SCSIZE nIndex = CalcOffset( nC, nR); return GetString( rFormatter, nIndex); @@ -489,7 +497,7 @@ String ScMatrix::GetString( SvNumberForm const ScMatrixValue* ScMatrix::Get(SCSIZE nC, SCSIZE nR, ScMatValType& nType) const { - if (ValidColRow( nC, nR)) + if (ValidColRowOrReplicated( nC, nR )) { SCSIZE nIndex = CalcOffset( nC, nR); if (mnValType) @@ -508,11 +516,11 @@ const ScMatrixValue* ScMatrix::Get(SCSIZ void ScMatrix::MatCopy(ScMatrix& mRes) const { - if (nColCount != mRes.nColCount || nRowCount != mRes.nRowCount) + if (nColCount > mRes.nColCount || nRowCount > mRes.nRowCount) { DBG_ERRORFILE("ScMatrix::MatCopy: dimension error"); } - else + else if ( nColCount == mRes.nColCount && nRowCount == mRes.nRowCount ) { if (mnValType) { @@ -541,6 +549,41 @@ void ScMatrix::MatCopy(ScMatrix& mRes) c mRes.pMat[i].fVal = pMat[i].fVal; } } + else + { + // Copy this matrix to upper left rectangle of result matrix. + if (mnValType) + { + ScMatValType nType; + mRes.ResetIsString(); + for (SCSIZE i = 0; i < nColCount; i++) + { + SCSIZE nStart = i * nRowCount; + SCSIZE nResStart = i * mRes.nRowCount; + for (SCSIZE j = 0; j < nRowCount; j++) + { + if (IsStringType( (nType = mnValType[nStart+j]))) + mRes.PutStringEntry( pMat[nStart+j].pS, nType, nResStart+j ); + else + { + mRes.pMat[nResStart+j].fVal = pMat[nStart+j].fVal; + mRes.mnValType[nResStart+j] = nType; + } + } + } + } + else + { + mRes.DeleteIsString(); + for (SCSIZE i = 0; i < nColCount; i++) + { + SCSIZE nStart = i * nRowCount; + SCSIZE nResStart = i * mRes.nRowCount; + for (SCSIZE j = 0; j < nRowCount; j++) + mRes.pMat[nResStart+j].fVal = pMat[nStart+j].fVal; + } + } + } } void ScMatrix::MatTrans(ScMatrix& mRes) const