ATLAS Offline Software
Loading...
Searching...
No Matches
ClingCallWrapper.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4#ifndef ROOTUTILS_CLINGCALLWRAPPER_H
5#define ROOTUTILS_CLINGCALLWRAPPER_H
6
8
9#include <type_traits>
10#include <array>
11#include <string>
12#include <sstream>
13#include <stdexcept>
14
15#include "TClass.h"
16#include "TMethod.h"
17#include "TROOT.h"
18#include "TInterpreter.h"
19#include "TVirtualMutex.h"
20#include "TGenericClassInfo.h"
21
23
24namespace RootUtils {
25template<typename T>
26constexpr auto getPtr(typename std::remove_reference<T>::type& arg) noexcept {
27 // the interface requires that the argument list is a list of non-const void pointers
28 // It is assumed that the argument types have been checked before hand.
29 auto non_const_arg ATLAS_THREAD_SAFE = const_cast<std::remove_cvref<T>::type *>( &arg);
30 return non_const_arg;
31}
32
33template <typename ...T_MethodArgs>
34class ClingCallWrapperUncheckedReturnValue;
35template <typename T_ReturnValue, typename ...T_MethodArgs>
36class ClingCallWrapper;
37
38template <typename ...T_MethodArgs>
39ClingCallWrapperUncheckedReturnValue<T_MethodArgs...> getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const);
40
41template <typename T_ReturnValue, typename ...T_MethodArgs>
42ClingCallWrapper<T_ReturnValue, T_MethodArgs...> getClingCallWrapperChecked(ClingCallWrapperUncheckedReturnValue<T_MethodArgs...> &&call_wrapper);
43
48// @TODO add access policy to also handle non-const methods securely
49template <typename ...T_MethodArgs>
51 template<typename ...T_MethodArgsFunc>
52 friend ClingCallWrapperUncheckedReturnValue<T_MethodArgsFunc...> getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const);
53
54 template <typename T_ReturnValue, typename ...T_MethodArgsFunc>
56
57protected:
58 // @brief The function prototype of the function returned by TMethod::InterfaceMethod:
59 // @param obj pointer to the object.
60 // @param nargs number of method arguments (excluding the this pointer).
61 // @param arg_list array of void pointers, pointing to each of the nargs arguments.
62 // @param ret_val pointer where the return value is to be stored.
63 using TClingCallFuncWrapper_t = void (*)(void* /*obj*/, int /* nargs*/, void** /*arg_list*/, void* /*ret_val*/);
64
66 : m_methodWrapper(method_wrapper),
67 m_method(method) {}
68
69 template<typename T_ReturnType>
70 T_ReturnType call(const void *object, T_MethodArgs...args) const {
71 T_ReturnType return_value;
72 std::array<void *, sizeof...(args)> arg_list{getPtr<T_MethodArgs>(args)...};
73
74 // it was already checked that the method is declared const
75 // the interface however requires a non const void pointer to the object independent of
76 // of the method being const or non-const.
77 void *non_const_obj ATLAS_THREAD_SAFE=const_cast<void *>(object);
78 m_methodWrapper(non_const_obj, arg_list.size(),arg_list.data(),&return_value);
79 return return_value;
80 }
81public:
84 template<typename T_ReturnType>
85 bool isReturnTypeMatching() const {
86 return ROOT::Internal::GetDemangledTypeName(typeid(T_ReturnType)) == m_method->GetReturnTypeNormalizedName();
87 }
88
90 std::string getReturnTypeNormalizedName() const {
91 return m_method->GetReturnTypeNormalizedName();
92 }
93private:
95 const TMethod *m_method = nullptr;
96 TMethodCall::EReturnType m_returnType{};
97};
98
102template <typename T_ReturnValue, typename ...T_MethodArgs>
104{
105template <typename T_ReturnValueFunc, typename ...T_MethodArgsFunc>
107
108protected:
113
117public:
123 // was used the create this wrapper, the result will be undefined.
124 T_ReturnValue operator()(const void *object, T_MethodArgs...args) const {
125 return this->template call<T_ReturnValue>(object, args...);
126 }
127};
128
133template <typename ...T_MethodArgs>
134struct ArgGen {
135static std::string addArgumentPrototype(std::string &arg_proto_type);
136};
137
138// specialization for an empty argument list.
139template <>
140struct ArgGen<> {
141static std::string addArgumentPrototype([[maybe_unused]] std::string &arg_proto_type) {
142 return std::string();
143}
144};
145
146// implementation for an non-empty argument list.
147template <typename T_First, typename ...T_MethodArgs>
148struct ArgGen<T_First, T_MethodArgs...> {
149static void addArgumentPrototype(std::string &arg_proto_type) {
150 if (!arg_proto_type.empty()) {
151 arg_proto_type+=",";
152 }
153 else {
154 constexpr unsigned int avTypeNameLength = 20;
155 arg_proto_type.reserve(sizeof...(T_MethodArgs) * avTypeNameLength);
156 }
157 arg_proto_type += ROOT::Internal::GetDemangledTypeName(typeid(T_First));
159}
160};
161
165template <typename ...T_MethodArgs>
167 std::string ret;
169 return ret;
170}
171
183template <typename ...T_MethodArgs>
184ClingCallWrapperUncheckedReturnValue<T_MethodArgs...> getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const) {
185 R__LOCKGUARD(gROOTMutex);
186 const TMethod *method = the_class->GetMethodWithPrototype(method_name.c_str(),
188 is_const,
189 ROOT::kConversionMatch);
190 if (!method) {
191 std::stringstream amsg; amsg << "Failed to get method " << method_name << "(" << makeArgumentPrototype<T_MethodArgs...>() << ").";
192 throw std::runtime_error(amsg.str());
193 }
194 MethodInfo_t *method_info=gInterpreter->MethodInfo_Factory(method->GetDeclId());
195 static constexpr unsigned int flags = (kIsStatic|kIsPublic);
196 unsigned int method_properties = gInterpreter->MethodInfo_Property(method_info);
197 if ( (method_properties & flags) != kIsPublic ) {
198 std::runtime_error("Method is not public or is static.");
199 }
200 if (is_const && (method_properties & kIsConstant) != kIsConstant) {
201 std::runtime_error("Method is not constant.");
202 }
203 using TheClingCallWrapper_t = ClingCallWrapperUncheckedReturnValue<T_MethodArgs...>;
204
205 return TheClingCallWrapper_t(reinterpret_cast<TheClingCallWrapper_t::TClingCallFuncWrapper_t>(method->InterfaceMethod()),method);
206}
207
213template <typename T_ReturnValue, typename ...T_MethodArgs>
215 if (!call_wrapper.template isReturnTypeMatching<T_ReturnValue>()) {
216 std::stringstream amsg;
217 amsg << "Return type mismatch. Desired "
219 << " != is " << call_wrapper.getReturnTypeNormalizedName();
220 throw std::runtime_error(amsg.str());
221 }
222 return ClingCallWrapper<T_ReturnValue, T_MethodArgs...>(std::forward<decltype(call_wrapper)>(call_wrapper));
223}
224}
225#endif
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
Intermediate helper class wrapping a cling method call with arbitrary return type.
T_ReturnType call(const void *object, T_MethodArgs...args) const
std::string getReturnTypeNormalizedName() const
the normalized name of the function return type.
ClingCallWrapperUncheckedReturnValue(TClingCallFuncWrapper_t method_wrapper, const TMethod *method)
void(*)(void *, int, void **, void *) TClingCallFuncWrapper_t
bool isReturnTypeMatching() const
Test whether the function return type and the template parameter are the same.
friend ClingCallWrapper< T_ReturnValue, T_MethodArgsFunc... > getClingCallWrapperChecked(ClingCallWrapperUncheckedReturnValue< T_MethodArgsFunc... > &&call_wrapper)
friend ClingCallWrapperUncheckedReturnValue< T_MethodArgsFunc... > getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const)
helper method to wrap a method of a certain name with defined arguments, but arbitrary return type im...
Helper class to wrap a cling method call of an object's method with defined return type and argument ...
friend ClingCallWrapper< T_ReturnValueFunc, T_MethodArgsFunc... > getClingCallWrapperChecked(ClingCallWrapperUncheckedReturnValue< T_MethodArgsFunc... > &&call_wrapper)
T_ReturnValue operator()(const void *object, T_MethodArgs...args) const
call the wrapped cling method.
ClingCallWrapper(const ClingCallWrapperUncheckedReturnValue< T_MethodArgs... > &call_wrapper)
create a cling method wrapper for a method with defined argument list and return type (copy).
ClingCallWrapper(ClingCallWrapperUncheckedReturnValue< T_MethodArgs... > &&call_wrapper)
create a cling method wrapper for a method with defined argument list and return type (move).
std::string makeArgumentPrototype()
template function to create a argument list prototype from a type list.
ClingCallWrapper< T_ReturnValue, T_MethodArgs... > getClingCallWrapperChecked(ClingCallWrapperUncheckedReturnValue< T_MethodArgs... > &&call_wrapper)
wrap a cling method call for a method with defined arguments and return types.
std::string getNormalizedTypeName()
constexpr auto getPtr(typename std::remove_reference< T >::type &arg) noexcept
ClingCallWrapperUncheckedReturnValue< T_MethodArgs... > getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const)
helper method to wrap a method of a certain name with defined arguments, but arbitrary return type im...
STL namespace.
static void addArgumentPrototype(std::string &arg_proto_type)
static std::string addArgumentPrototype(std::string &arg_proto_type)
helper template to turn an argument list into a prototype string.
static std::string addArgumentPrototype(std::string &arg_proto_type)