source: finroc_plugins_composite_ports/tInterfaceBase.cpp @ 38:925ca77b7361

tip
Last change on this file since 38:925ca77b7361 was 38:925ca77b7361, checked in by Max Reichardt <mreichardt@…>, 6 months ago

Fixes connect option processing for child connectors (issue introduced in recent changeset ea39cd84ad73)

File size: 45.7 KB
Line 
1//
2// You received this file as part of Finroc
3// A framework for intelligent robot control
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    plugins/composite_ports/tInterfaceBase.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2020-01-14
27 *
28 */
29//----------------------------------------------------------------------
30#include "plugins/composite_ports/tInterfaceBase.h"
31
32//----------------------------------------------------------------------
33// External includes (system with <>, local with "")
34//----------------------------------------------------------------------
35#include "core/tFrameworkElementTags.h"
36#include "core/tRuntimeEnvironment.h"
37#include "rrlib/util/string.h"
38#include "rrlib/rtti_conversion/tStaticCastOperation.h"
39
40//----------------------------------------------------------------------
41// Internal includes with ""
42//----------------------------------------------------------------------
43#include "plugins/composite_ports/internal/tInterfaceTypeInfo.h"
44#include "plugins/composite_ports/internal/type_traits.h"
45#include "plugins/composite_ports/defined_conversions.h"
46#include "plugins/composite_ports/tInterfaceModifier.h"
47#include "plugins/composite_ports/interface_types.h"
48#include "plugins/composite_ports/internal/tPortSelectConversionOperation.h"
49#include "plugins/composite_ports/utils/tPortSelector.h"
50
51//----------------------------------------------------------------------
52// Debugging
53//----------------------------------------------------------------------
54#include <cassert>
55
56//----------------------------------------------------------------------
57// Namespace usage
58//----------------------------------------------------------------------
59
60//----------------------------------------------------------------------
61// Namespace declaration
62//----------------------------------------------------------------------
63namespace finroc
64{
65namespace composite_ports
66{
67
68//----------------------------------------------------------------------
69// Forward declarations / typedefs / enums
70//----------------------------------------------------------------------
71typedef core::tFrameworkElementFlag tFlag;
72
73//----------------------------------------------------------------------
74// Const values
75//----------------------------------------------------------------------
76const std::string cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION = "finroc.composite_ports.single_backend_instantiation";
77
78//----------------------------------------------------------------------
79// Implementation
80//----------------------------------------------------------------------
81
82namespace
83{
84
85const tInterfaceModifier::tImplementation cMODIFIER_DEFAULT_IMPLEMENTATION;
86
87const core::tFrameworkElement* GetAggregator(const core::tFrameworkElement& element, core::tFrameworkElementFlags* extend_with_default_ports_flags = nullptr)
88{
89  if (element.GetFlag(tFlag::EDGE_AGGREGATOR) && (!element.IsPort()))
90  {
91    if (element.GetFlag(tFlag::INTERFACE) && extend_with_default_ports_flags)
92    {
93      (*extend_with_default_ports_flags) |= static_cast<const core::tPortGroup&>(element).GetDefaultPortFlags();
94      if (element.GetFlag(tFlag::SENSOR_DATA))
95      {
96        (*extend_with_default_ports_flags) |= tFlag::SENSOR_DATA;
97      }
98      if (element.GetFlag(tFlag::CONTROLLER_DATA))
99      {
100        (*extend_with_default_ports_flags) |= tFlag::CONTROLLER_DATA;
101      }
102      if (element.GetFlag(tFlag::INTERFACE_FOR_INPUTS) || element.GetFlag(tFlag::PARAMETER_INTERFACE))
103      {
104        (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_INPUT_PORT_FLAGS;
105      }
106      if (element.GetFlag(tFlag::INTERFACE_FOR_OUTPUTS))
107      {
108        (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_OUTPUT_PORT_FLAGS;
109      }
110      if (element.GetFlag(tFlag::PROXY_INTERFACE))
111      {
112        (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA;
113      }
114      if (element.GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
115      {
116        (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA;
117      }
118    }
119    return &element;
120  }
121  return element.GetParent() ? GetAggregator(*element.GetParent(), extend_with_default_ports_flags) : nullptr;
122}
123
124tInterfaceModifier* GetModifier(const core::tFrameworkElement& any_element)
125{
126  auto current_element = &any_element;
127  do
128  {
129    auto annotation = current_element->GetAnnotation<tInterfaceModifier>();
130    if (annotation)
131    {
132      return annotation;
133    }
134    current_element = current_element->GetParent();
135  }
136  while (current_element);
137  return nullptr;
138}
139
140tInterfaceBase::tPrimaryPortType ModifierDefinesPartialInterface(const core::tFrameworkElement& parent, const rrlib::rtti::tType& interface_type)
141{
142  tInterfaceModifier* modifier = GetModifier(parent);
143  if (modifier)
144  {
145    return modifier->Implementation().PartialInterface(interface_type);
146  }
147  return tInterfaceBase::tPrimaryPortType::ANY;
148}
149
150core::tAbstractPortCreationInfo MakeCreationInfo(const rrlib::rtti::tType& interface_type, const std::string& name, core::tFrameworkElement& parent_interface, bool partial_interface, bool shared)
151{
152  core::tAbstractPortCreationInfo result;
153  result.data_type = interface_type;
154  if (partial_interface)
155  {
156    auto partial_type = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo()).GetPartialType();
157    result.data_type = partial_type ? partial_type : result.data_type;
158  }
159  result.parent = &parent_interface;
160  result.flags |= tFlag::INTERFACE;
161  GetAggregator(parent_interface, &result.flags);
162  result.name = name;
163  assert(result.flags.Get(tFlag::EMITS_DATA) || result.flags.Get(tFlag::ACCEPTS_DATA));
164  if (shared)
165  {
166    result.flags |= tFlag::SHARED_PORT;
167  }
168  return result;
169}
170
171void FindInterfacesBelowImplementation(std::vector<tInterfaceBase>& result, core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces)
172{
173  for (auto it = parent.ChildrenBegin(); it != parent.ChildrenEnd(); ++it)
174  {
175    bool is_backend = typeid(*it) == typeid(tInterfaceBase::tBackend);
176    if (is_backend)
177    {
178      tInterfaceBase::tBackend& candidate = static_cast<tInterfaceBase::tBackend&>(*it);
179      if (candidate.IsPrimaryBackend() && (candidate.GetDataType() == type || ((!skip_derived_interfaces) && rrlib::rtti::conversion::tStaticCastOperation::IsImplicitlyConvertibleTo(candidate.GetDataType(), type))))
180      {
181        result.emplace_back(&candidate);
182        continue;
183      }
184    }
185    if ((!it->IsPort()) || is_backend)
186    {
187      FindInterfacesBelowImplementation(result, *it, type, skip_derived_interfaces);
188    }
189  }
190}
191
192//! Connector with operations for custom connecting attached
193const core::tConnectionFlags cRETAIN_FLAGS_FOR_CHILD_CONNECTIONS = core::tConnectionFlag::SCHEDULING_NEUTRAL | core::tConnectionFlag::DIRECTION_TO_SOURCE | core::tConnectionFlag::DIRECTION_TO_DESTINATION;
194
195class tConversionConnector : public core::tConnector
196{
197
198//----------------------------------------------------------------------
199// Public methods and typedefs
200//----------------------------------------------------------------------
201public:
202
203  tConversionConnector(core::tAbstractPort& source_port, core::tAbstractPort& destination_port, const core::tConnectOptions& connect_options) :
204    tConnector(source_port, destination_port, connect_options, this->connect_options.conversion_operations),
205    connect_options(connect_options),
206    original_flags(connect_options.flags.Raw() & cRETAIN_FLAGS_FOR_CHILD_CONNECTIONS.Raw())
207  {}
208
209  const core::tConnectOptions& ChildConnectOptions() const
210  {
211    connect_options.flags = original_flags;
212    return connect_options;
213  }
214
215  const core::tConnectOptions& ChildConnectOptions(const core::tConnectionFlag direction_flag) const
216  {
217    connect_options.flags = original_flags;
218    connect_options.flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, direction_flag == core::tConnectionFlag::DIRECTION_TO_SOURCE);
219    connect_options.flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, direction_flag == core::tConnectionFlag::DIRECTION_TO_DESTINATION);
220    return connect_options;
221  }
222
223//----------------------------------------------------------------------
224// Private fields and methods
225//----------------------------------------------------------------------
226private:
227
228  /*!
229   * Applied connect operations
230   * Notably, the flags are only accessed within this file (with runtime structure lock).
231   * Therefore, they can be temporarily modified (avoiding all the overhead for copying options)
232   */
233  mutable core::tConnectOptions connect_options;
234  const core::tConnectionFlags original_flags;
235
236};
237
238bool CompiledConnectOptions(const rrlib::rtti::conversion::tConversionOperationSequence& options)
239{
240  bool raw = (options.Size() >= 1 && ((!options[0].second) || (options[0].second->Parameter() && options.GetParameterValue(0).GetType() != options[0].second->Parameter().GetType()))) ||
241             (options.Size() >= 2 && ((!options[1].second) || (options[1].second->Parameter() && options.GetParameterValue(1).GetType() != options[1].second->Parameter().GetType())));
242  return !raw;
243}
244
245}
246
247void tInterfaceBase::operator()(core::tAbstractPortCreationInfo& creation_info) const
248{
249  if ((!Backend()) || (Backend() && Backend()->convenience_port_type))
250  {
251    creation_info.flags |= tFlag::READY; // tComponent::cNO_PORT_NAME_BUILDER;
252  }
253  if (!Backend())
254  {
255    creation_info.flags |= tFlag::DELETED;
256    return;
257  }
258
259  creation_info.parent = &Backend()->primary_backend;
260
261  auto aggregator = GetAggregator(*creation_info.parent);
262  if (aggregator && aggregator->GetFlag(tFlag::INTERFACE))
263  {
264    creation_info.flags |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags();
265  }
266  const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw();
267  creation_info.flags |= core::tFrameworkElementFlags(creation_info.parent->GetAllFlags().Raw() & cRELEVANT_FLAGS);
268
269  if (Backend()->primary_backend.IsPartialInterface() && Backend()->primary_backend.PrimaryPortType() != tPrimaryPortType::ANY && Backend()->primary_backend.relation_backend_mapping.front().second == nullptr)
270  {
271    creation_info.flags |= tFlag::DELETED;
272  }
273  else if (creation_info.parent)
274  {
275    auto modifier = GetModifier(*creation_info.parent);
276    if (modifier)
277    {
278      modifier->Implementation().AdjustPortCreationInfo(creation_info);
279    }
280  }
281
282  return;
283}
284
285core::tConnector* tInterfaceBase::ConnectTo(const tInterfaceBase& partner, const core::tConnectOptions& connect_options)
286{
287  if (Backend() && partner.Backend())
288  {
289    for (auto this_backend : Backend()->relation_backend_mapping)
290    {
291      for (auto other_backend : partner.Backend()->primary_backend.relation_backend_mapping)
292      {
293        if (this_backend.second && other_backend.second && this_backend.first - Backend()->primary_relation_id == other_backend.first - partner.Backend()->primary_relation_id)
294        {
295          return this_backend.second->ConnectTo(*other_backend.second, connect_options);
296        }
297      }
298    }
299  }
300  return nullptr;
301}
302
303tInterfaceBase::tBackend* tInterfaceBase::CreateBackend(rrlib::rtti::tType interface_type, tInterfaceBase* parent, const std::string& name, tPrimaryPortType primary_port_type, const tConnectFunction& custom_connect_function, int primary_relation_id, bool convience_port_type)
304{
305  assert(parent);
306  if (parent->Backend() == nullptr)
307  {
308    return nullptr;
309  }
310  tBackend* parent_backend = parent->Backend()->GetBackend(primary_relation_id);
311  bool partial_interface = false;
312  assert(parent_backend || parent->Backend()->IsPartialInterface());
313  if (!parent_backend)
314  {
315    const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo());
316    interface_type = info.GetPartialType();
317    partial_interface = interface_type && primary_port_type != tPrimaryPortType::ANY;
318    if (partial_interface)
319    {
320      parent_backend = parent->Backend();
321    }
322  }
323  return parent_backend ? new tInterfaceBase::tBackend(interface_type, convience_port_type ? parent->ParentComponent() : parent->Backend(), parent_backend, primary_relation_id, name, convience_port_type, custom_connect_function, nullptr, parent->Backend()->PrimaryPortType(), partial_interface) : nullptr;
324}
325
326tInterfaceBase::tBackend* tInterfaceBase::CreateBackend(rrlib::rtti::tType interface_type, tInterfaceBase::tBackend* parent, const std::string& name, tPrimaryPortType primary_port_type, const tConnectFunction& custom_connect_function, int primary_relation_id, bool convience_port_type)
327{
328  const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo());
329  return parent ? new tInterfaceBase::tBackend(info.GetPartialType(), convience_port_type ? parent->parent_component : parent, parent, primary_relation_id, name, convience_port_type, custom_connect_function, nullptr, parent->PrimaryPortType(), true) : nullptr;
330}
331
332void tInterfaceBase::SetConfigEntry(const rrlib::uri::tPath& config_entry)
333{
334  uint interface_count = 0;
335  auto primary_backend = this->Backend();
336  if (primary_backend)
337  {
338    for (auto backend : primary_backend->primary_backend.all_backends)
339    {
340      auto aggregator = GetAggregator(*backend);
341      if (aggregator && (!aggregator->IsPort()) && aggregator->GetFlag(tFlag::INTERFACE) && aggregator->GetFlag(tFlag::PARAMETER_INTERFACE))
342      {
343        auto parameter_info = backend->GetAnnotation<parameters::internal::tParameterInfo>();
344        if (!parameter_info)
345        {
346          parameter_info = &backend->EmplaceAnnotation<parameters::internal::tParameterInfo>();
347        }
348        std::stringstream temp;  // Temporary solution until tParameterInfo class accepts paths
349        temp << config_entry;
350        parameter_info->SetConfigEntry(temp.str(), false);
351        interface_count++;
352      }
353    }
354    if (!interface_count)
355    {
356      FINROC_LOG_PRINT(WARNING, "No parameters backend in interface ", *primary_backend);
357    }
358  }
359  else
360  {
361    FINROC_LOG_PRINT(WARNING, "Called on empty interface wrapper");
362  }
363}
364
365
366tInterfaceBase::tBackend::tBackend(const rrlib::rtti::tType& interface_type, core::tFrameworkElement* parent_component, core::tFrameworkElement* parent, int primary_relation_id, const std::string& name, bool convenience_port_type, const tConnectFunction& custom_connect_function, tCreateMissingComponentInterfaceFunction create_missing_component_interface_function, tPrimaryPortType primary_port_type, bool partial_interface) :
367  tAbstractPort(MakeCreationInfo(interface_type, name, *parent, partial_interface || tScopedExtraConstructorParameters::Get()->partial_interface || ModifierDefinesPartialInterface(*parent, interface_type), tScopedExtraConstructorParameters::Get()->shared)),
368  parent_component(parent_component),
369  primary_backend(*this),
370  custom_connect_function(custom_connect_function),
371  convenience_port_type(convenience_port_type),
372  primary_relation_id(primary_relation_id),
373  create_missing_component_interface_function(create_missing_component_interface_function),
374  primary_port_type(primary_port_type),
375  partial_interface(static_cast<const internal::tInterfaceTypeInfo&>(GetDataType().SharedTypeInfo()).GetFullType() != GetDataType()),
376  partial_interface_primary_port_type(true)
377{
378  all_backends.emplace_back(this);
379  tBackend* primary_relation_backend = this;
380  if (this->partial_interface && primary_port_type != tPrimaryPortType::ANY)
381  {
382    auto aggregator = GetAggregator(*this);
383    auto partial_definition = ModifierDefinesPartialInterface(*aggregator, interface_type);
384    if (partial_definition != tPrimaryPortType::ANY)
385    {
386      this->partial_interface_primary_port_type = partial_definition == primary_port_type;
387    }
388    else
389    {
390      bool sensor_parent = (aggregator && (aggregator->GetFlag(tFlag::SENSOR_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::SENSOR_PORT));
391      bool controller_parent = (aggregator && (aggregator->GetFlag(tFlag::CONTROLLER_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::CONTROLLER_PORT));
392      if ((sensor_parent && primary_port_type == tPrimaryPortType::CONTROLLER_PORT) || (controller_parent && primary_port_type == tPrimaryPortType::SENSOR_PORT))
393      {
394        this->partial_interface_primary_port_type = false;
395      }
396    }
397    if (!this->partial_interface_primary_port_type)
398    {
399      primary_relation_backend = nullptr;
400    }
401  }
402  relation_backend_mapping.emplace_back(primary_relation_id, primary_relation_backend);
403}
404
405tInterfaceBase::tBackend::tBackend(core::tAbstractPortCreationInfo& creation_info, tBackend& primary) :
406  tAbstractPort(creation_info),
407  parent_component(primary.parent_component),
408  primary_backend(primary),
409  custom_connect_function(primary.custom_connect_function),
410  convenience_port_type(false),
411  primary_relation_id(primary.primary_relation_id),
412  create_missing_component_interface_function(nullptr),
413  primary_port_type(primary.primary_port_type),
414  partial_interface(primary.partial_interface),
415  partial_interface_primary_port_type(primary.partial_interface_primary_port_type)
416{
417}
418
419void tInterfaceBase::tBackend::ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options)
420{
421  if (!CompiledConnectOptions(connect_options.conversion_operations))
422  {
423    throw std::runtime_error("This function requires compiled connect options");
424  }
425
426  struct tPerSelectOperation
427  {
428    const internal::tPortSelectConversionOperation* operation = nullptr;
429    const utils::tPortSelector* selector = nullptr;
430  } select_operations[2];
431  size_t select_operation_count = 0;
432  bool nested_connect_options_differ = false;
433
434  struct tNestedOperation
435  {
436    const rrlib::rtti::conversion::tRegisteredConversionOperation* operation = nullptr;
437    size_t index = 0;
438  };
439  struct tNestedOperations
440  {
441    tNestedOperation operations[2];
442    size_t count = 0;
443
444    void Add(const tNestedOperation& op)
445    {
446      operations[count] = op;
447      count++;
448    }
449
450  } nested_operations_non_convertible, nested_operations_convertible;
451
452  for (size_t i = 0; i < connect_options.conversion_operations.Size(); i++)
453  {
454    tNestedOperation nested_operation;
455    nested_operation.operation = connect_options.conversion_operations[i].second;
456    nested_operation.index = i;
457    bool nested_operation_valid = true;
458    if (typeid(*connect_options.conversion_operations[i].second) == typeid(internal::tPortSelectConversionOperation))
459    {
460      tPerSelectOperation data;
461      data.operation = static_cast<const internal::tPortSelectConversionOperation*>(connect_options.conversion_operations[i].second);
462      data.selector = connect_options.conversion_operations.GetParameterValue(i).Get<utils::tPortSelector>();
463      select_operations[select_operation_count] = data;
464      select_operation_count++;
465
466      nested_connect_options_differ = data.operation->NestedVariant() != data.operation;
467      nested_operation_valid = data.operation->NestedVariant();
468    }
469    if (nested_operation_valid)
470    {
471      nested_operations_non_convertible.Add(nested_operation);
472      if (connect_options.conversion_operations[i].second != &cCONNECT_BY_NAME_OPERATION)
473      {
474        nested_operations_convertible.Add(nested_operation);
475      }
476    }
477  }
478
479  for (auto port = this->ChildPortsBegin(); port != this->ChildPortsEnd(); ++port)
480  {
481    auto other_port_element = destination.GetChild(port->GetName());
482    if (other_port_element && other_port_element->IsPort())
483    {
484      auto& other_port = static_cast<core::tAbstractPort&>(*other_port_element);
485
486      // Check whether to include port
487      bool skip = false;
488      for (size_t i = 0; i < select_operation_count; i++)
489      {
490        const tPerSelectOperation& data = select_operations[i];
491        if (!data.operation->NestedOnly())
492        {
493          if (data.operation->ExcludeOperation())
494          {
495            skip |= data.selector->Accepts(*port) || data.selector->Accepts(other_port);
496          }
497          else
498          {
499            skip |= (!data.selector->Accepts(*port)) && (!data.selector->Accepts(other_port));
500          }
501        }
502      }
503      if (skip)
504      {
505        continue;
506      }
507
508
509      if (port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE)
510      {
511        auto option_flags = connect_options.flags;
512        option_flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, false);
513        option_flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, false);
514        port->ConnectTo(other_port, option_flags);
515      }
516      else
517      {
518        if (IsInterfaceType(port->GetDataType()))
519        {
520          bool convertible = port->GetDataType() == other_port.GetDataType() || IsDerivedFrom(port->GetDataType(), other_port.GetDataType()) || IsDerivedFrom(other_port.GetDataType(), port->GetDataType());
521          const tNestedOperations& operations = convertible ? nested_operations_convertible : nested_operations_non_convertible;
522          if ((!nested_connect_options_differ) && operations.count == connect_options.conversion_operations.Size())
523          {
524            port->ConnectTo(other_port, connect_options);
525          }
526          else
527          {
528            core::tConnectOptions nested_options(connect_options.flags);
529            if (operations.count)
530            {
531              nested_options.conversion_operations = operations.count == 1 ? rrlib::rtti::conversion::tConversionOperationSequence(*operations.operations[0].operation) : rrlib::rtti::conversion::tConversionOperationSequence(*operations.operations[0].operation, *operations.operations[1].operation);
532            }
533            for (size_t i = 0; i < operations.count; i++)
534            {
535              if (nested_options.conversion_operations[i].second->Parameter() && connect_options.conversion_operations.GetParameterValue(operations.operations[i].index))
536              {
537                nested_options.conversion_operations.SetParameterValue(i, connect_options.conversion_operations.GetParameterValue(operations.operations[i].index));
538              }
539            }
540            port->ConnectTo(other_port, nested_options);
541          }
542        }
543        else
544        {
545          port->ConnectTo(other_port, connect_options.flags);
546        }
547      }
548    }
549  }
550}
551
552core::tConnector* tInterfaceBase::tBackend::CreateConnector(core::tAbstractPort& destination, const core::tConnectOptions& connect_options)
553{
554  if (!(CompiledConnectOptions(connect_options.conversion_operations)))
555  {
556    assert(connect_options.conversion_operations.Size() >= 1);
557    const rrlib::rtti::conversion::tRegisteredConversionOperation* operations[2] = { nullptr, nullptr };
558
559    // Resolve ambiguous operations
560    for (size_t i = 0; i < connect_options.conversion_operations.Size(); i++)
561    {
562      auto operation = connect_options.conversion_operations[i];
563      if (operation.second)
564      {
565        operations[i] = operation.second;
566      }
567      else
568      {
569        auto& registered_operations = rrlib::rtti::conversion::tRegisteredConversionOperation::GetRegisteredOperations();
570        for (auto it = registered_operations.operations.Begin(); it != registered_operations.operations.End(); ++it)
571        {
572          if (strcmp((*it)->Name(), operation.first) == 0)
573          {
574            operations[i] = *it;
575            break;
576          }
577        }
578      }
579
580      if (!operations[i])
581      {
582        throw std::runtime_error(std::string("Operation lookup failed: ") + operation.first);
583      }
584    }
585
586    rrlib::rtti::conversion::tConversionOperationSequence conversion = connect_options.conversion_operations.Size() == 1 ? rrlib::rtti::conversion::tConversionOperationSequence(*operations[0]) : rrlib::rtti::conversion::tConversionOperationSequence(*operations[0], *operations[1], connect_options.conversion_operations.IntermediateType() ? connect_options.conversion_operations.IntermediateType() : destination.GetDataType());
587
588    // ############
589    // Convert any parameters provided as strings to their required types (see tConversionOperationSequence.cpp)
590    // ############
591    for (size_t i = 0; i < 2; i++)
592    {
593      const rrlib::rtti::conversion::tRegisteredConversionOperation* operation = operations[i];
594      if (operation && operation->Parameter() && connect_options.conversion_operations.GetParameterValue(i))
595      {
596        const rrlib::rtti::tTypedConstPointer& value = connect_options.conversion_operations.GetParameterValue(i);
597        if (value.GetType() == operation->Parameter().GetType())
598        {
599          conversion.SetParameterValue(i, value);
600        }
601        else if (value.GetType() == rrlib::rtti::tDataType<std::string>())
602        {
603          rrlib::serialization::tStringInputStream stream(*value.Get<std::string>());
604          auto buffer = operation->Parameter().GetType().CreateGenericObject();
605          buffer->Deserialize(stream);
606          conversion.SetParameterValue(i, *buffer);
607        }
608        else
609        {
610          throw std::runtime_error(std::string("Parameter ") + operation->Parameter().GetName() + " has invalid type");
611        }
612      }
613    }
614
615    return new tConversionConnector(*this, destination, core::tConnectOptions(conversion, connect_options.flags));
616  }
617  return new tConversionConnector(*this, destination, connect_options);
618}
619
620bool tInterfaceBase::tBackend::CreateOutputPort(int primary_relation_id)
621{
622  auto backend = GetBackend(primary_relation_id);
623  if (!backend)
624  {
625    return false;
626  }
627  auto component_interface = GetAggregator(*backend);
628  if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
629  {
630    return false;
631  }
632  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
633  {
634    int last_relation = primary_relation_id & 0xFF;
635    bool derived_from_backend_is_output = CreateOutputPort(primary_relation_id >> 8);
636    if (last_relation == internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT)
637    {
638      return !derived_from_backend_is_output;
639    }
640    else if (last_relation == internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT)
641    {
642      return derived_from_backend_is_output;
643    }
644  }
645  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS))
646  {
647    return true;
648  }
649  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_INPUTS) || component_interface->GetFlag(tFlag::PARAMETER_INTERFACE))
650  {
651    return false;
652  }
653  throw std::runtime_error("Unspecified port direction");
654}
655
656core::tAbstractPort* tInterfaceBase::tBackend::CreatePort(const core::tAbstractPortCreationInfo& creation_info, int primary_relation_id) const
657{
658  auto modifier = GetModifier(*creation_info.parent);
659  return (modifier ? modifier->Implementation() : cMODIFIER_DEFAULT_IMPLEMENTATION).CreatePort(creation_info, primary_relation_id);
660}
661
662std::vector<tInterfaceBase> tInterfaceBase::FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces)
663{
664  std::vector<tInterfaceBase> result;
665  if (type.GetTypeClassification() == rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE)
666  {
667    FindInterfacesBelowImplementation(result, parent, type, skip_derived_interfaces);
668  }
669  return result;
670}
671
672tInterfaceBase::tBackend* tInterfaceBase::tBackend::GetBackend(int primary_relation_id)
673{
674  if (&primary_backend != this)
675  {
676    return primary_backend.GetBackend(primary_relation_id);
677  }
678
679  for (auto & entry : relation_backend_mapping)
680  {
681    if (entry.first == primary_relation_id)
682    {
683      return entry.second;
684    }
685  }
686
687  core::tFrameworkElement* parent = nullptr;
688  bool do_not_create_primary_port_type = relation_backend_mapping.front().second == nullptr;
689  bool partial_interface_direction_is_output = GetAggregator(*this)->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS);
690  bool partial_interface_primary_relation_direction_is_output = !partial_interface_direction_is_output;
691  bool backend_for_client_port = false;
692  if (GetParent() && typeid(*GetParent()).name() == typeid(tBackend).name())
693  {
694    parent = static_cast<tBackend&>(*GetParent()).GetBackend(primary_relation_id);
695  }
696  else if (core::tFrameworkElementTags::IsTagged(*this->GetParent(), cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION))
697  {
698    parent = this->GetParent();
699  }
700  else if (this->partial_interface && (!IsPartOfPartialInstantiation(primary_relation_id, this->partial_interface_primary_port_type)))
701  {
702    parent = nullptr; // Skip
703  }
704  else
705  {
706    // Actually process relation
707    std::vector<int> relation_list;
708    tFrameworkElement* component_interface = this->GetParent();
709    int relation_id = primary_relation_id;
710    if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
711    {
712      FINROC_LOG_PRINT(WARNING, "Generic creation of port composite interfaces with multiple port types only works on components");
713      throw std::runtime_error("Generic creation of port composite interfaces with multiple port types only works on components");
714    }
715
716    const core::tFrameworkElementFlags relevant_flags = tFlag::SENSOR_DATA | tFlag::CONTROLLER_DATA | tFlag::INTERFACE_FOR_INPUTS | tFlag::INTERFACE_FOR_OUTPUTS | tFlag::PROXY_INTERFACE | tFlag::PARAMETER_INTERFACE;
717    tInterfaceModifier* interface_modifier = GetModifier(*component_interface);
718
719    // Compute opcode sequence
720    {
721      while (relation_id)
722      {
723        int opcode = relation_id & 0xFF;
724        relation_list.push_back(opcode);
725        relation_id = relation_id >> 8;
726      }
727      std::reverse(relation_list.begin(), relation_list.end());
728    }
729
730    tFrameworkElement* parent_candidate = do_not_create_primary_port_type ? nullptr : component_interface;
731    core::tFrameworkElementFlags use_these_original_flags;
732    if (do_not_create_primary_port_type)
733    {
734      assert(partial_interface && primary_port_type != tPrimaryPortType::ANY);
735      use_these_original_flags = tFlag::INTERFACE_FOR_DATA_PORTS | (primary_port_type == tPrimaryPortType::SENSOR_PORT ? tFlag::SENSOR_DATA : tFlag::CONTROLLER_DATA) | (partial_interface_primary_relation_direction_is_output ? tFlag::INTERFACE_FOR_OUTPUTS : tFlag::INTERFACE_FOR_INPUTS);
736      use_these_original_flags.Set(tFlag::PROXY_INTERFACE, component_interface->GetFlag(tFlag::PROXY_INTERFACE));
737    }
738
739    int remaining_relations = relation_list.size();
740    for (int opcode : relation_list)
741    {
742      remaining_relations--;
743      core::tFrameworkElementFlags original_flags = use_these_original_flags.Raw() ? use_these_original_flags : parent_candidate->GetAllFlags();
744      use_these_original_flags = core::tFrameworkElementFlags();
745      core::tFrameworkElementFlags target_set_flags = core::tFrameworkElementFlags(original_flags.Raw() & relevant_flags.Raw());
746      core::tFrameworkElementFlags target_unset_flags = core::tFrameworkElementFlags((~original_flags.Raw()) & relevant_flags.Raw());
747
748      typedef internal::tPortTypeRelation tOpCode;
749      switch (opcode)
750      {
751      case tOpCode::ePTR_COUNTER_PART:
752      case tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT:
753        if (original_flags.Get(tFlag::CONTROLLER_DATA) && (!original_flags.Get(tFlag::SENSOR_DATA)))
754        {
755          target_set_flags.Set(tFlag::SENSOR_DATA);
756          target_set_flags.Set(tFlag::CONTROLLER_DATA, false);
757          target_unset_flags.Set(tFlag::CONTROLLER_DATA);
758          target_unset_flags.Set(tFlag::SENSOR_DATA, false);
759        }
760        if (original_flags.Get(tFlag::SENSOR_DATA) && (!original_flags.Get(tFlag::CONTROLLER_DATA)))
761        {
762          target_set_flags.Set(tFlag::CONTROLLER_DATA);
763          target_set_flags.Set(tFlag::SENSOR_DATA, false);
764          target_unset_flags.Set(tFlag::SENSOR_DATA);
765          target_unset_flags.Set(tFlag::CONTROLLER_DATA, false);
766        }
767        if (original_flags.Get(tFlag::INTERFACE_FOR_INPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS)))
768        {
769          target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
770          target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
771          target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
772          target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
773          target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
774        }
775        if (original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_INPUTS)))
776        {
777          if (opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT)
778          {
779            target_set_flags = tFlag::PARAMETER_INTERFACE;
780            target_unset_flags = core::tFrameworkElementFlags();
781          }
782          else
783          {
784            target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
785            target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
786            target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
787            target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
788          }
789        }
790        break;
791      case internal::tPortTypeRelation::ePTR_INPUT:
792        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
793        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
794        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
795        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
796        break;
797      case internal::tPortTypeRelation::ePTR_OUTPUT:
798        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
799        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
800        target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
801        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
802        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
803        break;
804      case internal::tPortTypeRelation::ePTR_PARAMETER:
805        target_set_flags = tFlag::PARAMETER_INTERFACE;
806        target_unset_flags = core::tFrameworkElementFlags();
807        break;
808      case internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT:
809      case internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT:
810        backend_for_client_port = (remaining_relations == 0) && ((opcode == internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT && original_flags.Get(tFlag::INTERFACE_FOR_INPUTS)) || (opcode == internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT && original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS)));
811        target_set_flags = tFlag::INTERFACE_FOR_RPC_PORTS;
812        target_unset_flags = (partial_interface && (!parent_candidate)) ? target_set_flags : core::tFrameworkElementFlags(); // With partially instantiated interfaces, create service ports if the port types they are derived from are also created
813        break;
814      default:
815        break;
816      }
817
818      core::tFrameworkElement* new_candidate = nullptr;
819      size_t candidate_name_length_difference = std::numeric_limits<size_t>::max();
820      auto component = component_interface->GetParent();
821      for (auto it = component->ChildrenBegin(); it != component->ChildrenEnd(); ++it)
822      {
823        if ((!it->IsPort()) && it->GetFlag(tFlag::INTERFACE) && (it->GetAllFlags().Raw() & target_set_flags.Raw()) == target_set_flags.Raw() && (it->GetAllFlags().Raw() & target_unset_flags.Raw()) == 0)
824        {
825          size_t name_length_difference = std::abs(static_cast<long>(component_interface->GetName().length()) - static_cast<long>(it->GetName().length()));
826          if (name_length_difference < candidate_name_length_difference)
827          {
828            new_candidate = &*it;
829            candidate_name_length_difference = name_length_difference;
830          }
831        }
832      }
833
834      if ((!new_candidate) && this->IsPartialInterface() && remaining_relations)
835      {
836        use_these_original_flags = target_set_flags;
837        parent_candidate = nullptr;
838        continue;
839      }
840
841      // Not-yet-created component interfaces - until there is a generic way to do this
842      if ((!new_candidate) && create_missing_component_interface_function)
843      {
844        new_candidate = (*create_missing_component_interface_function)(component_interface->GetParent(), target_set_flags);
845      }
846
847      if ((!new_candidate) && interface_modifier)
848      {
849        use_these_original_flags = target_set_flags;
850        parent_candidate = nullptr;
851        continue;
852      }
853
854      if (new_candidate)
855      {
856        component_interface = new_candidate;
857        parent_candidate = new_candidate;
858      }
859      else
860      {
861        std::stringstream message;
862        message << "Generic creation of port composite interface failed: No interface with relation " << make_builder::GetEnumString(static_cast<tOpCode>(opcode)) << " found below " << *component_interface->GetParent();
863        FINROC_LOG_PRINT(WARNING, message.str());
864        throw std::runtime_error(message.str());
865      }
866    }
867    assert(remaining_relations == 0);
868
869    parent = parent_candidate;
870    if (interface_modifier)
871    {
872      parent = interface_modifier->Implementation().GetComponentInterface(parent_candidate && parent_candidate->GetFlag(tFlag::INTERFACE) ? static_cast<core::tPortGroup*>(parent_candidate) : nullptr, primary_relation_id);
873    }
874  }
875
876  if (!parent)
877  {
878    relation_backend_mapping.emplace_back(primary_relation_id, nullptr);
879    return nullptr;
880  }
881
882  for (auto backend : all_backends)
883  {
884    if (backend->GetParent() == parent)
885    {
886      relation_backend_mapping.emplace_back(primary_relation_id, backend);
887      return backend;
888    }
889  }
890
891  // Create new backend below this parent
892  assert(parent != this->GetParent());
893  core::tAbstractPortCreationInfo secondary_creation_info;
894  secondary_creation_info.data_type = this->GetDataType();
895  secondary_creation_info.name = GetName();
896  secondary_creation_info.parent = parent;
897  secondary_creation_info.flags = core::tFrameworkElementFlags(tFlag::INTERFACE);
898  auto aggregator = GetAggregator(*parent, &secondary_creation_info.flags);
899  if (backend_for_client_port && aggregator->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
900  {
901    secondary_creation_info.flags.Set(tFlag::OUTPUT_PORT, backend_for_client_port);
902  }
903  if (this->GetFlag(tFlag::SHARED))
904  {
905    secondary_creation_info.flags |= tFlag::SHARED;
906  }
907  all_backends.push_back(new tBackend(secondary_creation_info, *this));
908  relation_backend_mapping.emplace_back(primary_relation_id, all_backends.back());
909  return all_backends.back();
910}
911
912core::tFrameworkElementFlags tInterfaceBase::tBackend::GetDefaultPortFlags(bool generic_port_backend) const
913{
914  core::tFrameworkElementFlags result;
915  if (generic_port_backend)
916  {
917    GetAggregator(*this, &result);
918  }
919  else
920  {
921    auto aggregator = GetAggregator(*this);
922    if (aggregator && aggregator->GetFlag(tFlag::INTERFACE))
923    {
924      if (aggregator->GetFlag(tFlag::PROXY_INTERFACE))
925      {
926        result |= (tFlag::ACCEPTS_DATA | tFlag::EMITS_DATA | tFlag::PUSH_STRATEGY);
927      }
928      result |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags();
929    }
930  }
931  const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw();
932  result |= core::tFrameworkElementFlags(this->GetAllFlags().Raw() & cRELEVANT_FLAGS);
933  return result;
934}
935
936bool tInterfaceBase::tBackend::IsPartOfPartialInstantiation(int primary_relation_id, bool partial_instantiation_variant_primary_port_type)
937{
938  typedef internal::tPortTypeRelation tOpCode;
939  int switch_count = 0;
940  while (primary_relation_id)
941  {
942    int opcode = primary_relation_id & 0xFF;
943    switch_count += ((opcode == tOpCode::ePTR_COUNTER_PART || opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT) ? 1 : 0);
944    primary_relation_id = primary_relation_id >> 8;
945  }
946  bool primary_port_type_relation_id = (switch_count % 2) == 0;
947  return primary_port_type_relation_id == partial_instantiation_variant_primary_port_type;
948}
949
950void tInterfaceBase::tBackend::OnConnect(tAbstractPort& partner, bool partner_is_destination)
951{
952  if (primary_backend.operation_on_all_elements_pending)
953  {
954    return;
955  }
956
957  tBackend& other = static_cast<tBackend&>(partner);
958  bool connect_all_backends = this->IsPrimaryBackend() && other.IsPrimaryBackend();
959
960  // Are any conversion operations set?
961  const tConversionConnector* conversion_connector = nullptr;
962  {
963    if (partner_is_destination)
964    {
965      for (auto it = this->OutgoingConnectionsBegin(); it != this->OutgoingConnectionsEnd(); ++it)
966      {
967        if (&it->Destination() == &partner && typeid(*it) == typeid(tConversionConnector))
968        {
969          conversion_connector = &static_cast<const tConversionConnector&>(*it);
970          break;
971        }
972      }
973    }
974    else
975    {
976      for (auto it = this->IncomingConnectionsBegin(); it != this->IncomingConnectionsEnd(); ++it)
977      {
978        if (&it->Source() == &partner && typeid(*it) == typeid(tConversionConnector))
979        {
980          conversion_connector = &static_cast<const tConversionConnector&>(*it);
981          break;
982        }
983      }
984    }
985  }
986
987  primary_backend.operation_on_all_elements_pending = true;
988  try
989  {
990    if (!conversion_connector)
991    {
992      throw std::runtime_error("Invalid connector type");
993    }
994
995    if (primary_backend.custom_connect_function)
996    {
997      if (partner_is_destination)
998      {
999        primary_backend.custom_connect_function(*this, other, conversion_connector->ChildConnectOptions());
1000      }
1001      else
1002      {
1003        primary_backend.custom_connect_function(other, *this, conversion_connector->ChildConnectOptions());
1004      }
1005      primary_backend.operation_on_all_elements_pending = false;
1006      return;
1007    }
1008
1009    // Connect all matching backends and ports
1010    for (auto this_backend : primary_backend.relation_backend_mapping)
1011    {
1012      for (auto other_backend : other.primary_backend.primary_backend.relation_backend_mapping)
1013      {
1014        if (this_backend.second && other_backend.second && this_backend.first - primary_backend.primary_relation_id == other_backend.first - other.primary_backend.primary_relation_id && (connect_all_backends || this_backend.second == this || other_backend.second == &other))
1015        {
1016          core::tConnectionFlag direction = (this->IsOutputPort() == this_backend.second->IsOutputPort() ? partner_is_destination : (!partner_is_destination)) ? core::tConnectionFlag::DIRECTION_TO_DESTINATION : core::tConnectionFlag::DIRECTION_TO_SOURCE;
1017          this_backend.second->ConnectTo(*other_backend.second, conversion_connector->ChildConnectOptions(direction));
1018          this_backend.second->ConnectChildPortsByName(*other_backend.second, conversion_connector->ChildConnectOptions(direction));
1019        }
1020      }
1021    }
1022  }
1023  catch (const std::exception& e)
1024  {
1025    FINROC_LOG_PRINT(WARNING, "Connecting failed: ", e);
1026  }
1027  primary_backend.operation_on_all_elements_pending = false;
1028}
1029
1030void tInterfaceBase::tBackend::OnDisconnect(tAbstractPort& partner, bool partner_is_destination)
1031{
1032  bool& pending = primary_backend.primary_backend.operation_on_all_elements_pending;
1033  tBackend& other = static_cast<tBackend&>(partner).primary_backend;
1034  if (pending || other.operation_on_all_elements_pending || partner_is_destination)
1035  {
1036    return;
1037  }
1038
1039  pending = true;
1040  try
1041  {
1042    // Update other backend connection info
1043    for (auto this_backend : this->primary_backend.all_backends)
1044    {
1045      for (auto other_backend : other.primary_backend.all_backends)
1046      {
1047        this_backend->DisconnectFrom(*other_backend);
1048      }
1049    }
1050
1051    // Disconnect all ports to partner backends (this should also cover cases with custom connect function)
1052    for (auto backend : primary_backend.all_backends)
1053    {
1054      for (auto port = backend->ChildPortsBegin(); port != backend->ChildPortsEnd(); ++port)
1055      {
1056        for (auto partner = port->IncomingConnectionsBegin(); partner != port->IncomingConnectionsEnd(); ++partner)
1057        {
1058          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Source().GetParent()))
1059          {
1060            port->DisconnectFrom(partner->Source());
1061          }
1062        }
1063        for (auto partner = port->OutgoingConnectionsBegin(); partner != port->OutgoingConnectionsEnd(); ++partner)
1064        {
1065          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Destination().GetParent()))
1066          {
1067            port->DisconnectFrom(partner->Destination());
1068          }
1069        }
1070      }
1071    }
1072  }
1073  catch (const std::exception& e)
1074  {
1075    FINROC_LOG_PRINT(WARNING, "Disconnecting failed: ", e);
1076  }
1077  pending = false;
1078}
1079
1080void tInterfaceBase::tBackend::OnInitialization()
1081{
1082  bool& pending = primary_backend.operation_on_all_elements_pending;
1083  if (!pending)
1084  {
1085    pending = true;
1086    for (auto backend : primary_backend.all_backends)
1087    {
1088      if (backend != this)
1089      {
1090        backend->Init();
1091      }
1092    }
1093    pending = false;
1094  }
1095}
1096
1097void tInterfaceBase::tBackend::OnManagedDelete()
1098{
1099  rrlib::thread::tLock lock1(GetStructureMutex());
1100
1101  if (!core::tRuntimeEnvironment::ShuttingDown())
1102  {
1103    bool& pending = primary_backend.operation_on_all_elements_pending;
1104    if (!pending)
1105    {
1106      pending = true;
1107      for (auto backend : primary_backend.all_backends)
1108      {
1109        if (backend != this)
1110        {
1111          backend->ManagedDelete();
1112        }
1113      }
1114      pending = false;
1115    }
1116  }
1117
1118  tAbstractPort::OnManagedDelete();
1119}
1120
1121tInterfaceBase::tScopedExtraConstructorParameters tInterfaceBase::tScopedExtraConstructorParameters::Get()
1122{
1123  static tExtraConstructorParameters parameters;
1124  return tScopedExtraConstructorParameters(core::tRuntimeEnvironment::GetInstance().GetStructureMutex(), &parameters);  //
1125}
1126
1127void tInterfaceBase::tSecondaryPortModifier::operator()(core::tAbstractPortCreationInfo& creation_info) const
1128{
1129  creation_info.name = name;
1130  creation_info.parent = &backend;
1131  creation_info.flags |= backend.GetDefaultPortFlags(false);
1132
1133  {
1134    auto modifier = GetModifier(backend);
1135    if (modifier)
1136    {
1137      modifier->Implementation().AdjustPortCreationInfo(creation_info);
1138    }
1139  }
1140}
1141
1142//----------------------------------------------------------------------
1143// End of namespace declaration
1144//----------------------------------------------------------------------
1145}
1146}
Note: See TracBrowser for help on using the repository browser.