< Summary

Class:Towel.DataStructures.RedBlackTreeLinked<T1, T2>
Assembly:Towel
File(s):File 1: /home/runner/work/Towel/Towel/Sources/Towel/DataStructures/RedBlackTree.cs
Covered lines:208
Uncovered lines:251
Coverable lines:459
Total lines:677
Line coverage:45.3% (208 of 459)
Covered branches:76
Total branches:188
Branch coverage:40.4% (76 of 188)

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
File 1: .ctor(...)100%1100%
File 1: .ctor(...)100%1100%
File 1: .ctor(...)100%10%
File 1: get_CurrentLeast()0%40%
File 1: get_CurrentGreatest()0%40%
File 1: get_Count()100%1100%
File 1: get_Compare()100%1100%
File 1: TryAdd(...)62.5%1677.5%
File 1: Clear()100%10%
File 1: Clone()100%10%
File 1: Contains(...)100%1100%
File 1: ContainsSift(...)87.5%892.3%
File 1: TryGet(...)0%80%
File 1: TryRemove(...)100%1100%
File 1: TryRemoveSift(...)75%883.33%
File 1: Remove(...)56.25%1661.9%
File 1: StepperBreak(...)100%10%
File 1: StepperBreak(...)0%20%
File 1: StepperReverseBreak(...)100%10%
File 1: StepperReverseBreak(...)0%20%
File 1: System.Collections.IEnumerable.GetEnumerator()100%10%
File 1: GetEnumerator()100%4100%
File 1: BalanceAddition(...)50%1848.93%
File 1: RotateLeft(...)100%10100%
File 1: RotateRight(...)0%100%
File 1: BalanceRemoval(...)54.54%2246.15%
File 1: GetLeftMostNode(...)75%4100%
File 1: ToArray()100%10%

File(s)

/home/runner/work/Towel/Towel/Sources/Towel/DataStructures/RedBlackTree.cs

