sc/inc/cellvalue.hxx | 47 +----- sc/source/core/data/cellvalue.cxx | 256 ++++++++++++++++++-------------------- sc/source/core/data/column4.cxx | 2 sc/source/core/tool/chgtrack.cxx | 2 4 files changed, 138 insertions(+), 169 deletions(-)
New commits: commit 1a7913c1b57b333223b30194c67c4d8d11e583d2 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Wed Jun 15 09:27:31 2022 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Sat Jun 18 11:36:39 2022 +0200 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.gran...@collabora.co.uk> diff --git a/sc/inc/cellvalue.hxx b/sc/inc/cellvalue.hxx index 1095d32a3d39..caf42d2c0155 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 fa246b34d04b..e3786771d5e4 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 2c610d48d5fc..ce982e920f8c 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 29cc75e5d5a6..0fa7951d474b 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);