From 7d0f3695a20df18f5f6e609f70b8d1ef7825302b Mon Sep 17 00:00:00 2001 From: Kohei Yoshida Date: Mon, 9 Sep 2013 18:00:08 -0400 Subject: 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 --- formula/source/core/api/vectortoken.cxx | 2 +- include/formula/vectortoken.hxx | 4 +- sc/inc/formulagroup.hxx | 7 ++- sc/source/core/data/column2.cxx | 10 ++++- sc/source/core/tool/formulagroup.cxx | 78 +++++++++++++++++++++++++++++++-- 5 files changed, 92 insertions(+), 9 deletions(-) diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx index 557e0c058595..b752f5d669ba 100644 --- a/formula/source/core/api/vectortoken.cxx +++ b/formula/source/core/api/vectortoken.cxx @@ -13,7 +13,7 @@ namespace formula { VectorRefArray::VectorRefArray() : mpNumericArray(NULL), mbNumeric(true) {} VectorRefArray::VectorRefArray( const double* pArray ) : mpNumericArray(pArray), mbNumeric(true) {} -VectorRefArray::VectorRefArray( const OUString* pArray ) : mpStringArray(pArray), mbNumeric(false) {} +VectorRefArray::VectorRefArray( rtl_uString** pArray ) : mpStringArray(pArray), mbNumeric(false) {} SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) : FormulaToken(svSingleVectorRef, ocPush), maArray(pArray), mnArrayLength(nLength) {} diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx index 5186ca526922..9bc82f345e33 100644 --- a/include/formula/vectortoken.hxx +++ b/include/formula/vectortoken.hxx @@ -18,14 +18,14 @@ struct FORMULA_DLLPUBLIC VectorRefArray { union { const double* mpNumericArray; - const OUString* mpStringArray; + rtl_uString** mpStringArray; }; bool mbNumeric; VectorRefArray(); VectorRefArray( const double* pArray ); - VectorRefArray( const OUString* pArray ); + VectorRefArray( rtl_uString** pArray ); }; /** 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 #include +#include class ScDocument; class ScTokenArray; @@ -23,13 +24,17 @@ namespace sc { struct FormulaGroupContext : boost::noncopyable { + typedef boost::unordered_set StrHashType; typedef std::vector NumArrayType; - typedef std::vector StrArrayType; + typedef std::vector StrArrayType; typedef boost::ptr_vector NumArrayStoreType; typedef boost::ptr_vector 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 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 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 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(i) < p2->GetArrayLength() ? rArray.mpStringArray[i] : OUString()); + { + rtl_uString* pStr = NULL; + if (static_cast(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); } } -- cgit