[Libreoffice-commits] core.git: Branch 'private/kohei/calc-shared-string' - 3 commits - formula/source include/formula sc/qa sc/source
Kohei Yoshida
kohei.yoshida at collabora.com
Tue Oct 15 13:06:59 PDT 2013
formula/source/core/api/vectortoken.cxx | 11 +-
include/formula/vectortoken.hxx | 28 ++++-
sc/qa/unit/ucalc.hxx | 2
sc/qa/unit/ucalc_formula.cxx | 74 ++++++++++++++
sc/source/core/data/formulacell.cxx | 4
sc/source/core/tool/formulagroup.cxx | 160 ++++++++++++++++++++++++--------
6 files changed, 230 insertions(+), 49 deletions(-)
New commits:
commit cec617679b765611a17cd95a08f6e7029de989f7
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date: Tue Oct 15 16:07:08 2013 -0400
Right a new test case for fetching vector ref array.
This currently fails rightly.
Change-Id: Ic4d8d3d720b2ee879f963d1871dd8779461f352f
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 2c30f43..27bdaff 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -84,6 +84,7 @@ public:
void testRangeList();
void testInput();
+ void testFetchVectorRefArray();
void testFormulaHashAndTag();
void testFormulaRefData();
void testFormulaCompiler();
@@ -288,6 +289,7 @@ public:
CPPUNIT_TEST(testSharedStringPool);
CPPUNIT_TEST(testRangeList);
CPPUNIT_TEST(testInput);
+ CPPUNIT_TEST(testFetchVectorRefArray);
CPPUNIT_TEST(testFormulaHashAndTag);
CPPUNIT_TEST(testFormulaRefData);
CPPUNIT_TEST(testFormulaCompiler);
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index e85c01c55..ba73d11 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -16,15 +16,89 @@
#include "refdata.hxx"
#include "scopetools.hxx"
#include "formulacell.hxx"
+#include "formulagroup.hxx"
#include "inputopt.hxx"
#include "scmod.hxx"
#include "docsh.hxx"
#include "docfunc.hxx"
+#include "formula/vectortoken.hxx"
+
#include <boost/scoped_ptr.hpp>
using namespace formula;
+void Test::testFetchVectorRefArray()
+{
+ m_pDoc->InsertTab(0, "Test");
+
+ // All numeric cells in Column A.
+ m_pDoc->SetValue(ScAddress(0,0,0), 1);
+ m_pDoc->SetValue(ScAddress(0,1,0), 2);
+ m_pDoc->SetValue(ScAddress(0,2,0), 3);
+ m_pDoc->SetValue(ScAddress(0,3,0), 4);
+
+ sc::FormulaGroupContext aCxt;
+ formula::VectorRefArray aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(0,0,0), 4);
+ CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+ CPPUNIT_ASSERT_MESSAGE("Array is expected to be numeric cells only.", !aArray.mpStringArray);
+ CPPUNIT_ASSERT_EQUAL(1.0, aArray.mpNumericArray[0]);
+ CPPUNIT_ASSERT_EQUAL(2.0, aArray.mpNumericArray[1]);
+ CPPUNIT_ASSERT_EQUAL(3.0, aArray.mpNumericArray[2]);
+ CPPUNIT_ASSERT_EQUAL(4.0, aArray.mpNumericArray[3]);
+
+ aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(0,0,0), 5);
+ CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+ CPPUNIT_ASSERT_MESSAGE("Array is expected to be numeric cells only.", !aArray.mpStringArray);
+ CPPUNIT_ASSERT_EQUAL(1.0, aArray.mpNumericArray[0]);
+ CPPUNIT_ASSERT_EQUAL(2.0, aArray.mpNumericArray[1]);
+ CPPUNIT_ASSERT_EQUAL(3.0, aArray.mpNumericArray[2]);
+ CPPUNIT_ASSERT_EQUAL(4.0, aArray.mpNumericArray[3]);
+ CPPUNIT_ASSERT_MESSAGE("Empty cell should be represented by a NaN.", rtl::math::isNan(aArray.mpNumericArray[4]));
+
+ // All string cells in Column B. Note that the fetched string arrays are
+ // only to be compared case-insensitively. Right now, we use upper cased
+ // strings to achieve case-insensitive-ness, but that may change. So,
+ // don't count on that.
+ m_pDoc->SetString(ScAddress(1,0,0), "Andy");
+ m_pDoc->SetString(ScAddress(1,1,0), "Bruce");
+ m_pDoc->SetString(ScAddress(1,2,0), "Charlie");
+ m_pDoc->SetString(ScAddress(1,3,0), "David");
+ aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(1,0,0), 5);
+ CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+ CPPUNIT_ASSERT_MESSAGE("Array is expected to be string cells only.", !aArray.mpNumericArray);
+ CPPUNIT_ASSERT_MESSAGE("Failed on case in-sensitive equality test.", OUString(aArray.mpStringArray[0]).equalsIgnoreAsciiCaseAscii("Andy"));
+ CPPUNIT_ASSERT_MESSAGE("Failed on case in-sensitive equality test.", OUString(aArray.mpStringArray[1]).equalsIgnoreAsciiCaseAscii("Bruce"));
+ CPPUNIT_ASSERT_MESSAGE("Failed on case in-sensitive equality test.", OUString(aArray.mpStringArray[2]).equalsIgnoreAsciiCaseAscii("Charlie"));
+ CPPUNIT_ASSERT_MESSAGE("Failed on case in-sensitive equality test.", OUString(aArray.mpStringArray[3]).equalsIgnoreAsciiCaseAscii("David"));
+ CPPUNIT_ASSERT_MESSAGE("Empty cell should be represented by a NULL pointer.", !aArray.mpStringArray[4]);
+
+ // Mixture of numeric, string, and empty cells in Column C.
+ m_pDoc->SetString(ScAddress(2,0,0), "Header");
+ m_pDoc->SetValue(ScAddress(2,1,0), 11);
+ m_pDoc->SetValue(ScAddress(2,2,0), 12);
+ m_pDoc->SetValue(ScAddress(2,3,0), 13);
+ m_pDoc->SetString(ScAddress(2,5,0), "=SUM(C2:C4)");
+ m_pDoc->CalcAll();
+
+ aArray = m_pDoc->FetchVectorRefArray(aCxt, ScAddress(2,0,0), 7);
+ CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray.isValid());
+ CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray.mpNumericArray && aArray.mpStringArray);
+ CPPUNIT_ASSERT_MESSAGE("Failed on case in-sensitive equality test.", OUString(aArray.mpStringArray[0]).equalsIgnoreAsciiCaseAscii("Header"));
+ CPPUNIT_ASSERT_MESSAGE("String value should be NULL for numeric cell.", aArray.mpStringArray[1] == NULL);
+ CPPUNIT_ASSERT_MESSAGE("String value should be NULL for numeric cell.", aArray.mpStringArray[2] == NULL);
+ CPPUNIT_ASSERT_MESSAGE("String value should be NULL for numeric cell.", aArray.mpStringArray[3] == NULL);
+ CPPUNIT_ASSERT_EQUAL(11.0, aArray.mpNumericArray[1]);
+ CPPUNIT_ASSERT_EQUAL(12.0, aArray.mpNumericArray[2]);
+ CPPUNIT_ASSERT_EQUAL(13.0, aArray.mpNumericArray[3]);
+ CPPUNIT_ASSERT_MESSAGE("This cell should be empty.", aArray.mpStringArray[4] == NULL && rtl::math::isNan(aArray.mpNumericArray[4]));
+ CPPUNIT_ASSERT_MESSAGE("String value should be NULL for numeric cell.", aArray.mpStringArray[5] == NULL);
+ CPPUNIT_ASSERT_EQUAL(36.0, aArray.mpNumericArray[5]);
+ CPPUNIT_ASSERT_MESSAGE("This cell should be empty.", aArray.mpStringArray[6] == NULL && rtl::math::isNan(aArray.mpNumericArray[6]));
+
+ m_pDoc->DeleteTab(0);
+}
+
void Test::testFormulaHashAndTag()
{
m_pDoc->InsertTab(0, "Test");
commit f4a58f54f8a226839504b8c3461b0916cc80caa2
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date: Tue Oct 15 16:04:22 2013 -0400
More eye-pleasing way of checking for valid vector array...
Change-Id: If2f47a7d98a4cbc9e09dc98c1bb0e11f8f889265
diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index 206b9c9..55ab18e 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -15,6 +15,11 @@ VectorRefArray::VectorRefArray() : mpNumericArray(NULL), mpStringArray(NULL) {}
VectorRefArray::VectorRefArray( const double* pArray ) : mpNumericArray(pArray), mpStringArray(NULL) {}
VectorRefArray::VectorRefArray( rtl_uString** pArray ) : mpNumericArray(NULL), mpStringArray(pArray) {}
+bool VectorRefArray::isValid() const
+{
+ return mpNumericArray || mpStringArray;
+}
+
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 54043b1..3b1db68 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -40,6 +40,8 @@ struct FORMULA_DLLPUBLIC VectorRefArray
VectorRefArray();
VectorRefArray( const double* pArray );
VectorRefArray( rtl_uString** pArray );
+
+ bool isValid() const;
};
/**
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index dfcf352..9d32104 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 && !aArray.mpStringArray)
+ if (!aArray.isValid())
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 && !aArray.mpStringArray)
+ if (!aArray.isValid())
return false;
aArrays.push_back(aArray);
commit e647b2ff91fcfa5dda0278007148b05ee7fff2de
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date: Tue Oct 15 14:56:44 2013 -0400
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
diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index b752f5d..206b9c9 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 9bc82f3..54043b1 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 f3bf7fc..dfcf352 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 96ae83e..7f1bd74 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);
}
}
More information about the Libreoffice-commits
mailing list