From 2defc6390aa093b17727c4980d18e9c806b40660 Mon Sep 17 00:00:00 2001 From: Markus FRANK <Markus.Frank@cern.ch> Date: Tue, 24 Nov 2020 14:39:42 +0100 Subject: [PATCH] Towards a thread safe expression evaluation.... --- DDParsers/include/Evaluator/Evaluator.h | 71 ++++++++++++++++++- .../include/Evaluator/detail/Evaluator.h | 26 +++---- DDParsers/src/Evaluator/Evaluator.cpp | 48 +++++++++++++ .../src/Evaluator/ExpressionEvaluator.cpp | 47 ++++++++---- 4 files changed, 166 insertions(+), 26 deletions(-) diff --git a/DDParsers/include/Evaluator/Evaluator.h b/DDParsers/include/Evaluator/Evaluator.h index e509708b6..668d3af4f 100644 --- a/DDParsers/include/Evaluator/Evaluator.h +++ b/DDParsers/include/Evaluator/Evaluator.h @@ -98,6 +98,66 @@ namespace dd4hep { */ std::pair<int,double> evaluate(const std::string& expression, std::ostream& os) const; + /** + * Adds to the dictionary a function without parameters. + * If such a function already exist in the dictionary, + * then status will be set to WARNING_EXISTING_FUNCTION. + * + * @param name function name. + * @param fun pointer to the real function in the user code. + */ + void setFunction(const std::string& name, double (*fun)()) const; + + /** + * Adds to the dictionary a function with one parameter. + * If such a function already exist in the dictionary, + * then status will be set to WARNING_EXISTING_FUNCTION. + * + * @param name function name. + * @param fun pointer to the real function in the user code. + */ + void setFunction(const std::string& name, double (*fun)(double)) const; + + /** + * Adds to the dictionary a function with two parameters. + * If such a function already exist in the dictionary, + * then status will be set to WARNING_EXISTING_FUNCTION. + * + * @param name function name. + * @param fun pointer to the real function in the user code. + */ + void setFunction(const std::string& name, double (*fun)(double, double)) const; + + /** + * Adds to the dictionary a function with three parameters. + * If such a function already exist in the dictionary, + * then status will be set to WARNING_EXISTING_FUNCTION. + * + * @param name function name. + * @param fun pointer to the real function in the user code. + */ + void setFunction(const std::string& name, double (*fun)(double, double, double)) const; + + /** + * Adds to the dictionary a function with four parameters. + * If such a function already exist in the dictionary, + * then status will be set to WARNING_EXISTING_FUNCTION. + * + * @param name function name. + * @param fun pointer to the real function in the user code. + */ + void setFunction(const std::string& name, double (*fun)(double, double, double, double)) const; + + /** + * Adds to the dictionary a function with five parameters. + * If such a function already exist in the dictionary, + * then status will be set to WARNING_EXISTING_FUNCTION. + * + * @param name function name. + * @param fun pointer to the real function in the user code. + */ + void setFunction(const std::string& name, double (*fun)(double, double, double, double, double)) const; + /** * Adds to the dictionary a string constant * @@ -152,8 +212,17 @@ namespace dd4hep { */ bool findVariable(const std::string& name) const; + /** + * Finds the function in the dictionary. + * + * @param name name of the function to be unset. + * @param npar number of parameters of the function. + * @return true if such a function exists, false otherwise. + */ + bool findFunction(const std::string& name, int npar) const; + class Object; - Object* object = 0; // private data + Object* object = 0; // internal data private: Evaluator(const Evaluator &) = delete; // copy constructor is not allowed diff --git a/DDParsers/include/Evaluator/detail/Evaluator.h b/DDParsers/include/Evaluator/detail/Evaluator.h index 56387b849..7e20a03dd 100644 --- a/DDParsers/include/Evaluator/detail/Evaluator.h +++ b/DDParsers/include/Evaluator/detail/Evaluator.h @@ -74,7 +74,7 @@ namespace dd4hep { * @see error_position * @see print_error */ - double evaluate(const char * expression); + double evaluate(const char* expression); /** * Returns status of the last operation with the evaluator. @@ -119,7 +119,7 @@ namespace dd4hep { * @param name name of the variable. * @param value value assigned to the variable. */ - void setVariable(const char * name, double value); + void setVariable(const char* name, double value); /** * Adds to the dictionary a variable with an arithmetic expression @@ -130,7 +130,7 @@ namespace dd4hep { * @param name name of the variable. * @param expression arithmetic expression. */ - void setVariable(const char * name, const char * expression); + void setVariable(const char* name, const char* expression); /** * Adds to the dictionary a function without parameters. @@ -140,7 +140,7 @@ namespace dd4hep { * @param name function name. * @param fun pointer to the real function in the user code. */ - void setFunction(const char * name, double (*fun)()); + void setFunction(const char* name, double (*fun)()); /** * Adds to the dictionary a function with one parameter. @@ -150,7 +150,7 @@ namespace dd4hep { * @param name function name. * @param fun pointer to the real function in the user code. */ - void setFunction(const char * name, double (*fun)(double)); + void setFunction(const char* name, double (*fun)(double)); /** * Adds to the dictionary a function with two parameters. @@ -160,7 +160,7 @@ namespace dd4hep { * @param name function name. * @param fun pointer to the real function in the user code. */ - void setFunction(const char * name, double (*fun)(double, double)); + void setFunction(const char* name, double (*fun)(double, double)); /** * Adds to the dictionary a function with three parameters. @@ -170,7 +170,7 @@ namespace dd4hep { * @param name function name. * @param fun pointer to the real function in the user code. */ - void setFunction(const char * name, double (*fun)(double, double, double)); + void setFunction(const char* name, double (*fun)(double, double, double)); /** * Adds to the dictionary a function with four parameters. @@ -180,7 +180,7 @@ namespace dd4hep { * @param name function name. * @param fun pointer to the real function in the user code. */ - void setFunction(const char * name, double (*fun)(double, double, double, double)); + void setFunction(const char* name, double (*fun)(double, double, double, double)); /** * Adds to the dictionary a function with five parameters. @@ -190,7 +190,7 @@ namespace dd4hep { * @param name function name. * @param fun pointer to the real function in the user code. */ - void setFunction(const char * name, double (*fun)(double, double, double, double, double)); + void setFunction(const char* name, double (*fun)(double, double, double, double, double)); /** * Finds the variable in the dictionary. @@ -198,7 +198,7 @@ namespace dd4hep { * @param name name of the variable. * @return true if such a variable exists, false otherwise. */ - bool findVariable(const char * name) const; + bool findVariable(const char* name) const; /** * Finds the function in the dictionary. @@ -207,14 +207,14 @@ namespace dd4hep { * @param npar number of parameters of the function. * @return true if such a function exists, false otherwise. */ - bool findFunction(const char * name, int npar) const; + bool findFunction(const char* name, int npar) const; /** * Removes the variable from the dictionary. * * @param name name of the variable. */ - void removeVariable(const char * name); + void removeVariable(const char* name); /** * Removes the function from the dictionary. @@ -222,7 +222,7 @@ namespace dd4hep { * @param name name of the function to be unset. * @param npar number of parameters of the function. */ - void removeFunction(const char * name, int npar); + void removeFunction(const char* name, int npar); /** * Clear all settings. diff --git a/DDParsers/src/Evaluator/Evaluator.cpp b/DDParsers/src/Evaluator/Evaluator.cpp index 48ca55229..611edc4d0 100644 --- a/DDParsers/src/Evaluator/Evaluator.cpp +++ b/DDParsers/src/Evaluator/Evaluator.cpp @@ -933,5 +933,53 @@ bool Evaluator::findVariable(const std::string& name) const { return ret; } +//--------------------------------------------------------------------------- +void Evaluator::setFunction(const std::string& name, double (*fun)()) const { + object->lock(); + object->setFunction(name.c_str(), fun); + object->unlock(); +} + +//--------------------------------------------------------------------------- +void Evaluator::setFunction(const std::string& name, double (*fun)(double)) const { + object->lock(); + object->setFunction(name.c_str(), fun); + object->unlock(); +} + +//--------------------------------------------------------------------------- +void Evaluator::setFunction(const std::string& name, double (*fun)(double, double)) const { + object->lock(); + object->setFunction(name.c_str(), fun); + object->unlock(); +} + +//--------------------------------------------------------------------------- +void Evaluator::setFunction(const std::string& name, double (*fun)(double, double, double)) const { + object->lock(); + object->setFunction(name.c_str(), fun); + object->unlock(); +} +//--------------------------------------------------------------------------- +void Evaluator::setFunction(const std::string& name, double (*fun)(double, double, double, double)) const { + object->lock(); + object->setFunction(name.c_str(), fun); + object->unlock(); +} +//--------------------------------------------------------------------------- +void Evaluator::setFunction(const std::string& name, double (*fun)(double, double, double, double, double)) const { + object->lock(); + object->setFunction(name.c_str(), fun); + object->unlock(); +} + +//--------------------------------------------------------------------------- +bool Evaluator::findFunction(const std::string& name, int npar) const { + bool ret; + object->lock(); + ret = object->findFunction(name.c_str(), npar); + object->unlock(); + return ret; +} diff --git a/DDParsers/src/Evaluator/ExpressionEvaluator.cpp b/DDParsers/src/Evaluator/ExpressionEvaluator.cpp index 098c3adb2..74d0da5fe 100644 --- a/DDParsers/src/Evaluator/ExpressionEvaluator.cpp +++ b/DDParsers/src/Evaluator/ExpressionEvaluator.cpp @@ -10,14 +10,25 @@ // Author : M.Frank // //========================================================================== + +/// Framework include files #include "Parsers/config.h" #include "Evaluator/Evaluator.h" #include "Evaluator/detail/Evaluator.h" #include "Evaluator/DD4hepUnits.h" +/// C/C++ include files +#include <mutex> + namespace units = dd4hep; namespace { + + void _eval_lock(bool lock_or_unlock) { + static std::mutex construction_lock; + if ( lock_or_unlock ) construction_lock.lock(); + else construction_lock.unlock(); + } void _init(dd4hep::tools::Evaluator& e) { // Initialize numerical expressions parser with the standard math functions @@ -72,10 +83,14 @@ namespace dd4hep { const tools::Evaluator& evaluator() { static const tools::Evaluator* e = 0; if ( !e ) { - static tools::Evaluator ev; - _init(ev); - _tgeoUnits(ev); - e = &ev; + _eval_lock(true); + if ( !e ) { + static tools::Evaluator ev; + _init(ev); + _tgeoUnits(ev); + e = &ev; + } + _eval_lock(false); } return *e; } @@ -84,10 +99,14 @@ namespace dd4hep { const tools::Evaluator& g4Evaluator() { static const tools::Evaluator* e = 0; if ( !e ) { - static tools::Evaluator ev; - _init(ev); - _g4Units(ev); - e = &ev; + _eval_lock(true); + if ( !e ) { + static tools::Evaluator ev; + _init(ev); + _g4Units(ev); + e = &ev; + } + _eval_lock(false); } return *e; } @@ -96,10 +115,14 @@ namespace dd4hep { const tools::Evaluator& cgsEvaluator() { static const tools::Evaluator* e = 0; if ( !e ) { - static tools::Evaluator ev; - _init(ev); - _cgsUnits(ev); - e = &ev; + _eval_lock(true); + if ( !e ) { + static tools::Evaluator ev; + _init(ev); + _cgsUnits(ev); + e = &ev; + } + _eval_lock(false); } return *e; } -- GitLab