ATLAS Offline Software
Loading...
Searching...
No Matches
IdDictGroup.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4
6#include "src/Debugger.h"
10#include "IdDict/IdDictMgr.h"
14#include "Identifier/Range.h"
16
17#include <iostream>
18#include <map>
19#include <numeric> // for iota
20
21
26
27IdDictGroup::IdDictGroup (const std::string& name)
28 :
29 m_name(name),
31}
32
35
36const std::vector<IdDictRegion*>&
38 return(m_regions);
39}
40
44
45 for (const IdDictRegion* region : m_regions) {
46
47 // skip regions created from parents
48 if ("dummy" == region->name()) continue;
49
50 // skip empty regions - may arise from alternate_regions
51 // where a tag selects an empty region
52 if (region->is_empty()) continue;
53
54 Range r = region->build_range();
55 result.add(std::move(r));
56 }
57
58 return(result);
59}
60
61void
62IdDictGroup::add_dictentry(std::unique_ptr<IdDictDictEntry> region) {
63 m_entries.push_back(std::move(region));
64}
65
66void
68 IdDictDictionary& dictionary,
69 size_t& index) {
70 for (auto& ent : m_entries) {
71 ent->set_index(index);
72 index++;
73
74 ent->resolve_references(idd, dictionary);
75 }
76}
77
78void
80 IdDictDictionary& dictionary,
81 const std::string& tag) {
82 if (Debugger::debug()) {
83 std::cout << "IdDictGroup::generate_implementation>" << std::endl;
84 }
85
87 // Loop over entries and fill regions vec with selected region
88 // (AltRegions have a selection)
89 for (auto& ent : m_entries) {
90 ent->generate_implementation(idd, dictionary, tag);
91 // Get region and save in m_regions
92 IdDictRegion* region = dynamic_cast<IdDictRegion*> (ent.get());
93 if (region) {
94 m_regions.push_back(region);
95 } else {
96 IdDictAltRegions* altregions = dynamic_cast<IdDictAltRegions*> (ent.get());
97 if (altregions) {
98 m_regions.push_back(altregions->selected_region());
99 }
100 }
101 }
102
103 if (m_regions.size() != m_entries.size()) {
104 std::cout << "IdDictGroup::generate_implementation - mismatch of sizes: regions/entries "
105 << m_regions.size() << " " << m_entries.size()
106 << std::endl;
107 }
108
110 }
111}
112
113void
116 m_regions.clear();
117 for (auto& ent : m_entries) {
118 ent->reset_implementation();
119 }
121 }
122}
123
124bool
126 // Should check that all regions have the same number of levels,
127 // which is part of the definition of a group
128 return(true);
129}
130
138
140 std::map< ExpandedIdentifier, std::unique_ptr<IdDictDictEntry> > regions;
141
142 assert (m_regions.size() == m_entries.size());
143 for (size_t ientry = 0; IdDictRegion* region : m_regions) {
144 Range range = region->build_range();
145 RangeIterator itr(range);
146 auto first = itr.begin();
147 auto last = itr.end();
148 if (first != last) {
149 regions[*first] = std::move(m_entries[ientry++]);
150 } else {
151 std::cout << "IdDictDictionary::sort - WARNING empty region cannot sort "
152 << std::endl;
153 }
154 }
155 if (regions.size() != m_regions.size()) {
156 std::cout << "IdDictGroup::sort - WARNING region map size is NOT the same as the vector size. Map size "
157 << regions.size() << " vector size " << m_regions.size()
158 << std::endl;
159 }
160 // Reorder the regions
161 m_entries.resize (regions.size());
162 for (size_t vecIt = 0; auto& p : regions) {
163 m_entries[vecIt++] = std::move(p.second);
164 }
165}
166
167void
169 m_entries.clear();
170 m_regions.clear();
171 m_region_tree.clear();
172}
173
174
178 : m_impl (impl),
179 m_children (std::in_place_index<0>,
180 impl.ored_field().get_indices(), 0)
181{
182}
183
184
187{
188 if (m_children.index() == 0) {
189 uint64_t c = 0;
190 auto& children = std::get<0> (m_children);
191 size_t ipos = children.size();
192 while (ipos > 0 && children[ipos-1] == 0) {
193 --ipos;
194 }
195 if (ipos > 0) {
196 c = children[ipos-1];
197 size_t ipos2 = ipos;
198 while (ipos2 > 0 && children[ipos2-1] == c) {
199 --ipos2;
200 }
201 if (ipos2 > 0) return;
202 }
203 m_children.emplace<1> (ipos, c);
204 }
205}
206
207
218 const ExpandedIdentifier& prefix,
219 size_t index2,
220 ExpandedIdentifier& unpackedId,
221 std::vector<const IdDictFieldImplementation*>* impls /*= nullptr*/) const
222{
223 using element_type = ExpandedIdentifier::element_type;
224 using size_type = IdentifierField::size_type;
225
226 // Give up if the tree representation hasn't been built.
227 if (m_region_tree.empty()) std::abort();
228
229 // Clear output.
230 unpackedId.clear();
231 if (impls) {
232 impls->clear();
233 impls->reserve (12);
234 }
235
236 // Start at the first node, and assume success.
237 unsigned inode = 0;
238 int ret = 0;
239
240 // Loop over fields.
241 for (size_t index = 0; index <= index2; ++index) {
242
243 // Fetch the node.
245
246 // Find the index+value for this field. If we're looking at a prefix,
247 // get it from there; otherwise, unpack from the input identifier.
248 element_type val;
249 size_type validx;
250 if (index < prefix.fields()) {
251 val = prefix[index];
252 validx = n.m_impl.ored_field().get_value_index (val);
253 }
254 else {
255 validx = n.m_impl.unpackToIndex (id);
256 try {
257 val = n.m_impl.ored_field().get_value_at (validx);
258 } catch (const std::out_of_range&) {
259 ret = 1;
260 break;
261 }
262 }
263
264 // Find the next node.
265 if (n.m_children.index() == 0) {
266 // Children stored as a vector.
267 const auto& children = std::get<0> (n.m_children);
268 if (validx < children.size()) {
269 inode = children[validx];
270 }
271 else {
272 inode = 0;
273 }
274 }
275 else {
276 // Children stored as a size,node-number field.
277 const auto& children = std::get<1> (n.m_children);
278 if (validx < children.first) {
279 inode = children.second;
280 }
281 else {
282 inode = 0;
283 }
284 }
285
286 // Give up if no regions match the identifier.
287 if (!inode) {
288 break;
289 }
290
291 // Record this field in the output.
292 unpackedId.add (val);
293
294 // Also return the implementation, if requested.
295 // But we need to be sure that we return an implementation that actually
296 // matches the field value.
297 if (impls) {
298 if (n.m_impl.field().match (val)) {
299 impls->push_back (&n.m_impl);
300 }
301 else if (n.m_other_impls) {
302 for (const IdDictFieldImplementation* ii : *n.m_other_impls) {
303 if (ii->field().match (val)) {
304 impls->push_back (ii);
305 break;
306 }
307 }
308 }
309 if (unpackedId.fields() != impls->size()) std::abort();
310 }
311
312 // Stop if we've reached the end of the identifier.
313 if (inode == IdDictRegionTreeNode::END) break;
314 }
315
316 return ret;
317}
318
319
327 unsigned ifield,
328 unsigned inode)
329{
330 using element_type = IdentifierField::element_type;
331 using element_vector = IdentifierField::element_vector;
332 using size_type = IdentifierField::size_type;
333 using index_vector = IdentifierField::index_vector;
334
335 // Helper to retrieve the indices that may actually be used by a field.
336 // n is the node we're looking for. We use the ored_field referenced there
337 // to know what can actually be stored in the field.
338 // impl gives the field that we're trying to match.
339 // So we return the indices for the ored_field corresponding
340 // to valid values for impl.
341 auto get_field_indices = [] (const IdDictRegionTreeNode& n,
343 {
344 index_vector indices;
345 const Range::field& ored_field = n.m_impl.ored_field();
346 if (impl.field().isEnumerated()) {
347 const element_vector& vals = impl.field().get_values();
348 indices.reserve (vals.size());
349 for (element_type v : vals) {
350 indices.push_back (ored_field.get_value_index (v));
351 }
352 }
353 else if (impl.field().isBounded()) {
354 auto [minval, maxval] = impl.field().get_minmax();
355 size_type minidx = ored_field.get_value_index (minval);
356 size_type maxidx = ored_field.get_value_index (maxval);
357 indices.resize (maxidx - minidx + 1);
358 std::iota (indices.begin(), indices.end(), minidx);
359 }
360 else {
361 std::abort();
362 }
363 return indices;
364 };
365
366 // This will be the field we're matching.
367 const IdDictFieldImplementation& prev_impl = re.implementation(ifield-1);
368
369 {
370 // Get the children for the current node.
372 auto& children = std::get<0> (n.m_children);
373
374 // If we're looking at the last field, fill in the node pointersj
375 // with END; then we're done.
376 if (ifield == re.n_implementation()) {
377 index_vector indices = get_field_indices (n, prev_impl);
378 for (size_t idx : indices) {
379 children.at (idx) = IdDictRegionTreeNode::END;
380 }
381 return;
382 }
383
384 // Verify consistency of the field with what's stored in the node.
385 if (prev_impl.bits() != n.m_impl.bits() ||
386 prev_impl.bits_offset() != n.m_impl.bits_offset() ||
387 prev_impl.ored_field() != n.m_impl.ored_field())
388 {
389 dump();
390 std::abort();
391 }
392
393 // If this implementation has a field that is not equivalent with what
394 // we saved in the node, then save it in m_other_impls.
395 if (n.m_impl.field() != prev_impl.field()) {
396 if (!n.m_other_impls) {
397 n.m_other_impls = std::make_unique<std::vector<const IdDictFieldImplementation*> > (1, &prev_impl);
398 }
399 else {
400 if (std::ranges::find_if (*n.m_other_impls,
401 [&](const IdDictFieldImplementation* a)
402 { return a->field() == prev_impl.field(); })
403 == n.m_other_impls->end())
404 {
405 n.m_other_impls->push_back (&prev_impl);
406 }
407 }
408 }
409 }
410
411 // Indices we want to store.
412 index_vector indices = get_field_indices (m_region_tree[inode], prev_impl);
413 const IdDictFieldImplementation& impl = re.implementation(ifield);
414
415 // Children for the node.
416 auto children = [&]() -> std::vector<unsigned>& { return std::get<0> (m_region_tree[inode].m_children); };
417
418 unsigned new_node = 0;
419 std::vector<unsigned> nodes_seen;
420
421 // Loop over indices that we want to add.
422 for (size_t idx : indices) {
423
424 // If we've already recorded this index as END, fail.
425 unsigned next_node = children().at (idx);
426 if (next_node == IdDictRegionTreeNode::END) {
427 dump();
428 std::abort();
429 }
430
431 if (next_node != 0) {
432 // There is an existing node. Process it recursively; but we only
433 // need to this once for each unique node.
434 if (std::ranges::find (nodes_seen, next_node) == nodes_seen.end()) {
435 add_tree_field (re, ifield+1, next_node);
436 nodes_seen.push_back (next_node);
437 }
438 }
439 else {
440 // No node had been recorded for this index.
441 if (new_node != 0) {
442 // We've already made a new node. So just record it.
443 children().at(idx) = new_node;
444 }
445 else {
446 // Need to make a new node.
447 new_node = m_region_tree.size();
448 if (new_node == IdDictRegionTreeNode::END) {
449 std::abort();
450 }
451 // Careful --- this will invalidate references to nodes.
452 m_region_tree.emplace_back (impl);
453 children().at(idx) = new_node;
454 add_tree_field (re, ifield+1, new_node);
455 }
456 }
457 }
458}
459
460
464void
466{
467 // Loop through regions.
468 [[maybe_unused]] unsigned iregion = 0; // Region index, really only for debugging.
469 for (const IdDictRegion* re : m_regions) {
470 // Skip dummy/empty regions.
471 if (re->fieldSize() == 0 || re->name() == "dummy") {
472 ++iregion;
473 continue;
474 }
475
476 // Add an initial node if we haven't done so already.
477 if (m_region_tree.empty()) {
478 m_region_tree.emplace_back (re->implementation(0));
479 }
480
481 // Add nodes for the current region, starting at field 1.
482 add_tree_field (*re, 1, 0);
483
484 ++iregion;
485 }
486
487 // Compress child vectors if possible.
489 n.optimize();
490 }
491}
492
493
498{
499 std::cout << "===== IdDictGroup " << m_name << "\n";
500 dump_regions();
501 dump_tree();
502}
503
504
509{
510 std::cout << "Regions:\n";
511 for (unsigned iregion = 0; const IdDictRegion* re : m_regions) {
512 std::cout << " " << iregion++ << " " << re->name() << " " << re->group_name() << " " << re->tag() << "\n";
513 size_t nimpl = re->n_implementation();
514 bool first = true;
515 for (size_t i = 0; i < nimpl; ++i) {
516 const IdDictFieldImplementation& impl = re->implementation(i);
517 std::cout << (first ? " " : "; ") << impl.field() << " " << impl.ored_field() << " " << impl.bits() << "/" << impl.bits_offset();
518 first = false;
519 }
520 std::cout << "\n";
521 }
522}
523
524
529{
530 size_t sz = 0;
531 for (const auto& n : m_region_tree) {
532 if (n.m_children.index() == 0) {
533 sz += std::get<0>(n.m_children).size();
534 }
535 }
536 std::cout << "Region Tree totsize " << sz << "\n";
537 for (unsigned inode = 0; const auto& n : m_region_tree) {
538 std::cout << " " << inode++ << " " << n.m_impl.field()
539 << " " << n.m_impl.ored_field() << " -- ";
540
541 if (n.m_children.index() == 0) {
542 const auto& children = std::get<0> (n.m_children);
543 unsigned istart = 0;
544 unsigned ichild = 0;
545 bool first = true;
546 for (size_t i = 0; uint64_t c : children) {
547 if (c != ichild) {
548 if (ichild != 0) {
549 if (!first) std::cout << " ";
550 first = false;
551 if (istart != i-1) {
552 std::cout << istart << "-";
553 }
554 std::cout << i-1 << ":";
555 if (ichild == IdDictRegionTreeNode::END) {
556 std::cout << "END";
557 }
558 else {
559 std::cout << ichild;
560 }
561 }
562 ichild = c;
563 istart = i;
564 }
565 ++i;
566 }
567 if (ichild != 0) {
568 if (!first) std::cout << " ";
569 if (istart != children.size()-1) {
570 std::cout << istart << "-";
571 }
572 std::cout << children.size()-1 << ":";
573 if (ichild == IdDictRegionTreeNode::END) {
574 std::cout << "END";
575 }
576 else {
577 std::cout << ichild;
578 }
579 }
580 }
581 else {
582 const auto& children = std::get<1> (n.m_children);
583 if (children.first == 1) {
584 std::cout << "0:";
585 }
586 else {
587 std::cout << "0-" << children.first-1 << ":";
588 }
589 if (children.second == IdDictRegionTreeNode::END) {
590 std::cout << "END";
591 }
592 else {
593 std::cout << children.second;
594 }
595 }
596 if (n.m_other_impls) {
597 std::cout << " [";
598 bool first = true;
599 for (const IdDictFieldImplementation* ii : *n.m_other_impls) {
600 if (!first)
601 std::cout << "; ";
602 else
603 first = false;
604 std::cout << ii->field();
605 }
606 std::cout << "]";
607 }
608 std::cout << "\n";
609 }
610 std::cout.flush();
611}
const boost::regex re(r_e)
static Double_t sz
static Double_t a
static bool debug()
Definition Debugger.h:18
size_type fields() const
void add(element_type value)
Append a value into a new field.
void clear()
Erase all fields.
IdDictRegion * selected_region()
Currently selected region.
IdDictFieldImplementation is used to capture the specification of a single field of an Identifier.
const Range::field & ored_field() const
const Range::field & field() const
const std::vector< IdDictRegion * > & regions()
Non-const access to regions.
bool m_generated_implementation
std::vector< IdDictRegionTreeNode > m_region_tree
The list of region nodes.
void add_dictentry(std::unique_ptr< IdDictDictEntry > entry)
std::vector< std::unique_ptr< IdDictDictEntry > > m_entries
void build_region_tree()
Take the list of regions and build a tree structure for fast unpacking.
std::string m_name
int unpack(const Identifier &id, const ExpandedIdentifier &prefix, size_t index2, ExpandedIdentifier &unpackedId, std::vector< const IdDictFieldImplementation * > *impls=nullptr) const
Unpack the value_type id to an expanded Identifier, considering the provided prefix (result will incl...
void sort()
Sort:
void dump_tree() const
Dump the tree structure built from the regions for fast unpacking.
std::vector< IdDictRegion * > m_regions
void dump_regions() const
Dump the list of regions for this group.
void reset_implementation()
const IdDictRegion & region(size_t index) const
void generate_implementation(const IdDictMgr &idd, IdDictDictionary &dictionary, const std::string &tag="")
void add_tree_field(const IdDictRegion &re, unsigned ifield, unsigned inode)
Recursively add new nodes to the tree structure.
MultiRange build_multirange() const
Get MultiRange for this group.
const std::string & name() const
void dump() const
Dump regions and tree for this group.
void resolve_references(IdDictMgr &idd, IdDictDictionary &dictionary, size_t &index)
bool verify() const
ExpandedIdentifier::size_type size_type
std::vector< element_type > element_vector
size_type get_value_index(element_type value) const
ExpandedIdentifier::element_type element_type
bool match(element_type value) const
The basic match operation Given a value, test to see if it satisfies the constraints for this field.
std::vector< size_type > index_vector
A MultiRange combines several Ranges.
Definition MultiRange.h:17
This iterator is able to generate all possible identifiers, from a fully bounded Range.
RangeIterator end() const
RangeIterator begin() const
A Range describes the possible ranges for the field values of an ExpandedIdentifier.
int r
Definition globals.cxx:22
Definition index.py:1
STL namespace.
Tree structure for fast unpacking.
const IdDictFieldImplementation & m_impl
Reference to the the implementation field.
std::variant< std::vector< unsigned >, ChildPair > m_children
void optimize()
Compress the vector of node indices, if they are all the same.
static constexpr unsigned END
Special value used to indicate that we've reached the end.
IdDictRegionTreeNode(const IdDictFieldImplementation &impl)
Constructor, taking a reference to the implementation.