ATLAS Offline Software
Loading...
Searching...
No Matches
IdentifierField.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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
16using namespace Identifier;
17
18namespace{
19template<class SetA, class SetB, typename Compare = std::less<>>
20bool
21share_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 const auto & v = get_values();
57 if (v.size()==1) return 0;
58 if (not m_indexes.empty()) {
59 // Table has been created, do simple lookup
60 assert (value >= m_minimum && value - m_minimum < (int)m_indexes.size());
61 return (m_indexes.at(value - m_minimum));
62 } else {
63 auto it = std::ranges::find(v, value);
64 if (it != v.end()) return std::distance(v.begin(), it);
65 }
66 return 0;
67}
68
69//-----------------------------------------------
70bool
72 if (isBounded()) {
73 return ((value >= m_minimum) && (value <= m_maximum));
74 }
75 if (m_empty) return true;
76 const auto & v = get_values();
77 return (std::ranges::find(v, value)!=v.end());
78}
79
80
81
82//-----------------------------------------------
84 :
85 m_minimum(value),
86 m_maximum(value),
87 m_data{BoundedRange{value, value}},
88 m_empty{false}{
89 //
90}
91
92//-----------------------------------------------
94 set(minimum, maximum);
95}
96
97
100 set(values);
101}
102
103
104//-----------------------------------------------
105bool
107 if (m_empty){
108 previous = current - 1;
109 return (current != minimum_possible);
110 }
111 if (isBounded()){
112 if (current == m_minimum) {
114 previous = m_maximum;
115 return (true);
116 }
118 previous = m_previous;
119 return (true);
120 }
121 previous = current;
122 return (false);
123 }
124 previous = current - 1;
125 return (true);
126 }
127 const auto & values= get_values();
129 if (index == 0) {
131 previous = values.back();
132 return (true);
133 }
135 previous = m_previous;
136 return (true);
137 }
138 previous = current;
139 return (false);
140 }
141 --index;
142 previous = values[index];
143 return true;
144}
145
146
147//-----------------------------------------------
148bool
150 if (m_empty){
151 next = current + 1;
152 return (current != maximum_possible);
153 }
154
155 if (isBounded()){
156 if (current == m_maximum) {
158 next = m_minimum;
159 return (true);
160 }
162 next = m_next;
163 return (true);
164 }
165 next = current;
166 return (false);
167 }
168 next = current + 1;
169 return (true);
170 }
171 const auto & values= get_values();
173 if ((index == values.size() - 1) || (index == 0 && current != values.front())) {
175 next = values.front();
176 return (true);
177 }
179 next = m_next;
180 return (true);
181 }
182 next = current;
183 return (false);
184 }
185 ++index;
186 next = values[index];
187 return true;
188}
189
190
191
192//-----------------------------------------------
193bool
195 if (m_empty or other.m_empty) return true;
196 //
197 if (isBounded() and other.isBounded()){
198 return ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum));
199 }
200 //
201 if (isBounded() and other.isEnumerated() ){
202 const element_vector& ev = other.get_values();
203 for (const auto & v: ev) {
204 if (v >= m_minimum and v<= m_maximum) return (true);
205 }
206 return false;
207 } else if (isEnumerated() and other.isBounded()){
208 const element_vector& ev = get_values();
209 for (const auto & v: ev){
210 if ((v >= other.m_minimum) and (v <= other.m_maximum)) return (true);
211 }
212 return false;
213 }
214 // Both fields are enumerated only if there is possibility of overlap
215 if ((m_minimum <= other.m_maximum) && (m_maximum >= other.m_minimum)) {
216 return share_element(get_values(), other.get_values());
217 }
218 return (false);
219}
220
221
222//-----------------------------------------------
223void
225 m_minimum = 0;
226 m_maximum = 0;
227 m_previous = 0;
228 m_next = 0;
231 m_indexes.clear();
232 m_empty = true;
233}
234
235//-----------------------------------------------
236void
238 if (minimum == maximum) {
239 add_value(minimum);
240 } else {
241 std::tie(m_minimum,m_maximum) = std::minmax(minimum,maximum);
243 m_size = m_maximum - m_minimum + 1;
244 }
245 m_empty=false;
246}
247
248//-----------------------------------------------
249void
251 if (auto * p = dataPtr<element_vector>(); !p) {
252 clear();
253 m_data = element_vector(1,value);//now its enumerated
254 m_size = 1;
255 } else {
256 //check whether value already exists in the enumeration vector
257 if (std::ranges::binary_search(*p, value)) return;
258 p->push_back(value);
259 std::ranges::sort(*p);
260 m_size = p->size();
261 }
262 m_minimum = get_values().front();
263 m_maximum = get_values().back();
264 m_empty = false;
265}
266
267//-----------------------------------------------
268void
269IdentifierField::set(const std::vector <element_type>& values) {
270 auto * p = dataPtr<element_vector>();
271 if (not p) {
272 clear();
274 }
275 p->insert(p->end(), values.begin(), values.end());
276 std::ranges::sort (*p);
277 //ensure duplicates are taken out
278 p->erase( std::unique( p->begin(), p->end() ), p->end() );
279 m_minimum = p->front();
280 m_maximum = p->back();
281 m_empty=false;
282 m_size = p->size();
283}
284
285//-----------------------------------------------
286void
287IdentifierField::set(bool wraparound) {
288 if (wraparound) {
290 }
291}
292
293//-----------------------------------------------
294void
298 } else {
300 }
301 m_next = next;
302}
303
304
305//-----------------------------------------------
306void
310 } else {
312 }
313 m_previous = previous;
314}
315
316
317//-----------------------------------------------
318void
320 if (m_empty or other.m_empty){
321 clear();
322 m_size = 1;
323 return;
324 }
325 if (isEnumerated() and other.isEnumerated()){
326 set(other.get_values ());
327 return;
328 }
335 // all other cases...
336 const auto min = std::min(m_minimum, other.m_minimum);
337 const auto max = std::max(m_maximum, other.m_maximum);
338 set(min, max);
339}
340
341
342//-----------------------------------------------
343IdentifierField::operator std::string () const {
344 std::string result;
345 if (m_empty) {
346 result = "*";
347 } else {
348 const auto & [minimum, maximum] = get_minmax();
349 if (minimum == maximum) {
350 result = std::to_string(minimum);
351 } else {
352 if (isEnumerated()) {
353 std::string prefix;
354 for (size_type i = 0; i < get_indices (); ++i) {
355 result += prefix+std::to_string(get_value_at(i));
356 prefix = ",";
357 }
358 } else {
359 try {
360 result = std::format("{}:{}", minimum, maximum);
361 }
362 catch (const std::format_error& e) {
363 result = "ERROR ";
364 result += e.what();
365 }
366 }
367 }
368 }
369 return result;
370}
371
372//-----------------------------------------------
373bool
375 if (m_data != other.m_data) return false;
376 return (true);
377}
378
379
380//-----------------------------------------------
381void
383 std::cout << "min/max " << m_minimum << " " << m_maximum << " ";
384 std::cout << "values ";
385 for (const auto& v: get_values()) {
386 std::cout << v << " ";
387 }
388 std::cout << "indexes ";
389 for (const auto & idx: m_indexes) {
390 std::cout << idx << " ";
391 }
392 std::cout << "indices " << m_size << " ";
393 std::cout << "prev " << m_previous << " ";
394 std::cout << "next " << m_next << " ";
395 std::cout << "mode ";
396 if (m_empty){
397 std::cout << "unbounded ";
398 }else if (isBounded()){
399 std::cout << "both_bounded ";
400 }else if (isEnumerated()) {
401 std::cout << "enumerated ";
402 }
403 std::cout << "cont mode ";
404 switch (m_continuation_mode) {
406 std::cout << "none ";
407 break;
409 std::cout << "has_next ";
410 break;
412 std::cout << "has_previous ";
413 break;
415 std::cout << "has_both ";
416 break;
418 std::cout << "has_wrap_around ";
419 break;
420 }
421 std::cout << std::endl;
422}
423
424
425
426//-----------------------------------------------
427void
432
433
434//-----------------------------------------------
435bool
437 if (m_empty) return false;
438 if (isEnumerated()) {
439 //the enumerated values are kept sorted
440 if (m_size-1 == static_cast<size_type>(m_maximum - m_minimum)){
442 return true;
443 }
444 }
445 return false;
446}
447
448//-----------------------------------------------
449void
451 if (m_empty) return;
453 if (isEnumerated()) {
454 size_type size = m_maximum - m_minimum + 1;
455 // return if we are over the maximum desired vector table size
456 if (size > m_maxNumberOfIndices) {
457 m_indexes.clear();
458 return;
459 }
460 // Set up vectors for decoding
461 m_indexes = std::vector<size_type>(size, 0);
463 int i{};
464 auto &v = std::get<element_vector>(m_data);
465 for (const auto & thisValue: v) {
466 if (const auto idx=(thisValue - m_minimum); idx < (int)size) {
467 m_indexes[idx] = index;
468 index++;
469 } else {
470 std::cout << "size, value, index, i "
471 << size << " " << thisValue << " "
472 << index << " " << i++ << " min, max "
473 << m_minimum << " "
474 << m_maximum
475 << std::endl;
476 }
477 }
478 }
479}
480
481std::ostream &
482operator << (std::ostream &out, const IdentifierField &c){
483 out<<std::string(c);
484 return out;
485}
486
487//stream extraction allows to read from text (e.g. text file)
488std::istream &
489operator >> (std::istream &is, IdentifierField &idf){
490 idf.clear();
491 while (std::isspace(is.peek())){is.ignore();}
492 char c = is.peek();
493 if (c =='*'){
494 is.ignore();
495 //do nothing; the 'clear' set idf to unbounded
496 } else if (isDigit(c)){
497 if (c =='+') is.ignore();
498 int v = parseStreamDigits(is);//'is' ptr is incremented
499 c = is.peek();
500 //possible: bound, list
501 if (c == ','){ //found comma, so definitely list
502 is.ignore();
503 std::vector<int> vec(1,v);
504 const auto & restOfList = parseStreamList(is);
505 vec.insert(vec.end(), restOfList.begin(), restOfList.end());
506 idf.set(vec);
507 } else if (c == ':'){ //bounded
508 is.ignore();
509 c=is.peek(); //peek char after the colon
510 if (isDigit(c)){ //bounded
511 int v1 = parseStreamDigits(is);
512 idf.set(v,v1);
513 }
514 } else { //remaining alternative: single number
515 idf.add_value(v);
516 }
517 } else {
518 std::string msg{"Stream extraction for IdentifierField: "};
519 std::string remains;
520 is >> remains;
521 msg+=remains;
522 throw std::invalid_argument(msg);
523 }
524 return is;
525}
526
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
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