bool CLogIteratorBase::InternalHandleCopyAndDelete ( const CRevisionInfoContainer::CChangesIterator& first , const CRevisionInfoContainer::CChangesIterator& last , const CDictionaryBasedPath& revisionRootPath) { // any chance that this revision affects our search path? if (!revisionRootPath.IsValid()) return false; if (!revisionRootPath.IsSameOrParentOf (path.GetBasePath())) return false; // close examination of all changes CRevisionInfoContainer::CChangesIterator bestRename = last; for ( CRevisionInfoContainer::CChangesIterator iter = first ; iter != last ; ++iter) { // most entries will just be file content changes // -> skip them efficiently CRevisionInfoContainer::TChangeAction action = iter.GetAction(); if (action == CRevisionInfoContainer::ACTION_CHANGED) continue; // deletion / copy / rename / replacement // -> skip, if our search path is not affected (only some sub-path) CDictionaryBasedPath changedPath = iter->GetPath(); if (!changedPath.IsSameOrParentOf (path.GetBasePath())) continue; // now, this is serious switch (action) { // rename? case CRevisionInfoContainer::ACTION_ADDED: case CRevisionInfoContainer::ACTION_REPLACED: case CRevisionInfoContainer::ACTION_MOVED: case CRevisionInfoContainer::ACTION_MOVEREPLACED: { if (iter.HasFromPath()) { // continue search on copy source path // The last copy found will also be the one closed // to our searchPath (there may be multiple renames, // if the base path got renamed). assert ( ((bestRename == last) || (bestRename.GetPathID() < iter.GetPathID())) && "parent ADDs are not in strict order"); bestRename = iter; } else { // as part of a copy / rename, the parent path // may have been added in just the same revision. // // example: // // our path: /trunk/file // renamed to // /trunk/project/file // // this can only happen if // /trunk/project // is added first (usually without a copy from path) // // Stop iteration only if we found an ADD of // the exact search path. if (path == changedPath) { // the path we are following actually started here. addRevision = revision; addPath = path; revision = (revision_t)NO_REVISION; path.Invalidate(); return true; } } } break; case CRevisionInfoContainer::ACTION_DELETED: { // deletions are possible! // but we don't need to do anything with them. } break; // there should be no other default: { assert (0); } } } // there was a rename / copy from some older path,rev if (bestRename != last) { addRevision = revision; addPath = path; path = path.ReplaceParent ( bestRename.GetPath() , bestRename.GetFromPath()); revision = bestRename.GetFromRevision(); return true; } // all fine, no special action required return false; }
void CFullHistory::BuildForwardCopies() { // iterate through all revisions and fill copyToRelation: // for every copy-from info found, add an entry const CRevisionIndex& revisions = cache->GetRevisions(); const CRevisionInfoContainer& revisionInfo = cache->GetLogInfo(); // for all revisions ... copiesContainer.reserve (revisions.GetLastRevision()); for ( revision_t revision = revisions.GetFirstRevision() , last = revisions.GetLastRevision() ; revision < last ; ++revision) { // ... in the cache ... index_t index = revisions[revision]; if ( (index != NO_INDEX) && (revisionInfo.GetSumChanges (index) & CRevisionInfoContainer::HAS_COPY_FROM)) { // ... examine all changes ... for ( CRevisionInfoContainer::CChangesIterator iter = revisionInfo.GetChangesBegin (index) , end = revisionInfo.GetChangesEnd (index) ; iter != end ; ++iter) { // ... and if it has a copy-from info ... if (iter->HasFromPath()) { // ... add it to the list SCopyInfo* copyInfo = SCopyInfo::Create (copyInfoPool); copyInfo->fromRevision = iter->GetFromRevision(); copyInfo->fromPathIndex = iter->GetFromPathID(); copyInfo->toRevision = revision; copyInfo->toPathIndex = iter->GetPathID(); copiesContainer.push_back (copyInfo); } } } } // sort container by source revision and path copyToRelation = new SCopyInfo*[copiesContainer.size()]; copyToRelationEnd = copyToRelation + copiesContainer.size(); copyFromRelation = new SCopyInfo*[copiesContainer.size()]; copyFromRelationEnd = copyFromRelation + copiesContainer.size(); // in early phases, there will be no copies // -> front() iterator is invalid if (!copiesContainer.empty()) { size_t bytesToCopy = copiesContainer.size() * sizeof (SCopyInfo*[1]); memcpy (copyToRelation, &copiesContainer.front(), bytesToCopy); memcpy (copyFromRelation, &copiesContainer.front(), bytesToCopy); std::sort (copyToRelation, copyToRelationEnd, &AscendingToRevision); std::sort (copyFromRelation, copyFromRelationEnd, &AscendingFromRevision); } }