Beispiel #1
0
        private void BuildOrderedRowCache(IList <RevisionGraphRevision> orderedNodesCache, int currentRowIndex, int lastToCacheRowIndex)
        {
            // Ensure we keep using the same instance of the rowcache from here on
            var localOrderedRowCache = _orderedRowCache;

            if (localOrderedRowCache == null || CheckRowCacheIsDirty(localOrderedRowCache, orderedNodesCache))
            {
                localOrderedRowCache = new List <RevisionGraphRow>(currentRowIndex);
            }

            int nextIndex = localOrderedRowCache.Count;

            if (nextIndex > lastToCacheRowIndex)
            {
                return;
            }

            int cacheCount = orderedNodesCache.Count;

            while (nextIndex <= lastToCacheRowIndex && cacheCount > nextIndex)
            {
                bool startSegmentsAdded = false;

                RevisionGraphRevision revision = orderedNodesCache[nextIndex];

                // The list containing the segments is created later. We can set the correct capacity then, to prevent resizing
                List <RevisionGraphSegment> segments;

                if (nextIndex == 0)
                {
                    // This is the first row. Start with only the startsegments of this row
                    segments = new List <RevisionGraphSegment>(revision.StartSegments);
                }
                else
                {
                    // Copy lanes from last row
                    RevisionGraphRow previousRevisionGraphRow = localOrderedRowCache[nextIndex - 1];

                    // Create segments list with te correct capacity
                    segments = new List <RevisionGraphSegment>(previousRevisionGraphRow.Segments.Count + revision.StartSegments.Count);

                    // Loop through all segments that do not end in the previous row
                    foreach (var segment in previousRevisionGraphRow.Segments.Where(s => s.Parent != previousRevisionGraphRow.Revision))
                    {
                        segments.Add(segment);

                        // This segment that is copied from the previous row, connects to the node in this row.
                        // Copy all new segments that start from this node (revision) to this lane.
                        if (revision == segment.Parent && !startSegmentsAdded)
                        {
                            startSegmentsAdded = true;
                            segments.AddRange(revision.StartSegments);
                        }
                    }

                    // The startsegments do not connect to any previous row. This means that this is a new branch.
                    if (!startSegmentsAdded)
                    {
                        // Add new segments started by this revision to the end
                        segments.AddRange(revision.StartSegments);
                    }
                }

                localOrderedRowCache.Add(new RevisionGraphRow(revision, segments));
                nextIndex++;
            }

            // Overwrite the global instance at the end, to prevent flickering
            _orderedRowCache = localOrderedRowCache;

            Updated?.Invoke();
        }
Beispiel #2
0
 public RevisionGraphSegment(RevisionGraphRevision parent, RevisionGraphRevision child)
 {
     Parent = parent;
     Child  = child;
 }
Beispiel #3
0
 public bool TryGetNode(ObjectId objectId, out RevisionGraphRevision revision)
 {
     return(_nodeByObjectId.TryGetValue(objectId, out revision));
 }
Beispiel #4
0
 private void AddChild(RevisionGraphRevision child)
 {
     ImmutableInterlocked.Push(ref _children, child);
 }
 public RevisionGraphRow(RevisionGraphRevision revision, IReadOnlyList <RevisionGraphSegment> segments)
 {
     Revision = revision;
     Segments = segments;
 }
Beispiel #6
0
 private void AddChild(RevisionGraphRevision child)
 {
     Children.Add(child);
 }
