Skip to content

Commit 11e245f

Browse files
author
Paul van Brenk
committed
Make HierarchyId map easier to understand
1 parent cd4afe1 commit 11e245f

File tree

1 file changed

+28
-47
lines changed

1 file changed

+28
-47
lines changed

Nodejs/Product/Nodejs/SharedProject/HierarchyIdMap.cs

Lines changed: 28 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
22

33
using System;
4-
using System.Collections.Generic;
4+
using System.Collections.Concurrent;
55
using System.Diagnostics;
66

77
namespace Microsoft.VisualStudioTools.Project
88
{
99
internal sealed class HierarchyIdMap
1010
{
11-
private readonly List<WeakReference<HierarchyNode>> ids = new List<WeakReference<HierarchyNode>>();
12-
private readonly Stack<int> freedIds = new Stack<int>();
13-
14-
private readonly object theLock = new object();
11+
private readonly ConcurrentDictionary<int, WeakReference<HierarchyNode>> nodes = new ConcurrentDictionary<int, WeakReference<HierarchyNode>>();
12+
private readonly ConcurrentStack<int> freedIds = new ConcurrentStack<int>();
1513

1614
/// <summary>
1715
/// Must be called from the UI thread
1816
/// </summary>
1917
public uint Add(HierarchyNode node)
2018
{
19+
VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
20+
2121
#if DEBUG
22-
foreach (var reference in this.ids)
22+
foreach (var reference in this.nodes.Values)
2323
{
2424
if (reference != null)
2525
{
@@ -29,25 +29,15 @@ public uint Add(HierarchyNode node)
2929
}
3030
}
3131
}
32-
#endif
3332

34-
VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
35-
36-
lock (this.theLock)
33+
#endif
34+
if (!this.freedIds.TryPop(out var idx))
3735
{
38-
if (this.freedIds.Count > 0)
39-
{
40-
var i = this.freedIds.Pop();
41-
this.ids[i] = new WeakReference<HierarchyNode>(node);
42-
return (uint)i + 1;
43-
}
44-
else
45-
{
46-
this.ids.Add(new WeakReference<HierarchyNode>(node));
47-
// ids are 1 based
48-
return (uint)this.ids.Count;
49-
}
36+
idx = this.nodes.Count;
5037
}
38+
this.nodes[idx] = new WeakReference<HierarchyNode>(node);
39+
40+
return (uint)idx + 1;
5141
}
5242

5343
/// <summary>
@@ -57,33 +47,21 @@ public void Remove(HierarchyNode node)
5747
{
5848
VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
5949

60-
if (node == null)
61-
{
62-
throw new ArgumentNullException(nameof(node));
63-
}
50+
Debug.Assert(node != null, "Called with null node");
6451

65-
lock (this.theLock)
66-
{
67-
var i = (int)node.ID - 1;
68-
if (0 > i || i >= this.ids.Count)
69-
{
70-
throw new InvalidOperationException($"Invalid id. {i}");
71-
}
52+
var idx = (int)node.ID - 1;
7253

73-
var weakRef = this.ids[i];
74-
if (weakRef == null)
75-
{
76-
throw new InvalidOperationException("Trying to retrieve a node before adding.");
77-
}
54+
var removeCheck = this.nodes.TryGetValue(idx, out var weakRef);
7855

79-
if (weakRef.TryGetTarget(out var found) && !object.ReferenceEquals(node, found))
80-
{
81-
throw new InvalidOperationException("The node has the wrong id.");
82-
}
56+
Debug.Assert(removeCheck, "How did we get an id, which we haven't seen before");
57+
Debug.Assert(weakRef != null, "Double delete is not expected.");
8358

84-
this.ids[i] = null;
85-
this.freedIds.Push(i);
86-
}
59+
var checkReference = weakRef.TryGetTarget(out var found) && object.ReferenceEquals(node, found);
60+
61+
Debug.Assert(checkReference, "The node has the wrong id.");
62+
63+
this.nodes[idx] = null;
64+
this.freedIds.Push(idx);
8765
}
8866

8967
/// <summary>
@@ -93,12 +71,15 @@ public HierarchyNode this[uint itemId]
9371
{
9472
get
9573
{
74+
VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
75+
9676
var i = (int)itemId - 1;
97-
if (0 <= i && i < this.ids.Count)
77+
if (0 <= i && i < this.nodes.Count)
9878
{
99-
var reference = this.ids[i];
79+
var reference = this.nodes[i];
10080
if (reference != null && reference.TryGetTarget(out var node))
10181
{
82+
Debug.Assert(node != null);
10283
return node;
10384
}
10485
}

0 commit comments

Comments
 (0)