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#include <iostream>
17
18using namespace Identifier;
19
20namespace{
21template<class SetA, class SetB, typename Compare = std::less<>>
22bool
23share_element(SetA&& setA, SetB&& setB, Compare comp = Compare{}){
24 auto xA = setA.begin();
25 auto xB = setB.begin();
26 while (xA != setA.end() && xB != setB.end()){
27 if (comp(*xA, *xB)) {
28 ++xA;
29 } else if (comp(*xB, *xA)) {
30 ++xB;
31 } else {
32 return true;
33 }
34 }
35 return false;
36}
37
38}
39
40
41//------------------------------------------------------------------
43 size_t indices = get_indices ();
44 if (--indices) return std::bit_width(indices);
45 return 1;
46}
47
48
49//-----------------------------------------------
52 // Only both_bounded and enumerated are valid to calculate the
53 // index.
54 // both_bounded if the more frequent case and so comes first.
55 if (isBounded()) {
56 return (value - m_minimum);
57 }
58 const auto & v = get_values();
59 if (v.size()==1) return 0;
60 if (not m_indexes.empty()) {
61 // Table has been created, do simple lookup
62 assert (value >= m_minimum && value - m_minimum < (int)m_indexes.size());
63 return (m_indexes.at(value - m_minimum));
64 } else {
65 auto it = std::ranges::find(v, value);
66 if (it != v.end()) return std::distance(v.begin(), it);
67 }
68 return 0;
69}
70
71//-----------------------------------------------
72bool
74 if (isBounded()) {
75 return ((value >= m_minimum) && (value <= m_maximum));
76 }
77 if (m_empty) return true;
78 const auto & v = get_values();
79 return (std::ranges::find(v, value)!=v.end());
80}
81
82
83
84//-----------------------------------------------
86 :
87 m_minimum(value),
88 m_maximum(value),
89 m_data{BoundedRange{value, value}},
90 m_empty{false}{
91 //
92}
93
94//-----------------------------------------------
96 set(minimum, maximum);
97}
98
99
102 set(values);
103}
104
105
106//-----------------------------------------------
107bool
109 if (m_empty){
110 previous = current - 1;
111 return (current != minimum_possible);
112 }
113 if (isBounded()){
114 if (current == m_minimum) {
116 previous = m_maximum;
117 return (true);
118 }
120 previous = m_previous;
121 return (true);
122 }
123 previous = current;
124 return (false);
125 }
126 previous = current - 1;
127 return (true);
128 }
129 const auto & values= get_values();
131 if (index == 0) {
133 previous = values.back();
134 return (true);
135 }
137 previous = m_previous;
138 return (true);
139 }
140 previous = current;
141 return (false);
142 }
143 --index;
144 previous = values[index];
145 return true;
146}
147
148
149//-----------------------------------------------
150bool
152 if (m_empty){
153 next = current + 1;
154 return (current != maximum_possible);
155 }
156
157 if (isBounded()){
158 if (current == m_maximum) {
160 next = m_minimum;
161 return (true);
162 }
164 next = m_next;
165 return (true);
166 }
167 next = current;
168 return (false);
169 }
170 next = current + 1;
171 return (true);
172 }
173 const auto & values= get_values();
175 if ((index == values.size() - 1) || (index == 0 && current != values.front())) {
177 next = values.front();
178 return (true);
179 }
181 next = m_next;
182 return (true);
183 }
184 next = current;
185 return (false);
186 }
187 ++index;
188 next = values[index];
189 return true;
190}
191
192
193
194//-----------------------------------------------
195bool
197 if (m_empty or other.m_empty) return true;
198 //
199 if (isBounded() and other.isBounded()){
200 return ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum));
201 }
202 //
203 if (isBounded() and other.isEnumerated() ){
204 const element_vector& ev = other.get_values();
205 for (const auto & v: ev) {
206 if (v >= m_minimum and v<= m_maximum) return (true);
207 }
208 return false;
209 } else if (isEnumerated() and other.isBounded()){
210 const element_vector& ev = get_values();
211 for (const auto & v: ev){
212 if ((v >= other.m_minimum) and (v <= other.m_maximum)) return (true);
213 }
214 return false;
215 }
216 // Both fields are enumerated only if there is possibility of overlap
217 if ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum)) {
218 return share_element(get_values(), other.get_values());
219 }
220 return (false);
221}
222
223
224//-----------------------------------------------
225void
227 m_minimum = 0;
228 m_maximum = 0;
229 m_previous = 0;
230 m_next = 0;
233 m_indexes.clear();
234 m_empty = true;
235}
236
237//-----------------------------------------------
238void
240 if (minimum == maximum) {
241 add_value(minimum);
242 } else {
243 std::tie(m_minimum,m_maximum) = std::minmax(minimum,maximum);
245 m_size = m_maximum - m_minimum + 1;
246 }
247 m_empty=false;
248}
249
250//-----------------------------------------------
251void
253 if (auto * p = dataPtr<element_vector>(); !p) {
254 clear();
255 m_data = element_vector(1,value);//now its enumerated
256 m_size = 1;
257 } else {
258 //check whether value already exists in the enumeration vector
259 if (std::ranges::binary_search(*p, value)) return;
260 p->push_back(value);
261 std::ranges::sort(*p);
262 m_size = p->size();
263 }
264 m_minimum = get_values().front();
265 m_maximum = get_values().back();
266 m_empty = false;
267}
268
269//-----------------------------------------------
270void
271IdentifierField::set(const std::vector <element_type>& values) {
272 auto * p = dataPtr<element_vector>();
273 if (not p) {
274 clear();
276 }
277 p->insert(p->end(), values.begin(), values.end());
278 std::ranges::sort (*p);
279 //ensure duplicates are taken out
280 p->erase( std::unique( p->begin(), p->end() ), p->end() );
281 m_minimum = p->front();
282 m_maximum = p->back();
283 m_empty=false;
284 m_size = p->size();
285}
286
287//-----------------------------------------------
288void
289IdentifierField::set(bool wraparound) {
290 if (wraparound) {
292 }
293}
294
295//-----------------------------------------------
296void
300 } else {
302 }
303 m_next = next;
304}
305
306
307//-----------------------------------------------
308void
312 } else {
314 }
315 m_previous = previous;
316}
317
318
319//-----------------------------------------------
320void
322 if (m_empty or other.m_empty){
323 clear();
324 m_size = 1;
325 return;
326 }
327 if (isEnumerated() and other.isEnumerated()){
328 set(other.get_values ());
329 return;
330 }
337 // all other cases...
338 const auto min = std::min(m_minimum, other.m_minimum);
339 const auto max = std::max(m_maximum, other.m_maximum);
340 set(min, max);
341}
342
343
344//-----------------------------------------------
345IdentifierField::operator std::string () const {
346 std::string result;
347 if (m_empty) {
348 result = "*";
349 } else {
350 const auto & [minimum, maximum] = get_minmax();
351 if (minimum == maximum) {
352 result = std::to_string(minimum);
353 } else {
354 if (isEnumerated()) {
355 std::string prefix;
356 for (size_type i = 0; i < get_indices (); ++i) {
357 result += prefix+std::to_string(get_value_at(i));
358 prefix = ",";
359 }
360 } else {
361 try {
362 result = std::format("{}:{}", minimum, maximum);
363 }
364 catch (const std::format_error& e) {
365 result = "ERROR ";
366 result += e.what();
367 }
368 }
369 }
370 }
371 return result;
372}
373
374//-----------------------------------------------
375bool
377 if (m_data != other.m_data) return false;
378 return (true);
379}
380
381
382//-----------------------------------------------
383void
384IdentifierField::show(std::ostream & out) const {
385 out << "min/max " << m_minimum << " " << m_maximum << " ";
386 out << "values ";
387 for (const auto& v: get_values()) {
388 out << v << " ";
389 }
390 out << "indexes ";
391 for (const auto & idx: m_indexes) {
392 out << idx << " ";
393 }
394 out << "indices " << m_size << " ";
395 out << "prev " << m_previous << " ";
396 out << "next " << m_next << " ";
397 out << "mode ";
398 if (m_empty){
399 out << "unbounded ";
400 }else if (isBounded()){
401 out << "both_bounded ";
402 }else if (isEnumerated()) {
403 out << "enumerated ";
404 }
405 out << "cont mode ";
406 switch (m_continuation_mode) {
408 out << "none ";
409 break;
411 out << "has_next ";
412 break;
414 out << "has_previous ";
415 break;
417 out << "has_both ";
418 break;
420 out << "has_wrap_around ";
421 break;
422 }
423 out << std::endl;
424}
425
426void
427IdentifierField::show(MsgStream & out) const{
428 std::ostringstream os;
429 show(os);
430 out << os.str();
431}
432
433
434
435//-----------------------------------------------
436void
441
442
443//-----------------------------------------------
444bool
446 if (m_empty) return false;
447 if (isEnumerated()) {
448 //the enumerated values are kept sorted
449 if (m_size-1 == static_cast<size_type>(m_maximum - m_minimum)){
451 return true;
452 }
453 }
454 return false;
455}
456
457//-----------------------------------------------
458void
460 if (m_empty) return;
462 if (isEnumerated()) {
463 size_type size = m_maximum - m_minimum + 1;
464 // return if we are over the maximum desired vector table size
465 if (size > m_maxNumberOfIndices) {
466 m_indexes.clear();
467 return;
468 }
469 // Set up vectors for decoding
470 m_indexes = std::vector<size_type>(size, 0);
472 int i{};
473 auto &v = std::get<element_vector>(m_data);
474 for (const auto & thisValue: v) {
475 if (const auto idx=(thisValue - m_minimum); idx < (int)size) {
476 m_indexes[idx] = index;
477 index++;
478 } else {
479 std::cout << "size, value, index, i "
480 << size << " " << thisValue << " "
481 << index << " " << i++ << " min, max "
482 << m_minimum << " "
483 << m_maximum
484 << std::endl;
485 }
486 }
487 }
488}
489
490std::ostream &
491operator << (std::ostream &out, const IdentifierField &c){
492 out<<std::string(c);
493 return out;
494}
495
496//stream extraction allows to read from text (e.g. text file)
497std::istream &
498operator >> (std::istream &is, IdentifierField &idf){
499 idf.clear();
500 while (std::isspace(is.peek())){is.ignore();}
501 char c = is.peek();
502 if (c =='*'){
503 is.ignore();
504 //do nothing; the 'clear' set idf to unbounded
505 } else if (isDigit(c)){
506 if (c =='+') is.ignore();
507 int v = parseStreamDigits(is);//'is' ptr is incremented
508 c = is.peek();
509 //possible: bound, list
510 if (c == ','){ //found comma, so definitely list
511 is.ignore();
512 std::vector<int> vec(1,v);
513 const auto & restOfList = parseStreamList(is);
514 vec.insert(vec.end(), restOfList.begin(), restOfList.end());
515 idf.set(vec);
516 } else if (c == ':'){ //bounded
517 is.ignore();
518 c=is.peek(); //peek char after the colon
519 if (isDigit(c)){ //bounded
520 int v1 = parseStreamDigits(is);
521 idf.set(v,v1);
522 }
523 } else { //remaining alternative: single number
524 idf.add_value(v);
525 }
526 } else {
527 std::string msg{"Stream extraction for IdentifierField: "};
528 std::string remains;
529 is >> remains;
530 msg+=remains;
531 throw std::invalid_argument(msg);
532 }
533 return is;
534}
535
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 show(std::ostream &out) const
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
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