Skip to content

Commit

Permalink
Merge pull request #69086 from CyrusNajmabadi/valueTypeToRecord2
Browse files Browse the repository at this point in the history
Convert several other types over to being records.
  • Loading branch information
CyrusNajmabadi authored Jul 18, 2023
2 parents 19769f5 + b8bb12b commit ebc2841
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 169 deletions.
11 changes: 1 addition & 10 deletions src/EditorFeatures/Core/Shared/Utilities/VirtualTreePoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities
{
internal readonly struct VirtualTreePoint : IComparable<VirtualTreePoint>, IEquatable<VirtualTreePoint>
internal readonly record struct VirtualTreePoint : IComparable<VirtualTreePoint>
{
private readonly SyntaxTree _tree;
private readonly SourceText _text;
Expand All @@ -28,18 +28,12 @@ public VirtualTreePoint(SyntaxTree tree, SourceText text, int position, int virt
_virtualSpaces = virtualSpaces;
}

public static bool operator !=(VirtualTreePoint left, VirtualTreePoint right)
=> !(left == right);

public static bool operator <(VirtualTreePoint left, VirtualTreePoint right)
=> left.CompareTo(right) < 0;

public static bool operator <=(VirtualTreePoint left, VirtualTreePoint right)
=> left.CompareTo(right) <= 0;

public static bool operator ==(VirtualTreePoint left, VirtualTreePoint right)
=> object.Equals(left, right);

public static bool operator >(VirtualTreePoint left, VirtualTreePoint right)
=> left.CompareTo(right) > 0;

Expand Down Expand Up @@ -75,9 +69,6 @@ public int CompareTo(VirtualTreePoint other)
public bool Equals(VirtualTreePoint other)
=> CompareTo(other) == 0;

public override bool Equals(object? obj)
=> (obj is VirtualTreePoint) && Equals((VirtualTreePoint)obj);

public override int GetHashCode()
=> Text.GetHashCode() ^ Position.GetHashCode() ^ VirtualSpaces.GetHashCode();

Expand Down
30 changes: 14 additions & 16 deletions src/Features/Core/Portable/DocumentSpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,34 @@ namespace Microsoft.CodeAnalysis
/// <summary>
/// Represents a <see cref="TextSpan"/> location in a <see cref="Document"/>.
/// </summary>
internal readonly struct DocumentSpan(
Document document,
TextSpan sourceSpan,
ImmutableDictionary<string, object>? properties) : IEquatable<DocumentSpan>
internal readonly record struct DocumentSpan
{
public Document Document { get; } = document;
public TextSpan SourceSpan { get; } = sourceSpan;
public Document Document { get; }
public TextSpan SourceSpan { get; }

/// <summary>
/// Additional information attached to a document span by it creator.
/// </summary>
public ImmutableDictionary<string, object>? Properties { get; } = properties ?? ImmutableDictionary<string, object>.Empty;
public ImmutableDictionary<string, object>? Properties { get; }

public DocumentSpan(
Document document,
TextSpan sourceSpan,
ImmutableDictionary<string, object>? properties)
{
Document = document;
SourceSpan = sourceSpan;
Properties = properties ?? ImmutableDictionary<string, object>.Empty;
}

public DocumentSpan(Document document, TextSpan sourceSpan)
: this(document, sourceSpan, properties: null)
{
}

public override bool Equals(object? obj)
=> obj is DocumentSpan documentSpan && Equals(documentSpan);

public bool Equals(DocumentSpan obj)
=> Document == obj.Document && SourceSpan == obj.SourceSpan;

public static bool operator ==(DocumentSpan d1, DocumentSpan d2)
=> d1.Equals(d2);

public static bool operator !=(DocumentSpan d1, DocumentSpan d2)
=> !(d1 == d2);

public override int GetHashCode()
=> Hash.Combine(
Document,
Expand Down
62 changes: 10 additions & 52 deletions src/VisualStudio/Core/Impl/CodeModel/SyntaxNodeKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel
{
/// <summary>
/// Uniquely identifies a top-level syntax declaration within a SyntaxTree.
/// This is achieved by combining the qualified name of the declaration and an
/// ordinal value. The ordinal value is used to distinguish nodes which have the same
/// qualified name -- for example, across partial classes within the same tree.
/// Uniquely identifies a top-level syntax declaration within a SyntaxTree. This is achieved by combining the
/// qualified name of the declaration and an ordinal value. The ordinal value is used to distinguish nodes which
/// have the same qualified name -- for example, across partial classes within the same tree.
/// </summary>
internal readonly struct SyntaxNodeKey : IEquatable<SyntaxNodeKey>
internal readonly record struct SyntaxNodeKey
{
private readonly string _name;
private readonly int _ordinal;
public string Name { get; }
public int Ordinal { get; }

public static readonly SyntaxNodeKey Empty = new SyntaxNodeKey();
public static readonly SyntaxNodeKey Empty = new();

public SyntaxNodeKey(string name, int ordinal)
{
Expand All @@ -30,51 +29,10 @@ public SyntaxNodeKey(string name, int ordinal)
throw new ArgumentOutOfRangeException(nameof(ordinal));
}

_name = name ?? throw new ArgumentNullException(nameof(name));
_ordinal = ordinal;
Name = name ?? throw new ArgumentNullException(nameof(name));
Ordinal = ordinal;
}

public bool Equals(SyntaxNodeKey other)
{
return _name == other._name
&& _ordinal == other._ordinal;
}

public override bool Equals(object obj)
{
if (obj is SyntaxNodeKey key)
{
return Equals(key);
}

return false;
}

public override int GetHashCode()
=> _name.GetHashCode() + _ordinal;

public override string ToString()
=> $"{{{_name}, {_ordinal}}}";

public string Name
{
get { return _name; }
}

public int Ordinal
{
get { return _ordinal; }
}

public bool IsEmpty
{
get { return _name == null && _ordinal == 0; }
}

public static bool operator ==(SyntaxNodeKey left, SyntaxNodeKey right)
=> left.Equals(right);

public static bool operator !=(SyntaxNodeKey left, SyntaxNodeKey right)
=> !left.Equals(right);
public bool IsEmpty => Name is null && Ordinal == 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ private bool ChecksumMatches(TKey key, string name, Checksum checksum, Cancellat
static (self, connection, database, rowId) => self.ReadChecksum(connection, database, rowId),
this,
cancellationToken);
return optional.HasValue && checksum == optional.Value;
return optional.HasValue && checksum.Hash == optional.Value;
}

[PerformanceSensitive("https://github.com/dotnet/roslyn/issues/36114", AllowCaptures = false)]
Expand Down Expand Up @@ -312,7 +312,7 @@ private Optional<Stream> ReadDataBlob(
private bool ChecksumsMatch_MustRunInTransaction(SqlConnection connection, Database database, long rowId, Checksum checksum)
{
var storedChecksum = connection.ReadChecksum_MustRunInTransaction(database, Table, rowId);
return storedChecksum.HasValue && checksum == storedChecksum.Value;
return storedChecksum.HasValue && checksum.Hash == storedChecksum.Value;
}

private void BindPrimaryKey(SqlStatement statement, TDatabaseKey databaseKey, int dataNameId)
Expand Down
77 changes: 17 additions & 60 deletions src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,15 @@ namespace Microsoft.CodeAnalysis
/// without actually comparing data itself
/// </summary>
[DataContract]
internal sealed partial class Checksum(Checksum.HashData hash) : IObjectWritable, IEquatable<Checksum>
internal sealed partial record class Checksum(
[property: DataMember(Order = 0)] Checksum.HashData Hash) : IObjectWritable
{
/// <summary>
/// The intended size of the <see cref="HashData"/> structure.
/// </summary>
public const int HashSize = 20;

public static readonly Checksum Null = new(default);

[DataMember(Order = 0)]
private readonly HashData _checksum = hash;
public static readonly Checksum Null = new(Hash: default);

/// <summary>
/// Create Checksum from given byte array. if byte array is bigger than <see cref="HashSize"/>, it will be
Expand Down Expand Up @@ -59,17 +57,6 @@ public static Checksum From(ReadOnlySpan<byte> checksum)
return new Checksum(hash);
}

public bool Equals(Checksum other)
{
return other != null && _checksum == other._checksum;
}

public override bool Equals(object obj)
=> Equals(obj as Checksum);

public override int GetHashCode()
=> _checksum.GetHashCode();

public string ToBase64String()
{
#if NETCOREAPP
Expand All @@ -82,7 +69,7 @@ public string ToBase64String()
var data = new byte[HashSize];
fixed (byte* dataPtr = data)
{
*(HashData*)dataPtr = _checksum;
*(HashData*)dataPtr = Hash;
}

return Convert.ToBase64String(data, 0, HashSize);
Expand All @@ -96,27 +83,14 @@ public static Checksum FromBase64String(string value)
public override string ToString()
=> ToBase64String();

public static bool operator ==(Checksum left, Checksum right)
=> EqualityComparer<Checksum>.Default.Equals(left, right);

public static bool operator !=(Checksum left, Checksum right)
=> !(left == right);

public static bool operator ==(Checksum left, HashData right)
=> left._checksum == right;

public static bool operator !=(Checksum left, HashData right)
=> !(left == right);

bool IObjectWritable.ShouldReuseInSerialization => true;

public void WriteTo(ObjectWriter writer)
=> _checksum.WriteTo(writer);
=> Hash.WriteTo(writer);

public void WriteTo(Span<byte> span)
{
Contract.ThrowIfFalse(span.Length >= HashSize);
Contract.ThrowIfFalse(MemoryMarshal.TryWrite(span, ref Unsafe.AsRef(in _checksum)));
Hash.WriteTo(span);
}

public static Checksum ReadFrom(ObjectReader reader)
Expand All @@ -132,32 +106,25 @@ public static Checksum ReadFrom(ObjectReader reader)
/// This structure stores the 20-byte hash as an inline value rather than requiring the use of
/// <c>byte[]</c>.
/// </summary>
[DataContract]
[StructLayout(LayoutKind.Explicit, Size = HashSize)]
public readonly struct HashData(long data1, long data2, int data3) : IEquatable<HashData>
[DataContract, StructLayout(LayoutKind.Explicit, Size = HashSize)]
public readonly record struct HashData(
[field: FieldOffset(0)][property: DataMember(Order = 0)] long Data1,
[field: FieldOffset(8)][property: DataMember(Order = 1)] long Data2,
[field: FieldOffset(16)][property: DataMember(Order = 2)] int Data3)
{
[FieldOffset(0), DataMember(Order = 0)]
private readonly long Data1 = data1;

[FieldOffset(8), DataMember(Order = 1)]
private readonly long Data2 = data2;

[FieldOffset(16), DataMember(Order = 2)]
private readonly int Data3 = data3;

public static bool operator ==(HashData x, HashData y)
=> x.Equals(y);

public static bool operator !=(HashData x, HashData y)
=> !(x == y);

public void WriteTo(ObjectWriter writer)
{
writer.WriteInt64(Data1);
writer.WriteInt64(Data2);
writer.WriteInt32(Data3);
}

public void WriteTo(Span<byte> span)
{
Contract.ThrowIfFalse(span.Length >= HashSize);
Contract.ThrowIfFalse(MemoryMarshal.TryWrite(span, ref Unsafe.AsRef(in this)));
}

public static unsafe HashData FromPointer(HashData* hash)
=> new(hash->Data1, hash->Data2, hash->Data3);

Expand All @@ -169,16 +136,6 @@ public override int GetHashCode()
// The checksum is already a hash. Just read a 4-byte value to get a well-distributed hash code.
return (int)Data1;
}

public override bool Equals(object obj)
=> obj is HashData other && Equals(other);

public bool Equals(HashData other)
{
return Data1 == other.Data1
&& Data2 == other.Data2
&& Data3 == other.Data3;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
namespace Microsoft.CodeAnalysis
{
// various factory methods. all these are just helper methods
internal partial class Checksum
internal partial record class Checksum
{
// https://github.com/dotnet/runtime/blob/f2db6d6093c54e5eeb9db2d8dcbe15b2db92ad8c/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/SHA256.cs#L18-L19
private const int SHA256HashSizeBytes = 256 / 8;
Expand Down Expand Up @@ -223,7 +223,7 @@ private static Checksum CreateUsingByteArrays(Checksum checksum1, Checksum check

private static Checksum CreateUsingSpans(Checksum checksum1, Checksum checksum2)
{
Span<HashData> checksums = stackalloc HashData[] { checksum1._checksum, checksum2._checksum };
Span<HashData> checksums = stackalloc HashData[] { checksum1.Hash, checksum2.Hash };
Span<byte> hashResultSpan = stackalloc byte[SHA256HashSizeBytes];

SHA256.HashData(MemoryMarshal.AsBytes(checksums), hashResultSpan);
Expand All @@ -233,7 +233,7 @@ private static Checksum CreateUsingSpans(Checksum checksum1, Checksum checksum2)

private static Checksum CreateUsingSpans(Checksum checksum1, Checksum checksum2, Checksum checksum3)
{
Span<HashData> checksums = stackalloc HashData[] { checksum1._checksum, checksum2._checksum, checksum3._checksum };
Span<HashData> checksums = stackalloc HashData[] { checksum1.Hash, checksum2.Hash, checksum3.Hash };
Span<byte> hashResultSpan = stackalloc byte[SHA256HashSizeBytes];

SHA256.HashData(MemoryMarshal.AsBytes(checksums), hashResultSpan);
Expand Down
Loading

0 comments on commit ebc2841

Please sign in to comment.