Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:35

0001 
0002 // Copyright 2020, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 
0006 #ifndef _JSERVICELOCATOR_H_
0007 #define _JSERVICELOCATOR_H_
0008 
0009 
0010 #include <map>
0011 #include <typeinfo>
0012 #include <typeindex>
0013 #include <assert.h>
0014 #include <memory>
0015 #include <mutex>
0016 
0017 #include <JANA/JException.h>
0018 #include "JANA/Utils/JTypeInfo.h"
0019 #include <JANA/JServiceFwd.h>
0020 
0021 
0022 
0023 /// JService is a trait indicating that an object can be shared among JANA components
0024 /// via a simple ServiceLocator. It provides a callback interface for configuring itself
0025 /// when it depends on other JServices.
0026 
0027 /// JServiceLocator is a nexus for collecting, initializing, and retrieving JServices.
0028 /// This may be exposed via the JApplication facade, or used on its own. JServiceLocator
0029 /// uses shared-pointer semantics to ensure that JServices always get freed,
0030 /// but also don't get freed prematurely if a JApplication or JServiceLocator go out of scope.
0031 class JServiceLocator {
0032 
0033     std::map<std::type_index, std::shared_ptr<JService>> underlying;
0034     std::mutex mutex;
0035 
0036 public:
0037 
0038 
0039     template<typename T>
0040     void provide(std::shared_ptr<T> t) {
0041 
0042         /// Publish a Service to the ServiceLocator. This Service should have
0043         /// already been constructed, but not finalized.
0044         /// Users are intended to call this from InitPlugin() most of the time
0045 
0046         std::lock_guard<std::mutex> lock(mutex);
0047         auto svc = std::dynamic_pointer_cast<JService>(t);
0048         assert(svc != nullptr);
0049         svc->SetTypeName(JTypeInfo::demangle<T>());
0050         underlying[std::type_index(typeid(T))] = svc;
0051     }
0052 
0053     template<typename T>
0054     std::shared_ptr<T> get() {
0055         /// Retrieve a JService. If acquire_services() has not yet been called, it will be.
0056         /// Usually called from Service::finalize(). It may be called from anywhere,
0057         /// but it is generally safer to retrieve the services we need during acquire_dependencies()
0058         /// and keep pointers to those, instead of keeping a pointer to the ServiceLocator itself.
0059         /// (This also makes it easier to migrate to dependency injection if we so desire)
0060 
0061         auto iter = underlying.find(std::type_index(typeid(T)));
0062         if (iter == underlying.end()) {
0063             std::ostringstream oss;
0064             oss << "Service not found: '" << JTypeInfo::demangle<T>() << "'. Did you forget to include a plugin?" << std::endl;
0065             throw JException(oss.str());
0066         }
0067         auto svc = iter->second;
0068         svc->DoInit(this); 
0069         // Will short-circuit if already initialized
0070         // Note: Requires JApplication to already be set.
0071 
0072         auto svc_typed = std::static_pointer_cast<T>(svc);
0073         return svc_typed;
0074     }
0075 
0076     void wire_everything() {
0077         /// Make sure that all Services have been finalized. This is not strictly necessary,
0078         /// but it makes user errors easier to understand, and it prevents Services from being
0079         /// unpredictably finalized later on, particularly during computation.
0080 
0081         for (auto& entry : underlying) {
0082             entry.second->DoInit(this); 
0083         }
0084     }
0085 };
0086 
0087 #endif // _JSERVICELOCATOR_H_