void CCSVWriter::WriteSkipRanges (std::ostream& os, const CCachedLogInfo& cache) { // header os << "PathID,Path,StartRevision,Length\n"; // content const CSkipRevisionInfo& info = cache.GetSkippedRevisions(); // ids will be added on-the-fly for (size_t i = 0; i < info.GetPathCount(); ++i) { CDictionaryBasedPath path = info.GetPath(i); CSkipRevisionInfo::TRanges ranges = info.GetRanges(i); for (size_t k = 0, count = ranges.size(); k < count; ++k) { os << path.GetIndex() << ",\"" << path.GetPath().c_str() << "\"," << ranges[k].first << ',' << ranges[k].second << "\n"; } } }
bool CLogIteratorBase::PathInRevision() const { assert (!InternalDataIsMissing()); // special case: repository root // (report all revisions including empty ones) if (path.IsRoot()) return true; // if we don't have a path, we won't find any changes if (!path.IsValid()) return false; // revision data lookup revision_t index = revisionIndices[revision]; // any chance that this revision affects our path? CDictionaryBasedPath revisionRootPath = revisionInfo.GetRootPath (index); if (!revisionRootPath.IsValid()) return false; if (!path.GetBasePath().Intersects (revisionRootPath)) return false; // close examination of all changes return PathInRevision ( revisionInfo.GetChangesBegin(index) , revisionInfo.GetChangesEnd(index) , path); }
CDictionaryBasedTempPath CDictionaryBasedTempPath::ReplaceParent ( const CDictionaryBasedPath& oldParent , const CDictionaryBasedPath& newParent) const { assert (oldParent.IsSameOrParentOf (*this)); // I admit, this is the most stupid implementation possible ;) std::string newPath = newParent.GetPath() + GetPath().substr (oldParent.GetPath().length()); return CDictionaryBasedTempPath (GetDictionary(), newPath); }
CString CLogChangedPath::GetUIPath (const CDictionaryBasedPath& p) const { std::string utf8Path = p.GetPath(); // we don't need to adjust the path length as // the conversion will automatically stop at \0. return CUnicodeUtils::UTF8ToUTF16 (utf8Path); }
revision_t CSkipRevisionInfo::GetPreviousRevision ( const CDictionaryBasedPath& path , revision_t revision) const { // above the root or invalid parameter ? if (!path.IsValid() || (revision == NO_REVISION)) return (revision_t)NO_REVISION; // lookup the entry for this path index_t dataIndex = index.find (path.GetIndex()); SPerPathRanges* ranges = dataIndex == NO_INDEX ? NULL : data[dataIndex]; // crawl this and the parent path data // until we found a gap (i.e. could not improve further) revision_t startRevision = revision; revision_t result = revision; do { result = revision; revision_t parentNext = GetPreviousRevision (path.GetParent(), revision); if (parentNext != NO_REVISION) revision = parentNext; if (ranges != NULL) { revision_t next = ranges->FindPrevious (revision); if (next != NO_REVISION) revision = next; } } while (revision < result); // ready return revision == startRevision ? NO_REVISION : result; }
void CSkipRevisionInfo::Add ( const CDictionaryBasedPath& path , revision_t revision , revision_t size) { // violating these assertions will break our lookup algorithms assert (path.IsValid()); assert (revision != NO_REVISION); assert (size != NO_REVISION); assert (2*size > size); // reduce the range, if we have revision info at the boundaries TryReduceRange (revision, size); if (size == 0) return; // lookup / auto-insert entry for path SPerPathRanges* ranges = NULL; index_t dataIndex = index.find (path.GetIndex()); if (dataIndex == NO_INDEX) { ranges = new SPerPathRanges; ranges->pathID = path.GetIndex(); data.push_back (ranges); index.insert (path.GetIndex(), (index_t)data.size()-1); } else { ranges = data[dataIndex]; } // add range ranges->Add (revision, size); }
bool CLogIteratorBase::PathInRevision ( const CRevisionInfoContainer::CChangesIterator& first , const CRevisionInfoContainer::CChangesIterator& last , const CDictionaryBasedTempPath& path) { // close examination of all changes for ( CRevisionInfoContainer::CChangesIterator iter = first ; iter != last ; ++iter) { // if (and only if) path is a cached path, // it may be a parent of the changedPath // (i.e. report a change of this or some sub-path) CDictionaryBasedPath changedPath = iter->GetPath(); if ( path.IsFullyCachedPath() && path.GetBasePath().IsSameOrParentOf (changedPath)) return true; // this change affects a true parent path or completely unrelated path // -> ignore mere modifications (e.g. properties on a folder) if (iter->GetAction() == CRevisionInfoContainer::ACTION_CHANGED) continue; // this is an add / delete / replace. // does it affect our path? if (changedPath.IsSameOrParentOf (path.GetBasePath())) return true; } // no paths that we were looking for return false; }
CRemovePathsBySubString::PathClassification CRemovePathsBySubString::QuickClassification (const CDictionaryBasedPath& path) const { // ensure the index is valid within classification cache if (pathClassification.size() <= path.GetIndex()) { size_t newSize = max (8, pathClassification.size()) * 2; while (newSize <= path.GetIndex()) newSize *= 2; pathClassification.resize (newSize, UNKNOWN); } // auto-calculate the entry PathClassification& classification = pathClassification[path.GetIndex()]; if (classification == UNKNOWN) classification = Classify (path.GetPath()); // done here return classification; }
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; }