ATLAS Offline Software
IdentifierField.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
7 #include <algorithm>
8 #include <iostream>
9 #include <bit> //std::bit_width
10 #include <array>
11 #include <cctype> //std::isspace
12 #include <format>
13 #include <tuple> //for std::tie
14 #include <functional> //std::less
15 
16 using namespace Identifier;
17 
18 namespace{
19 template<class SetA, class SetB, typename Compare = std::less<>>
20 bool
21 share_element(SetA&& setA, SetB&& setB, Compare comp = Compare{}){
22  auto xA = setA.begin();
23  auto xB = setB.begin();
24  while (xA != setA.end() && xB != setB.end()){
25  if (comp(*xA, *xB)) {
26  ++xA;
27  } else if (comp(*xB, *xA)) {
28  ++xB;
29  } else {
30  return true;
31  }
32  }
33  return false;
34 }
35 
36 }
37 
38 
39 //------------------------------------------------------------------
41  size_t indices = get_indices ();
42  if (--indices) return std::bit_width(indices);
43  return 1;
44 }
45 
46 
47 //-----------------------------------------------
50  // Only both_bounded and enumerated are valid to calculate the
51  // index.
52  // both_bounded if the more frequent case and so comes first.
53  if (isBounded()) {
54  return (value - m_minimum);
55  }
56  if (not m_indexes.empty()) {
57  // Table has been created, do simple lookup
58  assert (value >= m_minimum && value - m_minimum < (int)m_indexes.size());
59  return (m_indexes.at(value - m_minimum));
60  } else {
61  const auto & v = get_values();
62  auto it = std::ranges::lower_bound(v, value);
63  if (it != v.end()) return std::distance(v.begin(), it);
64  }
65  return 0;
66 }
67 
68 //-----------------------------------------------
69 bool
71  if (isBounded()) {
72  return ((value >= m_minimum) && (value <= m_maximum));
73  }
74  if (m_empty) return true;
75  const auto & v = get_values();
76  return (std::ranges::binary_search(v, value));
77 }
78 
79 
80 
81 //-----------------------------------------------
83  :
84  m_minimum(value),
85  m_maximum(value),
87  m_empty{false}{
88  //
89 }
90 
91 //-----------------------------------------------
93  set(minimum, maximum);
94 }
95 
96 
99  set(values);
100 }
101 
102 
103 //-----------------------------------------------
104 bool
106  if (m_empty){
107  previous = current - 1;
108  return (current != minimum_possible);
109  }
110  if (isBounded()){
111  if (current == m_minimum) {
114  return (true);
115  }
118  return (true);
119  }
120  previous = current;
121  return (false);
122  }
123  previous = current - 1;
124  return (true);
125  }
126  const auto & values= get_values();
128  if (index == 0) {
130  previous = values.back();
131  return (true);
132  }
135  return (true);
136  }
137  previous = current;
138  return (false);
139  }
140  --index;
141  previous = values[index];
142  return true;
143 }
144 
145 
146 //-----------------------------------------------
147 bool
149  if (m_empty){
150  next = current + 1;
151  return (current != maximum_possible);
152  }
153 
154  if (isBounded()){
155  if (current == m_maximum) {
157  next = m_minimum;
158  return (true);
159  }
160  if (has_next == m_continuation_mode) {
161  next = m_next;
162  return (true);
163  }
164  next = current;
165  return (false);
166  }
167  next = current + 1;
168  return (true);
169  }
170  const auto & values= get_values();
172  if ((index == values.size() - 1) || (index == 0 && current != values.front())) {
174  next = values.front();
175  return (true);
176  }
177  if (has_next == m_continuation_mode) {
178  next = m_next;
179  return (true);
180  }
181  next = current;
182  return (false);
183  }
184  ++index;
185  next = values[index];
186  return true;
187 }
188 
189 
190 
191 //-----------------------------------------------
192 bool
194  if (m_empty or other.m_empty) return true;
195  //
196  if (isBounded() and other.isBounded()){
197  return ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum));
198  }
199  //
200  if (isBounded() and other.isEnumerated() ){
201  const element_vector& ev = other.get_values();
202  for (const auto & v: ev) {
203  if (v >= m_minimum and v<= m_maximum) return (true);
204  }
205  return false;
206  } else if (isEnumerated() and other.isBounded()){
207  const element_vector& ev = get_values();
208  for (const auto & v: ev){
209  if ((v >= other.m_minimum) and (v <= other.m_maximum)) return (true);
210  }
211  return false;
212  }
213  // Both fields are enumerated only if there is possibility of overlap
214  if ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum)) {
215  return share_element(get_values(), other.get_values());
216  }
217  return (false);
218 }
219 
220 
221 //-----------------------------------------------
222 void
224  m_minimum = 0;
225  m_maximum = 0;
226  m_previous = 0;
227  m_next = 0;
230  m_indexes.clear();
231  m_empty = true;
232 }
233 
234 //-----------------------------------------------
235 void
237  if (minimum == maximum) {
238  add_value(minimum);
239  } else {
240  std::tie(m_minimum,m_maximum) = std::minmax(minimum,maximum);
242  m_size = m_maximum - m_minimum + 1;
243  }
244  m_empty=false;
245 }
246 
247 //-----------------------------------------------
248 void
250  if (auto * p = dataPtr<element_vector>(); !p) {
251  clear();
252  m_data = element_vector(1,value);//now its enumerated
253  m_size = 1;
254  } else {
255  //check whether value already exists in the enumeration vector
256  if (std::ranges::binary_search(*p, value)) return;
257  p->push_back(value);
258  std::ranges::sort(*p);
259  m_size = p->size();
260  }
261  m_minimum = get_values().front();
262  m_maximum = get_values().back();
263  m_empty = false;
264 }
265 
266 //-----------------------------------------------
267 void
268 IdentifierField::set(const std::vector <element_type>& values) {
269  auto * p = dataPtr<element_vector>();
270  if (not p) {
271  clear();
272  p = dataPtr<element_vector>();
273  }
274  p->insert(p->end(), values.begin(), values.end());
275  std::ranges::sort (*p);
276  //ensure duplicates are taken out
277  p->erase( std::unique( p->begin(), p->end() ), p->end() );
278  m_minimum = p->front();
279  m_maximum = p->back();
280  m_empty=false;
281  m_size = p->size();
282 }
283 
284 //-----------------------------------------------
285 void
286 IdentifierField::set(bool wraparound) {
287  if (wraparound) {
289  }
290 }
291 
292 //-----------------------------------------------
293 void
297  } else {
299  }
300  m_next = next;
301 }
302 
303 
304 //-----------------------------------------------
305 void
307  if (has_next == m_continuation_mode) {
309  } else {
311  }
313 }
314 
315 
316 //-----------------------------------------------
317 void
319  if (m_empty or other.m_empty){
320  clear();
321  m_size = 1;
322  return;
323  }
324  if (isEnumerated() and other.isEnumerated()){
325  set(other.get_values ());
326  return;
327  }
334  // all other cases...
335  const auto min = std::min(m_minimum, other.m_minimum);
336  const auto max = std::max(m_maximum, other.m_maximum);
337  set(min, max);
338 }
339 
340 
341 //-----------------------------------------------
342 IdentifierField::operator std::string () const {
343  std::string result;
344  if (m_empty) {
345  result = "*";
346  } else {
347  const auto & [minimum, maximum] = get_minmax();
348  if (minimum == maximum) {
349  result = std::to_string(minimum);
350  } else {
351  if (isEnumerated()) {
352  std::string prefix;
353  for (size_type i = 0; i < get_indices (); ++i) {
354  result += prefix+std::to_string(get_value_at(i));
355  prefix = ",";
356  }
357  } else {
358  result = std::format("{}:{}", minimum, maximum);
359  }
360  }
361  }
362  return result;
363 }
364 
365 //-----------------------------------------------
366 bool
368  if (m_data != other.m_data) return false;
369  return (true);
370 }
371 
372 
373 //-----------------------------------------------
374 void
376  std::cout << "min/max " << m_minimum << " " << m_maximum << " ";
377  std::cout << "values ";
378  for (const auto& v: get_values()) {
379  std::cout << v << " ";
380  }
381  std::cout << "indexes ";
382  for (const auto & idx: m_indexes) {
383  std::cout << idx << " ";
384  }
385  std::cout << "indices " << m_size << " ";
386  std::cout << "prev " << m_previous << " ";
387  std::cout << "next " << m_next << " ";
388  std::cout << "mode ";
389  if (m_empty){
390  std::cout << "unbounded ";
391  }else if (isBounded()){
392  std::cout << "both_bounded ";
393  }else if (isEnumerated()) {
394  std::cout << "enumerated ";
395  }
396  std::cout << "cont mode ";
397  switch (m_continuation_mode) {
398  case IdentifierField::none:
399  std::cout << "none ";
400  break;
402  std::cout << "has_next ";
403  break;
405  std::cout << "has_previous ";
406  break;
408  std::cout << "has_both ";
409  break;
411  std::cout << "has_wrap_around ";
412  break;
413  }
414  std::cout << std::endl;
415 }
416 
417 
418 
419 //-----------------------------------------------
420 void
424 }
425 
426 
427 //-----------------------------------------------
428 bool
430  if (m_empty) return false;
431  if (isEnumerated()) {
432  //the enumerated values are kept sorted
433  if (m_size-1 == static_cast<size_type>(m_maximum - m_minimum)){
435  return true;
436  }
437  }
438  return false;
439 }
440 
441 //-----------------------------------------------
442 void
444  if (m_empty) return;
446  if (isEnumerated()) {
448  // return if we are over the maximum desired vector table size
449  if (size > m_maxNumberOfIndices) {
450  m_indexes.clear();
451  return;
452  }
453  // Set up vectors for decoding
454  m_indexes = std::vector<size_type>(size, 0);
455  size_type index{};
456  int i{};
457  auto &v = std::get<element_vector>(m_data);
458  for (const auto & thisValue: v) {
459  if (const auto idx=(thisValue - m_minimum); idx < (int)size) {
460  m_indexes[idx] = index;
461  index++;
462  } else {
463  std::cout << "size, value, index, i "
464  << size << " " << thisValue << " "
465  << index << " " << i++ << " min, max "
466  << m_minimum << " "
467  << m_maximum
468  << std::endl;
469  }
470  }
471  }
472 }
473 
474 std::ostream &
475 operator << (std::ostream &out, const IdentifierField &c){
476  out<<std::string(c);
477  return out;
478 }
479 
480 //stream extraction allows to read from text (e.g. text file)
481 std::istream &
482 operator >> (std::istream &is, IdentifierField &idf){
483  idf.clear();
484  while (std::isspace(is.peek())){is.ignore();}
485  char c = is.peek();
486  if (c =='*'){
487  is.ignore();
488  //do nothing; the 'clear' set idf to unbounded
489  } else if (isDigit(c)){
490  if (c =='+') is.ignore();
491  int v = parseStreamDigits(is);//'is' ptr is incremented
492  c = is.peek();
493  //possible: bound, list
494  if (c == ','){ //found comma, so definitely list
495  is.ignore();
496  std::vector<int> vec(1,v);
497  const auto & restOfList = parseStreamList(is);
498  vec.insert(vec.end(), restOfList.begin(), restOfList.end());
499  idf.set(vec);
500  } else if (c == ':'){ //bounded
501  is.ignore();
502  c=is.peek(); //peek char after the colon
503  if (isDigit(c)){ //bounded
504  int v1 = parseStreamDigits(is);
505  idf.set(v,v1);
506  }
507  } else { //remaining alternative: single number
508  idf.add_value(v);
509  }
510  } else {
511  std::string msg{"Stream extraction for IdentifierField: "};
512  std::string remains;
513  is >> remains;
514  msg+=remains;
515  throw std::invalid_argument(msg);
516  }
517  return is;
518 }
519 
plotting.yearwise_luminosity_vs_mu.comp
comp
Definition: yearwise_luminosity_vs_mu.py:23
fillPileUpNoiseLumi.current
current
Definition: fillPileUpNoiseLumi.py:52
get_generator_info.result
result
Definition: get_generator_info.py:21
max
#define max(a, b)
Definition: cfImp.cxx:41
vtune_athena.format
format
Definition: vtune_athena.py:14
IdentifierField::get_bits
size_type get_bits() const
Definition: IdentifierField.cxx:40
IdentifierField::element_type
ExpandedIdentifier::element_type element_type
Definition: IdentifierField.h:23
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
IdentifierField::overlaps_with
bool overlaps_with(const IdentifierField &other) const
Check whether two IdentifierFields overlap.
Definition: IdentifierField.cxx:193
index
Definition: index.py:1
m_data
std::vector< T > m_data
Definition: TrackTruthMatchingBaseAlg.cxx:660
IdentifierField::m_maxNumberOfIndices
static constexpr int m_maxNumberOfIndices
Definition: IdentifierField.h:120
Trk::indices
std::pair< long int, long int > indices
Definition: AlSymMatBase.h:24
Identifier::parseStreamDigits
IdentifierField::element_type parseStreamDigits(std::istream &is)
Definition: IdentifierFieldParser.cxx:21
skel.it
it
Definition: skel.GENtoEVGEN.py:396
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
IdentifierField::clear
void clear()
Set methods.
Definition: IdentifierField.cxx:223
IdentifierField::m_maximum
element_type m_maximum
Definition: IdentifierField.h:130
athena.value
value
Definition: athena.py:124
operator>>
std::istream & operator>>(std::istream &is, IdentifierField &idf)
Definition: IdentifierField.cxx:482
IdentifierField::get_values
const element_vector & get_values() const
Definition: IdentifierField.h:71
IdentifierField::set
void set(element_type minimum, element_type maximum)
Definition: IdentifierField.cxx:236
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:12
IdentifierField::has_both
@ has_both
Definition: IdentifierField.h:36
IdentifierField::m_continuation_mode
continuation_mode m_continuation_mode
Definition: IdentifierField.h:137
Identifier::parseStreamList
IdentifierField::element_vector parseStreamList(std::istream &is)
Definition: IdentifierFieldParser.cxx:37
IdentifierField::set_next
void set_next(int next)
Definition: IdentifierField.cxx:294
IdentifierField::m_next
element_type m_next
Definition: IdentifierField.h:135
IdentifierField::create_index_table
void create_index_table()
Create index table from value table.
Definition: IdentifierField.cxx:443
python.Bindings.values
values
Definition: Control/AthenaPython/python/Bindings.py:805
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
CxxUtils::vec
typename vecDetail::vec_typedef< T, N >::type vec
Define a nice alias for the vectorized type.
Definition: vec.h:207
IdentifierField::m_size
size_type m_size
Definition: IdentifierField.h:133
IdentifierField::match
bool match(element_type value) const
The basic match operation.
Definition: IdentifierField.cxx:70
IdentifierFieldParser.h
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ev
int ev
Definition: globals.cxx:25
IdentifierField::get_value_index
size_type get_value_index(element_type value) const
Definition: IdentifierField.cxx:49
Identifier::isDigit
bool isDigit(const char c)
Definition: IdentifierFieldParser.cxx:16
IdentifierField::operator==
bool operator==(const IdentifierField &other) const
Definition: IdentifierField.cxx:367
fillPileUpNoiseLumi.next
next
Definition: fillPileUpNoiseLumi.py:52
lumiFormat.i
int i
Definition: lumiFormat.py:85
IdentifierField::m_previous
element_type m_previous
Definition: IdentifierField.h:134
IdentifierField::minimum_possible
static constexpr auto minimum_possible
Definition: IdentifierField.h:28
IdentifierField::m_minimum
element_type m_minimum
Definition: IdentifierField.h:129
IdentifierField::m_data
std::variant< element_vector, BoundedRange > m_data
Definition: IdentifierField.h:131
checkCorrelInHIST.prefix
dictionary prefix
Definition: checkCorrelInHIST.py:391
IdentifierField::get_next
bool get_next(element_type current, element_type &next) const
Definition: IdentifierField.cxx:148
operator<<
std::ostream & operator<<(std::ostream &out, const IdentifierField &c)
Definition: IdentifierField.cxx:475
IdentifierField::isEnumerated
bool isEnumerated() const
Definition: IdentifierField.h:117
ExpandedIdentifier::size_type
boost::container::small_vector< element_type, 12 >::size_type size_type
Definition: DetectorDescription/Identifier/Identifier/ExpandedIdentifier.h:112
IdentifierField::element_vector
std::vector< element_type > element_vector
Definition: IdentifierField.h:25
IdentifierField::none
@ none
Definition: IdentifierField.h:33
min
#define min(a, b)
Definition: cfImp.cxx:40
IdentifierField.h
IdentifierField::set_previous
void set_previous(int previous)
Definition: IdentifierField.cxx:306
IdentifierField::check_for_both_bounded
bool check_for_both_bounded()
Check mode - switch from enumerated to both_bounded if possible.
Definition: IdentifierField.cxx:429
IdentifierField::size_type
ExpandedIdentifier::size_type size_type
Definition: IdentifierField.h:24
IdentifierField::maximum_possible
static constexpr auto maximum_possible
Definition: IdentifierField.h:29
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
IdentifierField::isBounded
bool isBounded() const
Definition: IdentifierField.h:116
IdentifierField::has_wrap_around
@ has_wrap_around
Definition: IdentifierField.h:37
python.PyAthena.v
v
Definition: PyAthena.py:154
IdentifierField::m_empty
bool m_empty
Definition: IdentifierField.h:136
DeMoScan.index
string index
Definition: DeMoScan.py:364
InDetDD::other
@ other
Definition: InDetDD_Defs.h:16
IdentifierField::operator|=
void operator|=(const IdentifierField &other)
Definition: IdentifierField.cxx:318
IdentifierField::m_indexes
index_vector m_indexes
Definition: IdentifierField.h:132
IdentifierField
This is the individual specification for the range of one ExpandedIdentifier IdentifierField.
Definition: IdentifierField.h:21
IdentifierField::BoundedRange
std::pair< element_type, element_type > BoundedRange
Definition: IdentifierField.h:27
IdentifierField::has_next
@ has_next
Definition: IdentifierField.h:34
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
IdentifierField::get_previous
bool get_previous(element_type current, element_type &previous) const
Returns false if previous/next is at end of range, or not possible.
Definition: IdentifierField.cxx:105
IdentifierField::has_previous
@ has_previous
Definition: IdentifierField.h:35
IdentifierField::show
void show() const
Definition: IdentifierField.cxx:375
IdentifierField::optimize
void optimize()
Optimize - try to switch mode to both_bounded, set up lookup table for finding index from value.
Definition: IdentifierField.cxx:421
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
python.compressB64.c
def c
Definition: compressB64.py:93
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
IdentifierField::add_value
void add_value(element_type value)
Definition: IdentifierField.cxx:249
Trk::previous
@ previous
Definition: BinningData.h:32
IdentifierField::IdentifierField
IdentifierField()=default
Create a wild-card value.
Identifier
Definition: IdentifierFieldParser.cxx:14