include/svx/sdasitm.hxx              |    5 +
 svx/source/items/customshapeitem.cxx |   98 +++++++++++++++++++++--------------
 2 files changed, 64 insertions(+), 39 deletions(-)

New commits:
commit 9ba45189c76373d0464cc06902270914888162a3
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Jan 6 14:15:44 2022 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Sun Jan 9 15:43:39 2022 +0100

    make SdrCustomShapeGeometryItem sortable and fast (bsc#1183308)
    
    The document contains a complex graphic consisting of many shapes,
    and SfxItemPool tries to avoid duplicates by checking for equality.
    And SdrCustomShapeGeometryItem contains a UNO sequence as data,
    and comparing those is non-trivial. Make the item sortable, which
    should make things faster, and use anyLess() for the ordering.
    Additionally first check the size of the list of property names
    the class keeps for an easy fast return.
    
    Change-Id: I49220e589b6510c6f1f40d584301be83367fb5a4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128047
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/include/svx/sdasitm.hxx b/include/svx/sdasitm.hxx
index 620e805b5813..ebd022980e6e 100644
--- a/include/svx/sdasitm.hxx
+++ b/include/svx/sdasitm.hxx
@@ -62,6 +62,9 @@ private:
             SdrCustomShapeGeometryItem & operator =(SdrCustomShapeGeometryItem 
&&) = delete; // due to SfxPoolItem
 
             virtual bool                operator==( const SfxPoolItem& ) const 
override;
+            virtual bool                operator<( const SfxPoolItem& ) const 
override;
+            virtual bool                IsSortable() const override { return 
true; }
+
             virtual bool GetPresentation(SfxItemPresentation ePresentation,
                                          MapUnit eCoreMetric, MapUnit 
ePresentationMetric,
                                          OUString &rText, const IntlWrapper&) 
const override;
diff --git a/svx/source/items/customshapeitem.cxx 
b/svx/source/items/customshapeitem.cxx
index 733b30f29e47..0bba5ca6eb33 100644
--- a/svx/source/items/customshapeitem.cxx
+++ b/svx/source/items/customshapeitem.cxx
@@ -20,6 +20,7 @@
 #include <sal/config.h>
 
 #include <o3tl/any.hxx>
+#include <comphelper/anycompare.hxx>
 #include <svx/sdasitm.hxx>
 
 #include <com/sun/star/beans/PropertyValue.hpp>
@@ -216,12 +217,35 @@ void SdrCustomShapeGeometryItem::ClearPropertyValue( 
const OUString& rPropName )
 SdrCustomShapeGeometryItem::~SdrCustomShapeGeometryItem()
 {
 }
+
 bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem& rCmp ) const
 {
-    bool bRet = SfxPoolItem::operator==( rCmp );
-    if ( bRet )
-        bRet = static_cast<const SdrCustomShapeGeometryItem&>(rCmp).aPropSeq 
== aPropSeq;
-    return bRet;
+    if( !SfxPoolItem::operator==( rCmp ))
+        return false;
+    const SdrCustomShapeGeometryItem& other = static_cast<const 
SdrCustomShapeGeometryItem&>(rCmp);
+    // This is called often by SfxItemPool, and comparing uno sequences is 
relatively slow.
+    // Optimize by checking the list of properties that this class keeps for 
the sequence,
+    // if the sizes are different, the sequences are different too, which 
should allow a cheap
+    // return for many cases.
+    if( aPropHashMap.size() != other.aPropHashMap.size())
+        return false;
+    if( aPropPairHashMap.size() != other.aPropPairHashMap.size())
+        return false;
+    return aPropSeq == other.aPropSeq;
+}
+
+bool SdrCustomShapeGeometryItem::operator<( const SfxPoolItem& rCmp ) const
+{
+    assert(dynamic_cast<const SdrCustomShapeGeometryItem*>( &rCmp ));
+    const SdrCustomShapeGeometryItem& other = static_cast<const 
SdrCustomShapeGeometryItem&>(rCmp);
+    // Again, optimize by checking the list of properties and compare by their 
count if different
+    // (this is operator< for sorting purposes, so the ordering can be 
somewhat arbitrary).
+    if( aPropHashMap.size() != other.aPropHashMap.size())
+        return aPropHashMap.size() < other.aPropHashMap.size();
+    if( aPropPairHashMap.size() != other.aPropPairHashMap.size())
+        return aPropPairHashMap.size() < other.aPropPairHashMap.size();
+    return comphelper::anyLess( css::uno::makeAny( aPropSeq ),
+        css::uno::makeAny( other.aPropSeq ));
 }
 
 bool SdrCustomShapeGeometryItem::GetPresentation(
commit 74a37dce322d56251edfa49e7b98a2195f8c8e45
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Fri Jan 7 11:29:33 2022 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Sun Jan 9 15:43:22 2022 +0100

    make SdrCustomShapeGeometryItem internal data consistent
    
    The PutValue() function didn't update the property map properly
    the same way the constructor and other functions do.
    
    Change-Id: I107f7095077d888cd9701d87a6e536339b0257b1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128104
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/include/svx/sdasitm.hxx b/include/svx/sdasitm.hxx
index c02076bfb923..620e805b5813 100644
--- a/include/svx/sdasitm.hxx
+++ b/include/svx/sdasitm.hxx
@@ -48,6 +48,8 @@ private:
 
     css::uno::Sequence< css::beans::PropertyValue > aPropSeq;
 
+    void SetPropSeq( const css::uno::Sequence< css::beans::PropertyValue >& 
rPropSeq );
+
     public:
 
             SdrCustomShapeGeometryItem();
diff --git a/svx/source/items/customshapeitem.cxx 
b/svx/source/items/customshapeitem.cxx
index d4e164ff5c88..733b30f29e47 100644
--- a/svx/source/items/customshapeitem.cxx
+++ b/svx/source/items/customshapeitem.cxx
@@ -35,30 +35,7 @@ SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem()
 SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem( const uno::Sequence< 
beans::PropertyValue >& rVal )
 :   SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
 {
-    sal_Int32 i, j;
-    aPropSeq = rVal;
-
-    for ( i = 0; i < aPropSeq.getLength(); i++ )
-    {
-        const beans::PropertyValue& rPropVal = aPropSeq[ i ];
-        std::pair<PropertyHashMap::iterator, bool> const ret(
-                aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
-        assert(ret.second); // serious bug: duplicate xml attribute exported
-        if (!ret.second)
-        {
-            throw uno::RuntimeException(
-                "CustomShapeGeometry has duplicate property " + rPropVal.Name);
-        }
-        if (auto rPropSeq = 
o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
-                rPropVal.Value))
-        {
-            for ( j = 0; j < rPropSeq->getLength(); j++ )
-            {
-                beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
-                aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name 
) ] = j;
-            }
-        }
-    }
+    SetPropSeq( rVal );
 }
 
 css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const 
