ATLAS Offline Software
Loading...
Searching...
No Matches
ClassIDSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <fstream>
6#include <iostream>
7#include <iterator>
9
10#include "GaudiKernel/IIncidentSvc.h"
11#include "GaudiKernel/Incident.h"
12#include "GaudiKernel/ModuleIncident.h"
13#include "GaudiKernel/System.h"
14#include "GaudiKernel/MsgStream.h"
15#include "GaudiKernel/ServiceHandle.h"
19
20#include "ClassIDSvc.h"
21
22namespace {
23 bool tryNumeric (const std::string& s, CLID& clid)
24 {
25 clid = CLID_NULL;
26 char* endptr = nullptr;
27 clid = strtol (s.c_str(), &endptr, 10);
28 return clid != CLID_NULL && endptr == (s.c_str() + s.size());
29 }
30
31
32// HACK LIFTED FROM AthenaBaseComps/AthMsgStreamMacros.h to remove dep loop
33#define ATH_MSG_LVL(lvl, x) \
34 do { \
35 if (msgLevel(lvl)) { \
36 msgStream(lvl) << x << endmsg; \
37 } \
38 } while (0)
39
40#define ATH_MSG_VERBOSE(x) ATH_MSG_LVL(MSG::VERBOSE, x)
41#define ATH_MSG_DEBUG(x) ATH_MSG_LVL(MSG::DEBUG, x)
42#define ATH_MSG_INFO(x) ATH_MSG_LVL(MSG::INFO, x)
43#define ATH_MSG_WARNING(x) ATH_MSG_LVL(MSG::WARNING, x)
44#define ATH_MSG_ERROR(x) ATH_MSG_LVL(MSG::ERROR, x)
45
46#define ATH_CONST_MSG_VERBOSE(x) \
47 do { \
48 if (msgLevel(MSG::VERBOSE)) { \
49 verbose() << x << endmsg; \
50 } \
51 } while (0)
52
53}
54
55
58CLID
63 while (valid <= CLIDdetail::MAXCLID &&
64 m_clidMap.find(valid) != m_clidMap.end())
65 {
66 ++valid;
67 }
68
69 if (valid > CLIDdetail::MAXCLID) {
70 throw std::runtime_error("ClassIDSvc::nextAvailableID: none in range");
71 }
72
73 return valid;
74}
75
76
77bool
78ClassIDSvc::isIDInUse(const CLID& id ) const {
81 return m_clidMap.find(id) != m_clidMap.end();
82}
83
84
85bool
86ClassIDSvc::isNameInUse(const std::string& name ) const {
89 return m_nameMap.find(name) != m_nameMap.end();
90}
91
92
94StatusCode
95ClassIDSvc::getTypeNameOfID(const CLID& id, std::string& typeName) const
96{
99
100 CLIDMap::const_iterator iID = m_clidMap.find(id);
101 if (iID != m_clidMap.end()) {
102 typeName = iID->second.first;
103 ATH_CONST_MSG_VERBOSE( "getTypeNameOfID(" << id << ") type name is " << typeName );
104 return StatusCode::SUCCESS;
105 }
106 else {
107 ATH_CONST_MSG_VERBOSE( "getTypeNameOfID(" << id << ") no associated type name found" );
108 return StatusCode::FAILURE;
109 }
110}
111
112
114StatusCode
115ClassIDSvc::getTypeInfoNameOfID(const CLID& id, std::string& typeInfoName) const
116{
118 maybeRescan();
119
120 CLIDMap::const_iterator iID = m_clidMap.find(id);
121 if (iID != m_clidMap.end()) {
122 typeInfoName = iID->second.second;
123 ATH_CONST_MSG_VERBOSE( "getTypeInfoNameOfID(" << id <<
124 ") type-info name is " << typeInfoName );
125 return StatusCode::SUCCESS;
126 }
127 else {
128 ATH_CONST_MSG_VERBOSE( "getTypeInfoNameOfID(" << id <<
129 ") no associated type-info name found" );
130 return StatusCode::FAILURE;
131 }
132}
133
134
136StatusCode
137ClassIDSvc::getIDOfTypeName(const std::string& typeName, CLID& id) const
138{
140 maybeRescan();
141
142 NameMap::const_iterator iID = m_nameMap.find(typeName);
143 if (iID != m_nameMap.end()) {
144 id = iID->second;
145 ATH_CONST_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") CLID is " << id );
146 return StatusCode::SUCCESS;
147 }
148 else if (tryNumeric (typeName, id)) {
149 ATH_CONST_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") is a numeric CLID" );
150 return StatusCode::SUCCESS;
151 }
152 else {
153 ATH_CONST_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") no associated CLID found" );
154 return StatusCode::FAILURE;
155 }
156}
157
158
160StatusCode
161ClassIDSvc::getIDOfTypeInfoName(const std::string& typeInfoName,
162 CLID& id) const
163{
165 maybeRescan();
166 NameMap::const_iterator iID = m_tiNameMap.find(typeInfoName);
167 if (iID != m_tiNameMap.end()) {
168 id = iID->second;
169 ATH_CONST_MSG_VERBOSE( "getIDOfTypeInfoName(" << typeInfoName << ") CLID is " << id );
170 return StatusCode::SUCCESS;
171 }
172 else {
173 ATH_CONST_MSG_VERBOSE( "getIDOfTypeInfoName(" << typeInfoName << ") no associated CLID found" );
174 return StatusCode::FAILURE;
175 }
176}
177
178
180StatusCode
182 const std::string& typeName,
183 const std::string& typeInfoName)
184{
186 if (id < CLIDdetail::MINCLID || id > CLIDdetail::MAXCLID) {
187 ATH_MSG_ERROR( "setTypeNameForID: input id " << id
188 << " is out of allowed range " << CLIDdetail::MINCLID
189 << " : " << CLIDdetail::MAXCLID );
190 return StatusCode::FAILURE;
191 }
192 return uncheckedSetTypePackageForID(id, typeName, typeInfoName);
193}
194
195
196void
198{
200 ATH_MSG_INFO( "dump: in memory" );
201
202 for (CLID clid : sortedIDs()) {
203 auto it = m_clidMap.find (clid);
204 if (it == m_clidMap.end()) {
205 ATH_MSG_INFO( "CLID: "<< clid << " - type name: NOT FOUND" );
206 }
207 else {
208 ATH_MSG_INFO( "CLID: "<< clid << " - type name: " << it->second.first );
209 }
210 }
211 ATH_MSG_INFO( "------------------------------" );
212}
213
214
215StatusCode
217{
218 ATH_MSG_VERBOSE( "Initializing " << name() ) ;
219
220 CHECK( Service::initialize() );
221
222 // set up the incident service:
223 ServiceHandle<IIncidentSvc> pIncSvc ("IncidentSvc", name());
224 CHECK( pIncSvc.retrieve() );
225
226 pIncSvc->addListener(this, ModuleLoadedIncident::TYPE(), /*priority*/ 100);
227 pIncSvc->release();
228
229 CHECK( maybeRescan() ); // calls fillDB() if not already done
230
231 return StatusCode::SUCCESS;
232}
233
234
235StatusCode
237 ATH_MSG_INFO( "RE-initializing " << name() ) ;
238 CHECK( fillDB() );
239 return StatusCode::SUCCESS;
240}
241
242
243StatusCode
245{
246 if (m_outputFileName != "NULL") {
247 std::ofstream outfile( m_outputFileName );
248 if ( !outfile ) {
249 ATH_MSG_ERROR( "unable to open output CLIDDB file: " << m_outputFileName );
250 return StatusCode::RECOVERABLE;
251 } else {
252 for (CLID clid : sortedIDs()) {
253 const std::string& typeName = m_clidMap[clid].first;
254 const std::string& tiName = m_clidMap[clid].second;
255 outfile << clid << "; " << typeName << "; " << tiName << std::endl;
256 }
257 ATH_MSG_INFO( "finalize: wrote " << m_clidMap.size() <<
258 " entries to output CLIDDB file: " << m_outputFileName );
259 }
260 }
261 return Service::finalize();
262}
263
264
265void ClassIDSvc::handle(const Incident &inc)
266{
268 const ModuleLoadedIncident& modInc(dynamic_cast<const ModuleLoadedIncident&>(inc));
269
270 getRegistryEntries(modInc.module());
271}
272
273
275ClassIDSvc::ClassIDSvc(const std::string& name,ISvcLocator* svc)
276 : base_class(name,svc),
277 m_clidDBPath(System::getEnv("DATAPATH"))
278{
279}
280
281
282// Return all registered IDs in sorted order.
283std::vector<CLID> ClassIDSvc::sortedIDs() const
284{
285 std::vector<CLID> ids;
286 ids.reserve (m_clidMap.size());
287 for (const auto& p : m_clidMap) {
288 ids.push_back (p.first);
289 }
290 std::sort (ids.begin(), ids.end());
291 return ids;
292}
293
294
296StatusCode
298 bool allOK(true);
299 for (const std::string& DBFile : m_DBFiles) {
300 DirSearchPath::path clidDB(DBFile);
301
302 if (clidDB.is_absolute()) {
303 allOK = processCLIDDB(clidDB.string());
304 } else {
305 std::list<DirSearchPath::path> paths(m_clidDBPath.find_all(clidDB));
306 if (paths.empty()) {
307 ATH_MSG_DEBUG( "Could not resolve clid DB path " << clidDB
308 << " using DATAPATH. Skipping it." );
309 } else {
310 for (const auto& p : paths) {
311 allOK &= processCLIDDB(p.string());
312 }
313 }
314 }
315 }
316 return StatusCode(allOK);
317}
318
319
320bool
321ClassIDSvc::processCLIDDB(const std::string& fileName)
322{
323 std::ifstream ifile(fileName);
324 if (!ifile) {
325 ATH_MSG_WARNING( "processCLIDDB: unable to open " << fileName );
326 return true;
327 }
328
329 bool allOK(true);
330 unsigned int newEntries(0);
331 std::string line;
332 // Format: CLID;typeName[;typeInfoName]
333 while (allOK && std::getline(ifile, line)) {
334 std::vector<std::string> columns = CxxUtils::tokenize(line, ';');
335 long id(-1);
336 if (columns.size()>=2) {
337 columns[0] = CxxUtils::trimWhiteSpaces(columns[0]);
338 try {
339 id = std::stol(columns[0]);
340 } catch (const std::logic_error& e) {
341 ATH_MSG_ERROR( "processCLIDDB: Can't cast ["<< columns[0] << "] to long (clid): " << e.what() );
342 allOK = false;
343 }
344
345 if (uncheckedSetTypePackageForID(id, columns[1],
346 columns.size()>2 ? columns[2] : "")) {
347 ++newEntries;
348 }
349 }
350 }
351
352 if (!allOK) {
353 ATH_MSG_ERROR( "processCLIDDB: processing record '" << line
354 << "' from CLIDDB file: " << fileName );
355 } else {
356 ATH_MSG_DEBUG( "processCLIDDB: read " << newEntries <<
357 " entries from CLIDDB file: " << fileName );
358 }
359
360 return allOK;
361}
362
363
364bool ClassIDSvc::getRegistryEntries(const std::string& moduleName)
365{
366 //not only this is fast, but is necessary to prevent recursion
367 if (!CLIDRegistry::hasNewEntries()) return true;
368
369 bool allOK(true);
370 size_t newEntries(0);
371 //to speed up processing we only take entries added to CLIDRegistry
372 //since last call (thanks Niels!)
373 for (const auto& [clid, typeName, typeInfoName] : CLIDRegistry::newEntries()) {
374 ATH_MSG_VERBOSE( "reading [" << clid << ", " << typeName << ", " << typeInfoName << "]" );
375 if (uncheckedSetTypePackageForID(clid, typeName, typeInfoName)) {
376 ++newEntries;
377 }
378 else {
379 allOK = false;
380 }
381 }
382
383 if (allOK) {
384 ATH_MSG_INFO( "getRegistryEntries: read " << newEntries
385 << " CLIDRegistry entries for module " << moduleName );
386 } else {
387 ATH_MSG_ERROR("getRegistryEntries: can not read CLIDRegistry entries for module "
388 << moduleName );
389 }
390
391 return allOK;
392}
393
394
395StatusCode
397 const std::string& typeName,
398 const std::string& typeInfoName)
399{
400 // process "raw" typeName
401 std::string procName(typeName);
402 procName = CxxUtils::trimWhiteSpaces(procName);
403
404 if (procName.empty()) {
405 ATH_MSG_ERROR( "Empty type name for CLID " << id );
406 return StatusCode::FAILURE;
407 }
408
409 // assign typeInfoName
410 std::string procTiName;
411 if (typeInfoName.empty()) {
412 procTiName = procName;
413 }
414 else {
415 procTiName = typeInfoName;
416 procTiName = CxxUtils::trimWhiteSpaces(procTiName);
417 }
418
419 // insert into CLID map
420 const auto& [clid_it, clid_success] = m_clidMap.try_emplace(id, procName, procTiName);
421 if (!clid_success && clid_it->second!=std::make_pair(procName,procTiName)) {
422 ATH_MSG_ERROR( "Cannot set type " << std::make_pair(procName,procTiName) << " for CLID " <<
423 id << ": known type for this ID " << clid_it->second );
424 return StatusCode::FAILURE;
425 }
426
427 // insert into type name map
428 const auto& [name_it, name_success] = m_nameMap.try_emplace(procName, id);
429 if (!name_success && name_it->second!=id) {
430 ATH_MSG_ERROR( "Cannot set CLID " << id << " for type name '"
431 << procName << "': known CLID for this name " << name_it->second );
432 return StatusCode::FAILURE;
433 }
434
435 // insert into typeInfo map
436 const auto& [info_it, info_success] = m_tiNameMap.try_emplace(procTiName, id);
437 if (!info_success && info_it->second!=id) {
438 ATH_MSG_ERROR( "Cannot set CLID " << id << " for type-info name '"
439 << procTiName << "' and type '" << procName
440 << "': known CLID for this type-info name " << info_it->second );
441 return StatusCode::FAILURE;
442 }
443
444 ATH_MSG_VERBOSE( "Set type name '" << procName << "' for CLID " << id <<
445 " with type-info name '" << procTiName << "'" );
446
447 return StatusCode::SUCCESS;
448}
449
450
452{
453 // thread-safe because calls are protected by mutex or during initialize
454 ClassIDSvc* nc ATLAS_THREAD_SAFE = const_cast<ClassIDSvc*>(this);
455
456 // read CLID database in case initialize() was not called yet (ATR-23634)
457 [[maybe_unused]] static bool fillDB ATLAS_THREAD_SAFE = nc->fillDB().isSuccess();
458
459 // make sure registry is up-to-date
460 bool status = nc->getRegistryEntries ("ALL");
461
462 return status && fillDB;
463}
464
465
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
a static registry of CLID->typeName entries.
#define ATH_CONST_MSG_VERBOSE(x)
a service to manage and verify CLID assignments in athena
Helpers for checking error return status codes and reporting errors.
#define CHECK(...)
Evaluate an expression and check for errors.
uint32_t CLID
The Class ID type.
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
static bool hasNewEntries()
registry accessors (used by ClassIDSvc)
static CLIDVector_t newEntries()
returns an iterator range over the entries added since last time newEntries was called
virtual StatusCode initialize() override
Gaudi Service Implementation.
StatusCode fillDB()
get clids from CLIDDB and from registry entries
NameMap m_tiNameMap
Definition ClassIDSvc.h:126
Gaudi::Property< std::vector< std::string > > m_DBFiles
Definition ClassIDSvc.h:117
bool processCLIDDB(const std::string &fileName)
load clid/names from a "db" file
virtual StatusCode reinitialize() override
CLIDMap m_clidMap
Definition ClassIDSvc.h:124
void handle(const Incident &inc) override
implement IIncidentListener
Gaudi::Property< std::string > m_outputFileName
Definition ClassIDSvc.h:121
virtual CLID nextAvailableID() const override
get next available CLID
void dump() const
dump to MsgStream contents of in memory DB
StatusCode uncheckedSetTypePackageForID(const CLID &id, const std::string &typeName, const std::string &typeInfoName)
associate type name with clID w/o checking CLID range
virtual StatusCode getIDOfTypeInfoName(const std::string &typeInfoName, CLID &id) const override
get id associated with type-info name (if any)
bool getRegistryEntries(const std::string &moduleName)
load clid/names from a DLL registry
std::vector< CLID > sortedIDs() const
Return all registered IDs in sorted order.
virtual bool isNameInUse(const std::string &name) const override
check if id is used
virtual StatusCode finalize() override
dump CLIDmap to outputFileName;
virtual StatusCode getTypeNameOfID(const CLID &id, std::string &typeName) const override
get type name associated with clID (if any)
virtual StatusCode getTypeInfoNameOfID(const CLID &id, std::string &typeInfoName) const override
get user assigned type-info name associated with clID
virtual bool isIDInUse(const CLID &id) const override
check if id is used
DirSearchPath m_clidDBPath
The path is which clid db files are to be searched (DATAPATH).
Definition ClassIDSvc.h:129
bool maybeRescan() const
Test to see if anything new has been added to the registry.
virtual StatusCode getIDOfTypeName(const std::string &typeName, CLID &id) const override
get id associated with type name (if any)
std::lock_guard< mutex_t > lock_t
Definition ClassIDSvc.h:133
ClassIDSvc(const std::string &name, ISvcLocator *svc)
Standard Constructor.
mutex_t m_mutex
Definition ClassIDSvc.h:134
NameMap m_nameMap
Definition ClassIDSvc.h:125
virtual StatusCode setTypeForID(const CLID &id, const std::string &typeName, const std::string &typeInfoName="") override
associate type name, package info and type-info name with clID
const unsigned long MINCLID
const unsigned long MAXCLID
2**31 - 1
std::string_view trimWhiteSpaces(std::string_view str) noexcept
Removes all trailing and starting whitespaces from a string.
std::vector< std::string > tokenize(std::string_view the_str, std::string_view delimiters)
Splits the string into smaller substrings.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.