19 internal class ArrayDeque<T> : IDeque<T>
22 const int MIN_INITIAL_CAPACITY = 8;
29 static int CalculateSize(
int numElements)
31 int initialCapacity = MIN_INITIAL_CAPACITY;
35 if (numElements >= initialCapacity)
37 initialCapacity = numElements;
38 initialCapacity |= (initialCapacity >>> 1);
39 initialCapacity |= (initialCapacity >>> 2);
40 initialCapacity |= (initialCapacity >>> 4);
41 initialCapacity |= (initialCapacity >>> 8);
42 initialCapacity |= (initialCapacity >>> 16);
45 if (initialCapacity < 0)
46 initialCapacity >>>= 1;
49 return initialCapacity;
61 _elements =
new T?[16];
68 public ArrayDeque(
int initialCapacity)
70 EnsureCapacity(initialCapacity);
77 [MemberNotNull(nameof(_elements))]
78 void EnsureCapacity(
int capacity)
80 _elements =
new T?[CalculateSize(capacity)];
89 Debug.Assert(_head == _tail);
92 int n = _elements.Length;
94 int newCapacity = n << 1;
96 throw new InvalidOperationException(
"Sorry, deque too big");
98 var a =
new T?[newCapacity];
99 Array.Copy(_elements, p, a, 0, r);
100 Array.Copy(_elements, 0, a, r, p);
108 public int Count => (_tail - _head) & (_elements.Length - 1);
111 public bool IsEmpty => _head == _tail;
114 public void InsertFirst(T item)
116 var m = _elements.Length - 1;
117 var p = (_head - 1) & m;
127 public bool TryRemoveFirst([MaybeNullWhen(
false)] out T result)
135 var m = _elements.Length - 1;
138 result = _elements[h]!;
140 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
142 _elements[h] =
default;
148 public T RemoveFirst()
150 if (TryRemoveFirst(out var result) ==
false)
151 throw new InvalidOperationException(
"The deque is empty.");
157 public void InsertLast(T item)
159 var m = _elements.Length - 1;
160 var p = (_tail + 1) & m;
162 _elements[_tail] = item;
170 public bool TryRemoveLast([MaybeNullWhen(
false)] out T result)
178 var m = _elements.Length - 1;
179 var p = (_tail - 1) & m;
181 result = _elements[p]!;
183 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
185 _elements[p] =
default;
191 public T RemoveLast()
193 if (TryRemoveLast(out var result) ==
false)
194 throw new InvalidOperationException(
"The deque is empty.");
200 public bool TryPeekFirst([MaybeNullWhen(
false)] out T result)
208 result = _elements[_head]!;
215 if (TryPeekFirst(out var result) ==
false)
216 throw new InvalidOperationException(
"The deque is empty.");
222 public bool TryPeekLast([MaybeNullWhen(
false)] out T result)
230 var m = _elements.Length - 1;
231 var t = (_tail - 1) & m;
232 result = _elements[t]!;
239 if (TryPeekLast(out var result) ==
false)
240 throw new InvalidOperationException(
"The deque is empty.");
246 public bool RemoveFirst(T item)
248 int m = _elements.Length - 1;
253 if (EqualityComparer<T?>.Default.Equals(item, _elements[p]))
266 public bool RemoveLast(T item)
268 int m = _elements.Length - 1;
275 if (EqualityComparer<T?>.Default.Equals(item, _elements[p]))
298 var elements = _elements;
299 int m = elements.Length - 1;
306 if (f >= ((t - h) & m))
307 throw new InvalidOperationException(
"Concurrent operation.");
313 Array.Copy(elements, h, elements, h + 1, f);
317 Array.Copy(elements, 0, elements, 1, i);
318 elements[0] = elements[m];
319 Array.Copy(elements, h, elements, h + 1, m - h);
322 elements[h] =
default;
330 Array.Copy(elements, i + 1, elements, i, b);
335 Array.Copy(elements, i + 1, elements, i, m - i);
336 elements[m] = elements[0];
337 Array.Copy(elements, 1, elements, 0, t);
346 public bool Contains(T item)
348 int m = _elements.Length - 1;
353 if (EqualityComparer<T?>.Default.Equals(item, _elements[i]))
374 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
378 int m = _elements.Length - 1;
382 _elements[i] =
default;
395 public void CopyTo(T[] a)
399 Array.Copy(_elements, _head, a, 0, Count);
401 else if (_head > _tail)
403 int headPortionLen = _elements.Length - _head;
404 Array.Copy(_elements, _head, a, 0, headPortionLen);
405 Array.Copy(_elements, 0, a, headPortionLen, _tail);
413 public void CopyTo(IList<T> list)
417 for (
int i = _head; i < Count; i++)
418 list.Add(_elements[i]!);
420 else if (_head > _tail)
422 int headPortionLen = _elements.Length - _head;
424 for (
int i = _head; i < headPortionLen; i++)
425 list.Add(_elements[i]!);
427 for (
int i = headPortionLen; i < _tail; i++)
428 list.Add(_elements[i]!);
436 public void CopyTo(ImmutableArray<T>.Builder builder)
440 builder.AddRange(_elements.AsSpan().Slice(_head, Count)!);
442 else if (_head > _tail)
444 int headPortionLen = _elements.Length - _head;
445 builder.AddRange(_elements.AsSpan().Slice(_head, headPortionLen)!);
446 builder.AddRange(_elements.AsSpan().Slice(headPortionLen, _tail)!);
459 var a =
new T[Count];
468 public ImmutableArray<T> ToImmutableArray()
470 var a = ImmutableArray.CreateBuilder<T>(Count);
472 return a.DrainToImmutable();
476 IEnumerator<T> IEnumerable<T>.GetEnumerator()
480 for (
int i = _head; i < Count; i++)
481 yield
return _elements[i]!;
483 else if (_head > _tail)
485 int headPortionLen = _elements.Length - _head;
487 for (
int i = _head; i < headPortionLen; i++)
488 yield
return _elements[i]!;
490 for (
int i = headPortionLen; i < _tail; i++)
491 yield
return _elements[i]!;
496 IEnumerator IEnumerable.GetEnumerator()
498 return ((IEnumerable<T>)
this).GetEnumerator();