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