formula/source/core/api/vectortoken.cxx | 2 include/formula/vectortoken.hxx | 4 sc/inc/document.hxx | 7 + sc/inc/formulacell.hxx | 1 sc/inc/formulagroup.hxx | 7 + sc/inc/formularesult.hxx | 1 sc/inc/table.hxx | 2 sc/source/core/data/column2.cxx | 173 ++++++++++++++++++++++++------- sc/source/core/data/document.cxx | 9 + sc/source/core/data/formulacell.cxx | 39 ++++++ sc/source/core/data/table1.cxx | 15 ++ sc/source/core/opencl/formulagroupcl.cxx | 33 +++-- sc/source/core/tool/formulagroup.cxx | 142 ++++++++++++++++++++++++- sc/source/core/tool/formularesult.cxx | 49 ++++++++ sc/source/core/tool/interpr6.cxx | 2 15 files changed, 422 insertions(+), 64 deletions(-)
New commits: commit 30f2a24ba7f1a0e1a39ab7491013615a25080909 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Tue Sep 10 09:17:12 2013 -0400 Oops I forgot a return statement. Change-Id: Ifdea804b178ccf5c25ef21fba2642f31a90e4061 diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index cf8c4fd..e6fa7c4 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1024,7 +1024,7 @@ SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const if (!pTab) return -1; - pTab->GetLastDataRow(nCol1, nCol2); + return pTab->GetLastDataRow(nCol1, nCol2); } // connected area commit 0ff9cdec746c016002fa55c62be76dffc1ceca28 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Tue Sep 10 00:11:13 2013 -0400 Fix several logic errors in required array size calculation. Change-Id: Ife05e21583d14c873d38c09d78e964cdb3817d6c diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 1954ffe..0a66ddc 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -3446,7 +3446,7 @@ public: case svDoubleRef: { ScComplexRefData aRef = pToken->GetDoubleRef(); - ScRange aAbs = aRef.toAbs(mrCell.aPos); + ScRange aAbs = aRef.toAbs(mrPos); // Check for self reference. if (aRef.Ref1.IsRowRel()) @@ -3472,12 +3472,16 @@ public: size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1; std::vector<formula::VectorRefArray> aArrays; aArrays.reserve(nCols); - SCROW nArrayLength = nLen; SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1; + SCROW nArrayLength = nRefRowSize; if (!bAbsLast) { // range end position is relative. Extend the array length. - nArrayLength += nRefRowSize - 1; + SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row(); + SCROW nLastRefRow = mrPos.Row() + nLen - 1 + nLastRefRowOffset; + SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1; + if (nNewLength > nArrayLength) + nArrayLength = nNewLength; } // Trim trailing empty rows. diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 5dff3d9..1dbe5bd 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -204,9 +204,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres nRowEnd += i; size_t nRowSize = nRowEnd - nRowStart + 1; ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize)); - if (p2->GetArrayLength() < nRowSize) - // Data array is shorter than the row size of the reference. Truncate it. - nRowSize = p2->GetArrayLength(); + + size_t nDataRowEnd = p2->GetArrayLength() - 1; + if (nRowStart > nDataRowEnd) + // Referenced rows are all empty. + nRowSize = 0; + else if (nRowEnd > nDataRowEnd) + // Data array is shorter than the row size of the reference. Truncate it to the data. + nRowSize -= nRowEnd - nDataRowEnd; for (size_t nCol = 0; nCol < nColSize; ++nCol) { commit 0a61d4af7502f1e0274b71cda0b40778ab51d742 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 23:14:19 2013 -0400 Trim data array length to remove trailing empty rows. Change-Id: I61a6a289ad1c2c757fcea490ada5d40fee08e840 diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index b6491cc..29fe96c 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1023,6 +1023,13 @@ public: SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const; + /** + * Return the last non-empty row position in given columns, or 0 if the + * columns are empty. A negative value is returned if the given sheet or + * column positions are invalid. + */ + SCROW GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const; + SC_DLLPUBLIC void GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const; SC_DLLPUBLIC bool GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const; diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index d36e183..205df2c 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -470,6 +470,8 @@ public: bool ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const; + SCROW GetLastDataRow( SCCOL nCol1, SCCOL nCol2 ) const; + SCSIZE GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const; diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 7bf5c66..cf8c4fd 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1018,6 +1018,15 @@ bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStar return maTabs[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly); } +SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const +{ + const ScTable* pTab = FetchTable(nTab); + if (!pTab) + return -1; + + pTab->GetLastDataRow(nCol1, nCol2); +} + // connected area void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 0ed8f9c..1954ffe 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -3368,6 +3368,18 @@ class GroupTokenConverter return true; } + + SCROW trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen) + { + SCROW nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2); + if (nLastRow < (nRow + nRowLen - 1)) + nRowLen = nLastRow - nRow + 1; + else if (nLastRow == 0) + // Column is empty. + nRowLen = 1; + + return nRowLen; + } public: GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) : mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {} @@ -3403,6 +3415,9 @@ public: if (isSelfReferenceRelative(aRefPos, aRef.Row())) return false; + // Trim data array length to actual data range. + nLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen); + // Fetch double array guarantees that the length of the // returned array equals or greater than the requested // length. @@ -3465,6 +3480,9 @@ public: nArrayLength += nRefRowSize - 1; } + // Trim trailing empty rows. + nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength); + for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i) { aRefPos.SetCol(i); diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 6391eee..9af12d6 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -987,6 +987,21 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow))); } +SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2 ) const +{ + if (!ValidCol(nCol1) || !ValidCol(nCol2)) + return -1; + + SCROW nLastRow = 0; + for (SCCOL i = nCol1; i <= nCol2; ++i) + { + SCROW nThis = aCol[i].GetLastDataPos(); + if (nLastRow < nThis) + nLastRow = nThis; + } + + return nLastRow; +} SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const commit 5bc696ffe0282a5a8fd77580d6193d0f492177d1 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 20:39:17 2013 -0400 Eliminate (almost) duplicate code blocks. Change-Id: Ib5d0fae3efda6bde056f7e4990de57c8b3541549 diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index b6c443f..c846d62 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2076,6 +2076,26 @@ void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nR namespace { +template<typename _Blk> +void getBlockIterators( + sc::CellStoreType::iterator it, size_t& rLenRemain, + typename _Blk::iterator& rData, typename _Blk::iterator& rDataEnd ) +{ + rData = _Blk::begin(*it->data); + if (rLenRemain >= it->size) + { + // Block is shorter than the remaining requested length. + rDataEnd = _Blk::end(*it->data); + rLenRemain -= it->size; + } + else + { + rDataEnd = rData; + std::advance(rDataEnd, rLenRemain); + rLenRemain = 0; + } +} + bool appendDouble( sc::FormulaGroupContext::NumArrayType& rArray, size_t nLen, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd ) @@ -2090,20 +2110,8 @@ bool appendDouble( { case sc::element_type_numeric: { - sc::numeric_block::iterator itData = sc::numeric_block::begin(*it->data); - sc::numeric_block::iterator itDataEnd; - if (nLenRemain >= it->size) - { - // Block is shorter than the remaining requested length. - itDataEnd = sc::numeric_block::end(*it->data); - nLenRemain -= it->size; - } - else - { - itDataEnd = itData; - std::advance(itDataEnd, nLenRemain); - nLenRemain = 0; - } + sc::numeric_block::iterator itData, itDataEnd; + getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd); for (; itData != itDataEnd; ++itData) rArray.push_back(*itData); @@ -2111,20 +2119,8 @@ bool appendDouble( break; case sc::element_type_formula: { - sc::formula_block::iterator itData = sc::formula_block::begin(*it->data); - sc::formula_block::iterator itDataEnd; - if (nLenRemain >= it->size) - { - // Block is shorter than the remaining requested length. - itDataEnd = sc::formula_block::end(*it->data); - nLenRemain -= it->size; - } - else - { - itDataEnd = itData; - std::advance(itDataEnd, nLenRemain); - nLenRemain = 0; - } + sc::formula_block::iterator itData, itDataEnd; + getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd); sal_uInt16 nErr; double fVal; @@ -2187,20 +2183,8 @@ bool appendStrings( { case sc::element_type_string: { - sc::string_block::iterator itData = sc::string_block::begin(*it->data); - sc::string_block::iterator itDataEnd; - if (nLenRemain >= it->size) - { - // Block is shorter than the remaining requested length. - itDataEnd = sc::string_block::end(*it->data); - nLenRemain -= it->size; - } - else - { - itDataEnd = itData; - std::advance(itDataEnd, nLenRemain); - nLenRemain = 0; - } + sc::string_block::iterator itData, itDataEnd; + getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd); for (; itData != itDataEnd; ++itData) rArray.push_back(rCxt.intern(*itData)); @@ -2208,20 +2192,8 @@ bool appendStrings( break; case sc::element_type_edittext: { - sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data); - sc::edittext_block::iterator itDataEnd; - if (nLenRemain >= it->size) - { - // Block is shorter than the remaining requested length. - itDataEnd = sc::edittext_block::end(*it->data); - nLenRemain -= it->size; - } - else - { - itDataEnd = itData; - std::advance(itDataEnd, nLenRemain); - nLenRemain = 0; - } + sc::edittext_block::iterator itData, itDataEnd; + getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd); for (; itData != itDataEnd; ++itData) { @@ -2232,20 +2204,8 @@ bool appendStrings( break; case sc::element_type_formula: { - sc::formula_block::iterator itData = sc::formula_block::begin(*it->data); - sc::formula_block::iterator itDataEnd; - if (nLenRemain >= it->size) - { - // Block is shorter than the remaining requested length. - itDataEnd = sc::formula_block::end(*it->data); - nLenRemain -= it->size; - } - else - { - itDataEnd = itData; - std::advance(itDataEnd, nLenRemain); - nLenRemain = 0; - } + sc::formula_block::iterator itData, itDataEnd; + getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd); sal_uInt16 nErr; OUString aStr; commit b9a52c39a3077265ff69a72d908cb6991430fad8 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 19:36:30 2013 -0400 Support fetching string array that spans over multiple blocks. Change-Id: I543fca231e0be886159b8ddbd83ceffa1bf69c1b diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 985aebe..d2d1db7 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -253,6 +253,7 @@ public: sal_uInt16 GetErrCode(); // interpret first if necessary sal_uInt16 GetRawError(); // don't interpret, just return code or result error bool GetErrorOrValue( sal_uInt16& rErr, double& rVal ); + bool GetErrorOrString( sal_uInt16& rErr, OUString& rStr ); sal_uInt8 GetMatrixFlag() const; ScTokenArray* GetCode(); const ScTokenArray* GetCode() const; diff --git a/sc/inc/formularesult.hxx b/sc/inc/formularesult.hxx index f1f7b5d..2459bcf 100644 --- a/sc/inc/formularesult.hxx +++ b/sc/inc/formularesult.hxx @@ -135,6 +135,7 @@ public: bool IsMultiline() const; bool GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const; + bool GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) const; /** Get error code if set or GetCellResultType() is formula::svError or svUnknown, else 0. */ diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 65e994e..b6c443f 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2174,6 +2174,138 @@ bool appendDouble( return false; } +bool appendStrings( + sc::FormulaGroupContext& rCxt, ScDocument* pDoc, + sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, + sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd ) +{ + size_t nLenRemain = nLen; + + for (; it != itEnd; ++it) + { + switch (it->type) + { + case sc::element_type_string: + { + sc::string_block::iterator itData = sc::string_block::begin(*it->data); + sc::string_block::iterator itDataEnd; + if (nLenRemain >= it->size) + { + // Block is shorter than the remaining requested length. + itDataEnd = sc::string_block::end(*it->data); + nLenRemain -= it->size; + } + else + { + itDataEnd = itData; + std::advance(itDataEnd, nLenRemain); + nLenRemain = 0; + } + + for (; itData != itDataEnd; ++itData) + rArray.push_back(rCxt.intern(*itData)); + } + break; + case sc::element_type_edittext: + { + sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data); + sc::edittext_block::iterator itDataEnd; + if (nLenRemain >= it->size) + { + // Block is shorter than the remaining requested length. + itDataEnd = sc::edittext_block::end(*it->data); + nLenRemain -= it->size; + } + else + { + itDataEnd = itData; + std::advance(itDataEnd, nLenRemain); + nLenRemain = 0; + } + + for (; itData != itDataEnd; ++itData) + { + OUString aStr = ScEditUtil::GetString(**itData, pDoc); + rArray.push_back(rCxt.intern(aStr)); + } + } + break; + case sc::element_type_formula: + { + sc::formula_block::iterator itData = sc::formula_block::begin(*it->data); + sc::formula_block::iterator itDataEnd; + if (nLenRemain >= it->size) + { + // Block is shorter than the remaining requested length. + itDataEnd = sc::formula_block::end(*it->data); + nLenRemain -= it->size; + } + else + { + itDataEnd = itData; + std::advance(itDataEnd, nLenRemain); + nLenRemain = 0; + } + + sal_uInt16 nErr; + OUString aStr; + for (; itData != itDataEnd; ++itData) + { + ScFormulaCell& rFC = **itData; + if (!rFC.GetErrorOrString(nErr, aStr) || nErr) + { + if (nErr == ScErrorCodes::errCircularReference) + { + // This cell needs to be recalculated on next visit. + rFC.SetErrCode(0); + rFC.SetDirtyVar(); + } + return false; + } + + rArray.push_back(rCxt.intern(aStr)); + } + } + break; + case sc::element_type_empty: + { + // Fill it with NULL pointers. + if (nLenRemain >= it->size) + { + rArray.resize(rArray.size() + it->size, NULL); + nLenRemain -= it->size; + } + else + { + rArray.resize(rArray.size() + nLenRemain, NULL); + nLenRemain = 0; + } + } + break; + case sc::element_type_numeric: + default: + return false; + } + + if (!nLenRemain) + return true; + } + + return false; +} + +void copyFirstBlock( sc::FormulaGroupContext& rCxt, size_t nLen, const sc::CellStoreType::position_type& rPos ) +{ + rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType); + sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back(); + rArray.reserve(nLen); + + const OUString* p = &sc::string_block::at(*rPos.first->data, rPos.second); + const OUString* pEnd = p + nLen; + for (; p != pEnd; ++p) + rArray.push_back(rCxt.intern(*p)); +} + } formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 ) @@ -2282,20 +2414,20 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& if (nLenRequested <= nLen) { // Requested length fits a single block. - rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType); + copyFirstBlock(rCxt, nLenRequested, aPos); sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back(); - rArray.reserve(nLenRequested); - - const OUString* p = &sc::string_block::at(*aPos.first->data, aPos.second); - const OUString* pEnd = p + nLenRequested; - for (; p != pEnd; ++p) - rArray.push_back(rCxt.intern(*p)); - return formula::VectorRefArray(&rArray[0]); } - // TODO: handle cases where the requested length goes beyond the - // current block just like we do with numeric array. + copyFirstBlock(rCxt, nLen, aPos); + sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back(); + + // Fill the remaining array with values from the following blocks. + ++aPos.first; + if (!appendStrings(rCxt, pDocument, rArray, nLenRequested - nLen, aPos.first, maCells.end())) + return formula::VectorRefArray(); + + return formula::VectorRefArray(&rArray[0]); } break; case sc::element_type_empty: diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 1c74667..0ed8f9c 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2091,6 +2091,17 @@ bool ScFormulaCell::GetErrorOrValue( sal_uInt16& rErr, double& rVal ) return aResult.GetErrorOrDouble(rErr, rVal); } +bool ScFormulaCell::GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) +{ + MaybeInterpret(); + + rErr = pCode->GetCodeError(); + if (rErr) + return true; + + return aResult.GetErrorOrString(rErr, rStr); +} + bool ScFormulaCell::HasOneReference( ScRange& r ) const { pCode->Reset(); diff --git a/sc/source/core/tool/formularesult.cxx b/sc/source/core/tool/formularesult.cxx index 77de2ae..c232a31 100644 --- a/sc/source/core/tool/formularesult.cxx +++ b/sc/source/core/tool/formularesult.cxx @@ -255,6 +255,19 @@ inline bool isValue( formula::StackVar sv ) || sv == formula::svEmptyCell || sv == formula::svHybridValueCell; } +inline bool isString( formula::StackVar sv ) +{ + switch (sv) + { + case formula::svString: + case formula::svHybridCell: + case formula::svHybridValueCell: + return true; + } + + return false; +} + } bool ScFormulaResult::IsValue() const @@ -321,6 +334,42 @@ bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const return true; } +bool ScFormulaResult::GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) const +{ + if (mnError) + { + rErr = mnError; + return true; + } + + formula::StackVar sv = GetCellResultType(); + if (sv == formula::svError) + { + if (GetType() == formula::svMatrixCell) + { + // don't need to test for mpToken here, GetType() already did it + rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)-> + GetUpperLeftToken()->GetError(); + } + else if (mpToken) + { + rErr = mpToken->GetError(); + } + } + + if (rErr) + return true; + + if (!mbToken) + return false; + + if (!isString(sv)) + return false; + + rStr = GetString(); + return true; +} + sal_uInt16 ScFormulaResult::GetResultError() const { if (mnError) commit 9ade2bcd4a5e811c779f86fc073d11e923c9ca2d Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 18:53:33 2013 -0400 Move common code blocks to a function. Change-Id: I1b1aaa0b1dd8cc6e14fbac1981c67a8b63c92c2c diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 0b37b97..5dff3d9 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -83,6 +83,18 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen ) } } +void flushSegment( + ScMatrix& rMat, size_t nCol, rtl_uString** pHead, rtl_uString** pCur, rtl_uString** pTop ) +{ + size_t nOffset = pHead - pTop; + std::vector<OUString> aStrs; + aStrs.reserve(pCur - pHead); + for (; pHead != pCur; ++pHead) + aStrs.push_back(OUString(*pHead)); + + rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset); +} + void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen ) { rtl_uString** p = pStrs; @@ -102,13 +114,7 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen ) if (pHead) { // Flush this non-empty segment to the matrix. - size_t nOffset = pHead - pStrs; - std::vector<OUString> aStrs; - aStrs.reserve(p - pHead); - for (; pHead != p; ++pHead) - aStrs.push_back(OUString(*pHead)); - - rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset); + flushSegment(rMat, nCol, pHead, p, pStrs); pHead = NULL; } } @@ -116,13 +122,7 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen ) if (pHead) { // Flush last non-empty segment to the matrix. - size_t nOffset = pHead - pStrs; - std::vector<OUString> aStrs; - aStrs.reserve(p - pHead); - for (; pHead != p; ++pHead) - aStrs.push_back(OUString(*pHead)); - - rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset); + flushSegment(rMat, nCol, pHead, p, pStrs); } } commit 1b9796d19f21d5fb5a9c8aadf8db8c0799c688da Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 18:00:08 2013 -0400 Correctly handle empty cells for string arrays too. Because we need to make a distinction between an empty cell and a string cell containing zero-length string, I decided to switch to using rtl_uString* array and use NULL values as empty cells. Change-Id: I5bedb593507f34782e41a8a900602d445e5b1f6f diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx index 557e0c0..b752f5d 100644 --- a/formula/source/core/api/vectortoken.cxx +++ b/formula/source/core/api/vectortoken.cxx @@ -13,7 +13,7 @@ namespace formula { VectorRefArray::VectorRefArray() : mpNumericArray(NULL), mbNumeric(true) {} VectorRefArray::VectorRefArray( const double* pArray ) : mpNumericArray(pArray), mbNumeric(true) {} -VectorRefArray::VectorRefArray( const OUString* pArray ) : mpStringArray(pArray), mbNumeric(false) {} +VectorRefArray::VectorRefArray( rtl_uString** pArray ) : mpStringArray(pArray), mbNumeric(false) {} SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) : FormulaToken(svSingleVectorRef, ocPush), maArray(pArray), mnArrayLength(nLength) {} diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx index 5186ca5..9bc82f3 100644 --- a/include/formula/vectortoken.hxx +++ b/include/formula/vectortoken.hxx @@ -18,14 +18,14 @@ struct FORMULA_DLLPUBLIC VectorRefArray { union { const double* mpNumericArray; - const OUString* mpStringArray; + rtl_uString** mpStringArray; }; bool mbNumeric; VectorRefArray(); VectorRefArray( const double* pArray ); - VectorRefArray( const OUString* pArray ); + VectorRefArray( rtl_uString** pArray ); }; /** diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx index 776b24d..f57b237 100644 --- a/sc/inc/formulagroup.hxx +++ b/sc/inc/formulagroup.hxx @@ -15,6 +15,7 @@ #include <boost/noncopyable.hpp> #include <boost/ptr_container/ptr_vector.hpp> +#include <boost/unordered_set.hpp> class ScDocument; class ScTokenArray; @@ -23,13 +24,17 @@ namespace sc { struct FormulaGroupContext : boost::noncopyable { + typedef boost::unordered_set<OUString, OUStringHash> StrHashType; typedef std::vector<double> NumArrayType; - typedef std::vector<OUString> StrArrayType; + typedef std::vector<rtl_uString*> StrArrayType; typedef boost::ptr_vector<NumArrayType> NumArrayStoreType; typedef boost::ptr_vector<StrArrayType> StrArrayStoreType; + StrHashType maStrPool; NumArrayStoreType maNumArrays; StrArrayStoreType maStrArrays; + + rtl_uString* intern( const OUString& rStr ); }; /** diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 7458426..65e994e 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2282,8 +2282,16 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& if (nLenRequested <= nLen) { // Requested length fits a single block. + rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType); + sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back(); + rArray.reserve(nLenRequested); + const OUString* p = &sc::string_block::at(*aPos.first->data, aPos.second); - return formula::VectorRefArray(p); + const OUString* pEnd = p + nLenRequested; + for (; p != pEnd; ++p) + rArray.push_back(rCxt.intern(*p)); + + return formula::VectorRefArray(&rArray[0]); } // TODO: handle cases where the requested length goes beyond the diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index f6a1dff..0b37b97 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -29,6 +29,23 @@ namespace sc { +rtl_uString* FormulaGroupContext::intern( const OUString& rStr ) +{ + StrHashType::iterator it = maStrPool.find(rStr); + if (it == maStrPool.end()) + { + // Not yet in the pool. + std::pair<StrHashType::iterator, bool> r = maStrPool.insert(rStr.intern()); + if (!r.second) + // Insertion failed. + return NULL; + + it = r.first; + } + + return it->pData; +} + namespace { /** @@ -63,7 +80,49 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen ) { // Flush last non-NaN segment to the matrix. rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums); - pHead = NULL; + } +} + +void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen ) +{ + rtl_uString** p = pStrs; + rtl_uString** pEnd = p + nLen; + rtl_uString** pHead = NULL; + for (; p != pEnd; ++p) + { + if (*p) + { + if (!pHead) + // Store the first non-empty string position. + pHead = p; + + continue; + } + + if (pHead) + { + // Flush this non-empty segment to the matrix. + size_t nOffset = pHead - pStrs; + std::vector<OUString> aStrs; + aStrs.reserve(p - pHead); + for (; pHead != p; ++pHead) + aStrs.push_back(OUString(*pHead)); + + rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset); + pHead = NULL; + } + } + + if (pHead) + { + // Flush last non-empty segment to the matrix. + size_t nOffset = pHead - pStrs; + std::vector<OUString> aStrs; + aStrs.reserve(p - pHead); + for (; pHead != p; ++pHead) + aStrs.push_back(OUString(*pHead)); + + rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset); } } @@ -124,7 +183,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres aCode2.AddDouble(fVal); } else - aCode2.AddString(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpStringArray[i] : OUString()); + { + rtl_uString* pStr = NULL; + if (static_cast<size_t>(i) < p2->GetArrayLength()) + pStr = rArray.mpStringArray[i]; + + if (pStr) + aCode2.AddString(OUString(pStr)); + } } break; case formula::svDoubleVectorRef: @@ -138,6 +204,10 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres nRowEnd += i; size_t nRowSize = nRowEnd - nRowStart + 1; ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize)); + if (p2->GetArrayLength() < nRowSize) + // Data array is shorter than the row size of the reference. Truncate it. + nRowSize = p2->GetArrayLength(); + for (size_t nCol = 0; nCol < nColSize; ++nCol) { const formula::VectorRefArray& rArray = rArrays[nCol]; @@ -149,9 +219,9 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres } else { - const OUString* pStrs = rArray.mpStringArray; + rtl_uString** pStrs = rArray.mpStringArray; pStrs += nRowStart; - pMat->PutString(pStrs, nRowSize, nCol, 0); + fillMatrix(*pMat, nCol, pStrs, nRowSize); } } commit 53252a2a17735a363df64fe8f8846ce8a7cbc82a Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 15:32:25 2013 -0400 Do the same for range vector tokens. Change-Id: Id80f76dbe575fc6b279dafbfc524a9230755ddc8 diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 9ec3e16..7458426 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2294,8 +2294,10 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& { if (nLenRequested <= nLen) { - // Fill the whole length with zero. - rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLenRequested, 0.0)); + // Fill the whole length with NaN's. + double fNan; + rtl::math::setNan(&fNan); + rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLenRequested, fNan)); return formula::VectorRefArray(&rCxt.maNumArrays.back()[0]); } diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index ca888dc..f6a1dff 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -29,6 +29,46 @@ namespace sc { +namespace { + +/** + * Input double array consists of segments of NaN's and normal values. + * Insert only the normal values into the matrix while skipping the NaN's. + */ +void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen ) +{ + const double* p = pNums; + const double* pEnd = p + nLen; + const double* pHead = NULL; + for (; p != pEnd; ++p) + { + if (!rtl::math::isNan(*p)) + { + if (!pHead) + // Store the first non-NaN position. + pHead = p; + + continue; + } + + if (pHead) + { + // Flush this non-NaN segment to the matrix. + rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums); + pHead = NULL; + } + } + + if (pHead) + { + // Flush last non-NaN segment to the matrix. + rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums); + pHead = NULL; + } +} + +} + ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/) { return ScMatrixRef(); @@ -97,7 +137,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres if (!p2->IsEndFixed()) nRowEnd += i; size_t nRowSize = nRowEnd - nRowStart + 1; - ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize, 0.0)); + ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize)); for (size_t nCol = 0; nCol < nColSize; ++nCol) { const formula::VectorRefArray& rArray = rArrays[nCol]; @@ -105,7 +145,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres { const double* pNums = rArray.mpNumericArray; pNums += nRowStart; - pMat->PutDouble(pNums, nRowSize, nCol, 0); + fillMatrix(*pMat, nCol, pNums, nRowSize); } else { commit f9ca9ea3daa8699932ac0cdd5bd2641dd72c7895 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 14:24:10 2013 -0400 Correctly handle empty cells in group calculation (software interpreter). Store NaN's to represent empty cells rather than storing 0's. Storing 0's would mess up COUNT(), for example. Change-Id: I8e350e1fe31358b844dd44451ed8659172fda1cb diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 2098921..9ec3e16 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2081,6 +2081,9 @@ bool appendDouble( sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd ) { size_t nLenRemain = nLen; + double fNan; + rtl::math::setNan(&fNan); + for (; it != itEnd; ++it) { switch (it->type) @@ -2145,15 +2148,15 @@ bool appendDouble( break; case sc::element_type_empty: { - // Fill it with 0's. + // Fill it with NaN's. if (nLenRemain >= it->size) { - rArray.resize(rArray.size() + it->size, 0); + rArray.resize(rArray.size() + it->size, fNan); nLenRemain -= it->size; } else { - rArray.resize(rArray.size() + nLenRemain, 0); + rArray.resize(rArray.size() + nLenRemain, fNan); nLenRemain = 0; } } diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 6c930e5..ca888dc 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -50,6 +50,9 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres aResults.reserve(xGroup->mnLength); CachedTokensType aCachedTokens; + double fNan; + rtl::math::setNan(&fNan); + for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow()) { ScTokenArray aCode2; @@ -70,7 +73,16 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p); const formula::VectorRefArray& rArray = p2->GetArray(); if (rArray.mbNumeric) - aCode2.AddDouble(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpNumericArray[i] : 0.0); + { + double fVal = fNan; + if (static_cast<size_t>(i) < p2->GetArrayLength()) + fVal = rArray.mpNumericArray[i]; + + if (rtl::math::isNan(fVal)) + aCode2.AddToken(ScEmptyCellToken(false, false)); + else + aCode2.AddDouble(fVal); + } else aCode2.AddString(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpStringArray[i] : OUString()); } diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx index 4dbbf1d..470c8d8 100644 --- a/sc/source/core/tool/interpr6.cxx +++ b/sc/source/core/tool/interpr6.cxx @@ -880,7 +880,7 @@ void ScInterpreter::ScCount() while (nParamCount-- > 0) { - switch (GetStackType()) + switch (GetRawStackType()) { case svString: { commit d2e74b9b4fd1f757f2f3a3c6e4ce36e0054ec302 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 11:05:03 2013 -0400 The OpenCL interpreter doesn't have to be a child class of the S/W one. Change-Id: Idcc28b98fceaffdc8947410fef5fadbae462450b diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx index 383dcad..33eb834 100644 --- a/sc/source/core/opencl/formulagroupcl.cxx +++ b/sc/source/core/opencl/formulagroupcl.cxx @@ -104,7 +104,7 @@ public: }; -class FormulaGroupInterpreterOpenCL : public FormulaGroupInterpreterSoftware +class FormulaGroupInterpreterOpenCL : public FormulaGroupInterpreter { SourceData *mSrcDataStack[SRCDATASIZE]; unsigned int mnStackPointer,mnDoublePtrCount; @@ -124,7 +124,7 @@ class FormulaGroupInterpreterOpenCL : public FormulaGroupInterpreterSoftware size_t mnRowSize; public: FormulaGroupInterpreterOpenCL() : - FormulaGroupInterpreterSoftware() + FormulaGroupInterpreter() { mnStackPointer = 0; mnpOclEndPos = NULL; @@ -959,6 +959,9 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress /// Special case of formula compiler for groundwatering class FormulaGroupInterpreterGroundwater : public FormulaGroupInterpreterSoftware { + bool interpretCL(ScDocument& rDoc, const ScAddress& rTopPos, + const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode); + public: FormulaGroupInterpreterGroundwater() : FormulaGroupInterpreterSoftware() @@ -972,8 +975,6 @@ public: } virtual ScMatrixRef inverseMatrix(const ScMatrix& /* rMat */) { return ScMatrixRef(); } - virtual bool interpretCL(ScDocument& rDoc, const ScAddress& rTopPos, - const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode); virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode); }; commit 47d76cfdae59c98beec6db4cc273d75a286c85e4 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Mon Sep 9 10:52:42 2013 -0400 Instantiate the software fallback outside of opencl code. Change-Id: I7ec7a951492616abd3c7327b85f09c1e913208ca diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx index daa0dcc..383dcad 100644 --- a/sc/source/core/opencl/formulagroupcl.cxx +++ b/sc/source/core/opencl/formulagroupcl.cxx @@ -1070,18 +1070,18 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd } namespace opencl { - sc::FormulaGroupInterpreter *createFormulaGroupInterpreter() - { - if (getenv("SC_SOFTWARE")) - { - fprintf(stderr, "Create S/W interp\n"); - return new sc::FormulaGroupInterpreterSoftware(); - } - if (getenv("SC_GROUNDWATER")) - return new sc::FormulaGroupInterpreterGroundwater(); - else - return new sc::FormulaGroupInterpreterOpenCL(); - } + +sc::FormulaGroupInterpreter *createFormulaGroupInterpreter() +{ + if (getenv("SC_SOFTWARE")) + return NULL; + + if (getenv("SC_GROUNDWATER")) + return new sc::FormulaGroupInterpreterGroundwater(); + + return new sc::FormulaGroupInterpreterOpenCL(); +} + } // namespace opencl } // namespace sc diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 2ea09c4..6c930e5 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -216,7 +216,10 @@ FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic() msInstance = sc::opencl::createFormulaGroupInterpreter(); #endif if ( !msInstance ) // software fallback + { + fprintf(stderr, "Create S/W interp\n"); msInstance = new sc::FormulaGroupInterpreterSoftware(); + } } return msInstance; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits