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#pragma once
5#include <type_traits>
6#include <array>
7#include <string>
8#include <sstream>
9#include <stdexcept>
10
11#include "TClass.h"
12#include "TMethod.h"
13#include "TROOT.h"
14#include "TInterpreter.h"
15#include "TVirtualMutex.h"
16#include "TGenericClassInfo.h"
17
19
20namespace RootUtils {
21template<typename T>
22constexpr auto getPtr(typename std::remove_reference<T>::type& arg) noexcept {
23 // the interface requires that the argument list is a list of non-const void pointers
24 // It is assumed that the argument types have been checked before hand.
25 auto non_const_arg ATLAS_THREAD_SAFE = const_cast<std::remove_cvref<T>::type *>( &arg);
26 return non_const_arg;
27}
28
29template <typename ...T_MethodArgs>
30class ClingCallWrapperUncheckedReturnValue;
31template <typename T_ReturnValue, typename ...T_MethodArgs>
32class ClingCallWrapper;
33
34template <typename ...T_MethodArgs>
35ClingCallWrapperUncheckedReturnValue<T_MethodArgs...> getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const);
36
37template <typename T_ReturnValue, typename ...T_MethodArgs>
38ClingCallWrapper<T_ReturnValue, T_MethodArgs...> getClingCallWrapperChecked(ClingCallWrapperUncheckedReturnValue<T_MethodArgs...> &&call_wrapper);
39
44// @TODO add access policy to also handle non-const methods securely
45template <typename ...T_MethodArgs>
47 template<typename ...T_MethodArgsFunc>
48 friend ClingCallWrapperUncheckedReturnValue<T_MethodArgsFunc...> getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const);
49
50 template <typename T_ReturnValue, typename ...T_MethodArgsFunc>
52
53protected:
54 // @brief The function prototype of the function returned by TMethod::InterfaceMethod:
55 // @param obj pointer to the object.
56 // @param nargs number of method arguments (excluding the this pointer).
57 // @param arg_list array of void pointers, pointing to each of the nargs arguments.
58 // @param ret_val pointer where the return value is to be stored.
59 using TClingCallFuncWrapper_t = void (*)(void* /*obj*/, int /* nargs*/, void** /*arg_list*/, void* /*ret_val*/);
60
62 : m_methodWrapper(method_wrapper),
63 m_method(method) {}
64
65 template<typename T_ReturnType>
66 T_ReturnType call(const void *object, T_MethodArgs...args) const {
67 T_ReturnType return_value;
68 std::array<void *, sizeof...(args)> arg_list{getPtr<T_MethodArgs>(args)...};
69
70 // it was already checked that the method is declared const
71 // the interface however requires a non const void pointer to the object independent of
72 // of the method being const or non-const.
73 void *non_const_obj ATLAS_THREAD_SAFE=const_cast<void *>(object);
74 m_methodWrapper(non_const_obj, arg_list.size(),arg_list.data(),&return_value);
75 return return_value;
76 }
77public:
80 template<typename T_ReturnType>
81 bool isReturnTypeMatching() const {
82 return ROOT::Internal::GetDemangledTypeName(typeid(T_ReturnType)) == m_method->GetReturnTypeNormalizedName();
83 }
84
86 std::string getReturnTypeNormalizedName() const {
87 return m_method->GetReturnTypeNormalizedName();
88 }
89private:
91 const TMethod *m_method = nullptr;
92 TMethodCall::EReturnType m_returnType;
93};
94
98template <typename T_ReturnValue, typename ...T_MethodArgs>
100{
101template <typename T_ReturnValueFunc, typename ...T_MethodArgsFunc>
103
104protected:
109
113public:
119 // was used the create this wrapper, the result will be undefined.
120 T_ReturnValue operator()(const void *object, T_MethodArgs...args) const {
121 return this->template call<T_ReturnValue>(object, args...);
122 }
123};
124
129template <typename ...T_MethodArgs>
130struct ArgGen {
131static std::string addArgumentPrototype(std::string &arg_proto_type);
132};
133
134// specialization for an empty argument list.
135template <>
136struct ArgGen<> {
137static std::string addArgumentPrototype([[maybe_unused]] std::string &arg_proto_type) {
138 return std::string();
139}
140};
141
142// implementation for an non-empty argument list.
143template <typename T_First, typename ...T_MethodArgs>
144struct ArgGen<T_First, T_MethodArgs...> {
145static void addArgumentPrototype(std::string &arg_proto_type) {
146 if (!arg_proto_type.empty()) {
147 arg_proto_type+=",";
148 }
149 else {
150 constexpr unsigned int avTypeNameLength = 20;
151 arg_proto_type.reserve(sizeof...(T_MethodArgs) * avTypeNameLength);
152 }
153 arg_proto_type += ROOT::Internal::GetDemangledTypeName(typeid(T_First));
155}
156};
157
161template <typename ...T_MethodArgs>
163 std::string ret;
165 return ret;
166}
167
179template <typename ...T_MethodArgs>
180ClingCallWrapperUncheckedReturnValue<T_MethodArgs...> getClingCallWrapper(TClass *the_class, const std::string &method_name, bool is_const) {
181 R__LOCKGUARD(gROOTMutex);
182 const TMethod *method = the_class->GetMethodWithPrototype(method_name.c_str(),
184 is_const,
185 ROOT::kConversionMatch);
186 if (!method) {
187 std::stringstream amsg; amsg << "Failed to get method " << method_name << "(" << makeArgumentPrototype<T_MethodArgs...>() << ").";
188 throw std::runtime_error(amsg.str());
189 }
190 MethodInfo_t *method_info=gInterpreter->MethodInfo_Factory(method->GetDeclId());
191 static constexpr unsigned int flags = (kIsStatic|kIsPublic);
192 unsigned int method_properties = gInterpreter->MethodInfo_Property(method_info);
193 if ( (method_properties & flags) != kIsPublic ) {
194 std::runtime_error("Method is not public or is static.");
195 }
196 if (is_const && (method_properties & kIsConstant) != kIsConstant) {
197 std::runtime_error("Method is not constant.");
198 }
199 using TheClingCallWrapper_t = ClingCallWrapperUncheckedReturnValue<T_MethodArgs...>;
200
201 return TheClingCallWrapper_t(reinterpret_cast<TheClingCallWrapper_t::TClingCallFuncWrapper_t>(method->InterfaceMethod()),method);
202}
203
209template <typename T_ReturnValue, typename ...T_MethodArgs>
211 if (!call_wrapper.template isReturnTypeMatching<T_ReturnValue>()) {
212 std::stringstream amsg;
213 amsg << "Return type mismatch. Desired "
214 << ROOT::Internal::GetDemangledTypeName(typeid(T_ReturnValue))
215 << " != is " << call_wrapper.getReturnTypeNormalizedName();
216 throw std::runtime_error(amsg.str());
217 }
218 return ClingCallWrapper<T_ReturnValue, T_MethodArgs...>(std::forward<decltype(call_wrapper)>(call_wrapper));
219}
220}
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.
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)