IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ArrayDeque.cs
Go to the documentation of this file.
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Collections.Immutable;
5using System.Diagnostics;
6using System.Diagnostics.CodeAnalysis;
8
10{
11
19 internal class ArrayDeque<T> : IDeque<T>
20 {
21
22 const int MIN_INITIAL_CAPACITY = 8;
23
29 static int CalculateSize(int numElements)
30 {
31 int initialCapacity = MIN_INITIAL_CAPACITY;
32
33 // Find the best power of two to hold elements.
34 // Tests "<=" because arrays aren't kept full.
35 if (numElements >= initialCapacity)
36 {
37 initialCapacity = numElements;
38 initialCapacity |= (initialCapacity >>> 1);
39 initialCapacity |= (initialCapacity >>> 2);
40 initialCapacity |= (initialCapacity >>> 4);
41 initialCapacity |= (initialCapacity >>> 8);
42 initialCapacity |= (initialCapacity >>> 16);
43 initialCapacity++;
44
45 if (initialCapacity < 0) // Too many elements, must back off
46 initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
47 }
48
49 return initialCapacity;
50 }
51
52 T?[] _elements;
53 int _head;
54 int _tail;
55
59 public ArrayDeque()
60 {
61 _elements = new T?[16];
62 }
63
68 public ArrayDeque(int initialCapacity)
69 {
70 EnsureCapacity(initialCapacity);
71 }
72
77 [MemberNotNull(nameof(_elements))]
78 void EnsureCapacity(int capacity)
79 {
80 _elements = new T?[CalculateSize(capacity)];
81 }
82
87 void DoubleCapacity()
88 {
89 Debug.Assert(_head == _tail);
90
91 int p = _head;
92 int n = _elements.Length;
93 int r = n - p; // number of elements to the right of p
94 int newCapacity = n << 1;
95 if (newCapacity < 0)
96 throw new InvalidOperationException("Sorry, deque too big");
97
98 var a = new T?[newCapacity];
99 Array.Copy(_elements, p, a, 0, r);
100 Array.Copy(_elements, 0, a, r, p);
101 _elements = a;
102
103 _head = 0;
104 _tail = n;
105 }
106
108 public int Count => (_tail - _head) & (_elements.Length - 1);
109
111 public bool IsEmpty => _head == _tail;
112
114 public void InsertFirst(T item)
115 {
116 var m = _elements.Length - 1;
117 var p = (_head - 1) & m;
118
119 _elements[p] = item;
120 _head = p;
121
122 if (_head == _tail)
123 DoubleCapacity();
124 }
125
127 public bool TryRemoveFirst([MaybeNullWhen(false)] out T result)
128 {
129 if (_head == _tail)
130 {
131 result = default;
132 return false;
133 }
134
135 var m = _elements.Length - 1;
136 var h = _head;
137
138 result = _elements[h]!;
139#if NET
140 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
141#endif
142 _elements[h] = default;
143 _head = (h + 1) & m;
144 return true;
145 }
146
148 public T RemoveFirst()
149 {
150 if (TryRemoveFirst(out var result) == false)
151 throw new InvalidOperationException("The deque is empty.");
152
153 return result;
154 }
155
157 public void InsertLast(T item)
158 {
159 var m = _elements.Length - 1;
160 var p = (_tail + 1) & m;
161
162 _elements[_tail] = item;
163 _tail = p;
164
165 if (_tail == _head)
166 DoubleCapacity();
167 }
168
170 public bool TryRemoveLast([MaybeNullWhen(false)] out T result)
171 {
172 if (_head == _tail)
173 {
174 result = default;
175 return false;
176 }
177
178 var m = _elements.Length - 1;
179 var p = (_tail - 1) & m;
180
181 result = _elements[p]!;
182#if NET
183 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
184#endif
185 _elements[p] = default;
186 _tail = p;
187 return true;
188 }
189
191 public T RemoveLast()
192 {
193 if (TryRemoveLast(out var result) == false)
194 throw new InvalidOperationException("The deque is empty.");
195
196 return result;
197 }
198
200 public bool TryPeekFirst([MaybeNullWhen(false)] out T result)
201 {
202 if (_head == _tail)
203 {
204 result = default;
205 return false;
206 }
207
208 result = _elements[_head]!;
209 return true;
210 }
211
213 public T PeekFirst()
214 {
215 if (TryPeekFirst(out var result) == false)
216 throw new InvalidOperationException("The deque is empty.");
217
218 return result;
219 }
220
222 public bool TryPeekLast([MaybeNullWhen(false)] out T result)
223 {
224 if (_head == _tail)
225 {
226 result = default;
227 return false;
228 }
229
230 var m = _elements.Length - 1;
231 var t = (_tail - 1) & m;
232 result = _elements[t]!;
233 return true;
234 }
235
237 public T PeekLast()
238 {
239 if (TryPeekLast(out var result) == false)
240 throw new InvalidOperationException("The deque is empty.");
241
242 return result;
243 }
244
246 public bool RemoveFirst(T item)
247 {
248 int m = _elements.Length - 1;
249 int p = _head;
250
251 while (p != _tail)
252 {
253 if (EqualityComparer<T?>.Default.Equals(item, _elements[p]))
254 {
255 DeleteAt(p);
256 return true;
257 }
258
259 p = (p + 1) & m;
260 }
261
262 return false;
263 }
264
266 public bool RemoveLast(T item)
267 {
268 int m = _elements.Length - 1;
269 int p = _tail;
270
271 while (p != _head)
272 {
273 p = (p - 1) & m;
274
275 if (EqualityComparer<T?>.Default.Equals(item, _elements[p]))
276 {
277 DeleteAt(p);
278 return true;
279 }
280 }
281
282 return false;
283 }
284
296 bool DeleteAt(int i)
297 {
298 var elements = _elements;
299 int m = elements.Length - 1;
300 int h = _head;
301 int t = _tail;
302 int f = (i - h) & m;
303 int b = (t - i) & m;
304
305 // invariant: head <= i < tail mod circularity
306 if (f >= ((t - h) & m))
307 throw new InvalidOperationException("Concurrent operation.");
308
309 if (f < b)
310 {
311 if (h <= i)
312 {
313 Array.Copy(elements, h, elements, h + 1, f);
314 }
315 else
316 {
317 Array.Copy(elements, 0, elements, 1, i);
318 elements[0] = elements[m];
319 Array.Copy(elements, h, elements, h + 1, m - h);
320 }
321
322 elements[h] = default;
323 _head = (h + 1) & m;
324 return false;
325 }
326 else
327 {
328 if (i < t)
329 {
330 Array.Copy(elements, i + 1, elements, i, b);
331 _tail = t - 1;
332 }
333 else
334 {
335 Array.Copy(elements, i + 1, elements, i, m - i);
336 elements[m] = elements[0];
337 Array.Copy(elements, 1, elements, 0, t);
338 _tail = (t - 1) & m;
339 }
340
341 return true;
342 }
343 }
344
346 public bool Contains(T item)
347 {
348 int m = _elements.Length - 1;
349 int i = _head;
350
351 while (i != _tail)
352 {
353 if (EqualityComparer<T?>.Default.Equals(item, _elements[i]))
354 return true;
355
356 i = (i + 1) & m;
357 }
358
359 return false;
360 }
361
363 public void Clear()
364 {
365 int h = _head;
366 int t = _tail;
367
368 if (h != t)
369 {
370 _head = _tail = 0;
371
372#if NET
373 // no need to zero out elements for unmanaged structs
374 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
375 {
376#endif
377 int i = h;
378 int m = _elements.Length - 1;
379
380 do
381 {
382 _elements[i] = default;
383 i = (i + 1) & m;
384 } while (i != t);
385#if NET
386 }
387#endif
388 }
389 }
390
395 public void CopyTo(T[] a)
396 {
397 if (_head < _tail)
398 {
399 Array.Copy(_elements, _head, a, 0, Count);
400 }
401 else if (_head > _tail)
402 {
403 int headPortionLen = _elements.Length - _head;
404 Array.Copy(_elements, _head, a, 0, headPortionLen);
405 Array.Copy(_elements, 0, a, headPortionLen, _tail);
406 }
407 }
408
413 public void CopyTo(IList<T> list)
414 {
415 if (_head < _tail)
416 {
417 for (int i = _head; i < Count; i++)
418 list.Add(_elements[i]!);
419 }
420 else if (_head > _tail)
421 {
422 int headPortionLen = _elements.Length - _head;
423
424 for (int i = _head; i < headPortionLen; i++)
425 list.Add(_elements[i]!);
426
427 for (int i = headPortionLen; i < _tail; i++)
428 list.Add(_elements[i]!);
429 }
430 }
431
436 public void CopyTo(ImmutableArray<T>.Builder builder)
437 {
438 if (_head < _tail)
439 {
440 builder.AddRange(_elements.AsSpan().Slice(_head, Count)!);
441 }
442 else if (_head > _tail)
443 {
444 int headPortionLen = _elements.Length - _head;
445 builder.AddRange(_elements.AsSpan().Slice(_head, headPortionLen)!);
446 builder.AddRange(_elements.AsSpan().Slice(headPortionLen, _tail)!);
447 }
448 }
449
457 public T[] ToArray()
458 {
459 var a = new T[Count];
460 CopyTo(a);
461 return a;
462 }
463
468 public ImmutableArray<T> ToImmutableArray()
469 {
470 var a = ImmutableArray.CreateBuilder<T>(Count);
471 CopyTo(a);
472 return a.DrainToImmutable();
473 }
474
476 IEnumerator<T> IEnumerable<T>.GetEnumerator()
477 {
478 if (_head < _tail)
479 {
480 for (int i = _head; i < Count; i++)
481 yield return _elements[i]!;
482 }
483 else if (_head > _tail)
484 {
485 int headPortionLen = _elements.Length - _head;
486
487 for (int i = _head; i < headPortionLen; i++)
488 yield return _elements[i]!;
489
490 for (int i = headPortionLen; i < _tail; i++)
491 yield return _elements[i]!;
492 }
493 }
494
496 IEnumerator IEnumerable.GetEnumerator()
497 {
498 return ((IEnumerable<T>)this).GetEnumerator();
499 }
500
501 }
502
503}