Changeset 126:abc5db1233c8 in finroc_plugins_data_ports
- Timestamp:
- 22.05.2017 01:34:21 (4 years ago)
- Branch:
- 17.03
- Phase:
- public
- Rebase:
- 62653330613263653936313863323438366631643662373766666265396264646361373266326563
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
tPortPack.h
r125 r126 40 40 // External includes (system with <>, local with "") 41 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 42 47 #include "rrlib/util/tTypeList.h" 43 #include "core/tFrameworkElement.h"44 48 45 49 //---------------------------------------------------------------------- … … 63 67 //---------------------------------------------------------------------- 64 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 65 285 /*! 66 286 * This class creates a list of instances of the given port template … … 69 289 * port on a specific layer at runtime. 70 290 * 291 * \note This class exists to support legacy code that used the initial 292 * version with tTypeList and 1-based port numbers. 293 * 71 294 * \param TPort A port class template to use for every packed port 72 295 * \param TTypeList A list of the data types used in the ports. e.g. rrlib::util::tTypeList 73 * \param Tsize The pack creates ports using TTypeList[0] to TTypeList[Tsize - 1]. This parameter must not be greater than TTypeList::cSIZE - 1 and is typically inferred and not set by the user.74 296 */ 75 template <template <typename> class TPort, typename TTypeList, size_t Tsize = rrlib::util::type_list::tSizeOf<TTypeList>::cVALUE>76 class tPortPack : private tPortPack < TPort, TTypeList, Tsize - 1>297 template <template <typename> class TPort, typename ... TTypes> 298 class tPortPack<TPort, rrlib::util::tTypeList<TTypes...>> : public tPortPack<TPort, TTypes...> 77 299 { 78 79 template <bool value, typename>80 using CheckIterators = std::integral_constant<bool, value>;81 82 //----------------------------------------------------------------------83 // Public methods and typedefs84 //----------------------------------------------------------------------85 300 public: 86 301 using tPortPack<TPort, TTypes...>::tPortPack; 87 302 inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix) : 88 tPortPack < TPort, TTypeList, Tsize - 1 > (parent, name_prefix), 89 port(name_prefix + std::to_string(Tsize), parent) 90 { 91 this->port.Init(); 92 } 93 94 template <typename TIterator, typename std::enable_if<CheckIterators<(Tsize> 1), TIterator>::value, int>::type = 0 > 95 inline tPortPack(core::tFrameworkElement *parent, TIterator names_begin, TIterator names_end) : 96 tPortPack < TPort, TTypeList, Tsize - 1 > (parent, names_begin, names_end - 1), 97 port(*(names_end - 1), parent) 98 { 99 this->port.Init(); 100 } 101 102 template <typename TIterator, typename std::enable_if<CheckIterators<(Tsize == 1), TIterator>::value, int>::type = 0> 103 inline tPortPack(core::tFrameworkElement *parent, TIterator names_begin, TIterator names_end) : 104 tPortPack < TPort, TTypeList, Tsize - 1 > (parent, *names_begin), 105 port(*names_begin, parent) 106 { 107 this->port.Init(); 108 } 109 110 inline size_t NumberOfPorts() const 111 { 112 return Tsize; 113 } 114 115 inline core::tPortWrapperBase &GetPort(size_t index) 116 { 117 assert(index < this->NumberOfPorts()); 118 if (index == Tsize - 1) 119 { 120 return this->port; 121 } 122 return tPortPack < TPort, TTypeList, Tsize - 1 >::GetPort(index); 123 } 124 125 inline bool HasChanged(size_t index) 126 { 127 assert(index < this->NumberOfPorts()); 128 if (index == Tsize - 1) 129 { 130 return this->port.HasChanged(); 131 } 132 return tPortPack < TPort, TTypeList, Tsize - 1 >::HasChanged(index); 133 } 134 135 inline void ManagedDelete() 136 { 137 this->port.GetWrapped()->ManagedDelete(); 138 tPortPack < TPort, TTypeList, Tsize - 1 >::ManagedDelete(); 139 } 140 141 //---------------------------------------------------------------------- 142 // Private fields and methods 143 //---------------------------------------------------------------------- 144 145 private: 146 147 TPort < typename TTypeList::template tAt < Tsize - 1 >::tResult > port; 148 149 }; 150 151 //! The partial specialization of tPortPack to terminate recursion 152 template <template <typename> class TPort, typename TTypeList> 153 struct tPortPack <TPort, TTypeList, 0> 154 { 155 inline tPortPack(core::tFrameworkElement *parent, const std::string &name_prefix) 156 {} 157 158 template <typename TIterator> 159 inline tPortPack(core::tFrameworkElement *parent, TIterator names_begin, TIterator names_end) 160 {} 161 162 inline core::tPortWrapperBase &GetPort(size_t index) 163 { 164 return *reinterpret_cast<core::tPortWrapperBase *>(0); 165 }; 166 167 inline bool HasChanged(size_t index) 168 { 169 return false; 170 }; 171 172 inline void ManagedDelete() 303 tPortPack<TPort, TTypes...>(parent, name_prefix, 1) 173 304 {} 174 305 }; -
tests/test_collection.cpp
r125 r126 45 45 #include "plugins/data_ports/tThreadLocalBufferManagement.h" 46 46 #include "plugins/data_ports/tPortPack.h" 47 48 #include "plugins/structure/tModule.h" 47 49 48 50 //---------------------------------------------------------------------- … … 369 371 } 370 372 373 struct mTestModule : structure::tModule 374 { 375 using tModule::tModule; 376 void Update() override {} 377 }; 378 379 template <typename ... T, typename NAMES> 380 void PortPackTestHelper(core::tFrameworkElement *parent, const std::initializer_list<NAMES> &names_initializer) 381 { 382 data_ports::tPortPack<mTestModule::tInput, T...> ports(parent, "X"); 383 384 RRLIB_UNIT_TESTS_EQUALITY(sizeof...(T), ports.NumberOfPorts()); 385 for (size_t i = 0; i < sizeof...(T); ++i) 386 { 387 RRLIB_UNIT_TESTS_EQUALITY("X" + std::to_string(i), ports.GetPort(i).GetName()); 388 } 389 390 std::array<NAMES, sizeof...(T)> names; 391 assert(names_initializer.size() == names.size()); 392 std::copy(names_initializer.begin(), names_initializer.end(), names.begin()); 393 data_ports::tPortPack<tInputPort, T...> named_ports(parent, names.begin(), names.end()); 394 395 RRLIB_UNIT_TESTS_EQUALITY(sizeof...(T), named_ports.NumberOfPorts()); 396 for (size_t i = 0; i < sizeof...(T); ++i) 397 { 398 RRLIB_UNIT_TESTS_EQUALITY(std::string(names[i]), named_ports.GetPort(i).GetName()); 399 } 400 } 401 371 402 class DataPortsTestCollection : public rrlib::util::tUnitTestSuite 372 403 { … … 374 405 RRLIB_UNIT_TESTS_ADD_TEST(Test); 375 406 RRLIB_UNIT_TESTS_ADD_TEST(PortPack); 407 RRLIB_UNIT_TESTS_ADD_TEST(PortPackLegacy); 376 408 RRLIB_UNIT_TESTS_END_SUITE; 377 409 … … 403 435 void PortPack() 404 436 { 405 auto parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortPack"); 437 auto parent = new mTestModule(&core::tRuntimeEnvironment::GetInstance(), "TestModule"); 438 439 PortPackTestHelper<int, double, std::string, bool>(parent, {"foo", "bar", "baz", "fnord"}); 440 441 std::array<std::string, 0> empty_names; 442 RRLIB_UNIT_TESTS_EQUALITY(size_t(0), data_ports::tPortPack<mTestModule::tInput>(parent, "X").NumberOfPorts()); 443 RRLIB_UNIT_TESTS_EQUALITY(size_t(0), data_ports::tPortPack<mTestModule::tInput>(parent, empty_names.begin(), empty_names.end()).NumberOfPorts()); 444 } 445 446 void PortPackLegacy() 447 { 448 auto parent = new mTestModule(&core::tRuntimeEnvironment::GetInstance(), "TestModule"); 406 449 407 450 using tTypeList = rrlib::util::tTypeList<int, double, std::string, bool>; 408 data_ports::tPortPack< tInputPort, tTypeList> ports(parent, "X");451 data_ports::tPortPack<mTestModule::tInput, tTypeList> ports(parent, "X"); 409 452 410 453 RRLIB_UNIT_TESTS_EQUALITY(tTypeList::cSIZE, ports.NumberOfPorts()); … … 416 459 417 460 std::array<std::string, tTypeList::cSIZE> names {"foo", "bar", "baz", "fnord"}; 418 data_ports::tPortPack< tInputPort, tTypeList> named_ports(parent, names.begin(), names.end());461 data_ports::tPortPack<mTestModule::tInput, tTypeList> named_ports(parent, names.begin(), names.end()); 419 462 420 463 for (size_t i = 0; i < tTypeList::cSIZE; ++i)
Note: See TracChangeset
for help on using the changeset viewer.