diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs index 20788ac35e4481c502447ad5d4bacfcc20771b26..7de8bc7d73aa61343eaf2393d6639d81ed056331 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs @@ -22,6 +22,8 @@ private MessageProvider() { } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { // write nothing, always read/deserialized as global Instance diff --git a/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs b/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs index 016232d811dd87288cb5e4a6dcb044511bcff3de..e16dd57275e6b069ce95bc043a11aa73cee17591 100644 --- a/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs +++ b/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs @@ -15,7 +15,7 @@ internal partial class Lexer // From what I see in our own codebase, tokens longer then 40-50 chars are // not very common. // So it seems reasonable to limit the sizes to some round number like 42. - private const int MaxCachedTokenSize = 42; + internal const int MaxCachedTokenSize = 42; private enum QuickScanState : byte { diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxToken.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxToken.cs index 674a265a0969f7e656deb7a17e23fe857063932f..9527381ba4b7e4cdbe4af8042f7c4cfa4e6a3048 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxToken.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxToken.cs @@ -66,6 +66,9 @@ internal SyntaxToken(ObjectReader reader) this.flags |= NodeFlags.IsNotMissing; //note: cleared by subclasses representing missing tokens } + internal override bool ShouldReuseInSerialization => base.ShouldReuseInSerialization && + FullWidth < Lexer.MaxCachedTokenSize; + //==================== public override bool IsToken => true; diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxTrivia.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxTrivia.cs index a7da3f7b6c2bf91cd630148b2aabe752445bb382..0212f9f75fffe9f91200d28f2a43c090ef7ac99b 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxTrivia.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxTrivia.cs @@ -34,6 +34,9 @@ static SyntaxTrivia() public override bool IsTrivia => true; + internal override bool ShouldReuseInSerialization => this.Kind == SyntaxKind.WhitespaceTrivia && + FullWidth < Lexer.MaxCachedTokenSize; + internal override void WriteTo(ObjectWriter writer) { base.WriteTo(writer); diff --git a/src/Compilers/Core/CodeAnalysisTest/ObjectSerializationTests.cs b/src/Compilers/Core/CodeAnalysisTest/ObjectSerializationTests.cs index 301f5c681952c9e6ce8009727808cd58a4b9a229..0041bf6250b9c97ce9e94d91a9c1bc34fee580d8 100644 --- a/src/Compilers/Core/CodeAnalysisTest/ObjectSerializationTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/ObjectSerializationTests.cs @@ -161,6 +161,8 @@ private TypeWithOneMember(ObjectReader reader) : (T)reader.ReadValue(); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { if (typeof(T).IsEnum) @@ -218,6 +220,8 @@ private TypeWithTwoMembers(ObjectReader reader) _member2 = (S)reader.ReadValue(); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { writer.WriteValue(_member1); @@ -276,6 +280,8 @@ private TypeWithManyMembers(ObjectReader reader) } } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { writer.WriteInt32(_members.Length); @@ -511,6 +517,8 @@ private PrimitiveArrayMemberTest(ObjectReader reader) TestReadingPrimitiveArrays(reader); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { TestWritingPrimitiveArrays(writer); @@ -804,6 +812,8 @@ private PrimitiveMemberTest(ObjectReader reader) TestReadingPrimitiveAPIs(reader); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { TestWritingPrimitiveAPIs(writer); @@ -886,6 +896,8 @@ private PrimitiveValueTest(ObjectReader reader) TestReadingPrimitiveValues(reader); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { TestWritingPrimitiveValues(writer); @@ -1146,6 +1158,30 @@ public void TestObjectGraph() TestRoundTripValue(new Node("x", oneNode, oneNode, oneNode, oneNode)); } + [Fact] + public void TestReuse() + { + var oneNode = new Node("one"); + var n1 = new Node("x", oneNode, oneNode, oneNode, oneNode); + var n2 = RoundTripValue(n1, recursive: true); + + Assert.Same(n2.Children[0], n2.Children[1]); + Assert.Same(n2.Children[1], n2.Children[2]); + Assert.Same(n2.Children[2], n2.Children[3]); + } + + [Fact] + public void TestReuseNegative() + { + var oneNode = new Node("one", isReusable: false); + var n1 = new Node("x", oneNode, oneNode, oneNode, oneNode); + var n2 = RoundTripValue(n1, recursive: true); + + Assert.NotSame(n2.Children[0], n2.Children[1]); + Assert.NotSame(n2.Children[1], n2.Children[2]); + Assert.NotSame(n2.Children[2], n2.Children[3]); + } + [Fact] public void TestWideObjectGraph() { @@ -1197,6 +1233,7 @@ private class Node : IObjectWritable, IEquatable { internal readonly string Name; internal readonly Node[] Children; + private readonly bool _isReusable = true; public Node(string name, params Node[] children) { @@ -1204,6 +1241,12 @@ public Node(string name, params Node[] children) this.Children = children; } + public Node(string name, bool isReusable) + : this(name) + { + this._isReusable = isReusable; + } + private Node(ObjectReader reader) { this.Name = reader.ReadString(); @@ -1212,6 +1255,8 @@ private Node(ObjectReader reader) private static readonly Func s_createInstance = r => new Node(r); + bool IObjectWritable.ShouldReuseInSerialization => _isReusable; + public void WriteTo(ObjectWriter writer) { writer.WriteString(this.Name); diff --git a/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs b/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs index 9a201b41234036500143ac37aab4f185eaa2f07b..666c7b4f198f1d8b68b117902ce3dac7a636fae1 100644 --- a/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs +++ b/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs @@ -138,6 +138,8 @@ internal DiagnosticInfo GetInstanceWithSeverity(DiagnosticSeverity severity) #region Serialization + bool IObjectWritable.ShouldReuseInSerialization => false; + void IObjectWritable.WriteTo(ObjectWriter writer) { this.WriteTo(writer); diff --git a/src/Compilers/Core/Portable/Diagnostic/LocalizableResourceString.cs b/src/Compilers/Core/Portable/Diagnostic/LocalizableResourceString.cs index 55011e200bc4d42290fc74268d206b4b99cdd337..744906601808c21c4aeb6122bb197938e271f82e 100644 --- a/src/Compilers/Core/Portable/Diagnostic/LocalizableResourceString.cs +++ b/src/Compilers/Core/Portable/Diagnostic/LocalizableResourceString.cs @@ -93,6 +93,8 @@ private LocalizableResourceString(ObjectReader reader) } } + bool IObjectWritable.ShouldReuseInSerialization => false; + void IObjectWritable.WriteTo(ObjectWriter writer) { writer.WriteType(_resourceSource); diff --git a/src/Compilers/Core/Portable/Serialization/IObjectWritable.cs b/src/Compilers/Core/Portable/Serialization/IObjectWritable.cs index a5c494ff6d7bbc090a922ed3c31a655ca5c9e370..3a331c4ff43f5f981ad793da2f4ea52119ea1d42 100644 --- a/src/Compilers/Core/Portable/Serialization/IObjectWritable.cs +++ b/src/Compilers/Core/Portable/Serialization/IObjectWritable.cs @@ -9,5 +9,12 @@ namespace Roslyn.Utilities internal interface IObjectWritable { void WriteTo(ObjectWriter writer); + + /// + /// Returns 'true' when the same instance could be used more than once. + /// Instances that return 'false' should not be tracked for the purpose + /// of de-duplication while serializing/deserializing. + /// + bool ShouldReuseInSerialization { get; } } } diff --git a/src/Compilers/Core/Portable/Serialization/ObjectBinder.cs b/src/Compilers/Core/Portable/Serialization/ObjectBinder.cs index 926418f39e44e79fa9a406edf926287fb512c9a8..13c884f237219a1374a4331106787f56256faf32 100644 --- a/src/Compilers/Core/Portable/Serialization/ObjectBinder.cs +++ b/src/Compilers/Core/Portable/Serialization/ObjectBinder.cs @@ -32,7 +32,7 @@ internal static class ObjectBinder /// private static readonly Dictionary s_typeToIndex = new Dictionary(); private static readonly List s_types = new List(); - private static readonly List> s_typeReaders = new List>(); + private static readonly List> s_typeReaders = new List>(); /// /// Gets an immutable copy of the state of this binder. This copy does not need to be @@ -51,7 +51,7 @@ public static ObjectBinderSnapshot GetSnapshot() } } - public static void RegisterTypeReader(Type type, Func typeReader) + public static void RegisterTypeReader(Type type, Func typeReader) { lock (s_gate) { diff --git a/src/Compilers/Core/Portable/Serialization/ObjectBinderSnapshot.cs b/src/Compilers/Core/Portable/Serialization/ObjectBinderSnapshot.cs index eb1f135610c2c896704409d6e3200c9aeecabaa2..8ccf8c7bdef5f31ff7777976940867aa62cc4ba9 100644 --- a/src/Compilers/Core/Portable/Serialization/ObjectBinderSnapshot.cs +++ b/src/Compilers/Core/Portable/Serialization/ObjectBinderSnapshot.cs @@ -6,16 +6,16 @@ namespace Roslyn.Utilities { - internal struct ObjectBinderSnapshot + internal readonly struct ObjectBinderSnapshot { private readonly Dictionary _typeToIndex; private readonly ImmutableArray _types; - private readonly ImmutableArray> _typeReaders; + private readonly ImmutableArray> _typeReaders; public ObjectBinderSnapshot( Dictionary typeToIndex, List types, - List> typeReaders) + List> typeReaders) { _typeToIndex = new Dictionary(typeToIndex); _types = types.ToImmutableArray(); @@ -28,7 +28,7 @@ public int GetTypeId(Type type) public Type GetTypeFromId(int typeId) => _types[typeId]; - public Func GetTypeReaderFromId(int typeId) + public Func GetTypeReaderFromId(int typeId) => _typeReaders[typeId]; } } diff --git a/src/Compilers/Core/Portable/Serialization/ObjectReader.cs b/src/Compilers/Core/Portable/Serialization/ObjectReader.cs index f484b40588844e58eaa2a8260df22ffebca853c6..ad60a3cdbdcc3a42175832ccd370d744cdb5a987 100644 --- a/src/Compilers/Core/Portable/Serialization/ObjectReader.cs +++ b/src/Compilers/Core/Portable/Serialization/ObjectReader.cs @@ -607,7 +607,12 @@ private object ReadObject() // recursive: read and construct instance immediately from member elements encoding next in the stream var instance = typeReader(this); - _objectReferenceMap.AddValue(objectId, instance); + + if (instance.ShouldReuseInSerialization) + { + _objectReferenceMap.AddValue(objectId, instance); + } + return instance; } diff --git a/src/Compilers/Core/Portable/Serialization/ObjectWriter.cs b/src/Compilers/Core/Portable/Serialization/ObjectWriter.cs index 41fa9a145def40e191690df1779aeae5937ded89..cc549dad06a75b3b13a1f9779678e3b43b2cf7f2 100644 --- a/src/Compilers/Core/Portable/Serialization/ObjectWriter.cs +++ b/src/Compilers/Core/Portable/Serialization/ObjectWriter.cs @@ -361,10 +361,14 @@ public void Dispose() public bool TryGetReferenceId(object value, out int referenceId) => _valueToIdMap.TryGetValue(value, out referenceId); - public void Add(object value) + public void Add(object value, bool isReusable) { var id = _nextId++; - _valueToIdMap.Add(value, id); + + if (isReusable) + { + _valueToIdMap.Add(value, id); + } } } @@ -432,7 +436,7 @@ private unsafe void WriteStringValue(string value) } else { - _stringReferenceMap.Add(value); + _stringReferenceMap.Add(value, isReusable: true); if (value.IsValidUnicodeString()) { @@ -801,9 +805,9 @@ private void WriteObject(object instance, IObjectWritable instanceAsWritableOpt) private void WriteObjectWorker(IObjectWritable writable) { - // emit object header up front - _objectReferenceMap.Add(writable); + _objectReferenceMap.Add(writable, writable.ShouldReuseInSerialization); + // emit object header up front _writer.Write((byte)EncodingKind.Object); // Directly write out the type-id for this object. i.e. no need to write out the 'Type' diff --git a/src/Compilers/Core/Portable/Syntax/GreenNode.cs b/src/Compilers/Core/Portable/Syntax/GreenNode.cs index 8794a0d6c85e4c3ab8cb295a9ec690f2839aa4b8..146899cc2823e9f64368b65982aea48104195811 100644 --- a/src/Compilers/Core/Portable/Syntax/GreenNode.cs +++ b/src/Compilers/Core/Portable/Syntax/GreenNode.cs @@ -437,6 +437,10 @@ internal GreenNode(ObjectReader reader) } } + bool IObjectWritable.ShouldReuseInSerialization => ShouldReuseInSerialization; + + internal virtual bool ShouldReuseInSerialization => this.IsCacheable; + void IObjectWritable.WriteTo(ObjectWriter writer) { this.WriteTo(writer); diff --git a/src/Compilers/Core/Portable/Syntax/SyntaxAnnotation.cs b/src/Compilers/Core/Portable/Syntax/SyntaxAnnotation.cs index b9d9dd48b53899672be1e190d4d9be3e292b36a6..0c3fd47d7a5ea10cd02d7652b664989b6a70babe 100644 --- a/src/Compilers/Core/Portable/Syntax/SyntaxAnnotation.cs +++ b/src/Compilers/Core/Portable/Syntax/SyntaxAnnotation.cs @@ -57,6 +57,8 @@ private SyntaxAnnotation(ObjectReader reader) this.Data = reader.ReadString(); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { writer.WriteInt64(_id); diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb index 61af6f7c56e04212a6ce53db85c38042faa57b11..939c74ade92327b060e761c2b4731c223cc3f36f 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb @@ -18,6 +18,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Private Sub New() End Sub + Private ReadOnly Property IObjectWritable_ShouldReuseInSerialization As Boolean Implements IObjectWritable.ShouldReuseInSerialization + Get + Return True + End Get + End Property + Private Sub WriteTo(writer As ObjectWriter) Implements IObjectWritable.WriteTo ' don't write anything since we always return the shared 'Instance' when read. End Sub diff --git a/src/Compilers/VisualBasic/Portable/Scanner/QuickTokenAccumulator.vb b/src/Compilers/VisualBasic/Portable/Scanner/QuickTokenAccumulator.vb index 6594cf01894f7bcfa04d18899e71d24966174c2c..7ef06deba004f4f0f4de1451a8aee315077c23e2 100644 --- a/src/Compilers/VisualBasic/Portable/Scanner/QuickTokenAccumulator.vb +++ b/src/Compilers/VisualBasic/Portable/Scanner/QuickTokenAccumulator.vb @@ -134,7 +134,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Private Const s_CHARPROP_LENGTH = &H180 ' Maximum length of a token to scan - Friend Const MAXTOKENSIZE = 42 + Friend Const MAX_CACHED_TOKENSIZE = 42 Shared Sub New() Debug.Assert(s_charProperties.Length = s_CHARPROP_LENGTH) @@ -183,7 +183,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Dim index = _lineBufferOffset And s_PAGE_MASK Dim qtStart = index - Dim limit = index + Math.Min(MAXTOKENSIZE, _bufferLen - offset) + Dim limit = index + Math.Min(MAX_CACHED_TOKENSIZE, _bufferLen - offset) limit = Math.Min(limit, pageArr.Length) Dim hashCode As Integer = Hash.FnvOffsetBias diff --git a/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxToken.vb b/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxToken.vb index 6cb568edf21df431b7cc1ebbd90a908db8dcc24d..d0efaa4704c2cb96e9e0c59d41c1a902254bf1c7 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxToken.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxToken.vb @@ -89,6 +89,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Me._trailingTrivia = DirectCast(reader.ReadValue(), GreenNode) End Sub + Private ReadOnly Property IObjectWritable_ShouldReuseInSerialization As Boolean Implements IObjectWritable.ShouldReuseInSerialization + Get + Return ShouldCacheTriviaInfo(_leadingTrivia, _trailingTrivia) + End Get + End Property + Public Sub WriteTo(writer As ObjectWriter) Implements IObjectWritable.WriteTo writer.WriteValue(_leadingTrivia) writer.WriteValue(_trailingTrivia) @@ -190,6 +196,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax End If End Sub + Friend Overrides ReadOnly Property ShouldReuseInSerialization As Boolean + Get + Return MyBase.ShouldReuseInSerialization AndAlso + Me.FullWidth < Scanner.MAX_CACHED_TOKENSIZE + End Get + End Property + Friend Overrides Sub WriteTo(writer As ObjectWriter) MyBase.WriteTo(writer) writer.WriteString(Me._text) diff --git a/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxTrivia.vb b/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxTrivia.vb index a4841610f366bc145a5739749a538acb692629cd..9681d37b55340af011be669b11a888e5901c7d93 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxTrivia.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxTrivia.vb @@ -49,6 +49,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax ObjectBinder.RegisterTypeReader(GetType(SyntaxTrivia), Function(r) New SyntaxTrivia(r)) End Sub + Friend Overrides ReadOnly Property ShouldReuseInSerialization As Boolean + Get + Select Case Me.Kind + Case SyntaxKind.WhitespaceTrivia, + SyntaxKind.EndOfLineTrivia, + SyntaxKind.LineContinuationTrivia, + SyntaxKind.DocumentationCommentExteriorTrivia, + SyntaxKind.ColonTrivia + + Return True + Case Else + Return False + End Select + End Get + End Property + Friend Overrides Sub WriteTo(writer As ObjectWriter) MyBase.WriteTo(writer) writer.WriteString(Me._text) diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs index 4efd12dab159a4ba2566a27896948113d99d6c2d..2e059a946584e8bd69aa36d041fe7baec2c45ea1 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs @@ -113,6 +113,8 @@ internal partial class SymbolTreeInfo : IObjectWritable return result; } + bool IObjectWritable.ShouldReuseInSerialization => true; + public void WriteTo(ObjectWriter writer) { writer.WriteString(SerializationFormat); diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs index 96024889efcc5b7fab43315f2e59af536a61be76..3771b4b7ac814be1550f2844ef398c1efca4e129 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs @@ -143,6 +143,8 @@ private void WriteFormatAndChecksum(ObjectWriter writer, string formatVersion) return false; } + bool IObjectWritable.ShouldReuseInSerialization => true; + public void WriteTo(ObjectWriter writer) { _literalInfo.WriteTo(writer); diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/BloomFilter_Serialization.cs b/src/Workspaces/Core/Portable/Shared/Utilities/BloomFilter_Serialization.cs index fccbb0a97091bc34f5da7b441f7a01391d731629..7b0de2b28cc0e4714b5eaf29f8c3377168d073ef 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/BloomFilter_Serialization.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/BloomFilter_Serialization.cs @@ -10,6 +10,8 @@ internal partial class BloomFilter : IObjectWritable { private const string SerializationFormat = "2"; + bool IObjectWritable.ShouldReuseInSerialization => true; + public void WriteTo(ObjectWriter writer) { writer.WriteString(SerializationFormat); diff --git a/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs b/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs index d3351772d08968722011b5ae96d9e31c327c5d6f..8f9f05e356b8c7311d9188b481594a464b01f99a 100644 --- a/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs +++ b/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs @@ -15,6 +15,7 @@ internal class SpellChecker : IObjectWritable, IChecksummedObject private const string SerializationFormat = "3"; public Checksum Checksum { get; } + private readonly BKTree _bkTree; public SpellChecker(Checksum checksum, BKTree bKTree) @@ -42,6 +43,8 @@ public IList FindSimilarWords(string value, bool substringsAreSimilar) return array; } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { writer.WriteString(SerializationFormat); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs index a9d41e9c78487d0061b322ebaa2fd7624009f570..5e1028e0846c73a1e2c0246067e9fb8c1e74d0d8 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs @@ -88,6 +88,8 @@ public override unsafe string ToString() return !(left == right); } + bool IObjectWritable.ShouldReuseInSerialization => true; + public void WriteTo(ObjectWriter writer) => _checkSum.WriteTo(writer); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentId.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentId.cs index 3053a7c7496c51904bbd9e1667501530926a6b54..0845d2d1310c6fd19a98f812c657cb6585869321 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentId.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentId.cs @@ -98,6 +98,8 @@ public override int GetHashCode() return !(left == right); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { ProjectId.WriteTo(writer); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentInfo.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentInfo.cs index f5afed3c35f1f108dd5930b12a6d30a1be316df1..58cafed33e4fb975e373e457dd048c9f9b4a2220 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentInfo.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentInfo.cs @@ -204,6 +204,8 @@ internal class DocumentAttributes : IChecksummedObject, IObjectWritable return new DocumentAttributes(newId, newName, newFolders, newSourceCodeKind, newFilePath, newIsGenerated); } + bool IObjectWritable.ShouldReuseInSerialization => true; + public void WriteTo(ObjectWriter writer) { Id.WriteTo(writer); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectId.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectId.cs index b5d167495869ae64a1713fb987ba37355d51d1be..60cad5efe4b4b47b8ef7b714b5bf37ed48a81c15 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectId.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectId.cs @@ -84,6 +84,8 @@ public override int GetHashCode() return this.Id.GetHashCode(); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { writer.WriteGuid(Id); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs index 71760a9d97558feedc643c66782f7f349567be78..4a25189c67e7a61e230a4a2b06bd4c627dbea562 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs @@ -486,6 +486,8 @@ internal class ProjectAttributes : IChecksummedObject, IObjectWritable newHasAllInformation); } + bool IObjectWritable.ShouldReuseInSerialization => true; + public void WriteTo(ObjectWriter writer) { Id.WriteTo(writer); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionId.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionId.cs index 3175c4b604cddd81541bab011e55e0536c234d09..7c11779c3587a8cbf16466cfb778381207e6cf36 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionId.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionId.cs @@ -81,6 +81,8 @@ public override int GetHashCode() return this.Id.GetHashCode(); } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { writer.WriteGuid(Id); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionInfo.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionInfo.cs index a76b498de81c87e2b8dde5afd4f0de8fb0ef792f..f33db027bd5e69dfd7ae68b32fa35855e2a946b8 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionInfo.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionInfo.cs @@ -112,6 +112,8 @@ public SolutionAttributes(SolutionId id, VersionStamp version, string filePath) FilePath = filePath; } + bool IObjectWritable.ShouldReuseInSerialization => true; + public void WriteTo(ObjectWriter writer) { Id.WriteTo(writer); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/VersionStamp.cs b/src/Workspaces/Core/Portable/Workspace/Solution/VersionStamp.cs index 91b7fd8a6e3fda947d122263feb731f8fb09107c..f1d1c2deb25b9c84fd79c7acd69d85dd8bdbc4c2 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/VersionStamp.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/VersionStamp.cs @@ -193,6 +193,8 @@ internal static bool CanReusePersistedVersion(VersionStamp baseVersion, VersionS return baseVersion._utcLastModified == persistedVersion._utcLastModified; } + bool IObjectWritable.ShouldReuseInSerialization => true; + void IObjectWritable.WriteTo(ObjectWriter writer) { WriteTo(writer);