ATLAS Offline Software
Loading...
Searching...
No Matches
IdentifierField Class Reference

This is the individual specification for the range of one ExpandedIdentifier IdentifierField. More...

#include <IdentifierField.h>

Collaboration diagram for IdentifierField:

Public Types

enum  continuation_mode {
  none , has_next , has_previous , has_both ,
  has_wrap_around
}
using element_type = ExpandedIdentifier::element_type
using size_type = ExpandedIdentifier::size_type
using element_vector = std::vector <element_type>
using index_vector = std::vector <size_type>
using BoundedRange = std::pair<element_type, element_type>

Public Member Functions

 IdentifierField ()=default
 Create a wild-card value.
 IdentifierField (element_type value)
 Create a unique value (understood as : low bound = high bound = value)
 IdentifierField (element_type minimum, element_type maximum)
 Create a full range specification (with explicit min and max)
 IdentifierField (const element_vector &values)
 Create with enumerated values.
bool wrap_around () const
element_type get_minimum () const
 Query the values.
std::pair< element_type, element_typeget_minmax () const
element_type get_maximum () const
const element_vectorget_values () const
bool get_previous (element_type current, element_type &previous) const
 Returns false if previous/next is at end of range, or not possible.
bool get_next (element_type current, element_type &next) const
size_type get_indices () const
const index_vectorget_indexes () const
size_type get_bits () const
 Return the number of bits needed to store a value of this field.
element_type get_value_at (size_type index) const
size_type get_value_index (element_type value) const
bool match (element_type value) const
 The basic match operation Given a value, test to see if it satisfies the constraints for this field.
bool overlaps_with (const IdentifierField &other) const
 Check whether two IdentifierFields overlap (Are there any values which satisfy the constraints of both fields?)
void clear ()
 Set methods.
void set (element_type minimum, element_type maximum)
void add_value (element_type value)
void set (const element_vector &values)
void set (bool wraparound)
void set_next (int next)
void set_previous (int previous)
void operator|= (const IdentifierField &other)
 Find the union of two fields.
 operator std::string () const
bool operator== (const IdentifierField &other) const
void show () const
bool check_for_both_bounded ()
 Check mode - switch from enumerated to both_bounded if possible.
void optimize ()
 Optimize - try to switch mode to both_bounded, set up lookup table for finding index from value.
bool empty () const
 If true, this field does not have any constraints, and may hold any value representable by element_type.
bool isBounded () const
bool isEnumerated () const

Static Public Attributes

static constexpr auto minimum_possible = std::numeric_limits<element_type>::min()
static constexpr auto maximum_possible = std::numeric_limits<element_type>::max()
static constexpr auto invalidValues = element_vector{}

Private Member Functions

void set_minimum (element_type value)
void set_maximum (element_type value)
void create_index_table ()
 Create index table from value table.
template<class T>
T * dataPtr ()

Private Attributes

element_type m_minimum {}
element_type m_maximum {}
std::variant< element_vector, BoundedRangem_data {}
index_vector m_indexes {}
size_type m_size {}
element_type m_previous {}
element_type m_next {}
bool m_empty {true}
continuation_mode m_continuation_mode {none}

Static Private Attributes

static constexpr int m_maxNumberOfIndices = 100

Detailed Description

This is the individual specification for the range of one ExpandedIdentifier IdentifierField.

