14#define GAUDI_PLUGIN_SERVICE_V1
30 std::mutex registrySingletonMutex;
39 constexpr struct is_space_t {
40 bool operator()(
int i )
const {
return std::isspace( i ); }
44 static inline std::string& ltrim( std::string& s ) {
45 s.erase(
s.begin(), std::find_if_not(
s.begin(),
s.end(), is_space ) );
50 static inline std::string& rtrim( std::string& s ) {
51 s.erase( std::find_if_not(
s.rbegin(),
s.rend(), is_space ).base(),
s.end() );
55 static inline std::string& trim( std::string& s ) {
return ltrim( rtrim( s ) ); }
62 inline void factoryInfoSetHelper( std::string& dest,
const std::string& value,
const std::string& desc,
63 const std::string&
id ) {
66 }
else if ( dest != value ) {
67 Gaudi::PluginService::Details::logger().warning(
"new factory loaded for '" +
id +
"' with different " + desc +
68 ": " + dest +
" != " + value );
74 void operator()(
const char c ) {
83 name.push_back(
'_' );
86 name.push_back(
'r' );
89 name.push_back(
'p' );
100 std::string old_style_name(
const std::string& name ) {
101 return std::for_each(
name.begin(),
name.end(), OldStyleCnv() ).name;
113 void*
getCreator(
const std::string&
id,
const std::string& type ) {
119 auto realname = std::unique_ptr<char, decltype( free )*>(
120 abi::__cxa_demangle(
id.c_str(),
nullptr,
nullptr, &status ), free );
121 if ( !realname )
return id;
122 return std::regex_replace(
124 std::regex{
"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?" },
130 auto _guard = std::scoped_lock{ ::registrySingletonMutex };
138 auto _guard = std::scoped_lock{
m_mutex };
141#if defined( __APPLE__ )
142 const auto envVars = {
"GAUDI_PLUGIN_PATH",
"DYLD_LIBRARY_PATH" };
143 const char sep =
':';
145 const auto envVars = {
"GAUDI_PLUGIN_PATH",
"LD_LIBRARY_PATH" };
146 const char sep =
':';
149 for (
const auto& envVar : envVars ) {
150 char* search_path = ::getenv( envVar );
152 logger().
debug( std::string(
"searching factories in " ) + envVar );
153 std::string path( search_path );
154 std::string::size_type pos = 0;
155 std::string::size_type newpos = 0;
156 while ( pos != std::string::npos ) {
159 newpos = path.find( sep, pos );
160 if ( newpos != std::string::npos ) {
161 dirName = path.substr( pos, newpos - pos );
164 dirName = path.substr( pos );
167 logger().
debug( std::string(
" looking into " ) + dirName );
169 DIR* dir = opendir( dirName.c_str() );
171 struct dirent* entry;
172 while ( ( entry = readdir( dir ) ) ) {
173 std::string name( entry->d_name );
175 std::string::size_type extpos = name.find(
".components" );
176 if ( ( extpos != std::string::npos ) && ( ( extpos + 11 ) == name.size() ) ) {
177 std::string fullPath = ( dirName +
'/' + name );
180 stat( fullPath.c_str(), &buf );
181 if ( !S_ISREG( buf.st_mode ) )
continue;
184 logger().
debug( std::string(
" reading " ) + name );
187 int factoriesCount = 0;
194 if ( line.empty() || line[0] ==
'#' )
continue;
196 if ( line.substr( 0, 4 ) ==
"v1::" )
197 line = line.substr( 4 );
201 auto pos = line.find(
':' );
202 if ( pos == std::string::npos ) {
203 logger().
warning(
"failed to parse line " + fullPath +
':' + std::to_string( lineCount ) );
206 const std::string lib( line, 0, pos );
207 const std::string fact( line, pos + 1 );
209#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
211 std::string old_name = old_style_name( fact );
212 if ( fact != old_name ) {
221 logger().
debug(
" found " + std::to_string( factoriesCount ) +
" factories" );
233 const std::string& rtype,
const std::string& className,
235 auto _guard = std::scoped_lock{
m_mutex };
237 auto entry = facts.find(
id );
238 if ( entry == facts.end() ) {
240 entry = facts.emplace(
id,
FactoryInfo(
"unknown", factory, type, rtype, className, props ) ).first;
243 if ( !entry->second.ptr ) entry->second.ptr = factory;
244 factoryInfoSetHelper( entry->second.type, type,
"type",
id );
245 factoryInfoSetHelper( entry->second.rtype, rtype,
"return type",
id );
246 factoryInfoSetHelper( entry->second.className, className,
"class",
id );
248#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
250 std::string old_name = old_style_name(
id );
251 if (
id != old_name )
252 add( old_name, factory, type, rtype, className, props ).
properties[
"ReflexName"] =
"true";
254 return entry->second;
257 void*
Registry::get(
const std::string&
id,
const std::string& type )
const {
258 auto _guard = std::scoped_lock{
m_mutex };
260 auto f = facts.find(
id );
261 if ( f != facts.end() ) {
262#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
263 const Properties& props = f->second.properties;
264 if ( props.find(
"ReflexName" ) != props.end() )
268 f->second.className +
"' instead" );
270 if ( !f->second.ptr ) {
271 if ( !dlopen( f->second.library.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
272 logger().
warning(
"cannot load " + f->second.library +
" for factory " +
id );
273 char* dlmsg = dlerror();
277 f = facts.find(
id );
279 if ( f->second.type == type )
return f->second.ptr;
281 " instead of " +
demangle( type ) );
287 auto _guard = std::scoped_lock{
m_mutex };
290 auto f = facts.find(
id );
291 return ( f != facts.end() ) ? f->second : unknown;
295 auto _guard = std::scoped_lock{
m_mutex };
297 auto f = facts.find(
id );
298 if ( f != facts.end() ) f->second.properties[k] = v;
303 auto _guard = std::scoped_lock{
m_mutex };
306 if ( f.second.ptr ) l.insert( f.first );
312 static const char* levels[] = {
"DEBUG : ",
"INFO : ",
"WARNING: ",
"ERROR : " };
313 if ( lvl >=
level() ) { std::cerr << levels[lvl] << msg << std::endl; }
316 static auto s_logger = std::make_unique<Logger>();
324 Logger& l = logger();
325 if ( debugLevel > 1 )
326 l.setLevel( Logger::Debug );
327 else if ( debugLevel > 0 )
328 l.setLevel( Logger::Info );
330 l.setLevel( Logger::Warning );
335 switch ( logger().level() ) {
#define GAUDI_PLUGIN_SERVICE_V1_INLINE
Simple logging class, just to provide a default implementation.
void debug(const std::string &msg)
void warning(const std::string &msg)
virtual void report(Level lvl, const std::string &msg)
const FactoryInfo & getInfo(const std::string &id) const
Retrieve the FactoryInfo object for an id.
bool m_initialized
Flag recording if the registry has been initialized or not.
void * get(const std::string &id, const std::string &type) const
Retrieve the factory for the given id.
static Registry & instance()
Retrieve the singleton instance of Registry.
std::set< KeyType > loadedFactoryNames() const
Return a list of all the known and loaded factories.
std::map< KeyType, FactoryInfo > FactoryMap
Type used for the database implementation.
std::recursive_mutex m_mutex
Mutex used to control concurrent access to the internal data.
FactoryInfo & add(const I &id, typename F::FuncType ptr)
Add a factory to the database.
Registry & addProperty(const std::string &id, const std::string &k, const std::string &v)
Add a property to an already existing FactoryInfo object (via its id.)
void initialize()
Initialize the registry loading the list of factories from the .component files in the library search...
Registry()
Private constructor for the singleton pattern.
const FactoryMap & factories() const
Return the known factories (loading the list if not yet done).
FactoryMap m_factories
Internal storage for factories.
const char * what() const override
Exception(std::string msg)
GAUDIPS_API void setLogger(Logger *logger)
Set the logger instance to use.
GAUDIPS_API Logger & logger()
Return the current logger instance.
std::string demangle()
Return a canonical name for the template argument.
GAUDIPS_API std::string demangle(const std::type_info &id)
Return a canonical name for type_info object (implementation borrowed from GaudiKernel/System).
GAUDIPS_API void * getCreator(const std::string &id, const std::string &type)
Function used to load a specific factory function.
GAUDIPS_API void SetDebug(int debugLevel)
Backward compatibility with Reflex.
GAUDIPS_API int Debug()
Backward compatibility with Reflex.
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...