#LineLine coverage
 1namespace Towel.DataStructures;
 2
 3/// <summary>A self sorting binary tree using the red-black tree algorithms.</summary>
 4/// <typeparam name="T">The type of values stored in this data structure.</typeparam>
 5public interface IRedBlackTree<T> : ISortedBinaryTree<T>
 6{
 7
 8}
 9
 10/// <summary>A self sorting binary tree using the red-black tree algorithms.</summary>
 11/// <typeparam name="T">The type of values stored in this data structure.</typeparam>
 12/// <typeparam name="TCompare">The type that is comparing <typeparamref name="T"/> values.</typeparam>
 13public interface IRedBlackTree<T, TCompare> : IRedBlackTree<T>, ISortedBinaryTree<T, TCompare>
 14  where TCompare : struct, IFunc<T, T, CompareResult>
 15{
 16
 17}
 18
 19/// <summary>Static helpers for <see cref="IRedBlackTree{T}"/> and <see cref="IRedBlackTree{T, TCompare}"/>.</summary>
 20public static class RedBlackTree
 21{
 22
 23}
 24
 25/// <summary>Static helpers for <see cref="RedBlackTreeLinked{T, TCompare}"/>.</summary>
 26public static class RedBlackTreeLinked
 27{
 28  #region Extension Methods
 29
 30  /// <summary>Constructs a new <see cref="RedBlackTreeLinked{T, TCompare}"/>.</summary>
 31  /// <typeparam name="T">The type of values stored in this data structure.</typeparam>
 32  /// <param name="compare">The function for comparing <typeparamref name="T"/> values.</param>
 33  /// <returns>The new constructed <see cref="RedBlackTreeLinked{T, TCompare}"/>.</returns>
 34  public static RedBlackTreeLinked<T, SFunc<T, T, CompareResult>> New<T>(
 35    Func<T, T, CompareResult>? compare = null) =>
 36    new(compare ?? Compare);
 37
 38  #endregion
 39}
 40
 41/// <summary>A self sorting binary tree using the red-black tree algorithms.</summary>
 42/// <typeparam name="T">The type of values stored in this data structure.</typeparam>
 43/// <typeparam name="TCompare">The type that is comparing <typeparamref name="T"/> values.</typeparam>
 44public class RedBlackTreeLinked<T, TCompare> : IRedBlackTree<T, TCompare>, ICloneable<RedBlackTreeLinked<T, TCompare>>
 45  where TCompare : struct, IFunc<T, T, CompareResult>
 46{
 47  internal const bool Red = true;
 48  internal const bool Black = false;
 1649  internal readonly Node _sentinelNode = new(value: default!, color: Black, leftChild: null!, rightChild: null!);
 50
 51  internal TCompare _compare;
 52  internal int _count;
 53  internal Node _root;
 54
 55  #region Nested Types
 56
 57  internal class Node
 58  {
 59    internal T Value;
 60    internal bool Color;
 61    internal Node? Parent;
 62    internal Node LeftChild;
 63    internal Node RightChild;
 64
 44965    public Node(
 44966      T value,
 44967      Node leftChild,
 44968      Node rightChild,
 44969      bool color = Red,
 44970      Node? parent = null)
 44971    {
 44972      Value = value;
 44973      Color = color;
 44974      Parent = parent;
 44975      LeftChild = leftChild;
 44976      RightChild = rightChild;
 44977    }
 78  }
 79
 80  #endregion
 81
 82  #region Constructors
 83
 84  /// <summary>Constructs a new Red Black Tree.</summary>
 85  /// <param name="compare">The comparison method to be used when sorting the values of the tree.</param>
 1686  public RedBlackTreeLinked(TCompare compare = default)
 1687  {
 1688    _root = _sentinelNode;
 1689    _compare = compare;
 1690  }
 91
 92  /// <summary>Constructor for cloning purposes.</summary>
 93  /// <param name="tree">The tree to be cloned.</param>
 094  internal RedBlackTreeLinked(RedBlackTreeLinked<T, TCompare> tree)
 095  {
 96    Node Clone(Node node, Node? parent)
 097    {
 098      if (node == _sentinelNode)
 099      {
 0100        return _sentinelNode;
 101      }
 0102      Node clone = new(
 0103        value: node.Value,
 0104        color: node.Color,
 0105        parent: parent,
 0106        leftChild: null!,
 0107        rightChild: null!);
 0108      clone.LeftChild = node.LeftChild == _sentinelNode ? _sentinelNode : Clone(node.LeftChild, clone);
 0109      clone.RightChild = node.RightChild == _sentinelNode ? _sentinelNode : Clone(node.RightChild, clone);
 0110      return clone;
 0111    }
 0112    _compare = tree._compare;
 0113    _count = tree._count;
 0114    _root = Clone(tree._root, null);
 0115  }
 116
 117  #endregion
 118
 119  #region Properties
 120
 121  /// <inheritdoc/>
 122  public T CurrentLeast
 123  {
 124    get
 0125    {
 0126      if (_root == _sentinelNode)
 0127      {
 0128        throw new InvalidOperationException("Attempting to get the least value from an empty tree.");
 129      }
 0130      Node node = _root;
 0131      while (node.LeftChild != _sentinelNode)
 0132      {
 0133        node = node.LeftChild;
 0134      }
 0135      return node.Value;
 0136    }
 137  }
 138
 139  /// <inheritdoc/>
 140  public T CurrentGreatest
 141  {
 142    get
 0143    {
 0144      if (_root == _sentinelNode)
 0145      {
 0146        throw new InvalidOperationException("Attempting to get the greatest value from an empty tree.");
 147      }
 0148      Node node = _root;
 0149      while (node.RightChild != _sentinelNode)
 0150      {
 0151        node = node.RightChild;
 0152      }
 0153      return node.Value;
 0154    }
 155  }
 156
 157  /// <inheritdoc/>
 16158  public int Count => _count;
 159
 160  /// <inheritdoc/>
 420161  public TCompare Compare => _compare;
 162
 163  #endregion
 164
 165  #region Methods
 166
 167  /// <inheritdoc/>
 168  public (bool Success, Exception? Exception) TryAdd(T value)
 433169  {
 433170    Exception? exception = null;
 433171    Node addition = new(value: value, leftChild: _sentinelNode, rightChild: _sentinelNode);
 433172    Node node = _root;
 3709173    while (node != _sentinelNode)
 3278174    {
 3278175      addition.Parent = node;
 3278176      CompareResult compareResult = _compare.Invoke(value, node.Value);
 3278177      switch (compareResult)
 178      {
 0179        case Less:    node = node.LeftChild; break;
 6552180        case Greater: node = node.RightChild; break;
 181        case Equal:
 2182          exception = new ArgumentException($"Adding to add a duplicate value to a {nameof(RedBlackTreeLinked<T, TCompar
 2183          goto Break;
 184        default:
 0185          exception = new ArgumentException($"Invalid {nameof(TCompare)} function; an undefined {nameof(CompareResult)} 
 0186          goto Break;
 187      }
 3276188    }
 433189  Break:
 433190    if (exception is not null)
 2191    {
 2192      return (false, exception);
 193    }
 431194    if (addition.Parent is not null)
 416195    {
 416196      CompareResult compareResult = _compare.Invoke(addition.Value, addition.Parent.Value);
 416197      switch (compareResult)
 198      {
 0199        case Less:    addition.Parent.LeftChild  = addition; break;
 832200        case Greater: addition.Parent.RightChild = addition; break;
 0201        case Equal:   exception = new CorruptedDataStructureException(); break;
 202        default:
 0203          exception = new ArgumentException($"Invalid {nameof(TCompare)} function; an undefined {nameof(CompareResult)} 
 0204          break;
 205      }
 416206    }
 207    else
 15208    {
 15209      _root = addition;
 15210    }
 431211    if (exception is not null)
 0212    {
 0213      return (false, exception);
 214    }
 431215    BalanceAddition(addition);
 431216    _count += 1;
 431217    return (true, null);
 433218  }
 219
 220  /// <inheritdoc/>
 221  public void Clear()
 0222  {
 0223    _root = _sentinelNode;
 0224    _count = 0;
 0225  }
 226
 227  /// <inheritdoc/>
 0228  public RedBlackTreeLinked<T, TCompare> Clone() => new(this);
 229
 230  /// <inheritdoc/>
 212231  public bool Contains(T value) => ContainsSift<SiftFromCompareAndValue<T, TCompare>>(new(value, Compare));
 232
 233  /// <inheritdoc/>
 234  public bool ContainsSift<TSift>(TSift sift = default)
 235    where TSift : struct, IFunc<T, CompareResult>
 212236  {
 212237    Node node = _root;
 1260238    while (node != _sentinelNode && node is not null)
 1254239    {
 1254240      CompareResult compareResult = sift.Invoke(node.Value);
 1254241      switch (compareResult)
 242      {
 1328243        case Less:    node = node.RightChild; break;
 768244        case Greater: node = node.LeftChild;  break;
 206245        case Equal:   return true;
 0246        default: throw new ArgumentException($"Invalid {nameof(TCompare)} function; an undefined {nameof(CompareResult)}
 247      }
 1048248    }
 6249    return false;
 212250  }
 251
 252  /// <inheritdoc/>
 253  public (bool Success, T? Value, Exception? Exception) TryGet<TSift>(TSift sift = default)
 254    where TSift : struct, IFunc<T, CompareResult>
 0255  {
 0256    Node node = _root;
 0257    while (node != _sentinelNode)
 0258    {
 0259      CompareResult compareResult = sift.Invoke(node.Value);
 0260      switch (compareResult)
 261      {
 0262        case Less:    node = node.LeftChild; break;
 0263        case Greater: node = node.RightChild; break;
 0264        case Equal: return (true, node.Value, null);
 265        default:
 0266          throw compareResult.IsDefined()
 0267            ? new TowelBugException($"Unhandled {nameof(CompareResult)} value: {compareResult}.")
 0268            : new ArgumentException($"Invalid {nameof(TCompare)} function; an undefined {nameof(CompareResult)} was retu
 269      }
 0270    }
 0271    return (false, default, new ArgumentException("Attempting to get a non-existing value."));
 0272  }
 273
 274  /// <inheritdoc/>
 208275  public (bool Success, Exception? Exception) TryRemove(T value) => TryRemoveSift<SiftFromCompareAndValue<T, TCompare>>(
 276
 277  /// <inheritdoc/>
 278  public (bool Success, Exception? Exception) TryRemoveSift<TSift>(TSift sift = default)
 279    where TSift : struct, IFunc<T, CompareResult>
 208280  {
 281    Node node;
 208282    node = _root;
 906283    while (node != _sentinelNode)
 904284    {
 904285      CompareResult compareResult = sift.Invoke(node.Value);
 904286      switch (compareResult)
 287      {
 4288        case Less:    node = node.RightChild; break;
 1392289        case Greater: node = node.LeftChild; break;
 290        case Equal:
 206291          if (node == _sentinelNode)
 0292          {
 0293            return (false, new ArgumentException("Attempting to remove a non-existing entry."));
 294          }
 206295          Remove(node);
 206296          _count -= 1;
 206297          return (true, null);
 298        default:
 0299          return (false, new ArgumentException($"Invalid {nameof(TCompare)} function; an undefined {nameof(CompareResult
 300      }
 698301    }
 2302    return (false, new ArgumentException("Attempting to remove a non-existing entry."));
 208303  }
 304
 305  internal void Remove(Node removal)
 206306  {
 307    Node x;
 308    Node temp;
 206309    if (removal.LeftChild == _sentinelNode || removal.RightChild == _sentinelNode)
 206310    {
 206311      temp = removal;
 206312    }
 313    else
 0314    {
 0315      temp = removal.RightChild;
 0316      while (temp.LeftChild != _sentinelNode)
 0317      {
 0318        temp = temp.LeftChild;
 0319      }
 0320    }
 206321    if (temp.LeftChild != _sentinelNode)
 0322    {
 0323      x = temp.LeftChild;
 0324    }
 325    else
 206326    {
 206327      x = temp.RightChild;
 206328    }
 206329    x.Parent = temp.Parent;
 206330    if (temp.Parent is not null)
 198331    {
 198332      if (temp == temp.Parent.LeftChild)
 198333      {
 198334        temp.Parent.LeftChild = x;
 198335      }
 336      else
 0337      {
 0338        temp.Parent.RightChild = x;
 0339      }
 198340    }
 341    else
 8342    {
 8343      _root = x;
 8344    }
 206345    if (temp != removal)
 0346    {
 0347      removal.Value = temp.Value;
 0348    }
 206349    if (temp.Color == Black)
 204350    {
 204351      BalanceRemoval(x);
 204352    }
 206353  }
 354
 355  /// <inheritdoc/>
 356  public StepStatus StepperBreak<TStep>(TStep step = default)
 357    where TStep : struct, IFunc<T, StepStatus>
 0358  {
 359    StepStatus Stepper(Node node)
 0360    {
 0361      if (node != _sentinelNode)
 0362      {
 0363        if (Stepper(node.LeftChild) is Break ||
 0364          step.Invoke(node.Value) is Break ||
 0365          Stepper(node.RightChild) is Break)
 0366          return Break;
 0367      }
 0368      return Continue;
 0369    }
 0370    return Stepper(_root);
 0371  }
 372
 373  /// <inheritdoc/>
 374  public virtual StepStatus StepperBreak<TStep>(T minimum, T maximum, TStep step = default)
 375    where TStep : struct, IFunc<T, StepStatus>
 0376  {
 377    StepStatus Stepper(Node node)
 0378    {
 0379      if (node != _sentinelNode)
 0380      {
 0381        if (_compare.Invoke(node.Value, minimum) is Less)
 0382        {
 0383          return Stepper(node.RightChild);
 384        }
 0385        else if (_compare.Invoke(node.Value, maximum) is Greater)
 0386        {
 0387          return Stepper(node.LeftChild);
 388        }
 389        else
 0390        {
 0391          if (Stepper(node.LeftChild) is Break ||
 0392            step.Invoke(node.Value) is Break ||
 0393            Stepper(node.RightChild) is Break)
 0394            return Break;
 0395        }
 0396      }
 0397      return Continue;
 0398    }
 0399    if (_compare.Invoke(minimum, maximum) is Greater)
 0400    {
 0401      throw new InvalidOperationException("!(" + nameof(minimum) + " <= " + nameof(maximum) + ")");
 402    }
 0403    return Stepper(_root);
 0404  }
 405
 406  /// <inheritdoc/>
 407  public StepStatus StepperReverseBreak<TStep>(TStep step = default)
 408    where TStep : struct, IFunc<T, StepStatus>
 0409  {
 410    StepStatus StepperReverse(Node node)
 0411    {
 0412      if (node != _sentinelNode)
 0413      {
 0414        if (StepperReverse(node.LeftChild) is Break ||
 0415          step.Invoke(node.Value) is Break ||
 0416          StepperReverse(node.RightChild) is Break)
 0417          return Break;
 0418      }
 0419      return Continue;
 0420    }
 0421    return StepperReverse(_root);
 0422  }
 423
 424  /// <inheritdoc/>
 425  public virtual StepStatus StepperReverseBreak<TStep>(T minimum, T maximum, TStep step = default)
 426    where TStep : struct, IFunc<T, StepStatus>
 0427  {
 428    StepStatus StepperReverse(Node node)
 0429    {
 0430      if (node != _sentinelNode)
 0431      {
 0432        if (_compare.Invoke(node.Value, minimum) is Less)
 0433        {
 0434          return StepperReverse(node.RightChild);
 435        }
 0436        else if (_compare.Invoke(node.Value, maximum) is Greater)
 0437        {
 0438          return StepperReverse(node.LeftChild);
 439        }
 440        else
 0441        {
 0442          if (StepperReverse(node.LeftChild) is Break ||
 0443            step.Invoke(node.Value) is Break ||
 0444            StepperReverse(node.RightChild) is Break)
 0445            return Break;
 0446        }
 0447      }
 0448      return Continue;
 0449    }
 0450    if (_compare.Invoke(minimum, maximum) is Greater)
 0451    {
 0452      throw new InvalidOperationException("!(" + nameof(minimum) + " <= " + nameof(maximum) + ")");
 453    }
 0454    return StepperReverse(_root);
 0455  }
 456
 0457  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
 458
 459  /// <inheritdoc/>
 460  public System.Collections.Generic.IEnumerator<T> GetEnumerator()
 7461  {
 462    Node? GetNextNode(Node node)
 26463    {
 26464      if (node.RightChild != _sentinelNode)
 10465      {
 10466        return GetLeftMostNode(node.RightChild);
 467      }
 16468      var parent = node.Parent;
 26469      while (parent is not null && node == parent.RightChild)
 10470      {
 10471        node = parent;
 10472        parent = parent.Parent;
 10473      }
 16474      return parent;
 26475    }
 7476    if (_count > 0)
 6477    {
 64478      for (var node = GetLeftMostNode(_root); node is not null; node = GetNextNode(node))
 26479      {
 26480        yield return node.Value;
 26481      }
 6482    }
 7483  }
 484
 485  internal void BalanceAddition(Node balancing)
 431486  {
 487    Node temp;
 1148488    while (balancing != _root && balancing.Parent!.Color == Red)
 717489    {
 717490      if (balancing.Parent == balancing.Parent.Parent!.LeftChild)
 0491      {
 0492        temp = balancing.Parent.Parent.RightChild;
 0493        if (temp is not null && temp.Color == Red)
 0494        {
 0495          balancing.Parent.Color = Black;
 0496          temp.Color = Black;
 0497          balancing.Parent.Parent.Color = Red;
 0498          balancing = balancing.Parent.Parent;
 0499        }
 500        else
 0501        {
 0502          if (balancing == balancing.Parent.RightChild)
 0503          {
 0504            balancing = balancing.Parent;
 0505            RotateLeft(balancing);
 0506          }
 0507          balancing.Parent!.Color = Black;
 0508          balancing.Parent.Parent!.Color = Red;
 0509          RotateRight(balancing.Parent.Parent);
 0510        }
 0511      }
 512      else
 717513      {
 717514        temp = balancing.Parent.Parent.LeftChild;
 717515        if (temp is not null && temp.Color == Red)
 351516        {
 351517          balancing.Parent.Color = Black;
 351518          temp.Color = Black;
 351519          balancing.Parent.Parent.Color = Red;
 351520          balancing = balancing.Parent.Parent;
 351521        }
 522        else
 366523        {
 366524          if (balancing == balancing.Parent.LeftChild)
 0525          {
 0526            balancing = balancing.Parent;
 0527            RotateRight(balancing);
 0528          }
 366529          balancing.Parent!.Color = Black;
 366530          balancing.Parent.Parent!.Color = Red;
 366531          RotateLeft(balancing.Parent.Parent);
 366532        }
 717533      }
 717534    }
 431535    _root.Color = Black;
 431536  }
 537
 538  internal void RotateLeft(Node redBlackTree)
 456539  {
 456540    Node temp = redBlackTree.RightChild;
 456541    redBlackTree.RightChild = temp.LeftChild;
 456542    if (temp.LeftChild != _sentinelNode)
 249543      temp.LeftChild.Parent = redBlackTree;
 456544    if (temp != _sentinelNode)
 456545      temp.Parent = redBlackTree.Parent;
 456546    if (redBlackTree.Parent is not null)
 411547    {
 411548      if (redBlackTree == redBlackTree.Parent.LeftChild)
 72549        redBlackTree.Parent.LeftChild = temp;
 550      else
 339551        redBlackTree.Parent.RightChild = temp;
 411552    }
 553    else
 45554    {
 45555      _root = temp;
 45556    }
 456557    temp.LeftChild = redBlackTree;
 456558    if (redBlackTree != _sentinelNode)
 456559      redBlackTree.Parent = temp;
 456560  }
 561
 562  internal void RotateRight(Node redBlacktree)
 0563  {
 0564    Node temp = redBlacktree.LeftChild;
 0565    redBlacktree.LeftChild = temp.RightChild;
 0566    if (temp.RightChild != _sentinelNode)
 0567      temp.RightChild.Parent = redBlacktree;
 0568    if (temp != _sentinelNode)
 0569      temp.Parent = redBlacktree.Parent;
 0570    if (redBlacktree.Parent is not null)
 0571    {
 0572      if (redBlacktree == redBlacktree.Parent.RightChild)
 0573        redBlacktree.Parent.RightChild = temp;
 574      else
 0575        redBlacktree.Parent.LeftChild = temp;
 0576    }
 577    else
 0578    {
 0579      _root = temp;
 0580    }
 0581    temp.RightChild = redBlacktree;
 0582    if (redBlacktree != _sentinelNode)
 0583      redBlacktree.Parent = temp;
 0584  }
 585
 586  internal void BalanceRemoval(Node balancing)
 204587  {
 588    Node temp;
 388589    while (balancing != _root && balancing.Color == Black)
 184590    {
 184591      if (balancing == balancing.Parent!.LeftChild)
 184592      {
 184593        temp = balancing.Parent.RightChild;
 184594        if (temp.Color == Red)
 80595        {
 80596          temp.Color = Black;
 80597          balancing.Parent.Color = Red;
 80598          RotateLeft(balancing.Parent);
 80599          temp = balancing.Parent.RightChild;
 80600        }
 184601        if (temp.LeftChild.Color == Black && temp.RightChild.Color == Black)
 174602        {
 174603          temp.Color = Red;
 174604          balancing = balancing.Parent;
 174605        }
 606        else
 10607        {
 10608          if (temp.RightChild.Color == Black)
 0609          {
 0610            temp.LeftChild.Color = Black;
 0611            temp.Color = Red;
 0612            RotateRight(temp);
 0613            temp = balancing.Parent.RightChild;
 0614          }
 10615          temp.Color = balancing.Parent.Color;
 10616          balancing.Parent.Color = Black;
 10617          temp.RightChild.Color = Black;
 10618          RotateLeft(balancing.Parent);
 10619          balancing = _root;
 10620        }
 184621      }
 622      else
 0623      {
 0624        temp = balancing.Parent.LeftChild;
 0625        if (temp.Color == Red)
 0626        {
 0627          temp.Color = Black;
 0628          balancing.Parent.Color = Red;
 0629          RotateRight(balancing.Parent);
 0630          temp = balancing.Parent.LeftChild;
 0631        }
 0632        if (temp.RightChild.Color == Black && temp.LeftChild.Color == Black)
 0633        {
 0634          temp.Color = Red;
 0635          balancing = balancing.Parent;
 0636        }
 637        else
 0638        {
 0639          if (temp.LeftChild.Color == Black)
 0640          {
 0641            temp.RightChild.Color = Black;
 0642            temp.Color = Red;
 0643            RotateLeft(temp);
 0644            temp = balancing.Parent.LeftChild;
 0645          }
 0646          temp.Color = balancing.Parent.Color;
 0647          balancing.Parent.Color = Black;
 0648          temp.LeftChild.Color = Black;
 0649          RotateRight(balancing.Parent);
 0650          balancing = _root;
 0651        }
 0652      }
 184653    }
 204654    balancing.Color = Black;
 204655  }
 656
 657  internal Node GetLeftMostNode(Node node)
 16658  {
 26659    while (node.LeftChild is not null && node.LeftChild != _sentinelNode)
 10660    {
 10661      node = node.LeftChild;
 10662    }
 16663    return node;
 16664  }
 665
 666  /// <inheritdoc/>
 667  public T[] ToArray()
 0668  {
 669#warning TODO: optimize
 0670    T[] array = new T[_count];
 0671    int i = 0;
 0672    this.Stepper(x => array[i++] = x);
 0673    return array;
 0674  }
 675
 676  #endregion
 677}