Changeset 139:b80094f9fac6 in finroc_plugins_data_ports


Ignore:
Timestamp:
18.02.2019 07:37:31 (8 months ago)
Author:
Max Reichardt <mreichardt@…>
Branch:
default
Parents:
124:ca459cc011c8 (diff), 138:b4ec8fe1d2ef (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Phase:
public
Message:

Merge with 17.03

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • tPortPack.h

    r124 r139  
    4040// External includes (system with <>, local with "") 
    4141//---------------------------------------------------------------------- 
     42#include "core/tFrameworkElement.h" 
     43#include "core/log_messages.h" 
     44#include "rrlib/util/tIteratorRange.h" 
     45#include "rrlib/util/tIntegerSequence.h" 
     46 
    4247#include "rrlib/util/tTypeList.h" 
    43 #include "core/tFrameworkElement.h" 
    4448 
    4549//---------------------------------------------------------------------- 
     
    6367//---------------------------------------------------------------------- 
    6468//! A group of several ports with different types. 
     69/*! 
     70 * This class creates a tuple of instances of the given port template 
     71 * inserting the given types.  It also provides methods to access the 
     72 * included ports and their change flags at runtime. 
     73 * 
     74 * \param TPort    A port class template to use for every packed port 
     75 * \param TTypes   A variadic list of the data types used in the ports 
     76 */ 
     77template <template <typename> class TPort, typename ... TTypes> 
     78class tPortPack 
     79{ 
     80  using tPorts = std::tuple<std::unique_ptr<TPort<TTypes>>...>; 
     81  using tIndex = typename rrlib::util::tIntegerSequenceGenerator<sizeof...(TTypes)>::type; 
     82 
     83//---------------------------------------------------------------------- 
     84// Public methods and typedefs 
     85//---------------------------------------------------------------------- 
     86public: 
     87 
     88  /*! Ctor with common port name prefix 
     89   * 
     90   * The port names will follow the scheme "<prefix> [0..]" 
     91   * 
     92   * \param parent        The parent framework element 
     93   * \param name_prefix   The common prefix used for all port names 
     94   */ 
     95  inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix) 
     96  { 
     97    this->DispatchInitializer(parent, tIndex(), [&name_prefix](size_t i) 
     98    { 
     99      return name_prefix + std::to_string(i); 
     100    }); 
     101  } 
     102 
     103  /*! Ctor with custom port names 
     104   * 
     105   * The port names are completely taken from two iterators 
     106   * 
     107   * \param parent        The parent framework element 
     108   * \param names_begin   Begin of the list of port names 
     109   * \param names_end     End of the list of port names 
     110   */ 
     111  template <typename TIterator> 
     112  inline tPortPack(core::tFrameworkElement *parent, TIterator names_begin, TIterator names_end) 
     113  { 
     114    auto number_of_names = std::distance(names_begin, names_end); 
     115    if (number_of_names != sizeof...(TTypes)) 
     116    { 
     117      FINROC_LOG_THROW(rrlib::util::tTraceableException<std::logic_error>("Number of ports names (" + std::to_string(number_of_names) + ") does not fit given number of ports (" + std::to_string(sizeof...(TTypes)) + ")")); 
     118    } 
     119    this->DispatchInitializer(parent, tIndex(), [names_begin](size_t i) mutable { return *names_begin++; }); 
     120  } 
     121 
     122  /*! Ctor with custom port names (range) 
     123   * 
     124   * The port names are completely specified 
     125   * 
     126   * \param parent   The parent framework element 
     127   * \param names    A range of port names to be used 
     128   */ 
     129  template <typename TIterator> 
     130  inline tPortPack(core::tFrameworkElement *parent, const rrlib::util::tIteratorRange<TIterator> &names) : 
     131    tPortPack(parent, names.begin(), names.end()) 
     132  {} 
     133 
     134  /*! The number of ports in this port pack 
     135   * 
     136   * \returns Number of ports in \a this pack 
     137   */ 
     138  inline static constexpr size_t NumberOfPorts() 
     139  { 
     140    return sizeof...(TTypes); 
     141  } 
     142 
     143  /*! Access a specific port (strong type version, compile time) 
     144   * 
     145   * \param Tindex   The index of the port in this pack 
     146   * 
     147   * \return The specified port 
     148   */ 
     149  template <size_t Tindex> 
     150  inline typename std::tuple_element<Tindex, std::tuple<TPort<TTypes>...>>::type &GetPort() 
     151  { 
     152    static_assert(Tindex < this->NumberOfPorts(), "Port index not in range"); 
     153    return *std::get<Tindex>(this->ports); 
     154  } 
     155 
     156  /*! Access a specific port (runtime version) 
     157   * 
     158   * \param index   The index of the port in this pack 
     159   * 
     160   * \return The specified port 
     161   */ 
     162  inline core::tPortWrapperBase &GetPort(size_t index) 
     163  { 
     164    assert(index < this->NumberOfPorts()); 
     165    return *this->port_wrappers[index]; 
     166  } 
     167 
     168  /*! Access a specific port's changed flag 
     169   * 
     170   * \param index   The index of the port in this pack 
     171   * 
     172   * \return Whether the port has changed or not 
     173   */ 
     174  inline bool HasChanged(size_t index) 
     175  { 
     176    return this->GetChangedFlags(tIndex())[index]; 
     177  } 
     178 
     179  /*! Check if any port in the pack has changed 
     180   * 
     181   * \return Whether any port in the pack has changed 
     182   */ 
     183  inline bool Changed() 
     184  { 
     185    auto changed_flags = this->GetChangedFlags(tIndex()); 
     186    return std::any_of(changed_flags.begin(), changed_flags.end(), [](bool x) 
     187    { 
     188      return x; 
     189    }); 
     190  } 
     191 
     192  /*! Publish a tuple of value through this port pack (only for output ports) 
     193   * 
     194   * \param values      A tuple of values that can be published via this portspacks ports 
     195   * \param timestamp   An optional timestamp to use (default: cNO_TIME) 
     196   */ 
     197  template <typename ... TValues> 
     198  inline void Publish(const std::tuple<TValues...> &values, const rrlib::time::tTimestamp timestamp = rrlib::time::cNO_TIME) 
     199  { 
     200    this->DispatchPublisher(tIndex(), values, timestamp); 
     201  } 
     202 
     203  /*! Deletion of the port pack's ports 
     204   */ 
     205  inline void ManagedDelete() 
     206  { 
     207    this->ManagedDelete(tIndex()); 
     208  } 
     209 
     210//---------------------------------------------------------------------- 
     211// Protected methods 
     212//---------------------------------------------------------------------- 
     213protected: 
     214 
     215  /*! Ctor with common port name prefix and port number offset to support legacy code 
     216   * 
     217   * The port names will follow the scheme "<prefix> [<offset>..]" 
     218   * 
     219   * \param parent        The parent framework element 
     220   * \param name_prefix   The common prefix used for all port names 
     221   * \param offset        Offset for numbering the created ports 
     222   */ 
     223  inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix, size_t offset) 
     224  { 
     225    this->DispatchInitializer(parent, tIndex(), [&name_prefix, offset](size_t i) 
     226    { 
     227      return name_prefix + std::to_string(i + offset); 
     228    }); 
     229  } 
     230 
     231//---------------------------------------------------------------------- 
     232// Private fields and methods 
     233//---------------------------------------------------------------------- 
     234private: 
     235 
     236  tPorts ports; 
     237  core::tPortWrapperBase *port_wrappers[sizeof...(TTypes)]; 
     238 
     239  template <size_t Tindex> 
     240  int InitializePort(core::tFrameworkElement *parent, const std::string &name) 
     241  { 
     242    std::get<Tindex>(this->ports).reset(new typename std::tuple_element<Tindex, std::tuple<TPort<TTypes>...>>::type(name, parent)); 
     243    std::get<Tindex>(this->ports)->Init(); 
     244    return 0; 
     245  } 
     246 
     247  template <int ... Tindex, typename TNameGenerator> 
     248  void DispatchInitializer(core::tFrameworkElement *parent, rrlib::util::tIntegerSequence<Tindex...>, TNameGenerator name_generator) 
     249  { 
     250    __attribute__((unused)) int foo[] = { InitializePort<Tindex>(parent, name_generator(Tindex))... }; 
     251    auto port_wrappers = std::initializer_list<core::tPortWrapperBase *> {std::get<Tindex>(this->ports).get()...}; 
     252    std::copy(port_wrappers.begin(), port_wrappers.end(), this->port_wrappers); 
     253  } 
     254 
     255  template <typename T, typename TValue> 
     256  int PublishPort(T &port, const TValue &value, const rrlib::time::tTimestamp &timestamp) 
     257  { 
     258    port.Publish(value, timestamp); 
     259    return 0; 
     260  } 
     261  template <int ... Tindex, typename ... TValues> 
     262  void DispatchPublisher(rrlib::util::tIntegerSequence<Tindex...>, const std::tuple<TValues...> &values, const rrlib::time::tTimestamp timestamp) 
     263  { 
     264    __attribute__((unused)) int foo[] = { PublishPort(*std::get<Tindex>(this->ports), std::get<Tindex>(values), timestamp)... }; 
     265  } 
     266 
     267  template <int ... Tindex> 
     268  inline std::array<bool, sizeof...(Tindex)> GetChangedFlags(rrlib::util::tIntegerSequence<Tindex...>) 
     269  { 
     270    return { std::get<Tindex>(this->ports)->HasChanged()... }; 
     271  } 
     272 
     273  template <int ... Tindex> 
     274  inline void ManagedDelete(rrlib::util::tIntegerSequence<Tindex...>) 
     275  { 
     276    for (auto p : this->port_wrappers) 
     277    { 
     278      p->GetWrapped()->ManagedDelete(); 
     279    } 
     280  } 
     281 
     282}; 
     283 
    65284/*! 
    66285 * This class creates a list of instances of the given port template 
     
    69288 * port on a specific layer at runtime. 
    70289 * 
     290 * \note This class exists to support legacy code that used the initial 
     291 *       version with tTypeList and 1-based port numbers. 
     292 * 
    71293 * \param TPort       A port class template to use for every packed port 
    72294 * \param TTypeList   A list of the data types used in the ports. e.g. rrlib::util::tTypeList 
    73  * \param Tsize       The pack creates ports using TTypeList[0] to TTypeList[Tsize - 1]. This parameter must not be greater than TTypeList::cSIZE - 1 and is typically inferred and not set by the user. 
    74295 */ 
    75 template <template <typename> class TPort, typename TTypeList, size_t Tsize = rrlib::util::type_list::tSizeOf<TTypeList>::cVALUE> 
    76 class tPortPack : private tPortPack < TPort, TTypeList, Tsize - 1 > 
     296template <template <typename> class TPort, typename ... TTypes> 
     297class tPortPack<TPort, rrlib::util::tTypeList<TTypes...>> : public tPortPack<TPort, TTypes...> 
    77298{ 
    78  
    79   template <bool value, typename> 
    80   using CheckIterators = std::integral_constant<bool, value>; 
    81  
    82 //---------------------------------------------------------------------- 
    83 // Public methods and typedefs 
    84 //---------------------------------------------------------------------- 
    85299public: 
    86  
     300  using tPortPack<TPort, TTypes...>::tPortPack; 
    87301  inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix) : 
    88     tPortPack < TPort, TTypeList, Tsize - 1 > (parent, name_prefix), 
    89     port(name_prefix + std::to_string(Tsize), parent) 
    90   { 
    91     this->port.Init(); 
    92   } 
    93  
    94   template <typename TIterator, typename std::enable_if<CheckIterators<(Tsize> 1), TIterator>::value, int>::type = 0 > 
    95       inline tPortPack(core::tFrameworkElement *parent, TIterator names_begin, TIterator names_end) : 
    96         tPortPack < TPort, TTypeList, Tsize - 1 > (parent, names_begin, names_end - 1), 
    97         port(*(names_end - 1), parent) 
    98   { 
    99     this->port.Init(); 
    100   } 
    101  
    102   template <typename TIterator, typename std::enable_if<CheckIterators<(Tsize == 1), TIterator>::value, int>::type = 0> 
    103   inline tPortPack(core::tFrameworkElement *parent, TIterator names_begin, TIterator names_end) : 
    104     tPortPack < TPort, TTypeList, Tsize - 1 > (parent, *names_begin), 
    105     port(*names_begin, parent) 
    106   { 
    107     this->port.Init(); 
    108   } 
    109  
    110   inline size_t NumberOfPorts() const 
    111   { 
    112     return Tsize; 
    113   } 
    114  
    115   inline core::tPortWrapperBase &GetPort(size_t index) 
    116   { 
    117     assert(index < this->NumberOfPorts()); 
    118     if (index == Tsize - 1) 
    119     { 
    120       return this->port; 
    121     } 
    122     return tPortPack < TPort, TTypeList, Tsize - 1 >::GetPort(index); 
    123   } 
    124  
    125   inline void ManagedDelete() 
    126   { 
    127     this->port.GetWrapped()->ManagedDelete(); 
    128     tPortPack < TPort, TTypeList, Tsize - 1 >::ManagedDelete(); 
    129   } 
    130  
    131 //---------------------------------------------------------------------- 
    132 // Private fields and methods 
    133 //---------------------------------------------------------------------- 
    134  
    135 private: 
    136  
    137   TPort < typename TTypeList::template tAt < Tsize - 1 >::tResult > port; 
    138  
    139 }; 
    140  
    141 //! The partial specialization of tPortPack to terminate recursion 
    142 template <template <typename> class TPort, typename TTypeList> 
    143 struct tPortPack <TPort, TTypeList, 0> 
    144 { 
    145   inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix) 
    146   {} 
    147  
    148   template <typename TIterator> 
    149   inline tPortPack(core::tFrameworkElement *parent, TIterator names_begin, TIterator names_end) 
    150   {} 
    151  
    152   inline core::tPortWrapperBase &GetPort(size_t index) 
    153   { 
    154     return *reinterpret_cast<core::tPortWrapperBase *>(0); 
    155   }; 
    156   inline void ManagedDelete() 
     302    tPortPack<TPort, TTypes...>(parent, name_prefix, 1) 
    157303  {} 
    158304}; 
  • tests/test_collection.cpp

    r124 r139  
    4545#include "plugins/data_ports/tThreadLocalBufferManagement.h" 
    4646#include "plugins/data_ports/tPortPack.h" 
     47 
     48#include "plugins/structure/tModule.h" 
    4749 
    4850//---------------------------------------------------------------------- 
     
    196198    void OnPortChange(const rrlib::rtti::tGenericObject& value, tChangeContext& change_context) 
    197199    { 
    198       FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic: ", value); 
     200      rrlib::serialization::tStringOutputStream stream; 
     201      value.Serialize(stream); 
     202      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic: ", stream.ToString()); 
    199203      this->calls++; 
    200204    } 
    201205    void OnPortChange(tPortDataPointer<const rrlib::rtti::tGenericObject>& value, tChangeContext& change_context) 
    202206    { 
    203       FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic (tPortDataPointer): ", *value); 
     207      rrlib::serialization::tStringOutputStream stream; 
     208      value->Serialize(stream); 
     209      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic (tPortDataPointer): ", stream.ToString()); 
    204210      this->calls++; 
    205211    } 
     
    365371} 
    366372 
     373struct mTestModule : structure::tModule 
     374{ 
     375  using tModule::tModule; 
     376  void Update() override {} 
     377}; 
     378 
     379template <typename ... T, typename NAMES> 
     380void PortPackTestHelper(core::tFrameworkElement *parent, const std::initializer_list<NAMES> &names_initializer) 
     381{ 
     382  data_ports::tPortPack<mTestModule::tInput, T...> ports(parent, "X"); 
     383 
     384  RRLIB_UNIT_TESTS_EQUALITY(sizeof...(T), ports.NumberOfPorts()); 
     385  for (size_t i = 0; i < sizeof...(T); ++i) 
     386  { 
     387    RRLIB_UNIT_TESTS_EQUALITY("X" + std::to_string(i), ports.GetPort(i).GetName()); 
     388  } 
     389 
     390  std::array<NAMES, sizeof...(T)> names; 
     391  assert(names_initializer.size() == names.size()); 
     392  std::copy(names_initializer.begin(), names_initializer.end(), names.begin()); 
     393  data_ports::tPortPack<tInputPort, T...> named_ports(parent, names.begin(), names.end()); 
     394 
     395  RRLIB_UNIT_TESTS_EQUALITY(sizeof...(T), named_ports.NumberOfPorts()); 
     396  for (size_t i = 0; i < sizeof...(T); ++i) 
     397  { 
     398    RRLIB_UNIT_TESTS_EQUALITY(std::string(names[i]), named_ports.GetPort(i).GetName()); 
     399  } 
     400} 
     401 
    367402class DataPortsTestCollection : public rrlib::util::tUnitTestSuite 
    368403{ 
     
    370405  RRLIB_UNIT_TESTS_ADD_TEST(Test); 
    371406  RRLIB_UNIT_TESTS_ADD_TEST(PortPack); 
     407  RRLIB_UNIT_TESTS_ADD_TEST(PortPackLegacy); 
    372408  RRLIB_UNIT_TESTS_END_SUITE; 
    373409 
     
    399435  void PortPack() 
    400436  { 
    401     auto parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortPack"); 
     437    auto parent = new mTestModule(&core::tRuntimeEnvironment::GetInstance(), "TestModule"); 
     438 
     439    PortPackTestHelper<int, double, std::string, bool>(parent, {"foo", "bar", "baz", "fnord"}); 
     440 
     441    std::array<std::string, 0> empty_names; 
     442    RRLIB_UNIT_TESTS_EQUALITY(size_t(0), data_ports::tPortPack<mTestModule::tInput>(parent, "X").NumberOfPorts()); 
     443    RRLIB_UNIT_TESTS_EQUALITY(size_t(0), data_ports::tPortPack<mTestModule::tInput>(parent, empty_names.begin(), empty_names.end()).NumberOfPorts()); 
     444  } 
     445 
     446  void PortPackLegacy() 
     447  { 
     448    auto parent = new mTestModule(&core::tRuntimeEnvironment::GetInstance(), "TestModule"); 
    402449 
    403450    using tTypeList = rrlib::util::tTypeList<int, double, std::string, bool>; 
    404     data_ports::tPortPack<tInputPort, tTypeList> ports(parent, "X"); 
     451    data_ports::tPortPack<mTestModule::tInput, tTypeList> ports(parent, "X"); 
    405452 
    406453    RRLIB_UNIT_TESTS_EQUALITY(tTypeList::cSIZE, ports.NumberOfPorts()); 
     
    412459 
    413460    std::array<std::string, tTypeList::cSIZE> names {"foo", "bar", "baz", "fnord"}; 
    414     data_ports::tPortPack<tInputPort, tTypeList> named_ports(parent, names.begin(), names.end()); 
     461    data_ports::tPortPack<mTestModule::tInput, tTypeList> named_ports(parent, names.begin(), names.end()); 
    415462 
    416463    for (size_t i = 0; i < tTypeList::cSIZE; ++i) 
Note: See TracChangeset for help on using the changeset viewer.