//----------------------------------------------------------------------- //----------------------------------------------------------------------- // file="PipelineNode.cs" // Project: StgSharp // AuthorGroup: Nitload Space // Copyright (c) Nitload Space. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the “Software”), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and // this permission notice shall be included in all copies // or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED “AS IS”, // WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //----------------------------------------------------------------------- //----------------------------------------------------------------------- using StgSharp.Entities; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; namespace StgSharp.PipeLine { /// /// /// /// /// Reset pipeline has risk, this operation is a direct operation to port in current node, the /// port on the other node cannot get the change. /// #pragma warning disable CA1036 public class PipelineNode #pragma warning restore CA1036 { private static Dictionary _emptyLayer = new(); private static PipelineNode _emptyNode = new PipelineNode( PipelineNodeLabel.Empty, null!, false ); private IConvertableToPipelineNode _mainOperation; private PipelineNodeLabel _label; private protected bool _nativeRequested; private protected Dictionary _input; private protected Dictionary _output; private protected int _level, _count; internal PipelineNode( PipelineNodeLabel label, IConvertableToPipelineNode node, bool isNative ) { _label = label; _nativeRequested = isNative; _mainOperation = node; InputPorts = new(); OutputPorts = new(); foreach( string port in node.InputPortName ) { InputPorts.Add( port, new PipelineNodeInPort( this, port ) ); } foreach( string port in node.OutputPortName ) { OutputPorts.Add( port, new PipelineNodeOutPort( this, port ) ); } } #pragma warning disable CS8618 internal PipelineNode( PipelineNodeOperation operation, PipelineNodeLabel name, bool isNative, string[] inputNames, string[] outputNames ) #pragma warning restore CS8618 { if( ( inputNames == null ) || ( inputNames.Length == 0 ) ) { throw new ArgumentNullException( nameof( inputNames ) ); } if( ( outputNames == null ) || ( outputNames.Length == 0 ) ) { throw new ArgumentNullException( nameof( outputNames ) ); } _label = name; _nativeRequested = isNative; if( operation == null ) { operation = DefaultOperation; } _mainOperation = new DefaultConvertableToBlueprintNode( operation, inputNames, outputNames ); InputPorts = new Dictionary(); OutputPorts = new Dictionary(); foreach( string port in inputNames ) { InputPorts.Add( port, new PipelineNodeInPort( this, port ) ); } foreach( string port in outputNames ) { OutputPorts.Add( port, new PipelineNodeOutPort( this, port ) ); } } public bool IsNative { get => _nativeRequested; internal set => _nativeRequested = value; } public static Dictionary EmptyPortLayer { get => _emptyLayer; } public IConvertableToPipelineNode NodeOperation => _mainOperation; public int Level { get => _level; private set { _level = value; } } public static PipelineNode Empty { get => _emptyNode; } public PipelineNodeLabel Label => _label; internal Dictionary InputPorts { get => _input; private set => _input = value; } internal Dictionary OutputPorts { get => _output; private set => _output = value; } internal HashSet Previous { get; } = new HashSet(); internal HashSet Next { get; } = new HashSet(); internal IConvertableToPipelineNode Value { get => _mainOperation; } internal int RemainingIncreaseCount => Previous.Count - _count; public static void Connect( PipelineNode front, string frontNodePort, string backNodePort, PipelineNode back ) { ArgumentNullException.ThrowIfNull( front ); ArgumentNullException.ThrowIfNull( back ); if( !front.OutputPorts.TryGetValue( frontNodePort, out PipelineNodeOutPort? frontPort ) ) { throw new ArgumentOutOfRangeException( $"Cannot find port named {frontNodePort}" ); } if( !back.InputPorts.TryGetValue( backNodePort, out PipelineNodeInPort? backPort ) ) { throw new ArgumentOutOfRangeException( $"Cannot find port named {backNodePort}" ); } backPort.Connect( frontPort ); frontPort.Connect( backPort ); } public IEnumerator GetFormerNodes() { foreach( PipelineNodeInPort port in InputPorts.Values ) { IEnumerator enumerator = port.GetFormerNodes(); while( enumerator.MoveNext() ) { yield return enumerator.Current; } } } public virtual void Run() { try { //Console.WriteLine(_label); PipelineNodeInPort.WaitAll( InputPorts ); if( _mainOperation != null ) { _mainOperation.NodeMain( in _input, in _output ); } } catch( Exception ) { throw; } } internal bool TryIncreaseLevelTo( int level ) { _count++; if( _count > Previous.Count ) { return false; } Level = int.Max( level, this.Level ); return true; } protected static void DefaultOperation( in Dictionary input, in Dictionary output ) { PipelineNodeOutPort.SkipAll( output ); } #region port operation public PipelineNodeInPort GetInputPort( string lable ) { if( !InputPorts.TryGetValue( lable, out PipelineNodeInPort? ret ) ) { throw new ArgumentOutOfRangeException( $"Cannot find the interface named {lable} in node {Label}." ); } return ret; } public PipelineNodeOutPort GetOutputPort( string lable ) { if( !OutputPorts.TryGetValue( lable, out PipelineNodeOutPort? ret ) ) { throw new ArgumentOutOfRangeException( $"Cannot find the interface named {lable} in node {Label}." ); } return ret; } public PipelineNodeInPort DefineCertainInputPort( string label ) { if( InputPorts.ContainsKey( label ) ) { return null; } PipelineNodeInPort port = new PipelineNodeInPort( this, label ); InputPorts[ label ] = port; return port; } public PipelineNodeOutPort DefineCertainOutputPort( string label ) { if( OutputPorts.ContainsKey( label ) ) { return null; } PipelineNodeOutPort port = new PipelineNodeOutPort( this, label ); OutputPorts[ label ] = port; return port; } #endregion }//--------------------------------- end of class ----------------------------------- public class PipelineNodeRunException : Exception { public PipelineNodeRunException() { } public PipelineNodeRunException( Exception ex ) : base( string.Empty, ex ) { } public PipelineNodeRunException( string message ) : base( message ) { } public PipelineNodeRunException( string message, Exception innerException ) : base( message, innerException ) { } } }