sc/inc/stringutil.hxx                |    3 
 sc/source/core/tool/stringutil.cxx   |  150 +++++++++++++++
 sc/source/ui/docshell/datastream.cxx |  338 +++++++++++++++++++++--------------
 sc/source/ui/inc/datastream.hxx      |   37 +++
 4 files changed, 388 insertions(+), 140 deletions(-)

New commits:
commit 6636050ee9427498537e4a76b0a2c8b7cd67420e
Author: Kohei Yoshida <kohei.yosh...@collabora.com>
Date:   Mon Dec 30 14:31:30 2013 -0500

    This part requires orcus library presence.
    
    Change-Id: I6bfba9872deb7318721ce4d73795ef7569a24e89

diff --git a/sc/source/ui/docshell/datastream.cxx 
b/sc/source/ui/docshell/datastream.cxx
index af11847..45bc637 100644
--- a/sc/source/ui/docshell/datastream.cxx
+++ b/sc/source/ui/docshell/datastream.cxx
@@ -269,10 +269,11 @@ private:
                 DataStream::Line& rLine = (*pLines)[i];
                 rLine.maCells.clear();
                 mpStream->ReadLine(rLine.maLine);
-
+#if ENABLE_ORCUS
                 CSVHandler aHdl(rLine, mnColCount);
                 orcus::csv_parser<CSVHandler> parser(rLine.maLine.getStr(), 
rLine.maLine.getLength(), aHdl, maConfig);
                 parser.parse();
+#endif
             }
 
             aGuard.reset(); // lock
commit add5b414df52dfc12cdd5004e97e7ab5707a163f
Author: Kohei Yoshida <kohei.yosh...@collabora.com>
Date:   Mon Dec 30 12:16:35 2013 -0500

    Parse CSV lines in the reader thread.
    
    Conflicts:
        sc/source/ui/docshell/datastream.cxx
    
    Change-Id: I6329a0e6e6fa6576df2ed473482d558bfd6cce08

diff --git a/sc/inc/stringutil.hxx b/sc/inc/stringutil.hxx
index 08e5c1e..d275007 100644
--- a/sc/inc/stringutil.hxx
+++ b/sc/inc/stringutil.hxx
@@ -126,6 +126,9 @@ public:
     static bool parseSimpleNumber(
         const OUString& rStr, sal_Unicode dsep, sal_Unicode gsep, double& 
rVal);
 
+    static bool parseSimpleNumber(
+        const char* p, size_t n, char dsep, char gsep, double& rVal);
+
     static sal_Int32 SC_DLLPUBLIC GetQuotedTokenCount(const OUString &rIn, 
const OUString& rQuotedPairs, sal_Unicode cTok = ';' );
     static OUString  SC_DLLPUBLIC GetQuotedToken(const OUString &rIn, 
sal_Int32 nToken, const OUString& rQuotedPairs,
                                         sal_Unicode cTok,  sal_Int32& rIndex );
diff --git a/sc/source/core/tool/stringutil.cxx 
b/sc/source/core/tool/stringutil.cxx
index e711bcb..5bdc2c2 100644
--- a/sc/source/core/tool/stringutil.cxx
+++ b/sc/source/core/tool/stringutil.cxx
@@ -18,11 +18,13 @@
  */
 
 #include "stringutil.hxx"
-#include "rtl/ustrbuf.hxx"
-#include "rtl/math.hxx"
 #include "global.hxx"
 #include "svl/zforlist.hxx"
 
+#include <rtl/ustrbuf.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/math.hxx>
+
 ScSetStringParam::ScSetStringParam() :
     mpNumFormatter(NULL),
     mbDetectNumberFormat(true),
@@ -194,6 +196,150 @@ bool ScStringUtil::parseSimpleNumber(
     return true;
 }
 
