ATLAS Offline Software
Loading...
Searching...
No Matches
SpecRegistry.cxx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4#include "SpecRegistry.h"
5
8
10
11#include "TClass.h"
12#include "TEnv.h"
13#include "THashList.h"
14#include "TInterpreter.h"
15
16#include <map>
17#include <memory>
18#include <mutex>
19#include <set>
20#include <string_view>
21#include <iostream>
22
23namespace GlobalSim {
24
25 namespace {
26
27 using BitsGetter = std::function<std::string(const SG::AuxElement&)>;
28 using BitsSetter = std::function<void(SG::AuxElement&, const std::string&)>;
29
30 constexpr std::string_view s_prefix{"GlobalSim::"};
31
37 const std::set<std::string>& registeredSpecs() {
38 static const std::set<std::string> specs = [] {
39 std::set<std::string> found;
40 const TEnv* mapfile = gInterpreter->GetMapfile();
41 if (mapfile == nullptr or mapfile->GetTable() == nullptr) { return found; }
42
43 for (const TObject* record : *mapfile->GetTable()) {
44 const std::string_view cls{record->GetName()};
45 if (not cls.starts_with(s_prefix)) { continue; }
46 const std::string_view name = cls.substr(s_prefix.size());
47 if (name.empty() or name.front() == '_' or
48 name.find('<') != std::string_view::npos) { continue; }
49 // verify if not a namespace
50 if(auto tcls = TClass::GetClass(cls.data()); tcls && (tcls->Property()&kIsNamespace)) {
51 continue;
52 }
53 found.emplace(name);
54 }
55 return found;
56 }();
57 return specs;
58 }
59
65 template<class T>
66 std::shared_ptr<T> interpret(const std::string& code, std::string& error) {
67 TInterpreter::EErrorCode err = TInterpreter::kNoError;
68 const Longptr_t address = gInterpreter->ProcessLine(code.c_str(), &err);
69 if (address == 0 or err != TInterpreter::kNoError) {
70 error = "the interpreter would not compile:\n" + code;
71 return nullptr;
72 }
73 return std::shared_ptr<T>(reinterpret_cast<T*>(address));
74 }
75
80 bool prepareInterpreter(const std::string& spec, std::string& error) {
81 if (TClass::GetClass(spec.c_str()) == nullptr) {
82 error = "no dictionary could be loaded for " + spec;
83 return false;
84 }
85 static const bool declared =
86 gInterpreter->Declare("#include \"GlobalSimulation/Object.h\"");
87 if (not declared) {
88 error = "the interpreter could not read GlobalSimulation/Object.h";
89 }
90 return declared;
91 }
92
93 SpecEntry buildEntry(const std::string& name, std::string& error) {
94 const std::string spec = "GlobalSim::" + name;
95 const std::string object = "GlobalSim::Object<" + spec + ">";
96
97 if (not prepareInterpreter(spec, error)) { return {}; }
98
99 // The packed word crosses into the interpreter as a string of '0' and
100 // '1' rather than as an integer: to_ullong() is fine for a 64 bit spec
101 // but throws for anything wider, and JET1Jet is 128 bits.
102 auto getter = interpret<BitsGetter>(
103 "new std::function<std::string(const SG::AuxElement&)>("
104 "[](const SG::AuxElement& tob) {"
105 " return " + object + "(tob).bits().to_string();"
106 "});", error);
107 if (not getter) { return {}; }
108
109 auto setter = interpret<BitsSetter>(
110 "new std::function<void(SG::AuxElement&, const std::string&)>("
111 "[](SG::AuxElement& tob, const std::string& bits) {"
112 " " + object + " obj(tob);"
113 " obj = " + spec + "::bitset_type(bits);"
114 "});", error);
115 if (not setter) { return {}; }
116
117 auto width = interpret<std::size_t>("new std::size_t(" + spec + "::width);",
118 error);
119 if (not width) { return {}; }
120
121 // The hex conversion stays on this side: binStrToHexStr is declared under
122 // src/Utilities, which is not part of the dictionary, so the interpreter
123 // cannot see it. Keeping it here also leaves SpecEntry unchanged.
124 return {*width,
125 [g = std::move(getter)](const SG::AuxElement& tob) {
126 return binStrToHexStr((*g)(tob));
127 },
128 [s = std::move(setter)](SG::AuxElement& tob, const std::string& token) {
129 (*s)(tob, hexStrToBinStr(token));
130 }};
131 }
132
133 } // anonymous namespace
134
135 const SpecEntry* specEntry(const std::string& name, std::string& error) {
136 // Reaching into the interpreter costs milliseconds and is not thread safe,
137 // so each spec is built once behind a lock. Both algorithms ask in
138 // initialize(), where the lock is uncontended; it is here so that the cache
139 // stays correct if that ever changes. References into a std::map survive
140 // later insertions, so the returned pointer stays valid.
141 static std::map<std::string, SpecEntry> cache ATLAS_THREAD_SAFE; // guarded by mutex
142 static std::mutex mutex;
143
144 const std::scoped_lock lock(mutex);
145
146 const auto cached = cache.find(name);
147 if (cached != cache.end()) { return &cached->second; }
148
149 if (not registeredSpecs().contains(name)) {
150 error = "not listed in GlobalSimulation/selection.xml. Known specs are: "
151 + knownSpecNames();
152 return nullptr;
153 }
154
155 SpecEntry entry = buildEntry(name, error);
156 if (entry.width == 0) { return nullptr; }
157
158 return &cache.emplace(name, std::move(entry)).first->second;
159 }
160
161 std::string knownSpecNames() {
162 std::string names;
163 for (const auto& spec : registeredSpecs()) {
164 if (not names.empty()) { names += ", "; }
165 names += spec;
166 }
167 if (names.empty())[[unlikely]]{
168 return "none -- no GlobalSim classes found in the rootmap";
169 }
170 return names;
171 }
172
173}
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
const double width
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
STL class.
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:116
AlgTool to read in LArStripNeighborhoods, and run the BDT Algorithm.
Definition BitSpec.h:24
const SpecEntry * specEntry(const std::string &name, std::string &error)
The entry for one spec, or nullptr if there is not one.
std::string hexStrToBinStr(std::string s)
std::string knownSpecNames()
Comma-separated list of the names in the dictionary, for error messages.
std::string binStrToHexStr(std::string_view s)
AuxElement(SG::AuxVectorData *container, size_t index)
Base class for elements of a container that can have aux data.
unsigned long long T
#define unlikely(x)