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 const char* envVar =
"LD_LIBRARY_PATH";
142 const char sep =
':';
143 char* search_path = ::getenv( envVar );
145 logger().
debug( std::string(
"searching factories in " ) + envVar );
146 std::string path( search_path );
147 std::string::size_type pos = 0;
148 std::string::size_type newpos = 0;
149 while ( pos != std::string::npos ) {
152 newpos = path.find( sep, pos );
153 if ( newpos != std::string::npos ) {
154 dirName = path.substr( pos, newpos - pos );
157 dirName = path.substr( pos );
160 logger().
debug( std::string(
" looking into " ) + dirName );
162 DIR* dir = opendir( dirName.c_str() );
164 struct dirent* entry;
165 while ( ( entry = readdir( dir ) ) ) {
166 std::string name( entry->d_name );
168 std::string::size_type extpos = name.find(
".components" );
169 if ( ( extpos != std::string::npos ) && ( ( extpos + 11 ) == name.size() ) ) {
170 std::string fullPath = ( dirName +
'/' + name );
173 stat( fullPath.c_str(), &buf );
174 if ( !S_ISREG( buf.st_mode ) )
continue;
177 logger().
debug( std::string(
" reading " ) + name );
180 int factoriesCount = 0;
187 if ( line.empty() || line[0] ==
'#' )
continue;
189 if ( line.substr( 0, 4 ) ==
"v1::" )
190 line = line.substr( 4 );
194 auto pos = line.find(
':' );
195 if ( pos == std::string::npos ) {
196 logger().
warning(
"failed to parse line " + fullPath +
':' + std::to_string( lineCount ) );
199 const std::string lib( line, 0, pos );
200 const std::string fact( line, pos + 1 );
202#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
204 std::string old_name = old_style_name( fact );
205 if ( fact != old_name ) {
214 logger().
debug(
" found " + std::to_string( factoriesCount ) +
" factories" );
225 const std::string& rtype,
const std::string& className,
227 auto _guard = std::scoped_lock{
m_mutex };
229 auto entry = facts.find(
id );
230 if ( entry == facts.end() ) {
232 entry = facts.emplace(
id,
FactoryInfo(
"unknown", factory, type, rtype, className, props ) ).first;
235 if ( !entry->second.ptr ) entry->second.ptr = factory;
236 factoryInfoSetHelper( entry->second.type, type,
"type",
id );
237 factoryInfoSetHelper( entry->second.rtype, rtype,
"return type",
id );
238 factoryInfoSetHelper( entry->second.className, className,
"class",
id );
240#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
242 std::string old_name = old_style_name(
id );
243 if (
id != old_name )
244 add( old_name, factory, type, rtype, className, props ).
properties[
"ReflexName"] =
"true";
246 return entry->second;
249 void*
Registry::get(
const std::string&
id,
const std::string& type )
const {
250 auto _guard = std::scoped_lock{
m_mutex };
252 auto f = facts.find(
id );
253 if ( f != facts.end() ) {
254#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
255 const Properties& props = f->second.properties;
256 if ( props.find(
"ReflexName" ) != props.end() )
260 f->second.className +
"' instead" );
262 if ( !f->second.ptr ) {
263 if ( !dlopen( f->second.library.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
264 logger().
warning(
"cannot load " + f->second.library +
" for factory " +
id );
265 char* dlmsg = dlerror();
269 f = facts.find(
id );
271 if ( f->second.type == type )
return f->second.ptr;
273 " instead of " +
demangle( type ) );
279 auto _guard = std::scoped_lock{
m_mutex };
282 auto f = facts.find(
id );
283 return ( f != facts.end() ) ? f->second : unknown;
287 auto _guard = std::scoped_lock{
m_mutex };
289 auto f = facts.find(
id );
290 if ( f != facts.end() ) f->second.properties[k] = v;
295 auto _guard = std::scoped_lock{
m_mutex };
298 if ( f.second.ptr ) l.insert( f.first );
304 static const char* levels[] = {
"DEBUG : ",
"INFO : ",
"WARNING: ",
"ERROR : " };
305 if ( lvl >=
level() ) { std::cerr << levels[lvl] << msg << std::endl; }
308 static auto s_logger = std::make_unique<Logger>();
316 Logger& l = logger();
317 if ( debugLevel > 1 )
318 l.setLevel( Logger::Debug );
319 else if ( debugLevel > 0 )
320 l.setLevel( Logger::Info );
322 l.setLevel( Logger::Warning );
327 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...