source: finroc_plugins_data_ports/tPortPack.h @ 126:abc5db1233c8

17.03
Last change on this file since 126:abc5db1233c8 was 126:abc5db1233c8, checked in by Tobias Föhst <foehst@…>, 2 years ago

Reimplements tPortPack via std::tuple for proper initialization, typed access and access via integer sequences

File size: 11.0 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    std::vector<bool> changed_flags = this->GetChangedFlags(tIndex()); // TODO: std::vector<bool> may be replaced by auto in c++14 and gcc < 4.9 to avoid heap allocation
177    return changed_flags[index];
178  }
179
180  /*! Check if any port in the pack has changed
181   *
182   * \return Whether any port in the pack has changed
183   */
184  inline bool Changed()
185  {
186    std::vector<bool> changed_flags = this->GetChangedFlags(tIndex()); // TODO: std::vector<bool> may be replaced by auto in c++14 and gcc < 4.9 to avoid heap allocation
187    return std::any_of(changed_flags.begin(), changed_flags.end(), [](bool x)
188    {
189      return x;
190    });
191  }
192
193  /*! Publish a tuple of value through this port pack (only for output ports)
194   *
195   * \param values      A tuple of values that can be published via this portspacks ports
196   * \param timestamp   An optional timestamp to use (default: cNO_TIME)
197   */
198  template <typename ... TValues>
199  inline void Publish(const std::tuple<TValues...> &values, const rrlib::time::tTimestamp timestamp = rrlib::time::cNO_TIME)
200  {
201    this->DispatchPublisher(tIndex(), values, timestamp);
202  }
203
204  /*! Deletion of the port pack's ports
205   */
206  inline void ManagedDelete()
207  {
208    this->ManagedDelete(tIndex());
209  }
210
211//----------------------------------------------------------------------
212// Protected methods
213//----------------------------------------------------------------------
214protected:
215
216  /*! Ctor with common port name prefix and port number offset to support legacy code
217   *
218   * The port names will follow the scheme "<prefix> [<offset>..]"
219   *
220   * \param parent        The parent framework element
221   * \param name_prefix   The common prefix used for all port names
222   * \param offset        Offset for numbering the created ports
223   */
224  inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix, size_t offset)
225  {
226    this->DispatchInitializer(parent, tIndex(), [&name_prefix, offset](size_t i)
227    {
228      return name_prefix + std::to_string(i + offset);
229    });
230  }
231
232//----------------------------------------------------------------------
233// Private fields and methods
234//----------------------------------------------------------------------
235private:
236
237  tPorts ports;
238  core::tPortWrapperBase *port_wrappers[sizeof...(TTypes)];
239
240  template <size_t Tindex>
241  int InitializePort(core::tFrameworkElement *parent, const std::string &name)
242  {
243    std::get<Tindex>(this->ports).reset(new typename std::tuple_element<Tindex, std::tuple<TPort<TTypes>...>>::type(name, parent));
244    std::get<Tindex>(this->ports)->Init();
245    return 0;
246  }
247
248  template <int ... Tindex, typename TNameGenerator>
249  void DispatchInitializer(core::tFrameworkElement *parent, rrlib::util::tIntegerSequence<Tindex...>, TNameGenerator name_generator)
250  {
251    __attribute__((unused)) int foo[] = { InitializePort<Tindex>(parent, name_generator(Tindex))... };
252    auto port_wrappers = std::initializer_list<core::tPortWrapperBase *> {std::get<Tindex>(this->ports).get()...};
253    std::copy(port_wrappers.begin(), port_wrappers.end(), this->port_wrappers);
254  }
255
256  template <typename T, typename TValue>
257  int PublishPort(T &port, const TValue &value, const rrlib::time::tTimestamp &timestamp)
258  {
259    port.Publish(value, timestamp);
260    return 0;
261  }
262  template <int ... Tindex, typename ... TValues>
263  void DispatchPublisher(rrlib::util::tIntegerSequence<Tindex...>, const std::tuple<TValues...> &values, const rrlib::time::tTimestamp timestamp)
264  {
265    __attribute__((unused)) int foo[] = { PublishPort(*std::get<Tindex>(this->ports), std::get<Tindex>(values), timestamp)... };
266  }
267
268  template <int ... Tindex>
269  inline std::initializer_list<bool> GetChangedFlags(rrlib::util::tIntegerSequence<Tindex...>)
270  {
271    return { std::get<Tindex>(this->ports)->HasChanged()..., false };
272  }
273
274  template <int ... Tindex>
275  inline void ManagedDelete(rrlib::util::tIntegerSequence<Tindex...>)
276  {
277    for (auto p : this->port_wrappers)
278    {
279      p->GetWrapped()->ManagedDelete();
280    }
281  }
282
283};
284
285/*!
286 * This class creates a list of instances of the given port template
287 * inserting several types from a list.  It therefore creates a nested
288 * structure of inherited classes and provides a method to access the
289 * port on a specific layer at runtime.
290 *
291 * \note This class exists to support legacy code that used the initial
292 *       version with tTypeList and 1-based port numbers.
293 *
294 * \param TPort       A port class template to use for every packed port
295 * \param TTypeList   A list of the data types used in the ports. e.g. rrlib::util::tTypeList
296 */
297template <template <typename> class TPort, typename ... TTypes>
298class tPortPack<TPort, rrlib::util::tTypeList<TTypes...>> : public tPortPack<TPort, TTypes...>
299{
300public:
301  using tPortPack<TPort, TTypes...>::tPortPack;
302  inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix) :
303    tPortPack<TPort, TTypes...>(parent, name_prefix, 1)
304  {}
305};
306
307//----------------------------------------------------------------------
308// End of namespace declaration
309//----------------------------------------------------------------------
310}
311}
312
313#endif
Note: See TracBrowser for help on using the repository browser.