< Summary

Class:Towel.DataStructures.TrieLinkedHashLinked<T1, T2, T3, T4>
Assembly:Towel
File(s):File 1: /home/runner/work/Towel/Towel/Sources/Towel/DataStructures/Trie.cs
Covered lines:0
Uncovered lines:180
Coverable lines:180
Total lines:659
Line coverage:0% (0 of 180)
Covered branches:0
Total branches:56
Branch coverage:0% (0 of 56)

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
File 1: .ctor(...)100%10%
File 1: .ctor(...)100%10%
File 1: .ctor(...)100%10%
File 1: get_Count()100%10%
File 1: get_Equate()100%10%
File 1: get_Hash()100%10%
File 1: TryAdd(...)0%120%
File 1: TryGet(...)0%100%
File 1: TryRemove(...)0%200%
File 1: Contains(...)0%100%
File 1: Clear()100%10%
File 1: StepperBreak(...)100%10%
File 1: System.Collections.IEnumerable.GetEnumerator()100%10%
File 1: GetEnumerator()100%10%
File 1: Clone()100%10%
File 1: ToArray()100%10%

File(s)

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

#LineLine coverage
 1namespace Towel.DataStructures;
 2
 3/// <summary>Extension methods for <see cref="ITrie{T}"/> and <see cref="ITrie{T, D}"/>.</summary>
 4public static class Trie
 5{
 6  #region Extensions Methods
 7
 8  /// <summary>Adds a value.</summary>
 9  /// <typeparam name="T">The type of value.</typeparam>
 10  /// <typeparam name="TData">The type of the data.</typeparam>
 11  /// <param name="trie">The trie to add the value to.</param>
 12  /// <param name="value">The value to be added.</param>
 13  /// <param name="stepper">The keys of the relative value.</param>
 14  public static void Add<T, TData>(this ITrie<T, TData> trie, TData value, Action<Action<T>> stepper)
 15  {
 16    var (success, exception) = trie.TryAdd(value, stepper);
 17    if (!success)
 18    {
 19      throw exception ?? new ArgumentException($"{nameof(Add)} failed but the {nameof(exception)} is null");
 20    }
 21  }
 22
 23  /// <summary>Gets a value.</summary>
 24  /// <typeparam name="T">The type of value.</typeparam>
 25  /// <typeparam name="TData">The type of the data.</typeparam>
 26  /// <param name="trie">The trie to get the value from.</param>
 27  /// <param name="stepper">The keys of the relative value.</param>
 28  /// <returns>The value.</returns>
 29  public static TData Get<T, TData>(this ITrie<T, TData> trie, Action<Action<T>> stepper)
 30  {
 31    var (success, value, exception) = trie.TryGet(stepper);
 32    if (!success)
 33    {
 34      throw exception ?? new ArgumentException($"{nameof(Get)} failed but the {nameof(exception)} is null");
 35    }
 36    return value!;
 37  }
 38
 39  /// <summary>Removes a value.</summary>
 40  /// <typeparam name="T">The type of value.</typeparam>
 41  /// <typeparam name="TData">The type of the data.</typeparam>
 42  /// <param name="trie">The trie to remove the value from.</param>
 43  /// <param name="stepper">The keys to store the value relative to.</param>
 44  public static void Remove<T, TData>(this ITrie<T, TData> trie, Action<Action<T>> stepper)
 45  {
 46    var (success, exception) = trie.TryRemove(stepper);
 47    if (!success)
 48    {
 49      throw exception ?? new ArgumentException($"{nameof(Remove)} failed but the {nameof(exception)} is null");
 50    }
 51  }
 52
 53  #endregion
 54}
 55
 56/// <summary>A trie data structure that allows partial value sharing to reduce redundant memory.</summary>
 57/// <typeparam name="T">The type of values in the trie.</typeparam>
 58public interface ITrie<T> : IDataStructure<Action<Action<T>>>,
 59  DataStructure.ICountable,
 60  DataStructure.IClearable,
 61  DataStructure.IAddable<Action<Action<T>>>,
 62  DataStructure.IRemovable<Action<Action<T>>>,
 63  DataStructure.IAuditable<Action<Action<T>>>
 64{
 65
 66}
 67
 68/// <summary>Static helpers.</summary>
 69public static class TrieLinkedHashLinked
 70{
 71  #region Extension Methods
 72
 73  /// <summary>Constructs a new <see cref="TrieLinkedHashLinked{T, TEquate, THash}"/>.</summary>
 74  /// <typeparam name="T">The type of values stored in this data structure.</typeparam>
 75  /// <param name="equate">The function for comparing <typeparamref name="T"/> values for equality.</param>
 76  /// <param name="hash">The function for hashing <typeparamref name="T"/> values.</param>
 77  /// <returns>The new constructed <see cref="TrieLinkedHashLinked{T, TEquate, THash}"/>.</returns>
 78  public static TrieLinkedHashLinked<T, SFunc<T, T, bool>, SFunc<T, int>> New<T>(
 79    Func<T, T, bool>? equate = null,
 80    Func<T, int>? hash = null) =>
 81    new(equate ?? Equate, hash ?? Hash);
 82
 83  /// <summary>Constructs a new <see cref="TrieLinkedHashLinked{T, D, TEquate, THash}"/>.</summary>
 84  /// <typeparam name="T">The type of values stored in this data structure.</typeparam>
 85  /// <typeparam name="TData">The additional data type to store with each leaf.</typeparam>
 86  /// <param name="equate">The function for comparing <typeparamref name="T"/> values for equality.</param>
 87  /// <param name="hash">The function for hashing <typeparamref name="T"/> values.</param>
 88  /// <returns>The new constructed <see cref="TrieLinkedHashLinked{T, D, TEquate, THash}"/>.</returns>
 89  public static TrieLinkedHashLinked<T, TData, SFunc<T, T, bool>, SFunc<T, int>> New<T, TData>(
 90    Func<T, T, bool>? equate = null,
 91    Func<T, int>? hash = null) =>
 92    new(equate ?? Equate, hash ?? Hash);
 93
 94  #endregion
 95}
 96
 97/// <summary>A trie data structure that allows partial value sharing to reduce redundant memory.</summary>
 98/// <typeparam name="T">The type of values in the trie.</typeparam>
 99/// <typeparam name="TEquate">The type of function for quality checking <typeparamref name="T"/> values.</typeparam>
 100/// <typeparam name="THash">The type of function for hashing <typeparamref name="T"/> values.</typeparam>
 101public class TrieLinkedHashLinked<T, TEquate, THash> : ITrie<T>,
 102  ICloneable<TrieLinkedHashLinked<T, TEquate, THash>>,
 103  DataStructure.IEquating<T, TEquate>,
 104  DataStructure.IHashing<T, THash>
 105  where TEquate : struct, IFunc<T, T, bool>
 106  where THash : struct, IFunc<T, int>
 107{
 108  internal MapHashLinked<Node, T, TEquate, THash> _map;
 109  internal int _count;
 110
 111  #region Nested Types
 112
 113  internal class Node
 114  {
 115    internal MapHashLinked<Node, T, TEquate, THash> Map;
 116    internal bool IsLeaf;
 117    internal int Count;
 118
 119    public Node(MapHashLinked<Node, T, TEquate, THash> map) => Map = map;
 120  }
 121
 122  #endregion
 123
 124  #region Constructors
 125
 126  /// <summary>Constructs a new trie that uses linked hash tables of linked lists.</summary>
 127  /// <param name="equate">The equality delegate for the keys.</param>
 128  /// <param name="hash">The hashing function for the keys.</param>
 129  public TrieLinkedHashLinked(TEquate equate = default, THash hash = default)
 130  {
 131    _count = 0;
 132    _map = new(equate, hash);
 133  }
 134
 135  /// <summary>This constructor is for cloning purposes.</summary>
 136  /// <param name="trie">The trie to clone.</param>
 137  public TrieLinkedHashLinked(TrieLinkedHashLinked<T, TEquate, THash> trie)
 138  {
 139    _count = trie._count;
 140    _map = trie._map.Clone();
 141  }
 142
 143  #endregion
 144
 145  #region Properties
 146
 147  /// <summary>The current count of the trie.</summary>
 148  public int Count => _count;
 149  /// <summary>The equality function of the keys.</summary>
 150  public TEquate Equate => _map.Equate;
 151  /// <summary>The hash fucntion for the keys.</summary>
 152  public THash Hash => _map.Hash;
 153
 154  #endregion
 155
 156  #region Methods
 157
 158  /// <inheritdoc/>
 159  public (bool Success, Exception? Exception) TryAdd(Action<Action<T>> stepper)
 160  {
 161    if (stepper is null)
 162    {
 163      return (false, new ArgumentNullException(nameof(stepper)));
 164    }
 165    IStack<Node> stack = new StackLinked<Node>();
 166    Node? node = null;
 167    stepper(key =>
 168    {
 169      var map = node is null ? _map : node.Map;
 170      if (map.Contains(key))
 171      {
 172        node = map[key];
 173      }
 174      else
 175      {
 176        Node temp = new(map: new(Equate, Hash));
 177        map[key] = temp;
 178        node = temp;
 179      }
 180      stack.Push(node);
 181    });
 182    if (node is null)
 183    {
 184      return (false, new ArgumentException("Stepper was empty.", nameof(stepper)));
 185    }
 186    else if (node.IsLeaf)
 187    {
 188      return (false, new ArgumentException("Attempted to add an already existing item.", nameof(stepper)));
 189    }
 190    else
 191    {
 192      node.IsLeaf = true;
 193      stack.Stepper(n => n.Count++);
 194      _count++;
 195      return (true, null);
 196    }
 197  }
 198
 199  /// <inheritdoc/>
 200  public (bool Success, Exception? Exception) TryRemove(Action<Action<T>> stepper)
 201  {
 202    if (stepper is null)
 203    {
 204      return (false, new ArgumentNullException(nameof(stepper)));
 205    }
 206    StackLinked<(T, MapHashLinked<Node, T, TEquate, THash>, Node)> stack = new();
 207    T finalKey;
 208    MapHashLinked<Node, T, TEquate, THash>? finalMap = null;
 209    Node? node = null;
 210    Exception? exception = null;
 211    stepper(key =>
 212    {
 213      finalKey = key;
 214      finalMap = node is null ? _map : node.Map;
 215      if (finalMap.Contains(key))
 216      {
 217        node = finalMap[key];
 218      }
 219      else
 220      {
 221        exception ??= new ArgumentException("Attempted to remove a non-existing item.", nameof(stepper));
 222      }
 223      stack.Push((finalKey, finalMap, node!));
 224    });
 225    if (exception is not null)
 226    {
 227      return (false, exception);
 228    }
 229    else if (node is null)
 230    {
 231      return (false, new ArgumentException("Stepper was empty.", nameof(stepper)));
 232    }
 233    else if (!node.IsLeaf)
 234    {
 235      return (false, new ArgumentException("Attempted to remove a non-existing item.", nameof(stepper)));
 236    }
 237    else
 238    {
 239      bool remove = true;
 240      while (stack.Count > 0)
 241      {
 242        var (k, m, n) = stack.Pop();
 243        n.Count--;
 244        if (remove && n.Count is 0)
 245        {
 246          m.Remove(k);
 247        }
 248        else
 249        {
 250          remove = false;
 251        }
 252      }
 253      _count--;
 254      return (true, null);
 255    }
 256  }
 257
 258  /// <inheritdoc/>
 259  public bool Contains(Action<Action<T>> stepper)
 260  {
 261    if (stepper is null) throw new ArgumentNullException(nameof(stepper));
 262    Node? node = null;
 263    bool contains = true;
 264    stepper(key =>
 265    {
 266      if (!contains)
 267      {
 268        return;
 269      }
 270      else
 271      {
 272        var map = node is null ? _map : node.Map;
 273        if (map.Contains(key))
 274        {
 275          node = map[key];
 276        }
 277        else
 278        {
 279          contains = false;
 280        }
 281      }
 282    });
 283    if (node is null)
 284    {
 285      throw new ArgumentException("Stepper was empty.", nameof(stepper));
 286    }
 287    return node.IsLeaf;
 288  }
 289
 290  /// <inheritdoc/>
 291  public void Clear()
 292  {
 293    _count = 0;
 294    _map.Clear();
 295  }
 296
 297  /// <inheritdoc/>
 298  public StepStatus StepperBreak<TStep>(TStep step = default)
 299    where TStep : struct, IFunc<Action<Action<T>>, StepStatus>
 300  {
 301    StepStatus Stepper(Node node, Action<Action<T>> stepper)
 302    {
 303      if (node.IsLeaf)
 304      {
 305        if (step.Invoke(stepper) is Break)
 306        {
 307          return Break;
 308        }
 309      }
 310      return node.Map.PairsBreak(pair =>
 311        Stepper(pair.Value, x => { stepper(x); x(pair.Key); }) is Break
 312          ? Break
 313          : Continue);
 314    }
 315    return _map.PairsBreak(pair => Stepper(pair.Value, x => x(pair.Key)));
 316  }
 317
 318  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
 319
 320  /// <inheritdoc/>
 321  public System.Collections.Generic.IEnumerator<Action<Action<T>>> GetEnumerator()
 322  {
 323#warning TODO: optimize
 324    IList<Action<Action<T>>> list = new ListLinked<Action<Action<T>>>();
 325    this.Stepper(x => list.Add(x));
 326    return list.GetEnumerator();
 327  }
 328
 329  /// <inheritdoc/>
 330  public TrieLinkedHashLinked<T, TEquate, THash> Clone() => new(this);
 331
 332  /// <inheritdoc/>
 333  public Action<Action<T>>[] ToArray()
 334  {
 335#warning TODO: optimize
 336    Action<Action<T>>[] array = new Action<Action<T>>[_count];
 337    int i = 0;
 338    this.Stepper(x => array[i++] = x);
 339    return array;
 340  }
 341
 342  #endregion
 343}
 344
 345/// <summary>A trie data structure that allows partial value sharing to reduce redundant memory.</summary>
 346/// <typeparam name="T">The type of values in the trie.</typeparam>
 347/// <typeparam name="TData">The additional data type to store with each leaf.</typeparam>
 348public interface ITrie<T, TData> : IDataStructure<(Action<Action<T>>, TData)>,
 349  DataStructure.ICountable,
 350  DataStructure.IClearable,
 351  DataStructure.IAuditable<Action<Action<T>>>
 352{
 353  #region Methods
 354
 355  /// <summary>Tries to add a value to the trie.</summary>
 356  /// <param name="value">The value to add.</param>
 357  /// <param name="stepper">The relative keys of the value.</param>
 358  /// <returns>True if the value was added or false if not.</returns>
 359  (bool Success, Exception? Exception) TryAdd(TData value, Action<Action<T>> stepper);
 360
 361  /// <summary>Tries to get a value.</summary>
 362  /// <param name="stepper">The relative keys of the value.</param>
 363  /// <returns>True if the remove was successful or false if not.</returns>
 364  (bool Success, TData? Value, Exception? Exception) TryGet(Action<Action<T>> stepper);
 365
 366  /// <summary>Tries to remove a value.</summary>
 367  /// <param name="stepper">The relative keys of the value.</param>
 368  /// <returns>True if the remove was successful or false if not.</returns>
 369  (bool Success, Exception? Exception) TryRemove(Action<Action<T>> stepper);
 370
 371  #endregion
 372}
 373
 374/// <summary>A trie data structure that allows partial value sharing to reduce redundant memory.</summary>
 375/// <typeparam name="T">The type of values in the trie.</typeparam>
 376/// <typeparam name="TData">The additional data type to store with each leaf.</typeparam>
 377/// <typeparam name="TEquate">The type of function for quality checking <typeparamref name="T"/> values.</typeparam>
 378/// <typeparam name="THash">The type of function for hashing <typeparamref name="T"/> values.</typeparam>
 379public class TrieLinkedHashLinked<T, TData, TEquate, THash> : ITrie<T, TData>,
 380  ICloneable<TrieLinkedHashLinked<T, TData, TEquate, THash>>,
 381  DataStructure.ICountable,
 382  DataStructure.IClearable,
 383  DataStructure.IEquating<T, TEquate>,
 384  DataStructure.IHashing<T, THash>
 385  where TEquate : struct, IFunc<T, T, bool>
 386  where THash : struct, IFunc<T, int>
 387{
 388  internal MapHashLinked<Node, T, TEquate, THash> _map;
 389  internal int _count;
 390
 391  #region Nested Types
 392
 393  internal class Node
 394  {
 395    internal MapHashLinked<Node, T, TEquate, THash> Map;
 396    internal TData? Value;
 397    internal bool HasValue;
 398    internal int Count;
 399
 0400    public Node(MapHashLinked<Node, T, TEquate, THash> map) => Map = map;
 401  }
 402
 403  #endregion
 404
 405  #region Constructors
 406
 407  /// <summary>Constructs a new trie that uses linked hash tables of linked lists.</summary>
 408  /// <param name="equate">The equality delegate for the keys.</param>
 409  /// <param name="hash">The hashing function for the keys.</param>
 0410  public TrieLinkedHashLinked(TEquate equate = default, THash hash = default)
 0411  {
 0412    _count = 0;
 0413    _map = new(equate, hash);
 0414  }
 415
 416  /// <summary>This constructor is for cloning purposes.</summary>
 417  /// <param name="trie">The trie to clone.</param>
 0418  public TrieLinkedHashLinked(TrieLinkedHashLinked<T, TData, TEquate, THash> trie)
 0419  {
 0420    _count = trie._count;
 0421    _map = trie._map.Clone();
 0422  }
 423
 424  #endregion
 425
 426  #region Properties
 427
 428  /// <summary>The current count of the trie.</summary>
 0429  public int Count => _count;
 430  /// <summary>The equality function of the keys.</summary>
 0431  public TEquate Equate => _map.Equate;
 432  /// <summary>The hash fucntion for the keys.</summary>
 0433  public THash Hash => _map.Hash;
 434
 435  #endregion
 436
 437  #region Methods
 438
 439  /// <inheritdoc/>
 440  public (bool Success, Exception? Exception) TryAdd(TData value, Action<Action<T>> stepper)
 0441  {
 0442    if (stepper is null)
 0443    {
 0444      return (false, new ArgumentNullException(nameof(stepper)));
 445    }
 0446    StackLinked<Node> stack = new();
 0447    Node? node = null;
 0448    stepper(key =>
 0449    {
 0450      var map = node is null ? _map : node.Map;
 0451      if (map.Contains(key))
 0452      {
 0453        node = map[key];
 0454      }
 0455      else
 0456      {
 0457        Node temp = new(map: new(Equate, Hash));
 0458        map[key] = temp;
 0459        node = temp;
 0460      }
 0461      stack.Push(node);
 0462    });
 0463    if (node is null)
 0464    {
 0465      return (false, new ArgumentException("Stepper was empty.", nameof(stepper)));
 466    }
 0467    else if (node.HasValue)
 0468    {
 0469      return (false, new ArgumentException("Attempted to add an already existing item.", nameof(stepper)));
 470    }
 471    else
 0472    {
 0473      node.Value = value;
 0474      node.HasValue = true;
 0475      stack.Stepper(n => n.Count++);
 0476      _count++;
 0477      return (true, null);
 478    }
 0479  }
 480
 481  /// <inheritdoc/>
 482  public (bool Success, TData? Value, Exception? Exception) TryGet(Action<Action<T>> stepper)
 0483  {
 0484    if (stepper is null)
 0485    {
 0486      return (false, default, new ArgumentNullException(nameof(stepper)));
 487    }
 0488    Node? node = null;
 0489    stepper(key =>
 0490    {
 0491      var map = node is null ? _map : node.Map;
 0492      if (map.Contains(key))
 0493      {
 0494        node = map[key];
 0495      }
 0496      else
 0497      {
 0498        Node temp = new(map: new(Equate, Hash));
 0499        map[key] = temp;
 0500        node = temp;
 0501      }
 0502    });
 0503    if (node is null)
 0504    {
 0505      return (false, default, new ArgumentException("Stepper was empty.", nameof(stepper)));
 506    }
 0507    else if (!node.HasValue)
 0508    {
 0509      return (false, default, new ArgumentException("Attempted to get a non-existing item.", nameof(stepper)));
 510    }
 511    else
 0512    {
 0513      return (true, node.Value, null);
 514    }
 0515  }
 516
 517  /// <inheritdoc/>
 518  public (bool Success, Exception? Exception) TryRemove(Action<Action<T>> stepper)
 0519  {
 0520    if (stepper is null)
 0521    {
 0522      return (false, new ArgumentNullException(nameof(stepper)));
 523    }
 0524    StackLinked<(T, MapHashLinked<Node, T, TEquate, THash>, Node)> stack = new();
 525    T finalKey;
 526    MapHashLinked<Node, T, TEquate, THash> finalMap;
 0527    Node? node = null;
 0528    Exception? capturedException = null;
 0529    stepper(key =>
 0530    {
 0531      finalKey = key;
 0532      finalMap = node is null ? _map : node.Map;
 0533      if (finalMap.Contains(key))
 0534      {
 0535        node = finalMap[key];
 0536      }
 0537      else
 0538      {
 0539        capturedException ??= new ArgumentException("Attempted to remove a non-existing item.", nameof(stepper));
 0540      }
 0541      stack.Push((finalKey, finalMap, node!));
 0542    });
 0543    if (capturedException is not null)
 0544    {
 0545      return (false, capturedException);
 546    }
 0547    else if (node is null)
 0548    {
 0549      return (false, new ArgumentException("Stepper was empty.", nameof(stepper)));
 550    }
 0551    else if (!node.HasValue)
 0552    {
 0553      return (false, new ArgumentException("Attempted to remove a non-existing item.", nameof(stepper)));
 554    }
 555    else
 0556    {
 0557      bool remove = true;
 0558      while (stack.Count > 0)
 0559      {
 0560        var (k, m, n) = stack.Pop();
 0561        n.Count--;
 0562        if (remove && n.Count is 0)
 0563        {
 0564          m.Remove(k);
 0565        }
 566        else
 0567        {
 0568          remove = false;
 0569        }
 0570      }
 0571      _count--;
 0572      return (true, null);
 573    }
 0574  }
 575
 576  /// <inheritdoc/>
 577  public bool Contains(Action<Action<T>> stepper)
 0578  {
 0579    if (stepper is null) throw new ArgumentNullException(nameof(stepper));
 0580    Node? node = null;
 0581    bool contains = true;
 0582    stepper(key =>
 0583    {
 0584      if (!contains)
 0585      {
 0586        return;
 0587      }
 0588      else
 0589      {
 0590        var map = node is null ? _map : node.Map;
 0591        if (map.Contains(key))
 0592        {
 0593          node = map[key];
 0594        }
 0595        else
 0596        {
 0597          contains = false;
 0598        }
 0599      }
 0600    });
 0601    if (node is null)
 0602    {
 0603      throw new ArgumentException("Stepper was empty.", nameof(stepper));
 604    }
 0605    return node.HasValue;
 0606  }
 607
 608  /// <inheritdoc/>
 609  public void Clear()
 0610  {
 0611    _count = 0;
 0612    _map.Clear();
 0613  }
 614
 615  /// <inheritdoc/>
 616  public StepStatus StepperBreak<TStep>(TStep step = default)
 617    where TStep : struct, IFunc<(Action<Action<T>>, TData), StepStatus>
 0618  {
 619    StepStatus Stepper(Node node, Action<Action<T>> stepper)
 0620    {
 0621      if (node.HasValue)
 0622      {
 0623        if (step.Invoke((stepper, node.Value!)) is Break)
 0624        {
 0625          return Break;
 626        }
 0627      }
 0628      return node.Map.PairsBreak(pair => Stepper(pair.Value, x => { stepper(x); x(pair.Key); }));
 0629    }
 0630    return _map.PairsBreak(pair => Stepper(pair.Value, x => x(pair.Key)));
 0631  }
 632
 633  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() =>
 0634    GetEnumerator();
 635
 636  /// <inheritdoc/>
 637  public System.Collections.Generic.IEnumerator<(Action<Action<T>>, TData)> GetEnumerator()
 0638  {
 639#warning TODO: optimize
 0640    IList<(Action<Action<T>>, TData)> list = new ListLinked<(Action<Action<T>>, TData)>();
 0641    this.Stepper(x => list.Add(x));
 0642    return list.GetEnumerator();
 0643  }
 644
 645  /// <inheritdoc/>
 0646  public TrieLinkedHashLinked<T, TData, TEquate, THash> Clone() => new(this);
 647
 648  /// <inheritdoc/>
 649  public (Action<Action<T>>, TData)[] ToArray()
 0650  {
 651#warning TODO: optimize
 0652    (Action<Action<T>>, TData)[] array = new (Action<Action<T>>, TData)[_count];
 0653    int i = 0;
 0654    this.Stepper(x => array[i++] = x);
 0655    return array;
 0656  }
 657
 658  #endregion
 659}