LRC-LIB-SMARTCOLL: album_reaches uses a hash set; loop test describes the guard

From review: the walk through smart-album references kept its seen-set
in a Vec, which is quadratic over long chains. The loop test's comment
now says what a saved loop does: inside it, the album being evaluated
counts as holding no photos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nathaniel Ledford
2026-10-09 10:54:57 -04:00
co-authored by Claude Opus 5.5
parent f40c7fb204
commit 2ad901e6dc
2 changed files with 4 additions and 4 deletions
+2 -3
View File
@@ -335,13 +335,12 @@ impl Catalog {
/// rules of `from` would then change when those of `to` do). Loops in saved rules end the
/// search, they don't repeat it.
pub fn album_reaches(&self, from: AlbumId, to: AlbumId) -> bool {
let mut seen: Vec<AlbumId> = Vec::new();
let mut seen: std::collections::HashSet<AlbumId> = std::collections::HashSet::new();
let mut next = vec![from];
while let Some(a) = next.pop() {
if seen.contains(&a) {
if !seen.insert(a) {
continue;
}
seen.push(a);
let tested = self
.albums
.get(&a)
+2 -1
View File
@@ -522,7 +522,8 @@ fn a_smart_album_can_exclude_another() {
/// An album can't include itself, directly or through other smart albums: the check refuses the
/// loop for the album being edited, and a loop saved anyway (an older version, a hand-edited file)
/// neither recurses forever nor crashes; it is reported and its rule matches nothing.
/// neither recurses forever nor crashes: inside it, the album being evaluated counts as holding no
/// photos, and every album in it is reported.
#[test]
fn smart_album_loops_are_refused_and_survived() {
let mut c = Catalog::new();