summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2013-10-15 14:56:44 -0400
committerKohei Yoshida <kohei.yoshida@collabora.com>2013-10-18 23:22:39 -0400
commit7586151cbea2d3b93b42a42aa8dd157e75ca4f60 (patch)
treed36752372db3648e011ca6c078897a8ddf832d78
parentInitial experimental support for Visual Studio 2013 (diff)
downloadcore-7586151cbea2d3b93b42a42aa8dd157e75ca4f60.tar.gz
core-7586151cbea2d3b93b42a42aa8dd157e75ca4f60.zip
Allow vector array tokens to store both numeric and string values.
This is achieved by storing two physical arrays in each vector reference array. Change-Id: Iafb9e57b86e57e75eed8ff692a6d882c2049f710
-rw-r--r--formula/source/core/api/vectortoken.cxx6
-rw-r--r--include/formula/vectortoken.hxx26
-rw-r--r--sc/source/core/data/formulacell.cxx4
-rw-r--r--sc/source/core/tool/formulagroup.cxx160
4 files changed, 147 insertions, 49 deletions
diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index b752f5d669ba..206b9c9da8e8 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -11,9 +11,9 @@
namespace formula {
-VectorRefArray::VectorRefArray() : mpNumericArray(NULL), mbNumeric(true) {}
-VectorRefArray::VectorRefArray( const double* pArray ) : mpNumericArray(pArray), mbNumeric(true) {}
-VectorRefArray::VectorRefArray( rtl_uString** pArray ) : mpStringArray(pArray), mbNumeric(false) {}
+VectorRefArray::VectorRefArray() : mpNumericArray(NULL), mpStringArray(NULL) {}
+VectorRefArray::VectorRefArray( const double* pArray ) : mpNumericArray(pArray), mpStringArray(NULL) {}
+VectorRefArray::VectorRefArray( rtl_uString** pArray ) : mpNumericArray(NULL), mpStringArray(pArray) {}
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 9bc82f345e33..54043b114990 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -14,14 +14,28 @@
namespace formula {
+/**
+ * Single unit of vector reference consists of two physical arrays.
+ *
+ * <p>If the whole data array consists of only numeric values, mpStringArray
+ * will be NULL, and NaN values in the numeric array represent empty
+ * cells.</p>
+ *
+ * <p>If the whole data array consists of only string values, mpNumericArray
+ * will be NULL, and NULL values in the string array represent empty
+ * cells.</p>
+ *
+ * <p>If the data array consists of numeric and string values, then both
+ * mpNumericArray and mpStringArray will be non-NULL, and a string cell will
+ * be represented by a non-NULL pointer value in the string array. If the
+ * string value is NULL, check the corresponding value in the numeric array.
+ * If the value in the numeric array is NaN, it's an empty cell, otherwise
+ * it's a numeric cell.</p>
+ */
struct FORMULA_DLLPUBLIC VectorRefArray
{
- union {
- const double* mpNumericArray;
- rtl_uString** mpStringArray;
- };
-
- bool mbNumeric;
+ const double* mpNumericArray;
+ rtl_uString** mpStringArray;
VectorRefArray();
VectorRefArray( const double* pArray );
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index f3bf7fcbd059..dfcf352145d5 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3420,7 +3420,7 @@ public:
// length.
formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(mrCxt, aRefPos, nLen);
- if (!aArray.mpNumericArray)
+ if (!aArray.mpNumericArray && !aArray.mpStringArray)
return false;
formula::SingleVectorRefToken aTok(aArray, nLen);
@@ -3488,7 +3488,7 @@ public:
{
aRefPos.SetCol(i);
formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(mrCxt, aRefPos, nArrayLength);
- if (!aArray.mpNumericArray)
+ if (!aArray.mpNumericArray && !aArray.mpStringArray)
return false;
aArrays.push_back(aArray);
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 96ae83e46800..7f1bd747d78c 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -47,43 +47,43 @@ namespace {
*/
void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen )
{
- const double* p = pNums;
- const double* pEnd = p + nLen;
- const double* pHead = NULL;
- for (; p != pEnd; ++p)
+ const double* pNum = pNums;
+ const double* pNumEnd = pNum + nLen;
+ const double* pNumHead = NULL;
+ for (; pNum != pNumEnd; ++pNum)
{
- if (!rtl::math::isNan(*p))
+ if (!rtl::math::isNan(*pNum))
{
- if (!pHead)
+ if (!pNumHead)
// Store the first non-NaN position.
- pHead = p;
+ pNumHead = pNum;
continue;
}
- if (pHead)
+ if (pNumHead)
{
// Flush this non-NaN segment to the matrix.
- rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums);
- pHead = NULL;
+ rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
+ pNumHead = NULL;
}
}
- if (pHead)
+ if (pNumHead)
{
// Flush last non-NaN segment to the matrix.
- rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums);
+ rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
}
}
-void flushSegment(
+void flushStrSegment(
ScMatrix& rMat, size_t nCol, rtl_uString** pHead, rtl_uString** pCur, rtl_uString** pTop )
{
size_t nOffset = pHead - pTop;
std::vector<svl::SharedString> aStrs;
aStrs.reserve(pCur - pHead);
for (; pHead != pCur; ++pHead)
- aStrs.push_back(svl::SharedString(*pHead, NULL));
+ aStrs.push_back(svl::SharedString(*pHead, *pHead));
rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
}
@@ -107,7 +107,7 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
if (pHead)
{
// Flush this non-empty segment to the matrix.
- flushSegment(rMat, nCol, pHead, p, pStrs);
+ flushStrSegment(rMat, nCol, pHead, p, pStrs);
pHead = NULL;
}
}
@@ -115,7 +115,75 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
if (pHead)
{
// Flush last non-empty segment to the matrix.
- flushSegment(rMat, nCol, pHead, p, pStrs);
+ flushStrSegment(rMat, nCol, pHead, p, pStrs);
+ }
+}
+
+void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, rtl_uString** pStrs, size_t nLen )
+{
+ if (!pStrs)
+ {
+ fillMatrix(rMat, nCol, pNums, nLen);
+ return;
+ }
+
+ const double* pNum = pNums;
+ const double* pNumHead = NULL;
+ rtl_uString** pStr = pStrs;
+ rtl_uString** pStrEnd = pStr + nLen;
+ rtl_uString** pStrHead = NULL;
+
+ for (; pStr != pStrEnd; ++pStr, ++pNum)
+ {
+ if (*pStr)
+ {
+ // String cell exists.
+
+ if (pNumHead)
+ {
+ // Flush this numeric segment to the matrix.
+ rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
+ pNumHead = NULL;
+ }
+
+ if (!pStrHead)
+ // Store the first non-empty string position.
+ pStrHead = pStr;
+
+ continue;
+ }
+
+ // No string cell. Check the numeric cell value.
+
+ if (pStrHead)
+ {
+ // Flush this non-empty string segment to the matrix.
+ flushStrSegment(rMat, nCol, pStrHead, pStr, pStrs);
+ pStrHead = NULL;
+ }
+
+ if (!rtl::math::isNan(*pNum))
+ {
+ // Numeric cell exists.
+ if (!pNumHead)
+ // Store the first non-NaN position.
+ pNumHead = pNum;
+
+ continue;
+ }
+
+ // Empty cell. No action required.
+ }
+
+ if (pStrHead)
+ {
+ // Flush the last non-empty segment to the matrix.
+ flushStrSegment(rMat, nCol, pStrHead, pStr, pStrs);
+ }
+ else if (pNumHead)
+ {
+ // Flush the last numeric segment to the matrix.
+ rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
}
}
@@ -168,26 +236,28 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
{
const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
const formula::VectorRefArray& rArray = p2->GetArray();
- if (rArray.mbNumeric)
- {
- double fVal = fNan;
- if (static_cast<size_t>(i) < p2->GetArrayLength())
- fVal = rArray.mpNumericArray[i];
- if (rtl::math::isNan(fVal))
- aCode2.AddToken(ScEmptyCellToken(false, false));
- else
- aCode2.AddDouble(fVal);
- }
- else
+ rtl_uString* pStr = NULL;
+ double fVal = fNan;
+ if (static_cast<size_t>(i) < p2->GetArrayLength())
{
- rtl_uString* pStr = NULL;
- if (static_cast<size_t>(i) < p2->GetArrayLength())
+ if (rArray.mpStringArray)
+ // See if the cell is of string type.
pStr = rArray.mpStringArray[i];
- if (pStr)
- aCode2.AddString(OUString(pStr));
+ if (!pStr && rArray.mpNumericArray)
+ fVal = rArray.mpNumericArray[i];
}
+
+ if (pStr)
+ // This is a string cell.
+ aCode2.AddString(OUString(pStr));
+ else if (rtl::math::isNan(fVal))
+ // Value of NaN represents an empty cell.
+ aCode2.AddToken(ScEmptyCellToken(false, false));
+ else
+ // Numeric cell.
+ aCode2.AddDouble(fVal);
}
break;
case formula::svDoubleVectorRef:
@@ -213,17 +283,31 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
for (size_t nCol = 0; nCol < nColSize; ++nCol)
{
const formula::VectorRefArray& rArray = rArrays[nCol];
- if (rArray.mbNumeric)
+ if (rArray.mpStringArray)
{
- const double* pNums = rArray.mpNumericArray;
- pNums += nRowStart;
- fillMatrix(*pMat, nCol, pNums, nRowSize);
+ if (rArray.mpNumericArray)
+ {
+ // Mixture of string and numeric values.
+ const double* pNums = rArray.mpNumericArray;
+ pNums += nRowStart;
+ rtl_uString** pStrs = rArray.mpStringArray;
+ pStrs += nRowStart;
+ fillMatrix(*pMat, nCol, pNums, pStrs, nRowSize);
+ }
+ else
+ {
+ // String cells only.
+ rtl_uString** pStrs = rArray.mpStringArray;
+ pStrs += nRowStart;
+ fillMatrix(*pMat, nCol, pStrs, nRowSize);
+ }
}
else
{
- rtl_uString** pStrs = rArray.mpStringArray;
- pStrs += nRowStart;
- fillMatrix(*pMat, nCol, pStrs, nRowSize);
+ // Numeric cells only.
+ const double* pNums = rArray.mpNumericArray;
+ pNums += nRowStart;
+ fillMatrix(*pMat, nCol, pNums, nRowSize);
}
}