[Libreoffice-commits] core.git: Branch 'feature/calc-group-interpreter-2' - 11 commits - formula/source include/formula sc/inc sc/source
Kohei Yoshida
kohei.yoshida at collabora.com
Tue Sep 10 06:40:05 PDT 2013
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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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.yoshida at 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;
More information about the Libreoffice-commits
mailing list