From ac1883e5ece334924119db38b5eac30a78dcf632 Mon Sep 17 00:00:00 2001
From: Christopher Jones <chrisdjones15@gmail.com>
Date: Fri, 4 Dec 2020 09:41:30 -0600
Subject: [PATCH] Set units as part of Evaluator constructor

- Allows object to be a private member data
- Initialization of globally accessible Evaluators no longer
 requires a lock as static construction is guaranteed to be
 thread safe.
---
 DDParsers/include/Evaluator/Evaluator.h       |  8 +-
 .../include/Evaluator/detail/Evaluator.h      | 57 +++++++++----
 DDParsers/src/Evaluator/Evaluator.cpp         | 17 +++-
 .../src/Evaluator/ExpressionEvaluator.cpp     | 81 +++++--------------
 4 files changed, 82 insertions(+), 81 deletions(-)

diff --git a/DDParsers/include/Evaluator/Evaluator.h b/DDParsers/include/Evaluator/Evaluator.h
index eee6210c9..86d3688d5 100644
--- a/DDParsers/include/Evaluator/Evaluator.h
+++ b/DDParsers/include/Evaluator/Evaluator.h
@@ -68,7 +68,13 @@ namespace dd4hep  {
       /**
        * Constructor.
        */
-      Evaluator();
+      Evaluator(double meter = 1.0, double kilogram = 1.0, double second = 1.0, double ampere = 1.0, double kelvin = 1.0
+                , double mole = 1.0, double candela = 1.0, double radians = 1.0);
+
+      /**
+       * MoveConstructor.
+       */
+      Evaluator(Evaluator&&);
 
       /**
        * Destructor.
diff --git a/DDParsers/include/Evaluator/detail/Evaluator.h b/DDParsers/include/Evaluator/detail/Evaluator.h
index 6bb22d2e3..82da50cb0 100644
--- a/DDParsers/include/Evaluator/detail/Evaluator.h
+++ b/DDParsers/include/Evaluator/detail/Evaluator.h
@@ -85,7 +85,36 @@ namespace dd4hep  {
       /**
        * Constructor.
        */
-      Object();
+
+      /**
+       * Sets system of units. Default is the SI system of units.
+       * To set the CGS (Centimeter-Gram-Second) system of units
+       * one should call:
+       *   Object o(100., 1000., 1.0, 1.0, 1.0, 1.0, 1.0);
+       *
+       * To set system of units accepted in the GEANT4 simulation toolkit
+       * one should call:
+       * @code
+       *   setSystemOfUnits(1.e+3, 1./1.60217733e-25, 1.e+9, 1./1.60217733e-10,
+       *                    1.0, 1.0, 1.0);
+       * @endcode
+       *
+       * The basic units in GEANT4 are:
+       * @code
+       *   millimeter              (millimeter = 1.)
+       *   nanosecond              (nanosecond = 1.)
+       *   Mega electron Volt      (MeV        = 1.)
+       *   positron charge         (eplus      = 1.)
+       *   degree Kelvin           (kelvin     = 1.)
+       *   the amount of substance (mole       = 1.)
+       *   luminous intensity      (candela    = 1.)
+       *   radian                  (radian     = 1.)
+       *   steradian               (steradian  = 1.)
+       * @endcode
+       */
+
+      Object(double meter = 1.0, double kilogram = 1.0, double second = 1.0, double ampere = 1.0, double kelvin =
+                            1.0, double mole = 1.0, double candela = 1.0, double radians = 1.0 );
 
       /**
        * Destructor.
@@ -240,11 +269,9 @@ namespace dd4hep  {
        */
       void clear();
 
-      /**
-       * Sets standard mathematical functions and constants.
-       */
-      void setStdMath();
-
+      struct Struct;
+      
+    private:
       /**
        * Sets system of units. Default is the SI system of units.
        * To set the CGS (Centimeter-Gram-Second) system of units
@@ -271,16 +298,18 @@ namespace dd4hep  {
        *   steradian               (steradian  = 1.)
        * @endcode
        */
-      void setSystemOfUnits(double meter = 1.0, double kilogram = 1.0, double second = 1.0, double ampere = 1.0, double kelvin =
-                            1.0, double mole = 1.0, double candela = 1.0, double radians = 1.0 );
+      void setSystemOfUnits(double meter, double kilogram, double second, double ampere, double kelvin
+                          , double mole, double candela, double radians );
 
+      /**
+       * Sets standard mathematical functions and constants.
+       */
+      void setStdMath();
 
-      struct Struct;
-      
-    private:
-      Struct* imp {0};                      // private data
-      Object(const Object &);               // copy constructor is not allowed
-      Object & operator=(const Object &);   // assignment is not allowed
+
+      Struct* imp {0};                               // private data
+      Object(const Object &) = delete;               // copy constructor is not allowed
+      Object & operator=(const Object &) = delete;   // assignment is not allowed
     };
 
   }   // namespace tools
