using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Threading;
using Internal;

namespace System.Collections.Concurrent
{
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy(typeof(SingleProducerSingleConsumerQueue<>.SingleProducerSingleConsumerQueue_DebugView))]
	internal sealed class SingleProducerSingleConsumerQueue<T> : IEnumerable<T>, IEnumerable
	{
		public SingleProducerSingleConsumerQueue()
		{
			this._head = (this._tail = new SingleProducerSingleConsumerQueue<T>.Segment(32));
		}

		public void Enqueue(T item)
		{
			SingleProducerSingleConsumerQueue<T>.Segment tail = this._tail;
			T[] array = tail._array;
			int last = tail._state._last;
			int num = (last + 1) & (array.Length - 1);
			if (num != tail._state._firstCopy)
			{
				array[last] = item;
				tail._state._last = num;
				return;
			}
			this.EnqueueSlow(item, ref tail);
		}

		private void EnqueueSlow(T item, ref SingleProducerSingleConsumerQueue<T>.Segment segment)
		{
			if (segment._state._firstCopy != segment._state._first)
			{
				segment._state._firstCopy = segment._state._first;
				this.Enqueue(item);
				return;
			}
			int num = this._tail._array.Length << 1;
			if (num > 16777216)
			{
				num = 16777216;
			}
			SingleProducerSingleConsumerQueue<T>.Segment segment2 = new SingleProducerSingleConsumerQueue<T>.Segment(num);
			segment2._array[0] = item;
			segment2._state._last = 1;
			segment2._state._lastCopy = 1;
			try
			{
			}
			finally
			{
				Volatile.Write<SingleProducerSingleConsumerQueue<T>.Segment>(ref this._tail._next, segment2);
				this._tail = segment2;
			}
		}

		public bool TryDequeue([MaybeNullWhen(false)] out T result)
		{
			SingleProducerSingleConsumerQueue<T>.Segment head = this._head;
			T[] array = head._array;
			int first = head._state._first;
			if (first != head._state._lastCopy)
			{
				result = array[first];
				array[first] = default(T);
				head._state._first = (first + 1) & (array.Length - 1);
				return true;
			}
			return this.TryDequeueSlow(head, array, false, out result);
		}

		public bool TryPeek([MaybeNullWhen(false)] out T result)
		{
			SingleProducerSingleConsumerQueue<T>.Segment head = this._head;
			T[] array = head._array;
			int first = head._state._first;
			if (first != head._state._lastCopy)
			{
				result = array[first];
				return true;
			}
			return this.TryDequeueSlow(head, array, true, out result);
		}

		private bool TryDequeueSlow(SingleProducerSingleConsumerQueue<T>.Segment segment, T[] array, bool peek, [MaybeNullWhen(false)] out T result)
		{
			if (segment._state._last != segment._state._lastCopy)
			{
				segment._state._lastCopy = segment._state._last;
				if (!peek)
				{
					return this.TryDequeue(out result);
				}
				return this.TryPeek(out result);
			}
			else
			{
				if (segment._next != null && segment._state._first == segment._state._last)
				{
					segment = segment._next;
					array = segment._array;
					this._head = segment;
				}
				int first = segment._state._first;
				if (first == segment._state._last)
				{
					result = default(T);
					return false;
				}
				result = array[first];
				if (!peek)
				{
					array[first] = default(T);
					segment._state._first = (first + 1) & (segment._array.Length - 1);
					segment._state._lastCopy = segment._state._last;
				}
				return true;
			}
		}

		public bool IsEmpty
		{
			get
			{
				SingleProducerSingleConsumerQueue<T>.Segment head = this._head;
				return head._state._first == head._state._lastCopy && head._state._first == head._state._last && head._next == null;
			}
		}

		public IEnumerator<T> GetEnumerator()
		{
			SingleProducerSingleConsumerQueue<T>.<GetEnumerator>d__12 <GetEnumerator>d__ = new SingleProducerSingleConsumerQueue<T>.<GetEnumerator>d__12(0);
			<GetEnumerator>d__.<>4__this = this;
			return <GetEnumerator>d__;
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		internal int Count
		{
			get
			{
				int num = 0;
				for (SingleProducerSingleConsumerQueue<T>.Segment segment = this._head; segment != null; segment = segment._next)
				{
					int num2 = segment._array.Length;
					int first;
					int last;
					do
					{
						first = segment._state._first;
						last = segment._state._last;
					}
					while (first != segment._state._first);
					num += (last - first) & (num2 - 1);
				}
				return num;
			}
		}

		private volatile SingleProducerSingleConsumerQueue<T>.Segment _head;

		private volatile SingleProducerSingleConsumerQueue<T>.Segment _tail;

		[StructLayout(LayoutKind.Sequential)]
		private sealed class Segment
		{
			internal Segment(int size)
			{
				this._array = new T[size];
			}

			internal SingleProducerSingleConsumerQueue<T>.Segment _next;

			internal readonly T[] _array;

			internal SingleProducerSingleConsumerQueue<T>.SegmentState _state;
		}

		private struct SegmentState
		{
			internal PaddingFor32 _pad0;

			internal volatile int _first;

			internal int _lastCopy;

			internal PaddingFor32 _pad1;

			internal int _firstCopy;

			internal volatile int _last;

			internal PaddingFor32 _pad2;
		}

		private sealed class SingleProducerSingleConsumerQueue_DebugView
		{
			public SingleProducerSingleConsumerQueue_DebugView(SingleProducerSingleConsumerQueue<T> queue)
			{
				this._queue = queue;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public T[] Items
			{
				get
				{
					return new List<T>(this._queue).ToArray();
				}
			}

			private readonly SingleProducerSingleConsumerQueue<T> _queue;
		}
	}
}
