# UNDF: UNDF-2026-000000797 # UNDF: (leave blank) # darktable-0003: map view clustering g_list_find(sel_imgs) inside O(I*J) loop # # In src/views/map.c, the map clustering code iterates over all images (i-loop) # and for each cluster, iterates again over all images (j-loop). Inside the # j-loop, g_list_find(sel_imgs, GINT_TO_POINTER(p[j].imgid)) performs a linear # scan of the selected-images list (length S). Total complexity: O(I*J*S) # which for 5000 map images with 500 selected is O(5000*5000*500) = 12.5 # billion pointer comparisons. # # The outer i-loop also calls g_list_find(sel_imgs, ...) for NOISE points # and cluster heads — each O(S), contributing O(I*S) additional. # # Fix: build a GHashTable from sel_imgs before the loop, replace g_list_find # with g_hash_table_contains for O(1) lookup. # # Severity: HIGH — map view is redrawn on every pan/zoom with the full image # collection; O(I²×S) collapses to O(I²+S). --- a/src/views/map.c +++ b/src/views/map.c @@ -1506,6 +1506,12 @@ gboolean *processed = calloc(num_clusters+1,sizeof(gboolean)); GList *sel_imgs = dt_act_on_get_images(FALSE, FALSE, FALSE); + + // Build hash set for O(1) selection membership test + GHashTable *sel_set = g_hash_table_new(g_direct_hash, g_direct_equal); + for(GList *si = sel_imgs; si; si = g_list_next(si)) + g_hash_table_add(sel_set, si->data); + int group = -1; for(i = 0; i< img_count; i++) { @@ -1523,8 +1529,7 @@ if(sel_imgs) - entry->selected_in_group = g_list_find((GList *)sel_imgs, - GINT_TO_POINTER(entry->imgid)) - ? TRUE : FALSE; + entry->selected_in_group = + g_hash_table_contains(sel_set, GINT_TO_POINTER(entry->imgid)); lib->images = g_slist_prepend(lib->images, entry); @@ -1540,8 +1545,7 @@ - entry->selected_in_group = (sel_imgs && g_list_find((GList *)sel_imgs, - GINT_TO_POINTER(p[i].imgid))) - ? TRUE : FALSE; + entry->selected_in_group = sel_imgs + && g_hash_table_contains(sel_set, GINT_TO_POINTER(p[i].imgid)); @@ -1557,7 +1561,7 @@ if(sel_imgs && !entry->selected_in_group) { - if(g_list_find((GList *)sel_imgs, GINT_TO_POINTER(p[j].imgid))) + if(g_hash_table_contains(sel_set, GINT_TO_POINTER(p[j].imgid))) entry->selected_in_group = TRUE; } } free(processed); + g_hash_table_destroy(sel_set); g_list_free(sel_imgs);