Files
stgsharp/StgSharp.RegularAnalysis/Abstraction/SequenceEmitter.cs
T

178 lines
4.6 KiB
C#

// -----------------------------------------------------------------------------
// 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<T>
{
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<T> 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<T> Append(
SequenceEmitter<T> 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<T> ToList()
{
List<T> 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<T> emitter
) : IEnumerator<T>
{
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<T> IRList { get; } = [];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(
T ir
)
{
IRList.Add(ir);
}
}
}
}