A field specifies a constraint on the values it may contain. This may take one of three forms:

  • Completely unconstrained. In this case, empty() will return true, implying that the field may hold any value representable by element_type. (Yes, it's a bad name and means the opposite of what you may think...) An empty field is made by the default constructor, and also by calling clear().
  • A bounded (inclusive) range. In this case, isBounded() will return true, get_maximum/get_minimum will return the ends of the range, and get_indices() will return the number of values in the range (maximum - minimum + 1). A bounded field may be made by calling the constructor with a minimum and maximum, or by calling set() with the same arguments. The range is also stored in m_data as the BoundedRange option.
  • An enumeration. In this case, isEnumerated() will return true, get_maximum/get_minimum will return the minimum and maximum enumeration values, and get_indices() will return the number of enumeration values. get_values() will return a (sorted) vector of all the values. An enumerated field may be made by passing a vector to the constructor or set(), or by calling add_value() with individual values. The values are stored in m_data as the element_vector option.

Each valid value is assigned an index, starting with 0. For bounded ranges, this just starts from the minimum value and counts up. For enumerations, it is the index of that particular enumeration value. You can convert between values and indices using get_value_at() and get_value_index(). For value->index conversions, a lookup table is used if optimize() has been called and the spread of values is not too large. get_indices() will return this table.

As far as users of this class see, there is not really a distinction between a dense enumeration and a bounded range. In fact, check_for_both_bounded()/optimize() will convert a dense enumeration to a bounded range.

Given a value, one can ask for the next/previous valid value using get_next()/get_previous(). For an enumeration, this will return the next or previous enumeration value. If you try to call get_next() for the maximum value in the range, or get_previous() from the minimum, then they will by default fail (return false). This can be changed by calling set_next()/set_previous() to specify explictly values to be returned in these cases, or by calling set(true) to enable wraparound mode; in that case, calling get_next() for the maximum value will return the minimum value, and analogously for get_previous().

Other operations include:

  • get_bits(): Return the number of bits needed to store a value of this field.

match(): Given a value, test whether it satisfies the constraints for this field.

  • overlaps_with(): Test to see if there are any values which satisfy the constraints of both fields.
  • operator|=(): Find the union of two fields. Note: does not correctly handle the cases of an enumeration and a bounded range or two disjoint bounded ranges! If either is empty (meaning no constraint), then the result will be empty.
    • operator==(): Test if two fields have identical constraints. However, a dense enumeration will not compare identically to an equivalent bounded range.

Definition at line 82 of file IdentifierField.h.

Member Typedef Documentation

◆ BoundedRange

Definition at line 89 of file IdentifierField.h.

◆ element_type

◆ element_vector

Definition at line 87 of file IdentifierField.h.

◆ index_vector

Definition at line 88 of file IdentifierField.h.

◆ size_type

Member Enumeration Documentation

◆ continuation_mode

Enumerator
none 
has_next 
has_previous 
has_both 
has_wrap_around 

Definition at line 94 of file IdentifierField.h.

Constructor & Destructor Documentation

◆ IdentifierField() [1/4]

IdentifierField::IdentifierField ( )
default

Create a wild-card value.

◆ IdentifierField() [2/4]

IdentifierField::IdentifierField ( element_type value)

Create a unique value (understood as : low bound = high bound = value)

Definition at line 83 of file IdentifierField.cxx.

84 :
85 m_minimum(value),
86 m_maximum(value),
88 m_empty{false}{
89 //
90}
std::pair< element_type, element_type > BoundedRange
element_type m_maximum
element_type m_minimum
std::variant< element_vector, BoundedRange > m_data

◆ IdentifierField() [3/4]

IdentifierField::IdentifierField ( element_type minimum,
element_type maximum )

Create a full range specification (with explicit min and max)

Definition at line 93 of file IdentifierField.cxx.

93 {
94 set(minimum, maximum);
95}
void set(element_type minimum, element_type maximum)

◆ IdentifierField() [4/4]

IdentifierField::IdentifierField ( const element_vector & values)

Create with enumerated values.

Definition at line 99 of file IdentifierField.cxx.

99 {
100 set(values);
101}

Member Function Documentation

◆ add_value()

void IdentifierField::add_value ( element_type value)

Definition at line 250 of file IdentifierField.cxx.

250 {
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}
void clear()
Set methods.
std::vector< element_type > element_vector
const element_vector & get_values() const

◆ check_for_both_bounded()

bool IdentifierField::check_for_both_bounded ( )

Check mode - switch from enumerated to both_bounded if possible.

Definition at line 436 of file IdentifierField.cxx.

436 {
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}
ExpandedIdentifier::size_type size_type
bool isEnumerated() const

◆ clear()

void IdentifierField::clear ( )

Set methods.

Definition at line 224 of file IdentifierField.cxx.

224 {
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}
element_type m_next
index_vector m_indexes
element_type m_previous
continuation_mode m_continuation_mode

◆ create_index_table()

void IdentifierField::create_index_table ( )
private

Create index table from value table.

Create index table from value table

Definition at line 450 of file IdentifierField.cxx.

450 {
451 if (m_empty) return;
453 if (isEnumerated()) {
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) {
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}
static constexpr int m_maxNumberOfIndices
str index
Definition DeMoScan.py:362

◆ dataPtr()

template<class T>
T * IdentifierField::dataPtr ( )
inlineprivate

Definition at line 195 of file IdentifierField.h.

195{return std::get_if<T>(&m_data);}

◆ empty()

bool IdentifierField::empty ( ) const
inline

If true, this field does not have any constraints, and may hold any value representable by element_type.

Definition at line 182 of file IdentifierField.h.

182{return m_empty;}

◆ get_bits()

ExpandedIdentifier::size_type IdentifierField::get_bits ( ) const

Return the number of bits needed to store a value of this field.

Definition at line 40 of file IdentifierField.cxx.

40 {
41 size_t indices = get_indices ();
42 if (--indices) return std::bit_width(indices);
43 return 1;
44}
size_type get_indices() const
std::pair< long int, long int > indices

◆ get_indexes()

const index_vector & IdentifierField::get_indexes ( ) const
inline

Definition at line 141 of file IdentifierField.h.

141{return m_indexes;}

◆ get_indices()

size_type IdentifierField::get_indices ( ) const
inline

Definition at line 140 of file IdentifierField.h.

140{return m_size;}

◆ get_maximum()

element_type IdentifierField::get_maximum ( ) const
inline

Definition at line 130 of file IdentifierField.h.

130{return m_maximum;}

◆ get_minimum()

element_type IdentifierField::get_minimum ( ) const
inline

Query the values.

Definition at line 121 of file IdentifierField.h.

121{return m_minimum;}

◆ get_minmax()

std::pair< element_type, element_type > IdentifierField::get_minmax ( ) const
inline

Definition at line 125 of file IdentifierField.h.

125 {
126 return {m_minimum, m_maximum};
127 }

◆ get_next()

bool IdentifierField::get_next ( element_type current,
element_type & next ) const

Definition at line 149 of file IdentifierField.cxx.

149 {
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}
static constexpr auto maximum_possible
size_type get_value_index(element_type value) const
bool isBounded() const

◆ get_previous()

bool IdentifierField::get_previous ( element_type current,
element_type & previous ) const

Returns false if previous/next is at end of range, or not possible.

Definition at line 106 of file IdentifierField.cxx.

106 {
107 if (m_empty){
108 previous = current - 1;
109 return (current != minimum_possible);
110 }
111 if (isBounded()){
112 if (current == m_minimum) {
115 return (true);
116 }
119 return (true);
120 }
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 }
136 return (true);
137 }
139 return (false);
140 }
141 --index;
143 return true;
144}
static constexpr auto minimum_possible
@ previous
Definition BinningData.h:32

