合并主线最近几年来的主要更新,重点推进TinyHttpClient,替代HttpClient
大石头 authored at 2023-03-08 18:39:12
4.17 KiB
X_NET20
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace System.Collections.Concurrent
{
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy(typeof(CollectionDebuggerView<>))]
	public class ConcurrentStack<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable
	{
		private class Node
		{
			public T Value = default(T);

			public Node Next;
		}

		private class NodeObjectPool : ObjectPool<Node>
		{
			protected override Node Creator()
			{
				return new Node();
			}
		}

		private Node head;

		private int count;

		private static readonly NodeObjectPool pool = new NodeObjectPool();

		private object syncRoot = new object();

		bool ICollection.IsSynchronized => true;

		object ICollection.SyncRoot => syncRoot;

		public int Count => count;

		public bool IsEmpty => count == 0;

		private static Node ZeroOut(Node node)
		{
			node.Value = default(T);
			node.Next = null;
			return node;
		}

		public ConcurrentStack()
		{
		}

		public ConcurrentStack(IEnumerable<T> collection)
		{
			foreach (T item in collection)
			{
				Push(item);
			}
		}

		bool IProducerConsumerCollection<T>.TryAdd(T elem)
		{
			Push(elem);
			return true;
		}

		public void Push(T item)
		{
			Node temp = pool.Take();
			temp.Value = item;
			do
			{
				temp.Next = head;
			}
			while (Interlocked.CompareExchange(ref head, temp, temp.Next) != temp.Next);
			Interlocked.Increment(ref count);
		}

		public void PushRange(T[] items)
		{
			PushRange(items, 0, items.Length);
		}

		public void PushRange(T[] items, int startIndex, int count)
		{
			Node insert = null;
			Node first = null;
			for (int i = startIndex; i < count; i++)
			{
				Node temp = pool.Take();
				temp.Value = items[i];
				temp.Next = insert;
				insert = temp;
				if (first == null)
				{
					first = temp;
				}
			}
			do
			{
				first.Next = head;
			}
			while (Interlocked.CompareExchange(ref head, insert, first.Next) != first.Next);
			Interlocked.Add(ref count, count);
		}

		public bool TryPop(out T result)
		{
			Node temp;
			do
			{
				temp = head;
				if (temp == null)
				{
					result = default(T);
					return false;
				}
			}
			while (Interlocked.CompareExchange(ref head, temp.Next, temp) != temp);
			Interlocked.Decrement(ref count);
			result = temp.Value;
			pool.Release(ZeroOut(temp));
			return true;
		}

		public int TryPopRange(T[] items)
		{
			return TryPopRange(items, 0, items.Length);
		}

		public int TryPopRange(T[] items, int startIndex, int count)
		{
			Node temp;
			Node end;
			do
			{
				temp = head;
				if (temp == null)
				{
					return -1;
				}
				end = temp;
				for (int j = 0; j < count - 1; j++)
				{
					end = end.Next;
					if (end == null)
					{
						break;
					}
				}
			}
			while (Interlocked.CompareExchange(ref head, end, temp) != temp);
			int i;
			for (i = startIndex; i < count; i++)
			{
				if (temp == null)
				{
					break;
				}
				items[i] = temp.Value;
				end = temp;
				temp = temp.Next;
				pool.Release(ZeroOut(end));
			}
			return i - 1;
		}

		public bool TryPeek(out T result)
		{
			Node myHead = head;
			if (myHead == null)
			{
				result = default(T);
				return false;
			}
			result = myHead.Value;
			return true;
		}

		public void Clear()
		{
			count = 0;
			head = null;
		}

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

		public IEnumerator<T> GetEnumerator()
		{
			return InternalGetEnumerator();
		}

		private IEnumerator<T> InternalGetEnumerator()
		{
			Node my_head = head;
			if (my_head != null)
			{
				Node next;
				do
				{
					yield return my_head.Value;
					my_head = (next = my_head.Next);
				}
				while (next != null);
			}
		}

		void ICollection.CopyTo(Array array, int index)
		{
			T[] dest = array as T[];
			if (dest != null)
			{
				CopyTo(dest, index);
			}
		}

		public void CopyTo(T[] array, int index)
		{
			IEnumerator<T> e = InternalGetEnumerator();
			int i = index;
			while (e.MoveNext())
			{
				array[i++] = e.Current;
			}
		}

		bool IProducerConsumerCollection<T>.TryTake(out T item)
		{
			return TryPop(out item);
		}

		public T[] ToArray()
		{
			T[] dest = new T[count];
			CopyTo(dest, 0);
			return dest;
		}
	}
}