[Libreoffice-commits] core.git: Branch 'private/kohei/xlsx-import-speedup' - 5 commits - formula/source sc/inc sc/source svl/source

Kohei Yoshida kohei.yoshida at collabora.com
Thu Nov 7 00:53:00 CET 2013


 formula/source/core/api/FormulaCompiler.cxx |   66 +++--
 sc/inc/compiler.hxx                         |    3 
 sc/inc/document.hxx                         |    1 
 sc/source/core/data/documen2.cxx            |    5 
 sc/source/core/data/poolhelp.cxx            |   28 +-
 sc/source/core/inc/poolhelp.hxx             |    4 
 sc/source/core/tool/compiler.cxx            |   62 ++---
 sc/source/filter/inc/formulabuffer.hxx      |   38 ++-
 sc/source/filter/oox/formulabuffer.cxx      |  318 ++++++++++++++++++----------
 svl/source/numbers/zforfind.cxx             |    6 
 svl/source/numbers/zforfind.hxx             |    3 
 11 files changed, 354 insertions(+), 180 deletions(-)

New commits:
commit 4af2f3c8cc98949271df5dc70358e3d33e751719
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Nov 6 18:51:34 2013 -0500

    Perform formula cell compilations in multiple threads during xlsx import.
    
    One sheet per thread. Right now the thread count is set to 1 due to non
    re-entrancy of a large portion of Calc core, and beyond. We need to fix
    that first before setting the thread count to more than 1.
    
    Change-Id: I6997c1e9540de939f1f00b1798e2b32059787ae5

diff --git a/sc/source/filter/inc/formulabuffer.hxx b/sc/source/filter/inc/formulabuffer.hxx
index f9e5229..7e881ee 100644
--- a/sc/source/filter/inc/formulabuffer.hxx
+++ b/sc/source/filter/inc/formulabuffer.hxx
@@ -13,6 +13,8 @@
 #include <utility>
 #include "oox/helper/refmap.hxx"
 #include "oox/helper/refvector.hxx"
+#include "salhelper/thread.hxx"
+#include "osl/mutex.hxx"
 #include "workbookhelper.hxx"
 #include <com/sun/star/table/CellAddress.hpp>
 #include <com/sun/star/table/CellRangeAddress.hpp>
