ATLAS Offline Software
Loading...
Searching...
No Matches
IdentifierField.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "GaudiKernel/MsgStream.h"
8#include <algorithm>
9#include <sstream> //ostringstream
10#include <bit> //std::bit_width
11#include <array>
12#include <cctype> //std::isspace
13#include <format>
14#include <tuple> //for std::tie
15#include <functional> //std::less
16
17using namespace Identifier;
18
19namespace{
20template<class SetA, class SetB, typename Compare = std::less<>>
21bool
22share_element(SetA&& setA, SetB&& setB, Compare comp = Compare{}){
23 auto xA = setA.begin();
24 auto xB = setB.begin();
25 while (xA != setA.end() && xB != setB.end()){
26 if (comp(*xA, *xB)) {
27 ++xA;
28 } else if (comp(*xB, *xA)) {
29 ++xB;
30 } else {
31 return true;
32 }
33 }
34 return false;
35}
36
37}
38
39
40//------------------------------------------------------------------
42 size_t indices = get_indices ();
43 if (--indices) return std::bit_width(indices);
44 return 1;
45}
46
47
48//-----------------------------------------------
51 // Only both_bounded and enumerated are valid to calculate the
52 // index.
53 // both_bounded if the more frequent case and so comes first.
54 if (isBounded()) {
55 return (value - m_minimum);
56 }
57 const auto & v = get_values();
58 if (v.size()==1) return 0;
59 if (not m_indexes.empty()) {
60 // Table has been created, do simple lookup
61 assert (value >= m_minimum && value - m_minimum < (int)m_indexes.size());
62 return (m_indexes.at(value - m_minimum));
63 } else {
64 auto it = std::ranges::find(v, value);
65 if (it != v.end()) return std::distance(v.begin(), it);
66 }
67 return 0;
68}
69
70//-----------------------------------------------
71bool
73 if (isBounded()) {
74 return ((value >= m_minimum) && (value <= m_maximum));
75 }
76 if (m_empty) return true;
77 const auto & v = get_values();
78 return (std::ranges::find(v, value)!=v.end());
79}
80
81
82
83//-----------------------------------------------
85 :
86 m_minimum(value),
87 m_maximum(value),
88 m_data{BoundedRange{value, value}},
89 m_empty{false}{
90 //
91}
92
93//-----------------------------------------------
95 set(minimum, maximum);
96}
97
98
101 set(values);
102}
103
104
105//-----------------------------------------------
106bool
108 if (m_empty){
109 previous = current - 1;
110 return (current != minimum_possible);
111 }
112 if (isBounded()){
113 if (current == m_minimum) {
115 previous = m_maximum;
116 return (true);
117 }
119 previous = m_previous;
120 return (true);
121 }
122 previous = current;
123 return (false);
124 }
125 previous = current - 1;
126 return (true);
127 }
128 const auto & values= get_values();
130 if (index == 0) {
132 previous = values.back();
133 return (true);
134 }
136 previous = m_previous;
137 return (true);
138 }
139 previous = current;
140 return (false);
141 }
142 --index;
143 previous = values[index];
144 return true;
145}
146
147
148//-----------------------------------------------
149bool
151 if (m_empty){
152 next = current + 1;
153 return (current != maximum_possible);
154 }
155
156 if (isBounded()){
157 if (current == m_maximum) {
159 next = m_minimum;
160 return (true);
161 }
163 next = m_next;
164 return (true);
165 }
166 next = current;
167 return (false);
168 }
169 next = current + 1;
170 return (true);
171 }
172 const auto & values= get_values();
174 if ((index == values.size() - 1) || (index == 0 && current != values.front())) {
176 next = values.front();
177 return (true);
178 }
180 next = m_next;
181 return (true);
182 }
183 next = current;
184 return (false);
185 }
186 ++index;
187 next = values[index];
188 return true;
189}
190
191
192
193//-----------------------------------------------
194bool
196 if (m_empty or other.m_empty) return true;
197 //
198 if (isBounded() and other.isBounded()){
199 return ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum));
200 }
201 //
202 if (isBounded() and other.isEnumerated() ){
203 const element_vector& ev = other.get_values();
204 for (const auto & v: ev) {
205 if (v >= m_minimum and v<= m_maximum) return (true);
206 }
207 return false;
208 } else if (isEnumerated() and other.isBounded()){
209 const element_vector& ev = get_values();
210 for (const auto & v: ev){
211 if ((v >= other.m_minimum) and (v <= other.m_maximum)) return (true);
212 }
213 return false;
214 }
215 // Both fields are enumerated only if there is possibility of overlap
216 if ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum)) {
217 return share_element(get_values(), other.get_values());
218 }
219 return (false);
220}
221
222
223//-----------------------------------------------
224void
226 m_minimum = 0;
227 m_maximum = 0;
228 m_previous = 0;
229 m_next = 0;
232 m_indexes.clear();
233 m_empty = true;
234}
235
236//-----------------------------------------------
237void
239 if (minimum == maximum) {
240 add_value(minimum);
241 } else {
242 std::tie(m_minimum,m_maximum) = std::minmax(minimum,maximum);
244 m_size = m_maximum - m_minimum + 1;
245 }
246 m_empty=false;
247}
248
249//-----------------------------------------------
250void
252 if (auto * p = dataPtr<element_vector>(); !p) {
253 clear();
254 m_data = element_vector(1,value);//now its enumerated
255 m_size = 1;
256 } else {
257 //check whether value already exists in the enumeration vector
258 if (std::ranges::binary_search(*p, value)) return;
259 p->push_back(value);
260 std::ranges::sort(*p);
261 m_size = p->size();
262 }
263 m_minimum = get_values().front();
264 m_maximum = get_values().back();
265 m_empty = false;
266}
267
268//-----------------------------------------------
269void
270IdentifierField::set(const std::vector <element_type>& values) {
271 auto * p = dataPtr<element_vector>();
272 if (not p) {
273 clear();
275 }
276 p->insert(p->end(), values.begin(), values.end());
277 std::ranges::sort (*p);
278 //ensure duplicates are taken out
279 p->erase( std::unique( p->begin(), p->end() ), p->end() );
280 m_minimum = p->front();
281 m_maximum = p->back();
282 m_empty=false;
283 m_size = p->size();
284}
285
286//-----------------------------------------------
287void
288IdentifierField::set(bool wraparound) {
289 if (wraparound) {
291 }
292}
293
294//-----------------------------------------------
295void
299 } else {
301 }
302 m_next = next;
303}
304
305
306//-----------------------------------------------
307void
311 } else {
313 }
314 m_previous = previous;
315}
316
317
318//-----------------------------------------------
319void
321 if (m_empty or other.m_empty){
322 clear();
323 m_size = 1;
324 return;
325 }
326 if (isEnumerated() and other.isEnumerated()){
327 set(other.get_values ());
328 return;
329 }
336 // all other cases...
337 const auto min = std::min(m_minimum, other.m_minimum);
338 const auto max = std::max(m_maximum, other.m_maximum);
339 set(min, max);
340}
341
342
343//-----------------------------------------------
344IdentifierField::operator std::string () const {
345 std::string result;
346 if (m_empty) {
347 result = "*";
348 } else {
349 const auto & [minimum, maximum] = get_minmax();
350 if (minimum == maximum) {
351 result = std::to_string(minimum);
352 } else {
353 if (isEnumerated()) {
354 std::string prefix;
355 for (size_type i = 0; i < get_indices (); ++i) {
356 result += prefix+std::to_string(get_value_at(i));
357 prefix = ",";
358 }
359 } else {
360 try {
361 result = std::format("{}:{}", minimum, maximum);
362 }
363 catch (const std::format_error& e) {
364 result = "ERROR ";
365 result += e.what();
366 }
367 }
368 }
369 }
370 return result;
371}
372
373//-----------------------------------------------
374bool
376 if (m_data != other.m_data) return false;
377 return (true);
378}
379
380
381//-----------------------------------------------
382void
383IdentifierField::show(std::ostream & out) const {
384 out << "min/max " << m_minimum << " " << m_maximum << " ";
385 out << "values ";
386 for (const auto& v: get_values()) {
387 out << v << " ";
388 }
389 out << "indexes ";
390 for (const auto & idx: m_indexes) {
391 out << idx << " ";
392 }
393 out << "indices " << m_size << " ";
394 out << "prev " << m_previous << " ";
395 out << "next " << m_next << " ";
396 out << "mode ";
397 if (m_empty){
398 out << "unbounded ";
399 }else if (isBounded()){
400 out << "both_bounded ";
401 }else if (isEnumerated()) {
402 out << "enumerated ";
403 }
404 out << "cont mode ";
405 switch (m_continuation_mode) {
407 out << "none ";
408 break;
410 out << "has_next ";
411 break;
413 out << "has_previous ";
414 break;
416 out << "has_both ";
417 break;
419 out << "has_wrap_around ";
420 break;
421 }
422 out << std::endl;
423}
424
425void
426IdentifierField::show(MsgStream & out) const{
427 std::ostringstream os;
428 show(os);
429 out << os.str();
430}
431
432
433
434//-----------------------------------------------
435void
440
441
442//-----------------------------------------------
443bool
445 if (m_empty) return false;
446 if (isEnumerated()) {
447 //the enumerated values are kept sorted
448 if (m_size-1 == static_cast<size_type>(m_maximum - m_minimum)){
450 return true;
451 }
452 }
453 return false;
454}
455
456//-----------------------------------------------
457void
459 if (m_empty) return;
461 if (isEnumerated()) {
462 size_type size = m_maximum - m_minimum + 1;
463 // return if we are over the maximum desired vector table size
464 if (size > m_maxNumberOfIndices) {
465 m_indexes.clear();
466 return;
467 }
468 // Set up vectors for decoding
469 m_indexes = std::vector<size_type>(size, 0);
471 int i{};
472 auto &v = std::get<element_vector>(m_data);
473 for (const auto & thisValue: v) {
474 if (const auto idx=(thisValue - m_minimum); idx < (int)size) {
475 m_indexes[idx] = index;
476 index++;
477 } else {
478 std::cout << "size, value, index, i "
479 << size << " " << thisValue << " "
480 << index << " " << i++ << " min, max "
481 << m_minimum << " "
482 << m_maximum
483 << std::endl;
484 }
485 }
486 }
487}
488
489std::ostream &
490operator << (std::ostream &out, const IdentifierField &c){
491 out<<std::string(c);
492 return out;
493}
494
495//stream extraction allows to read from text (e.g. text file)
496std::istream &
497operator >> (std::istream &is, IdentifierField &idf){
498 idf.clear();
499 while (std::isspace(is.peek())){is.ignore();}
500 char c = is.peek();
501 if (c =='*'){
502 is.ignore();
503 //do nothing; the 'clear' set idf to unbounded
504 } else if (isDigit(c)){
505 if (c =='+') is.ignore();
506 int v = parseStreamDigits(is);//'is' ptr is incremented
507 c = is.peek();
508 //possible: bound, list
509 if (c == ','){ //found comma, so definitely list
510 is.ignore();
511 std::vector<int> vec(1,v);
512 const auto & restOfList = parseStreamList(is);
513 vec.insert(vec.end(), restOfList.begin(), restOfList.end());
514 idf.set(vec);
515 } else if (c == ':'){ //bounded
516 is.ignore();
517 c=is.peek(); //peek char after the colon
518 if (isDigit(c)){ //bounded
519 int v1 = parseStreamDigits(is);
520 idf.set(v,v1);
521 }
522 } else { //remaining alternative: single number
523 idf.add_value(v);
524 }
525 } else {
526 std::string msg{"Stream extraction for IdentifierField: "};
527 std::string remains;
528 is >> remains;
529 msg+=remains;
530 throw std::invalid_argument(msg);
531 }
532 return is;
533}
534
std::vector< size_t > vec
std::ostream & operator<<(std::ostream &out, const IdentifierField &c)
std::istream & operator>>(std::istream &is, IdentifierField &idf)
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
boost::container::small_vector< element_type, 12 >::size_type size_type
This is the individual specification for the range of one ExpandedIdentifier IdentifierField.
ExpandedIdentifier::size_type size_type
bool operator==(const IdentifierField &other) const
static constexpr auto minimum_possible
IdentifierField()=default
Create a wild-card value.
size_type get_indices() const
std::pair< element_type, element_type > BoundedRange
element_type m_next
void set_previous(int previous)
void clear()
Set methods.
bool get_previous(element_type current, element_type &previous) const
Returns false if previous/next is at end of range, or not possible.
index_vector m_indexes
void add_value(element_type value)
void set(element_type minimum, element_type maximum)
void set_next(int next)
static constexpr auto maximum_possible
void show(std::ostream &out=std::cout) const
element_type m_previous
bool overlaps_with(const IdentifierField &other) const
Check whether two IdentifierFields overlap (Are there any values which satisfy the constraints of bot...
std::vector< element_type > element_vector
std::pair< element_type, element_type > get_minmax() const
continuation_mode m_continuation_mode
element_type m_maximum
bool check_for_both_bounded()
Check mode - switch from enumerated to both_bounded if possible.
size_type get_value_index(element_type value) const
bool isEnumerated() const
element_type m_minimum
void operator|=(const IdentifierField &other)
Find the union of two fields.
void optimize()
Optimize - try to switch mode to both_bounded, set up lookup table for finding index from value.
bool get_next(element_type current, element_type &next) const
ExpandedIdentifier::element_type element_type
void create_index_table()
Create index table from value table.
bool match(element_type value) const
The basic match operation Given a value, test to see if it satisfies the constraints for this field.
static constexpr int m_maxNumberOfIndices
element_type get_value_at(size_type index) const
const element_vector & get_values() const
bool isBounded() const
size_type get_bits() const
Return the number of bits needed to store a value of this field.
std::variant< element_vector, BoundedRange > m_data
int ev
Definition globals.cxx:25
bool isDigit(const char c)
IdentifierField::element_type parseStreamDigits(std::istream &is)
IdentifierField::element_vector parseStreamList(std::istream &is)
Definition index.py:1
DataModel_detail::iterator< DVL > unique(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of unique for DataVector/List.
MsgStream & msg
Definition testRead.cxx:32