< Summary

Class:Towel.DataStructures.BTreeLinked<T1, T2>
Assembly:Towel
File(s):File 1: /home/runner/work/Towel/Towel/Sources/Towel/DataStructures/BTree.cs
Covered lines:466
Uncovered lines:23
Coverable lines:489
Total lines:684
Line coverage:95.2% (466 of 489)
Covered branches:179
Total branches:194
Branch coverage:92.2% (179 of 194)

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
File 1: .ctor(...)100%1100%
File 1: get_IsLeaf()100%1100%
File 1: get_IsFull()100%1100%
File 1: .ctor(...)50%4100%
File 1: get_Count()100%1100%
File 1: get_Compare()100%1100%
File 1: get_MaxDegree()100%1100%
File 1: Clear()100%2100%
File 1: Search(...)100%8100%
File 1: Contains(...)100%1100%
File 1: TryAdd(...)100%10100%
File 1: Split(...)100%16100%
File 1: TryAdd(...)85%2090.9%
File 1: TryRemove(...)95%10096.47%
File 1: ToArray()100%2100%
File 1: LeftmostNode(...)100%2100%
File 1: NextNode(...)100%10100%
File 1: GetEnumerator()25%425%
File 1: System.Collections.IEnumerable.GetEnumerator()100%10%
File 1: StepperBreak(...)100%2100%
File 1: StepperBreak(...)75%481.81%
File 1: Clone()90%10100%

File(s)

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

