Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-27 09:14:57

0001 // lAger: General Purpose l/A-event Generator
0002 // Copyright (C) 2016-2021 Sylvester Joosten <sjoosten@anl.gov>
0003 // 
0004 // This file is part of lAger.
0005 // 
0006 // lAger is free software: you can redistribute it and/or modify
0007 // it under the terms of the GNU General Public License as published by
0008 // the Free Shoftware Foundation, either version 3 of the License, or
0009 // (at your option) any later version.
0010 // 
0011 // lAger is distributed in the hope that it will be useful,
0012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 // GNU General Public License for more details.
0015 // 
0016 // You should have received a copy of the GNU General Public License
0017 // along with lAger.  If not, see <https://www.gnu.org/licenses/>.
0018 // 
0019 
0020 #ifndef LAGER_CORE_FACTORY_LOADED
0021 #define LAGER_CORE_FACTORY_LOADED
0022 
0023 #include <map>
0024 #include <memory>
0025 #include <mutex>
0026 #include <lager/core/assert.hh>
0027 #include <lager/core/logger.hh>
0028 #include <string>
0029 
0030 namespace lager {
0031 
0032 // errors
0033 class factory_error : public lager::exception {
0034 public:
0035   factory_error(const std::string& msg,
0036                 const std::string& type = "factory_error")
0037       : lager::exception{msg, type} {}
0038 };
0039 class factory_key_error : public factory_error {
0040 public:
0041   factory_key_error(const std::string& msg)
0042       : factory_error{msg, "factory_key_error"} {}
0043 };
0044 
0045 // register a class with a (global) factory
0046 #define FACTORY_REGISTER(gen, class, name)                                     \
0047   namespace {                                                                  \
0048   struct proxy_##class {                                                       \
0049     proxy_##class() { gen::factory_instance.add<class>(name); }                \
0050   };                                                                           \
0051   const proxy_##class p_##class;                                               \
0052   }
0053 #define FACTORY_REGISTER2(gen, class, name)                                    \
0054   gen::factory_instance.add<class>(name)
0055 
0056 // construct a generator instance
0057 #define FACTORY_CREATE(gen, conf, path, rng)                                   \
0058   gen::factory_instance.create(                                                \
0059       conf.get<std::string>(string_path(path) / "type"), conf, path, rng)
0060 
0061 // a generic factory base class
0062 template <class T, class... Args> class factory {
0063 private:
0064   struct worker_base;
0065   using worker_map_type = std::map<std::string, std::shared_ptr<worker_base>>;
0066 
0067 public:
0068   std::shared_ptr<T> create(const std::string& name, Args... a) const {
0069     // Removed lock guard because it screws up when doing nested constructions,
0070     // and we are not running in a multi-threaded environment anyway
0071     //    std::lock_guard<std::mutex> lock{mutex_};
0072     LOG_DEBUG("factory", "Constructing " + name);
0073     if (!workers_) {
0074       LOG_DEBUG("factory",
0075                 "Worker pointer is a null pointer. This should never happen.");
0076     }
0077     if (!workers_ || !workers_->count(name)) {
0078       LOG_ERROR("factory", "Cannot construct object " + name +
0079                                ": no such name registered.");
0080       throw factory_key_error{"Failed to construct object."};
0081     }
0082     return workers_->find(name)->second->create(a...);
0083   }
0084 
0085   template <class U> void add(const std::string& name) {
0086     // there is NO guarantee that the worker map will be initialized before
0087     // we attempt to proxy-register a class to a global factory.
0088     // To avoid this problem we manually construct the map when it's
0089     // first needed
0090     // A bit of a hack, but necessecary
0091     std::lock_guard<std::mutex> lock{mutex_};
0092     LOG_DEBUG("factory", "Registered class: " + name);
0093     if (!workers_) {
0094       workers_ = std::make_unique<worker_map_type>();
0095     }
0096     workers_->insert(std::make_pair(name, std::make_shared<worker<U>>()));
0097   }
0098 
0099   void remove(const std::string& name) {
0100     std::lock_guard<std::mutex> lock{mutex_};
0101     if (!workers_ || !workers_->count(name)) {
0102       LOG_ERROR("factory", "Cannot remove worker for class " + name +
0103                                ": no such name registered.");
0104       throw factory_key_error{"Failed to remove worker."};
0105     }
0106     workers_.erase(name);
0107   }
0108 
0109 private:
0110   // factory worker
0111   struct worker_base {
0112     virtual std::shared_ptr<T> create(Args...) const = 0;
0113   };
0114   template <class U> struct worker : worker_base {
0115     virtual std::shared_ptr<T> create(Args... a) const {
0116       return std::make_shared<U>(a...);
0117     }
0118   };
0119 
0120   std::unique_ptr<worker_map_type> workers_;
0121   mutable std::mutex mutex_;
0122 };
0123 
0124 } // namespace lager
0125 
0126 #endif