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
67 lines
2.3 KiB
Diff
67 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000000803
|
||
# UNDF: (leave blank)
|
||
# scribus-0002: getUsedPatterns results.contains O(I×R) pattern collection
|
||
#
|
||
# In scribus/scribusdoc.cpp, getUsedPatterns() iterates over all page items
|
||
# and for each checks results.contains(pattern) — a QStringList linear scan
|
||
# O(R) where R is the number of results accumulated so far. With I page items
|
||
# each potentially contributing 3 pattern names (fill, stroke, mask), the
|
||
# overall complexity is O(3×I×R). For a document with 2000 items and 200
|
||
# patterns, that is ~1.2M string comparisons.
|
||
#
|
||
# The same pattern repeats in getUsedPatternsSelection() and
|
||
# getUsedPatternsHelper() and getPatternDependencyList().
|
||
#
|
||
# Fix: maintain a companion QSet<QString> for O(1) membership alongside the
|
||
# QStringList for ordered results.
|
||
#
|
||
# Severity: MEDIUM — triggered during document save, export, and pattern
|
||
# cleanup; scales with item count × pattern count.
|
||
--- a/scribus/scribusdoc.cpp
|
||
+++ b/scribus/scribusdoc.cpp
|
||
@@ -3933,6 +3933,7 @@
|
||
QStringList ScribusDoc::getUsedPatterns() const
|
||
{
|
||
QStringList results;
|
||
+ QSet<QString> resultSet;
|
||
|
||
for (PageItemIterator it(this, ...); *it; ++it)
|
||
{
|
||
const PageItem* currItem = *it;
|
||
- if ((!results.contains(currItem->pattern())) && ...)
|
||
+ if ((!resultSet.contains(currItem->pattern())) && ...)
|
||
+ {
|
||
results.append(currItem->pattern());
|
||
+ resultSet.insert(currItem->pattern());
|
||
+ }
|
||
if (!currItem->strokePattern().isEmpty())
|
||
{
|
||
- if (!results.contains(currItem->strokePattern()))
|
||
+ if (!resultSet.contains(currItem->strokePattern()))
|
||
+ {
|
||
results.append(currItem->strokePattern());
|
||
+ resultSet.insert(currItem->strokePattern());
|
||
+ }
|
||
}
|
||
if (!currItem->patternMask().isEmpty())
|
||
{
|
||
- if (!results.contains(currItem->patternMask()))
|
||
+ if (!resultSet.contains(currItem->patternMask()))
|
||
+ {
|
||
results.append(currItem->patternMask());
|
||
+ resultSet.insert(currItem->patternMask());
|
||
+ }
|
||
}
|
||
}
|
||
|
||
// Same fix for the inner docPatterns loop (lines 3955-3983)
|
||
- // Replace results.contains(...) with resultSet.contains(...)
|
||
+ // and add resultSet.insert(...) after each results.append(...)
|
||
|
||
return results;
|
||
}
|
||
|
||
// Same fix applies to:
|
||
// getUsedPatternsSelection() (line 3988)
|
||
// getUsedPatternsHelper() (line 4036)
|
||
// getPatternDependencyList() (line 4087)
|