Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-08-25 23:07:07

0001 #ifndef FWCore_Utilities_interface_propagate_const_array_h
0002 #define FWCore_Utilities_interface_propagate_const_array_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     FWCore/Utilities
0006 // Class  :     propagate_const_array
0007 // Description: Propagate const to array-like objects. Based on C++ experimental std::propagate_const.
0008 //              If used with an array of incomplete type, edm::propagate_const_array can only be declared
0009 //              and assigned to nullptr, but not assigned to an actual object or dereferenced.
0010 
0011 // system include files
0012 #include <cstddef>
0013 #include <type_traits>
0014 #include <utility>
0015 
0016 // user include files
0017 
0018 // forward declarations
0019 
0020 namespace edm {
0021   namespace impl {
0022 
0023     template <typename T>
0024     concept ArrayAddressable = requires(T& a) { a[0]; } or std::is_array_v<T>;
0025 
0026     // for a type T, return the type of the return value of the subscript operator T[N]
0027     template <typename T, typename = void, typename = void>
0028     struct subscript_type {};
0029 
0030     // the specialisations for arrays allow supporting incomplete types
0031     template <typename T>
0032     struct subscript_type<T[]> {
0033       using type = T;
0034     };
0035 
0036     template <typename T, int N>
0037     struct subscript_type<T[N]> {
0038       using type = T;
0039     };
0040 
0041     // for non-array types that implement the subscript operator[], a complete type is needed
0042     template <typename T>
0043       requires requires {
0044         requires not std::is_array_v<T>;
0045         requires ArrayAddressable<T>;
0046       }
0047     struct subscript_type<T> {
0048       using type = typename std::remove_reference<decltype(std::declval<T&>()[0])>::type;
0049     };
0050 
0051     template <typename T>
0052     using subscript_type_t = typename subscript_type<T>::type;
0053 
0054   }  // namespace impl
0055 
0056   template <impl::ArrayAddressable T>
0057   class propagate_const_array;
0058 
0059   template <typename T>
0060   constexpr std::decay_t<T>& get_underlying(propagate_const_array<T>&);
0061   template <typename T>
0062   constexpr std::decay_t<T> const& get_underlying(propagate_const_array<T> const&);
0063 
0064   template <impl::ArrayAddressable T>
0065   class propagate_const_array {
0066   public:
0067     friend constexpr std::decay_t<T>& get_underlying<T>(propagate_const_array<T>&);
0068     friend constexpr std::decay_t<T> const& get_underlying<T>(propagate_const_array<T> const&);
0069 
0070     template <impl::ArrayAddressable U>
0071     friend class propagate_const_array;
0072 
0073     using element_type = typename impl::subscript_type_t<T>;
0074 
0075     constexpr propagate_const_array() = default;
0076     constexpr propagate_const_array(propagate_const_array<T>&&) = default;
0077     propagate_const_array(propagate_const_array<T> const&) = delete;
0078     template <typename U>
0079     constexpr propagate_const_array(U&& u) : m_value(std::forward<U>(u)) {}
0080 
0081     constexpr propagate_const_array<T>& operator=(propagate_const_array&&) = default;
0082     propagate_const_array<T>& operator=(propagate_const_array<T> const&) = delete;
0083 
0084     template <typename U>
0085     constexpr propagate_const_array& operator=(propagate_const_array<U>& other) {
0086       static_assert(std::is_convertible_v<std::decay_t<U>, std::decay_t<T>>,
0087                     "Cannot assign propagate_const_array<> of incompatible types");
0088       m_value = other.m_value;
0089       return *this;
0090     }
0091 
0092     template <typename U>
0093     constexpr propagate_const_array& operator=(U&& u) {
0094       m_value = std::forward<U>(u);
0095       return *this;
0096     }
0097 
0098     // ---------- const member functions ---------------------
0099     constexpr element_type const* get() const { return &m_value[0]; }
0100     constexpr element_type const& operator[](std::ptrdiff_t pos) const { return m_value[pos]; }
0101 
0102     constexpr operator element_type const*() const { return this->get(); }
0103 
0104     // ---------- member functions ---------------------------
0105     constexpr element_type* get() { return &m_value[0]; }
0106     constexpr element_type& operator[](std::ptrdiff_t pos) { return m_value[pos]; }
0107 
0108     constexpr operator element_type*() { return this->get(); }
0109 
0110   private:
0111     // ---------- member data --------------------------------
0112     std::decay_t<T> m_value;
0113   };
0114 
0115   template <typename T>
0116   constexpr std::decay_t<T>& get_underlying(propagate_const_array<T>& iP) {
0117     return iP.m_value;
0118   }
0119 
0120   template <typename T>
0121   constexpr std::decay_t<T> const& get_underlying(propagate_const_array<T> const& iP) {
0122     return iP.m_value;
0123   }
0124 
0125 }  // namespace edm
0126 
0127 #endif  // FWCore_Utilities_interface_propagate_const_array_h