reduce dynamic_cast usage in an O(N^2) algorithm
When scrolling down in tdf#130431 this is the major CPU cost. Move the dynamic_cast out of the loops as much as possible. Change-Id: I0ea9f457bb17fbdde880f09b059f07dec4b1790b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94858 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
This commit is contained in:
parent
3a93748c9c
commit
ef4964a4e5
3 changed files with 50 additions and 53 deletions
|
@ -305,18 +305,11 @@ namespace drawinglayer::primitive2d
|
|||
ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
|
||||
|
||||
Primitive2DReference tryMergeBorderLinePrimitive2D(
|
||||
const Primitive2DReference& rCandidateA,
|
||||
const Primitive2DReference& rCandidateB)
|
||||
const BorderLinePrimitive2D* pCandidateA,
|
||||
const BorderLinePrimitive2D* pCandidateB)
|
||||
{
|
||||
// try to cast to BorderLinePrimitive2D
|
||||
const primitive2d::BorderLinePrimitive2D* pCandidateA = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateA.get());
|
||||
const primitive2d::BorderLinePrimitive2D* pCandidateB = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateB.get());
|
||||
|
||||
// we need a comparable BorderLinePrimitive2D
|
||||
if(nullptr == pCandidateA || nullptr == pCandidateB)
|
||||
{
|
||||
return Primitive2DReference();
|
||||
}
|
||||
assert(pCandidateA);
|
||||
assert(pCandidateB);
|
||||
|
||||
// start of candidate has to match end of this
|
||||
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
|
||||
|
|
|
@ -81,12 +81,6 @@ public:
|
|||
bool operator==(const BorderLine& rBorderLine) const;
|
||||
};
|
||||
|
||||
/// helper to try to merge two instances of BorderLinePrimitive2D. If it was possible,
|
||||
/// a merged version is in the returned Primitive2DReference. Lots of preconditions
|
||||
/// have to be met to allow that, see implementation (and maybe even expand)
|
||||
Primitive2DReference DRAWINGLAYER_DLLPUBLIC tryMergeBorderLinePrimitive2D(
|
||||
const Primitive2DReference& rCandidateA, const Primitive2DReference& rCandidateB);
|
||||
|
||||
/** BorderLinePrimitive2D class
|
||||
|
||||
This is the basic primitive to build frames around objects, e.g. tables.
|
||||
|
@ -141,6 +135,12 @@ public:
|
|||
virtual sal_uInt32 getPrimitive2DID() const override;
|
||||
};
|
||||
|
||||
/// helper to try to merge two instances of BorderLinePrimitive2D. If it was possible,
|
||||
/// a merged version is in the returned Primitive2DReference. Lots of preconditions
|
||||
/// have to be met to allow that, see implementation (and maybe even expand)
|
||||
Primitive2DReference DRAWINGLAYER_DLLPUBLIC tryMergeBorderLinePrimitive2D(
|
||||
const BorderLinePrimitive2D* pCandidateA, const BorderLinePrimitive2D* pCandidateB);
|
||||
|
||||
} // end of namespace drawinglayer::primitive2d
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
|
@ -797,51 +797,55 @@ namespace drawinglayer::primitive2d
|
|||
|
||||
for(const auto& aCandidatePartial : aPartial)
|
||||
{
|
||||
if(aRetval.empty())
|
||||
{
|
||||
// no local data yet, just add as 1st entry, done
|
||||
aRetval.append(aCandidatePartial);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bDidMerge(false);
|
||||
bool bDidMerge(false);
|
||||
|
||||
// This algorithm is O(N^2) and repeated dynamic_cast inside would be quite costly.
|
||||
// So check first and skip if the primitives aren't BorderLinePrimitive2D.
|
||||
const drawinglayer::primitive2d::BorderLinePrimitive2D* candidatePartialAsBorder
|
||||
= dynamic_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D*>(aCandidatePartial.get());
|
||||
if(candidatePartialAsBorder)
|
||||
{
|
||||
for(auto& aCandidateRetval : aRetval)
|
||||
{
|
||||
// try to merge by appending new data to existing data
|
||||
const drawinglayer::primitive2d::Primitive2DReference aMergeRetvalPartial(
|
||||
drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
|
||||
aCandidateRetval,
|
||||
aCandidatePartial));
|
||||
|
||||
if(aMergeRetvalPartial.is())
|
||||
const drawinglayer::primitive2d::BorderLinePrimitive2D* candidateRetvalAsBorder
|
||||
= dynamic_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D*>(aCandidateRetval.get());
|
||||
if(candidateRetvalAsBorder)
|
||||
{
|
||||
// could append, replace existing data with merged data, done
|
||||
aCandidateRetval = aMergeRetvalPartial;
|
||||
bDidMerge = true;
|
||||
break;
|
||||
}
|
||||
// try to merge by appending new data to existing data
|
||||
const drawinglayer::primitive2d::Primitive2DReference aMergeRetvalPartial(
|
||||
drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
|
||||
candidateRetvalAsBorder,
|
||||
candidatePartialAsBorder));
|
||||
|
||||
// try to merge by appending existing data to new data
|
||||
const drawinglayer::primitive2d::Primitive2DReference aMergePartialRetval(
|
||||
drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
|
||||
aCandidatePartial,
|
||||
aCandidateRetval));
|
||||
if(aMergeRetvalPartial.is())
|
||||
{
|
||||
// could append, replace existing data with merged data, done
|
||||
aCandidateRetval = aMergeRetvalPartial;
|
||||
bDidMerge = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(aMergePartialRetval.is())
|
||||
{
|
||||
// could append, replace existing data with merged data, done
|
||||
aCandidateRetval = aMergePartialRetval;
|
||||
bDidMerge = true;
|
||||
break;
|
||||
// try to merge by appending existing data to new data
|
||||
const drawinglayer::primitive2d::Primitive2DReference aMergePartialRetval(
|
||||
drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
|
||||
candidatePartialAsBorder,
|
||||
candidateRetvalAsBorder));
|
||||
|
||||
if(aMergePartialRetval.is())
|
||||
{
|
||||
// could append, replace existing data with merged data, done
|
||||
aCandidateRetval = aMergePartialRetval;
|
||||
bDidMerge = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!bDidMerge)
|
||||
{
|
||||
// no merge after checking all existing data, append as new segment
|
||||
aRetval.append(aCandidatePartial);
|
||||
}
|
||||
if(!bDidMerge)
|
||||
{
|
||||
// no merge after checking all existing data, append as new segment
|
||||
aRetval.append(aCandidatePartial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue