summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/formula/token.hxx8
-rw-r--r--include/formula/types.hxx35
-rw-r--r--sc/inc/column.hxx7
-rw-r--r--sc/inc/document.hxx11
-rw-r--r--sc/inc/formulacell.hxx2
-rw-r--r--sc/inc/table.hxx4
-rw-r--r--sc/inc/token.hxx4
-rw-r--r--sc/inc/types.hxx3
-rw-r--r--sc/source/core/data/column2.cxx70
-rw-r--r--sc/source/core/data/document.cxx16
-rw-r--r--sc/source/core/data/formulacell.cxx126
-rw-r--r--sc/source/core/data/table1.cxx28
12 files changed, 234 insertions, 80 deletions
diff --git a/include/formula/token.hxx b/include/formula/token.hxx
index 3a174d7b9d4f..82bdf7f7acf2 100644
--- a/include/formula/token.hxx
+++ b/include/formula/token.hxx
@@ -27,8 +27,7 @@
#include <tools/mempool.hxx>
#include "formula/IFunctionDescription.hxx"
#include "formula/formuladllapi.h"
-
-#include <boost/intrusive_ptr.hpp>
+#include "formula/types.hxx"
namespace formula
{
@@ -79,11 +78,6 @@ typedef sal_uInt8 StackVar;
typedef StackVarEnum StackVar;
#endif
-
-class FormulaToken;
-typedef ::boost::intrusive_ptr<FormulaToken> FormulaTokenRef;
-typedef ::boost::intrusive_ptr<const FormulaToken> FormulaConstTokenRef;
-
class FormulaTokenArray;
class FORMULA_DLLPUBLIC FormulaToken : public IFormulaToken
diff --git a/include/formula/types.hxx b/include/formula/types.hxx
new file mode 100644
index 000000000000..33ead51620a6
--- /dev/null
+++ b/include/formula/types.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef FORMULA_TYPES_HXX
+#define FORMULA_TYPES_HXX
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace formula {
+
+class FormulaToken;
+typedef ::boost::intrusive_ptr<FormulaToken> FormulaTokenRef;
+typedef ::boost::intrusive_ptr<const FormulaToken> FormulaConstTokenRef;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 866fce3bf113..157bc173e98f 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -25,11 +25,13 @@
#include "address.hxx"
#include "rangenam.hxx"
#include "types.hxx"
-#include <boost/intrusive_ptr.hpp>
+#include "formula/types.hxx"
#include <set>
#include <vector>
+#include <boost/intrusive_ptr.hpp>
+
#define DEBUG_COLUMN_STORAGE 0
#if DEBUG_COLUMN_STORAGE
@@ -448,7 +450,8 @@ public:
size_t GetFormulaHash( SCROW nRow ) const;
ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const;
- bool ResolveVectorReference( SCROW nRow1, SCROW nRow2 );
+ formula::FormulaTokenRef ResolveStaticReference( SCROW nRow );
+ bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 );
ScRefCellValue GetRefCellValue( SCROW );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 052b81d208e9..cdb80e041e95 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -32,6 +32,7 @@
#include "sortparam.hxx"
#include "types.hxx"
#include "formula/grammar.hxx"
+#include "formula/types.hxx"
#include <com/sun/star/chart2/XChartDocument.hpp>
#include "typedstrdata.hxx"
#include "compressedarray.hxx"
@@ -1940,14 +1941,8 @@ public:
ScFormulaVectorState GetFormulaVectorState( const ScAddress& rPos ) const;
- /**
- * Check if the range contains any "dirty" formula cells. In the future
- * we'll use this function to interpret those "dirty" formula cells on
- * demand.
- *
- * @return true if the range is totally clean, false otherwise.
- */
- bool ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow );
+ formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos );
+ formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
private: // CLOOK-Impl-methods
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index e6239e3f2226..397fd9c72fe4 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -282,6 +282,8 @@ public:
*/
void SetResultDouble( double n ) { aResult.SetDouble( n); }
+ double GetResultDouble() const { return aResult.GetDouble(); }
+
void SetErrCode( sal_uInt16 n );
bool IsHyperLinkCell() const;
EditTextObject* CreateURLObject();
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index eb5f7561a1ef..c04b902135d1 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -30,6 +30,7 @@
#include "compressedarray.hxx"
#include "postit.hxx"
#include "types.hxx"
+#include "formula/types.hxx"
#include <set>
#include <map>
@@ -819,7 +820,8 @@ public:
size_t GetFormulaHash( SCCOL nCol, SCROW nRow ) const;
ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
- bool ResolveVectorReference( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
+ formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
+ formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow );
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index a54055561bae..abd3cd5c06cc 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -31,13 +31,11 @@
#include "scdllapi.h"
#include "formula/IFunctionDescription.hxx"
#include "formula/token.hxx"
-
+#include "types.hxx"
class ScJumpMatrix;
-class ScToken;
typedef ::std::vector< ScComplexRefData > ScRefList;
-typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
class SC_DLLPUBLIC ScToken : public formula::FormulaToken
{
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 7227472aa949..1af6e2d73b62 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -17,6 +17,9 @@ class ScMatrix;
typedef ::boost::intrusive_ptr<ScMatrix> ScMatrixRef;
typedef ::boost::intrusive_ptr<const ScMatrix> ScConstMatrixRef;
+class ScToken;
+typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
+
/**
* When vectorization is enabled, we could potentially mass-calculate a
* series of formula token arrays in adjacent formula cells in one step,
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index e95dcf93a6c4..20483f84a4d2 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1589,28 +1589,78 @@ ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
}
-bool ScColumn::ResolveVectorReference( SCROW nRow1, SCROW nRow2 )
+formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
{
std::vector<ColEntry>::iterator itEnd = maItems.end();
// Find first cell whose position is equal or greater than nRow1.
ColEntry aBound;
- aBound.nRow = nRow1;
+ aBound.nRow = nRow;
std::vector<ColEntry>::iterator it =
std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
- if (it == itEnd)
+ if (it == itEnd || it->nRow != nRow)
+ {
+ // Empty cell.
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+ }
+
+ ScBaseCell* pCell = it->pCell;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ ScValueCell* pVC = static_cast<ScValueCell*>(pCell);
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pVC->GetValue()));
+ }
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
+ if (pFC->GetDirty())
+ // Dirty formula cell is not considered static. Return null token.
+ return formula::FormulaTokenRef();
+
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pFC->GetResultDouble()));
+ }
+ default:
+ ;
+ }
+
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+}
+
+bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
+{
+ if (nRow1 > nRow2)
return false;
+ std::vector<ColEntry>::iterator itEnd = maItems.end();
+ // Find first cell whose position is equal or greater than nRow1.
+ ColEntry aBound;
+ aBound.nRow = nRow1;
+ std::vector<ColEntry>::iterator it =
+ std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
+
for (; it != itEnd && it->nRow <= nRow2; ++it)
{
- if (it->pCell->GetCellType() != CELLTYPE_FORMULA)
- // Non-formula cells are fine.
- continue;
+ switch (it->pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ ScValueCell* pVC = static_cast<ScValueCell*>(it->pCell);
+ rMat.PutDouble(pVC->GetValue(), nMatCol, it->nRow - nRow1);
+ }
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
+ if (pFC->GetDirty())
+ // Dirty formula cell is not considered static. Return null token.
+ return false;
- ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
- if (pFC->GetDirty())
- // Dirty formula cells are not supported yet.
- return false;
+ rMat.PutDouble(pFC->GetResultDouble(), nMatCol, it->nRow - nRow1);
+ }
+ default:
+ ;
+ }
}
return true;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 6a00d36d0b6e..9a3dcf7b1668 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1574,13 +1574,23 @@ ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos )
return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
}
-bool ScDocument::ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow )
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
{
SCTAB nTab = rPos.Tab();
if (!TableExists(nTab))
- return false;
+ return formula::FormulaTokenRef();
+
+ return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
+}
+
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
+ return formula::FormulaTokenRef();
- return maTabs[nTab]->ResolveVectorReference(rPos.Col(), rPos.Row(), nEndRow);
+ return maTabs[nTab]->ResolveStaticReference(
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
}
bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e73641d606b0..43d80cf906df 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2954,27 +2954,75 @@ bool ScFormulaCell::InterpretFormulaGroup()
switch (pCode->GetVectorState())
{
case FormulaVectorEnabled:
+ case FormulaVectorCheckReference:
// Good.
break;
- case FormulaVectorCheckReference:
- // To support this we would need a real range-based dependency
- // tracking. We can't support this right now.
- return false;
case FormulaVectorDisabled:
case FormulaVectorUnknown:
default:
+ // Not good.
return false;
}
-// fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() );
-
if (xGroup->mbInvariant)
{
-// fprintf( stderr, "struck gold - completely invariant for %d items !\n",
-// (int)xGroup->mnLength );
+ if (pCode->GetVectorState() == FormulaVectorCheckReference)
+ {
+ // An invariant group should only have absolute references, and no
+ // external references are allowed.
+
+ ScTokenArray aCode;
+ pCode->Reset();
+ for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
+ {
+ const ScToken* pToken = static_cast<const ScToken*>(p);
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rRef = pToken->GetSingleRef();
+ ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab);
+ formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
+ if (!pNewToken)
+ return false;
+
+ aCode.AddToken(*pNewToken);
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rRef = pToken->GetDoubleRef();
+ ScRange aRefRange(
+ rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab,
+ rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab);
+
+ formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
+ if (!pNewToken)
+ return false;
+
+ aCode.AddToken(*pNewToken);
+ }
+ break;
+ default:
+ aCode.AddToken(*pToken);
+ }
+ }
+
+ ScCompiler aComp(pDocument, aPos, aCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ aComp.CompileTokenArray(); // Create RPN token array.
+ ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
+ aInterpreter.Interpret();
+ aResult.SetToken(aInterpreter.GetResultToken().get());
+ }
+ else
+ {
+ // Formula contains no references.
+ ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
+ aInterpreter.Interpret();
+ aResult.SetToken(aInterpreter.GetResultToken().get());
+ }
- // calculate ourselves:
- InterpretTail( SCITP_NORMAL );
for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
{
ScAddress aTmpPos = aPos;
@@ -2993,37 +3041,35 @@ bool ScFormulaCell::InterpretFormulaGroup()
}
return true;
}
- else
- {
- // scan the formula ...
- // have a document method: "Get2DRangeAsDoublesArray" that does the
- // column-based heavy lifting call it for each absolute range from the
- // first cell pos in the formula group.
- //
- // Project single references to ranges by adding their vector * xGroup->mnLength
- //
- // TODO:
- // elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
- // produces a diagonal 'column' that serves no useful purpose for us.
- // these should be very rare. Should elide in GetDeltas anyway and
- // assert here.
- //
- // Having built our input data ...
- // Throw it, and the formula over to some 'OpenCLCalculage' hook
- //
- // on return - release references on these double buffers
- //
- // transfer the result to the formula cells (as above)
- // store the doubles in the columns' maDoubles array for
- // dependent formulae
- //
- // TODO:
- // need to abort/fail when we get errors returned and fallback to
- // stock interpreting [ I guess ], unless we can use NaN etc. to
- // signal errors.
- return false;
- }
+ // scan the formula ...
+ // have a document method: "Get2DRangeAsDoublesArray" that does the
+ // column-based heavy lifting call it for each absolute range from the
+ // first cell pos in the formula group.
+ //
+ // Project single references to ranges by adding their vector * xGroup->mnLength
+ //
+ // TODO:
+ // elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
+ // produces a diagonal 'column' that serves no useful purpose for us.
+ // these should be very rare. Should elide in GetDeltas anyway and
+ // assert here.
+ //
+ // Having built our input data ...
+ // Throw it, and the formula over to some 'OpenCLCalculage' hook
+ //
+ // on return - release references on these double buffers
+ //
+ // transfer the result to the formula cells (as above)
+ // store the doubles in the columns' maDoubles array for
+ // dependent formulae
+ //
+ // TODO:
+ // need to abort/fail when we get errors returned and fallback to
+ // stock interpreting [ I guess ], unless we can use NaN etc. to
+ // signal errors.
+
+ return false;
}
void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 7ae3c66ea8d7..52e0bb98c8e2 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2113,15 +2113,31 @@ ScFormulaVectorState ScTable::GetFormulaVectorState( SCCOL nCol, SCROW nRow ) co
return aCol[nCol].GetFormulaVectorState(nRow);
}
-bool ScTable::ResolveVectorReference( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
+formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol, SCROW nRow )
{
- if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
- return false;
+ if (!ValidCol(nCol) || !ValidRow(nRow))
+ return formula::FormulaTokenRef();
- if (!aCol[nCol].ResolveVectorReference(nRow1, nRow2))
- return false;
+ return aCol[nCol].ResolveStaticReference(nRow);
+}
- return true;
+formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ if (nCol2 < nCol1 || nRow2 < nRow1)
+ return formula::FormulaTokenRef();
+
+ if (!ValidCol(nCol1) || !ValidCol(nCol2) || !ValidRow(nRow1) || !ValidRow(nRow2))
+ return formula::FormulaTokenRef();
+
+ ScMatrixRef pMat(new ScMatrix(nCol2-nCol1+1, nRow2-nRow1+1, 0.0));
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ if (!aCol[nCol].ResolveStaticReference(*pMat, nCol2-nCol1, nRow1, nRow2))
+ // Column contains non-static cell. Failed.
+ return formula::FormulaTokenRef();
+ }
+
+ return formula::FormulaTokenRef(new ScMatrixToken(pMat));
}
ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )