diff --git a/src/UndoManager.cpp b/src/UndoManager.cpp index bfeb2f3f9..979a0ce7d 100644 --- a/src/UndoManager.cpp +++ b/src/UndoManager.cpp @@ -72,7 +72,7 @@ UndoManager::~UndoManager() namespace { SpaceArray::value_type - CalculateUsage(TrackList *tracks, Set *prev, Set *cur) + CalculateUsage(TrackList *tracks, Set *seen) { SpaceArray::value_type result = 0; @@ -90,18 +90,17 @@ namespace { { const auto &file = block.f; - // Accumulate space used by the file if the file didn't exist - // in the previous level - if (!prev || !cur || - (prev->count( &*file ) == 0 && cur->count( &*file ) == 0)) + // Accumulate space used by the file if the file was not + // yet seen + if ( !seen || (seen->count( &*file ) == 0 ) ) { unsigned long long usage{ file->GetSpaceUsage() }; result += usage; } // Add file to current set - if (cur) - cur->insert( &*file ); + if (seen) + seen->insert( &*file ); } } @@ -117,25 +116,31 @@ void UndoManager::CalculateSpaceUsage() space.clear(); space.resize(stack.size(), 0); - Set s1, s2; - Set *prev = &s1; - Set *cur = &s2; + Set seen; - for (size_t i = 0, cnt = stack.size(); i < cnt; i++) + // After copies and pastes, a block file may be used in more than + // one place in one undo history state, and it may be used in more than + // one undo history state. It might even be used in two states, but not + // in another state that is between them -- as when you have state A, + // then make a cut to get state B, but then paste it back into state C. + + // So be sure to count each block file once only, in the last undo item that + // contains it. + + // Why the last and not the first? Because the user of the History dialog + // may delete undo states, oldest first. To reclaim disk space you must + // delete all states containing the block file. So the block file's + // contribution to space usage should be counted only in that latest state. + + for (size_t nn = stack.size(); nn--;) { - // Swap map pointers - std::swap(cur, prev); - - // And clean out the NEW current map - cur->clear(); - // Scan all tracks at current level - auto tracks = stack[i]->state.tracks.get(); - space[i] = CalculateUsage(tracks, prev, cur); + auto tracks = stack[nn]->state.tracks.get(); + space[nn] = CalculateUsage(tracks, &seen); } mClipboardSpaceUsage = CalculateUsage - (AudacityProject::GetClipboardTracks(), nullptr, nullptr); + (AudacityProject::GetClipboardTracks(), nullptr); //TIMER_STOP( space_calc ); }