ATLAS Offline Software
Loading...
Searching...
No Matches
ProxyContainer.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4#ifndef UTILS_PROXY_CONTAINER_H
5#define UTILS_PROXY_CONTAINER_H
6
7#include <cassert>
8#include <utility>
9
10// Helper classes to construct proxy container objects
11// to handle iteration over containers like jagged vectors.
12// A use case would be a container which contains containers
13// of objects where the elements of the lowest level objects
14// of all containers are contained in a single buffer, or
15// in a SOA like arrangement, and the sub-containers are realized
16// by index ranges. Example, for such a hierarchy:
17// container[module_i][cluster_i][cell_i].cellId()
18// container[module_i][cluster_i][cell_i].cellPosition()
19// where the underlying container has the following structure:
20// struct CellData {
21// std::vector<int> m_cellId;
22// std::vector<float> m_cellPosition;
23// std:vector<std::pair<unsigned int, unsigned int> > m_clusterCellIndexRange;
24// std:vector<std::pair<unsigned int, unsigned int> > m_moduleClusterIndexRange;
25// };
26
27namespace Utils {
28
34
35// test whether a container has a size() member function
36template <typename Container>
37concept hasSize = requires(Container a) { a.size(); };
38
39// test whether the difference can be computed for a certain index type
40template <typename IndexType>
41concept hasDifference = requires(IndexType a, IndexType b) { a-b; };
42
43// test whether a count can be added to a certain index type
44template <typename IndexType>
45concept hasAddition = requires(IndexType a, std::size_t count) { a+count; };
46
47// test whether a proxy is meant to be temporary and provides a method to convert to the actual proxy to be used.
48// Such a temporary proxy has to provide the member functions:
49// class ElementProxy ... { ..
50// static ActualProxy ElementProxy::create(ContainerType *container, IndexType index);
51// static ActualProxy ElementProxy::create(const ContainerType *container, IndexType index);
52// ... };
53// For such cases iterators, or the element access operators ([], front, back), would yield the
54// type "ActualProxy". The Element Proxy should define at the same time also a method getOriginalElementIndex
55// to "compute" the "child" index from the ActualProxy, where the child index is the index that can be
56// used to to recover an element proxy from the parent proxy using the access operator[].
57// class ElementProxy ... { ..
58// static ActualProxy ElementProxy::create(ContainerType *container, IndexType index);
59// static ActualProxy ElementProxy::create(const ContainerType *container, IndexType index);
60// static IndexType getOriginalElementIndex(const ActualProxy &converted_element_proxy);
61// ... };
62// auto child_proxy = parent_proxy[index];
63// auto index_restore = ParentProxy::computeChildElementIndex(child_proxy);
64// assert( index == index_restore )
65template <typename T_Proxy, typename T_ContainerPtr, typename T_Index>
66concept hasCreateProxy = requires(T_Proxy &&a, T_ContainerPtr ptr, T_Index index) { T_Proxy::create(ptr, index); };
67
68template <typename T_Proxy>
69concept hasReadWriteProxy = requires( typename T_Proxy::ReadWriteProxy a) { T_Proxy(a);};
70
71template <typename T_DestProxy, typename T_SrcProxy>
72concept isConvertableToReadOnlyProxy = requires( const T_SrcProxy &a) { T_DestProxy(&(a.container()), a.index());};
73
74
79};
80
81// Forward declaration of the actual container proxy class
82template <class Container,
83 class T_Derived,
84 class ElementProxy,
85 typename RangeType=RootNodeIndex,
87struct ContainerProxy;
88
95template <class Container,
96 typename ElementIndexType,
99 using element_index_t = ElementIndexType;
100
101 // helper class to provide access control to a pointer i.e. read/write or read only.
102 template <AccessPolicy ptrAccessPolicy=accessPolicy>
104 template <AccessPolicy IteratorAccessPolicy>
105 friend class iterator_base;
106
107 using ContainerPtr = std::conditional_t< ptrAccessPolicy == AccessPolicy::ReadOnly, const Container *, Container *>;
108
109 template <class _Container,
110 class _T_Derived,
111 class _ElementProxy,
112 typename _RangeType,
113 AccessPolicy _accessPolicy>
114 friend struct ContainerProxy;
115
116 template <AccessPolicy otherAccessPolicy>
117 ContainerPtrBase(ContainerPtrBase<otherAccessPolicy> container) requires ( otherAccessPolicy==ptrAccessPolicy
118 || otherAccessPolicy == AccessPolicy::ReadWrite)
120
121 ContainerPtrBase(const Container *container) requires (ptrAccessPolicy == AccessPolicy::ReadOnly)
123
126
127 // test whether the pointer is not nullptr
128 bool isValid() const { return m_container != nullptr; }
129
130 // return a const reference of the container
131 // results are "undefined" if isValid has not been checked before
132 const Container &container() const { assert(isValid()); return *m_container; }
133 // return a non-const reference of the container if the access policy permits read write access.
134 // Results are "undefined" if isValid has not been checked before
135 Container &container() requires(ptrAccessPolicy == AccessPolicy::ReadWrite) { assert(isValid()); return *m_container; }
136
137 // return the const pointer of the container.
138 // The result can be a nullptr.
139 const Container *cptr() const {return m_container; }
140 // return a non-const pointer if the access policy permits read write access. The result can be a nullptr
141 Container *ptr() requires(ptrAccessPolicy == AccessPolicy::ReadWrite) {return m_container; }
142
143 // convenience method to return const or non const pointer depending on
144 // an external access policy.
145 template <AccessPolicy otherAccessPolicy>
146 auto accessPtr() requires(ptrAccessPolicy==AccessPolicy::ReadWrite) {
147 if constexpr(otherAccessPolicy == AccessPolicy::ReadWrite) {
148 return this->ptr();
149 }
150 else {
151 return this->cptr();
152 }
153 }
154 // convenience method to return const or non const pointer depending on
155 // an external access policy, if access is restricted to read only access.
156 template <AccessPolicy otherAccessPolicy>
158 requires(otherAccessPolicy==AccessPolicy::ReadOnly)
159 {
160 return this->cptr();
161 }
162
163 // true if the pointer is not nullptr
164 operator bool() const { return isValid(); }
165
166 // return a const reference of the container
167 // Result is "undefined" if container is not valid;
168 const Container &operator*() const { return container(); }
169 // return a non const reference of the container if the access policy
170 // permits read-write access. Result is "undefined" if container is not valid;
171 Container &operator*() requires(ptrAccessPolicy == AccessPolicy::ReadWrite) { return container(); }
172
173 // test whether the two container pointers point to the same container
174 template <AccessPolicy otherAccessPolicy>
175 bool operator==(const ContainerPtrBase<otherAccessPolicy> &other) const { return m_container == other.m_container; }
176 private:
178 };
179
180 using ContainerPtr = ContainerPtrBase<AccessPolicy::ReadWrite>; // non-const access controlled container pointer
182 ContainerPtrBase<accessPolicy> m_container; // pointer to the container this proxy refers to
183
184 ContainerProxyBase(const Container *container) : m_container(container) {} // creates a proxy which provides read-only access to its elements
185 ContainerProxyBase(Container *container) : m_container(container) {} // creates a proxy which provides read-write access to its elements
186
187 // @brief Possible base class for an element proxy.
188 // This base class is used by the proxy container iterators
189 template <AccessPolicy ptrAccessPolicy=accessPolicy>
191 using index_t = ElementIndexType;
192
193 protected:
194 ContainerPtrBase<ptrAccessPolicy> m_container; // refers to the original container the parent proxy refers to
195 index_t m_index; // an "index" which indicates the element this proxy refers to
196 public:
197 ElementProxyBase(const Container *container, const index_t &index) // create a read-only element proxy
199 {}
200 ElementProxyBase(Container *container, const index_t &index) // create a read-write element proxy
202 {}
203 ElementProxyBase(const Container *container, index_t &&index) // create a read only element proxy, and moves the provided "index"
205 {}
206 ElementProxyBase(Container *container, index_t &&index) // create a read-write element proxy, and moves the provided "index"
208 {}
209 ElementProxyBase(const ElementProxyBase<ptrAccessPolicy> &other) // create a read-write element proxy, and moves the provided "index"
210 : m_container(other.m_container), m_index(other.m_index)
211 {}
212 ElementProxyBase(const ElementProxyBase<AccessPolicy::ReadWrite> &other) // create a read-write element proxy, and moves the provided "index"
213 requires(ptrAccessPolicy == AccessPolicy::ReadOnly)
214 : m_container(other.container().cptr()), m_index(other.m_index)
215 {}
216
217 template <typename T_RWProxy>
218 ElementProxyBase(const T_RWProxy &other) // create a read-write element proxy, and moves the provided "index"
220 : m_container(&other.container()), m_index(other.index())
221 {}
222
230 index_t index() const { return m_index; }
231
234 const Container &container() const { return m_container.container(); }
237 Container &container() requires(ptrAccessPolicy==AccessPolicy::ReadWrite) { return m_container.container(); }
238 };
239
241 const Container &container() const { return m_container.container(); }
244 Container &container() requires(accessPolicy==AccessPolicy::ReadWrite) { return m_container.container(); }
245};
246
262template <class Container,
263 class T_Derived,
264 class ElementProxy,
265 typename IndexType,
266 AccessPolicy accessPolicy>
267struct ContainerProxy : ContainerProxyBase<Container, typename ElementProxy::index_t, accessPolicy> {
268 using value_type = ElementProxy;
269 using index_t = IndexType;
270 using element_index_t = typename ElementProxy::index_t;
272
273 // the base class
275
279 requires ( std::is_same_v<index_t,RootNodeIndex> && hasSize<Container> )
280 : BASE(container), m_index() {}
281
285 requires ( std::is_same_v<index_t,RootNodeIndex> && hasSize<Container> )
286 : BASE(container), m_index() {}
287
295
297 template <typename T_RWProxy>
298 ContainerProxy(const T_RWProxy &other)
299 requires(accessPolicy == AccessPolicy::ReadOnly
301 : BASE(&other.container()), m_index(other.index())
302 {}
303
308 static auto createElementProxy(const Container *ptr, element_index_t &&element_index) {
309 if constexpr(hasCreateProxy<ElementProxy, decltype(ptr), element_index_t> ) {
310 return ElementProxy::create(ptr, std::move(element_index));
311 }
312 else {
313 return ElementProxy(ptr, std::move(element_index));
314 }
315 }
316
321 static auto createElementProxy(Container *ptr, element_index_t &&element_index) requires (accessPolicy == AccessPolicy::ReadWrite) {
322 if constexpr(hasCreateProxy<ElementProxy, decltype(ptr), element_index_t> ) {
323 return ElementProxy::create(ptr, std::move(element_index));
324 }
325 else {
326 return ElementProxy(ptr, element_index);
327 }
328 }
329
330 // base class of proxy objects referring to elements of this container proxy
331 template <AccessPolicy elementAccessPolicy>
333
335 template <AccessPolicy iteratorAccessPolicy>
336 struct iterator_base : ElementProxyBase<iteratorAccessPolicy> {
337 using ElementProxyBase<iteratorAccessPolicy>::ElementProxyBase;
338
339 // Go to the next element of this container proxy.
341 this->m_index = T_Derived::nextElementIndex(this->m_container.cptr(), std::move(this->m_index));
342 return *this;
343 }
344
345 // Create a proxy object to access the element this iterator refers to.
347 {
348 return createElementProxy(this->m_container.template accessPtr<iteratorAccessPolicy>(),
350 }
351
352 // Test whether two iterators of this proxy container refer to the same element.
353 // The result is undefined if the iterators refer to different containers.
354 template<AccessPolicy otherIteratorAccessPolicy>
356 assert ( this->m_container == other.m_container);
357 return this->m_index == other.m_index;
358 }
359 };
360
361 // the iterator class to iterator over elements of this proxy container with read write element access
362 using iterator = iterator_base<AccessPolicy::ReadWrite>;
363 // the iterator class to iterator over elements of this proxy container with read only element access
364 using const_iterator = iterator_base<AccessPolicy::ReadOnly>;
365
371 const index_t &index() const { return m_index; }
372
374 element_index_t computeChildElementIndex(const ElementProxy &element_proxy) const
377 {
378 return element_proxy.index() - T_Derived::beginIndex(this->m_container.cptr(), m_index);
379 }
380
382 template <typename T_ElementProxy>
383 element_index_t computeChildElementIndex(const T_ElementProxy &element_proxy) const
386 {
387 return ElementProxy::getOriginalElementIndex(element_proxy.index()) - T_Derived::beginIndex(this->m_container.cptr(), m_index);
388 }
389
391 iterator begin() requires ( accessPolicy == AccessPolicy::ReadWrite ) {
392 return iterator(this->m_container.ptr(), T_Derived::beginIndex(this->m_container.cptr(), m_index) );
393 }
394
395 iterator end() requires ( accessPolicy == AccessPolicy::ReadWrite ) {
396 return iterator(this->m_container.ptr(), T_Derived::endIndex(this->m_container.cptr(), m_index) );
397 }
398
401 return const_iterator(this->m_container.cptr(), T_Derived::beginIndex(this->m_container.cptr(), m_index) );
402 }
403
405 return const_iterator(this->m_container.cptr(), T_Derived::endIndex(this->m_container.cptr(), m_index) );
406 }
407
411 auto operator[](std::size_t element_count) const
412 { assert( element_count < size() );
413 return createElementProxy(this->m_container.cptr(), T_Derived::elementIndexAt(this->m_container.cptr(), this->m_index,element_count)); }
414
417 auto operator[](std::size_t element_count) requires (accessPolicy == AccessPolicy::ReadWrite)
418 { assert( element_count < size() );
419 return createElementProxy(this->m_container.ptr(), T_Derived::elementIndexAt(this->m_container.cptr(), this->m_index,element_count));}
420
423 auto front() const
424 { assert( !empty() );
425 return createElementProxy(this->m_container.cptr(), T_Derived::beginIndex(this->m_container.cptr(), this->m_index));}
426
428 auto front() requires (accessPolicy == AccessPolicy::ReadWrite)
429 { assert( !empty() );
430 return createElementProxy(this->m_container.ptr(), T_Derived::beginIndex(this->m_container.cptr(), this->m_index));}
431
434 auto back() const
435 { assert(this->size() > 0);
436 std::size_t element_count = this->size()-1;
437 return createElementProxy(this->m_container.cptr(), T_Derived::elementIndexAt(this->m_container.cptr(), this->m_index,element_count));
438 }
439
441 auto back() requires (accessPolicy == AccessPolicy::ReadWrite)
442 { assert(this->size() > 0);
443 //coverity[INTEGER_OVERFLOW]
444 std::size_t element_count = this->size()-1;
445 return createElementProxy(this->m_container.ptr(), T_Derived::elementIndexAt(this->m_container.ptr(), this->m_index,element_count));
446 }
447
452 static element_index_t beginIndex([[maybe_unused]] const Container *container, [[maybe_unused]] const index_t &this_index)
453 requires (std::is_same_v<index_t,RootNodeIndex> && std::is_convertible_v<std::size_t, element_index_t> && hasSize<Container> )
454 {
455 return static_cast<element_index_t>(0u);
456 }
457
461 static element_index_t endIndex([[maybe_unused]] const Container *container, [[maybe_unused]] const index_t &this_index)
462 requires (std::is_same_v<index_t,RootNodeIndex> && std::is_convertible_v<std::size_t, element_index_t> && hasSize<Container>)
463 {
464 assert( !container || container->size() < std::numeric_limits<element_index_t>::max());
465 return (container ? static_cast<element_index_t>(container->size()) : 0u);
466 }
467 // @brief Default implementation to get the next index following the element identified by the given element index.
468 // In most cases the next element is computed by the prefix increment operator
469 static element_index_t nextElementIndex([[maybe_unused]] const Container *container, element_index_t &&element_index)
470 {
471 assert( container );
472 return ++element_index;
473 }
474
480 static element_index_t elementIndexAt(const Container *container, const index_t &this_index, std::size_t element_counter)
482 { return T_Derived::beginIndex(container,this_index) + element_counter; }
483
484
488 std::size_t size() const
490 {
491 return (this->m_container.cptr()
492 ? T_Derived::endIndex(this->m_container.cptr(), m_index)-T_Derived::beginIndex(this->m_container.cptr(), m_index)
493 : 0u);
494 }
495
498 std::size_t empty() const
499 {
500 return (this->m_container.cptr()
501 ? T_Derived::endIndex(this->m_container.cptr(), m_index)==T_Derived::beginIndex(this->m_container.cptr(), m_index)
502 : true);
503 }
504
505};
506}
507#endif
static Double_t a
storage of the time histories of all the cells
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
AccessPolicy
@breif Indicate whether a container provides read only or read write access
Definition index.py:1
std::conditional_t< ptrAccessPolicy==AccessPolicy::ReadOnly, const Container *, Container * > ContainerPtr
ContainerPtrBase(const Container *container)
ContainerPtrBase(ContainerPtrBase< otherAccessPolicy > container)
bool operator==(const ContainerPtrBase< otherAccessPolicy > &other) const
ElementProxyBase(const Container *container, index_t &&index)
ElementProxyBase(Container *container, const index_t &index)
ElementProxyBase(const ElementProxyBase< AccessPolicy::ReadWrite > &other)
ElementProxyBase(const ElementProxyBase< ptrAccessPolicy > &other)
ContainerPtrBase< ptrAccessPolicy > m_container
ElementProxyBase(Container *container, index_t &&index)
ElementProxyBase(const Container *container, const index_t &index)
ElementIndexType element_index_t
ContainerPtrBase< AccessPolicy::ReadWrite > ContainerPtr
ContainerPtrBase< AccessPolicy::ReadOnly > ConstContainerPtr
ContainerProxyBase(Container *container)
Container & container()
Return a non const pointer of the container which contains the elements this proxy refers to provided...
ContainerProxyBase(const Container *container)
Base class of iterators to iterate over the elements of this proxy container.
bool operator==(const iterator_base< otherIteratorAccessPolicy > &other) const
The proxy container object which provides the means to iterate over its elements and create element p...
iterator begin()
Get the begin iterator of this proxy container for read write element access provided the access poli...
element_index_t computeChildElementIndex(const ElementProxy &element_proxy) const
Compute the "index" of the given element which can be used to recover this element via the access ope...
ContainerProxy(Container *container)
Create a root container proxy with read-write access to its elements where a root container proxy ref...
ContainerProxy(Container *container, const index_t &index)
Create a sub-container proxy with read-write access to its elements where a sub-container proxy is a ...
static auto createElementProxy(const Container *ptr, element_index_t &&element_index)
Create a proxy for one element of the "container" this proxy represents (read-only access).
const_iterator end() const
Get the end iterator of this proxy container for read only element access.
auto front()
Get a proxy for the first child element (read-write).
auto operator[](std::size_t element_count) const
Element access operator (read-only access)
ContainerProxy(const Container *container)
Create a root container proxy with read-only access to its elements which is only possible if the acc...
static element_index_t beginIndex(const Container *container, const index_t &this_index)
Default implementation to get the index of the first element of this proxy container For a full range...
std::size_t size() const
Default implementation to compute the number of elements this proxy container contains/refers to The ...
static auto createElementProxy(Container *ptr, element_index_t &&element_index)
Create a proxy for one element of the "container" this proxy represents (read-write access).
const index_t & index() const
The index of this proxy container which identifies this proxy container within the parent container.
auto back() const
Get a proxy for the last child element (read-only).
auto back()
Get a proxy for the last child element (read-write).
static element_index_t elementIndexAt(const Container *container, const index_t &this_index, std::size_t element_counter)
Default implementation to get the full index of a certain element.
const_iterator begin() const
Get the begin iterator of this proxy container for read only element access.
element_index_t computeChildElementIndex(const T_ElementProxy &element_proxy) const
compute the "index" of the given element which can be used to recover this element via the access ope...
static element_index_t endIndex(const Container *container, const index_t &this_index)
Default implementation to get the index after the last element of this proxy container For a full ran...
ContainerProxy(const T_RWProxy &other)
Create a read only element proxy from a read write proxy.
std::size_t empty() const
Default implementation to test whether the container does not contain elements.
auto operator[](std::size_t element_count)
Element access operator (read-write access)
static element_index_t nextElementIndex(const Container *container, element_index_t &&element_index)
auto front() const
Get a proxy for the first child element (read-only) The operation is undefined if there are no child ...
iterator end()
Get the end iterator of this proxy container for read write element access provided the access policy...
ContainerProxy(const Container *container, const index_t &index)
Create a sub-container proxy with read-only access to its elements which is only possible if the acce...
Helper struct to indicate the "index" of a top level container proxy.