// Copyright (C) 2021-2022 Jakub Melka // // This file is part of PDF4QT. // // PDF4QT is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // with the written consent of the copyright owner, any later version. // // PDF4QT is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with PDF4QT. If not, see . #include "pdfalgorithmlcs.h" #include "pdfdbgheap.h" namespace pdf { void PDFAlgorithmLongestCommonSubsequenceBase::markSequence(Sequence& sequence, const std::vector& movedItemsLeft, const std::vector& movedItemsRight) { Sequence updatedSequence; Q_ASSERT(std::is_sorted(movedItemsLeft.cbegin(), movedItemsLeft.cend())); Q_ASSERT(std::is_sorted(movedItemsRight.cbegin(), movedItemsRight.cend())); for (auto it = sequence.cbegin(); it != sequence.cend();) { if (it->isMatch()) { updatedSequence.push_back(*it); ++it; continue; } Sequence leftItems; Sequence rightItems; for (; it != sequence.cend() && !it->isMatch(); ++it) { const SequenceItem& currentItem = *it; Q_ASSERT(currentItem.isLeft() || currentItem.isRight()); if (currentItem.isLeft()) { if (std::binary_search(movedItemsLeft.cbegin(), movedItemsLeft.cend(), currentItem.index1)) { SequenceItem item = *it; item.markMovedLeft(); updatedSequence.push_back(item); } else { leftItems.push_back(currentItem); } } if (currentItem.isRight()) { if (std::binary_search(movedItemsRight.cbegin(), movedItemsRight.cend(), currentItem.index2)) { SequenceItem item = *it; item.markMovedRight(); updatedSequence.push_back(item); } else { rightItems.push_back(currentItem); } } } std::reverse(leftItems.begin(), leftItems.end()); std::reverse(rightItems.begin(), rightItems.end()); bool isReplaced = !leftItems.empty() && !rightItems.empty(); while (!leftItems.empty() && !rightItems.empty()) { SequenceItem item; item.index1 = leftItems.back().index1; item.index2 = rightItems.back().index2; item.markReplaced(); updatedSequence.push_back(item); leftItems.pop_back(); rightItems.pop_back(); } while (!leftItems.empty()) { SequenceItem item = leftItems.back(); item.markRemoved(); if (isReplaced) { item.markReplaced(); } updatedSequence.push_back(item); leftItems.pop_back(); } while (!rightItems.empty()) { SequenceItem item = rightItems.back(); item.markAdded(); if (isReplaced) { item.markReplaced(); } updatedSequence.push_back(item); rightItems.pop_back(); } } for (SequenceItem& item : updatedSequence) { if (item.isMatch() && !item.isRemoved() && !item.isReplaced() && !item.isAdded() && item.index1 != item.index2) { item.markMoved(); } } sequence = qMove(updatedSequence); } PDFAlgorithmLongestCommonSubsequenceBase::SequenceItemRanges PDFAlgorithmLongestCommonSubsequenceBase::getModifiedRanges(Sequence& sequence) { SequenceItemRanges result; for (auto it = sequence.begin(); it != sequence.end();) { const SequenceItem& item = *it; if (!item.isModified()) { ++it; continue; } // Jakub Melka: now, we have iterator pointing on item, // which has been modified. We will search for modification // range. auto itEnd = it; while (itEnd != sequence.end() && itEnd->isModified()) { ++itEnd; } result.emplace_back(it, itEnd); it = itEnd; } return result; } PDFAlgorithmLongestCommonSubsequenceBase::SequenceItemFlags PDFAlgorithmLongestCommonSubsequenceBase::collectFlags(const SequenceItemRange& range) { SequenceItemFlags flags = SequenceItemFlags(); for (auto it = range.first; it != range.second; ++it) { flags |= it->flags; } return flags; } } // namespace pdf