@@ -29,6 +31,21 @@ namespace oox { namespace xls {
 
 class FormulaBuffer : public WorkbookHelper
 {
+    class FinalizeThread : public salhelper::Thread
+    {
+        FormulaBuffer& mrParent;
+        size_t mnThreadCount;
+    public:
+        FinalizeThread( FormulaBuffer& rParent, size_t nThreadCount );
+        virtual ~FinalizeThread();
+
+    protected:
+        virtual void execute();
+    };
+
+    friend class FinalizeThread;
+
+public:
     /**
      * Represents a shared formula definition.
      */
@@ -74,6 +91,20 @@ class FormulaBuffer : public WorkbookHelper
         TokenRangeAddressItem( const TokenAddressItem& rTokenAndAddress, const ::com::sun::star::table::CellRangeAddress& rCellRangeAddress ) : maTokenAndAddress( rTokenAndAddress ), maCellRangeAddress( rCellRangeAddress ) {}
     };
 
+    typedef std::pair<com::sun::star::table::CellAddress, double> ValueAddressPair;
+
+    struct SheetItem
+    {
+        std::vector<TokenAddressItem>* mpCellFormulas;
+        std::vector<TokenRangeAddressItem>* mpArrayFormulas;
+        std::vector<ValueAddressPair>* mpCellFormulaValues;
+        std::vector<SharedFormulaEntry>* mpSharedFormulaEntries;
+        std::vector<SharedFormulaDesc>* mpSharedFormulaIDs;
+
+        SheetItem();
+    };
+
+private:
     typedef ::std::map< SCTAB, std::vector<TokenAddressItem> > FormulaDataMap;
     typedef ::std::map< SCTAB, std::vector<TokenRangeAddressItem> > ArrayFormulaDataMap;
     // sheet -> list of shared formula descriptions
@@ -81,19 +112,16 @@ class FormulaBuffer : public WorkbookHelper
     // sheet -> stuff needed to create shared formulae
     typedef ::std::map< SCTAB, std::vector<SharedFormulaEntry> >  SheetToFormulaEntryMap;
 
-    typedef ::std::pair< ::com::sun::star::table::CellAddress, double > ValueAddressPair;
     typedef ::std::map< SCTAB, std::vector<ValueAddressPair> > FormulaValueMap;
 
+    osl::Mutex maMtxData;
     FormulaDataMap maCellFormulas;
     ArrayFormulaDataMap maCellArrayFormulas;
     SheetToFormulaEntryMap maSharedFormulas;
     SheetToSharedFormulaid maSharedFormulaIds;
     FormulaValueMap maCellFormulaValues;
 
-    void                applyArrayFormulas(  const std::vector< TokenRangeAddressItem >& rVector );
-    void                applyCellFormulas(  const std::vector< TokenAddressItem >& rVector );
-    void                applyCellFormulaValues( const std::vector< ValueAddressPair >& rVector );
-    void applySharedFormulas( SCTAB nTab );
+    SheetItem getSheetItem( SCTAB nTab );
 
 public:
     explicit            FormulaBuffer( const WorkbookHelper& rHelper );
diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index 04be139..c3e1d24 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -33,114 +33,22 @@ using namespace ::com::sun::star::table;
 using namespace ::com::sun::star::sheet;
 using namespace ::com::sun::star::container;
 
-namespace oox { namespace xls {
-
-FormulaBuffer::SharedFormulaEntry::SharedFormulaEntry(
-    const table::CellAddress& rAddr, const table::CellRangeAddress& rRange,
-    const OUString& rTokenStr, sal_Int32 nSharedId ) :
-    maAddress(rAddr), maRange(rRange), maTokenStr(rTokenStr), mnSharedId(nSharedId) {}
-
-FormulaBuffer::SharedFormulaDesc::SharedFormulaDesc(
-    const com::sun::star::table::CellAddress& rAddr, sal_Int32 nSharedId,
-    const OUString& rCellValue, sal_Int32 nValueType ) :
-    maAddress(rAddr), mnSharedId(nSharedId), maCellValue(rCellValue), mnValueType(nValueType) {}
-
-FormulaBuffer::FormulaBuffer( const WorkbookHelper& rHelper ) : WorkbookHelper( rHelper )
-{
-}
-
-void FormulaBuffer::finalizeImport()
-{
-    ISegmentProgressBarRef xFormulaBar = getProgressBar().createSegment( getProgressBar().getFreeLength() );
-
-    ScDocument& rDoc = getScDocument();
-    rDoc.SetAutoNameCache( new ScAutoNameCache( &rDoc ) );
-    for (SCTAB nTab = 0, nElem = rDoc.GetTableCount(); nTab < nElem; ++nTab)
-    {
-        double fPosition = static_cast< double> (nTab + 1) /static_cast<double>(nElem);
-        xFormulaBar->setPosition( fPosition );
+#include <boost/scoped_ptr.hpp>
 
-        applySharedFormulas(nTab);
-
-        FormulaDataMap::iterator cellIt = maCellFormulas.find( nTab );
-        if ( cellIt != maCellFormulas.end() )
-        {
-            applyCellFormulas( cellIt->second );
-        }
-
-        ArrayFormulaDataMap::iterator itArray = maCellArrayFormulas.find( nTab );
-        if ( itArray != maCellArrayFormulas.end() )
-        {
-            applyArrayFormulas( itArray->second );
-        }
-
-        FormulaValueMap::iterator itValues = maCellFormulaValues.find( nTab );
-        if ( itValues != maCellFormulaValues.end() )
-        {
-            std::vector< ValueAddressPair > & rVector = itValues->second;
-            applyCellFormulaValues( rVector );
-        }
-    }
-    rDoc.SetAutoNameCache( NULL );
-    xFormulaBar->setPosition( 1.0 );
-}
-
-void FormulaBuffer::applyCellFormulas( const std::vector< TokenAddressItem >& rVector )
-{
-    ScDocumentImport& rDoc = getDocImport();
-    ScExternalRefManager::ApiGuard aExtRefGuard(&rDoc.getDoc());
-    for ( std::vector< TokenAddressItem >::const_iterator it = rVector.begin(), it_end = rVector.end(); it != it_end; ++it )
-    {
-        ScAddress aPos;
-        ScUnoConversion::FillScAddress(aPos, it->maCellAddress);
-        ScCompiler aCompiler(&rDoc.getDoc(), aPos);
-        aCompiler.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
-        ScTokenArray* pCode = aCompiler.CompileString(it->maTokenStr);
-        if (!pCode)
-            continue;
+namespace oox { namespace xls {
 
-        rDoc.setFormulaCell(aPos, pCode);
-    }
-}
+namespace {
 
-void FormulaBuffer::applyCellFormulaValues( const std::vector< ValueAddressPair >& rVector )
+void applySharedFormulas(
+    ScDocumentImport& rDoc,
+    SvNumberFormatter& rFormatter,
+    std::vector<FormulaBuffer::SharedFormulaEntry>& rSharedFormulas,
+    std::vector<FormulaBuffer::SharedFormulaDesc>& rCells )
 {
-    ScDocument& rDoc = getScDocument();
-    for ( std::vector< ValueAddressPair >::const_iterator it = rVector.begin(), it_end = rVector.end(); it != it_end; ++it )
-    {
-        ScAddress aCellPos;
-        ScUnoConversion::FillScAddress( aCellPos, it->first );
-        ScFormulaCell* pCell = rDoc.GetFormulaCell(aCellPos);
-        if (pCell)
-        {
-            pCell->SetHybridDouble( it->second );
-            pCell->ResetDirty();
-            pCell->SetChanged(false);
-        }
-    }
-}
-
-void FormulaBuffer::applySharedFormulas( SCTAB nTab )
-{
-    SheetToFormulaEntryMap::const_iterator itShared = maSharedFormulas.find(nTab);
-    if (itShared == maSharedFormulas.end())
-        // There is no shared formulas for this sheet.
-        return;
-
-    SheetToSharedFormulaid::const_iterator itCells = maSharedFormulaIds.find(nTab);
-    if (itCells == maSharedFormulaIds.end())
-        // There is no formula cells that use shared formulas for this sheet.
-        return;
-
-    const std::vector<SharedFormulaEntry>& rSharedFormulas = itShared->second;
-    const std::vector<SharedFormulaDesc>& rCells = itCells->second;
-
-    ScDocumentImport& rDoc = getDocImport();
-
     sc::SharedFormulaGroups aGroups;
     {
         // Process shared formulas first.
-        std::vector<SharedFormulaEntry>::const_iterator it = rSharedFormulas.begin(), itEnd = rSharedFormulas.end();
+        std::vector<FormulaBuffer::SharedFormulaEntry>::const_iterator it = rSharedFormulas.begin(), itEnd = rSharedFormulas.end();
         for (; it != itEnd; ++it)
         {
             const table::CellAddress& rAddr = it->maAddress;
@@ -150,6 +58,7 @@ void FormulaBuffer::applySharedFormulas( SCTAB nTab )
             ScAddress aPos;
             ScUnoConversion::FillScAddress(aPos, rAddr);
             ScCompiler aComp(&rDoc.getDoc(), aPos);
+            aComp.SetNumberFormatter(&rFormatter);
             aComp.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
             ScTokenArray* pArray = aComp.CompileString(rTokenStr);
             if (pArray)
@@ -159,7 +68,7 @@ void FormulaBuffer::applySharedFormulas( SCTAB nTab )
 
     {
         // Process formulas that use shared formulas.
-        std::vector<SharedFormulaDesc>::const_iterator it = rCells.begin(), itEnd = rCells.end();
+        std::vector<FormulaBuffer::SharedFormulaDesc>::const_iterator it = rCells.begin(), itEnd = rCells.end();
         for (; it != itEnd; ++it)
         {
             const table::CellAddress& rAddr = it->maAddress;
@@ -194,10 +103,32 @@ void FormulaBuffer::applySharedFormulas( SCTAB nTab )
     }
 }
 
-void FormulaBuffer::applyArrayFormulas( const std::vector< TokenRangeAddressItem >& rVector )
+void applyCellFormulas(
+    ScDocumentImport& rDoc, SvNumberFormatter& rFormatter,
+    const std::vector<FormulaBuffer::TokenAddressItem>& rCells )
 {
-    ScDocumentImport& rDocImport = getDocImport();
-    std::vector<TokenRangeAddressItem>::const_iterator it = rVector.begin(), itEnd = rVector.end();
+    ScExternalRefManager::ApiGuard aExtRefGuard(&rDoc.getDoc());
+    std::vector<FormulaBuffer::TokenAddressItem>::const_iterator it = rCells.begin(), itEnd = rCells.end();
+    for (; it != itEnd; ++it)
+    {
+        ScAddress aPos;
+        ScUnoConversion::FillScAddress(aPos, it->maCellAddress);
+        ScCompiler aCompiler(&rDoc.getDoc(), aPos);
+        aCompiler.SetNumberFormatter(&rFormatter);
+        aCompiler.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
+        ScTokenArray* pCode = aCompiler.CompileString(it->maTokenStr);
+        if (!pCode)
+            continue;
+
+        rDoc.setFormulaCell(aPos, pCode);
+    }
+}
+
+void applyArrayFormulas(
+    ScDocumentImport& rDoc, SvNumberFormatter& rFormatter,
+    const std::vector<FormulaBuffer::TokenRangeAddressItem>& rArrays )
+{
+    std::vector<FormulaBuffer::TokenRangeAddressItem>::const_iterator it = rArrays.begin(), itEnd = rArrays.end();
     for (; it != itEnd; ++it)
     {
         ScAddress aPos;
@@ -205,12 +136,185 @@ void FormulaBuffer::applyArrayFormulas( const std::vector< TokenRangeAddressItem
         ScRange aRange;
         ScUnoConversion::FillScRange(aRange, it->maCellRangeAddress);
 
-        ScCompiler aComp(&rDocImport.getDoc(), aPos);
+        ScCompiler aComp(&rDoc.getDoc(), aPos);
+        aComp.SetNumberFormatter(&rFormatter);
         aComp.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
         boost::scoped_ptr<ScTokenArray> pArray(aComp.CompileString(it->maTokenAndAddress.maTokenStr));
         if (pArray)
-            rDocImport.setMatrixCells(aRange, *pArray, formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
+            rDoc.setMatrixCells(aRange, *pArray, formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
+    }
+}
+
+void applyCellFormulaValues(
+    ScDocumentImport& rDoc, const std::vector<FormulaBuffer::ValueAddressPair>& rVector )
+{
+    std::vector<FormulaBuffer::ValueAddressPair>::const_iterator it = rVector.begin(), itEnd = rVector.end();
+    for (; it != itEnd; ++it)
+    {
+        ScAddress aCellPos;
+        ScUnoConversion::FillScAddress(aCellPos, it->first);
+        ScFormulaCell* pCell = rDoc.getDoc().GetFormulaCell(aCellPos);
+        if (pCell)
+        {
+            pCell->SetHybridDouble(it->second);
+            pCell->ResetDirty();
+            pCell->SetChanged(false);
+        }
+    }
+}
+
+class WorkerThread : public salhelper::Thread
+{
+    ScDocumentImport& mrDoc;
+    FormulaBuffer::SheetItem& mrItem;
+    boost::scoped_ptr<SvNumberFormatter> mpFormatter;
+
+    WorkerThread( const WorkerThread& );
+    WorkerThread& operator= ( const WorkerThread& );
+
+public:
+    WorkerThread( ScDocumentImport& rDoc, FormulaBuffer::SheetItem& rItem, SvNumberFormatter* pFormatter ) :
+        salhelper::Thread("xlsx-import-formula-buffer-worker-thread"),
+        mrDoc(rDoc), mrItem(rItem), mpFormatter(pFormatter) {}
+
+    virtual ~WorkerThread() {}
+
+protected:
+    virtual void execute()
+    {
+        if (mrItem.mpSharedFormulaEntries && mrItem.mpSharedFormulaIDs)
+            applySharedFormulas(mrDoc, *mpFormatter, *mrItem.mpSharedFormulaEntries, *mrItem.mpSharedFormulaIDs);
+
+        if (mrItem.mpCellFormulas)
+            applyCellFormulas(mrDoc, *mpFormatter, *mrItem.mpCellFormulas);
+
+        if (mrItem.mpArrayFormulas)
+            applyArrayFormulas(mrDoc, *mpFormatter, *mrItem.mpArrayFormulas);
+
+        if (mrItem.mpCellFormulaValues)
+            applyCellFormulaValues(mrDoc, *mrItem.mpCellFormulaValues);
+    }
+};
+
+}
+
+FormulaBuffer::SharedFormulaEntry::SharedFormulaEntry(
+    const table::CellAddress& rAddr, const table::CellRangeAddress& rRange,
+    const OUString& rTokenStr, sal_Int32 nSharedId ) :
+    maAddress(rAddr), maRange(rRange), maTokenStr(rTokenStr), mnSharedId(nSharedId) {}
+
+FormulaBuffer::SharedFormulaDesc::SharedFormulaDesc(
+    const com::sun::star::table::CellAddress& rAddr, sal_Int32 nSharedId,
+    const OUString& rCellValue, sal_Int32 nValueType ) :
+    maAddress(rAddr), mnSharedId(nSharedId), maCellValue(rCellValue), mnValueType(nValueType) {}
+
+FormulaBuffer::SheetItem::SheetItem() :
+    mpCellFormulas(NULL),
+    mpArrayFormulas(NULL),
+    mpCellFormulaValues(NULL),
+    mpSharedFormulaEntries(NULL),
+    mpSharedFormulaIDs(NULL) {}
+
+FormulaBuffer::FinalizeThread::FinalizeThread( FormulaBuffer& rParent, size_t nThreadCount ) :
+    salhelper::Thread("xlsx-import-formula-buffer-finalize-thread"),
+    mrParent(rParent), mnThreadCount(nThreadCount) {}
+
+FormulaBuffer::FinalizeThread::~FinalizeThread() {}
+
+void FormulaBuffer::FinalizeThread::execute()
+{
+    ScDocumentImport& rDoc = mrParent.getDocImport();
+    rDoc.getDoc().SetAutoNameCache(new ScAutoNameCache(&rDoc.getDoc()));
+    SCTAB nTabCount = rDoc.getDoc().GetTableCount();
+
+    std::vector<SheetItem> aSheetItems;
+    aSheetItems.reserve(nTabCount);
+    for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+        aSheetItems.push_back(mrParent.getSheetItem(nTab));
+
+    typedef rtl::Reference<WorkerThread> WorkerThreadRef;
+    std::vector<WorkerThreadRef> aThreads;
+    aThreads.reserve(mnThreadCount);
+
+    std::vector<SheetItem>::iterator it = aSheetItems.begin(), itEnd = aSheetItems.end();
+
+    while (it != itEnd)
+    {
+        for (size_t i = 0; i < mnThreadCount; ++i)
+        {
+            if (it == itEnd)
+                break;
+
+            WorkerThreadRef xThread(new WorkerThread(rDoc, *it, rDoc.getDoc().CreateFormatTable()));
+            ++it;
+            aThreads.push_back(xThread);
+            xThread->launch();
+        }
+
+        for (size_t i = 0, n = aThreads.size(); i < n; ++i)
+        {
+            if (aThreads[i].is())
+                aThreads[i]->join();
+        }
+
+        aThreads.clear();
+    }
+
+    rDoc.getDoc().SetAutoNameCache(NULL);
+}
+
+FormulaBuffer::FormulaBuffer( const WorkbookHelper& rHelper ) : WorkbookHelper( rHelper )
+{
+}
+
+void FormulaBuffer::finalizeImport()
+{
+    ISegmentProgressBarRef xFormulaBar = getProgressBar().createSegment( getProgressBar().getFreeLength() );
+
+    rtl::Reference<FinalizeThread> xThreadMgr(new FinalizeThread(*this, 1));
+    xThreadMgr->launch();
+
+    if (xThreadMgr.is())
+        xThreadMgr->join();
+
+    xFormulaBar->setPosition( 1.0 );
+}
+
+FormulaBuffer::SheetItem FormulaBuffer::getSheetItem( SCTAB nTab )
+{
+    osl::MutexGuard aGuard(&maMtxData);
+
+    SheetItem aItem;
+    {
+        FormulaDataMap::iterator it = maCellFormulas.find(nTab);
+        if (it != maCellFormulas.end())
+            aItem.mpCellFormulas = &it->second;
+    }
+
+    {
+        ArrayFormulaDataMap::iterator it = maCellArrayFormulas.find(nTab);
+        if (it != maCellArrayFormulas.end())
+            aItem.mpArrayFormulas = &it->second;
+    }
+
+    {
+        FormulaValueMap::iterator it = maCellFormulaValues.find(nTab);
+        if (it != maCellFormulaValues.end())
+            aItem.mpCellFormulaValues = &it->second;
+    }
+
+    {
+        SheetToFormulaEntryMap::iterator it = maSharedFormulas.find(nTab);
+        if (it != maSharedFormulas.end())
+            aItem.mpSharedFormulaEntries = &it->second;
+    }
+
+    {
+        SheetToSharedFormulaid::iterator it = maSharedFormulaIds.find(nTab);
+        if (it != maSharedFormulaIds.end())
+            aItem.mpSharedFormulaIDs = &it->second;
     }
+    return aItem;
 }
 
 void FormulaBuffer::createSharedFormulaMapEntry(
commit 9e8523defe69d99517957ee808b77256bdf32fb9
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Nov 6 18:43:47 2013 -0500

    Allow instantiation of more than one SvNumberFormatter from the document.
    
    Change-Id: Ide6875e031268337bf6a21286176a38905c12691

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 6929e9b..09f1466 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1621,6 +1621,7 @@ public:
         const ScMarkData* pMarkData = NULL );
 
     SC_DLLPUBLIC SvNumberFormatter* GetFormatTable() const;
+    SC_DLLPUBLIC SvNumberFormatter* CreateFormatTable() const;
 
     void            Sort( SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress );
     SCSIZE          Query( SCTAB nTab, const ScQueryParam& rQueryParam, bool bKeepSub );
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 1e0bb87..23a4bcf 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -491,6 +491,11 @@ SvNumberFormatter* ScDocument::GetFormatTable() const
     return xPoolHelper->GetFormTable();
 }
 
+SvNumberFormatter* ScDocument::CreateFormatTable() const
+{
+    return xPoolHelper->CreateNumberFormatter();
+}
+
 SfxItemPool* ScDocument::GetEditPool() const
 {
     return xPoolHelper->GetEditPool();
diff --git a/sc/source/core/data/poolhelp.cxx b/sc/source/core/data/poolhelp.cxx
index b6f027a..74d5cbe 100644
--- a/sc/source/core/data/poolhelp.cxx
+++ b/sc/source/core/data/poolhelp.cxx
@@ -71,14 +71,8 @@ SfxItemPool*        ScPoolHelper::GetEnginePool() const
 }
 SvNumberFormatter*  ScPoolHelper::GetFormTable() const
 {
-    if ( !pFormTable )
-    {
-        pFormTable = new SvNumberFormatter( comphelper::getProcessComponentContext(), ScGlobal::eLnge );
-        pFormTable->SetColorLink( LINK( m_pSourceDoc, ScDocument, GetUserDefinedColor ) );
-        pFormTable->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT );
-
-        UseDocOptions();        // null date, year2000, std precision
-    }
+    if (!pFormTable)
+        pFormTable = CreateNumberFormatter();
     return pFormTable;
 }
 
@@ -100,6 +94,24 @@ void ScPoolHelper::SetFormTableOpt(const ScDocOptions& rOpt)
     UseDocOptions();        // #i105512# if the number formatter exists, update its settings
 }
 
+SvNumberFormatter* ScPoolHelper::CreateNumberFormatter() const
+{
+    SvNumberFormatter* p = NULL;
+    {
+        osl::MutexGuard aGuard(&maMtxCreateNumFormatter);
+        p = new SvNumberFormatter(comphelper::getProcessComponentContext(), ScGlobal::eLnge);
+    }
+    p->SetColorLink( LINK(m_pSourceDoc, ScDocument, GetUserDefinedColor) );
+    p->SetEvalDateFormat(NF_EVALDATEFORMAT_INTL_FORMAT);
+
+    sal_uInt16 d,m,y;
+    aOpt.GetDate(d, m, y);
+    p->ChangeNullDate(d, m, y);
+    p->ChangeStandardPrec(aOpt.GetStdPrecision());
+    p->SetYear2000(aOpt.GetYear2000());
+    return p;
+}
+
 void ScPoolHelper::SourceDocumentGone()
 {
     //  reset all pointers to the source document
diff --git a/sc/source/core/inc/poolhelp.hxx b/sc/source/core/inc/poolhelp.hxx
index 6eaa0a9..c60bd1b 100644
--- a/sc/source/core/inc/poolhelp.hxx
+++ b/sc/source/core/inc/poolhelp.hxx
@@ -23,6 +23,7 @@
 #include <rtl/ref.hxx>
 #include <salhelper/simplereferenceobject.hxx>
 #include "docoptio.hxx"
+#include "osl/mutex.hxx"
 
 class ScDocument;
 class ScDocumentPool;
@@ -34,6 +35,7 @@ class SfxItemPool;
 class ScPoolHelper : public salhelper::SimpleReferenceObject
 {
 private:
+    mutable osl::Mutex maMtxCreateNumFormatter;
     ScDocOptions        aOpt;
     ScDocumentPool*     pDocPool;
     rtl::Reference< ScStyleSheetPool > mxStylePool;
@@ -59,6 +61,8 @@ public:
     SfxItemPool*        GetEnginePool() const;
 
     void                SetFormTableOpt(const ScDocOptions& rOpt);
+
+    SvNumberFormatter* CreateNumberFormatter() const;
 };
 
 #endif
commit 39074224e5f233c85c677b4f3bb9797e4e94a477
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Nov 6 18:41:18 2013 -0500

    Allow non-pooled instance of SvNumberFormatter inside ScCompiler.
    
    Change-Id: I645079254621c2f2684a69116b094e37e46f46f4

diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index c16f749..0cd47c5 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -312,6 +312,8 @@ private:
     ScDocument* pDoc;
     ScAddress   aPos;
 
+    SvNumberFormatter* mpFormatter;
+
     // For CONV_XL_OOX, may be set via API by MOOXML filter.
     ::com::sun::star::uno::Sequence< const ::com::sun::star::sheet::ExternalLinkInfo > maExternalLinks;
 
@@ -400,6 +402,7 @@ public:
 
     void            SetGrammar( const formula::FormulaGrammar::Grammar eGrammar );
 
+    void SetNumberFormatter( SvNumberFormatter* pFormatter );
     EncodeUrlMode   GetEncodeUrlMode() const;
 private:
     /** Set grammar and reference convention from within SetFormulaLanguage()
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 95e4ef0..41e1d56 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -239,6 +239,11 @@ void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar )
     }
 }
 
+void ScCompiler::SetNumberFormatter( SvNumberFormatter* pFormatter )
+{
+    mpFormatter = pFormatter;
+}
+
 ScCompiler::EncodeUrlMode ScCompiler::GetEncodeUrlMode() const
 {
     return meEncodeUrlMode;
@@ -1640,6 +1645,7 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArra
         : FormulaCompiler(rArr),
         pDoc( pDocument ),
         aPos( rPos ),
+        mpFormatter(pDoc->GetFormatTable()),
         pCharClass( ScGlobal::pCharClass ),
         mnPredetectedReference(0),
         mnRangeOpPosInSymbol(-1),
@@ -1656,6 +1662,7 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos)
         :
         pDoc( pDocument ),
         aPos( rPos ),
+        mpFormatter(pDoc->GetFormatTable()),
         pCharClass( ScGlobal::pCharClass ),
         mnPredetectedReference(0),
         mnRangeOpPosInSymbol(-1),
@@ -2517,40 +2524,37 @@ bool ScCompiler::IsOpCode2( const OUString& rName )
 bool ScCompiler::IsValue( const OUString& rSym )
 {
     double fVal;
-    sal_uInt32 nIndex = ( mxSymbols->isEnglish() ?
-        pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US ) : 0 );
+    sal_uInt32 nIndex = mxSymbols->isEnglish() ? mpFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US) : 0;
 
-    if (pDoc->GetFormatTable()->IsNumberFormat( rSym, nIndex, fVal ) )
-    {
-        sal_uInt16 nType = pDoc->GetFormatTable()->GetType(nIndex);
+    if (!mpFormatter->IsNumberFormat(rSym, nIndex, fVal))
+        return false;
 
-        // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
-        // Dates should never be entered directly and automatically converted
-        // to serial, because the serial would be wrong if null-date changed.
-        // Usually it wouldn't be accepted anyway because the date separator
-        // clashed with other separators or operators.
-        if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE))
-            return false;
+    sal_uInt16 nType = mpFormatter->GetType(nIndex);
 
-        if (nType == NUMBERFORMAT_LOGICAL)
-        {
-            const sal_Unicode* p = aFormula.getStr() + nSrcPos;
-            while( *p == ' ' )
-                p++;
-            if (*p == '(')
-                return false;   // Boolean function instead.
-        }
+    // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
+    // Dates should never be entered directly and automatically converted
+    // to serial, because the serial would be wrong if null-date changed.
+    // Usually it wouldn't be accepted anyway because the date separator
+    // clashed with other separators or operators.
+    if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE))
+        return false;
 
-        if( nType == NUMBERFORMAT_TEXT )
-            // HACK: number too big!
-            SetError( errIllegalArgument );
-        ScRawToken aToken;
-        aToken.SetDouble( fVal );
-        pRawToken = aToken.Clone();
-        return true;
+    if (nType == NUMBERFORMAT_LOGICAL)
+    {
+        const sal_Unicode* p = aFormula.getStr() + nSrcPos;
+        while( *p == ' ' )
+            p++;
+        if (*p == '(')
+            return false;   // Boolean function instead.
     }
-    else
-        return false;
+
+    if( nType == NUMBERFORMAT_TEXT )
+        // HACK: number too big!
+        SetError( errIllegalArgument );
+    ScRawToken aToken;
+    aToken.SetDouble( fVal );
+    pRawToken = aToken.Clone();
+    return true;
 }
 
 bool ScCompiler::IsString()
commit 091b0ad48d3cf94108e8ffb73894629ae0a6c9ee
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Nov 6 18:34:18 2013 -0500

    Protect those global symbols containers with mutex during initialization.
    
    Change-Id: Id15b3e1a2bfebd2ea795fd412a259f125f5d9bab

diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index fda54bd..804fb03 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -24,6 +24,8 @@
 #include "core_resource.hxx"
 #include "core_resource.hrc"
 
+#include "osl/mutex.hxx"
+
 #include <svl/zforlist.hxx>
 #include <tools/rc.hxx>
 #include <tools/rcid.h>
@@ -39,8 +41,7 @@ namespace formula
 
     static const sal_Char* pInternal[ 1 ] = { "TTT" };
 
-namespace
-{
+namespace {
 
 class FormulaCompilerRecursionGuard
 {
@@ -248,6 +249,13 @@ const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr, sal_Unicode c )
     return NULL;
 }
 
+struct OpCodeMapData
+{
+    FormulaCompiler::NonConstOpCodeMapPtr mxSymbolMap;
+    osl::Mutex maMtx;
+};
+
+
 } // namespace
 
 
@@ -625,21 +633,25 @@ FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
 
 void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, bool bDestroy = false )
 {
-    static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap;
+    static OpCodeMapData aSymbolMap;
+    osl::MutexGuard aGuard(&aSymbolMap.maMtx);
+
     if ( bDestroy )
     {
-        s_SymbolMap.reset();
+        aSymbolMap.mxSymbolMap.reset();
     }
-    else if ( !s_SymbolMap.get() )
+    else if (!aSymbolMap.mxSymbolMap)
     {
         // Core
-        s_SymbolMap.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, true,
-                    FormulaGrammar::GRAM_NATIVE_UI));
+        aSymbolMap.mxSymbolMap.reset(
+            new FormulaCompiler::OpCodeMap(
+                SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
         OModuleClient aModuleClient;
-        OpCodeList aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES, s_SymbolMap );
+        OpCodeList aOpCodeListNative(RID_STRLIST_FUNCTION_NAMES, aSymbolMap.mxSymbolMap);
         // No AddInMap for native core mapping.
     }
-    xMap = s_SymbolMap;
+
+    xMap = aSymbolMap.mxSymbolMap;
 }
 
 const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp )
@@ -661,34 +673,38 @@ void FormulaCompiler::InitSymbolsNative() const
 
 void FormulaCompiler::InitSymbolsEnglish() const
 {
-    static NonConstOpCodeMapPtr s_sSymbol;
-    if ( !s_sSymbol.get() )
-        loadSymbols( RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, s_sSymbol);
-    mxSymbolsEnglish = s_sSymbol;
+    static OpCodeMapData aMap;
+    osl::MutexGuard aGuard(&aMap.maMtx);
+    if (!aMap.mxSymbolMap)
+        loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
+    mxSymbolsEnglish = aMap.mxSymbolMap;
 }
 
 void FormulaCompiler::InitSymbolsPODF() const
 {
-    static NonConstOpCodeMapPtr s_sSymbol;
-    if ( !s_sSymbol.get() )
-        loadSymbols( RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_PODF, s_sSymbol);
-    mxSymbolsPODF = s_sSymbol;
+    static OpCodeMapData aMap;
+    osl::MutexGuard aGuard(&aMap.maMtx);
+    if (!aMap.mxSymbolMap)
+        loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap);
+    mxSymbolsPODF = aMap.mxSymbolMap;
 }
 
 void FormulaCompiler::InitSymbolsODFF() const
 {
-    static NonConstOpCodeMapPtr s_sSymbol;
-    if ( !s_sSymbol.get() )
-        loadSymbols( RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, s_sSymbol);
-    mxSymbolsODFF = s_sSymbol;
+    static OpCodeMapData aMap;
+    osl::MutexGuard aGuard(&aMap.maMtx);
+    if (!aMap.mxSymbolMap)
+        loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap);
+    mxSymbolsODFF = aMap.mxSymbolMap;
 }
 
 void FormulaCompiler::InitSymbolsEnglishXL() const
 {
-    static NonConstOpCodeMapPtr s_sSymbol;
-    if ( !s_sSymbol.get() )
-        loadSymbols( RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, s_sSymbol);
-    mxSymbolsEnglishXL = s_sSymbol;
+    static OpCodeMapData aMap;
+    osl::MutexGuard aGuard(&aMap.maMtx);
+    if (!aMap.mxSymbolMap)
+        loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
+    mxSymbolsEnglishXL = aMap.mxSymbolMap;
 
     // TODO: For now, just replace the separators to the Excel English
     // variants. Later, if we want to properly map Excel functions with Calc
commit 42d42c72086aaed09834ed07071f6d5dd7e5e9b0
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Nov 6 14:55:41 2013 -0500

    Make TransformInput() a non-member function.
    
    Change-Id: Ieb077b6ce661e2885d6010519f137235a048f9df

diff --git a/svl/source/numbers/zforfind.cxx b/svl/source/numbers/zforfind.cxx
index 9cd3362..3726c33 100644
--- a/svl/source/numbers/zforfind.cxx
+++ b/svl/source/numbers/zforfind.cxx
@@ -147,8 +147,8 @@ inline bool ImpSvNumberInputScan::MyIsdigit( sal_Unicode c )
     return c < 128 && isdigit( (unsigned char) c );
 }
 
-
-void ImpSvNumberInputScan::TransformInput( OUString& rStr )
+// native number transliteration if necessary
+void TransformInput( SvNumberFormatter* pFormatter, OUString& rStr )
 {
     sal_Int32 nPos, nLen;
     for ( nPos = 0, nLen = rStr.getLength(); nPos < nLen; ++nPos )
@@ -3271,7 +3271,7 @@ bool ImpSvNumberInputScan::IsNumberFormat( const OUString& rString,         // s
         // NoMoreUpperNeeded, all comparisons on UpperCase
         aString = pFormatter->GetCharClass()->uppercase( rString );
         // convert native number to ASCII if necessary
-        TransformInput( aString );
+        TransformInput(pFormatter, aString);
         res = IsNumberFormatMain( aString, pFormat );
     }
 
diff --git a/svl/source/numbers/zforfind.hxx b/svl/source/numbers/zforfind.hxx
index 4c070a1..6e24040 100644
--- a/svl/source/numbers/zforfind.hxx
+++ b/svl/source/numbers/zforfind.hxx
@@ -362,9 +362,6 @@ private:
 
     static inline bool MyIsdigit( sal_Unicode c );
 
-    // native number transliteration if necessary
-    void TransformInput( OUString& rString );
-
     /** Whether input matches locale dependent date acceptance pattern.
 
         @param nStartPatternAt


More information about the Libreoffice-commits mailing list