Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:03:54

0001 #ifndef DataFormats_Common_interface_StdArray_h
0002 #define DataFormats_Common_interface_StdArray_h
0003 
0004 #include <array>
0005 #include <cstddef>
0006 #include <iostream>
0007 #include <iterator>
0008 
0009 #include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
0010 
0011 namespace edm {
0012 
0013   // Due to a ROOT limitation an std::array cannot be serialised to a ROOT file.
0014   // See https://github.com/root-project/root/issues/12007 for a discussion on the issue.
0015   //
0016   // This class reimplements the full std::array<T,N> interface, using a regular
0017   // Reflex dictionary for the ROOT serialisation.
0018   // To be more GPU-friendly, all methods are constexpr, and out-of-bound data access
0019   // aborts instead of throwing an exception.
0020   //
0021   // Note: dictonaries for edm::StdArray<T,N> where T is a standard C/C++ type
0022   // should be declared in DataFormats/Common/src/classed_def.xml.
0023 
0024   namespace detail {
0025     template <typename T, std::size_t N>
0026     class StdArrayTrait {
0027     public:
0028       using array_type = T[N];
0029     };
0030 
0031     template <typename T>
0032     class StdArrayTrait<T, 0> {
0033     public:
0034       struct array_type {};
0035     };
0036   }  // namespace detail
0037 
0038   template <typename T, std::size_t N>
0039   class StdArray {
0040   public:
0041     // Member types
0042 
0043     using value_type = T;
0044     using size_type = std::size_t;
0045     using difference_type = std::ptrdiff_t;
0046     using reference = value_type&;
0047     using const_reference = value_type const&;
0048     using pointer = value_type*;
0049     using const_pointer = const value_type*;
0050     using iterator = pointer;
0051     using const_iterator = const_pointer;
0052     using reverse_iterator = std::reverse_iterator<iterator>;
0053     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0054 
0055     // Interoperability with std::array
0056 
0057     // copy assignment from an std::array
0058     constexpr StdArray& operator=(std::array<T, N> const& init) {
0059       for (size_type i = 0; i < N; ++i) {
0060         data_[i] = init[i];
0061       }
0062       return *this;
0063     }
0064 
0065     // move assignment from an std::array
0066     constexpr StdArray& operator=(std::array<T, N>&& init) {
0067       for (size_type i = 0; i < N; ++i) {
0068         data_[i] = std::move(init[i]);
0069       }
0070       return *this;
0071     }
0072 
0073     // cast operator to an std::array
0074     constexpr operator std::array<T, N>() const {
0075       std::array<T, N> copy;
0076       for (size_type i = 0; i < N; ++i) {
0077         copy[i] = data_[i];
0078       }
0079       return copy;
0080     }
0081 
0082     // Element access
0083 
0084     // Returns a reference to the element at specified location pos, with bounds checking.
0085     // If pos is not within the range of the container, the program aborts.
0086     constexpr reference at(size_type pos) {
0087       if (pos >= N)
0088         abort();
0089       return data_[pos];
0090     }
0091     constexpr const_reference at(size_type pos) const {
0092       if (pos >= N)
0093         abort();
0094       return data_[pos];
0095     }
0096 
0097     // Returns a reference to the element at specified location pos. No bounds checking is performed.
0098     constexpr reference operator[](size_type pos) { return data_[pos]; }
0099     constexpr const_reference operator[](size_type pos) const { return data_[pos]; }
0100 
0101     // Returns a reference to the first element in the container.
0102     // Calling front on an empty container causes the program to abort.
0103     constexpr reference front() {
0104       if constexpr (N == 0)
0105         abort();
0106       return data_[0];
0107     }
0108     constexpr const_reference front() const {
0109       if constexpr (N == 0)
0110         abort();
0111       return data_[0];
0112     }
0113 
0114     // Returns a reference to the last element in the container.
0115     // Calling back on an empty container causes the program to abort.
0116     constexpr reference back() {
0117       if constexpr (N == 0)
0118         abort();
0119       return data_[N - 1];
0120     }
0121     constexpr const_reference back() const {
0122       if constexpr (N == 0)
0123         abort();
0124       return data_[N - 1];
0125     }
0126 
0127     // Returns pointer to the underlying array serving as element storage.
0128     // The pointer is such that range [data(), data() + size()) is always a valid range,
0129     // even if the container is empty (data() is not dereferenceable in that case).
0130     constexpr pointer data() noexcept {
0131       if constexpr (N != 0)
0132         return data_;
0133       else
0134         return nullptr;
0135     }
0136     constexpr const_pointer data() const noexcept {
0137       if constexpr (N != 0)
0138         return data_;
0139       else
0140         return nullptr;
0141     }
0142 
0143     // Iterators
0144 
0145     // Returns an iterator to the first element of the array.
0146     // If the array is empty, the returned iterator will be equal to end().
0147     constexpr iterator begin() noexcept {
0148       if constexpr (N != 0)
0149         return data_;
0150       else
0151         return nullptr;
0152     }
0153     constexpr const_iterator begin() const noexcept {
0154       if constexpr (N != 0)
0155         return data_;
0156       else
0157         return nullptr;
0158     }
0159     constexpr const_iterator cbegin() const noexcept {
0160       if constexpr (N != 0)
0161         return data_;
0162       else
0163         return nullptr;
0164     }
0165 
0166     // Returns an iterator to the element following the last element of the array.
0167     // This element acts as a placeholder; attempting to access it results in undefined behavior.
0168     constexpr iterator end() noexcept {
0169       if constexpr (N != 0)
0170         return data_ + N;
0171       else
0172         return nullptr;
0173     }
0174     constexpr const_iterator end() const noexcept {
0175       if constexpr (N != 0)
0176         return data_ + N;
0177       else
0178         return nullptr;
0179     }
0180     constexpr const_iterator cend() const noexcept {
0181       if constexpr (N != 0)
0182         return data_ + N;
0183       else
0184         return nullptr;
0185     }
0186 
0187     // Returns a reverse iterator to the first element of the reversed array.
0188     // It corresponds to the last element of the non-reversed array. If the array is empty, the returned iterator is equal to rend().
0189     constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
0190     constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
0191     constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
0192 
0193     // Returns a reverse iterator to the element following the last element of the reversed array.
0194     // It corresponds to the element preceding the first element of the non-reversed array. This element acts as a placeholder, attempting to access it results in undefined behavior.
0195     constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
0196     constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
0197     constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
0198 
0199     // Capacity
0200 
0201     // Checks if the container has no elements, i.e. whether begin() == end().
0202     constexpr bool empty() const noexcept { return N == 0; }
0203 
0204     // Returns the number of elements in the container, i.e. std::distance(begin(), end()).
0205     constexpr size_type size() const noexcept { return N; }
0206 
0207     // Returns the maximum number of elements the container is able to hold due to system or library implementation limitations, i.e. std::distance(begin(), end()) for the largest container.
0208     constexpr size_type max_size() const noexcept { return N; }
0209 
0210     // Operations
0211 
0212     // Assigns the value to all elements in the container.
0213     constexpr void fill(const T& value) {
0214       for (size_type i = 0; i < N; ++i)
0215         data_[i] = N;
0216     }
0217 
0218     // Exchanges the contents of the container with those of other. Does not cause iterators and references to associate with the other container.
0219     constexpr void swap(StdArray& other) noexcept(std::is_nothrow_swappable_v<T>) {
0220       if (&other == this)
0221         return;
0222       for (size_type i = 0; i < N; ++i)
0223         std::swap(data_[i], other[i]);
0224     }
0225 
0226     // Data members
0227 
0228     // Use a public data member to allow aggregate initialisation
0229     typename detail::StdArrayTrait<T, N>::array_type data_;
0230 
0231     // ROOT dictionary support for templated classes
0232     CMS_CLASS_VERSION(3);
0233   };
0234 
0235   // comparison operator; T and U must be inequality comparable
0236   template <class T, class U, std::size_t N>
0237   constexpr bool operator==(StdArray<T, N> const& lhs, StdArray<U, N> const& rhs) {
0238     for (std::size_t i = 0; i < N; ++i) {
0239       if (lhs[i] != rhs[i])
0240         return false;
0241     }
0242     return true;
0243   }
0244 
0245   // output stream operator
0246   template <typename T, std::size_t N>
0247   std::ostream& operator<<(std::ostream& out, edm::StdArray<T, N> const& array) {
0248     out << "{";
0249     if constexpr (N > 0) {
0250       out << " " << array[0];
0251     }
0252     for (std::size_t i = 1; i < N; ++i)
0253       out << ", " << array[i];
0254     out << " }";
0255     return out;
0256   }
0257 
0258 }  // namespace edm
0259 
0260 #endif  // DataFormats_Common_interface_StdArray_h