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#include <type_traits>
10
11// Helper classes to construct proxy container objects
12// to handle iteration over containers like jagged vectors.
13// A use case would be a container which contains containers
14// of objects where the elements of the lowest level objects
15// of all containers are contained in a single buffer, or
16// in a SOA like arrangement, and the sub-containers are realized
17// by index ranges. Example, for such a hierarchy:
18// container[module_i][cluster_i][cell_i].cellId()
19// container[module_i][cluster_i][cell_i].cellPosition()
20// where the underlying container has the following structure:
21// struct CellData {
22// std::vector<int> m_cellId;
23// std::vector<float> m_cellPosition;
24// std:vector<std::pair<unsigned int, unsigned int> > m_clusterCellIndexRange;
25// std:vector<std::pair<unsigned int, unsigned int> > m_moduleClusterIndexRange;
26// };
27
28namespace Utils {
29
31enum class AccessPolicy {
34};
35
36template <bool isConst>
38
39template<>
43
44template<>
48
49template <typename Container, AccessPolicy accessPolicy>
51 using ContainerNonConst = std::remove_cvref_t<Container>;
52 using ContainerPtr = std::conditional<accessPolicy==AccessPolicy::Const , const ContainerNonConst *, ContainerNonConst *>::type;
53 using ContainerType = std::conditional<accessPolicy==AccessPolicy::Const , const ContainerNonConst, ContainerNonConst>::type;
54};
55
56// test whether a container has a size() member function
57template <typename Container>
58concept hasSize = requires(Container a) { a.size(); };
59
60// test whether the difference can be computed for a certain index type
61template <typename IndexType>
62concept hasDifference = requires(IndexType a, IndexType b) { a-b; };
63
64// test whether a count can be added to a certain index type
65template <typename IndexType>
66concept hasAddition = requires(IndexType a, std::size_t count) { a+count; };
67
68// test whether a proxy is meant to be temporary and provides a method to convert to the actual proxy to be used.
69// Such a temporary proxy has to provide the member functions:
70// class ElementProxy ... { ..
71// static ActualProxy ElementProxy::create(ContainerType *container, IndexType index);
72// static ActualProxy ElementProxy::create(const ContainerType *container, IndexType index);
73// ... };
74// For such cases iterators, or the element access operators ([], front, back), would yield the
75// type "ActualProxy". The Element Proxy should define at the same time also a method getOriginalElementIndex
76// to "compute" the "child" index from the ActualProxy, where the child index is the index that can be
77// used to to recover an element proxy from the parent proxy using the access operator[].
78// class ElementProxy ... { ..
79// static ActualProxy ElementProxy::create(ContainerType *container, IndexType index);
80// static ActualProxy ElementProxy::create(const ContainerType *container, IndexType index);
81// static IndexType getOriginalElementIndex(const ActualProxy &converted_element_proxy);
82// ... };
83// auto child_proxy = parent_proxy[index];
84// auto index_restore = ParentProxy::computeChildElementIndex(child_proxy);
85// assert( index == index_restore )
86template <typename T_Proxy, typename T_ContainerPtr, typename T_Index>
87concept hasCreateProxy = requires(T_Proxy &&a, T_ContainerPtr ptr, T_Index index) { T_Proxy::create(ptr, index); };
88
89template <typename T_Proxy>
90concept hasReadWriteProxy = requires( typename T_Proxy::ReadWriteProxy a) { T_Proxy(a);};
91
92template <typename T_DestProxy, typename T_SrcProxy>
93concept isConvertableToReadOnlyProxy = requires( const T_SrcProxy &a) { T_DestProxy(&(a.container()), a.index());};
94
99};
100
101// Forward declaration of the actual container proxy class
102template <class Container,
103 class T_Derived,
104 class ElementProxy,
105 typename RangeType=RootNodeIndex>
106struct ContainerProxy;
107
108
109// @brief Possible base class for an element proxy.
110// This base class is used by the proxy container iterators
111template <class Container,
112 typename ElementIndexType>
114 static constexpr bool isConst = std::is_const_v<Container>;
115 using index_t = ElementIndexType;
116 using ContainerNonConst = std::remove_cvref_t<Container>;
117 using ContainerPtr = std::conditional<isConst , const ContainerNonConst *, ContainerNonConst *>::type;
118
119public:
120 ElementProxyBase(const ContainerNonConst *container, const index_t &index) // create a read-only element proxy
121 requires(isConst)
123 {}
124 ElementProxyBase(ContainerNonConst *container, const index_t &index) // create a read-write element proxy
126 {}
127 ElementProxyBase(const ContainerNonConst *container, index_t &&index) // create a read only element proxy, and moves the provided "index"
128 requires(isConst)
130 {}
131 ElementProxyBase(ContainerNonConst *container, index_t &&index) // create a read-write element proxy, and moves the provided "index"
133 {}
134 template <class OtherContainer>
135 ElementProxyBase(const ElementProxyBase<OtherContainer, ElementIndexType> &other)// create a read-write element proxy, and moves the provided "index"
136 requires(std::is_same_v<ContainerNonConst, typename OtherContainer::ContainerNonConst>
137 && (!OtherContainer::isConst || isConst) )
138 : m_container(other.m_container), m_index(other.m_index)
139 {}
140
148 index_t index() const { return m_index; }
149
153 { assert( m_container != nullptr); return *m_container; }
154
157 { assert( m_container != nullptr); return *m_container; }
158protected:
159 const ContainerNonConst *cptr() const {
160 return &container();
161 }
162 ContainerPtr m_container; // refers to the original container the parent proxy refers to
163 index_t m_index; // an "index" which indicates the element this proxy refers to
164};
165
172template <class Container,
173 typename ElementIndexType>
175 static constexpr bool isConst = std::is_const_v<Container>;
176 using element_index_t = ElementIndexType;
177 using ContainerNonConst = std::remove_cvref_t<Container>;
178 using ContainerPtr = std::conditional<isConst , const ContainerNonConst *, ContainerNonConst *>::type;
179
180 template <class OtherContainer>
182 requires(std::is_same_v<ContainerNonConst, typename OtherContainer::ContainerNonConst> || !OtherContainer::isConst)
185 : m_container(container) {} // creates a proxy which provides read-only access to its elements
187 : m_container(container) {} // creates a proxy which provides read-write access to its elements
188
191 { assert(m_container != nullptr); return *m_container; }
192
195 { assert( m_container != nullptr); return *m_container; }
196
197protected:
198 const ContainerNonConst *cptr() const {
199 return m_container;
200 }
202 return m_container;
203 }
204
205 ContainerPtr m_container; // pointer to the container this proxy refers to
206};
207
209template <class Container,
210 class T_Derived,
211 class ElementProxy>
212struct ProxyIteratorBase : ElementProxyBase<Container, typename ElementProxy::index_t> {
213 using element_index_t = typename ElementProxy::index_t;
215 using BASE::BASE;
216
217 // Go to the next element of this container proxy.
219 this->m_index = T_Derived::nextElementIndex(this->cptr(), std::move(this->m_index));
220 return *this;
221 }
223 this->m_index = this->m_index + offset;
224 return *this;
225 }
226
227 // Create a proxy object to access the element this iterator refers to.
229 {
230 return this->createElementProxy(this->m_container,
231 typename BASE::index_t(this->m_index));
232 }
233
234 // Test whether two iterators of this proxy container refer to the same element.
235 // The result is undefined if the iterators refer to different containers.
236 template<class OtherContainer>
238 requires(std::is_same_v<typename BASE::ContainerNonConst,
240 {
241 assert ( this->m_container == other.m_container);
242 return this->m_index == other.m_index;
243 }
244
252 static auto createElementProxy(const BASE::ContainerNonConst *ptr, element_index_t &&element_index)
253 requires(hasCreateProxy<ElementProxy, decltype(ptr), element_index_t> )
254 {
255 return ElementProxy::create(ptr,std::move(element_index));
256 }
257
264 static auto createElementProxy(const BASE::ContainerNonConst *ptr, element_index_t &&element_index)
265 requires(ElementProxy::isConst && !hasCreateProxy<ElementProxy, decltype(ptr), element_index_t> )
266 {
267 return ElementProxy(ptr,std::move(element_index));
268 }
269
275 requires (!BASE::isConst) {
276 if constexpr(hasCreateProxy<ElementProxy, decltype(ptr), element_index_t> ) {
277 return ElementProxy::create(ptr, std::move(element_index));
278 }
279 else {
280 return ElementProxy(ptr, std::move(element_index));
281 }
282 }
283
284};
285
286// extension of the ProxyIteratorBase to make it usable in std::ranges::subrange
287template <class Container,
288 class T_Derived,
289 class ElementProxy>
290struct ProxyIterator : ProxyIteratorBase<Container,T_Derived, ElementProxy> {
291public:
293 using BASE::BASE;
294
295 // default constructor needed to use these iterators in a std::range::subrange
296 ProxyIterator() : BASE(nullptr,typename BASE::element_index_t{}) {}
297
299 (void) BASE::operator++();
300 return *this;
301 }
303 (void) BASE::operator+=(offset);
304 return *this;
305 }
306
307 // also define post-fix iterator to allow these iterators to be used to create a std::ranges::subrange
309 ProxyIterator clone(*this);
310 this->m_index = T_Derived::nextElementIndex(this->cptr(), std::move(this->m_index));
311 return clone;
312 }
313
314 template<class OtherContainer>
316 requires(std::is_same_v<typename BASE::ContainerNonConst, typename ProxyIteratorBase<OtherContainer, T_Derived, ElementProxy>::ContainerNonConst>)
317 {
318 return !(this->operator==(other));
319 }
320
321 // the type resulting from dereferencing the iterator
322 using value_type = decltype( std::declval<BASE>().operator *());
323private:
324 // helper class to define the type representing the differences of two iterators
325 // e.g. used to compute the size of std::ranges::subrange
326 template <typename T>
328 // for integral types assume that a 64 bit signed integer is a good choice
329 static std::int64_t diff(const T &a, const T &b)
330 requires(std::is_integral_v<T>)
331 {return a-b;}
332
333 // if a difference operation is defined for the index then use the return type
334 static auto diff(const T &a, const T &b)
335 requires(!std::is_integral_v<T> && hasDifference<T>)
336 {return a-b;}
337
338 // otherwise use a type which is not a valid difference type what concerns std::ranges::subrange
339 static void diff([[maybe_unused]] const T &a, [[maybe_unused]] const T &b)
340 requires(!std::is_integral_v<T> && !hasDifference<T>)
341 { }
342 };
343public:
344 using difference_type = decltype( diff_type_helper<typename BASE::element_index_t>::diff(std::declval<typename BASE::element_index_t>(),
345 std::declval<typename BASE::element_index_t>()) );
346};
347
348
363template <class Container,
364 class T_Derived,
365 class ElementProxy,
366 typename IndexType>
367struct ContainerProxy : ContainerProxyBase<Container, typename ElementProxy::index_t> {
368 // the base class
371 using value_type = ElementProxy;
372 using index_t = IndexType;
373 using element_index_t = typename ElementProxy::index_t;
375
379 requires ( std::is_same_v<index_t,RootNodeIndex> && hasSize<Container> )
380 : BASE(container), m_index() {}
381
385 requires ( std::is_same_v<index_t,RootNodeIndex> && hasSize<Container> )
386 : BASE(container), m_index() {}
387
395
397 template <typename T_RWProxy>
398 ContainerProxy(const T_RWProxy &other)
399 requires(BASE::isConst
401 : BASE(&other.container()), m_index(other.index())
402 {}
403
404
405
406
407 // the iterator class to iterator over elements of this proxy container with read write element access
409 // the iterator class to iterator over elements of this proxy container with read only element access
411
417 const index_t &index() const { return m_index; }
418
420 element_index_t computeChildElementIndex(const ElementProxy &element_proxy) const
423 {
424 return element_proxy.index() - T_Derived::beginIndex(this->cptr(), m_index);
425 }
426
428 template <typename T_ElementProxy>
429 element_index_t computeChildElementIndex(const T_ElementProxy &element_proxy) const
432 {
433 return ElementProxy::getOriginalElementIndex(element_proxy.index()) - T_Derived::beginIndex(this->cptr(), m_index);
434 }
435
437 iterator begin() requires ( !BASE::isConst ) {
438 return iterator(this->ptr(), T_Derived::beginIndex(this->cptr(), m_index) );
439 }
440
441 iterator end() requires ( !BASE::isConst ) {
442 return iterator(this->ptr(), T_Derived::endIndex(this->cptr(), m_index) );
443 }
444
447 return const_iterator(this->cptr(), T_Derived::beginIndex(this->cptr(), m_index) );
448 }
449
451 return const_iterator(this->cptr(), T_Derived::endIndex(this->cptr(), m_index) );
452 }
453
457 auto operator[](std::size_t element_count) const
458 { assert( element_count < size() );
459 return const_iterator::createElementProxy(this->cptr(), T_Derived::elementIndexAt(this->cptr(), this->m_index,element_count)); }
460
463 auto operator[](std::size_t element_count) requires (!BASE::isConst)
464 { assert( element_count < size() );
465 return iterator::createElementProxy(this->ptr(), T_Derived::elementIndexAt(this->cptr(), this->m_index,element_count));}
466
469 auto front() const
470 { assert( !empty() );
471 return const_iterator::createElementProxy(this->cptr(), T_Derived::beginIndex(this->cptr(), this->m_index));}
472
474 auto front() requires (!BASE::isConst)
475 { assert( !empty() );
476 return iterator::createElementProxy(this->ptr(), T_Derived::beginIndex(this->cptr(), this->m_index));}
477
480 auto back() const
481 { assert(this->size() > 0);
482 std::size_t element_count = this->size()-1;
483 return const_iterator::createElementProxy(this->cptr(), T_Derived::elementIndexAt(this->cptr(), this->m_index,element_count));
484 }
485
487 auto back() requires (!BASE::isConst)
488 { assert(this->size() > 0);
489 //coverity[INTEGER_OVERFLOW]
490 std::size_t element_count = this->size()-1;
491 return iterator::createElementProxy(this->ptr(), T_Derived::elementIndexAt(this->ptr(), this->m_index,element_count));
492 }
493
498 static element_index_t beginIndex([[maybe_unused]] const ContainerNonConst *container, [[maybe_unused]] const index_t &this_index)
499 requires (std::is_same_v<index_t,RootNodeIndex> && std::is_convertible_v<std::size_t, element_index_t> && hasSize<ContainerNonConst> )
500 {
501 return static_cast<element_index_t>(0u);
502 }
503
507 static element_index_t endIndex([[maybe_unused]] const ContainerNonConst *container, [[maybe_unused]] const index_t &this_index)
508 requires (std::is_same_v<index_t,RootNodeIndex> && std::is_convertible_v<std::size_t, element_index_t> && hasSize<Container>)
509 {
510 assert( !container || container->size() < std::numeric_limits<element_index_t>::max());
511 return (container ? static_cast<element_index_t>(container->size()) : 0u);
512 }
513 // @brief Default implementation to get the next index following the element identified by the given element index.
514 // In most cases the next element is computed by the prefix increment operator
515 static element_index_t nextElementIndex([[maybe_unused]] const ContainerNonConst *container, element_index_t &&element_index)
516 {
517 assert( container );
518 return ++element_index;
519 }
520
526 static element_index_t elementIndexAt(const ContainerNonConst *container, const index_t &this_index, std::size_t element_counter)
528 { return T_Derived::beginIndex(container,this_index) + element_counter; }
529
533 std::size_t size() const
535 {
536 return (this->cptr()
537 ? T_Derived::endIndex(this->cptr(), m_index)-T_Derived::beginIndex(this->cptr(), m_index)
538 : 0u);
539 }
540
543 std::size_t empty() const
544 {
545 return (this->cptr()
546 ? T_Derived::endIndex(this->cptr(), m_index)==T_Derived::beginIndex(this->cptr(), m_index)
547 : true);
548 }
549};
550}
551#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
Indicate whether a container provides read only or read write access.
Definition index.py:1
static constexpr AccessPolicy accessPolicy
static constexpr AccessPolicy accessPolicy
std::remove_cvref_t< Container > ContainerNonConst
std::conditional< accessPolicy==AccessPolicy::Const, const ContainerNonConst, ContainerNonConst >::type ContainerType
std::conditional< accessPolicy==AccessPolicy::Const, const ContainerNonConst *, ContainerNonConst * >::type ContainerPtr
ContainerNonConst * ptr()
std::remove_cvref_t< Container > ContainerNonConst
ContainerNonConst & container()
Return a non const pointer of the container which contains the elements this proxy refers to provided...
ContainerProxyBase(const ContainerProxyBase< OtherContainer, ElementIndexType > &a)
ContainerProxyBase(ContainerNonConst *container)
ContainerProxyBase(const ContainerNonConst *container)
ElementIndexType element_index_t
std::conditional< isConst, const ContainerNonConst *, ContainerNonConst * >::type ContainerPtr
const ContainerNonConst * cptr() const
The proxy container object which provides the means to iterate over its elements and create element p...
const index_t & index() const
The index of this proxy container which identifies this proxy container within the parent container.
auto operator[](std::size_t element_count) const
Element access operator (read-only access)
ProxyIterator< ContainerNonConst, RawDataContainerProxy< T_RawDataContainer, T_RawDataProxy >, T_RawDataProxy > iterator
std::size_t size() const
Default implementation to compute the number of elements this proxy container contains/refers to The ...
const_iterator begin() const
Get the begin iterator of this proxy container for read only element access.
auto operator[](std::size_t element_count)
Element access operator (read-write access)
iterator end()
Get the end iterator of this proxy container for read write element access provided the access policy...
auto front()
Get a proxy for the first child element (read-write).
static element_index_t elementIndexAt(const ContainerNonConst *container, const index_t &this_index, std::size_t element_counter)
Default implementation to get the full index of a certain element.
std::size_t empty() const
Default implementation to test whether the container does not contain elements.
ContainerProxy(const ContainerNonConst *container, const index_t &index)
Create a sub-container proxy with read-only access to its elements which is only possible if the cont...
auto back()
Get a proxy for the last child element (read-write).
ContainerProxy(const T_RWProxy &other)
Create a read only element proxy from a read write proxy.
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...
const_iterator end() const
Get the end iterator of this proxy container for read only element access.
ContainerProxy(const ContainerNonConst *container)
Create a root container proxy with read-only access to its elements which is only possible if the con...
ProxyIterator< const ContainerNonConst, RawDataContainerProxy< T_RawDataContainer, T_RawDataProxy >, T_RawDataProxy > const_iterator
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...
iterator begin()
Get the begin iterator of this proxy container for read write element access provided the access poli...
ContainerProxy(ContainerNonConst *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 element_index_t nextElementIndex(const ContainerNonConst *container, element_index_t &&element_index)
ContainerProxy(ContainerNonConst *container)
Create a root container proxy with read-write access to its elements where a root container proxy ref...
static element_index_t beginIndex(const ContainerNonConst *container, const index_t &this_index)
Default implementation to get the index of the first element of this proxy container For a full range...
static element_index_t endIndex(const ContainerNonConst *container, const index_t &this_index)
Default implementation to get the index after the last element of this proxy container For a full ran...
auto front() const
Get a proxy for the first child element (read-only) The operation is undefined if there are no child ...
auto back() const
Get a proxy for the last child element (read-only).
std::remove_cvref_t< T_RawDataContainer > ContainerNonConst
ElementProxyBase(ContainerNonConst *container, index_t &&index)
ElementProxyBase(const ElementProxyBase< OtherContainer, ElementIndexType > &other)
std::conditional< isConst, const ContainerNonConst *, ContainerNonConst * >::type ContainerPtr
const ContainerNonConst * cptr() const
ElementProxyBase(const ContainerNonConst *container, const index_t &index)
ContainerNonConst & container()
ElementProxyBase(const ContainerNonConst *container, index_t &&index)
ElementProxyBase(ContainerNonConst *container, const index_t &index)
Base class of iterators to iterate over the elements of this proxy container.
ProxyIteratorBase & operator+=(std::size_t offset)
typename ElementProxy::index_t element_index_t
ElementProxyBase< Container, element_index_t > BASE
static auto createElementProxy(const BASE::ContainerNonConst *ptr, element_index_t &&element_index)
Create a proxy for one element of the "container" this proxy represents (read-only access).
bool operator==(const ProxyIteratorBase< OtherContainer, T_Derived, ElementProxy > &other) const
static auto createElementProxy(const BASE::ContainerNonConst *ptr, element_index_t &&element_index)
Create a proxy for one element of the "container" this proxy represents (read-only access).
static auto createElementProxy(BASE::ContainerNonConst *ptr, element_index_t &&element_index)
Create a proxy for one element of the "container" this proxy represents (read-write access).
ProxyIteratorBase & operator++()
static auto diff(const T &a, const T &b)
static std::int64_t diff(const T &a, const T &b)
static void diff(const T &a, const T &b)
ProxyIterator operator++(int)
decltype(diff_type_helper< typename BASE::element_index_t >::diff(std::declval< typename BASE::element_index_t >(), std::declval< typename BASE::element_index_t >())) difference_type
ProxyIterator & operator++()
decltype(std::declval< BASE >().operator*()) value_type
bool operator!=(const ProxyIteratorBase< OtherContainer, T_Derived, ElementProxy > &other) const
ProxyIterator & operator+=(std::size_t offset)
ProxyIteratorBase< Container, T_Derived, ElementProxy > BASE
Helper struct to indicate the "index" of a top level container proxy.