internal HighFidelityTrackingPoint(ITextVersion version, int position, PointTrackingMode trackingMode, TrackingFidelityMode fidelity) : base(version, position, trackingMode) { if (fidelity != TrackingFidelityMode.UndoRedo && fidelity != TrackingFidelityMode.Backward) { throw new ArgumentOutOfRangeException(nameof(fidelity)); } List <VersionNumberPosition> initialHistory = null; if (fidelity == TrackingFidelityMode.UndoRedo && version.VersionNumber > 0) { // The system may perform undo operations that reach prior to the initial version; if any of // those transitions are noninvertible, then redoing back to the initial version will give the // wrong answer. Thus we save the state of the point for the initial version, unless the // initial version happens to be version zero (in which case we could not undo past it). initialHistory = new List <VersionNumberPosition>(); if (version.VersionNumber != version.ReiteratedVersionNumber) { Debug.Assert(version.ReiteratedVersionNumber < version.VersionNumber); // If the current version and reiterated version differ, also remember the position // using the reiterated version number, since when undoing back to this point it // will be the key that is used. initialHistory.Add(new VersionNumberPosition(version.ReiteratedVersionNumber, position)); } initialHistory.Add(new VersionNumberPosition(version.VersionNumber, position)); } this.cachedPosition = new VersionPositionHistory(version, position, initialHistory); this.fidelity = fidelity; }
protected override int TrackPosition(ITextVersion targetVersion) { // Compute the new position on the requested snapshot. // This object caches the most recently requested version and the position in that version. // // We are relying on the atomicity of pointer copies (this.cachedPosition might change after we've // fetched it below but we will always get a self-consistent VersionPosition). This ensures we // have proper behavior when called from multiple threads (multiple threads may all track and update the // cached value if called at inconvenient times, but they will return consistent results). // // In most cases, one can track backwards from the cached version to a previously computed // version and get the same result, but this is not always the case: in particular, when the // position lies in a deleted region, simulating reinsertion of that region will not cause // the previous value of the position to be recovered. Such transitions are called noninvertible. // This class explicitly tracks the positions of the point for versions for which the subsequent // transition is noninvertible; this allows the value to be computed properly when tracking backwards // or in undo/redo situations. VersionPositionHistory cached = this.cachedPosition; // must fetch just once if (targetVersion == cached.Version) { // easy! return(cached.Position); } List <VersionNumberPosition> noninvertibleHistory = cached.NoninvertibleHistory; int targetPosition; if (targetVersion.VersionNumber > cached.Version.VersionNumber) { // Roll the cached version forward to the requested version. targetPosition = TrackPositionForwardInTime (this.trackingMode, this.fidelity, ref noninvertibleHistory, cached.Position, cached.Version, targetVersion); // Cache new position this.cachedPosition = new VersionPositionHistory(targetVersion, targetPosition, noninvertibleHistory); } else { // roll backwards from the cached version targetPosition = TrackPositionBackwardInTime (this.trackingMode, this.fidelity == TrackingFidelityMode.Backward ? noninvertibleHistory : null, cached.Position, cached.Version, targetVersion); } return(targetPosition); }
public override string ToString() { VersionPositionHistory c = this.cachedPosition; System.Text.StringBuilder sb = new System.Text.StringBuilder("*"); sb.Append(ToString(c.Version, c.Position, this.trackingMode)); if (c.NoninvertibleHistory != null) { sb.Append("["); foreach (VersionNumberPosition vp in c.NoninvertibleHistory) { sb.Append(string.Format(System.Globalization.CultureInfo.CurrentCulture, "V{0}@{1}", vp.VersionNumber, vp.Position)); } sb.Append("]"); } return(sb.ToString()); }