This repository was archived by the owner on Nov 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 498
Expand file tree
/
Copy pathWaitHandleArray.cs
More file actions
130 lines (105 loc) · 4.45 KB
/
Copy pathWaitHandleArray.cs
File metadata and controls
130 lines (105 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Threading
{
/// <summary>
/// An array intended to be used for thread-specific collections representing wait handles used for multi-wait operations by
/// the thread, to avoid allocations for each multi-wait. Has an initial capacity and grows up to a capacity of
/// <see cref="WaitHandle.MaxWaitHandles"/>. Does not provide a count; the user is responsible for managing the array
/// contents and track the count of elements that are actually used.
/// </summary>
internal struct WaitHandleArray<T>
{
private const int MaximumCapacity = WaitHandle.MaxWaitHandles;
private const int InitialCapacity = 4; // should cover most typical cases
private T[] _items;
public WaitHandleArray(Func<int, T> elementInitializer)
{
Debug.Assert((MaximumCapacity & (MaximumCapacity - 1)) == 0); // is a power of 2
Debug.Assert((InitialCapacity & (InitialCapacity - 1)) == 0); // is a power of 2
Debug.Assert(InitialCapacity < MaximumCapacity);
// Precreating these prevents waits from having to throw <see cref="OutOfMemoryException"/> in most typical cases
_items = new T[InitialCapacity];
if (elementInitializer != null)
{
for (int i = 0; i < InitialCapacity; ++i)
{
_items[i] = elementInitializer(i);
}
}
}
public T[] Items => _items;
public T[] RentItems()
{
Debug.Assert(_items != null);
T[] items = _items;
_items = null;
return items;
}
public void ReturnItems(T[] items)
{
Debug.Assert(items != null);
Debug.Assert(items.Length >= InitialCapacity);
Debug.Assert(items.Length <= MaximumCapacity);
Debug.Assert((items.Length & (items.Length - 1)) == 0); // is a power of 2
Debug.Assert(_items == null);
_items = items;
}
[Conditional("DEBUG")]
public void VerifyElementsAreDefault()
{
Debug.Assert(_items != null);
for (int i = 0; i < _items.Length; ++i)
{
// Do not call EqualityComparer<T>.Default here as it may call type loader. Type loader uses
// locks and we would end up with infinite recursion.
// Debug.Assert(EqualityComparer<T>.Default.Equals(_items[i], default(T)));
if (default(T) != null)
Debug.Assert(_items[i].Equals(default(T)));
else
Debug.Assert(_items[i] == null);
}
}
public void EnsureCapacity(int requiredCapacity, Func<int, T> elementInitializer = null)
{
Debug.Assert(requiredCapacity > 0);
Debug.Assert(requiredCapacity <= MaximumCapacity);
Debug.Assert(_items != null);
if (requiredCapacity > _items.Length)
{
Grow(requiredCapacity, elementInitializer);
}
}
private void Grow(int requiredCapacity, Func<int, T> elementInitializer = null)
{
Debug.Assert(requiredCapacity > _items.Length);
Debug.Assert(requiredCapacity <= MaximumCapacity);
Debug.Assert(_items != null);
int oldCapacity = _items.Length;
int newCapacity = oldCapacity;
do
{
newCapacity <<= 1;
} while (newCapacity < requiredCapacity);
Debug.Assert(newCapacity <= MaximumCapacity);
var newItems = new T[newCapacity];
if (elementInitializer != null)
{
for (int i = 0; i < oldCapacity; ++i)
{
newItems[i] = _items[i];
}
// Run the element initializers before changing the array. If an initializer fails, we'll try the resize again
// next time.
for (int i = oldCapacity; i < newCapacity; ++i)
{
newItems[i] = elementInitializer(i);
}
}
_items = newItems;
}
}
}