Beispiel #7
0
        // Build the revision graph. There are two caches that are build in this method.
        // cache 1: an ordered list of the revisions. This is very cheap to build. (_orderedNodesCache)
        // cache 2: an ordered list of all prepared graphrows. This is expensive to build. (_orderedRowCache)
        // untillRow: the row that needs to be displayed. This ensures the orded revisions are available untill this index.
        // graphUntillRow: the graph can be build per x rows. This defines the row index that the graph will be cached until.
        public void CacheTo(int untillRow, int graphUntillRow)
        {
            if (_orderedNodesCache == null || _reorder || _orderedNodesCache.Count < untillRow)
            {
                _orderedNodesCache = _nodes.OrderBy(n => n.Score).ToList();
                if (_orderedNodesCache.Count > 0)
                {
                    _cachedUntillScore = _orderedNodesCache.Last().Score;
                }

                if (_reorder || _orderedRowCache == null)
                {
                    _orderedRowCache = new List <RevisionGraphRow>(untillRow);
                }

                _reorder = false;
                Updated?.Invoke();
            }

            int nextIndex = _orderedRowCache.Count;

            if (nextIndex <= graphUntillRow)
            {
                int cacheCount = _orderedNodesCache.Count;
                while (nextIndex <= graphUntillRow && cacheCount > nextIndex)
                {
                    bool startSegmentsAdded = false;

                    RevisionGraphRevision revision = _orderedNodesCache[nextIndex];

                    // The list containing the segments is created later. We can set the correct capacity then, to prevent resizing
                    List <RevisionGraphSegment> segments;

                    if (nextIndex > 0)
                    {
                        // Copy lanes from last row
                        RevisionGraphRow previousRevisionGraphRow = _orderedRowCache[nextIndex - 1];

                        // Create segments list with te correct capacity
                        segments = new List <RevisionGraphSegment>(previousRevisionGraphRow.Segments.Count + revision.StartSegments.Count);

                        // Loop through all segments that do not end in this row
                        foreach (var segment in previousRevisionGraphRow.Segments.Where(s => s.Parent != previousRevisionGraphRow.Revision))
                        {
                            segments.Add(segment);

                            // This segments continues in the next row. Copy all other segments that start from this revision to this lane.
                            if (revision == segment.Parent && !startSegmentsAdded)
                            {
                                startSegmentsAdded = true;
                                segments.AddRange(revision.StartSegments);
                            }
                        }
                    }
                    else
                    {
                        // Create segments list with te correct capacity
                        segments = new List <RevisionGraphSegment>(revision.StartSegments.Count);
                    }

                    if (!startSegmentsAdded)
                    {
                        // Add new segments started by this revision to the end
                        segments.AddRange(revision.StartSegments);
                    }

                    _orderedRowCache.Add(new RevisionGraphRow(_orderedNodesCache[nextIndex], segments));
                    nextIndex++;
                }

                Updated?.Invoke();
            }
        }
        private void BuildOrderedRowCache(RevisionGraphRevision[] orderedNodesCache, int currentRowIndex, int lastToCacheRowIndex)
        {
            // Ensure we keep using the same instance of the rowcache from here on
            IList <RevisionGraphRow>?localOrderedRowCache = _orderedRowCache;

            if (localOrderedRowCache is null || CheckRowCacheIsDirty(localOrderedRowCache, orderedNodesCache))
            {
                localOrderedRowCache = new List <RevisionGraphRow>(currentRowIndex);
            }

            lastToCacheRowIndex = Math.Min(lastToCacheRowIndex, orderedNodesCache.Length - 1);
            int startIndex = localOrderedRowCache.Count;

            if (startIndex > lastToCacheRowIndex)
            {
                return;
            }

            for (int nextIndex = startIndex; nextIndex <= lastToCacheRowIndex; ++nextIndex)
            {
                bool startSegmentsAdded = false;

                RevisionGraphRevision revision = orderedNodesCache[nextIndex];

                // The list containing the segments is created later. We can set the correct capacity then, to prevent resizing
                List <RevisionGraphSegment> segments;

                if (nextIndex == 0)
                {
                    // This is the first row. Start with only the startsegments of this row
                    segments = new List <RevisionGraphSegment>(revision.StartSegments);

                    foreach (var startSegment in revision.StartSegments)
                    {
                        startSegment.LaneInfo = new LaneInfo(startSegment, derivedFrom: null);
                    }
                }
                else
                {
                    // Copy lanes from last row
                    RevisionGraphRow previousRevisionGraphRow = localOrderedRowCache[nextIndex - 1];

                    // Create segments list with te correct capacity
                    segments = new List <RevisionGraphSegment>(previousRevisionGraphRow.Segments.Count + revision.StartSegments.Count);

                    // Loop through all segments that do not end in the previous row
                    foreach (var segment in previousRevisionGraphRow.Segments.Where(s => s.Parent != previousRevisionGraphRow.Revision))
                    {
                        segments.Add(segment);

                        // This segment that is copied from the previous row, connects to the node in this row.
                        // Copy all new segments that start from this node (revision) to this lane.
                        if (revision == segment.Parent)
                        {
                            if (!startSegmentsAdded)
                            {
                                startSegmentsAdded = true;
                                segments.AddRange(revision.StartSegments);
                            }

                            foreach (var startSegment in revision.StartSegments)
                            {
                                if (startSegment == revision.StartSegments.First())
                                {
                                    if (startSegment.LaneInfo is null || startSegment.LaneInfo.StartScore > segment.LaneInfo?.StartScore)
                                    {
                                        startSegment.LaneInfo = segment.LaneInfo;
                                    }
                                }
                                else
                                {
                                    if (startSegment.LaneInfo is null)
                                    {
                                        startSegment.LaneInfo = new LaneInfo(startSegment, derivedFrom: segment.LaneInfo);
                                    }
                                }
                            }
                        }
                    }

                    // The startsegments do not connect to any previous row. This means that this is a new branch.
                    if (!startSegmentsAdded)
                    {
                        // Add new segments started by this revision to the end
                        segments.AddRange(revision.StartSegments);

                        foreach (var startSegment in revision.StartSegments)
                        {
                            startSegment.LaneInfo = new LaneInfo(startSegment, derivedFrom: null);
                        }
                    }
                }

                localOrderedRowCache.Add(new RevisionGraphRow(revision, segments));
            }

            StraightenLanes(startIndex - _straightenLanesLookAhead, lastToCacheRowIndex, localOrderedRowCache);

            // Overwrite the global instance at the end, to prevent flickering
            _orderedRowCache = localOrderedRowCache;

            Updated?.Invoke();

            return;