source: finroc_plugins_data_ports/tPortPack.h @ 139:b80094f9fac6

Last change on this file since 139:b80094f9fac6 was 139:b80094f9fac6, checked in by Max Reichardt <mreichardt@…>, 10 months ago

Merge with 17.03

File size: 10.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/data_ports/tPortPack.h
23 *
24 * \author  Tobias Föhst
25 *
26 * \date    2012-10-18
27 *
28 * \brief   Contains tPortPack
29 *
30 * \b tPortPack
31 *
32 * A group of several ports with different types.
33 *
34 */
35//----------------------------------------------------------------------
36#ifndef __plugins__data_ports__tPortPack_h__
37#define __plugins__data_ports__tPortPack_h__
38
39//----------------------------------------------------------------------
40// External includes (system with <>, local with "")
41//----------------------------------------------------------------------
42#include "core/tFrameworkElement.h"
43#include "core/log_messages.h"
44#include "rrlib/util/tIteratorRange.h"
45#include "rrlib/util/tIntegerSequence.h"
46
47#include "rrlib/util/tTypeList.h"
48
49//----------------------------------------------------------------------
50// Internal includes with ""
51//----------------------------------------------------------------------
52
53//----------------------------------------------------------------------
54// Namespace declaration
55//----------------------------------------------------------------------
56namespace finroc
57{
58namespace data_ports
59{
60
61//----------------------------------------------------------------------
62// Forward declarations / typedefs / enums
63//----------------------------------------------------------------------
64
65//----------------------------------------------------------------------
66// Class declaration
67//----------------------------------------------------------------------
68//! 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
284/*!
285 * This class creates a list of instances of the given port template
286 * inserting several types from a list.  It therefore creates a nested
287 * structure of inherited classes and provides a method to access the
288 * port on a specific layer at runtime.
289 *
290 * \note This class exists to support legacy code that used the initial
291 *       version with tTypeList and 1-based port numbers.
292 *
293 * \param TPort       A port class template to use for every packed port
294 * \param TTypeList   A list of the data types used in the ports. e.g. rrlib::util::tTypeList
295 */
296template <template <typename> class TPort, typename ... TTypes>
297class tPortPack<TPort, rrlib::util::tTypeList<TTypes...>> : public tPortPack<TPort, TTypes...>
298{
299public:
300  using tPortPack<TPort, TTypes...>::tPortPack;
301  inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix) :
302    tPortPack<TPort, TTypes...>(parent, name_prefix, 1)
303  {}
304};
305
306//----------------------------------------------------------------------
307// End of namespace declaration
308//----------------------------------------------------------------------
309}
310}
311
312#endif
Note: See TracBrowser for help on using the repository browser.