source: finroc_plugins_data_ports/tGenericPort.h @ 41:eb5957b12387

Last change on this file since 41:eb5957b12387 was 41:eb5957b12387, checked in by Max Reichardt <mreichardt@…>, 6 years ago

Refactored implementation of variadic argument constructors in port wrapper classes.

File size: 11.6 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
8// modify it under the terms of the GNU General Public License
9// as published by the Free Software Foundation; either version 2
10// of the License, or (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
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20//
21//----------------------------------------------------------------------
22/*!\file    plugins/data_ports/tGenericPort.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2012-10-24
27 *
28 * \brief   Contains tGenericPort
29 *
30 * \b tGenericPort
31 *
32 * Wrapper class for ports whose type is not known at compile time.
33 *
34 * (note: Get and Publish are currently only implemented based on deep-copying data.
35 *  Therefore, Generic ports are only efficient for data types that can be copied cheaply)
36 */
37//----------------------------------------------------------------------
38#ifndef __plugins__data_ports__tGenericPort_h__
39#define __plugins__data_ports__tGenericPort_h__
40
41//----------------------------------------------------------------------
42// External includes (system with <>, local with "")
43//----------------------------------------------------------------------
44#include "core/port/tPortWrapperBase.h"
45
46//----------------------------------------------------------------------
47// Internal includes with ""
48//----------------------------------------------------------------------
49#include "plugins/data_ports/api/tGenericPortImplementation.h"
50
51//----------------------------------------------------------------------
52// Namespace declaration
53//----------------------------------------------------------------------
54namespace finroc
55{
56namespace data_ports
57{
58
59//----------------------------------------------------------------------
60// Forward declarations / typedefs / enums
61//----------------------------------------------------------------------
62
63namespace api
64{
65template <typename LISTENER, bool FIRST_LISTENER>
66class tPortListenerAdapterGeneric;
67template <typename LISTENER, bool FIRST_LISTENER>
68class tPortListenerAdapterGenericForPointer;
69}
70
71//----------------------------------------------------------------------
72// Class declaration
73//----------------------------------------------------------------------
74//! Generic port
75/*!
76 * Wrapper class for ports whose type is not known at compile time.
77 *
78 * (note: Get and Publish are currently only implemented based on deep-copying data.
79 *  Therefore, Generic ports are only efficient for data types that can be copied cheaply)
80 */
81class tGenericPort : public core::tPortWrapperBase
82{
83
84//----------------------------------------------------------------------
85// Public methods and typedefs
86//----------------------------------------------------------------------
87public:
88
89  /*!
90   * Empty constructor in case port is created later
91   */
92  tGenericPort() :
93    implementation()
94  {}
95
96  /*!
97   * Constructor takes variadic argument list... just any properties you want to assign to port.
98   *
99   * The first string is interpreted as port name, the second possibly as config entry (relevant for parameters only).
100   * A framework element pointer is interpreted as parent.
101   * unsigned int arguments are interpreted as flags.
102   * A tQueueSettings argument creates an input queue with the specified settings.
103   * tBounds<T> are port's bounds.
104   * tUnit argument is port's unit.
105   * tPortCreationBase argument is copied. This is only allowed as first argument.
106   */
107  template <typename ... ARGS>
108  tGenericPort(const ARGS&... args)
109  {
110    tConstructorArguments<common::tAbstractDataPortCreationInfo> creation_info(args...);
111    if ((creation_info.data_type.GetTypeTraits() & rrlib::rtti::trait_flags::cIS_BINARY_SERIALIZABLE) == 0)
112    {
113      throw std::runtime_error("Only binary serializable types may be used in data ports");
114    }
115    implementation = api::tGenericPortImplementation::GetImplementation(creation_info.data_type);
116    SetWrapped(implementation->CreatePort(creation_info));
117  }
118
119  /*!
120   * \param listener Listener to add
121   *
122   * \tparam LISTENER Listener class needs to implement a method
123   * void PortChanged(const rrlib::rtti::tGenericObject& value, tChangeContext& change_context)
124   *
125   * (It's preferred to add listeners before port is initialized)
126   * (Note: Buffer in 'value' always has data type of port backend (e.g. tNumber instead of double)
127   */
128  template <typename TListener>
129  void AddPortListener(TListener& listener);
130
131  /*!
132   * \param listener Listener to add
133   *
134   * \tparam LISTENER Listener class needs to implement a method
135   * void PortChanged(tPortDataPointer<const rrlib::rtti::tGenericObject>& value, tChangeContext& change_context)
136   *
137   * (It's preferred to add listeners before port is initialized)
138   * (Note: Buffer in 'value' always has data type of port backend (e.g. tNumber instead of double)
139   */
140  template <typename TListener>
141  void AddPortListenerForPointer(TListener& listener);
142
143  /*!
144   * \param listener Listener to add
145   *
146   * \tparam LISTENER Listener class needs to implement a method
147   * void PortChanged(tChangeContext& change_context)
148   *
149   * (It's preferred to add listeners before port is initialized)
150   */
151  template <typename TListener>
152  void AddPortListenerSimple(TListener& listener);
153
154  /*!
155   * Publish buffer through port
156   * (not in normal operation, but from browser; difference: listeners on this port will be notified)
157   *
158   * \param pointer Buffer with data
159   * \param notify_listener_on_this_port Notify listener on this port?
160   * \param change_constant Change constant to use for publishing operation
161   * \return Error message if something did not work
162   */
163  inline std::string BrowserPublish(tPortDataPointer<rrlib::rtti::tGenericObject>& pointer, bool notify_listener_on_this_port = true,
164                                    tChangeStatus change_constant = tChangeStatus::CHANGED)
165  {
166    if (IsCheaplyCopiedType(pointer->GetType()))
167    {
168      typename optimized::tCheapCopyPort::tUnusedManagerPointer pointer2(static_cast<optimized::tCheaplyCopiedBufferManager*>(pointer.implementation.Release()));
169      return static_cast<optimized::tCheapCopyPort*>(GetWrapped())->BrowserPublishRaw(pointer2, notify_listener_on_this_port, change_constant);
170    }
171    else
172    {
173      typename standard::tStandardPort::tUnusedManagerPointer pointer2(static_cast<standard::tPortBufferManager*>(pointer.implementation.Release()));
174      static_cast<standard::tStandardPort*>(GetWrapped())->BrowserPublish(pointer2, notify_listener_on_this_port, change_constant);
175    }
176    return "";
177  }
178
179  /*!
180   * Gets port's current value
181   *
182   * \param result Buffer to (deep) copy port's current value to
183   * \param timestamp Buffer to copy timestamp attached to data to (optional)
184   */
185  inline void Get(rrlib::rtti::tGenericObject& result)
186  {
187    rrlib::time::tTimestamp timestamp;
188    Get(result, timestamp);
189  }
190  inline void Get(rrlib::rtti::tGenericObject& result, rrlib::time::tTimestamp& timestamp)
191  {
192    implementation->Get(*GetWrapped(), result, timestamp);
193  }
194
195  /*!
196   * Gets Port's current value in buffer
197   *
198   * \param strategy Strategy to use for get operation
199   * \return Buffer with port's current value with read lock.
200   *
201   * Note: Buffer always has data type of port backend (e.g. tNumber instead of double)
202   * If this is not desired, use pass-by-value-Get Operation above.
203   */
204  inline tPortDataPointer<const rrlib::rtti::tGenericObject> GetPointer(tStrategy strategy = tStrategy::DEFAULT)
205  {
206    return implementation->GetPointer(*GetWrapped(), strategy);
207  }
208
209  /*!
210   * \return Port's default value (NULL if none has been set)
211   */
212  const rrlib::rtti::tGenericObject* GetDefaultValue()
213  {
214    return implementation->GetDefaultValue(*GetWrapped());
215  }
216
217  /*!
218   * Note: Buffer always has data type of port backend (e.g. tNumber instead of double)
219   * If this is not desired, use pass-by-value-Publish Operation below.
220   *
221   * \return Unused buffer.
222   * Buffers to be published using this port should be acquired using this function.
223   * The buffer might contain old data, so it should be cleared prior to using.
224   */
225  inline tPortDataPointer<rrlib::rtti::tGenericObject> GetUnusedBuffer()
226  {
227    return implementation->GetUnusedBuffer(*GetWrapped());
228  }
229
230  /*!
231   * \return Wrapped port. For rare case that someone really needs to access ports.
232   */
233  inline common::tAbstractDataPort* GetWrapped() const
234  {
235    return static_cast<common::tAbstractDataPort*>(tPortWrapperBase::GetWrapped());
236  }
237
238  /*!
239   * Publish Data Buffer. This data will be forwarded to any connected ports.
240   * Should only be called on output ports.
241   *
242   * \param data Data to publish. It will be deep-copied.
243   * \param timestamp Timestamp to attach to data.
244   */
245  inline void Publish(const rrlib::rtti::tGenericObject& data, const rrlib::time::tTimestamp& timestamp = rrlib::time::cNO_TIME)
246  {
247    implementation->Publish(*GetWrapped(), data, timestamp);
248  }
249
250  /*!
251   * Set new bounds
252   * (This is not thread-safe and must only be done in "pause mode")
253   *
254   * \param b New Bounds
255   */
256  inline void SetBounds(const rrlib::rtti::tGenericObject& min, const rrlib::rtti::tGenericObject& max)
257  {
258    implementation->SetBounds(*GetWrapped(), min, max);
259  }
260
261  /*!
262   * \param pull_request_handler Object that handles any incoming pull requests - null if there is none (typical case)
263   */
264  void SetPullRequestHandler(tPullRequestHandler<rrlib::rtti::tGenericObject>* pull_request_handler)
265  {
266    implementation->SetPullRequestHandler(*GetWrapped(), pull_request_handler);
267  }
268
269  /*!
270   * Wraps raw port
271   * Throws std::runtime_error if port to wrap has invalid type.
272   *
273   * \param wrap Type-less tAbstractPort to wrap as tGenericPort
274   * \param use_backend_type_only Use only the internal data type that used in the port backend? (e.g. tNumber instead of double; relevant e.g. for Get() and Publish() methods)
275   */
276  static tGenericPort Wrap(core::tAbstractPort& wrap, bool use_backend_type_only = false)
277  {
278    if (!IsDataFlowType(wrap.GetDataType()))
279    {
280      throw std::runtime_error(wrap.GetDataType().GetName() + " is no data flow type and cannot be wrapped.");
281    }
282    tGenericPort port;
283    port.SetWrapped(&wrap);
284    port.implementation = api::tGenericPortImplementation::GetImplementation(
285                            ((!use_backend_type_only) && wrap.GetWrapperDataType() != NULL) ? wrap.GetWrapperDataType() : wrap.GetDataType());
286    return port;
287  }
288
289//----------------------------------------------------------------------
290// Private fields and methods
291//----------------------------------------------------------------------
292private:
293
294  template <typename LISTENER, bool FIRST_LISTENER>
295  friend class api::tPortListenerAdapterGeneric;
296  template <typename LISTENER, bool FIRST_LISTENER>
297  friend class api::tPortListenerAdapterGenericForPointer;
298
299  /** Implementation of port functionality */
300  api::tGenericPortImplementation* implementation;
301
302};
303
304//----------------------------------------------------------------------
305// End of namespace declaration
306//----------------------------------------------------------------------
307}
308}
309
310#include "plugins/data_ports/tInputPort.h"
311#include "plugins/data_ports/tGenericPort.hpp"
312#include "plugins/data_ports/api/tPortListenerAdapter.h"
313
314#endif
Note: See TracBrowser for help on using the repository browser.