sw/inc/charformats.hxx | 114 ++++++++++++++++++++++++++++++++++++ sw/inc/doc.hxx | 1 sw/inc/docary.hxx | 6 - sw/source/core/doc/docfmt.cxx | 8 +- sw/source/core/doc/docnew.cxx | 9 +- sw/source/core/doc/number.cxx | 2 sw/source/core/txtnode/chrfmt.cxx | 77 ++++++++++++++++++++++++ sw/source/core/undo/rolbck.cxx | 2 sw/source/core/unocore/unosett.cxx | 13 ---- sw/source/core/unocore/unostyle.cxx | 2 10 files changed, 206 insertions(+), 28 deletions(-)
New commits: commit cf15c4dad74e31a035c0d1ca899dfbef4da90ad2 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Wed Jun 23 08:51:05 2021 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Wed Jun 30 17:53:36 2021 +0200 tdf#135316 optimise SwCharFormats::FindFormatByName reduces load time by 10% Change-Id: Ic5c90588825592245d09f8ebe03b13e34676496a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117699 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/sw/inc/charformats.hxx b/sw/inc/charformats.hxx new file mode 100644 index 000000000000..f72958298ea8 --- /dev/null +++ b/sw/inc/charformats.hxx @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "docary.hxx" +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/composite_key.hpp> +#include <boost/multi_index/identity.hpp> +#include <boost/multi_index/mem_fun.hpp> +#include <boost/multi_index/ordered_index.hpp> +#include <boost/multi_index/random_access_index.hpp> + +// Like o3tl::find_partialorder_ptrequals +// We don't allow duplicated object entries! +struct char_formats_name_key + : boost::multi_index::composite_key< + SwCharFormat*, + boost::multi_index::const_mem_fun<SwFormat, const OUString&, &SwFormat::GetName>, + boost::multi_index::identity<SwCharFormat*> // the actual object pointer + > +{ +}; + +typedef boost::multi_index_container< + SwCharFormat*, + boost::multi_index::indexed_by<boost::multi_index::random_access<>, + boost::multi_index::ordered_unique<char_formats_name_key>>> + SwCharFormatsBase; + +class SW_DLLPUBLIC SwCharFormats final : public SwFormatsBase +{ + // function updating ByName index via modify + friend void SwFormat::SetName(const OUString&, bool); + +public: + typedef SwCharFormatsBase::nth_index<0>::type ByPos; + typedef SwCharFormatsBase::nth_index<1>::type ByName; + typedef ByPos::iterator iterator; + +private: + SwCharFormatsBase m_Array; + ByPos& m_PosIndex; + ByName& m_NameIndex; + +public: + typedef ByPos::const_iterator const_iterator; + typedef SwCharFormatsBase::size_type size_type; + typedef SwCharFormatsBase::value_type value_type; + + SwCharFormats(); + // frees all SwCharFormat! + virtual ~SwCharFormats() override; + + bool empty() const { return m_Array.empty(); } + size_t size() const { return m_Array.size(); } + + // Only fails, if you try to insert the same object twice + void insert(SwCharFormat* x); + + // This will try to remove the exact object! + void erase(const_iterator const& position); + + // Get the iterator of the exact object (includes pointer!), + // e.g for position with std::distance. + // There is also ContainsFormat, if you don't need the position. + const_iterator find(const SwCharFormat* x) const; + size_t GetPos(const SwCharFormat* p) const; + + // search for formats by name + ByName::const_iterator findByName(const OUString& name) const; + // So we can actually check for end() + ByName::const_iterator byNameEnd() const { return m_NameIndex.end(); } + + SwCharFormat* operator[](size_t index_) const { return m_PosIndex.operator[](index_); } + const_iterator begin() const { return m_PosIndex.begin(); } + const_iterator end() const { return m_PosIndex.end(); } + + void dumpAsXml(xmlTextWriterPtr pWriter) const; + + virtual size_t GetFormatCount() const override { return m_Array.size(); } + virtual SwCharFormat* GetFormat(size_t idx) const override { return operator[](idx); } + + /// fast check if given format is contained here + /// @precond pFormat must not have been deleted + bool ContainsFormat(SwCharFormat* pFormat) const; + /// not so fast check that given format is still alive (i.e. contained here) + bool IsAlive(SwCharFormat const*) const; + + void DeleteAndDestroyAll(bool keepDefault = false); + + // Override return type to reduce casting + virtual SwCharFormat* FindFormatByName(const OUString& rName) const override; + + /** Need to call this when the format name changes */ + void SetFormatNameAndReindex(SwCharFormat* v, const OUString& sNewName); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index f72c2b89cb0d..d5c3a210af42 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -37,6 +37,7 @@ #include "frmfmt.hxx" #include "charfmt.hxx" #include "docary.hxx" +#include "charformats.hxx" #include "pagedesc.hxx" #include "tblenum.hxx" #include "ndarr.hxx" diff --git a/sw/inc/docary.hxx b/sw/inc/docary.hxx index 49d1a7c368a7..43939b1d84d1 100644 --- a/sw/inc/docary.hxx +++ b/sw/inc/docary.hxx @@ -187,12 +187,6 @@ public: SwFrameFormatsV() : SwFormatsModifyBase( DestructorPolicy::KeepElements ) {} }; -class SwCharFormats final : public SwFormatsModifyBase<SwCharFormat*> -{ -public: - void dumpAsXml(xmlTextWriterPtr pWriter) const; -}; - class SwTextFormatColls final : public SwFormatsModifyBase<SwTextFormatColl*> { public: diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx index f6ccbb799b92..7f07cf62e99c 100644 --- a/sw/source/core/doc/docfmt.cxx +++ b/sw/source/core/doc/docfmt.cxx @@ -845,7 +845,7 @@ SwCharFormat *SwDoc::MakeCharFormat( const OUString &rFormatName, bool bBroadcast ) { SwCharFormat *pFormat = new SwCharFormat( GetAttrPool(), rFormatName, pDerivedFrom ); - mpCharFormatTable->push_back( pFormat ); + mpCharFormatTable->insert( pFormat ); pFormat->SetAuto(false); getIDocumentState().SetModified(); @@ -1926,7 +1926,11 @@ void SwDoc::RenameFormat(SwFormat & rFormat, const OUString & sNewName, } } - rFormat.SetName(sNewName); + // name change means the o3tl::sorted_array is not property sorted + if (rFormat.Which() == RES_CHRFMT) + mpCharFormatTable->SetFormatNameAndReindex(static_cast<SwCharFormat*>(&rFormat), sNewName); + else + rFormat.SetName(sNewName); if (bBroadcast) BroadcastStyleOperation(sNewName, eFamily, SfxHintId::StyleSheetModified); diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx index ae2f24a92a8a..b1ed62e0bccc 100644 --- a/sw/source/core/doc/docnew.cxx +++ b/sw/source/core/doc/docnew.cxx @@ -113,6 +113,8 @@ using namespace ::com::sun::star; using namespace ::com::sun::star::document; +constexpr OUStringLiteral DEFAULT_CHAR_FORMAT_NAME = u"Character style"; + /* * global functions... */ @@ -223,7 +225,7 @@ SwDoc::SwDoc() mpDfltFrameFormat( new SwFrameFormat( GetAttrPool(), "Frameformat", nullptr ) ), mpEmptyPageFormat( new SwFrameFormat( GetAttrPool(), "Empty Page", mpDfltFrameFormat.get() ) ), mpColumnContFormat( new SwFrameFormat( GetAttrPool(), "Columncontainer", mpDfltFrameFormat.get() ) ), - mpDfltCharFormat( new SwCharFormat( GetAttrPool(), "Character style", nullptr ) ), + mpDfltCharFormat( new SwCharFormat( GetAttrPool(), DEFAULT_CHAR_FORMAT_NAME, nullptr ) ), mpDfltTextFormatColl( new SwTextFormatColl( GetAttrPool(), "Paragraph style" ) ), mpDfltGrfFormatColl( new SwGrfFormatColl( GetAttrPool(), "Graphikformatvorlage" ) ), mpFrameFormatTable( new SwFrameFormats() ), @@ -296,7 +298,7 @@ SwDoc::SwDoc() */ /* Formats */ mpFrameFormatTable->push_back(mpDfltFrameFormat.get()); - mpCharFormatTable->push_back(mpDfltCharFormat.get()); + mpCharFormatTable->insert(mpDfltCharFormat.get()); /* FormatColls */ // TXT @@ -531,7 +533,6 @@ SwDoc::~SwDoc() * now. */ mpFrameFormatTable->erase( mpFrameFormatTable->begin() ); - mpCharFormatTable->erase( mpCharFormatTable->begin() ); #if HAVE_FEATURE_DBCONNECTIVITY // On load, SwDBManager::setEmbeddedName() may register a data source. @@ -728,7 +729,7 @@ void SwDoc::ClearDoc() mpTextFormatCollTable->DeleteAndDestroy(2, mpTextFormatCollTable->size()); mpTextFormatCollTable->DeleteAndDestroy(1, mpTextFormatCollTable->size()); mpGrfFormatCollTable->DeleteAndDestroy(1, mpGrfFormatCollTable->size()); - mpCharFormatTable->DeleteAndDestroy(1, mpCharFormatTable->size()); + mpCharFormatTable->DeleteAndDestroyAll(/*keepDefault*/true); if( getIDocumentLayoutAccess().GetCurrentViewShell() ) { diff --git a/sw/source/core/doc/number.cxx b/sw/source/core/doc/number.cxx index 9bd2f27283b9..045d58f63fde 100644 --- a/sw/source/core/doc/number.cxx +++ b/sw/source/core/doc/number.cxx @@ -872,7 +872,7 @@ SwNumRule& SwNumRule::CopyNumRule( SwDoc& rDoc, const SwNumRule& rNumRule ) { Set( n, rNumRule.maFormats[ n ].get() ); if( maFormats[ n ] && maFormats[ n ]->GetCharFormat() && - !rDoc.GetCharFormats()->IsAlive(maFormats[n]->GetCharFormat())) + !rDoc.GetCharFormats()->ContainsFormat(maFormats[n]->GetCharFormat())) { // If we copy across different Documents, then copy the // corresponding CharFormat into the new Document. diff --git a/sw/source/core/txtnode/chrfmt.cxx b/sw/source/core/txtnode/chrfmt.cxx index 04301067ec23..3ee46ee3e8e8 100644 --- a/sw/source/core/txtnode/chrfmt.cxx +++ b/sw/source/core/txtnode/chrfmt.cxx @@ -20,7 +20,7 @@ #include <libxml/xmlwriter.h> #include <charfmt.hxx> -#include <docary.hxx> +#include <charformats.hxx> void SwCharFormat::dumpAsXml(xmlTextWriterPtr pWriter) const { @@ -39,4 +39,79 @@ void SwCharFormats::dumpAsXml(xmlTextWriterPtr pWriter) const (void)xmlTextWriterEndElement(pWriter); } +SwCharFormats::SwCharFormats() + : m_PosIndex(m_Array.get<0>()) + , m_NameIndex(m_Array.get<1>()) +{ +} + +SwCharFormats::~SwCharFormats() +{ + // default char format is owned by SwDoc + DeleteAndDestroyAll(true); +} + +SwCharFormats::const_iterator SwCharFormats::find(const SwCharFormat* x) const +{ + ByName::iterator it + = m_NameIndex.find(boost::make_tuple(x->GetName(), const_cast<SwCharFormat*>(x))); + return m_Array.project<0>(it); +} + +SwCharFormats::ByName::const_iterator SwCharFormats::findByName(const OUString& name) const +{ + return m_NameIndex.find(boost::make_tuple(name)); +} + +SwCharFormat* SwCharFormats::FindFormatByName(const OUString& rName) const +{ + auto it = findByName(rName); + if (it != m_NameIndex.end()) + return *it; + return nullptr; +} + +void SwCharFormats::DeleteAndDestroyAll(bool keepDefault) +{ + if (empty()) + return; + const int _offset = keepDefault ? 1 : 0; + for (const_iterator it = begin() + _offset; it != end(); ++it) + { + assert(!(*it)->HasName(u"Character style")); + delete *it; + } + if (_offset) + m_PosIndex.erase(begin() + _offset, end()); + else + m_Array.clear(); +} + +void SwCharFormats::insert(SwCharFormat* x) +{ + assert(!ContainsFormat(x)); + m_PosIndex.push_back(x); +} + +void SwCharFormats::erase(const_iterator const& position) { m_PosIndex.erase(position); } + +bool SwCharFormats::ContainsFormat(SwCharFormat* x) const { return find(x) != end(); } + +bool SwCharFormats::IsAlive(SwCharFormat const* const p) const { return find(p) != end(); } + +/** Need to call this when the format name changes */ +void SwCharFormats::SetFormatNameAndReindex(SwCharFormat* v, const OUString& sNewName) +{ + auto it = find(v); + erase(it); + v->SetName(sNewName); + insert(v); +} + +size_t SwCharFormats::GetPos(const SwCharFormat* p) const +{ + auto it = find(p); + return it == end() ? SIZE_MAX : it - begin(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx index 402f1486654b..cf308182c60b 100644 --- a/sw/source/core/undo/rolbck.cxx +++ b/sw/source/core/undo/rolbck.cxx @@ -254,7 +254,7 @@ void SwHistorySetText::SetInDoc( SwDoc* pDoc, bool ) if ( RES_TXTATR_CHARFMT == m_pAttr->Which() ) { // ask the Doc if the CharFormat still exists - if (!pDoc->GetCharFormats()->IsAlive(static_cast<SwFormatCharFormat&>(*m_pAttr).GetCharFormat())) + if (!pDoc->GetCharFormats()->ContainsFormat(static_cast<SwFormatCharFormat&>(*m_pAttr).GetCharFormat())) return; // do not set, format does not exist } diff --git a/sw/source/core/unocore/unosett.cxx b/sw/source/core/unocore/unosett.cxx index 186b0e98116e..101a70f10ada 100644 --- a/sw/source/core/unocore/unosett.cxx +++ b/sw/source/core/unocore/unosett.cxx @@ -1589,21 +1589,10 @@ void SwXNumberingRules::SetPropertiesToNumFormat( } else if (pLocalDoc) { - const SwCharFormats* pFormats = pLocalDoc->GetCharFormats(); - const size_t nChCount = pFormats->size(); - SwCharFormat* pCharFormat = nullptr; if (!sCharFormatName.isEmpty()) { - for(size_t j = 0; j< nChCount; ++j) - { - SwCharFormat* pTmp = (*pFormats)[j]; - if(pTmp->GetName() == sCharFormatName) - { - pCharFormat = pTmp; - break; - } - } + pCharFormat = pLocalDoc->FindCharFormatByName(sCharFormatName); if(!pCharFormat) { diff --git a/sw/source/core/unocore/unostyle.cxx b/sw/source/core/unocore/unostyle.cxx index a6a14abef2dc..86d9381b8573 100644 --- a/sw/source/core/unocore/unostyle.cxx +++ b/sw/source/core/unocore/unostyle.cxx @@ -891,7 +891,7 @@ uno::Any XStyleFamily::getByName(const OUString& rName) throw uno::RuntimeException(); SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.m_eFamily); if(!pBase) - throw container::NoSuchElementException(); + throw container::NoSuchElementException(rName); uno::Reference<style::XStyle> xStyle = FindStyle(sStyleName); if(!xStyle.is()) xStyle = m_rEntry.m_fCreateStyle(m_pBasePool, m_pDocShell, m_rEntry.m_eFamily == SfxStyleFamily::Frame ? pBase->GetName() : sStyleName); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits