Skip to content

Commit

Permalink
Remove ImmutableHashMap in favor of ImmutableDictionary (#72520)
Browse files Browse the repository at this point in the history
My understanding is that ImmutableHashMap precedes ImmutableDictionary and only exists because of that reason. These two data structures appear to have similar performance and functionality. There is no reason to have our own implementation if there isn't an advantage to doing so.
  • Loading branch information
ToddGrun authored Mar 14, 2024
1 parent 369fbe6 commit c87268a
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 1,195 deletions.
21 changes: 10 additions & 11 deletions src/Workspaces/Core/Portable/Workspace/Solution/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Collections.Immutable;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis;
Expand All @@ -28,10 +27,10 @@ public partial class Project
{
private readonly Solution _solution;
private readonly ProjectState _projectState;
private ImmutableHashMap<DocumentId, Document> _idToDocumentMap = [];
private ImmutableHashMap<DocumentId, SourceGeneratedDocument> _idToSourceGeneratedDocumentMap = [];
private ImmutableHashMap<DocumentId, AdditionalDocument> _idToAdditionalDocumentMap = [];
private ImmutableHashMap<DocumentId, AnalyzerConfigDocument> _idToAnalyzerConfigDocumentMap = [];
private ImmutableDictionary<DocumentId, Document?> _idToDocumentMap = ImmutableDictionary<DocumentId, Document?>.Empty;
private ImmutableDictionary<DocumentId, SourceGeneratedDocument> _idToSourceGeneratedDocumentMap = ImmutableDictionary<DocumentId, SourceGeneratedDocument>.Empty;
private ImmutableDictionary<DocumentId, AdditionalDocument?> _idToAdditionalDocumentMap = ImmutableDictionary<DocumentId, AdditionalDocument?>.Empty;
private ImmutableDictionary<DocumentId, AnalyzerConfigDocument?> _idToAnalyzerConfigDocumentMap = ImmutableDictionary<DocumentId, AnalyzerConfigDocument?>.Empty;

internal Project(Solution solution, ProjectState projectState)
{
Expand Down Expand Up @@ -236,19 +235,19 @@ public bool ContainsAnalyzerConfigDocument(DocumentId documentId)
/// Get the document in this project with the specified document Id.
/// </summary>
public Document? GetDocument(DocumentId documentId)
=> ImmutableHashMapExtensions.GetOrAdd(ref _idToDocumentMap, documentId, s_tryCreateDocumentFunction, this);
=> ImmutableInterlocked.GetOrAdd(ref _idToDocumentMap, documentId, s_tryCreateDocumentFunction, this);

/// <summary>
/// Get the additional document in this project with the specified document Id.
/// </summary>
public TextDocument? GetAdditionalDocument(DocumentId documentId)
=> ImmutableHashMapExtensions.GetOrAdd(ref _idToAdditionalDocumentMap, documentId, s_tryCreateAdditionalDocumentFunction, this);
=> ImmutableInterlocked.GetOrAdd(ref _idToAdditionalDocumentMap, documentId, s_tryCreateAdditionalDocumentFunction, this);

/// <summary>
/// Get the analyzer config document in this project with the specified document Id.
/// </summary>
public AnalyzerConfigDocument? GetAnalyzerConfigDocument(DocumentId documentId)
=> ImmutableHashMapExtensions.GetOrAdd(ref _idToAnalyzerConfigDocumentMap, documentId, s_tryCreateAnalyzerConfigDocumentFunction, this);
=> ImmutableInterlocked.GetOrAdd(ref _idToAnalyzerConfigDocumentMap, documentId, s_tryCreateAnalyzerConfigDocumentFunction, this);

/// <summary>
/// Gets a document or a source generated document in this solution with the specified document ID.
Expand Down Expand Up @@ -285,7 +284,7 @@ public async ValueTask<IEnumerable<SourceGeneratedDocument>> GetSourceGeneratedD

// return an iterator to avoid eagerly allocating all the document instances
return generatedDocumentStates.States.Values.Select(state =>
ImmutableHashMapExtensions.GetOrAdd(ref _idToSourceGeneratedDocumentMap, state.Id, s_createSourceGeneratedDocumentFunction, (state, this)))!;
ImmutableInterlocked.GetOrAdd(ref _idToSourceGeneratedDocumentMap, state.Id, s_createSourceGeneratedDocumentFunction, (state, this)));
}

internal async ValueTask<IEnumerable<Document>> GetAllRegularAndSourceGeneratedDocumentsAsync(CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -318,7 +317,7 @@ internal async ValueTask<IEnumerable<Document>> GetAllRegularAndSourceGeneratedD
}

internal SourceGeneratedDocument GetOrCreateSourceGeneratedDocument(SourceGeneratedDocumentState state)
=> ImmutableHashMapExtensions.GetOrAdd(ref _idToSourceGeneratedDocumentMap, state.Id, s_createSourceGeneratedDocumentFunction, (state, this))!;
=> ImmutableInterlocked.GetOrAdd(ref _idToSourceGeneratedDocumentMap, state.Id, s_createSourceGeneratedDocumentFunction, (state, this));

/// <summary>
/// Returns the <see cref="SourceGeneratedDocumentState"/> for a source generated document that has already been generated and observed.
Expand Down Expand Up @@ -349,7 +348,7 @@ internal SourceGeneratedDocument GetOrCreateSourceGeneratedDocument(SourceGenera
if (documentState == null)
return null;

return ImmutableHashMapExtensions.GetOrAdd(ref _idToSourceGeneratedDocumentMap, documentId, s_createSourceGeneratedDocumentFunction, (documentState, this));
return ImmutableInterlocked.GetOrAdd(ref _idToSourceGeneratedDocumentMap, documentId, s_createSourceGeneratedDocumentFunction, (documentState, this));
}

internal ValueTask<ImmutableArray<Diagnostic>> GetSourceGeneratorDiagnosticsAsync(CancellationToken cancellationToken)
Expand Down
7 changes: 3 additions & 4 deletions src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Collections.Immutable;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis;
Expand All @@ -28,7 +27,7 @@ public partial class Solution
private readonly SolutionCompilationState _compilationState;

// Values for all these are created on demand.
private ImmutableHashMap<ProjectId, Project> _projectIdToProjectMap;
private ImmutableDictionary<ProjectId, Project> _projectIdToProjectMap;

/// <summary>
/// Result of calling <see cref="WithFrozenPartialCompilationsAsync"/>.
Expand All @@ -45,7 +44,7 @@ private Solution(
SolutionCompilationState compilationState,
AsyncLazy<Solution>? cachedFrozenSolution = null)
{
_projectIdToProjectMap = [];
_projectIdToProjectMap = ImmutableDictionary<ProjectId, Project>.Empty;
_compilationState = compilationState;

_cachedFrozenSolution = cachedFrozenSolution ??
Expand Down Expand Up @@ -141,7 +140,7 @@ public Workspace Workspace
{
if (this.ContainsProject(projectId))
{
return ImmutableHashMapExtensions.GetOrAdd(ref _projectIdToProjectMap, projectId, s_createProjectFunction, this);
return ImmutableInterlocked.GetOrAdd(ref _projectIdToProjectMap, projectId, s_createProjectFunction, this);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Extensions\TextSpanExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\CompilerUtilities\CompilerPathUtilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\CompilerUtilities\ImmutableDictionaryExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\CompilerUtilities\ImmutableHashMap.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\CompilerUtilities\ImmutableHashMapExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ConcatImmutableArray`1.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ReferenceCountedDisposable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ReferenceCountedDisposableCache.cs" />
Expand Down
Loading

0 comments on commit c87268a

Please sign in to comment.