◆ get_value_at()

IdentifierField::element_type IdentifierField::get_value_at ( size_type index) const
inline

Definition at line 209 of file IdentifierField.h.

209 {
210 // Only both_bounded and enumerated are valid to calculate the
211 // value.
212 // both_bounded is the more frequent case and so comes first.
213 if (m_empty) return 0;
214 if (const auto * p{std::get_if<BoundedRange>(&m_data)}; p) {
215 if (index >= (size_type) (p->second - p->first + 1)) {
216 throw std::out_of_range("IdentifierField::get_value_at");
217 }
218 return (p->first + index);
219 }
220 return ((std::get<element_vector>(m_data)).at(index));
221
222}

◆ get_value_index()

ExpandedIdentifier::size_type IdentifierField::get_value_index ( element_type value) const

Definition at line 49 of file IdentifierField.cxx.

49 {
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}

◆ get_values()

const element_vector & IdentifierField::get_values ( ) const
inline

Definition at line 133 of file IdentifierField.h.

133 {
134 if (isBounded()) return invalidValues;
135 return std::get<element_vector>(m_data);
136 }
static constexpr auto invalidValues

◆ isBounded()

bool IdentifierField::isBounded ( ) const
inline

Definition at line 184 of file IdentifierField.h.

184{return std::holds_alternative<BoundedRange>(m_data);}

◆ isEnumerated()

bool IdentifierField::isEnumerated ( ) const
inline

Definition at line 185 of file IdentifierField.h.

185{return std::holds_alternative<element_vector>(m_data);}

◆ match()

bool IdentifierField::match ( element_type value) const

The basic match operation Given a value, test to see if it satisfies the constraints for this field.

Definition at line 71 of file IdentifierField.cxx.

71 {
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}

◆ operator std::string()

IdentifierField::operator std::string ( ) const

Definition at line 343 of file IdentifierField.cxx.

343 {
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}
std::pair< element_type, element_type > get_minmax() const
element_type get_value_at(size_type index) const

◆ operator==()

bool IdentifierField::operator== ( const IdentifierField & other) const

Definition at line 374 of file IdentifierField.cxx.

374 {
375 if (m_data != other.m_data) return false;
376 return (true);
377}

