// ----------------------------------------------------------------------------- // file="SequenceEmitter" // Project: StgSharp // Copyright (c) Nitload. // SPDX-License-Identifier: MIT // ----------------------------------------------------------------------------- using StgSharp.RegularAnalysis.Text; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace StgSharp.RegularAnalysis.Abstraction { public sealed class SequenceEmitter { private bool _isRoot; private readonly Node _head; private Node _tail; public SequenceEmitter() { _isRoot = true; _head = new(); _tail = _head; } public int Count { get; private set; } public SequenceEmitter Append( T unit ) { if (!_isRoot) { throw new InvalidOperationException("This emitter has been appended to another emitter. It is now readonly."); } _tail.Add(unit); Count++; return this; } public SequenceEmitter Append( SequenceEmitter emitter ) { if (emitter == null || emitter.Count == 0) { return this; } if (ReferenceEquals(this, emitter)) { throw new InvalidOperationException("Cannot append emitter to itself."); } if (!emitter._isRoot) { throw new InvalidOperationException("The emitter has been appended to another emitter."); } _tail.Next = emitter._head; _tail = emitter._tail; Count += emitter.Count; emitter._isRoot = false; return this; } public Enumerator GetEnumerator() { return _isRoot ? new Enumerator(this) : throw new InvalidOperationException("This emitter has been appended to another emitter. You should not get its enumerator."); } public List ToList() { List result = new(Count); Node current = _head; while (current != null) { result.AddRange(current.IRList); current = current.Next!; } return result; } #pragma warning disable CA1063 #pragma warning disable CA1816 public class Enumerator( [NotNull] SequenceEmitter emitter ) : IEnumerator { private int _index = -1; private Node _current = null!; private readonly Node _root = emitter._head; public T Current { get { if (_current is null || _index < 0 || _index >= _current.Count) { throw new InvalidOperationException(); } return _current[_index]; } } public void Dispose() { } public bool MoveNext() { _current ??= _root; int index = _index + 1; if (index < _current.Count) { _index = index; return true; } Node current = _current.Next!; if (current is null || ReferenceEquals(current, _root)) { _index = -1; return false; } _current = current; _index = -1; return true; } public void Reset() { _current = _root; _index = -1; } object IEnumerator.Current => Current!; } #pragma warning restore CA1063 #pragma warning restore CA1816 private sealed class Node { public T this[ int index ] { get => IRList[index]; set => IRList[index] = value; } public Node? Next { get; set; } public int Count => IRList.Count; public List IRList { get; } = []; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add( T ir ) { IRList.Add(ir); } } } }