Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 13:29:19

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 
0022   namespace impl {
0023 
0024     // check if a type T has a subscript operator T[N]
0025     template <typename, typename = void>
0026     struct has_subscript_operator : std::false_type {};
0027 
0028     template <typename T>
0029     struct has_subscript_operator<T, std::void_t<decltype(std::declval<T&>()[0])>> : std::true_type {};
0030 
0031     template <typename T>
0032     constexpr auto has_subscript_operator_v = has_subscript_operator<T>::value;
0033 
0034     // for a type T, return the type of the return value of the subscript operator T[N]
0035     template <typename T, typename = void, typename = void>
0036     struct subscript_type {};
0037 
0038     // the specialisations for arrays allow supporting incomplete types
0039     template <typename T>
0040     struct subscript_type<T[]> {
0041       using type = T;
0042     };
0043 
0044     template <typename T, int N>
0045     struct subscript_type<T[N]> {
0046       using type = T;
0047     };
0048 
0049     // for non-array types that implement the subscript operator[], a complete type is needed
0050     template <typename T>
0051     struct subscript_type<T, std::enable_if_t<not std::is_array_v<T>>, std::enable_if_t<has_subscript_operator_v<T>>> {
0052       using type = typename std::remove_reference<decltype(std::declval<T&>()[0])>::type;
0053     };
0054 
0055     template <typename T>
0056     using subscript_type_t = typename subscript_type<T>::type;
0057 
0058   }  // namespace impl
0059 
0060   template <typename T>
0061   class propagate_const_array;
0062 
0063   template <typename T>
0064   constexpr std::decay_t<T>& get_underlying(propagate_const_array<T>&);
0065   template <typename T>
0066   constexpr std::decay_t<T> const& get_underlying(propagate_const_array<T> const&);
0067 
0068   template <typename T>
0069   class propagate_const_array {
0070   public:
0071     friend constexpr std::decay_t<T>& get_underlying<T>(propagate_const_array<T>&);
0072     friend constexpr std::decay_t<T> const& get_underlying<T>(propagate_const_array<T> const&);
0073 
0074     template <typename U>
0075     friend class propagate_const_array;
0076 
0077     using element_type = typename impl::subscript_type_t<T>;
0078 
0079     constexpr propagate_const_array() = default;
0080     constexpr propagate_const_array(propagate_const_array<T>&&) = default;
0081     propagate_const_array(propagate_const_array<T> const&) = delete;
0082     template <typename U>
0083     constexpr propagate_const_array(U&& u) : m_value(std::forward<U>(u)) {}
0084 
0085     constexpr propagate_const_array<T>& operator=(propagate_const_array&&) = default;
0086     propagate_const_array<T>& operator=(propagate_const_array<T> const&) = delete;
0087 
0088     template <typename U>
0089     constexpr propagate_const_array& operator=(propagate_const_array<U>& other) {
0090       static_assert(std::is_convertible_v<std::decay_t<U>, std::decay_t<T>>,
0091                     "Cannot assign propagate_const_array<> of incompatible types");
0092       m_value = other.m_value;
0093       return *this;
0094     }
0095 
0096     template <typename U>
0097     constexpr propagate_const_array& operator=(U&& u) {
0098       m_value = std::forward<U>(u);
0099       return *this;
0100     }
0101 
0102     // ---------- const member functions ---------------------
0103     constexpr element_type const* get() const { return &m_value[0]; }
0104     constexpr element_type const& operator[](std::ptrdiff_t pos) const { return m_value[pos]; }
0105 
0106     constexpr operator element_type const *() const { return this->get(); }
0107 
0108     // ---------- member functions ---------------------------
0109     constexpr element_type* get() { return &m_value[0]; }
0110     constexpr element_type& operator[](std::ptrdiff_t pos) { return m_value[pos]; }
0111 
0112     constexpr operator element_type*() { return this->get(); }
0113 
0114   private:
0115     // ---------- member data --------------------------------
0116     std::decay_t<T> m_value;
0117   };
0118 
0119   template <typename T>
0120   constexpr std::decay_t<T>& get_underlying(propagate_const_array<T>& iP) {
0121     return iP.m_value;
0122   }
0123 
0124   template <typename T>
0125   constexpr std::decay_t<T> const& get_underlying(propagate_const_array<T> const& iP) {
0126     return iP.m_value;
0127   }
0128 
0129 }  // namespace edm
0130 
0131 #endif  // FWCore_Utilities_interface_propagate_const_array_h