diff --git a/README/ReleaseNotes/v642/index.md b/README/ReleaseNotes/v642/index.md index e83165d9f748d..416fa70c8c2fc 100644 --- a/README/ReleaseNotes/v642/index.md +++ b/README/ReleaseNotes/v642/index.md @@ -64,6 +64,7 @@ Users are encouraged to export their models to ONNX and use the retained ONNX pa * The **RooStats::DebuggingSampler** and **RooStats::DebuggingTestStat** classes are removed. They were mock implementations of the `TestStatSampler` and `TestStatistic` interfaces that returned uniform random numbers independent of the data, only meant for debugging the RooStats framework itself during its initial development. * The `RooTrace` class is deprecated and will be removed in ROOT 6.44. It was a RooFit-specific memory tracer whose instrumentation hooks are compiled out by default, so it has been inert and untested for years. For memory debugging, please use general-purpose tools such as AddressSanitizer or Valgrind instead. * Support for the AIX operating system has been removed from the codebase. This support has not been tested since the late v5 releases and the LLVM JIT is not yet supporting AIX. +* The `ROOT::Math::ParamFunctionBase`, `ROOT::Math::ParamFunctorHandler` and `ROOT::Math::ParamMemFunHandler` classes in `Math/ParamFunctor.h` are removed, together with the `ParamFunctor::GetImpl()` and `ParamFunctor::SetFunction()` methods that exposed them. They implemented the type erasure that `ParamFunctor` now gets from `std::function`, mirroring what was already done for `ROOT::Math::Functor`. Constructing and calling a `ParamFunctor` is unchanged, except that the constructor from an object and one of its member functions now takes a plain pointer to the object instead of anything dereferenceable, so smart pointers are no longer accepted there. ## Build System diff --git a/math/mathcore/inc/Math/ParamFunctor.h b/math/mathcore/inc/Math/ParamFunctor.h index 789192f0b5600..68a0478e92d6b 100644 --- a/math/mathcore/inc/Math/ParamFunctor.h +++ b/math/mathcore/inc/Math/ParamFunctor.h @@ -9,256 +9,20 @@ **********************************************************************/ // Header file for Functor classes. -// design is inspired by the Loki Functor #ifndef ROOT_Math_ParamFunctor #define ROOT_Math_ParamFunctor -// #ifndef ROOT_Math_IFunction -// #include "Math/IFunction.h" -// #endif - -// #ifndef Root_Math_StaticCheck -// #include "Math/StaticCheck.h" -// #endif - -//#include - #include "RtypesCore.h" + #include -#include +#include +#include namespace ROOT { namespace Math { -/** - * \defgroup ParamFunctor_int N-D parametric functions - * \brief Multi-dimensional parametric functions - * \ingroup Math - */ - -/** class defining the signature for multi-dim parametric functions - - @ingroup ParamFunctor_int - */ -template -class ParamFunctionBase { - public: - virtual ~ParamFunctionBase() {} - virtual T operator() (const T * x, const double *p) = 0; - virtual T operator() (T * x, double *p) = 0; - virtual ParamFunctionBase * Clone() const = 0; -}; - - - -/** - ParamFunctor Handler class is responsible for wrapping any other functor and pointer to - free C functions. - It can be created from any function implementing the correct signature - corresponding to the requested type - - @ingroup ParamFunctor_int - -*/ - -template -class ParamFunctorHandler : public ParentFunctor::Impl { - - typedef typename ParentFunctor::EvalType EvalType; - typedef typename ParentFunctor::Impl Base; - -public: - - // constructor - ParamFunctorHandler(const Func & fun) : fFunc(fun) {} - - - virtual ~ParamFunctorHandler() {} - - - // for 1D functions - inline EvalType operator() (EvalType x, double *p) { - return fFunc(x,p); - } -// inline double operator() (double x, const double *p) const { -// return fFunc(x,p); -// } - // for multi-dimensional functions -// inline double operator() (const double * x, const double *p) const { -// return fFunc(x,p); -// } - inline EvalType operator() (EvalType * x, double *p) override { - return FuncEvaluator::Eval(fFunc,x,p); - } - - inline EvalType operator() (const EvalType * x, const double *p) override { - return FuncEvaluator::EvalConst(fFunc,x,p); - } - - // clone (use same pointer) - ParamFunctorHandler * Clone() const override { - return new ParamFunctorHandler(fFunc); - } - - -private : - - Func fFunc; - - // structure to distinguish pointer types - template struct FuncEvaluator { - inline static T Eval( F & f, T *x, double * p) { - return f(x, p); - } - - inline static T EvalConst( F & f, const T *x, const double * p) { - return f((T*)x, (double*)p); - } - }; - - template struct FuncEvaluator { - inline static T Eval( F * f, T *x, double * p) { - return (*f)(x, p); - } - - inline static T EvalConst( F * f, const T *x, const double * p) { - return (*f)((T*)x, (double*)p); - - } - }; - - template struct FuncEvaluator { - inline static T Eval( const F * f, T *x, double * p) { - return (*f)(x, p); - } - - inline static T EvalConst( const F * f, const T *x, const double * p) { - return (*f)((T*)x, (double*)p); - } - }; - - // need maybe also volatile ? -}; - - -#if defined(__ROOTCLING__) || defined(G__DICTIONARY) -// needed since Cling initialize it with TRootIOCtor -//class TRootIOCtor; -template -class ParamFunctorHandler : public ParentFunctor::Impl -{ -public: - - ParamFunctorHandler(TRootIOCtor *) {} - - double operator() (double *, double * ) { return 0; } - - double operator() (const double *, const double * ) { return 0; } - // clone (use same pointer) - ParamFunctorHandler * Clone() const { - return 0; - } - -}; -#endif - - -/** - ParamFunctor Handler to Wrap pointers to member functions - - @ingroup ParamFunctor_int -*/ -template -class ParamMemFunHandler : public ParentFunctor::Impl -{ - typedef typename ParentFunctor::Impl Base; - - -public: - - /// constructor from a pointer to the class and a pointer to the function - ParamMemFunHandler(const PointerToObj& pObj, PointerToMemFn pMemFn) - : fObj(pObj), fMemFn(pMemFn) - {} - - virtual ~ParamMemFunHandler() {} - -// inline double operator() (double x, const double * p) const { -// return ((*fObj).*fMemFn)(x,p); -// } - - inline double operator() (double x, double * p) { - return ((*fObj).*fMemFn)(x,p); - } - -// inline double operator() (const double * x, const double * p) const { -// return ((*fObj).*fMemFn)(x,p); -// } - - inline double operator() (double * x, double * p) override { - return MemFuncEvaluator::Eval(fObj,fMemFn,x,p); - } - - inline double operator() (const double * x, const double * p) override { - return MemFuncEvaluator::EvalConst(fObj,fMemFn,x,p); - } - - // clone (use same pointer) - ParamMemFunHandler * Clone() const override { - return new ParamMemFunHandler(fObj, fMemFn); - } - -private: - - // structure to distinguish pointer types - template struct MemFuncEvaluator { - inline static T Eval(PObj & pobj, F & f, T *x, double * p) { - return ((*pobj).*f)(x, p); - } - - inline static T EvalConst(PObj & pobj, F & f, const T *x, const double * p) { - return ((*pobj).*f)((T*)x, (double*)p); - } - }; - - - // // these are needed ?? - // template struct MemFuncEvaluator { - // inline static T Eval(PObj & pobj, F * f, T *x, double * p) { - // return ((*pobj).*f)f(x, p); - // } - - // inline static T EvalConst(PObj & pobj, F * f, const T *x, const double * p) { - // return ((*pobj).*f)((T*)x, (double*)p); - - // } - // }; - - // template struct FuncEvaluator { - // inline static T Eval(PObj &, const F * f, T *x, double * p) { - // return ((*pobj).*f)f(x, p); - // } - - // inline static T EvalConst(PObj & pobj, const F * f, const T *x, const double * p) { - // return ((*pobj).*f)((T*)x, (double*)p); - // } - // }; - -private : - ParamMemFunHandler(const ParamMemFunHandler&) = delete; // Not implemented - ParamMemFunHandler& operator=(const ParamMemFunHandler&) = delete; // Not implemented - - PointerToObj fObj; - PointerToMemFn fMemFn; - -}; - - - - /** Param Functor class for Multidimensional functions. It is used to wrap in a very simple and convenient way @@ -270,127 +34,71 @@ private : */ - -template -class ParamFunctorTempl { - +template +class ParamFunctorTempl { public: + using EvalType = T; - typedef T EvalType; - typedef ParamFunctionBase Impl; + /// The signature every wrapped callable is normalized to. + using Signature = T(const T *, const double *); + ParamFunctorTempl() = default; - /** - Default constructor - */ - ParamFunctorTempl () : fImpl(nullptr) {} - - - /** - construct from a pointer to member function (multi-dim type) - */ - template - ParamFunctorTempl(const PtrObj& p, MemFn memFn) - : fImpl(new ParamMemFunHandler, PtrObj, MemFn>(p, memFn)) - {} - - - - /** - construct from another generic Functor of multi-dimension - */ - template - explicit ParamFunctorTempl( const Func & f) : - fImpl(new ParamFunctorHandler,Func>(f) ) - {} - - - - // specialization used in TF1 - typedef T (* FreeFunc ) (T * , double *); - ParamFunctorTempl(FreeFunc f) : - fImpl(new ParamFunctorHandler,FreeFunc>(f) ) + /// Construct from a pointer to a class object and a pointer to one of its member + /// functions, like `Foo::EvalPar(const double *x, const double *p)`. + template + ParamFunctorTempl(Obj *p, MemFn memFn) + : fFunc{[p, memFn](const T *x, const double *par) { + return (p->*memFn)(const_cast(x), const_cast(par)); + }} { } - // specialization used in TF1 - ParamFunctorTempl(const std::function &func) : - fImpl(new ParamFunctorHandler, const std::function>(func)) + /// Construct from any callable object, or from a pointer to one. + template + explicit ParamFunctorTempl(const Func &f) : fFunc{Adapt(f)} { } - /** - Destructor (no operations) - */ - virtual ~ParamFunctorTempl () { - if (fImpl) delete fImpl; - } + /// Implicit conversion, relied on by PyROOT when passing a callable to TF1. + ParamFunctorTempl(std::function f) : fFunc{std::move(f)} {} - /** - Copy constructor - */ - ParamFunctorTempl(const ParamFunctorTempl & rhs) : - fImpl(nullptr) - { -// if (rhs.fImpl.get() != 0) -// fImpl = std::unique_ptr( (rhs.fImpl)->Clone() ); - if (rhs.fImpl) fImpl = rhs.fImpl->Clone(); - } + T operator()(const T *x, const double *p) const { return fFunc(x, p); } - /** - Assignment operator - */ - ParamFunctorTempl & operator = (const ParamFunctorTempl & rhs) { -// ParamFunctor copy(rhs); - // swap unique_ptr by hand -// Impl * p = fImpl.release(); -// fImpl.reset(copy.fImpl.release()); -// copy.fImpl.reset(p); + bool Empty() const { return !fFunc; } - if(this != &rhs) { - if (fImpl) delete fImpl; - fImpl = nullptr; - if (rhs.fImpl) - fImpl = rhs.fImpl->Clone(); +private: + /// Normalize any supported callable to the `T (const T *, const double *)` signature. + /// + /// A pointer to a callable object is called through without taking ownership of it, and + /// callables that insist on non-const pointers (the classic `T (T *x, double *p)` + /// signature) get their arguments cast for them. + template + static std::function Adapt(Func f) + { + if constexpr (std::is_pointer_v && std::is_class_v>) { + if constexpr (std::is_invocable_v &, const T *, const double *>) { + return [f](const T *x, const double *p) { return (*f)(x, p); }; + } else { + return [f](const T *x, const double *p) { return (*f)(const_cast(x), const_cast(p)); }; + } + } else if constexpr (std::is_invocable_v) { + return std::move(f); + } else { + return [f = std::move(f)](const T *x, const double *p) mutable { + return f(const_cast(x), const_cast(p)); + }; } - return *this; - } - - void * GetImpl() { return (void *) fImpl; } - - - T operator() ( T * x, double * p) { - return (*fImpl)(x,p); - } - - T operator() (const T * x, const double * p) { - return (*fImpl)(x,p); - } - - - bool Empty() const { return !fImpl; } - - - void SetFunction(Impl * f) { - fImpl = f; } -private : - - - //std::unique_ptr fImpl; - Impl * fImpl; - - + std::function fFunc; }; - using ParamFunctor = ParamFunctorTempl; - } // end namespace Math +} // end namespace Math } // end namespace ROOT - #endif /* ROOT_Math_ParamFunctor */