+bool ScStringUtil::parseSimpleNumber(
+    const char* p, size_t n, char dsep, char gsep, double& rVal)
+{
+    // Actually almost the entire pre-check is unnecessary and we could call
+    // rtl::math::stringToDouble() just after having exchanged ascii space with
+    // non-breaking space, if it wasn't for check of grouped digits. The NaN
+    // and Inf cases that are accepted by stringToDouble() could be detected
+    // using rtl::math::isFinite() on the result.
+
+    /* TODO: The grouped digits check isn't even valid for locales that do not
+     * group in thousands ... e.g. Indian locales. But that's something also
+     * the number scanner doesn't implement yet, only the formatter. */
+
+    OStringBuffer aBuf;
+
+    size_t i = 0;
+    const char* pLast = p + (n-1);
+    sal_Int32 nPosDSep = -1, nPosGSep = -1;
+    sal_uInt32 nDigitCount = 0;
+    sal_Int32 nPosExponent = -1;
+
+    // Skip preceding spaces.
+    for (i = 0; i < n; ++i, ++p)
+    {
+        char c = *p;
+        if (c != ' ')
+            // first non-space character.  Exit.
+            break;
+    }
+
+    if (i == n)
+        // the whole string is space.  Fail.
+        return false;
+
+    n -= i; // Subtract the length of the preceding spaces.
+
+    // Determine the last non-space character.
+    for (; p != pLast; --pLast, --n)
+    {
+        char c = *pLast;
+        if (c != ' ')
+            // Non space character. Exit.
+            break;
+    }
+
+    for (i = 0; i < n; ++i, ++p)
+    {
+        char c = *p;
+
+        if ('0' <= c && c <= '9')
+        {
+            // this is a digit.
+            aBuf.append(c);
+            ++nDigitCount;
+        }
+        else if (c == dsep)
+        {
+            // this is a decimal separator.
+
+            if (nPosDSep >= 0)
+                // a second decimal separator -> not a valid number.
+                return false;
+
+            if (nPosGSep >= 0 && i - nPosGSep != 4)
+                // the number has a group separator and the decimal sep is not
+                // positioned correctly.
+                return false;
+
+            nPosDSep = i;
+            nPosGSep = -1;
+            aBuf.append(c);
+            nDigitCount = 0;
+        }
+        else if (c == gsep)
+        {
+            // this is a group (thousand) separator.
+
+            if (i == 0)
+                // not allowed as the first character.
+                return false;
+
+            if (nPosDSep >= 0)
+                // not allowed after the decimal separator.
+                return false;
+
+            if (nPosGSep >= 0 && nDigitCount != 3)
+                // must be exactly 3 digits since the last group separator.
+                return false;
+
+            if (nPosExponent >= 0)
+                // not allowed in exponent.
+                return false;
+
+            nPosGSep = i;
+            nDigitCount = 0;
+        }
+        else if (c == '-' || c == '+')
+        {
+            // A sign must be the first character if it's given, or immediately
+            // follow the exponent character if present.
+            if (i == 0 || (nPosExponent >= 0 && i == 
static_cast<size_t>(nPosExponent+1)))
+                aBuf.append(c);
+            else
+                return false;
+        }
+        else if (c == 'E' || c == 'e')
+        {
+            // this is an exponent designator.
+
+            if (nPosExponent >= 0)
+                // Only one exponent allowed.
+                return false;
+
+            if (nPosGSep >= 0 && nDigitCount != 3)
+                // must be exactly 3 digits since the last group separator.
+                return false;
+
+            aBuf.append(c);
+            nPosExponent = i;
+            nPosDSep = -1;
+            nPosGSep = -1;
+            nDigitCount = 0;
+        }
+        else
+            return false;
+    }
+
+    // finished parsing the number.
+
+    if (nPosGSep >= 0 && nDigitCount != 3)
+        // must be exactly 3 digits since the last group separator.
+        return false;
+
+    rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
+    sal_Int32 nParseEnd = 0;
+    OString aString( aBuf.makeStringAndClear());
+    rVal = ::rtl::math::stringToDouble( aString, dsep, gsep, &eStatus, 
&nParseEnd);
+    if (eStatus != rtl_math_ConversionStatus_Ok || nParseEnd < 
aString.getLength())
+        // Not a valid number or not entire string consumed.
+        return false;
+
+    return true;
+}
+
 sal_Int32 ScStringUtil::GetQuotedTokenCount(const OUString &rIn, const 
OUString& rQuotedPairs, sal_Unicode cTok )
 {
     assert( !(rQuotedPairs.getLength()%2) );
diff --git a/sc/source/ui/docshell/datastream.cxx 
b/sc/source/ui/docshell/datastream.cxx
index 3ca8faf..af11847 100644
--- a/sc/source/ui/docshell/datastream.cxx
+++ b/sc/source/ui/docshell/datastream.cxx
@@ -56,6 +56,8 @@ double datastream_get_time(int nIdx)
     return fTimes[ nIdx ];
 }
 
