source: finroc_plugins_structure/tConveniencePort.h @ 136:632254c6a691

17.03
Last change on this file since 136:632254c6a691 was 136:632254c6a691, checked in by Max Reichardt <mreichardt@…>, 3 years ago

Fixes compiler warning with gcc 9.3 (swapping base classes initializes convenience port construction concern before any use)

File size: 10.8 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/structure/tConveniencePort.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2012-12-02
27 *
28 * \brief   Contains tConveniencePort
29 *
30 * \b tConveniencePort
31 *
32 * Base class for ports that are typically used inside
33 * groups and modules from an application developer.
34 *
35 * In many cases (if plain member variable of a group or module)
36 * it is able to determine its name and parent automatically.
37 */
38//----------------------------------------------------------------------
39#ifndef __plugins__structure__tConveniencePort_h__
40#define __plugins__structure__tConveniencePort_h__
41
42//----------------------------------------------------------------------
43// External includes (system with <>, local with "")
44//----------------------------------------------------------------------
45#include "core/port/tPortGroup.h"
46#include "plugins/data_ports/definitions.h"
47#include "plugins/parameters/tStaticParameter.h"
48
49//----------------------------------------------------------------------
50// Internal includes with ""
51//----------------------------------------------------------------------
52#include "plugins/structure/internal/register.h"
53
54//----------------------------------------------------------------------
55// Namespace declaration
56//----------------------------------------------------------------------
57namespace finroc
58{
59namespace structure
60{
61
62//----------------------------------------------------------------------
63// Forward declarations / typedefs / enums
64//----------------------------------------------------------------------
65
66enum class tNoArgument
67{
68  NONE
69};
70
71class tConveniencePortBase
72{};
73
74//! Uniform handling of ports and parameters concern (as used in components)
75template <typename TPort>
76class tBasicConveniencePort : public TPort, public tConveniencePortBase
77{
78public:
79  using TPort::TPort;
80
81  /*!
82   * (relevant for input ports and parameters only)
83   *
84   * \return Has port changed since last reset?
85   */
86  bool HasChanged()
87  {
88    return TPort::GetWrapped()->GetCustomChangedFlag() != data_ports::tChangeStatus::NO_CHANGE;
89  }
90
91  /*!
92   * Resets port's changed flag
93   * (both "real" port's and the one for the custom API)
94   * (usually does not need to be called - only if you want to ignore more changes)
95   */
96  void ResetChanged()
97  {
98    TPort::GetWrapped()->ResetChanged();
99    TPort::GetWrapped()->SetCustomChangedFlag(data_ports::tChangeStatus::NO_CHANGE);
100  }
101};
102
103template <typename T>
104class tBasicConveniencePort<parameters::tStaticParameter<T>> : public parameters::tStaticParameter<T>, public tConveniencePortBase
105{
106public:
107  using parameters::tStaticParameter<T>::tStaticParameter;
108};
109
110
111/*! Construction concern of convenience ports */
112template <typename TElement, typename TContainer, TContainer& (TElement::*GET_CONTAINER)()>
113class tConveniencePortConstruction
114{
115public:
116
117  typedef TElement tComponent;
118
119  /*!
120   * \param component Parent component (group or module)
121   * \return Component interface to add port to
122   */
123  static TContainer& GetParentInterface(tComponent& component)
124  {
125    return (component.*GET_CONTAINER)();
126  }
127
128//----------------------------------------------------------------------
129// Protected methods
130//----------------------------------------------------------------------
131protected:
132
133  /*! Processes port creation info for this convenience port */
134  void AdjustCreationInfo(core::tAbstractPortCreationInfo& info)
135  {
136    if (!info.flags.Get(core::tFrameworkElementFlag::READY))
137    {
138      // covered by port-name builder
139      if (info.name.length() == 0)
140      {
141        info.name = this->GetPortName();
142      }
143      else
144      {
145        if (!info.parent)
146        {
147          this->UpdateCurrentPortNameIndex(this->FindParent());
148        }
149        else
150        {
151          this->UpdateCurrentPortNameIndex(static_cast<TElement*>(info.parent));
152        }
153      }
154    }
155    if (!info.flags.Get(core::tFrameworkElementFlag::DELETED))
156    {
157      if (!info.parent)
158      {
159        info.parent = &(this->FindParent()->*GET_CONTAINER)();
160      }
161      else if (tComponent::IsComponent(info.parent))
162      {
163        info.parent = &(static_cast<TElement*>(info.parent)->*GET_CONTAINER)();
164      }
165    }
166    if (info.parent && typeid(*info.parent) == typeid(core::tPortGroup))
167    {
168      info.flags |= static_cast<core::tPortGroup*>(info.parent)->GetDefaultPortFlags();
169    }
170  }
171
172  /*! \return Parent module of parameter */
173  TElement* FindParent()
174  {
175    return static_cast<TElement*>(internal::FindParent(this));
176  }
177
178  /*! Get auto-generated port name */
179  std::string GetPortName()
180  {
181    TElement* parent = FindParent();
182    return internal::GetAutoGeneratedPortName(parent, UpdateCurrentPortNameIndex());
183  }
184
185  /*!
186   * Create port creation info for this convenience port (non-template constructor)
187   */
188  core::tAbstractPortCreationInfo MakeStandardCreationInfo(const std::string& name, core::tFrameworkElement* parent)
189  {
190    core::tAbstractPortCreationInfo result;
191    result.name = name;
192    result.parent = parent;
193    if (result.parent && typeid(*result.parent) == typeid(core::tPortGroup))
194    {
195      result.flags |= static_cast<core::tPortGroup*>(result.parent)->GetDefaultPortFlags();
196    }
197    return result;
198  }
199
200  /*! Get & update current index for auto-generated port names */
201  int UpdateCurrentPortNameIndex(TElement* parent = NULL)
202  {
203    if (parent == NULL)
204    {
205      parent = FindParent();
206    }
207    if (typeid(*parent).name() != parent->count_for_type) // detect class change when traversing module type hierarchy
208    {
209      parent->count_for_type = typeid(*parent).name();
210      parent->auto_name_port_count = 0;
211    }
212    int current_index = parent->auto_name_port_count;
213    parent->auto_name_port_count++;
214    return current_index;
215  }
216};
217
218
219//----------------------------------------------------------------------
220// Class declaration
221//----------------------------------------------------------------------
222//! Convenience port
223/*!
224 * Base class for ports that are typically used inside
225 * groups and modules from an application developer.
226 *
227 * In many cases (if plain member variable of a group or module)
228 * it is able to determine its name and parent automatically.
229 *
230 * \tparam TPort  Port class that this class derives from
231 * \tparam TElement Framework element class these ports belong to (typically group or module)
232 * \tparam TContainer  Framework element type this port will be child of (typically port group)
233 * \tparam GET_CONTAINER  Function that returns framework element to add port to (typically port group)
234 */
235template <typename TPort, typename TElement, typename TContainer, TContainer& (TElement::*GET_CONTAINER)()>
236class tConveniencePort : public tConveniencePortConstruction<TElement, TContainer, GET_CONTAINER>, public tBasicConveniencePort<TPort>
237{
238  typedef typename TPort::tConstructorParameters tConstructorParameters;
239  typedef core::tPortWrapperBase::tConstructorArguments<tConstructorParameters> tConstructorArguments;
240  typedef tBasicConveniencePort<TPort> tBasePort;
241
242//----------------------------------------------------------------------
243// Public methods and typedefs
244//----------------------------------------------------------------------
245public:
246
247  tConveniencePort() : tBasePort(this->MakeStandardCreationInfo(this->GetPortName(), &(this->FindParent()->*GET_CONTAINER)())) {}
248
249  /*!
250   * Constructor takes variadic argument list... just any properties you want to assign to port.
251   *
252   * Unlike tPort, port name and parent are determined automatically
253   * (this is, however, only possible when port is direct class member of the component).
254   * If this is not possible/desired, the name needs to be provided as first constructor argument - and the parent as an arbitrary one.
255   *
256   * So...
257   *
258   * A string as first parameter is interpreted as port name; Any other string as config entry (relevant for parameters only).
259   * A framework element pointer is interpreted as parent.
260   * tFrameworkElement::tFlags arguments are interpreted as flags.
261   * A tQueueSettings argument creates an input queue with the specified settings.
262   * tBounds<T> are port's bounds.
263   * const T& is interpreted as port's default value.
264   * tConstructorParameters argument is copied.
265   *
266   * This becomes a little tricky when T is a string type. There we have these rules:
267   * A String not provided as first argument is interpreted as default value.
268   * Any further string is interpreted as config entry.
269   */
270  template<typename T1, typename T2, typename ... TRest>
271  explicit tConveniencePort(T1&& arg1, T2&& arg2, TRest&&... rest) :
272    tBasePort(MakeCreationInfo(std::forward<T1>(arg1), std::forward<T2>(arg2), std::forward<TRest>(rest)...))
273  {}
274
275  // with a single argument, do not catch calls for copy construction
276  template < typename T1, typename = typename std::enable_if < (!data_ports::IsString<T1>::value) && (!std::is_base_of<tConveniencePortBase, typename std::decay<T1>::type>::value), int >::type >
277  explicit tConveniencePort(T1 && arg1) :
278    tBasePort(MakeCreationInfo(std::forward<T1>(arg1)))
279  {}
280  explicit tConveniencePort(const std::string& arg1) :
281    tBasePort(MakeCreationInfo(arg1))
282  {}
283
284//----------------------------------------------------------------------
285// Private fields and methods
286//----------------------------------------------------------------------
287private:
288
289  /*!
290   * Create port creation info for this convenience port (template constructors)
291   */
292  template<typename A1, typename ... ARest>
293  tConstructorParameters MakeCreationInfo(A1&& arg1, ARest&&... rest)
294  {
295    tConstructorParameters arguments = data_ports::IsString<A1>::value ? core::tPortWrapperBase::tConstructorArguments<tConstructorParameters>(arg1, rest...) : core::tPortWrapperBase::tConstructorArguments<tConstructorParameters>("", arg1, rest...);
296    this->AdjustCreationInfo(arguments);
297    return arguments;
298  }
299
300};
301
302//----------------------------------------------------------------------
303// End of namespace declaration
304//----------------------------------------------------------------------
305}
306}
307
308
309#endif
Note: See TracBrowser for help on using the repository browser.