summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2013-09-09 18:00:08 -0400
committerKohei Yoshida <kohei.yoshida@collabora.com>2013-09-10 11:47:45 -0400
commit7d0f3695a20df18f5f6e609f70b8d1ef7825302b (patch)
tree914a0de4fd1792e7cdd3baa55ea7e630569847c1 /sc
parent6dd0d051e986b868bf2225c16137e72d6e2dd3b6 (diff)
Correctly handle empty cells for string arrays too.
Because we need to make a distinction between an empty cell and a string cell containing zero-length string, I decided to switch to using rtl_uString* array and use NULL values as empty cells. Change-Id: I5bedb593507f34782e41a8a900602d445e5b1f6f
Diffstat (limited to 'sc')
-rw-r--r--sc/inc/formulagroup.hxx7
-rw-r--r--sc/source/core/data/column2.cxx10
-rw-r--r--sc/source/core/tool/formulagroup.cxx78
3 files changed, 89 insertions, 6 deletions
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index 776b24d9b348..f57b23722940 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -15,6 +15,7 @@
#include <boost/noncopyable.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/unordered_set.hpp>
class ScDocument;
class ScTokenArray;
@@ -23,13 +24,17 @@ namespace sc {
struct FormulaGroupContext : boost::noncopyable
{
+ typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
typedef std::vector<double> NumArrayType;
- typedef std::vector<OUString> StrArrayType;
+ typedef std::vector<rtl_uString*> StrArrayType;
typedef boost::ptr_vector<NumArrayType> NumArrayStoreType;
typedef boost::ptr_vector<StrArrayType> StrArrayStoreType;
+ StrHashType maStrPool;
NumArrayStoreType maNumArrays;
StrArrayStoreType maStrArrays;
+
+ rtl_uString* intern( const OUString& rStr );
};
/**
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 34ecbb2f79f7..7a97972e0c2a 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2256,8 +2256,16 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
if (nLenRequested <= nLen)
{
// Requested length fits a single block.
+ rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType);
+ sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
+ rArray.reserve(nLenRequested);
+
const OUString* p = &sc::string_block::at(*aPos.first->data, aPos.second);
- return formula::VectorRefArray(p);
+ const OUString* pEnd = p + nLenRequested;
+ for (; p != pEnd; ++p)
+ rArray.push_back(rCxt.intern(*p));
+
+ return formula::VectorRefArray(&rArray[0]);
}
// TODO: handle cases where the requested length goes beyond the
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index f6a1dff37e5d..0b37b97600cf 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -29,6 +29,23 @@
namespace sc {
+rtl_uString* FormulaGroupContext::intern( const OUString& rStr )
+{
+ StrHashType::iterator it = maStrPool.find(rStr);
+ if (it == maStrPool.end())
+ {
+ // Not yet in the pool.
+ std::pair<StrHashType::iterator, bool> r = maStrPool.insert(rStr.intern());
+ if (!r.second)
+ // Insertion failed.
+ return NULL;
+
+ it = r.first;
+ }
+
+ return it->pData;
+}
+
namespace {
/**
@@ -63,7 +80,49 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen )
{
// Flush last non-NaN segment to the matrix.
rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums);
- pHead = NULL;
+ }
+}
+
+void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
+{
+ rtl_uString** p = pStrs;
+ rtl_uString** pEnd = p + nLen;
+ rtl_uString** pHead = NULL;
+ for (; p != pEnd; ++p)
+ {
+ if (*p)
+ {
+ if (!pHead)
+ // Store the first non-empty string position.
+ pHead = p;
+
+ continue;
+ }
+
+ if (pHead)
+ {
+ // Flush this non-empty segment to the matrix.
+ size_t nOffset = pHead - pStrs;
+ std::vector<OUString> aStrs;
+ aStrs.reserve(p - pHead);
+ for (; pHead != p; ++pHead)
+ aStrs.push_back(OUString(*pHead));
+
+ rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
+ pHead = NULL;
+ }
+ }
+
+ if (pHead)
+ {
+ // Flush last non-empty segment to the matrix.
+ size_t nOffset = pHead - pStrs;
+ std::vector<OUString> aStrs;
+ aStrs.reserve(p - pHead);
+ for (; pHead != p; ++pHead)
+ aStrs.push_back(OUString(*pHead));
+
+ rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
}
}
@@ -124,7 +183,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
aCode2.AddDouble(fVal);
}
else
- aCode2.AddString(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpStringArray[i] : OUString());
+ {
+ rtl_uString* pStr = NULL;
+ if (static_cast<size_t>(i) < p2->GetArrayLength())
+ pStr = rArray.mpStringArray[i];
+
+ if (pStr)
+ aCode2.AddString(OUString(pStr));
+ }
}
break;
case formula::svDoubleVectorRef:
@@ -138,6 +204,10 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
nRowEnd += i;
size_t nRowSize = nRowEnd - nRowStart + 1;
ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize));
+ if (p2->GetArrayLength() < nRowSize)
+ // Data array is shorter than the row size of the reference. Truncate it.
+ nRowSize = p2->GetArrayLength();
+
for (size_t nCol = 0; nCol < nColSize; ++nCol)
{
const formula::VectorRefArray& rArray = rArrays[nCol];
@@ -149,9 +219,9 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
}
else
{
- const OUString* pStrs = rArray.mpStringArray;
+ rtl_uString** pStrs = rArray.mpStringArray;
pStrs += nRowStart;
- pMat->PutString(pStrs, nRowSize, nCol, 0);
+ fillMatrix(*pMat, nCol, pStrs, nRowSize);
}
}