◆ operator|=()

void IdentifierField::operator|= ( const IdentifierField & other)

Find the union of two fields.

Note: does not correctly handle the cases of an enumeration and a bounded range or two disjoint bounded ranges! If either is empty (meaning no constraint), then the result will be empty.

If there is no overlap we should build a multi-segment specification. The current algorithm is only correct if the overlap in not empty !! A multi-segment specification might also be implemented as an expanded enumerated set (not very optimized !!)

Definition at line 319 of file IdentifierField.cxx.

319 {
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}
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41

◆ optimize()

void IdentifierField::optimize ( )

Optimize - try to switch mode to both_bounded, set up lookup table for finding index from value.

Check mode - switch from enumerated to both_bounded if possible

Definition at line 428 of file IdentifierField.cxx.

428 {
431}
bool check_for_both_bounded()
Check mode - switch from enumerated to both_bounded if possible.
void create_index_table()
Create index table from value table.

◆ overlaps_with()

bool IdentifierField::overlaps_with ( const IdentifierField & other) const

Check whether two IdentifierFields overlap (Are there any values which satisfy the constraints of both fields?)

Definition at line 194 of file IdentifierField.cxx.

194 {
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}
int ev
Definition globals.cxx:25

◆ set() [1/3]

void IdentifierField::set ( bool wraparound)

Definition at line 287 of file IdentifierField.cxx.

287 {
288 if (wraparound) {
290 }
291}

◆ set() [2/3]

void IdentifierField::set ( const element_vector & values)

◆ set() [3/3]

void IdentifierField::set ( element_type minimum,
element_type maximum )

Definition at line 237 of file IdentifierField.cxx.

237 {
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}
void add_value(element_type value)

◆ set_maximum()

void IdentifierField::set_maximum ( element_type value)
private

◆ set_minimum()

void IdentifierField::set_minimum ( element_type value)
private

◆ set_next()

void IdentifierField::set_next ( int next)

Definition at line 295 of file IdentifierField.cxx.

295 {
298 } else {
300 }
301 m_next = next;
302}

◆ set_previous()

void IdentifierField::set_previous ( int previous)

Definition at line 307 of file IdentifierField.cxx.

307 {
310 } else {
312 }
314}

◆ show()

void IdentifierField::show ( ) const

Definition at line 382 of file IdentifierField.cxx.

382 {
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}

◆ wrap_around()

bool IdentifierField::wrap_around ( ) const
inline

Definition at line 116 of file IdentifierField.h.

Member Data Documentation

◆ invalidValues

auto IdentifierField::invalidValues = element_vector{}
staticconstexpr

Definition at line 92 of file IdentifierField.h.

92{};

◆ m_continuation_mode

continuation_mode IdentifierField::m_continuation_mode {none}
private

Definition at line 205 of file IdentifierField.h.

205{none};

◆ m_data

std::variant<element_vector, BoundedRange> IdentifierField::m_data {}
private

Definition at line 199 of file IdentifierField.h.

199{};

◆ m_empty

bool IdentifierField::m_empty {true}
private

Definition at line 204 of file IdentifierField.h.

204{true};

◆ m_indexes

index_vector IdentifierField::m_indexes {}
private

Definition at line 200 of file IdentifierField.h.

200{};

◆ m_maximum

element_type IdentifierField::m_maximum {}
private

Definition at line 198 of file IdentifierField.h.

198{};

◆ m_maxNumberOfIndices

int IdentifierField::m_maxNumberOfIndices = 100
staticconstexprprivate

Definition at line 188 of file IdentifierField.h.

◆ m_minimum

element_type IdentifierField::m_minimum {}
private

Definition at line 197 of file IdentifierField.h.

197{};

◆ m_next

element_type IdentifierField::m_next {}
private

Definition at line 203 of file IdentifierField.h.

203{};

◆ m_previous

element_type IdentifierField::m_previous {}
private

Definition at line 202 of file IdentifierField.h.

202{};

◆ m_size

size_type IdentifierField::m_size {}
private

Definition at line 201 of file IdentifierField.h.

201{};

◆ maximum_possible

auto IdentifierField::maximum_possible = std::numeric_limits<element_type>::max()
staticconstexpr

Definition at line 91 of file IdentifierField.h.

◆ minimum_possible

auto IdentifierField::minimum_possible = std::numeric_limits<element_type>::min()
staticconstexpr

Definition at line 90 of file IdentifierField.h.


The documentation for this class was generated from the following files: