SMACC2
Loading...
Searching...
No Matches
introspection.hpp
Go to the documentation of this file.
1// Copyright 2025 Robosoft Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20
21#pragma once
22
23#include <boost/statechart/event.hpp>
24#include <boost/statechart/simple_state.hpp>
25#include <boost/statechart/state.hpp>
26
27#include <boost/mpl/for_each.hpp>
28#include <boost/mpl/list.hpp>
29#include <boost/mpl/transform.hpp>
30#include <rclcpp/rclcpp.hpp>
31#include <typeinfo>
32
36
37#include <cxxabi.h>
38#include "smacc2_msgs/msg/smacc_transition.hpp"
39
40namespace sc = boost::statechart;
41
42namespace smacc2
43{
44namespace introspection
45{
46using namespace boost;
48
50 const SmaccTransitionInfo & transition, smacc2_msgs::msg::SmaccTransition & transitionMsg);
51
52typedef std::allocator<boost::statechart::none> SmaccAllocator;
53
54template <class T>
55auto optionalNodeHandle(std::shared_ptr<T> & obj) -> T *
56{
57 return obj.get;
58}
59
60template <class T>
61auto optionalNodeHandle(boost::intrusive_ptr<T> & obj) -> T *
62{
63 return obj.get();
64}
65
66template <class T>
67auto optionalNodeHandle(T * obj) -> T *
68{
69 return obj;
70}
71
72inline std::string demangleSymbol(const std::string & name) { return demangleSymbol(name.c_str()); }
73
74inline std::string demangleSymbol(const char * name)
75{
76#if (__GNUC__ && __cplusplus && __GNUC__ >= 3)
77 int status;
78 char * res = abi::__cxa_demangle(name, 0, 0, &status);
79 if (res)
80 {
81 const std::string demangled_name(res);
82 std::free(res);
83 return demangled_name;
84 }
85 // Demangling failed, fallback to mangled name
86 return std::string(name);
87#else
88 return std::string(name);
89#endif
90}
91
92template <typename T>
93inline std::string demangleSymbol()
94{
95 return demangleSymbol(typeid(T).name());
96}
97
98template <class T>
99inline std::string demangledTypeName()
100{
101 return demangleSymbol(typeid(T).name());
102}
103
104inline std::string demangleType(const std::type_info * tinfo)
105{
106 return demangleSymbol(tinfo->name());
107}
108
109inline std::string demangleType(const std::type_info & tinfo)
110{
111 return demangleSymbol(tinfo.name());
112}
113
114template <typename...>
116{
117};
118
119//-------------------------------------------------------------------------
120template <typename T>
122{
123private:
124 typedef char YesType[1];
125 typedef char NoType[2];
126
127 template <typename C>
128 static YesType & test(decltype(&C::getEventLabel));
129 template <typename C>
130 static NoType & test(...);
131
132public:
133 enum
134 {
135 value = sizeof(test<T>(0)) == sizeof(YesType)
136 };
137};
138
139template <typename T>
140typename std::enable_if<HasEventLabel<T>::value, void>::type EventLabel(std::string & label)
141{
142 label = T::getEventLabel();
143}
144
145template <typename T>
146typename std::enable_if<!HasEventLabel<T>::value, void>::type EventLabel(std::string & label)
147{
148 label = "";
149}
150//-----------------------------------------------------------------------
151
152template <typename T>
154{
155private:
156 typedef char YesType[1];
157 typedef char NoType[2];
158
159 template <typename C>
160 static YesType & test(decltype(&C::getDefaultTransitionTag));
161 template <typename C>
162 static NoType & test(...);
163
164public:
165 enum
166 {
167 value = sizeof(test<T>(0)) == sizeof(YesType)
168 };
169};
170
171template <typename T>
172typename std::enable_if<HasAutomaticTransitionTag<T>::value, void>::type automaticTransitionTag(
173 std::string & transition_name)
174{
175 transition_name = T::getDefaultTransitionTag();
176}
177
178template <typename T>
179typename std::enable_if<!HasAutomaticTransitionTag<T>::value, void>::type automaticTransitionTag(
180 std::string & transition_name)
181{
182 transition_name = "";
183}
184
185//-------------------------------------------------
186template <typename T>
188{
189private:
190 typedef char YesType[1];
191 typedef char NoType[2];
192
193 template <typename C>
194 static YesType & test(decltype(&C::getDefaultTransitionType));
195 template <typename C>
196 static NoType & test(...);
197
198public:
199 enum
200 {
201 value = sizeof(test<T>(0)) == sizeof(YesType)
202 };
203};
204
205template <typename T>
206typename std::enable_if<HasAutomaticTransitionType<T>::value, void>::type automaticTransitionType(
207 std::string & transition_type)
208{
209 transition_type = T::getDefaultTransitionType();
210}
211
212template <typename T>
213typename std::enable_if<!HasAutomaticTransitionType<T>::value, void>::type automaticTransitionType(
214 std::string & transition_type)
215{
216 transition_type = demangledTypeName<DEFAULT>();
217}
218
219// there are many ways to implement this, for instance adding static methods to the types
220typedef boost::mpl::list<SUCCESS, ABORT, CANCEL, /*PREEMPT,*/ CONTINUELOOP, ENDLOOP>
222
223//--------------------------------
224
225template <typename T>
226struct type_
227{
228 using type = T;
229};
230
231//---------------------------------------------
232template <typename T>
234{
235 using type = type_<T>;
236};
237
238template <typename TTransition>
240{
241 CheckType(std::string * transitionTypeName) { this->transitionTypeName = transitionTypeName; }
242
243 std::string * transitionTypeName;
244 template <typename T>
246 {
247 //RCLCPP_INFO_STREAM(nh_->get_logger(),"comparing.."<< demangleSymbol<T>() <<" vs " << demangleSymbol<TTransition>() );
248 if (std::is_base_of<T, TTransition>::value || std::is_same<T, TTransition>::value)
249 {
251 //RCLCPP_INFO(nh_->get_logger(),"YESS!");
252 }
253 }
254};
255
256template <typename TTransition>
257static std::string getTransitionType()
258{
259 std::string output;
260 CheckType<TTransition> op(&output);
261 using boost::mpl::_1;
262 using wrappedList = typename boost::mpl::transform<DEFAULT_TRANSITION_TYPES, _1>::type;
263
264 boost::mpl::for_each<wrappedList>(op);
265 return output;
266}
267
268} // namespace introspection
269} // namespace smacc2
static YesType & test(decltype(&C::getDefaultTransitionTag))
static YesType & test(decltype(&C::getDefaultTransitionType))
static YesType & test(decltype(&C::getEventLabel))
boost::mpl::list< SUCCESS, ABORT, CANCEL, CONTINUELOOP, ENDLOOP > DEFAULT_TRANSITION_TYPES
std::enable_if< HasAutomaticTransitionType< T >::value, void >::type automaticTransitionType(std::string &transition_type)
auto optionalNodeHandle(std::shared_ptr< T > &obj) -> T *
std::enable_if< HasEventLabel< T >::value, void >::type EventLabel(std::string &label)
static std::string getTransitionType()
std::allocator< boost::statechart::none > SmaccAllocator
std::string demangleSymbol()
std::enable_if< HasAutomaticTransitionTag< T >::value, void >::type automaticTransitionTag(std::string &transition_name)
std::string demangledTypeName()
std::string demangleType(const std::type_info *tinfo)
void transitionInfoToMsg(const SmaccTransitionInfo &transition, smacc2_msgs::msg::SmaccTransition &transitionMsg)
CheckType(std::string *transitionTypeName)