+namespace {
+
 inline double getNow()
 {
     TimeValue now;
@@ -63,6 +65,50 @@ inline double getNow()
     return static_cast<double>(now.Seconds) + static_cast<double>(now.Nanosec) 
/ 1000000000.0;
 }
 
+#if ENABLE_ORCUS
+
+class CSVHandler
+{
+    DataStream::Line& mrLine;
+    size_t mnColCount;
+    size_t mnCols;
+    const char* mpLineHead;
+
+public:
+    CSVHandler( DataStream::Line& rLine, size_t nColCount ) :
+        mrLine(rLine), mnColCount(nColCount), mnCols(0), 
mpLineHead(rLine.maLine.getStr()) {}
+
+    void begin_parse() {}
+    void end_parse() {}
+    void begin_row() {}
+    void end_row() {}
+
+    void cell(const char* p, size_t n)
+    {
+        if (mnCols >= mnColCount)
+            return;
+
+        DataStream::Cell aCell;
+        if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', aCell.mfValue))
+        {
+            aCell.mbValue = true;
+        }
+        else
+        {
+            aCell.mbValue = false;
+            aCell.maStr.Pos = std::distance(mpLineHead, p);
+            aCell.maStr.Size = n;
+        }
+        mrLine.maCells.push_back(aCell);
+
+        ++mnCols;
+    }
+};
+
+#endif
+
+}
+
 namespace datastreams {
 
 class CallerThread : public salhelper::Thread
@@ -96,7 +142,7 @@ private:
     }
 };
 