OUString& rPropName )
@@ -275,24 +252,43 @@ bool SdrCustomShapeGeometryItem::QueryValue( uno::Any& 
rVal, sal_uInt8 /*nMember
 
 bool SdrCustomShapeGeometryItem::PutValue( const uno::Any& rVal, sal_uInt8 
/*nMemberId*/ )
 {
-    if ( ! ( rVal >>= aPropSeq ) )
+    css::uno::Sequence< css::beans::PropertyValue > propSeq;
+    if ( ! ( rVal >>= propSeq ) )
         return false;
 
-    for (sal_Int32 i = 0; i < aPropSeq.getLength(); ++i)
+    SetPropSeq( propSeq );
+    return true;
+}
+
+void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence< 
css::beans::PropertyValue >& rVal )
+{
+    if( aPropSeq == rVal )
+        return;
+
+    aPropSeq = rVal;
+    aPropHashMap.clear();
+    aPropPairHashMap.clear();
+    for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
     {
-        const auto& rName = aPropSeq[i].Name;
-        bool isDuplicated = std::any_of(std::next(std::cbegin(aPropSeq), i + 
1), std::cend(aPropSeq),
-            [&rName](const css::beans::PropertyValue& rProp) { return 
rProp.Name == rName; });
-        if (isDuplicated)
+        const beans::PropertyValue& rPropVal = aPropSeq[ i ];
+        std::pair<PropertyHashMap::iterator, bool> const ret(
+                aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
+        assert(ret.second); // serious bug: duplicate xml attribute exported
+        if (!ret.second)
         {
-            assert(false); // serious bug: duplicate xml attribute exported
-            OUString const name(aPropSeq[i].Name);
-            aPropSeq.realloc(0);
             throw uno::RuntimeException(
-                "CustomShapeGeometry has duplicate property " + name);
+                "CustomShapeGeometry has duplicate property " + rPropVal.Name);
+        }
+        if (auto rPropSeq = 
o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
+                rPropVal.Value))
+        {
+            for ( sal_Int32 j = 0; j < rPropSeq->getLength(); j++ )
+            {
+                beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
+                aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name 
) ] = j;
+            }
         }
     }
-    return true;
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to