summaryrefslogtreecommitdiff
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
parent3164924fac45a377b3620ca68e7658be19999359 (diff)
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);
}
}