Loading [MathJax]/extensions/tex2jax.js
Radium Engine  1.5.29
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GraphNodes.hpp
1#pragma once
2
3#include <Dataflow/RaDataflow.hpp>
4
5#include <Dataflow/Core/Node.hpp>
6
7#include <Core/Types.hpp>
8
9#include <functional>
10
11namespace Ra {
12namespace Dataflow {
13namespace Core {
14
15#define BASIC_NODE_INIT( TYPE, BASE ) \
16 public: \
17 explicit TYPE( const std::string& name ) : TYPE( name, TYPE::node_typename() ) {} \
18 static const std::string& node_typename() { \
19 static std::string demangledName = #TYPE; \
20 return demangledName; \
21 } \
22 TYPE( const std::string& instanceName, const std::string& typeName ) : \
23 BASE( instanceName, typeName )
24
25class RA_DATAFLOW_CORE_API GraphNode : public Node
26{
27 BASIC_NODE_INIT( GraphNode, Node ) {}
28
29 public:
30 bool execute() override {
31 CORE_ASSERT( m_inputs.size() == m_outputs.size(),
32 "GraphNode input and output size differ" );
33
34 for ( size_t i = 0; i < m_inputs.size(); ++i ) {
35 auto factory = PortFactory::getInstance();
36 auto output_setter = factory->output_setter( m_outputs[i]->type() );
37 auto input_getter = factory->input_getter( m_inputs[i]->type() );
38 output_setter( m_outputs[i].get(), input_getter( m_inputs[i].get() ) );
39 }
40 return true;
41 }
42
43 void remove_unlinked_ports() {
44 CORE_ASSERT( m_inputs.size() == m_outputs.size(),
45 "GraphNode input and output size differ" );
46
47 int last_index = m_inputs.size();
48 for ( int i = 0; i < last_index; ++i ) {
49 if ( !m_inputs[i]->is_linked() && m_outputs[i]->link_count() == 0 ) {
50 std::swap( m_inputs[i], m_inputs[last_index - 1] );
51 std::swap( m_outputs[i], m_outputs[last_index - 1] );
52 --last_index;
53 --i;
54 }
55 }
56 m_inputs.erase( m_inputs.begin() + last_index, m_inputs.end() );
57 m_outputs.erase( m_outputs.begin() + last_index, m_outputs.end() );
58 }
59
60 void set_graph( Node* node ) { m_graph = node; }
61 Node* graph() const { return m_graph; }
62
63 protected:
64 auto add_ports( PortBaseRawPtr port ) {
65 auto factory = PortFactory::getInstance();
66 auto in_name = find_available_name( "in", port->name() );
67 auto in = factory->make_input_port( this, in_name, port->type() );
68 auto out_name = find_available_name( "out", port->name() );
69 auto out = factory->make_output_port( this, out_name, port->type() );
70 if ( in && out ) {
71 auto input_idx = add_input( in );
72 auto output_idx = add_output( out );
73 return std::make_tuple( input_idx, output_idx, in, out );
74 }
75 return std::make_tuple( PortIndex {}, PortIndex {}, in, out );
76 }
77
78 auto find_available_name( const std::string& type, const std::string& name ) -> std::string {
79 int suffix = 1;
80 std::string new_name = name;
81 while ( port_by_name( type, new_name ).first.isValid() ) {
82 new_name = name + "_" + std::to_string( suffix++ );
83 }
84 return new_name;
85 }
86
87 template <typename T>
88 void make_port_helper(
89 const nlohmann::json& ports,
90 std::map<size_t, T>& port_map,
91 std::function<T( Node* node, const std::string& name, std::string type )> ctor ) {
92 for ( const auto& port : ports ) {
93 size_t index = port["port_index"];
94 std::string type = port["type"];
95 std::string name = port["name"];
96 port_map[index] = ctor( this, name, type );
97 }
98 }
99
100 bool fromJsonInternal( const nlohmann::json& data ) override {
101 auto factory = PortFactory::getInstance();
104 using namespace std::placeholders;
105 if ( const auto& ports = data.find( "inputs" ); ports != data.end() ) {
106 auto ctor = std::bind( &PortFactory::make_input_port_from_name, factory, _1, _2, _3 );
107 make_port_helper<PortBaseInPtr>( *ports, inputs, ctor );
108 }
109 if ( const auto& ports = data.find( "outputs" ); ports != data.end() ) {
110 auto ctor = std::bind( &PortFactory::make_output_port_from_name, factory, _1, _2, _3 );
111 make_port_helper<PortBaseOutPtr>( *ports, outputs, ctor );
112 }
113
114 m_inputs.clear();
115 m_outputs.clear();
116 for ( const auto& [key, value] : inputs ) {
117 assert( m_inputs.size() == key );
118 m_inputs.push_back( value );
119 }
120 for ( const auto& [key, value] : outputs ) {
121 assert( m_outputs.size() == key );
122 m_outputs.push_back( value );
123 }
124 CORE_ASSERT( m_inputs.size() == m_outputs.size(),
125 "json do not contains same number of inputs and outputs for GraphNode" );
126
127 return true;
128 }
129
130 private:
131 Node* m_graph { nullptr };
132};
133
134class RA_DATAFLOW_CORE_API GraphInputNode : public GraphNode
135{
136 BASIC_NODE_INIT( GraphInputNode, GraphNode ) {}
137
138 public:
139 PortIndex add_output_port( PortBaseInRawPtr port ) {
140 auto [input_idx, output_idx, in, out] = add_ports( port );
141 if ( in && out ) port->connect( out.get() );
142 return input_idx;
143 }
144};
145
146class RA_DATAFLOW_CORE_API GraphOutputNode : public GraphNode
147{
148 BASIC_NODE_INIT( GraphOutputNode, GraphNode ) {}
149
150 public:
151 PortIndex add_input_port( PortBaseOutRawPtr port ) {
152 auto [input_idx, output_idx, in, out] = add_ports( port );
153 if ( in && out ) in->connect( port );
154 return output_idx;
155 }
156};
157} // namespace Core
158} // namespace Dataflow
159} // namespace Ra
T bind(T... args)
T make_tuple(T... args)
auto factory(const NodeFactorySet::key_type &name) -> NodeFactorySet::mapped_type
Gets the given factory from the manager.
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:4
T swap(T... args)
T to_string(T... args)