diff --git a/DDParsers/src/Evaluator/Evaluator.cpp b/DDParsers/src/Evaluator/Evaluator.cpp
index af350bfc1..449a3deb4 100644
--- a/DDParsers/src/Evaluator/Evaluator.cpp
+++ b/DDParsers/src/Evaluator/Evaluator.cpp
@@ -646,8 +646,11 @@ static int setItem(const char * prefix, const char * name,
 using namespace dd4hep::tools;
 
 //---------------------------------------------------------------------------
-Evaluator::Object::Object() {
-  imp = new Struct();
+Evaluator::Object::Object(double meter, double kilogram, double second, double ampere, double kelvin
+                          , double mole, double candela, double radians) : imp( new Struct()) {
+  setStdMath();
+  setSystemOfUnits(meter, kilogram, second, ampere, kelvin
+                   , mole, candela, radians );
 }
 
 //---------------------------------------------------------------------------
@@ -815,8 +818,14 @@ void Evaluator::Object::removeFunction(const char * name, int npar) {
 }
 
 //---------------------------------------------------------------------------
-Evaluator::Evaluator()   {
-  object = new Object();
+Evaluator::Evaluator(double meter, double kilogram, double second, double ampere, double kelvin
+                          , double mole, double candela, double radians)   {
+  object = new Object(meter, kilogram, second, ampere, kelvin, mole, candela, radians);
+}
+
+//---------------------------------------------------------------------------
+Evaluator::Evaluator(Evaluator&& other):object(other.object) {
+  other.object=nullptr;
 }
 
 //---------------------------------------------------------------------------
diff --git a/DDParsers/src/Evaluator/ExpressionEvaluator.cpp b/DDParsers/src/Evaluator/ExpressionEvaluator.cpp
index defc244cb..f6febd6be 100644
--- a/DDParsers/src/Evaluator/ExpressionEvaluator.cpp
+++ b/DDParsers/src/Evaluator/ExpressionEvaluator.cpp
@@ -18,31 +18,18 @@
 #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
-    // and the system of units used by Gaudi (Geant4)
-    e.object->setStdMath();
-  }
-
-  void _cgsUnits(dd4hep::tools::Evaluator& e) {
+  dd4hep::tools::Evaluator _cgsUnits() {
     // ===================================================================================
     // CGS units
-    e.object->setSystemOfUnits(100., 1000., 1.0, 1.0, 1.0, 1.0, 1.0);
+    return dd4hep::tools::Evaluator(100., 1000., 1.0, 1.0, 1.0, 1.0, 1.0, 1.0);
   }
   
-  void _tgeoUnits(dd4hep::tools::Evaluator& e) {
+  dd4hep::tools::Evaluator _tgeoUnits() {
     // ===================================================================================
     // DDG4 units (TGeo) 1 sec = 10^9 [nsec]
     //                   1 Coulomb = 1/e As
@@ -51,21 +38,21 @@ namespace {
 
     //    e.setSystemOfUnits(1.e+2, 1./1.60217733e-6, 1.0, 1./1.60217733e-19, 1.0, 1.0, 1.0);
     // use the units as defined in DD4hepUnits.h:
-    e.object->setSystemOfUnits( units::meter,
-				units::kilogram,
-				units::second,
-				units::ampere,
-				units::kelvin,
-				units::mole,
-				units::candela,
-				units::rad );
+    return dd4hep::tools::Evaluator( units::meter,
+                                     units::kilogram,
+                                     units::second,
+                                     units::ampere,
+                                     units::kelvin,
+                                     units::mole,
+                                     units::candela,
+                                     units::rad );
   }
   
-  void _g4Units(dd4hep::tools::Evaluator& e) {
+  dd4hep::tools::Evaluator _g4Units() {
     // ===================================================================================
     // Geant4 units
     // Geant4:  kilogram = joule*s*s/(m*m) 1/e_SI * 1e-6 * 1e9 1e9 / 1e3 / 1e3 = 1. / 1.60217733e-25
-    e.object->setSystemOfUnits(1.e+3, 1./1.60217733e-25, 1.e+9, 1./1.60217733e-10, 1.0, 1.0, 1.0);
+    return dd4hep::tools::Evaluator(1.e+3, 1./1.60217733e-25, 1.e+9, 1./1.60217733e-10, 1.0, 1.0, 1.0, 1.0);
   }
 }
 
@@ -73,50 +60,20 @@ namespace {
 namespace dd4hep {
 
   const tools::Evaluator& evaluator() {
-    static const tools::Evaluator* e = 0;
-    if ( !e )   {
-      _eval_lock(true);
-      if ( !e )   {
-	static tools::Evaluator ev;
-	_init(ev);
-	_tgeoUnits(ev);
-	e = &ev;
-      }
-      _eval_lock(false);
-    }
-    return *e;
+    static const tools::Evaluator e = _tgeoUnits();
+    return e;
   }
 
   /// Access to G4 evaluator. Note: Uses Geant4 units!
   const tools::Evaluator& g4Evaluator()   {
-    static const tools::Evaluator* e = 0;
-    if ( !e )   {
-      _eval_lock(true);
-      if ( !e )   {
-	static tools::Evaluator ev;
-	_init(ev);
-	_g4Units(ev);
-	e = &ev;
-      }
-      _eval_lock(false);
-    }
-    return *e;
+    static const tools::Evaluator e = _g4Units();
+    return e;
   }
 
   /// Access to G4 evaluator. Note: Uses cgs units!
   const tools::Evaluator& cgsEvaluator()   {
-    static const tools::Evaluator* e = 0;
-    if ( !e )   {
-      _eval_lock(true);
-      if ( !e )   {
-	static tools::Evaluator ev;
-	_init(ev);
-	_cgsUnits(ev);
-	e = &ev;
-      }
-      _eval_lock(false);
-    }
-    return *e;
+    static const tools::Evaluator e = _cgsUnits();
+    return e;
   }
 }
 
-- 
GitLab