summaryrefslogtreecommitdiff
path: root/sw/inc
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2019-05-28 11:06:23 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2019-05-28 16:41:26 +0200
commit7ac940d278f9bb3fbb1988a74dfa4909960bd998 (patch)
tree68228a3de97842d00d67217b1e7736a6db94f355 /sw/inc
parent7376a47680b65cbdfd747a736f288e06f51f7f2d (diff)
tdf#125372 writer, file with lots of hints very slow to open, part3
There were O(n^2) issues all over the places where we walk these lists. This takes the opening time from 10m+ to 4m. (*) Invalidate the sorting on a much less aggressive basis, by having the SwTextAttr objects tell the SwpHints object when start and end pos changes (*) Add a bool field to indicate when the maps become unsorted, so we can resort them only when we actually need sorted access (*) Add an API for walking the list of SwTextAttr* without triggering sorting, which is particularly important when the RedlineManager starts moving things around. (*) Add various asserts to catch code that tries to iterate over these sorted lists but triggers resorting during the loop. I also moved some of the logic around so that instead of update hint delete hint insert hint it now goes delete hint update hint insert hint which means that the needToSort flag does not get set because the hint is disconnected while it is being updated. Change-Id: Ie153ddafc9ef9e3470d588db2be2457c676232a8 Reviewed-on: https://gerrit.libreoffice.org/73090 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'sw/inc')
-rw-r--r--sw/inc/ndhints.hxx65
-rw-r--r--sw/inc/txatbase.hxx18
-rw-r--r--sw/inc/txtrfmrk.hxx3
-rw-r--r--sw/inc/txttxmrk.hxx3
4 files changed, 51 insertions, 38 deletions
diff --git a/sw/inc/ndhints.hxx b/sw/inc/ndhints.hxx
index c3112844db8e..299218a55399 100644
--- a/sw/inc/ndhints.hxx
+++ b/sw/inc/ndhints.hxx
@@ -54,23 +54,8 @@ SwTextAttr* MakeRedlineTextAttr(
SwDoc & rDoc,
SfxPoolItem const & rAttr );
-
-/// SwTextAttr's, sorted by start
-struct CompareSwpHtStart
-{
- bool operator()(SwTextAttr const * const lhs, SwTextAttr const * const rhs) const;
-};
-class SwpHtStart : public o3tl::sorted_vector<SwTextAttr*, CompareSwpHtStart,
- o3tl::find_partialorder_ptrequals> {};
-
-/// SwTextAttr's, sorted by end
-struct CompareSwpHtEnd
-{
- bool operator()(SwTextAttr const * const lhs, SwTextAttr const * const rhs) const;
-};
-class SwpHtEnd : public o3tl::sorted_vector<SwTextAttr*, CompareSwpHtEnd,
- o3tl::find_partialorder_ptrequals> {};
-
+bool CompareSwpHtEnd( const SwTextAttr* lhs, const SwTextAttr* rhs );
+bool CompareSwpHtWhichStart( const SwTextAttr* lhs, const SwTextAttr* rhs );
/// An SwTextAttr container, stores all directly formatted text portions for a text node.
class SwpHints
@@ -82,8 +67,8 @@ private:
// failure, so just allow SAL_MAX_SIZE-1 hints
static const size_t MAX_HINTS = SAL_MAX_SIZE-1;
- SwpHtStart m_HintsByStart;
- SwpHtEnd m_HintsByEnd;
+ std::vector<SwTextAttr*> m_HintsByStart;
+ std::vector<SwTextAttr*> m_HintsByEnd;
SwRegHistory* m_pHistory; ///< for Undo
@@ -96,6 +81,9 @@ private:
mutable bool m_bHiddenByParaField : 1;
bool m_bFootnote : 1; ///< footnotes
bool m_bDDEFields : 1; ///< the TextNode has DDE fields
+ // Sort on demand to avoid O(n^2) behaviour
+ mutable bool m_bStartMapNeedsSorting : 1;
+ mutable bool m_bEndMapNeedsSorting : 1;
/// records a new attribute in m_pHistory.
void NoteInHistory( SwTextAttr *pAttr, const bool bNew = false );
@@ -129,18 +117,11 @@ private:
bool MergePortions( SwTextNode& rNode );
void Insert( const SwTextAttr *pHt );
- void Resort();
+ SW_DLLPUBLIC void Resort() const;
+ SW_DLLPUBLIC void ResortStartMap() const;
+ SW_DLLPUBLIC void ResortEndMap() const;
- size_t GetIndexOf( const SwTextAttr *pHt ) const
- {
- SwpHtStart::const_iterator const it =
- m_HintsByStart.find(const_cast<SwTextAttr*>(pHt));
- if ( it == m_HintsByStart.end() )
- {
- return SAL_MAX_SIZE;
- }
- return it - m_HintsByStart.begin();
- }
+ size_t GetIndexOf( const SwTextAttr *pHt ) const;
#ifdef DBG_UTIL
bool Check(bool) const;
@@ -153,12 +134,32 @@ public:
bool Contains( const SwTextAttr *pHt ) const;
SwTextAttr * Get( size_t nPos ) const
{
+ assert( !(nPos != 0 && m_bStartMapNeedsSorting) && "going to trigger a resort in the middle of an iteration, that's bad" );
+ if (m_bStartMapNeedsSorting)
+ ResortStartMap();
+ return m_HintsByStart[nPos];
+ }
+ // Get without triggering resorting - useful if we are modifying start/end pos while iterating
+ SwTextAttr * GetWithoutResorting( size_t nPos ) const
+ {
return m_HintsByStart[nPos];
}
+ int GetLastPosSortedByEnd(sal_Int32 nEndPos) const;
SwTextAttr * GetSortedByEnd( size_t nPos ) const
{
+ assert( !(nPos != 0 && m_bEndMapNeedsSorting) && "going to trigger a resort in the middle of an iteration, that's bad" );
+ if (m_bEndMapNeedsSorting)
+ ResortEndMap();
return m_HintsByEnd[nPos];
}
+ /// Trigger the sorting if necessary
+ void SortIfNeedBe() const
+ {
+ if (m_bStartMapNeedsSorting)
+ ResortStartMap();
+ if (m_bEndMapNeedsSorting)
+ ResortEndMap();
+ }
SwTextAttr * Cut( const size_t nPosInStart )
{
SwTextAttr *pHt = m_HintsByStart[nPosInStart];
@@ -184,6 +185,10 @@ public:
// calc current value of m_bHiddenByParaField, returns true iff changed
bool CalcHiddenParaField() const; // changes mutable state
+
+ // Marks the hint-maps as needing sorting because the position of something has changed
+ void StartPosChanged() const { m_bStartMapNeedsSorting = true; m_bEndMapNeedsSorting = true; }
+ void EndPosChanged() const { m_bStartMapNeedsSorting = true; m_bEndMapNeedsSorting = true; }
};
#endif
diff --git a/sw/inc/txatbase.hxx b/sw/inc/txatbase.hxx
index 4be53ba7a408..0e2aebdb846f 100644
--- a/sw/inc/txatbase.hxx
+++ b/sw/inc/txatbase.hxx
@@ -30,11 +30,13 @@
#include "fmtftn.hxx"
#include "fchrfmt.hxx"
#include "tox.hxx"
+#include "ndhints.hxx"
class SfxItemPool;
class SAL_DLLPUBLIC_RTTI SwTextAttr
{
+friend class SwpHints;
private:
SfxPoolItem * const m_pAttr;
sal_Int32 m_nStart;
@@ -56,6 +58,8 @@ private:
SwTextAttr& operator=(SwTextAttr const&) = delete;
protected:
+ SwpHints * m_pHints = nullptr; // the SwpHints holds a pointer to this, and needs to be notified if the start/end changes
+
SwTextAttr( SfxPoolItem& rAttr, sal_Int32 nStart );
virtual ~SwTextAttr() COVERITY_NOEXCEPT_FALSE;
@@ -74,11 +78,12 @@ public:
static void Destroy( SwTextAttr * pToDestroy, SfxItemPool& rPool );
/// start position
- sal_Int32& GetStart() { return m_nStart; }
- const sal_Int32& GetStart() const { return m_nStart; }
+ void SetStart(sal_Int32 n) { m_nStart = n; if (m_pHints) m_pHints->StartPosChanged(); }
+ sal_Int32 GetStart() const { return m_nStart; }
/// end position
- virtual sal_Int32* GetEnd(); // also used to change the end position
+ virtual const sal_Int32* GetEnd() const;
+ virtual void SetEnd(sal_Int32);
inline const sal_Int32* End() const;
/// end (if available), else start
inline const sal_Int32* GetAnyEnd() const;
@@ -127,7 +132,8 @@ protected:
public:
SwTextAttrEnd( SfxPoolItem& rAttr, sal_Int32 nStart, sal_Int32 nEnd );
- virtual sal_Int32* GetEnd() override;
+ virtual const sal_Int32* GetEnd() const override;
+ virtual void SetEnd(sal_Int32) override;
};
// attribute that must not overlap others
@@ -141,13 +147,13 @@ protected:
inline const sal_Int32* SwTextAttr::End() const
{
- return const_cast<SwTextAttr * >(this)->GetEnd();
+ return GetEnd();
}
inline const sal_Int32* SwTextAttr::GetAnyEnd() const
{
const sal_Int32* pEnd = End();
- return pEnd ? pEnd : &GetStart();
+ return pEnd ? pEnd : &m_nStart;
}
inline const SfxPoolItem& SwTextAttr::GetAttr() const
diff --git a/sw/inc/txtrfmrk.hxx b/sw/inc/txtrfmrk.hxx
index f756a587ce18..c8261c0e5ce4 100644
--- a/sw/inc/txtrfmrk.hxx
+++ b/sw/inc/txtrfmrk.hxx
@@ -33,7 +33,8 @@ public:
SwTextRefMark( SwFormatRefMark& rAttr,
sal_Int32 const nStart, sal_Int32 const*const pEnd = nullptr);
- virtual sal_Int32* GetEnd() override; // SwTextAttr
+ virtual const sal_Int32* GetEnd() const override; // SwTextAttr
+ virtual void SetEnd(sal_Int32) override; // SwTextAttr
// get and set TextNode pointer
inline const SwTextNode& GetTextNode() const;
diff --git a/sw/inc/txttxmrk.hxx b/sw/inc/txttxmrk.hxx
index a0c26987b707..bcb0a5b06acf 100644
--- a/sw/inc/txttxmrk.hxx
+++ b/sw/inc/txttxmrk.hxx
@@ -35,7 +35,8 @@ public:
sal_Int32 const nStart, sal_Int32 const*const pEnd);
virtual ~SwTextTOXMark() override;
- virtual sal_Int32 *GetEnd() override; // SwTextAttr
+ virtual const sal_Int32 *GetEnd() const override; // SwTextAttr
+ virtual void SetEnd(sal_Int32) override; // SwTextAttr
void CopyTOXMark( SwDoc* pDestDoc );