[Libreoffice-commits] core.git: Branch 'feature/calc-group-interpreter' - 2 commits - sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Mon Jun 3 21:59:37 PDT 2013


 sc/source/core/data/column2.cxx     |   50 ++-----
 sc/source/core/data/formulacell.cxx |  246 +++++++++++++++++++++---------------
 2 files changed, 166 insertions(+), 130 deletions(-)

New commits:
commit f8f3e2e1a811e2a95147146463a0f64c83f9890e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jun 4 01:01:02 2013 -0400

    Expand shared formula tokens from Excel (which are basically range names).
    
    Also, use a better way to fetch a double array.
    
    Change-Id: I65a5bb9c972620f63e79a84b461245cc7fea1a51

diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index fcf21b0..603b486 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1818,43 +1818,29 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& /*rCxt*/, SCR
     if (nRow1 > nRow2)
         return NULL;
 
-    ColDoubleEntry aBound;
-    aBound.mnStart = nRow1;
-    std::vector<ColDoubleEntry*>::const_iterator it =
-        std::lower_bound(maDoubles.begin(), maDoubles.end(), &aBound, ColDoubleEntry::LessByPtr());
-
-    if (it == maDoubles.end())
-        return NULL;
-
-    // There should never be an entry with empty double array. So we don't
-    // even bother checking for emptiness here.
-
-    const ColDoubleEntry& rEntry = **it;
-
-    if (rEntry.mnStart == nRow1)
+    std::vector<ColDoubleEntry*>::const_iterator it = maDoubles.begin(), itEnd = maDoubles.end();
+    size_t nOffset = 0;
+    for (; it != itEnd; ++it)
     {
-        SCROW nLastRow = rEntry.mnStart + rEntry.maData.size() - 1;
-        if (nLastRow < nRow2)
-            // Array is shorter than requested length.
-            return NULL;
-
-        return &rEntry.maData[0];
+        const ColDoubleEntry& rEntry = **it;
+        SCROW nRowStart = rEntry.mnStart;
+        SCROW nRowEnd = nRowStart + rEntry.maData.size() - 1;
+        if (nRowStart <= nRow1 && nRow2 <= nRowEnd)
+        {
+            // Found it.
+            nOffset = nRow1 - nRowStart;
+            break;
+        }
     }
 
-    OSL_ASSERT(nRow1 < rEntry.mnStart);
-
-    if (it == maDoubles.begin())
-        // This is the very first array entry.
-        return NULL;
-
-    --it; // Go to previous array so that rEntry.mnStart < nRow1.
-    OSL_ASSERT((**it).mnStart < nRow1);
-    SCROW nLastRow = rEntry.mnStart + rEntry.maData.size() - 1;
-    if (nLastRow < nRow2)
-        // Array is shorter than requested length.
+    if (it == itEnd)
+    {
+        // Array not found.
         return NULL;
+    }
 
-    return &rEntry.maData[nRow1 - rEntry.mnStart];
+    const ColDoubleEntry& rEntry = **it;
+    return &rEntry.maData[0] + nOffset;
 }
 
 ScRefCellValue ScColumn::GetRefCellValue( SCROW nRow )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index b0ab6ff..fbc66ca 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3059,6 +3059,32 @@ public:
                     }
                 }
                 break;
+                case svIndex:
+                {
+                    // Named range.
+                    ScRangeName* pNames = mrDoc.GetRangeName();
+                    if (!pNames)
+                        // This should never fail.
+                        return false;
+
+                    ScRangeData* pRange = pNames->findByIndex(p->GetIndex());
+                    if (!pRange)
+                        // No named range exists by that index.
+                        return false;
+
+                    ScTokenArray* pNamedTokens = pRange->GetCode();
+                    if (!pNamedTokens)
+                        // This named range is empty.
+                        return false;
+
+                    mrGroupTokens.AddOpCode(ocOpen);
+
+                    if (!convert(*pNamedTokens))
+                        return false;
+
+                    mrGroupTokens.AddOpCode(ocClose);
+                }
+                break;
                 default:
                     mrGroupTokens.AddToken(*pToken);
             }
