|
34 | 34 | #ifndef FUSE_PUBLISHERS_STAMPED_VARIABLE_SYNCHRONIZER_H |
35 | 35 | #define FUSE_PUBLISHERS_STAMPED_VARIABLE_SYNCHRONIZER_H |
36 | 36 |
|
37 | | -#include <fuse_core/graph.h> |
38 | | -#include <fuse_core/fuse_macros.h> |
39 | | -#include <fuse_core/transaction.h> |
40 | | -#include <fuse_core/uuid.h> |
41 | | -#include <fuse_core/variable.h> |
42 | | -#include <fuse_variables/stamped.h> |
43 | | -#include <ros/time.h> |
| 37 | +#include <fuse_variables/stamped_variable_synchronizer.h> |
44 | 38 |
|
45 | | -#include <type_traits> |
46 | | - |
47 | | - |
48 | | -namespace fuse_publishers |
49 | | -{ |
50 | | - |
51 | | -/** |
52 | | - * @brief A utility class that finds the most recent timestamp shared by a set of stamped variables |
53 | | - * |
54 | | - * This is designed to be used by derived fuse_core::Publisher classes. The class remembers the last common timestamp |
55 | | - * from the previous call, and attempts to find a more recent common timestamp using the provided transaction |
56 | | - * information. If no common timestamp is found after searching the transaction, a full search of the graph will |
57 | | - * be conducted. If no common timestamp is found after searching the full graph, a zero timestamp will be returned. |
58 | | - * |
59 | | - * The set of variable types are provided in the template parameters. e.g. |
60 | | - * @code{.cpp} |
61 | | - * auto synchronizer = StampedVariableSynchronizer<Orientation2DStamped, Position2DStamped>(device_id); |
62 | | - * @endcode |
63 | | - * |
64 | | - * This class only functions with variables derived from the fuse_variables::Stamped base class. |
65 | | - */ |
66 | | -template <typename ...Ts> |
67 | | -class StampedVariableSynchronizer |
68 | | -{ |
69 | | -public: |
70 | | - FUSE_SMART_PTR_DEFINITIONS(StampedVariableSynchronizer); |
71 | | - static const ros::Time TIME_ZERO; //!< Constant representing a zero timestamp |
72 | | - |
73 | | - /** |
74 | | - * @brief Construct a synchronizer object |
75 | | - * |
76 | | - * @param[in] device_id The device id to use for all variable types |
77 | | - */ |
78 | | - explicit StampedVariableSynchronizer(const fuse_core::UUID& device_id = fuse_core::uuid::NIL); |
79 | | - |
80 | | - /** |
81 | | - * @brief Find the latest timestamp for which variables of all the specified template types exist in the graph |
82 | | - * |
83 | | - * @param[in] transaction A fuse_core::Transaction object containing the changes to the graph since the last call |
84 | | - * @param[in] graph The complete graph |
85 | | - * @return The latest timestamp shared by all requested variable types |
86 | | - */ |
87 | | - ros::Time findLatestCommonStamp(const fuse_core::Transaction& transaction, const fuse_core::Graph& graph); |
88 | | - |
89 | | -private: |
90 | | - fuse_core::UUID device_id_; //!< The device_id to use with the Stamped classes |
91 | | - ros::Time latest_common_stamp_; //!< The previously discovered common stamp |
92 | | - |
93 | | - /** |
94 | | - * @brief Search the variables in the provided range for more recent timestamps. Update the \p latest_common_stamp_ |
95 | | - * member variable if a newer common timestamp is found. |
96 | | - * |
97 | | - * @param[in] variable_range The collection of variables to test |
98 | | - * @param[in] graph The complete graph, used to verify that all requested variables exist for a given time |
99 | | - */ |
100 | | - template <typename VariableRange> |
101 | | - void updateTime(const VariableRange& variable_range, const fuse_core::Graph& graph); |
102 | | -}; |
103 | | - |
104 | | -namespace detail |
105 | | -{ |
106 | | - |
107 | | -/** |
108 | | - * @brief Some helper structs for testing properties of all types in a template parameter pack |
109 | | - */ |
110 | | -template<bool...> struct bool_pack; |
111 | | -template<bool ...bs> |
112 | | -using all_true_helper = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>; |
113 | | - |
114 | | -/** |
115 | | - * @brief Test if a property is true for all types in a template parameter pack. This is a type. |
116 | | - */ |
117 | | -template <typename ...Ts> |
118 | | -using all_true = all_true_helper<Ts::value...>; |
119 | | - |
120 | | -/** |
121 | | - * @brief Test if a property is true for all types in a template parameter pack. This is a boolean value. |
122 | | - */ |
123 | | -template<typename ...Ts> |
124 | | -constexpr bool allTrue = all_true<Ts...>::value; |
125 | | - |
126 | | -/** |
127 | | - * @brief Test if a class is derived from the fuse_variables::Stamped base class. This is a type. |
128 | | - */ |
129 | | -template<typename T> |
130 | | -using is_stamped = std::is_base_of<fuse_variables::Stamped, T>; |
131 | | - |
132 | | -/** |
133 | | - * @brief Test if a class is derived from the fuse_variables::Stamped base class. This is a boolean value. |
134 | | - */ |
135 | | -template<typename T> |
136 | | -constexpr bool isStamped = is_stamped<T>::value; |
137 | | - |
138 | | -/** |
139 | | - * @brief Test if a class is derived from the fuse_core::Variable base class. This is a type. |
140 | | - */ |
141 | | -template<typename T> |
142 | | -using is_variable = std::is_base_of<fuse_core::Variable, T>; |
143 | | - |
144 | | -/** |
145 | | - * @brief Test if a class is derived from the fuse_core::Variable base class. This is a boolean value. |
146 | | - */ |
147 | | -template<typename T> |
148 | | -constexpr bool isVariable = is_variable<T>::value; |
149 | | - |
150 | | -/** |
151 | | - * @brief Test if a class is derived from both the fuse_core::Variable base class and the fuse_variables::Stamped |
152 | | - * base class. This is a type. |
153 | | - */ |
154 | | -template<typename T> |
155 | | -struct is_stamped_variable |
156 | | -{ |
157 | | - static constexpr bool value = isStamped<T> && isVariable<T>; |
158 | | -}; |
159 | | - |
160 | | -/** |
161 | | - * @brief Test if a class is derived from both the fuse_core::Variable base class and the fuse_variables::Stamped |
162 | | - * base class. This is a boolean value. |
163 | | - */ |
164 | | -template<typename T> |
165 | | -constexpr bool isStampedVariable = is_stamped_variable<T>::value; |
166 | | - |
167 | | -/** |
168 | | - * @brief Test if all of the template parameter pack types are fuse_core::Variable and fuse_variables::Stamped. |
169 | | - * This is a type. |
170 | | - */ |
171 | | -template <typename ...Ts> |
172 | | -using all_stamped_variables = all_true<is_stamped_variable<Ts>...>; |
173 | | - |
174 | | -/** |
175 | | - * @brief Test if all of the template parameter pack types are fuse_core::Variable and fuse_variables::Stamped. |
176 | | - * This is a boolean value. |
177 | | - */ |
178 | | -template<typename ...Ts> |
179 | | -constexpr bool allStampedVariables = all_stamped_variables<Ts...>::value; |
180 | | - |
181 | | -/** |
182 | | - * @brief Test if instances of all the template parameter pack types exist in the graph |
183 | | - * |
184 | | - * This version accepts an empty parameter pack, and is used to terminate the recursive template parameter pack |
185 | | - * expansion. |
186 | | - * |
187 | | - * This would be much easier to write in C++17 using 'if constexpr (sizeof...(Ts) > 0)' |
188 | | - * |
189 | | - * @param[in] graph The complete graph, used to verify the existence of a variable |
190 | | - * @param[in] stamp The timestamp used to construct all variable types |
191 | | - * @param[in] device_id The device id used to construct all variable types |
192 | | - * @return True if all variables exist, false otherwise |
193 | | - */ |
194 | | -template <typename...> |
195 | | -struct all_variables_exist |
196 | | -{ |
197 | | - static bool value(const fuse_core::Graph& /*graph*/, const ros::Time& /*stamp*/, const fuse_core::UUID& /*device_id*/) |
198 | | - { |
199 | | - return true; |
200 | | - } |
201 | | -}; |
202 | | - |
203 | | -/** |
204 | | - * @brief Test if instances of all the template parameter pack types exist in the graph |
205 | | - * |
206 | | - * This version accepts two or more template arguments. The template parameter pack is expanded recursively. |
207 | | - * |
208 | | - * @param[in] graph The complete graph, used to verify the existence of a variable |
209 | | - * @param[in] stamp The timestamp used to construct all variable types |
210 | | - * @param[in] device_id The device id used to construct all variable types |
211 | | - * @return True if all variables exist, false otherwise |
212 | | - */ |
213 | | -template <typename T, typename ...Ts> |
214 | | -struct all_variables_exist<T, Ts...> |
215 | | -{ |
216 | | - static bool value(const fuse_core::Graph& graph, const ros::Time& stamp, const fuse_core::UUID& device_id) |
217 | | - { |
218 | | - return graph.variableExists(T(stamp, device_id).uuid()) && |
219 | | - all_variables_exist<Ts...>::value(graph, stamp, device_id); |
220 | | - } |
221 | | -}; |
222 | | - |
223 | | -/** |
224 | | - * @brief Test if a given variable is included in the template parameter pack types |
225 | | - * |
226 | | - * This version accepts an empty parameter pack, and is used to terminate the recursive template parameter pack |
227 | | - * expansion. |
228 | | - * |
229 | | - * This would be much easier to write in C++17 using 'if constexpr (sizeof...(Ts) > 0)' |
230 | | - * |
231 | | - * @param[in] variable The variable to check against the template parameter pack |
232 | | - * @return True if the variable's type is part of the template parameter pack, false otherwise |
233 | | - */ |
234 | | -template <typename...> |
235 | | -struct is_variable_in_pack |
236 | | -{ |
237 | | - static bool value(const fuse_core::Variable& /*variable*/) |
238 | | - { |
239 | | - return false; |
240 | | - } |
241 | | -}; |
242 | | - |
243 | | -/** |
244 | | - * @brief Test if a given variable is included in the template parameter pack types |
245 | | - * |
246 | | - * This version accepts two or more template arguments. The template parameter pack is expanded recursively. |
247 | | - * |
248 | | - * @param[in] variable The variable to check against the template parameter pack |
249 | | - * @return True if the variable's type is part of the template parameter pack, false otherwise |
250 | | - */ |
251 | | -template <typename T, typename ...Ts> |
252 | | -struct is_variable_in_pack<T, Ts...> |
253 | | -{ |
254 | | - static bool value(const fuse_core::Variable& variable) |
255 | | - { |
256 | | - auto derived = dynamic_cast<const T*>(&variable); |
257 | | - return static_cast<bool>(derived) || |
258 | | - is_variable_in_pack<Ts...>::value(variable); |
259 | | - } |
260 | | -}; |
261 | | - |
262 | | -} // namespace detail |
263 | | - |
264 | | -template <typename ...Ts> |
265 | | -const ros::Time StampedVariableSynchronizer<Ts...>::TIME_ZERO = ros::Time(0, 0); |
266 | | - |
267 | | -template <typename ...Ts> |
268 | | -StampedVariableSynchronizer<Ts...>::StampedVariableSynchronizer(const fuse_core::UUID& device_id) : |
269 | | - device_id_(device_id), |
270 | | - latest_common_stamp_(TIME_ZERO) |
271 | | -{ |
272 | | - static_assert(detail::allStampedVariables<Ts...>, "All synchronized types must be derived from both " |
273 | | - "fuse_core::Variable and fuse_variable::Stamped."); |
274 | | - static_assert(sizeof...(Ts) > 0, "At least one type must be specified."); |
275 | | -} |
276 | | - |
277 | | -template <typename ...Ts> |
278 | | -ros::Time StampedVariableSynchronizer<Ts...>::findLatestCommonStamp( |
279 | | - const fuse_core::Transaction& transaction, |
280 | | - const fuse_core::Graph& graph) |
281 | | -{ |
282 | | - // Clear the previous stamp if the variable was deleted |
283 | | - if (latest_common_stamp_ != TIME_ZERO && |
284 | | - !detail::all_variables_exist<Ts...>::value(graph, latest_common_stamp_, device_id_)) |
285 | | - { |
286 | | - latest_common_stamp_ = TIME_ZERO; |
287 | | - } |
288 | | - // Search the transaction for more recent variables |
289 | | - updateTime(transaction.addedVariables(), graph); |
290 | | - // If no common timestamp was found, search the whole graph for the most recent variable set |
291 | | - if (latest_common_stamp_ == TIME_ZERO) |
292 | | - { |
293 | | - updateTime(graph.getVariables(), graph); |
294 | | - } |
295 | | - return latest_common_stamp_; |
296 | | -} |
297 | | - |
298 | | -template <typename ...Ts> |
299 | | -template <typename VariableRange> |
300 | | -void StampedVariableSynchronizer<Ts...>::updateTime( |
301 | | - const VariableRange& variable_range, |
302 | | - const fuse_core::Graph& graph) |
303 | | -{ |
304 | | - for (const auto& candidate_variable : variable_range) |
305 | | - { |
306 | | - if (detail::is_variable_in_pack<Ts...>::value(candidate_variable)) |
307 | | - { |
308 | | - const auto& stamped_variable = dynamic_cast<const fuse_variables::Stamped&>(candidate_variable); |
309 | | - if ((stamped_variable.stamp() > latest_common_stamp_) && |
310 | | - (stamped_variable.deviceId() == device_id_) && |
311 | | - (detail::all_variables_exist<Ts...>::value(graph, stamped_variable.stamp(), device_id_))) |
312 | | - { |
313 | | - latest_common_stamp_ = stamped_variable.stamp(); |
314 | | - } |
315 | | - } |
316 | | - } |
317 | | -} |
318 | | - |
319 | | -} // namespace fuse_publishers |
| 39 | +#pragma message("The StampedVariableSynchronizer class has been moved to the fuse_variables package. " \ |
| 40 | + "Please include that header instead.") |
320 | 41 |
|
321 | 42 | #endif // FUSE_PUBLISHERS_STAMPED_VARIABLE_SYNCHRONIZER_H |
0 commit comments