-void emptyLineQueue( std::queue<LinesList*>& rQueue )
+void emptyLineQueue( std::queue<DataStream::LinesType*>& rQueue )
 {
     while (!rQueue.empty())
     {
@@ -108,22 +154,34 @@ void emptyLineQueue( std::queue<LinesList*>& rQueue )
 class ReaderThread : public salhelper::Thread
 {
     SvStream *mpStream;
+    size_t mnColCount;
     bool mbTerminate;
     osl::Mutex maMtxTerminate;
 
-    std::queue<LinesList* > maPendingLines;
-    std::queue<LinesList* > maUsedLines;
+    std::queue<DataStream::LinesType*> maPendingLines;
+    std::queue<DataStream::LinesType*> maUsedLines;
     osl::Mutex maMtxLines;
 
     osl::Condition maCondReadStream;
     osl::Condition maCondConsume;
 
+#if ENABLE_ORCUS
+    orcus::csv_parser_config maConfig;
+#endif
+
 public:
 
-    ReaderThread(SvStream *pData):
+    ReaderThread(SvStream *pData, size_t nColCount):
         Thread("ReaderThread"),
         mpStream(pData),
-        mbTerminate(false) {}
+        mnColCount(nColCount),
+        mbTerminate(false)
+    {
+#if ENABLE_ORCUS
+        maConfig.delimiters.push_back(',');
+        maConfig.text_qualifier = '"';
+#endif
+    }
 
     virtual ~ReaderThread()
     {
@@ -156,9 +214,9 @@ public:
         maCondConsume.reset();
     }
 
-    LinesList* popNewLines()
+    DataStream::LinesType* popNewLines()
     {
-        LinesList* pLines = maPendingLines.front();
+        DataStream::LinesType* pLines = maPendingLines.front();
         maPendingLines.pop();
         return pLines;
     }
@@ -174,7 +232,7 @@ public:
         return !maPendingLines.empty();
     }
 
-    void pushUsedLines( LinesList* pLines )
+    void pushUsedLines( DataStream::LinesType* pLines )
     {
         maUsedLines.push(pLines);
     }
@@ -189,7 +247,7 @@ private:
     {
         while (!isTerminateRequested())
         {
-            LinesList* pLines = NULL;
+            DataStream::LinesType* pLines = NULL;
             osl::ResettableMutexGuard aGuard(maMtxLines);
 
             if (!maUsedLines.empty())
@@ -202,12 +260,20 @@ private:
             else
             {
                 aGuard.clear(); // unlock
-                pLines = new LinesList(10);
+                pLines = new DataStream::LinesType(10);
             }
 
             // Read & store new lines from stream.
-            for (size_t i = 0; i < pLines->size(); ++i)
-                mpStream->ReadLine( pLines->at(i) );
+            for (size_t i = 0, n = pLines->size(); i < n; ++i)
+            {
+                DataStream::Line& rLine = (*pLines)[i];
+                rLine.maCells.clear();
+                mpStream->ReadLine(rLine.maLine);
+
+                CSVHandler aHdl(rLine, mnColCount);
+                orcus::csv_parser<CSVHandler> parser(rLine.maLine.getStr(), 
rLine.maLine.getLength(), aHdl, maConfig);
+                parser.parse();
+            }
 
             aGuard.reset(); // lock
             while (!isTerminateRequested() && maPendingLines.size() >= 8)
@@ -228,6 +294,19 @@ private:
 
 }
 
+DataStream::Cell::Cell() : mfValue(0.0), mbValue(true) {}
+
+DataStream::Cell::Cell( const Cell& r ) : mbValue(r.mbValue)
+{
+    if (r.mbValue)
+        mfValue = r.mfValue;
+    else
+    {
+        maStr.Pos = r.maStr.Pos;
+        maStr.Size = r.maStr.Size;
+    }
+}
+
 void DataStream::MakeToolbarVisible()
 {
     css::uno::Reference< css::frame::XFrame > xFrame =
@@ -312,13 +391,13 @@ DataStream::~DataStream()
     delete mpLines;
 }
 
-OString DataStream::ConsumeLine()
+DataStream::Line DataStream::ConsumeLine()
 {
     if (!mpLines || mnLinesCount >= mpLines->size())
     {
         mnLinesCount = 0;
         if (mxReaderThread->isTerminateRequested())
-            return OString();
+            return Line();
 
         osl::ResettableMutexGuard aGuard(mxReaderThread->getLinesMutex());
         if (mpLines)
@@ -402,7 +481,7 @@ void DataStream::StartImport()
             pStream = new SvScriptStream(msURL);
         else
             pStream = new SvFileStream(msURL, STREAM_READ);
-        mxReaderThread = new datastreams::ReaderThread( pStream );
+        mxReaderThread = new datastreams::ReaderThread(pStream, 
maStartRange.aEnd.Col() - maStartRange.aStart.Col() + 1);
         mxReaderThread->launch();
     }
     mbRunning = true;
@@ -476,82 +555,10 @@ void DataStream::MoveData()
 
 #if ENABLE_ORCUS
 
-namespace {
-
-struct StrVal
-{
-    ScAddress maPos;
-    OUString maStr;
-
-    StrVal( const ScAddress& rPos, const OUString& rStr ) : maPos(rPos), 
maStr(rStr) {}
-};
-
-struct NumVal
-{
-    ScAddress maPos;
-    double mfVal;
-
-    NumVal( const ScAddress& rPos, double fVal ) : maPos(rPos), mfVal(fVal) {}
-};
-
-typedef std::vector<StrVal> StrValArray;
-typedef std::vector<NumVal> NumValArray;
-
-/**
- * This handler handles a single line CSV input.
- */
-class CSVHandler
-{
-    ScAddress maPos;
-    SCROW mnRow;
-    SCCOL mnCol;
-    SCCOL mnEndCol;
-    SCTAB mnTab;
-
-    StrValArray maStrs;
-    NumValArray maNums;
-
-public:
-    CSVHandler( const ScAddress& rPos, SCCOL nEndCol ) : maPos(rPos), 
mnEndCol(nEndCol) {}
-
-    void begin_parse() {}
-    void end_parse() {}
-    void begin_row() {}
-    void end_row() {}
-
-    void cell(const char* p, size_t n)
-    {
-        if (maPos.Col() <= mnEndCol)
-        {
-            OUString aStr(p, n, RTL_TEXTENCODING_UTF8);
-            double fVal;
-            if (ScStringUtil::parseSimpleNumber(aStr, '.', ',', fVal))
-                maNums.push_back(NumVal(maPos, fVal));
-            else
-                maStrs.push_back(StrVal(maPos, aStr));
-        }
-        maPos.IncCol();
-    }
-
-    const StrValArray& getStrs() const { return maStrs; }
-    const NumValArray& getNums() const { return maNums; }
-};
-
-}
-
 void DataStream::Text2Doc()
 {
-    OString aLine = ConsumeLine();
-    orcus::csv_parser_config aConfig;
-    aConfig.delimiters.push_back(',');
-    aConfig.text_qualifier = '"';
-    CSVHandler aHdl(ScAddress(maStartRange.aStart.Col(), mnCurRow, 
maStartRange.aStart.Tab()), maStartRange.aEnd.Col());
-    orcus::csv_parser<CSVHandler> parser(aLine.getStr(), aLine.getLength(), 
aHdl, aConfig);
-    parser.parse();
-
-    const StrValArray& rStrs = aHdl.getStrs();
-    const NumValArray& rNums = aHdl.getNums();
-    if (rStrs.empty() && rNums.empty() && mbRefreshOnEmptyLine)
+    Line aLine = ConsumeLine();
+    if (aLine.maCells.empty() && mbRefreshOnEmptyLine)
     {
         // Empty line detected.  Trigger refresh and discard it.
         Refresh();
@@ -562,15 +569,24 @@ void DataStream::Text2Doc()
 
     MoveData();
     {
-        StrValArray::const_iterator it = rStrs.begin(), itEnd = rStrs.end();
-        for (; it != itEnd; ++it)
-            maDocAccess.setStringCell(it->maPos, it->maStr);
-    }
-
-    {
-        NumValArray::const_iterator it = rNums.begin(), itEnd = rNums.end();
-        for (; it != itEnd; ++it)
-            maDocAccess.setNumericCell(it->maPos, it->mfVal);
+        std::vector<Cell>::const_iterator it = aLine.maCells.begin(), itEnd = 
aLine.maCells.end();
+        SCCOL nCol = maStartRange.aStart.Col();
+        const char* pLineHead = aLine.maLine.getStr();
+        for (; it != itEnd; ++it, ++nCol)
+        {
+            const Cell& rCell = *it;
+            if (rCell.mbValue)
+            {
+                maDocAccess.setNumericCell(
+                    ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()), 
rCell.mfValue);
+            }
+            else
+            {
+                maDocAccess.setStringCell(
+                    ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()),
+                    OUString(pLineHead+rCell.maStr.Pos, rCell.maStr.Size, 
RTL_TEXTENCODING_UTF8));
+            }
+        }
     }
 
     fTimes[ DEBUG_TIME_IMPORT ] = getNow() - fStart;
diff --git a/sc/source/ui/inc/datastream.hxx b/sc/source/ui/inc/datastream.hxx
index 5a4d8cd..5af2dc7 100644
--- a/sc/source/ui/inc/datastream.hxx
+++ b/sc/source/ui/inc/datastream.hxx
@@ -33,15 +33,37 @@ namespace datastreams {
     class ReaderThread;
 }
 
-typedef std::vector<OString> LinesList;
 
 class DataStream : boost::noncopyable
 {
-    OString ConsumeLine();
-    void MoveData();
-    void Text2Doc();
-
 public:
+    struct Cell
+    {
+        struct Str
+        {
+            size_t Pos;
+            size_t Size;
+        };
+
+        union
+        {
+            Str maStr;
+            double mfValue;
+        };
+
+        bool mbValue;
+
+        Cell();
+        Cell( const Cell& r );
+    };
+
+    struct Line
+    {
+        OString maLine;
+        std::vector<Cell> maCells;
+    };
+    typedef std::vector<Line> LinesType;
+
     enum MoveType { NO_MOVE, RANGE_DOWN, MOVE_DOWN, MOVE_UP };
     enum { SCRIPT_STREAM = 1, VALUES_IN_LINE = 2 };
 
@@ -75,6 +97,9 @@ public:
     void SetRefreshOnEmptyLine( bool bVal );
 
 private:
+    Line ConsumeLine();
+    void MoveData();
+    void Text2Doc();
     void Refresh();
 
 private:
@@ -89,7 +114,7 @@ private:
     bool mbRunning;
     bool mbValuesInLine;
     bool mbRefreshOnEmptyLine;
-    LinesList* mpLines;
+    LinesType* mpLines;
     size_t mnLinesCount;
     size_t mnLinesSinceRefresh;
     double mfLastRefreshTime;
commit b5e76c5142b2eb87c3ea8a058e05273aae220408
Author: Kohei Yoshida <kohei.yosh...@collabora.com>
Date:   Fri Dec 27 23:22:54 2013 -0500

    Disallow direct access to member variables.
    
    Change-Id: I82d6c2a2c2844fbb6c2976327b129e42f6b63053

diff --git a/sc/source/ui/docshell/datastream.cxx 
b/sc/source/ui/docshell/datastream.cxx
index a1192b6..3ca8faf 100644
--- a/sc/source/ui/docshell/datastream.cxx
+++ b/sc/source/ui/docshell/datastream.cxx
@@ -110,12 +110,15 @@ class ReaderThread : public salhelper::Thread
     SvStream *mpStream;
     bool mbTerminate;
     osl::Mutex maMtxTerminate;
-public:
-    osl::Condition maProduceResume;
-    osl::Condition maConsumeResume;
-    osl::Mutex maMtxLines;
+
     std::queue<LinesList* > maPendingLines;
     std::queue<LinesList* > maUsedLines;
+    osl::Mutex maMtxLines;
+
+    osl::Condition maCondReadStream;
+    osl::Condition maCondConsume;
+
+public:
 
     ReaderThread(SvStream *pData):
         Thread("ReaderThread"),
@@ -144,7 +147,41 @@ public:
     void endThread()
     {
         requestTerminate();
-        maProduceResume.set();
+        maCondReadStream.set();
+    }
+
+    void waitForNewLines()
+    {
+        maCondConsume.wait();
+        maCondConsume.reset();
+    }
+
+    LinesList* popNewLines()
+    {
+        LinesList* pLines = maPendingLines.front();
+        maPendingLines.pop();
+        return pLines;
+    }
+
+    void resumeReadStream()
+    {
+        if (maPendingLines.size() <= 4)
+            maCondReadStream.set(); // start producer again
+    }
+
+    bool hasNewLines()
+    {
+        return !maPendingLines.empty();
+    }
+
+    void pushUsedLines( LinesList* pLines )
+    {
+        maUsedLines.push(pLines);
+    }
+
+    osl::Mutex& getLinesMutex()
+    {
+        return maMtxLines;
     }
 
 private:
@@ -157,6 +194,7 @@ private:
 
             if (!maUsedLines.empty())
             {
+                // Re-use lines from previous runs.
                 pLines = maUsedLines.front();
                 maUsedLines.pop();
                 aGuard.clear(); // unlock
@@ -167,6 +205,7 @@ private:
                 pLines = new LinesList(10);
             }
 
+            // Read & store new lines from stream.
             for (size_t i = 0; i < pLines->size(); ++i)
                 mpStream->ReadLine( pLines->at(i) );
 
@@ -175,12 +214,12 @@ private:
             {
                 // pause reading for a bit
                 aGuard.clear(); // unlock
-                maProduceResume.wait();
-                maProduceResume.reset();
+                maCondReadStream.wait();
+                maCondReadStream.reset();
                 aGuard.reset(); // lock
             }
             maPendingLines.push(pLines);
-            maConsumeResume.set();
+            maCondConsume.set();
             if (!mpStream->good())
                 requestTerminate();
         }
@@ -281,22 +320,19 @@ OString DataStream::ConsumeLine()
         if (mxReaderThread->isTerminateRequested())
             return OString();
 
-        osl::ResettableMutexGuard aGuard(mxReaderThread->maMtxLines);
+        osl::ResettableMutexGuard aGuard(mxReaderThread->getLinesMutex());
         if (mpLines)
-            mxReaderThread->maUsedLines.push(mpLines);
+            mxReaderThread->pushUsedLines(mpLines);
 
-        while (mxReaderThread->maPendingLines.empty())
+        while (!mxReaderThread->hasNewLines())
         {
             aGuard.clear(); // unlock
-            mxReaderThread->maConsumeResume.wait();
-            mxReaderThread->maConsumeResume.reset();
+            mxReaderThread->waitForNewLines();
             aGuard.reset(); // lock
         }
 
-        mpLines = mxReaderThread->maPendingLines.front();
-        mxReaderThread->maPendingLines.pop();
-        if (mxReaderThread->maPendingLines.size() <= 4)
-            mxReaderThread->maProduceResume.set(); // start producer again
+        mpLines = mxReaderThread->popNewLines();
+        mxReaderThread->resumeReadStream();
     }
     return mpLines->at(mnLinesCount++);
 }
commit 430585987ba54abf11276142e5ef997bf1a6f498
Author: Kohei Yoshida <kohei.yosh...@collabora.com>
Date:   Fri Dec 27 22:40:14 2013 -0500

    Protect access to the terminate flag.
    
    Change-Id: I9c47e8f114f3d4dcdd5e62b1fffd2b65e7bfb00e

diff --git a/sc/source/ui/docshell/datastream.cxx 
b/sc/source/ui/docshell/datastream.cxx
index 86be028..a1192b6 100644
--- a/sc/source/ui/docshell/datastream.cxx
+++ b/sc/source/ui/docshell/datastream.cxx
@@ -108,20 +108,19 @@ void emptyLineQueue( std::queue<LinesList*>& rQueue )
 class ReaderThread : public salhelper::Thread
 {
     SvStream *mpStream;
+    bool mbTerminate;
+    osl::Mutex maMtxTerminate;
 public:
-    bool mbTerminateReading;
     osl::Condition maProduceResume;
     osl::Condition maConsumeResume;
-    osl::Mutex maLinesProtector;
+    osl::Mutex maMtxLines;
     std::queue<LinesList* > maPendingLines;
     std::queue<LinesList* > maUsedLines;
 
     ReaderThread(SvStream *pData):
-        Thread("ReaderThread")
-        ,mpStream(pData)
-        ,mbTerminateReading(false)
-    {
-    }
+        Thread("ReaderThread"),
+        mpStream(pData),
+        mbTerminate(false) {}
 
     virtual ~ReaderThread()
     {
@@ -130,19 +129,31 @@ public:
         emptyLineQueue(maUsedLines);
     }
 
+    bool isTerminateRequested()
+    {
+        osl::MutexGuard aGuard(maMtxTerminate);
+        return mbTerminate;
+    }
+
+    void requestTerminate()
+    {
+        osl::MutexGuard aGuard(maMtxTerminate);
+        mbTerminate = true;
+    }
+
     void endThread()
     {
-        mbTerminateReading = true;
+        requestTerminate();
         maProduceResume.set();
     }
 
 private:
     virtual void execute() SAL_OVERRIDE
     {
-        while (!mbTerminateReading)
+        while (!isTerminateRequested())
         {
             LinesList* pLines = NULL;
-            osl::ResettableMutexGuard aGuard(maLinesProtector);
+            osl::ResettableMutexGuard aGuard(maMtxLines);
 
             if (!maUsedLines.empty())
             {
@@ -160,7 +171,7 @@ private:
                 mpStream->ReadLine( pLines->at(i) );
 
             aGuard.reset(); // lock
-            while (!mbTerminateReading && maPendingLines.size() >= 8)
+            while (!isTerminateRequested() && maPendingLines.size() >= 8)
             {
                 // pause reading for a bit
                 aGuard.clear(); // unlock
@@ -171,7 +182,7 @@ private:
             maPendingLines.push(pLines);
             maConsumeResume.set();
             if (!mpStream->good())
-                mbTerminateReading = true;
+                requestTerminate();
         }
     }
 };
@@ -267,11 +278,13 @@ OString DataStream::ConsumeLine()
     if (!mpLines || mnLinesCount >= mpLines->size())
     {
         mnLinesCount = 0;
-        if (mxReaderThread->mbTerminateReading)
+        if (mxReaderThread->isTerminateRequested())
             return OString();
-        osl::ResettableMutexGuard aGuard(mxReaderThread->maLinesProtector);
+
+        osl::ResettableMutexGuard aGuard(mxReaderThread->maMtxLines);
         if (mpLines)
             mxReaderThread->maUsedLines.push(mpLines);
+
         while (mxReaderThread->maPendingLines.empty())
         {
             aGuard.clear(); // unlock
@@ -279,6 +292,7 @@ OString DataStream::ConsumeLine()
             mxReaderThread->maConsumeResume.reset();
             aGuard.reset(); // lock
         }
+
         mpLines = mxReaderThread->maPendingLines.front();
         mxReaderThread->maPendingLines.pop();
         if (mxReaderThread->maPendingLines.size() <= 4)
commit 46ef36d86d7306764c5d2ae3ac6296dfa05e550c
Author: Kohei Yoshida <kohei.yosh...@collabora.com>
Date:   Fri Dec 27 21:57:25 2013 -0500

    Misc cleanup.
    
    Change-Id: Ia3d0f2e098804dabdbdd324562097b9f69528d35

diff --git a/sc/source/ui/docshell/datastream.cxx 
b/sc/source/ui/docshell/datastream.cxx
index 5852778..86be028 100644
--- a/sc/source/ui/docshell/datastream.cxx
+++ b/sc/source/ui/docshell/datastream.cxx
@@ -96,6 +96,15 @@ private:
     }
 };
 
+void emptyLineQueue( std::queue<LinesList*>& rQueue )
+{
+    while (!rQueue.empty())
+    {
+        delete rQueue.front();
+        rQueue.pop();
+    }
+}
+
 class ReaderThread : public salhelper::Thread
 {
     SvStream *mpStream;
@@ -117,23 +126,14 @@ public:
     virtual ~ReaderThread()
     {
         delete mpStream;
-        while (!maPendingLines.empty())
-        {
-            delete maPendingLines.front();
-            maPendingLines.pop();
-        }
-        while (!maUsedLines.empty())
-        {
-            delete maUsedLines.front();
-            maUsedLines.pop();
-        }
+        emptyLineQueue(maPendingLines);
+        emptyLineQueue(maUsedLines);
     }
 
     void endThread()
     {
         mbTerminateReading = true;
         maProduceResume.set();
-        join();
     }
 
 private:
@@ -141,8 +141,9 @@ private:
     {
         while (!mbTerminateReading)
         {
-            LinesList *pLines = 0;
+            LinesList* pLines = NULL;
             osl::ResettableMutexGuard aGuard(maLinesProtector);
+
             if (!maUsedLines.empty())
             {
                 pLines = maUsedLines.front();
@@ -154,11 +155,14 @@ private:
                 aGuard.clear(); // unlock
                 pLines = new LinesList(10);
             }
+
             for (size_t i = 0; i < pLines->size(); ++i)
                 mpStream->ReadLine( pLines->at(i) );
+
             aGuard.reset(); // lock
             while (!mbTerminateReading && maPendingLines.size() >= 8)
-            { // pause reading for a bit
+            {
+                // pause reading for a bit
                 aGuard.clear(); // unlock
                 maProduceResume.wait();
                 maProduceResume.reset();
@@ -251,7 +255,10 @@ DataStream::~DataStream()
     mxThread->maStart.set();
     mxThread->join();
     if (mxReaderThread.is())
+    {
         mxReaderThread->endThread();
+        mxReaderThread->join();
+    }
     delete mpLines;
 }
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to