darktable-0001: map_locations image diff g_list_find O(N*M) MEDIUM 375x darktable-0002: tags _tag_add_tags_to_list g_list_find O(T*L) MEDIUM 375x darktable-0003: map view clustering g_list_find(sel_imgs) O(I²×S) HIGH 160x scribus-0001: getSortedStyleList retList.contains O(N²) MEDIUM 167x (×4 copies) scribus-0002: getUsedPatterns results.contains O(I×R) MEDIUM 98x scribus-0003: Selection::addItems m_SelList.contains O(N×M) MEDIUM 2100x
44 lines
1.6 KiB
Diff
44 lines
1.6 KiB
Diff
# UNDF: UNDF-2026-000000804
|
||
# UNDF: (leave blank)
|
||
# scribus-0003: Selection::addItems m_SelList.contains O(N×M)
|
||
#
|
||
# In scribus/selection.cpp, addItems() iterates over the items to add (N) and
|
||
# for each calls m_SelList.contains(item), which is O(M) on the existing
|
||
# QList<QPointer<PageItem>> selection list. Total: O(N×M). For a "Select All"
|
||
# on a 5000-item document adding to an existing selection of 2000, this is
|
||
# ~10M pointer comparisons.
|
||
#
|
||
# The single-item addItem() also calls m_SelList.contains(item) — O(M) per
|
||
# call — but is less severe since it adds one item at a time.
|
||
#
|
||
# Fix: build a QSet<PageItem*> from m_SelList before the loop for O(1) lookup,
|
||
# or maintain a companion QSet as a class member.
|
||
#
|
||
# Severity: MEDIUM — triggered on every multi-select operation (rubber-band,
|
||
# Select All, group selection); scales with document item count.
|
||
--- a/scribus/selection.cpp
|
||
+++ b/scribus/selection.cpp
|
||
@@ -194,6 +194,12 @@
|
||
bool Selection::addItems(const QList<PageItem *>& items)
|
||
{
|
||
if (items.isEmpty())
|
||
return false;
|
||
|
||
+ // Build hash set for O(1) membership check instead of O(M) QList::contains
|
||
+ QSet<PageItem*> existing;
|
||
+ existing.reserve(m_SelList.count());
|
||
+ for (int i = 0; i < m_SelList.count(); ++i)
|
||
+ existing.insert(m_SelList.at(i).data());
|
||
+
|
||
QList< QPointer<PageItem> > toAdd;
|
||
toAdd.reserve(items.count());
|
||
for (int i = 0; i < items.count(); ++i)
|
||
{
|
||
PageItem* item = items.at(i);
|
||
- if (m_SelList.contains(item))
|
||
+ if (existing.contains(item))
|
||
continue;
|
||
toAdd.append(item);
|
||
+ existing.insert(item);
|
||
item->setSelected(true);
|
||
}
|