include/svl/custritm.hxx | 4 - include/svl/itempool.hxx | 6 ++ include/svx/xbtmpit.hxx | 2 include/svx/xcolit.hxx | 2 include/svx/xflgrit.hxx | 2 include/svx/xflhtit.hxx | 2 include/svx/xlndsit.hxx | 2 include/svx/xlnedit.hxx | 2 include/svx/xlnstit.hxx | 2 svl/source/inc/poolio.hxx | 92 +++++++++++++++++++++++++++----- svl/source/items/itempool.cxx | 15 +++++ svx/source/unodraw/UnoNameItemTable.cxx | 40 +++++-------- 12 files changed, 120 insertions(+), 51 deletions(-)
New commits: commit f1ed27eed68228edbab5eb63951a602263e4c3a7 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Sat May 4 14:38:07 2019 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Tue May 7 10:54:20 2019 +0200 tdf#63640 FILEOPEN/FILESAVE: particular .odt loads/saves very slow, part2 Use the existing sorting functionality in SfxItemPool and extend it to search for NameOrIndex item in SvxUnoNameItemTable This is a little tricky in that we are defining only a partial ordering over the CntUnencodedStringItem (and their subclasses) items. Partial because I can only use the part of the item that is not randomly mutated by various code, which is why the other fields in the subclasses are mostly out of bounds. I had to exclude FillBitmapItem because it triggers a unit test failure and I cannot figure out why that specific item does not play nice with this optimisation. After this optimisation, the load time goes from 3.6s to 2s on my machine. Change-Id: I52d58c68db2536b69a7b0a9611a2b4c703bc4928 Reviewed-on: https://gerrit.libreoffice.org/71461 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/include/svl/custritm.hxx b/include/svl/custritm.hxx index 3899df7b2fbc..5677c990569e 100644 --- a/include/svl/custritm.hxx +++ b/include/svl/custritm.hxx @@ -23,6 +23,7 @@ #include <svl/svldllapi.h> #include <tools/debug.hxx> #include <svl/poolitem.hxx> +#include <cassert> class SVL_DLLPUBLIC CntUnencodedStringItem: public SfxPoolItem { @@ -60,8 +61,7 @@ public: inline void CntUnencodedStringItem::SetValue(const OUString & rTheValue) { - DBG_ASSERT(GetRefCount() == 0, - "CntUnencodedStringItem::SetValue(): Pooled item"); + assert(GetRefCount() == 0 && "cannot modify name of pooled item"); m_aValue = rTheValue; } diff --git a/include/svl/itempool.hxx b/include/svl/itempool.hxx index 7f74cb85c11d..3a2ff084d723 100644 --- a/include/svl/itempool.hxx +++ b/include/svl/itempool.hxx @@ -171,6 +171,12 @@ public: sal_uInt32 GetItemCount2(sal_uInt16 nWhich) const; Item2Range GetItemSurrogates(sal_uInt16 nWhich) const; + /* + This is only valid for SfxPoolItem that override IsSortable and operator<. + Returns a range of items defined by using operator<. + @param rNeedle must be the same type or a supertype of the pool items for nWhich. + */ + std::vector<const SfxPoolItem*> FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const & rNeedle) const; sal_uInt16 GetFirstWhich() const; sal_uInt16 GetLastWhich() const; diff --git a/include/svx/xbtmpit.hxx b/include/svx/xbtmpit.hxx index dedff05369ec..8987aaf107a4 100644 --- a/include/svx/xbtmpit.hxx +++ b/include/svx/xbtmpit.hxx @@ -42,7 +42,7 @@ public: XFillBitmapItem( const XFillBitmapItem& rItem ); virtual bool operator==( const SfxPoolItem& rItem ) const override; - // NameOrIndex is sortable, but we are not + // no idea why, but this item does not play nice with the sorting optimisation, get failures in sd_import_tests virtual bool IsSortable() const override { return false; } virtual SfxPoolItem* Clone( SfxItemPool* pPool = nullptr ) const override; diff --git a/include/svx/xcolit.hxx b/include/svx/xcolit.hxx index 63d5e475ec31..df3723542516 100644 --- a/include/svx/xcolit.hxx +++ b/include/svx/xcolit.hxx @@ -47,8 +47,6 @@ public: XColorItem(const XColorItem& rItem); virtual bool operator==(const SfxPoolItem& rItem) const override; - // NameOrIndex is sortable, but we are not - virtual bool IsSortable() const override { return false; } virtual SfxPoolItem* Clone(SfxItemPool* pPool = nullptr) const override; const Color& GetColorValue() const; diff --git a/include/svx/xflgrit.hxx b/include/svx/xflgrit.hxx index 8e931cb40ef0..159c6862dc79 100644 --- a/include/svx/xflgrit.hxx +++ b/include/svx/xflgrit.hxx @@ -42,8 +42,6 @@ public: XFillGradientItem(const XFillGradientItem& rItem); virtual bool operator==(const SfxPoolItem& rItem) const override; - // NameOrIndex is sortable, but we are not - virtual bool IsSortable() const override { return false; } virtual SfxPoolItem* Clone(SfxItemPool* pPool = nullptr) const override; virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override; diff --git a/include/svx/xflhtit.hxx b/include/svx/xflhtit.hxx index 1f85088ad7cb..a81e7232abfa 100644 --- a/include/svx/xflhtit.hxx +++ b/include/svx/xflhtit.hxx @@ -41,8 +41,6 @@ public: XFillHatchItem(const XFillHatchItem& rItem); virtual bool operator==(const SfxPoolItem& rItem) const override; - // NameOrIndex is sortable, but we are not - virtual bool IsSortable() const override { return false; } virtual SfxPoolItem* Clone(SfxItemPool* pPool = nullptr) const override; virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override; diff --git a/include/svx/xlndsit.hxx b/include/svx/xlndsit.hxx index 8afc71545301..a19e50608d15 100644 --- a/include/svx/xlndsit.hxx +++ b/include/svx/xlndsit.hxx @@ -42,8 +42,6 @@ public: XLineDashItem(const XLineDashItem& rItem); virtual bool operator==(const SfxPoolItem& rItem) const override; - // NameOrIndex is sortable, but we are not - virtual bool IsSortable() const override { return false; } virtual SfxPoolItem* Clone(SfxItemPool* pPool = nullptr) const override; virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override; diff --git a/include/svx/xlnedit.hxx b/include/svx/xlnedit.hxx index 2896138a7e87..b24d4825946f 100644 --- a/include/svx/xlnedit.hxx +++ b/include/svx/xlnedit.hxx @@ -41,8 +41,6 @@ public: XLineEndItem(const XLineEndItem& rItem); virtual bool operator==(const SfxPoolItem& rItem) const override; - // NameOrIndex is sortable, but we are not - virtual bool IsSortable() const override { return false; } virtual SfxPoolItem* Clone(SfxItemPool* pPool = nullptr) const override; virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override; diff --git a/include/svx/xlnstit.hxx b/include/svx/xlnstit.hxx index c37cfc3bdd6d..3e9c402e8bb9 100644 --- a/include/svx/xlnstit.hxx +++ b/include/svx/xlnstit.hxx @@ -41,8 +41,6 @@ public: XLineStartItem(const XLineStartItem& rItem); virtual bool operator==(const SfxPoolItem& rItem) const override; - // NameOrIndex is sortable, but we are not - virtual bool IsSortable() const override { return false; } virtual SfxPoolItem* Clone(SfxItemPool* pPool = nullptr) const override; virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override; diff --git a/svl/source/inc/poolio.hxx b/svl/source/inc/poolio.hxx index cc2039b97a66..2939d50aaf2f 100644 --- a/svl/source/inc/poolio.hxx +++ b/svl/source/inc/poolio.hxx @@ -33,13 +33,10 @@ class SfxItemPoolUser; static const sal_uInt32 SFX_ITEMS_DEFAULT = 0xfffffffe; -struct CompareSortablePoolItems +static bool CompareSortablePoolItems(SfxPoolItem const* lhs, SfxPoolItem const* rhs) { - bool operator()(SfxPoolItem const* lhs, SfxPoolItem const* rhs) const - { - return (*lhs) < (*rhs); - } -}; + return (*lhs) < (*rhs); +} /** * This array contains a set of SfxPoolItems, if those items are * poolable then each item has a unique set of properties, and we @@ -50,7 +47,11 @@ struct SfxPoolItemArray_Impl { private: o3tl::sorted_vector<SfxPoolItem*> maPoolItemSet; - o3tl::sorted_vector<const SfxPoolItem*, CompareSortablePoolItems> maSortablePoolItems; + // In some cases, e.g. subclasses of NameOrIndex, the parent class (NameOrIndex) is sortable, + // but the subclasses do not define an operator<, which means that we don't get an ordering + // strong enough to enforce uniqueness purely with operator<, which means we need to do + // a partial scan with operator== + std::vector<SfxPoolItem*> maSortablePoolItems; public: o3tl::sorted_vector<SfxPoolItem*>::const_iterator begin() const { return maPoolItemSet.begin(); } o3tl::sorted_vector<SfxPoolItem*>::const_iterator end() const { return maPoolItemSet.end(); } @@ -59,22 +60,87 @@ public: void clear(); size_t size() const {return maPoolItemSet.size();} bool empty() const {return maPoolItemSet.empty();} + o3tl::sorted_vector<SfxPoolItem*>::const_iterator find(SfxPoolItem* pItem) const { return maPoolItemSet.find(pItem); } void insert(SfxPoolItem* pItem) { maPoolItemSet.insert(pItem); if (pItem->IsSortable()) - maSortablePoolItems.insert(pItem); + { + // bail early if someone modified one of these things underneath me + assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end()); + + auto it = std::lower_bound(maSortablePoolItems.begin(), maSortablePoolItems.end(), pItem, CompareSortablePoolItems); + maSortablePoolItems.insert(maSortablePoolItems.begin() + (it - maSortablePoolItems.begin()), pItem); + } } - o3tl::sorted_vector<SfxPoolItem*>::const_iterator find(SfxPoolItem* pItem) const { return maPoolItemSet.find(pItem); } - const SfxPoolItem* findByLessThan(const SfxPoolItem* pItem) const + const SfxPoolItem* findByLessThan(const SfxPoolItem* pNeedle) const + { + // bail early if someone modified one of these things underneath me + assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end()); + assert( maPoolItemSet.empty() || maPoolItemSet.front()->IsSortable() ); + + auto it = std::lower_bound(maSortablePoolItems.begin(), maSortablePoolItems.end(), pNeedle, CompareSortablePoolItems); + for (;;) + { + if (it == maSortablePoolItems.end()) + return nullptr; + if (**it < *pNeedle) + return nullptr; + if (*pNeedle == **it) + return *it; + ++it; + } + } + std::vector<const SfxPoolItem*> findSurrogateRange(const SfxPoolItem* pNeedle) const { - auto it = maSortablePoolItems.find(pItem); - return it == maSortablePoolItems.end() ? nullptr : *it; + std::vector<const SfxPoolItem*> rv; + if (!maSortablePoolItems.empty()) + { + // bail early if someone modified one of these things underneath me + assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end()); + + auto range = std::equal_range(maSortablePoolItems.begin(), maSortablePoolItems.end(), pNeedle, CompareSortablePoolItems); + rv.reserve(std::distance(range.first, range.second)); + for (auto it = range.first; it != range.second; ++it) + rv.push_back(*it); + } + else + { + for (const SfxPoolItem* p : maPoolItemSet) + if (*pNeedle == *p) + rv.push_back(p); + } + return rv; } void erase(o3tl::sorted_vector<SfxPoolItem*>::const_iterator it) { + auto pNeedle = *it; if ((*it)->IsSortable()) - maSortablePoolItems.erase(*it); + { + // bail early if someone modified one of these things underneath me + assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end()); + + auto sortIt = std::lower_bound(maSortablePoolItems.begin(), maSortablePoolItems.end(), pNeedle, CompareSortablePoolItems); + for (;;) + { + if (sortIt == maSortablePoolItems.end()) + { + assert(false && "did not find item?"); + break; + } + if (**sortIt < *pNeedle) + { + assert(false && "did not find item?"); + break; + } + if (**sortIt == *pNeedle) + { + maSortablePoolItems.erase(sortIt); + break; + } + ++sortIt; + } + } return maPoolItemSet.erase(it); } }; diff --git a/svl/source/items/itempool.cxx b/svl/source/items/itempool.cxx index 7c6f746ba319..70809ac65ad4 100644 --- a/svl/source/items/itempool.cxx +++ b/svl/source/items/itempool.cxx @@ -843,6 +843,21 @@ SfxItemPool::Item2Range SfxItemPool::GetItemSurrogates(sal_uInt16 nWhich) const return { rItemArr.begin(), rItemArr.end() }; } +/* This is only valid for SfxPoolItem that override IsSortable and operator< */ +std::vector<const SfxPoolItem*> SfxItemPool::FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const & rSample) const +{ + if ( !IsInRange(nWhich) ) + { + if ( pImpl->mpSecondary ) + return pImpl->mpSecondary->FindItemSurrogate( nWhich, rSample ); + assert(false && "unknown WhichId - cannot resolve surrogate"); + return std::vector<const SfxPoolItem*>(); + } + + SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)]; + return rItemArr.findSurrogateRange(&rSample); +} + sal_uInt32 SfxItemPool::GetItemCount2(sal_uInt16 nWhich) const { if ( !IsInRange(nWhich) ) diff --git a/svx/source/unodraw/UnoNameItemTable.cxx b/svx/source/unodraw/UnoNameItemTable.cxx index 5a27573e62f2..56fe86d489ca 100644 --- a/svx/source/unodraw/UnoNameItemTable.cxx +++ b/svx/source/unodraw/UnoNameItemTable.cxx @@ -159,16 +159,15 @@ void SAL_CALL SvxUnoNameItemTable::replaceByName( const OUString& aApiName, cons bool bFound = false; if (mpModelPool) - for (const SfxPoolItem* pItem : mpModelPool->GetItemSurrogates(mnWhich)) - { - NameOrIndex *pNameOrIndex = const_cast<NameOrIndex*>(static_cast<const NameOrIndex*>(pItem)); - if (pNameOrIndex && aName == pNameOrIndex->GetName()) + { + NameOrIndex aSample(mnWhich, aName); + for (const SfxPoolItem* pNameOrIndex : mpModelPool->FindItemSurrogate(mnWhich, aSample)) + if (isValid(static_cast<const NameOrIndex*>(pNameOrIndex))) { - pNameOrIndex->PutValue( aElement, mnMemberId ); + const_cast<SfxPoolItem*>(pNameOrIndex)->PutValue( aElement, mnMemberId ); bFound = true; - break; } - } + } if( !bFound ) throw container::NoSuchElementException(); @@ -187,20 +186,16 @@ uno::Any SAL_CALL SvxUnoNameItemTable::getByName( const OUString& aApiName ) OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName); - uno::Any aAny; - if (mpModelPool && !aName.isEmpty()) { - for (const SfxPoolItem* pItem : mpModelPool->GetItemSurrogates(mnWhich)) - { - const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem); - - if (isValid(pNameOrIndex) && aName == pNameOrIndex->GetName()) + NameOrIndex aSample(mnWhich, aName); + for (const SfxPoolItem* pFindItem : mpModelPool->FindItemSurrogate(mnWhich, aSample)) + if (isValid(static_cast<const NameOrIndex*>(pFindItem))) { - pNameOrIndex->QueryValue( aAny, mnMemberId ); + uno::Any aAny; + pFindItem->QueryValue( aAny, mnMemberId ); return aAny; } - } } throw container::NoSuchElementException(); @@ -237,14 +232,13 @@ sal_Bool SAL_CALL SvxUnoNameItemTable::hasByName( const OUString& aApiName ) if (aName.isEmpty()) return false; - if (mpModelPool) - for (const SfxPoolItem* pItem : mpModelPool->GetItemSurrogates(mnWhich)) - { - const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem); - if (isValid(pNameOrIndex) && aName == pNameOrIndex->GetName()) - return true; - } + if (!mpModelPool) + return false; + NameOrIndex aSample(mnWhich, aName); + for (const SfxPoolItem* pFindItem : mpModelPool->FindItemSurrogate(mnWhich, aSample)) + if (isValid(static_cast<const NameOrIndex*>(pFindItem))) + return true; return false; } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits