tdf#137544 reduce cost of ChildrenManagerImpl::Update

there are 2 O(n^2) algorithms here, reduce them to O(n log n) by
pre-sorting

Change-Id: Ib3912155cda62cac95b5037528e23ef3c686a7e8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136655
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/svx/source/accessibility/ChildrenManagerImpl.cxx b/svx/source/accessibility/ChildrenManagerImpl.cxx
index 56b47c7..d22f81e 100644
--- a/svx/source/accessibility/ChildrenManagerImpl.cxx
+++ b/svx/source/accessibility/ChildrenManagerImpl.cxx
@@ -316,6 +316,21 @@ void ChildrenManagerImpl::CreateListOfVisibleShapes (
    }
}

namespace
{
struct ChildDescriptorLess
{
    bool operator()(const ChildDescriptor& lhs, const ChildDescriptor& rhs) const
    {
        auto pLhsShape = lhs.mxShape.get();
        auto pRhsShape = rhs.mxShape.get();
        if (pLhsShape || pRhsShape)
            return pLhsShape < pRhsShape;
        return lhs.mxAccessibleShape.get() < rhs.mxAccessibleShape.get();
    }
};
}
    
void ChildrenManagerImpl::RemoveNonVisibleChildren (
    const ChildDescriptorListType& rNewChildList,
    ChildDescriptorListType& rOldChildList)
@@ -323,9 +338,16 @@ void ChildrenManagerImpl::RemoveNonVisibleChildren (
    // Iterate over list of formerly visible children and remove those that
    // are not visible anymore, i.e. member of the new list of visible
    // children.

    // the lists have already been sorted in MergeAccessibilityInformation
    auto newIt = rNewChildList.begin();
    auto newEnd = rNewChildList.end();

    for (auto& rChild : rOldChildList)
    {
        if (::std::find(rNewChildList.begin(), rNewChildList.end(), rChild) == rNewChildList.end())
        while (newIt != newEnd && ChildDescriptorLess()(*newIt, rChild))
            newIt++;
        if (newIt == newEnd || !(*newIt == rChild) )
        {
            // The child is disposed when there is a UNO shape from which
            // the accessible shape can be created when the shape becomes
@@ -349,16 +371,19 @@ void ChildrenManagerImpl::RemoveNonVisibleChildren (
void ChildrenManagerImpl::MergeAccessibilityInformation (
    ChildDescriptorListType& raNewChildList)
{
    ChildDescriptorListType::const_iterator aStartVisibleChildren = maVisibleChildren.begin();
    // sort the lists by mxShape, and then walk them in parallel, which avoids an O(n^2) loop
    std::sort(maVisibleChildren.begin(), maVisibleChildren.end(), ChildDescriptorLess());
    std::sort(raNewChildList.begin(), raNewChildList.end(), ChildDescriptorLess());
    ChildDescriptorListType::const_iterator aOldChildDescriptor = maVisibleChildren.begin();
    ChildDescriptorListType::const_iterator aEndVisibleChildren = maVisibleChildren.end();

    for (auto& rChild : raNewChildList)
    {
        ChildDescriptorListType::const_iterator aOldChildDescriptor =
            std::find(aStartVisibleChildren, aEndVisibleChildren, rChild);
        while (aOldChildDescriptor != aEndVisibleChildren && ChildDescriptorLess()(*aOldChildDescriptor, rChild))
            aOldChildDescriptor++;

        // Copy accessible shape if that exists in the old descriptor.
        if (aOldChildDescriptor != aEndVisibleChildren &&
        if (aOldChildDescriptor != aEndVisibleChildren && *aOldChildDescriptor == rChild &&
            aOldChildDescriptor->mxAccessibleShape.is())
        {
            rChild.mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;