#LineLine coverage
 1namespace Towel.DataStructures;
 2
 3/// <summary>Static helpers for <see cref="BTreeLinked{T, TCompare}"/>.</summary>
 4public static class BTreeLinked
 5{
 6  #region Extension Methods
 7
 8  /// <inheritdoc cref="BTreeLinked{T, TCompare}.BTreeLinked(byte, TCompare)" />
 9  /// <inheritdoc cref="BTreeLinked{T, TCompare}" />
 10  /// <returns>The new constructed <see cref="BTreeLinked{T, TCompare}"/>.</returns>
 11  public static BTreeLinked<T, SFunc<T, T, CompareResult>> New<T>(
 12    byte maxDegree,
 13    Func<T, T, CompareResult>? compare = null) =>
 14    new(maxDegree, compare ?? Compare);
 15
 16  #endregion
 17}
 18
 19/// <summary>B-Tree Data structure.</summary>
 20/// <typeparam name="T">The type to store</typeparam>
 21/// <typeparam name="TCompare">The type that is comparing <typeparamref name="T"/> values.</typeparam>
 22public class BTreeLinked<T, TCompare> : IDataStructure<T>,
 23  DataStructure.IAddable<T>,
 24  DataStructure.IRemovable<T>,
 25  DataStructure.ICountable,
 26  DataStructure.IClearable,
 27  DataStructure.IAuditable<T>,
 28  DataStructure.IComparing<T, TCompare>,
 29  ICloneable<BTreeLinked<T, TCompare>>
 30  where TCompare : struct, IFunc<T, T, CompareResult>
 31{
 32  internal Node _root;
 33  internal int _count;
 34  internal TCompare _compare;
 35  internal byte _maxDegree;
 36
 37  #region Nested Types
 38
 39  internal class Node
 40  {
 41    internal T[] _values;
 42    internal Node?[] _children;
 43    internal Node? _parent;
 44    internal byte _parentIndex;
 45    internal byte _count;
 46
 646747    public Node(byte maxdegree)
 646748    {
 646749      _values = new T[maxdegree - 1];
 646750      _children = new Node?[maxdegree];
 646751    }
 52
 10781053    public bool IsLeaf => _children[0] is null;
 54
 9845155    public bool IsFull => _count + 1 == _children.Length;
 56  }
 57
 58  #endregion
 59
 60  #region Constructors
 61
 62  /// <summary>Creates a B-Tree having nodes of given maximum size. Maximum size must be even</summary>
 63  /// <param name="maxdegree">The maximum degree/children a node can have. Must be even</param>
 64  /// <param name="compare">The function for comparing <typeparamref name="T"/> values.</param>
 1665  public BTreeLinked(byte maxdegree, TCompare compare = default)
 1666  {
 1667    if (maxdegree < 4) throw new ArgumentException("Maximum degree should be at least 4", nameof(maxdegree));
 1668    if (maxdegree % 2 is not 0) throw new ArgumentException("Maximum degree should be an even number", nameof(maxdegree)
 1669    _root = new(maxdegree);
 1670    _count = 0;
 1671    _maxDegree = maxdegree;
 1672    _compare = compare;
 1673  }
 74
 75  #endregion
 76
 77  #region Properties
 78
 79  /// <inheritdoc />
 480  public int Count => _count;
 81
 82  /// <inheritdoc />
 48415283  public TCompare Compare => _compare;
 84
 85  /// <summary>The fixed size of a node within this tree</summary>
 1522386  public byte MaxDegree => _maxDegree;
 87
 88  #endregion
 89
 90  #region Methods
 91
 92  /// <inheritdoc />
 93  public void Clear()
 294  {
 295    _count = 0;
 296    _root._count = 0;
 3697    for (int i = 0; i < MaxDegree; i++)
 1698    {
 1699      _root._children[i] = null;
 16100    }
 2101  }
 102
 103  /// <summary>
 104  /// Searches for an value in the tree and provides the
 105  /// node it is contained in and its index in the array (as 'out' variables)
 106  /// if it exists. Otherwise provides the leaf node where the value shold be inserted
 107  /// </summary>
 108  /// <param name="value">The value to search</param>
 109  /// <param name="node">The node found</param>
 110  /// <param name="index">The index at which it is found</param>
 111  /// <returns>Returns true if value exists in the tree, otherwise false</returns>
 112  internal bool Search(T value, out Node node, out int index)
 6000113  {
 6000114    index = -1;
 6000115    Node? next = _root;
 116    do
 23564117    {
 23564118      node = next;
 23564119      next = node._children[node._count];
 162984120      for (int i = 0; i < node._count; i++)
 77104121      {
 77104122        CompareResult c = Compare.Invoke(node._values[i], value);
 77104123        if (c is Equal)
 2000124        {
 2000125          index = i;
 2000126          return true;
 127        }
 75104128        else if (c is Greater)
 17176129        {
 17176130          next = node._children[i];
 17176131          break;
 132        }
 57928133      }
 43128134    } while (next is not null);
 4000135    return false;
 6000136  }
 137
 138  /// <inheritdoc />
 139  public bool Contains(T value)
 6000140  {
 6000141    return Search(value, out _, out _);
 6000142  }
 143
 144  /// <summary>
 145  /// Finds the best index at which the insertion can be done and
 146  /// inserts the value at the given index, displacing the values as necessary <br/> <br/>
 147  /// Before using this method, ensure that the node is <br/>
 148  /// 1. A leaf node <br/>
 149  /// 2. Can support adding a value in it, i.e Count is at most MaxDegree-1 after insertion
 150  /// </summary>
 151  /// <param name="value">value to add</param>
 152  /// <param name="node">The node in which the value is to be added</param>
 153  /// <returns>returns true if addition was successful. If a duplicate is found, addition fails and the method returns f
 154  internal (bool Success, Exception? Exception) TryAdd(T value, Node node)
 18422155  {
 18422156    int index = 0;
 18422157    if (node._count > 0)
 18408158    {
 158036159      for (; index < node._count; index++)
 73468160      {
 73468161        CompareResult c = Compare.Invoke(node._values[index], value);
 73468162        if (c is Equal)
 5163        {
 5164          return (false, new ArgumentException($"Adding to add a duplicate value to an {nameof(BTreeLinked<T, TCompare>)
 165        }
 73463166        else if (c is Greater)
 3649167        {
 3649168          break;
 169        }
 69814170      }
 60606171      for (int i = node._count - 1; i >= index; i--)
 11900172      {
 11900173        node._values[i + 1] = node._values[i];
 11900174      }
 18403175    }
 18417176    node._values[index] = value;
 18417177    node._count++;
 18417178    _count++;
 18417179    return (true, default);
 18422180  }
 181
 182  /// <summary>
 183  /// Splits the full node into a node having two child nodes<br/><br/>
 184  /// Before calling this method, ensure that <br/>
 185  /// 1. the node is full <br/>
 186  /// 2. the parent node is Not full (Not applicable for the Root node)
 187  /// </summary>
 188  /// <param name="fullNode">The node to split</param>
 189  internal void Split(Node fullNode)
 6329190  {
 6329191    Node right = new(MaxDegree);
 6329192    Node? parent = fullNode._parent, x;
 12658193    int l = MaxDegree - 1, MedianIndex = l >> 1;
 194    int i;
 195    int j;
 69297196    for (i = MedianIndex + 1, j = 0; i < l; i++, j++)
 16770197    {
 16770198      right._values[j] = fullNode._values[i];
 16770199      fullNode._values[i] = default!;
 16770200    }
 6329201    right._count = (byte)j;
 6329202    if (!fullNode.IsLeaf)
 1791203    {
 23349204      for (i = MedianIndex + 1, j = 0; i <= l; i++, j++)
 5992205      {
 5992206        right._children[j] = x = fullNode._children[i];
 5992207        if (x is not null)
 5992208        {
 5992209          x._parent = right;
 5992210          x._parentIndex = (byte)j;
 5992211        }
 5992212        fullNode._children[i] = null;
 5992213      }
 1791214    }
 6329215    fullNode._count = (byte)MedianIndex;
 6329216    if (parent is null) // 'fullnode' is Root
 43217    {
 43218      _root = new(MaxDegree);
 43219      _root._values[0] = fullNode._values[MedianIndex];
 43220      fullNode._values[MedianIndex] = default!;
 43221      _root._count = 1;
 43222      _root._children[0] = fullNode;
 43223      fullNode._parentIndex = 0;
 43224      _root._children[1] = right;
 43225      right._parentIndex = 1;
 43226      fullNode._parent = right._parent = _root;
 43227    }
 228    else
 6286229    {
 25245230      for (i = parent._count + 1, j = i--; i > fullNode._parentIndex; j--, i--)
 2129231      {
 2129232        parent._children[j] = x = parent._children[i];
 2129233        if (x is not null)
 2129234        {
 2129235          x._parentIndex = (byte)j;
 2129236        }
 2129237      }
 25245238      for (i = parent._count, j = i--; i >= fullNode._parentIndex; j--, i--)
 2129239      {
 2129240        parent._values[j] = parent._values[i];
 2129241      }
 6286242      parent._values[j] = fullNode._values[MedianIndex];
 6286243      fullNode._values[MedianIndex] = default!;
 6286244      parent._children[j] = fullNode;
 6286245      fullNode._parentIndex = (byte)j;
 6286246      parent._children[j + 1] = right;
 6286247      right._parentIndex = (byte)(j + 1);
 6286248      right._parent = parent;
 6286249      parent._count++;
 6286250    }
 6329251  }
 252
 253  /// <inheritdoc />
 254  public (bool Success, Exception? Exception) TryAdd(T value)
 18423255  {
 18423256    if (_root.IsFull)
 43257    {
 43258      Split(_root);
 43259    }
 18423260    Node node = _root;
 261    Node? child;
 98451262    while (!node.IsLeaf)
 80029263    {
 80029264      int i = 0;
 265      CompareResult c;
 362567266      while (i < node._count && (c = Compare.Invoke(node._values[i], value)) is not Greater)
 282539267      {
 282539268        if (c is Equal)
 1269        {
 1270          return (false, new ArgumentException($"Adding to add a duplicate value to an {nameof(BTreeLinked<T, TCompare>)
 271        }
 282538272        i++;
 282538273      }
 80028274      child = node._children[i];
 80028275      if (child is not null && child.IsFull)
 6286276      {
 6286277        Split(child);
 6286278        c = Compare.Invoke(node._values[i], value);
 6286279        switch (c)
 280        {
 826281          case Greater: child = node._children[i];     break;
 11746282          case Less:    child = node._children[i + 1]; break;
 0283          case Equal: return (false, new ArgumentException($"Adding to add a duplicate value to an {nameof(BTreeLinked<T
 284        }
 6286285      }
 80028286      if (child is null)
 0287      {
 0288        return (false, new CorruptedDataStructureException("Expected a non-null internal node, but found a null node"));
 289      }
 80028290      node = child;
 80028291    }
 18422292    return TryAdd(value, node);
 18423293  }
 294
 295  /// <inheritdoc />
 296  public (bool Success, Exception? Exception) TryRemove(T value)
 2425297  {
 2425298    if (_count is 0)
 0299    {
 0300      return (false, new ArgumentException($"Attempting to remove a non-existing entry: {value}.", nameof(value)));
 301    }
 2425302    Node? node = _root;
 303    Node? child;
 2425304    int t = MaxDegree >> 1;
 305    // All nodes (except root) must contain at least this many values
 306    // [value of (t) in Cormen's "Introduction to Algorithms"]
 307    do
 9454308    {
 9454309      int i = 0;
 310      CompareResult c;
 36418311      while (i < node._count && (c = Compare.Invoke(node._values[i], value)) is not Greater)
 29910312      {
 29910313        if (c is Equal)
 2948314        {
 2948315          if (node.IsLeaf) // CASE 1
 2415316          {
 15626317            for (int j = i + 1; j < node._count; j++)
 5398318            {
 5398319              node._values[j - 1] = node._values[j];
 5398320            }
 2415321            node._values[--node._count] = default!;
 2415322            node = null;
 2415323          }
 324          else
 533325          {
 533326            Node? lc = node._children[i];
 533327            Node? rc = node._children[i + 1];
 533328            if (lc is null || rc is null)
 0329            {
 0330              return (false, new CorruptedDataStructureException("Found null children of an internal node!"));
 331            }
 533332            if (lc._count >= t) // CASE 2a
 313333            {
 334              do
 400335              {
 400336                child = lc;
 400337                lc = lc._children[lc._count];
 800338              } while (lc is not null);
 339              // At this point lc is null, child is the rightmost node of subtree preceeding 'value'
 313340              value = node._values[i] = child._values[child._count - 1];
 313341            }
 220342            else if (rc._count >= t) // Case 2b
 127343            {
 344              do
 145345              {
 145346                child = rc;
 145347                rc = rc._children[0];
 290348              } while (rc is not null);
 349              // At this point rc is null, child is the leftmost node of subtree following 'value'
 127350              value = node._values[i++] = child._values[0];
 127351            }
 352            else // Case 2c
 93353            {
 354              int p;
 355              int q;
 93356              int r = lc._count;
 93357              lc._values[lc._count++] = node._values[i];
 936358              for (p = i, q = i + 1; q < node._count; p++, q++)
 219359              {
 219360                node._values[p] = node._values[q];
 219361              }
 93362              node._values[p] = default!;
 936363              for (p = i + 1, q = p + 1; q <= node._count; p++, q++)
 219364              {
 219365                child = node._children[p] = node._children[q];
 219366                if (child is not null)
 219367                {
 219368                  child._parentIndex = (byte)p;
 219369                }
 370                else
 0371                {
 0372                  return (false, new CorruptedDataStructureException("Found null children of an internal node!"));
 373                }
 219374              }
 93375              node._children[p] = null;
 93376              node._count--;
 1623377              for (p = lc._count, q = 0; q < rc._count; p++, q++, lc._count++)
 336378              {
 336379                lc._values[p] = rc._values[q];
 336380                rc._values[q] = default!;
 336381              }
 1566382              for (p = r + 1, q = 0; q <= rc._count; p++, q++)
 429383              {
 429384                child = lc._children[p] = rc._children[q];
 429385                if (child is not null)
 11386                {
 11387                  child._parentIndex = (byte)p;
 11388                  child._parent = lc;
 11389                }
 429390                rc._children[q] = null;
 429391              }
 93392              rc._parent = null; // delete rc from memory ?
 93393              if (node == _root && node._count is 0)
 2394              {
 2395                _root = lc;
 2396                _root._parent = null;
 2397                node._values = default!;
 2398                node._children = default!; // delete node from memory ?
 2399                node = lc;
 2400                i = 0;
 2401                continue;
 402              }
 91403            }
 531404          }
 2946405          break;
 406        }
 26962407        i++;
 26962408      }
 9454409      if (node is null)
 2415410      {
 2415411        break; // 'node' would be null after Case 1
 412      }
 413      else
 7039414      {
 7039415        child = node._children[i]; // 'child' will be null only if 'node' is a Leaf node
 7039416      }
 7039417      if (child is null)
 10418      {
 10419        return (false, new ArgumentException($"Attempting to remove a non-existing entry: {value}.", nameof(value)));
 420      }
 7029421      else if (child._count < t)
 1308422      {
 1308423        Node? lc = i > 0 ? node._children[i - 1] : null;
 1308424        Node? rc = i < node._count ? node._children[i + 1] : null;
 425        int j;
 1308426        if (lc is not null && lc._count >= t) // Case 3a-Left
 678427        {
 6558428          for (j = child._count; j > 0; j--)
 2601429          {
 2601430            child._values[j] = child._values[j - 1];
 2601431          }
 678432          child._count++;
 7914433          for (j = child._count; j > 0; j--)
 3279434          {
 3279435            rc = child._children[j] = child._children[j - 1];
 3279436            if (rc is not null)
 1665437            {
 1665438              rc._parentIndex = (byte)j;
 1665439            }
 3279440          }
 678441          rc = lc._children[lc._count];
 678442          if (rc is not null)
 344443          {
 344444            child._children[0] = rc;
 344445            rc._parent = child;
 344446            rc._parentIndex = 0;
 344447          }
 678448          child._values[0] = node._values[i - 1];
 678449          node._values[i - 1] = lc._values[--lc._count];
 678450          lc._values[lc._count] = default!;
 678451        }
 630452        else if (rc is not null && rc._count >= t) // Case 3a-Right
 330453        {
 330454          child._values[child._count++] = node._values[i];
 330455          node._values[i] = rc._values[0];
 330456          lc = rc._children[0];
 330457          if (lc is not null)
 149458          {
 149459            child._children[child._count] = lc;
 149460            lc._parentIndex = child._count;
 149461            lc._parent = child;
 149462          }
 3662463          for (j = 1; j < rc._count; j++)
 1501464          {
 1501465            rc._values[j - 1] = rc._values[j];
 1501466          }
 4322467          for (j = 1; j <= rc._count; j++)
 1831468          {
 1831469            lc = rc._children[j - 1] = rc._children[j];
 1831470            if (lc is not null)
 747471            {
 747472              lc._parentIndex = (byte)(j - 1);
 747473            }
 1831474          }
 330475          rc._children[rc._count--] = null;
 330476          rc._values[rc._count] = default!;
 330477        }
 478        else
 300479        {
 480          int k;
 300481          if (lc is not null) // Case 3b-Left
 234482          {
 234483            lc._values[lc._count++] = node._values[i - 1];
 4083484            for (j = lc._count, k = 0; k <= child._count; j++, k++)
 1127485            {
 1127486              rc = lc._children[j] = child._children[k];
 1127487              if (rc is not null)
 162488              {
 162489                rc._parentIndex = (byte)j;
 162490                rc._parent = lc;
 162491              }
 1127492            }
 2254493            for (k = 0; k < child._count; k++)
 893494            {
 893495              lc._values[lc._count++] = child._values[k];
 893496            }
 234497            child._values = default!;
 234498            child._children = default!;
 234499            child._parent = null;
 234500            child = lc;
 234501          }
 66502          else if (rc is not null) // Case 3b-Right || PS: can leave it at else {...} but this avoids Null reference war
 66503          {
 66504            child._values[child._count++] = node._values[i];
 1101505            for (j = child._count, k = 0; k <= rc._count; j++, k++)
 301506            {
 301507              lc = child._children[j] = rc._children[k];
 301508              if (lc is not null)
 97509              {
 97510                lc._parentIndex = (byte)j;
 97511                lc._parent = child;
 97512              }
 301513            }
 602514            for (k = 0; k < rc._count; k++)
 235515            {
 235516              child._values[child._count++] = rc._values[k];
 235517            }
 66518            rc._values = default!;
 66519            rc._children = default!;
 66520            rc._parent = null;
 66521          }
 522          else
 0523          {
 0524            return (false, new CorruptedDataStructureException("Found null children of an internal node!"));
 525          }
 2078526          for (k = child._parentIndex + 1; k < node._count; k++)
 739527          {
 739528            node._values[k - 1] = node._values[k];
 739529            lc = node._children[k] = node._children[k + 1];
 739530            if (lc is not null)
 739531            {
 739532              lc._parentIndex = (byte)k;
 739533            }
 739534          }
 300535          node._children[node._count--] = null;
 300536          node._values[node._count] = default!;
 300537          if (node == _root && node._count is 0)
 3538          {
 3539            node._children = null!;
 3540            _root = child;
 3541            _root._parent = null;
 3542            _root._parentIndex = 0;
 3543          }
 300544        }
 1308545      }
 7029546      node = child;
 14058547    } while (node is not null);
 2415548    _count--;
 2415549    return (true, default);
 2425550  }
 551
 552  /// <inheritdoc />
 553  public T[] ToArray()
 6554  {
 6555    if (_count is 0)
 1556    {
 1557      return Array.Empty<T>();
 558    }
 5559    T[] array = new T[_count];
 5560    this.Stepper<T, FillArray<T>>(array);
 5561    return array;
 6562  }
 563
 564  internal static Node LeftmostNode(Node node)
 191565  {
 191566    Node? leftChild = node._children[0];
 239567    while (leftChild is not null)
 48568    {
 48569      node = leftChild;
 48570      leftChild = node._children[0];
 48571    }
 191572    return node;
 191573  }
 574
 575  /// <summary>Given a value's index in a node, returns the node and index of the value which is next to the given value
 576  /// <param name="node">The node in which the current value is contained</param>
 577  /// <param name="index">The index of the value within the node</param>
 578  /// <returns>The node and index of the next value</returns>
 579  internal static (Node? Node, int Index) NextNode(Node node, int index)
 1014580  {
 1014581    index++;
 1014582    Node? p = node._children[index];
 1014583    if (index >= node._count && p is null)
 191584    {
 191585      index = node._parentIndex;
 191586      p = node._parent;
 239587      while (p is not null && index == p._count)
 48588      {
 48589        node = p;
 48590        p = p._parent;
 48591        index = node._parentIndex;
 48592      }
 191593      return (p, index);
 594    }
 823595    else if (p is not null)
 186596    {
 186597      return (LeftmostNode(p), 0);
 598    }
 599    else
 637600    {
 637601      return (node, index);
 602    }
 1014603  }
 604
 605  /// <inheritdoc />
 606  public System.Collections.Generic.IEnumerator<T> GetEnumerator()
 1607  {
 1608    if (_count > 0)
 0609    {
 0610      int index = 0;
 611      Node node;
 0612      Node? nextnode = LeftmostNode(_root);
 613      do
 0614      {
 0615        node = nextnode;
 0616        yield return node._values[index];
 0617        (nextnode, index) = NextNode(node, index);
 0618      } while (nextnode is not null);
 0619    }
 1620    yield break;
 621  }
 622
 0623  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
 624
 625  /// <inheritdoc />
 626  public StepStatus StepperBreak<TStep>(TStep step = default)
 627    where TStep : struct, IFunc<T, StepStatus>
 6628  {
 6629    if (_count is 0)
 1630    {
 1631      return Continue;
 632    }
 5633    return StepperBreak(_root, step);
 6634  }
 635
 636  internal StepStatus StepperBreak<TStep>(Node start, TStep step = default)
 637    where TStep : struct, IFunc<T, StepStatus>
 5638  {
 5639    int index = 0;
 5640    Node? node = LeftmostNode(start);
 641    do
 1014642    {
 1014643      if (step.Invoke(node._values[index]) is Break)
 0644      {
 0645        return Break;
 646      }
 1014647      (node, index) = NextNode(node!, index);
 2028648    } while (node is not null);
 5649    return Continue;
 5650  }
 651
 652  /// <inheritdoc />
 653  public BTreeLinked<T, TCompare> Clone()
 2654  {
 2655    BTreeLinked<T, TCompare> clone = new(_maxDegree, _compare);
 2656    StackLinked<(Node original, Node copy)> stack = new();
 2657    stack.Push((_root, clone._root));
 83658    while (stack._count > 0)
 81659    {
 81660      (Node original, Node copy) = stack.Pop();
 81661      copy._parentIndex = original._parentIndex;
 81662      copy._count = original._count;
 962663      for (int i = 0; i < original._count; i++)
 400664      {
 400665        copy._values[i] = original._values[i];
 400666      }
 81667      if (!original.IsLeaf)
 14668      {
 186669        for (int i = 0; i <= original._count; i++)
 79670        {
 79671          Node c = copy._children[i] = new(MaxDegree);
 79672          c._parent = copy;
 79673          Node? o = original._children[i];
 79674          if (o is null) throw new CorruptedDataStructureException("Found null children of an internal node!");
 79675          stack.Push((o, c));
 79676        }
 14677      }
 81678    }
 2679    clone._count = _count;
 2680    return clone;
 2681  }
 682
 683  #endregion
 684}