tdf#126109 calc slow when replacing string to number
Store SharedString inline in ScCellValue.
Shaves 10% off time.
Use std::variant to handle the complexities of correctly calling
constructor and destructor of SharedString.
Change-Id: I820de5339e31434fbdbde1a72e25abe207bf008d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135863
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/sc/inc/cellvalue.hxx b/sc/inc/cellvalue.hxx
index 1095d32..caf42d2 100644
--- a/sc/inc/cellvalue.hxx
+++ b/sc/inc/cellvalue.hxx
@@ -10,6 +10,8 @@
#pragma once
#include "global.hxx"
#include <svl/sharedstring.hxx>
#include <variant>
class ScDocument;
class ScFormulaCell;
@@ -21,12 +23,6 @@ namespace sc {
struct ColumnBlockPosition;
}
namespace svl {
class SharedString;
}
/**
* Store arbitrary cell value of any kind. It only stores cell value and
* nothing else. It creates a copy of the original cell value, and manages
@@ -34,15 +30,8 @@ class SharedString;
*/
struct SC_DLLPUBLIC ScCellValue
{
private:
CellType meType;
public:
union {
double mfValue1;
svl::SharedString* mpString;
EditTextObject* mpEditText1;
ScFormulaCell* mpFormula1;
};
/// bool is there to indicate CellType::NONE
std::variant<bool, double, svl::SharedString, EditTextObject*, ScFormulaCell*> maData;
ScCellValue();
ScCellValue( const ScRefCellValue& rCell );
@@ -61,25 +50,13 @@ public:
void set( std::unique_ptr<EditTextObject> );
void set( ScFormulaCell* pFormula );
CellType getType() const { return meType; }
double getDouble() const { assert(meType == CELLTYPE_VALUE); return mfValue1; }
svl::SharedString* getSharedString() const { assert(meType == CELLTYPE_STRING); return mpString; }
EditTextObject* getEditText() const { assert(meType == CELLTYPE_EDIT); return mpEditText1; }
EditTextObject* releaseEditText()
{
assert(meType == CELLTYPE_EDIT);
auto p = mpEditText1;
mpEditText1 = nullptr;
return p;
}
ScFormulaCell* getFormula() const { assert(meType == CELLTYPE_FORMULA); return mpFormula1; }
ScFormulaCell* releaseFormula()
{
assert(meType == CELLTYPE_FORMULA);
auto p = mpFormula1;
mpFormula1 = nullptr;
return p;
}
CellType getType() const;
double getDouble() const { return std::get<double>(maData); }
ScFormulaCell* getFormula() const { return std::get<ScFormulaCell*>(maData); }
const svl::SharedString* getSharedString() const { return &std::get<svl::SharedString>(maData); }
EditTextObject* getEditText() const { return std::get<EditTextObject*>(maData); }
EditTextObject* releaseEditText() { auto p = getEditText(); maData = static_cast<EditTextObject*>(nullptr); return p; }
ScFormulaCell* releaseFormula() { auto p = getFormula(); maData = static_cast<ScFormulaCell*>(nullptr); return p; }
/**
* Take cell value from specified position in specified document.
@@ -125,6 +102,8 @@ public:
*/
struct SC_DLLPUBLIC ScRefCellValue
{
/// bool is there to indicate CellType::NONE
std::variant<bool, double, svl::SharedString, EditTextObject*, ScFormulaCell*> maData;
private:
CellType meType;
public:
diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx
index fa246b3..e378677 100644
--- a/sc/source/core/data/cellvalue.cxx
+++ b/sc/source/core/data/cellvalue.cxx
@@ -38,17 +38,17 @@ template<typename T>
OUString getString( const T& rVal )
{
if (rVal.getType() == CELLTYPE_STRING)
return rVal.mpString->getString();
return rVal.getSharedString()->getString();
if (rVal.getType() == CELLTYPE_EDIT)
{
OUStringBuffer aRet;
sal_Int32 n = rVal.mpEditText1->GetParagraphCount();
sal_Int32 n = rVal.getEditText()->GetParagraphCount();
for (sal_Int32 i = 0; i < n; ++i)
{
if (i > 0)
aRet.append('\n');
aRet.append(rVal.mpEditText1->GetText(i));
aRet.append(rVal.getEditText()->GetText(i));
}
return aRet.makeStringAndClear();
}
@@ -107,15 +107,42 @@ bool equalsWithoutFormatImpl( const T& left, const T& right )
return false;
}
bool equalsWithoutFormatImpl( const ScCellValue& left, const ScCellValue& right )
{
CellType eType1 = adjustCellType(left.getType());
CellType eType2 = adjustCellType(right.getType());
if (eType1 != eType2)
return false;
switch (eType1)
{
case CELLTYPE_NONE:
return true;
case CELLTYPE_VALUE:
return left.getDouble() == right.getDouble();
case CELLTYPE_STRING:
{
OUString aStr1 = getString(left);
OUString aStr2 = getString(right);
return aStr1 == aStr2;
}
case CELLTYPE_FORMULA:
return equalsFormulaCells(left.getFormula(), right.getFormula());
default:
;
}
return false;
}
void commitToColumn( const ScCellValue& rCell, ScColumn& rColumn, SCROW nRow )
{
switch (rCell.getType())
{
case CELLTYPE_STRING:
rColumn.SetRawString(nRow, *rCell.mpString);
rColumn.SetRawString(nRow, *rCell.getSharedString());
break;
case CELLTYPE_EDIT:
rColumn.SetEditText(nRow, ScEditUtil::Clone(*rCell.mpEditText1, rColumn.GetDoc()));
rColumn.SetEditText(nRow, ScEditUtil::Clone(*rCell.getEditText(), rColumn.GetDoc()));
break;
case CELLTYPE_VALUE:
rColumn.SetValue(nRow, rCell.getDouble());
@@ -123,7 +150,7 @@ void commitToColumn( const ScCellValue& rCell, ScColumn& rColumn, SCROW nRow )
case CELLTYPE_FORMULA:
{
ScAddress aDestPos(rColumn.GetCol(), nRow, rColumn.GetTab());
rColumn.SetFormulaCell(nRow, new ScFormulaCell(*rCell.mpFormula1, rColumn.GetDoc(), aDestPos));
rColumn.SetFormulaCell(nRow, new ScFormulaCell(*rCell.getFormula(), rColumn.GetDoc(), aDestPos));
}
break;
default:
@@ -158,21 +185,21 @@ bool hasNumericImpl( CellType eType, ScFormulaCell* pFormula )
}
}
template<typename CellT>
OUString getStringImpl( const CellT& rCell, const ScDocument* pDoc )
template <typename T>
OUString getStringImpl( const T& rCell, const ScDocument* pDoc )
{
switch (rCell.getType())
{
case CELLTYPE_VALUE:
return OUString::number(rCell.getDouble());
case CELLTYPE_STRING:
return rCell.mpString->getString();
return rCell.getSharedString()->getString();
case CELLTYPE_EDIT:
if (rCell.mpEditText1)
return ScEditUtil::GetString(*rCell.mpEditText1, pDoc);
if (rCell.getEditText())
return ScEditUtil::GetString(*rCell.getEditText(), pDoc);
break;
case CELLTYPE_FORMULA:
return rCell.mpFormula1->GetString().getString();
return rCell.getFormula()->GetString().getString();
default:
;
}
@@ -202,69 +229,58 @@ OUString getRawStringImpl( const CellT& rCell, const ScDocument& rDoc )
}
ScCellValue::ScCellValue() : meType(CELLTYPE_NONE), mfValue1(0.0) {}
ScCellValue::ScCellValue() {}
ScCellValue::ScCellValue( const ScRefCellValue& rCell ) : meType(rCell.getType()), mfValue1(rCell.mfValue1)
ScCellValue::ScCellValue( const ScRefCellValue& rCell )
{
switch (rCell.getType())
{
case CELLTYPE_STRING:
mpString = new svl::SharedString(*rCell.mpString);
maData = *rCell.mpString;
break;
case CELLTYPE_EDIT:
mpEditText1 = rCell.mpEditText1->Clone().release();
maData = rCell.getEditText()->Clone().release();
break;
case CELLTYPE_FORMULA:
mpFormula1 = rCell.mpFormula1->Clone();
maData = rCell.getFormula()->Clone();
break;
default:
;
case CELLTYPE_VALUE:
maData = rCell.getDouble();
break;
default: ;
}
}
ScCellValue::ScCellValue( double fValue ) : meType(CELLTYPE_VALUE), mfValue1(fValue) {}
ScCellValue::ScCellValue( double fValue ) : maData(fValue) {}
ScCellValue::ScCellValue( const svl::SharedString& rString ) : meType(CELLTYPE_STRING), mpString(new svl::SharedString(rString)) {}
ScCellValue::ScCellValue( const svl::SharedString& rString ) : maData(rString) {}
ScCellValue::ScCellValue( std::unique_ptr<EditTextObject> xEdit ) : meType(CELLTYPE_EDIT), mpEditText1(xEdit.release()) {}
ScCellValue::ScCellValue( std::unique_ptr<EditTextObject> xEdit ) : maData(xEdit.release()) {}
ScCellValue::ScCellValue( const ScCellValue& r ) : meType(r.meType), mfValue1(r.mfValue1)
ScCellValue::ScCellValue( const ScCellValue& r )
{
switch (r.meType)
switch (r.getType())
{
case CELLTYPE_STRING:
mpString = new svl::SharedString(*r.mpString);
maData = *r.getSharedString();
break;
case CELLTYPE_EDIT:
mpEditText1 = r.mpEditText1->Clone().release();
maData = r.getEditText()->Clone().release();
break;
case CELLTYPE_FORMULA:
mpFormula1 = r.mpFormula1->Clone();
maData = r.getFormula()->Clone();
break;
default:
;
case CELLTYPE_VALUE:
maData = r.getDouble();
break;
default: ;
}
}
ScCellValue::ScCellValue(ScCellValue&& r) noexcept
: meType(r.meType)
, mfValue1(r.mfValue1)
: maData(std::move(r.maData))
{
switch (r.meType)
{
case CELLTYPE_STRING:
mpString = r.mpString;
break;
case CELLTYPE_EDIT:
mpEditText1 = r.mpEditText1;
break;
case CELLTYPE_FORMULA:
mpFormula1 = r.mpFormula1;
break;
default:
;
}
r.meType = CELLTYPE_NONE;
r.maData = true; // reset to empty;
}
ScCellValue::~ScCellValue()
@@ -272,61 +288,67 @@ ScCellValue::~ScCellValue()
clear();
}
CellType ScCellValue::getType() const
{
switch (maData.index())
{
case 0: return CELLTYPE_NONE;
case 1: return CELLTYPE_VALUE;
case 2: return CELLTYPE_STRING;
case 3: return CELLTYPE_EDIT;
case 4: return CELLTYPE_FORMULA;
default:
assert(false);
return CELLTYPE_NONE;
}
}
void ScCellValue::clear() noexcept
{
switch (meType)
switch (getType())
{
case CELLTYPE_STRING:
delete mpString;
break;
case CELLTYPE_EDIT:
delete mpEditText1;
delete getEditText();
break;
case CELLTYPE_FORMULA:
delete mpFormula1;
delete getFormula();
break;
default:
;
}
// Reset to empty value.
meType = CELLTYPE_NONE;
mfValue1 = 0.0;
maData = true;
}
void ScCellValue::set( double fValue )
{
clear();
meType = CELLTYPE_VALUE;
mfValue1 = fValue;
maData = fValue;
}
void ScCellValue::set( const svl::SharedString& rStr )
{
clear();
meType = CELLTYPE_STRING;
mpString = new svl::SharedString(rStr);
maData = rStr;
}
void ScCellValue::set( const EditTextObject& rEditText )
{
clear();
meType = CELLTYPE_EDIT;
mpEditText1 = rEditText.Clone().release();
maData = rEditText.Clone().release();
}
void ScCellValue::set( std::unique_ptr<EditTextObject> xEditText )
{
clear();
meType = CELLTYPE_EDIT;
mpEditText1 = xEditText.release();
maData = xEditText.release();
}
void ScCellValue::set( ScFormulaCell* pFormula )
{
clear();
meType = CELLTYPE_FORMULA;
mpFormula1 = pFormula;
maData = pFormula;
}
void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos )
@@ -335,24 +357,21 @@ void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos )
ScRefCellValue aRefVal(const_cast<ScDocument&>(rDoc), rPos);
meType = aRefVal.getType();
switch (meType)
switch (aRefVal.getType())
{
case CELLTYPE_STRING:
mpString = new svl::SharedString(*aRefVal.mpString);
maData = *aRefVal.mpString;
break;
case CELLTYPE_EDIT:
if (aRefVal.mpEditText1)
mpEditText1 = aRefVal.mpEditText1->Clone().release();
maData = aRefVal.mpEditText1 ? aRefVal.mpEditText1->Clone().release() : static_cast<EditTextObject*>(nullptr);
break;
case CELLTYPE_VALUE:
mfValue1 = aRefVal.mfValue1;
maData = aRefVal.mfValue1;
break;
case CELLTYPE_FORMULA:
mpFormula1 = aRefVal.mpFormula1->Clone();
maData = aRefVal.mpFormula1->Clone();
break;
default:
meType = CELLTYPE_NONE; // reset to empty.
default: ; // leave empty
}
}
@@ -360,66 +379,64 @@ void ScCellValue::assign(const ScCellValue& rOther, ScDocument& rDestDoc, ScClon
{
clear();
meType = rOther.meType;
switch (meType)
switch (rOther.getType())
{
case CELLTYPE_STRING:
mpString = new svl::SharedString(*rOther.mpString);
maData = rOther.maData;
break;
case CELLTYPE_EDIT:
{
// Switch to the pool of the destination document.
ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
if (rOther.mpEditText1->HasOnlineSpellErrors())
if (rOther.getEditText()->HasOnlineSpellErrors())
{
EEControlBits nControl = rEngine.GetControlWord();
const EEControlBits nSpellControl = EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS;
bool bNewControl = ((nControl & nSpellControl) != nSpellControl);
if (bNewControl)
rEngine.SetControlWord(nControl | nSpellControl);
rEngine.SetTextCurrentDefaults(*rOther.mpEditText1);
mpEditText1 = rEngine.CreateTextObject().release();
rEngine.SetTextCurrentDefaults(*rOther.getEditText());
maData = rEngine.CreateTextObject().release();
if (bNewControl)
rEngine.SetControlWord(nControl);
}
else
{
rEngine.SetTextCurrentDefaults(*rOther.mpEditText1);
mpEditText1 = rEngine.CreateTextObject().release();
rEngine.SetTextCurrentDefaults(*rOther.getEditText());
maData = rEngine.CreateTextObject().release();
}
}
break;
case CELLTYPE_VALUE:
mfValue1 = rOther.mfValue1;
maData = rOther.maData;
break;
case CELLTYPE_FORMULA:
// Switch to the destination document.
mpFormula1 = new ScFormulaCell(*rOther.mpFormula1, rDestDoc, rOther.mpFormula1->aPos, nCloneFlags);
maData = new ScFormulaCell(*rOther.getFormula(), rDestDoc, rOther.getFormula()->aPos, nCloneFlags);
break;
default:
meType = CELLTYPE_NONE; // reset to empty.
default: ; // leave empty
}
}
void ScCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
{
switch (meType)
switch (getType())
{
case CELLTYPE_STRING:
{
ScSetStringParam aParam;
aParam.setTextInput();
rDoc.SetString(rPos, mpString->getString(), &aParam);
rDoc.SetString(rPos, getSharedString()->getString(), &aParam);
}
break;
case CELLTYPE_EDIT:
rDoc.SetEditText(rPos, mpEditText1->Clone());
rDoc.SetEditText(rPos, getEditText()->Clone());
break;
case CELLTYPE_VALUE:
rDoc.SetValue(rPos, mfValue1);
rDoc.SetValue(rPos, getDouble());
break;
case CELLTYPE_FORMULA:
rDoc.SetFormulaCell(rPos, mpFormula1->Clone());
rDoc.SetFormulaCell(rPos, getFormula()->Clone());
break;
default:
rDoc.SetEmptyCell(rPos);
@@ -433,64 +450,60 @@ void ScCellValue::commit( ScColumn& rColumn, SCROW nRow ) const
void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos )
{
switch (meType)
switch (getType())
{
case CELLTYPE_STRING:
{
// Currently, string cannot be placed without copying.
ScSetStringParam aParam;
aParam.setTextInput();
rDoc.SetString(rPos, mpString->getString(), &aParam);
delete mpString;
rDoc.SetString(rPos, getSharedString()->getString(), &aParam);
}
break;
case CELLTYPE_EDIT:
// Cell takes the ownership of the text object.
rDoc.SetEditText(rPos, std::unique_ptr<EditTextObject>(mpEditText1));
rDoc.SetEditText(rPos, std::unique_ptr<EditTextObject>(getEditText()));
break;
case CELLTYPE_VALUE:
rDoc.SetValue(rPos, mfValue1);
rDoc.SetValue(rPos, getDouble());
break;
case CELLTYPE_FORMULA:
// This formula cell instance is directly placed in the document without copying.
rDoc.SetFormulaCell(rPos, mpFormula1);
rDoc.SetFormulaCell(rPos, getFormula());
break;
default:
rDoc.SetEmptyCell(rPos);
}
meType = CELLTYPE_NONE;
mfValue1 = 0.0;
maData = true; // reset to empty
}
void ScCellValue::release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType )
{
switch (meType)
switch (getType())
{
case CELLTYPE_STRING:
{
// Currently, string cannot be placed without copying.
rColumn.SetRawString(nRow, *mpString);
delete mpString;
rColumn.SetRawString(nRow, *getSharedString());
}
break;
case CELLTYPE_EDIT:
// Cell takes the ownership of the text object.
rColumn.SetEditText(nRow, std::unique_ptr<EditTextObject>(mpEditText1));
rColumn.SetEditText(nRow, std::unique_ptr<EditTextObject>(getEditText()));
break;
case CELLTYPE_VALUE:
rColumn.SetValue(nRow, mfValue1);
rColumn.SetValue(nRow, getDouble());
break;
case CELLTYPE_FORMULA:
// This formula cell instance is directly placed in the document without copying.
rColumn.SetFormulaCell(nRow, mpFormula1, eListenType);
rColumn.SetFormulaCell(nRow, getFormula(), eListenType);
break;
default:
rColumn.DeleteContent(nRow);
}
meType = CELLTYPE_NONE;
mfValue1 = 0.0;
maData = true; // reset to empty
}
OUString ScCellValue::getString( const ScDocument& rDoc ) const
@@ -500,7 +513,7 @@ OUString ScCellValue::getString( const ScDocument& rDoc ) const
bool ScCellValue::isEmpty() const
{
return meType == CELLTYPE_NONE;
return getType() == CELLTYPE_NONE;
}
bool ScCellValue::equalsWithoutFormat( const ScCellValue& r ) const
@@ -518,27 +531,8 @@ ScCellValue& ScCellValue::operator= ( const ScCellValue& r )
ScCellValue& ScCellValue::operator=(ScCellValue&& rCell) noexcept
{
clear();
meType = rCell.meType;
mfValue1 = rCell.mfValue1;
switch (rCell.meType)
{
case CELLTYPE_STRING:
mpString = rCell.mpString;
break;
case CELLTYPE_EDIT:
mpEditText1 = rCell.mpEditText1;
break;
case CELLTYPE_FORMULA:
mpFormula1 = rCell.mpFormula1;
break;
default:
;
}
//we don't need to reset mpString/mpEditText1/mpFormula1 if we
//set meType to NONE as the ScCellValue dtor keys off the meType
rCell.meType = CELLTYPE_NONE;
maData = std::move(rCell.maData);
rCell.maData = true; // reset to empty;
return *this;
}
@@ -551,11 +545,7 @@ ScCellValue& ScCellValue::operator= ( const ScRefCellValue& r )
void ScCellValue::swap( ScCellValue& r )
{
std::swap(meType, r.meType);
// double is 8 bytes, whereas a pointer may be 4 or 8 bytes depending on
// the platform. Swap by double values.
std::swap(mfValue1, r.mfValue1);
std::swap(maData, r.maData);
}
ScRefCellValue::ScRefCellValue() : meType(CELLTYPE_NONE), mfValue1(0.0) {}
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 2c610d4..ce982e9 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -291,7 +291,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
// same document. If not, re-intern shared strings.
svl::SharedStringPool* pSharedStringPool = (bSameDocPool ? nullptr : &rDocument.GetSharedStringPool());
svl::SharedString aStr = (pSharedStringPool ?
pSharedStringPool->intern( rSrcCell.getSharedString()-> getString()) :
pSharedStringPool->intern( rSrcCell.getSharedString()->getString()) :
*rSrcCell.getSharedString());
std::vector<svl::SharedString> aStrs(nDestSize, aStr);
diff --git a/sc/source/core/tool/chgtrack.cxx b/sc/source/core/tool/chgtrack.cxx
index 29cc75e..0fa7951 100644
--- a/sc/source/core/tool/chgtrack.cxx
+++ b/sc/source/core/tool/chgtrack.cxx
@@ -1365,7 +1365,7 @@ void ScChangeActionContent::SetValueString(
if ( rStr.getLength() > 1 && rStr[0] == '=' )
{
rValue.clear();
rCell = ScCellValue(new ScFormulaCell(
rCell.set(new ScFormulaCell(
*pDoc, aBigRange.aStart.MakeAddress(*pDoc), rStr,
pDoc->GetGrammar() ));
rCell.getFormula()->SetInChangeTrack(true);