[Libreoffice-commits] core.git: sw/inc sw/source

Noel Grandin (via logerrit) logerrit at kemper.freedesktop.org
Wed Jun 30 15:54:03 UTC 2021


 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.grandin at collabora.co.uk>
AuthorDate: Wed Jun 23 08:51:05 2021 +0200
Commit:     Noel Grandin <noel.grandin at 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.grandin at 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);


More information about the Libreoffice-commits mailing list