File: System\Diagnostics\DiagLinkedList.cs
Web Access
Project: src\src\libraries\System.Diagnostics.DiagnosticSource\src\System.Diagnostics.DiagnosticSource.csproj (System.Diagnostics.DiagnosticSource)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Collections.Generic;
 
namespace System.Diagnostics
{
    internal sealed partial class DiagNode<T>
    {
        public DiagNode(T value) => Value = value;
        public T Value;
        public DiagNode<T>? Next;
    }
 
    // We are not using the public LinkedList<T> because we need to ensure thread safety operation on the list.
    internal sealed class DiagLinkedList<T> : IEnumerable<T>
    {
        private DiagNode<T>? _first;
        private DiagNode<T>? _last;
 
        public DiagLinkedList() { }
 
        public DiagLinkedList(T firstValue) => _last = _first = new DiagNode<T>(firstValue);
 
        public DiagLinkedList(IEnumerator<T> e)
        {
            Debug.Assert(e is not null);
            _last = _first = new DiagNode<T>(e.Current);
 
            while (e.MoveNext())
            {
                _last.Next = new DiagNode<T>(e.Current);
                _last = _last.Next;
            }
        }
 
        public DiagNode<T>? First => _first;
 
        public void Clear()
        {
            lock (this)
            {
                _first = _last = null;
            }
        }
 
        private void UnsafeAdd(DiagNode<T> newNode)
        {
            if (_first is null)
            {
                _first = _last = newNode;
                return;
            }
 
            Debug.Assert(_first is not null);
            Debug.Assert(_last is not null);
 
            _last!.Next = newNode;
            _last = newNode;
        }
 
        public void Add(T value)
        {
            DiagNode<T> newNode = new DiagNode<T>(value);
 
            lock (this)
            {
                UnsafeAdd(newNode);
            }
        }
 
        public bool AddIfNotExist(T value, Func<T, T, bool> compare)
        {
            lock (this)
            {
                DiagNode<T>? current = _first;
                while (current is not null)
                {
                    if (compare(value, current.Value))
                    {
                        return false;
                    }
 
                    current = current.Next;
                }
 
                DiagNode<T> newNode = new DiagNode<T>(value);
                UnsafeAdd(newNode);
 
                return true;
            }
        }
 
        public T? Remove(T value, Func<T, T, bool> compare)
        {
            lock (this)
            {
                DiagNode<T>? previous = _first;
                if (previous is null)
                {
                    return default;
                }
 
                if (compare(previous.Value, value))
                {
                    _first = previous.Next;
                    if (_first is null)
                    {
                        _last = null;
                    }
                    return previous.Value;
                }
 
                DiagNode<T>? current = previous.Next;
 
                while (current is not null)
                {
                    if (compare(current.Value, value))
                    {
                        previous.Next = current.Next;
                        if (object.ReferenceEquals(_last, current))
                        {
                            _last = previous;
                        }
 
                        return current.Value;
                    }
 
                    previous = current;
                    current = current.Next;
                }
 
                return default;
            }
        }
 
        public void AddFront(T value)
        {
            DiagNode<T> newNode = new DiagNode<T>(value);
 
            lock (this)
            {
                newNode.Next = _first;
                _first = newNode;
            }
        }
 
        public DiagEnumerator<T> GetEnumerator() => new DiagEnumerator<T>(_first);
        IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
 
    internal struct DiagEnumerator<T> : IEnumerator<T>
    {
        private static readonly DiagNode<T> s_Empty = new DiagNode<T>(default!);
 
        private DiagNode<T>? _nextNode;
        private DiagNode<T> _currentNode;
 
        public DiagEnumerator(DiagNode<T>? head)
        {
            _nextNode = head;
            _currentNode = s_Empty;
        }
 
        public T Current => _currentNode.Value;
 
        object? IEnumerator.Current => Current;
 
        public bool MoveNext()
        {
            if (_nextNode == null)
            {
                _currentNode = s_Empty;
                return false;
            }
 
            _currentNode = _nextNode;
            _nextNode = _nextNode.Next;
            return true;
        }
 
        public void Reset() => throw new NotSupportedException();
 
        public void Dispose()
        {
        }
    }
}