commit 647a1ce3590a7c6ba5bb747d2ce7b0f5b0a600fa
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jun 3 23:47:13 2013 -0400

    Extract the group token conversion loop out into a separate class.
    
    Change-Id: I790db61d2a60cf4074fd2e3291ec42f0a4649b9e

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 98df69a..b0ab6ff 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2951,6 +2951,125 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell *p
     return bInvariant ? EqualInvariant : EqualRelativeRef;
 }
 
+namespace {
+
+class GroupTokenConverter
+{
+    sc::FormulaGroupContext maCxt;
+    ScTokenArray& mrGroupTokens;
+    ScDocument& mrDoc;
+    ScFormulaCell& mrCell;
+public:
+    GroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) :
+        mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {}
+
+    bool convert(ScTokenArray& rCode)
+    {
+        rCode.Reset();
+        for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
+        {
+            // A reference can be either absolute or relative.  If it's absolute,
+            // convert it to a static value token.  If relative, convert it to a
+            // vector reference token.  Note: we only care about relative vs
+            // absolute reference state for row directions.
+
+            const ScToken* pToken = static_cast<const ScToken*>(p);
+            switch (pToken->GetType())
+            {
+                case svSingleRef:
+                {
+                    ScSingleRefData aRef = pToken->GetSingleRef();
+                    aRef.CalcAbsIfRel(mrCell.aPos);
+                    ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
+                    if (aRef.IsRowRel())
+                    {
+                        // Fetch double array guarantees that the length of the
+                        // returned array equals or greater than the requested
+                        // length.
+
+                        // TODO: For now, it returns an array pointer only when
+                        // the entire array is in contiguous memory space.  Once
+                        // we finish cell storage rework, we'll support temporary
+                        // generation of a double array which is a combination of
+                        // multiple cell array segments.
+                        const double* pArray = mrDoc.FetchDoubleArray(maCxt, aRefPos, mrCell.GetCellGroup()->mnLength);
+                        if (!pArray)
+                            return false;
+
+                        formula::SingleVectorRefToken aTok(pArray, mrCell.GetCellGroup()->mnLength);
+                        mrGroupTokens.AddToken(aTok);
+                    }
+                    else
+                    {
+                        // Absolute row reference.
+                        formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos);
+                        if (!pNewToken)
+                            return false;
+
+                        mrGroupTokens.AddToken(*pNewToken);
+                    }
+                }
+                break;
+                case svDoubleRef:
+                {
+                    ScComplexRefData aRef = pToken->GetDoubleRef();
+                    aRef.CalcAbsIfRel(mrCell.aPos);
+                    if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel())
+                    {
+                        // Row reference is relative.
+                        bool bAbsFirst = !aRef.Ref1.IsRowRel();
+                        bool bAbsLast = !aRef.Ref2.IsRowRel();
+                        ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab);
+                        size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1;
+                        std::vector<const double*> aArrays;
+                        aArrays.reserve(nCols);
+                        SCROW nArrayLength = mrCell.GetCellGroup()->mnLength;
+                        SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1;
+                        if (!bAbsLast)
+                        {
+                            // range end position is relative. Extend the array length.
+                            nArrayLength += nRefRowSize - 1;
+                        }
+
+                        for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i)
+                        {
+                            aRefPos.SetCol(i);
+                            const double* pArray = mrDoc.FetchDoubleArray(maCxt, aRefPos, nArrayLength);
+                            if (!pArray)
+                                return false;
+
+                            aArrays.push_back(pArray);
+                        }
+
+                        formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
+                        mrGroupTokens.AddToken(aTok);
+                    }
+                    else
+                    {
+                        // Absolute row reference.
+                        ScRange aRefRange(
+                            aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab,
+                            aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab);
+
+                        formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefRange);
+                        if (!pNewToken)
+                            return false;
+
+                        mrGroupTokens.AddToken(*pNewToken);
+                    }
+                }
+                break;
+                default:
+                    mrGroupTokens.AddToken(*pToken);
+            }
+        }
+
+        return true;
+    }
+};
+
+}
+
 bool ScFormulaCell::InterpretFormulaGroup()
 {
     // Re-build formulae groups if necessary - ideally this is done at
@@ -2979,104 +3098,9 @@ bool ScFormulaCell::InterpretFormulaGroup()
     sc::FormulaGroupContext aCxt;
 
     ScTokenArray aCode;
-    pCode->Reset();
-    for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
-    {
-        // A reference can be either absolute or relative.  If it's absolute,
-        // convert it to a static value token.  If relative, convert it to a
-        // vector reference token.  Note: we only care about relative vs
-        // absolute reference state for row directions.
-
-        const ScToken* pToken = static_cast<const ScToken*>(p);
-        switch (pToken->GetType())
-        {
-            case svSingleRef:
-            {
-                ScSingleRefData aRef = pToken->GetSingleRef();
-                aRef.CalcAbsIfRel(aPos);
-                ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
-                if (aRef.IsRowRel())
-                {
-                    // Fetch double array guarantees that the length of the
-                    // returned array equals or greater than the requested
-                    // length.
-
-                    // TODO: For now, it returns an array pointer only when
-                    // the entire array is in contiguous memory space.  Once
-                    // we finish cell storage rework, we'll support temporary
-                    // generation of a double array which is a combination of
-                    // multiple cell array segments.
-                    const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, xGroup->mnLength);
-                    if (!pArray)
-                        return false;
-
-                    formula::SingleVectorRefToken aTok(pArray, xGroup->mnLength);
-                    aCode.AddToken(aTok);
-                }
-                else
-                {
-                    // Absolute row reference.
-                    formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
-                    if (!pNewToken)
-                        return false;
-
-                    aCode.AddToken(*pNewToken);
-                }
-            }
-            break;
-            case svDoubleRef:
-            {
-                ScComplexRefData aRef = pToken->GetDoubleRef();
-                aRef.CalcAbsIfRel(aPos);
-                if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel())
-                {
-                    // Row reference is relative.
-                    bool bAbsFirst = !aRef.Ref1.IsRowRel();
-                    bool bAbsLast = !aRef.Ref2.IsRowRel();
-                    ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab);
-                    size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1;
-                    std::vector<const double*> aArrays;
-                    aArrays.reserve(nCols);
-                    SCROW nArrayLength = xGroup->mnLength;
-                    SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1;
-                    if (!bAbsLast)
-                    {
-                        // range end position is relative. Extend the array length.
-                        nArrayLength += nRefRowSize - 1;
-                    }
-
-                    for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i)
-                    {
-                        aRefPos.SetCol(i);
-                        const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, nArrayLength);
-                        if (!pArray)
-                            return false;
-
-                        aArrays.push_back(pArray);
-                    }
-
-                    formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
-                    aCode.AddToken(aTok);
-                }
-                else
-                {
-                    // Absolute row reference.
-                    ScRange aRefRange(
-                        aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab,
-                        aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab);
-
-                    formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
-                    if (!pNewToken)
-                        return false;
-
-                    aCode.AddToken(*pNewToken);
-                }
-            }
-            break;
-            default:
-                aCode.AddToken(*pToken);
-        }
-    }
+    GroupTokenConverter aConverter(aCode, *pDocument, *this);
+    if (!aConverter.convert(*pCode))
+        return false;
 
     sc::FormulaGroupInterpreter aInterpreter(*pDocument, aPos, xGroup, aCode);
     return aInterpreter.interpret();


More information about the Libreoffice-commits mailing list