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 | //---------------------------------------------------------------------- |
---|
56 | namespace finroc |
---|
57 | { |
---|
58 | namespace 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 | */ |
---|
77 | template <template <typename> class TPort, typename ... TTypes> |
---|
78 | class 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 | //---------------------------------------------------------------------- |
---|
86 | public: |
---|
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 | //---------------------------------------------------------------------- |
---|
214 | protected: |
---|
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 | //---------------------------------------------------------------------- |
---|
235 | private: |
---|
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 ×tamp) |
---|
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 | */ |
---|
297 | template <template <typename> class TPort, typename ... TTypes> |
---|
298 | class tPortPack<TPort, rrlib::util::tTypeList<TTypes...>> : public tPortPack<TPort, TTypes...> |
---|
299 | { |
---|
300 | public: |
---|
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 |
---|