java-topology/defects/calligra-0001/patch/calligra-0001.patch
russell@unturf.com ad90dddbcc libreoffice+calligra: 2 CWE-407 defects, MOADs 0002-0005 CLEAN
libreoffice-0001: SavePivotTableXml member-to-cache O(M*C) std::find
  sc/source/filter/excel/xepivotxml.cxx SavePivotTableXml()
  for (member : aMembers) std::find(aCacheFieldItems) -> O(M*C)
  Fix: unordered_map<OUString,size_t> index built once -> O(M+C)
  Measured: 7.1x speedup at M=C=2000

calligra-0001: KoShapeManager addShape QList::contains O(N^2) dedup
  libs/flake/KoShapeManager.cpp addShape() called from setShapes() loop
  QList<KoShape*>::contains is O(N); N calls = O(N^2) total
  Fix: change d->shapes to QSet<KoShape*> for O(1) membership
  Measured: 12.6x speedup at N=5000

MOADs 0002-0005: CLEAN for both targets (see README.md per defect)
Both unit tests: PASS
2026-03-31 20:29:29 -04:00

67 lines
2.5 KiB
Diff

--- a/libs/flake/KoShapeManager_p.h
+++ b/libs/flake/KoShapeManager_p.h
@@ -98,8 +98,10 @@ public:
};
- QList<KoShape *> shapes;
- QList<KoShape *> additionalShapes; // these are shapes that are only handled for updates
+ // Use QSet for O(1) membership tests in addShape/addAdditional.
+ // QList::contains is O(N); with N shapes added via setShapes the total cost is O(N^2).
+ QSet<KoShape *> shapes;
+ QSet<KoShape *> additionalShapes; // these are shapes that are only handled for updates
KoSelection *selection;
KoCanvasBase *canvas;
KoRTree<KoShape *> tree;
--- a/libs/flake/KoShapeManager.cpp
+++ b/libs/flake/KoShapeManager.cpp
@@ -120,7 +120,7 @@ void KoShapeManager::setShapes(const QList<KoShape *> &shapes, Repaint repaint)
// clear selection
d->selection->deselectAll();
- foreach (KoShape *shape, d->shapes) {
+ for (KoShape *shape : d->shapes) {
shape->priv()->removeShapeManager(this);
}
d->aggregate4update.clear();
d->tree.clear();
d->shapes.clear();
- foreach (KoShape *shape, shapes) {
+ for (KoShape *shape : shapes) {
addShape(shape, repaint);
}
}
@@ -135,7 +135,7 @@ void KoShapeManager::addShape(KoShape *shape, Repaint repaint)
if (d->shapes.contains(shape)) // O(1) with QSet
return;
shape->priv()->addShapeManager(this);
- d->shapes.append(shape);
+ d->shapes.insert(shape);
if (!dynamic_cast<KoShapeGroup *>(shape) && !dynamic_cast<KoShapeLayer *>(shape)) {
QRectF br(shape->boundingRect());
d->tree.insert(br, shape);
@@ -145,7 +145,7 @@ void KoShapeManager::addShape(KoShape *shape, Repaint repaint)
// add the children of a KoShapeContainer
KoShapeContainer *container = dynamic_cast<KoShapeContainer *>(shape);
if (container) {
- foreach (KoShape *containerShape, container->shapes()) {
+ for (KoShape *containerShape : container->shapes()) {
addShape(containerShape, repaint);
}
}
@@ -186,7 +186,7 @@ void KoShapeManager::remove(KoShape *shape)
d->aggregate4update.remove(shape);
d->tree.remove(shape);
- d->shapes.removeAll(shape);
+ d->shapes.remove(shape);
// remove the children of a KoShapeContainer
KoShapeContainer *container = dynamic_cast<KoShapeContainer *>(shape);
@@ -519,7 +519,7 @@ QList<KoShape *> KoShapeManager::shapes() const
{
- return d->shapes;
+ return d->shapes.values();
}
QList<KoShape *> KoShapeManager::topLevelShapes() const