Home | History | Annotate | Download | only in gprpp
      1 /*
      2  *
      3  * Copyright 2016 gRPC authors.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  */
     18 
     19 #ifndef GRPC_CORE_LIB_GPRPP_MANUAL_CONSTRUCTOR_H
     20 #define GRPC_CORE_LIB_GPRPP_MANUAL_CONSTRUCTOR_H
     21 
     22 // manually construct a region of memory with some type
     23 
     24 #include <grpc/support/port_platform.h>
     25 
     26 #include <stddef.h>
     27 #include <stdlib.h>
     28 #include <new>
     29 #include <type_traits>
     30 #include <utility>
     31 
     32 #include <grpc/support/log.h>
     33 
     34 namespace grpc_core {
     35 
     36 // this contains templated helpers needed to implement the ManualConstructors
     37 // in this file.
     38 namespace manual_ctor_impl {
     39 
     40 // is_one_of returns true it a class, Member, is present in a variadic list of
     41 // classes, List.
     42 template <class Member, class... List>
     43 class is_one_of;
     44 
     45 template <class Member, class... List>
     46 class is_one_of<Member, Member, List...> {
     47  public:
     48   static constexpr const bool value = true;
     49 };
     50 
     51 template <class Member, class A, class... List>
     52 class is_one_of<Member, A, List...> {
     53  public:
     54   static constexpr const bool value = is_one_of<Member, List...>::value;
     55 };
     56 
     57 template <class Member>
     58 class is_one_of<Member> {
     59  public:
     60   static constexpr const bool value = false;
     61 };
     62 
     63 // max_size_of returns sizeof(Type) for the largest type in the variadic list
     64 // of classes, Types.
     65 template <class... Types>
     66 class max_size_of;
     67 
     68 template <class A>
     69 class max_size_of<A> {
     70  public:
     71   static constexpr const size_t value = sizeof(A);
     72 };
     73 
     74 template <class A, class... B>
     75 class max_size_of<A, B...> {
     76  public:
     77   static constexpr const size_t value = sizeof(A) > max_size_of<B...>::value
     78                                             ? sizeof(A)
     79                                             : max_size_of<B...>::value;
     80 };
     81 
     82 // max_size_of returns alignof(Type) for the largest type in the variadic list
     83 // of classes, Types.
     84 template <class... Types>
     85 class max_align_of;
     86 
     87 template <class A>
     88 class max_align_of<A> {
     89  public:
     90   static constexpr const size_t value = alignof(A);
     91 };
     92 
     93 template <class A, class... B>
     94 class max_align_of<A, B...> {
     95  public:
     96   static constexpr const size_t value = alignof(A) > max_align_of<B...>::value
     97                                             ? alignof(A)
     98                                             : max_align_of<B...>::value;
     99 };
    100 
    101 }  // namespace manual_ctor_impl
    102 
    103 template <class BaseType, class... DerivedTypes>
    104 class PolymorphicManualConstructor {
    105  public:
    106   // No constructor or destructor because one of the most useful uses of
    107   // this class is as part of a union, and members of a union could not have
    108   // constructors or destructors till C++11.  And, anyway, the whole point of
    109   // this class is to bypass constructor and destructor.
    110 
    111   BaseType* get() { return reinterpret_cast<BaseType*>(&space_); }
    112   const BaseType* get() const {
    113     return reinterpret_cast<const BaseType*>(&space_);
    114   }
    115 
    116   BaseType* operator->() { return get(); }
    117   const BaseType* operator->() const { return get(); }
    118 
    119   BaseType& operator*() { return *get(); }
    120   const BaseType& operator*() const { return *get(); }
    121 
    122   template <class DerivedType>
    123   void Init() {
    124     FinishInit(new (&space_) DerivedType);
    125   }
    126 
    127   // Init() constructs the Type instance using the given arguments
    128   // (which are forwarded to Type's constructor).
    129   //
    130   // Note that Init() with no arguments performs default-initialization,
    131   // not zero-initialization (i.e it behaves the same as "new Type;", not
    132   // "new Type();"), so it will leave non-class types uninitialized.
    133   template <class DerivedType, typename... Ts>
    134   void Init(Ts&&... args) {
    135     FinishInit(new (&space_) DerivedType(std::forward<Ts>(args)...));
    136   }
    137 
    138   // Init() that is equivalent to copy and move construction.
    139   // Enables usage like this:
    140   //   ManualConstructor<std::vector<int>> v;
    141   //   v.Init({1, 2, 3});
    142   template <class DerivedType>
    143   void Init(const DerivedType& x) {
    144     FinishInit(new (&space_) DerivedType(x));
    145   }
    146   template <class DerivedType>
    147   void Init(DerivedType&& x) {
    148     FinishInit(new (&space_) DerivedType(std::move(x)));
    149   }
    150 
    151   void Destroy() { get()->~BaseType(); }
    152 
    153  private:
    154   template <class DerivedType>
    155   void FinishInit(DerivedType* p) {
    156     static_assert(
    157         manual_ctor_impl::is_one_of<DerivedType, DerivedTypes...>::value,
    158         "DerivedType must be one of the predeclared DerivedTypes");
    159     GPR_ASSERT(static_cast<BaseType*>(p) == p);
    160   }
    161 
    162   typename std::aligned_storage<
    163       grpc_core::manual_ctor_impl::max_size_of<DerivedTypes...>::value,
    164       grpc_core::manual_ctor_impl::max_align_of<DerivedTypes...>::value>::type
    165       space_;
    166 };
    167 
    168 template <typename Type>
    169 class ManualConstructor {
    170  public:
    171   // No constructor or destructor because one of the most useful uses of
    172   // this class is as part of a union, and members of a union could not have
    173   // constructors or destructors till C++11.  And, anyway, the whole point of
    174   // this class is to bypass constructor and destructor.
    175 
    176   Type* get() { return reinterpret_cast<Type*>(&space_); }
    177   const Type* get() const { return reinterpret_cast<const Type*>(&space_); }
    178 
    179   Type* operator->() { return get(); }
    180   const Type* operator->() const { return get(); }
    181 
    182   Type& operator*() { return *get(); }
    183   const Type& operator*() const { return *get(); }
    184 
    185   void Init() { new (&space_) Type; }
    186 
    187   // Init() constructs the Type instance using the given arguments
    188   // (which are forwarded to Type's constructor).
    189   //
    190   // Note that Init() with no arguments performs default-initialization,
    191   // not zero-initialization (i.e it behaves the same as "new Type;", not
    192   // "new Type();"), so it will leave non-class types uninitialized.
    193   template <typename... Ts>
    194   void Init(Ts&&... args) {
    195     new (&space_) Type(std::forward<Ts>(args)...);
    196   }
    197 
    198   // Init() that is equivalent to copy and move construction.
    199   // Enables usage like this:
    200   //   ManualConstructor<std::vector<int>> v;
    201   //   v.Init({1, 2, 3});
    202   void Init(const Type& x) { new (&space_) Type(x); }
    203   void Init(Type&& x) { new (&space_) Type(std::move(x)); }
    204 
    205   void Destroy() { get()->~Type(); }
    206 
    207  private:
    208   typename std::aligned_storage<sizeof(Type), alignof(Type)>::type space_;
    209 };
    210 
    211 }  // namespace grpc_core
    212 
    213 #endif
    214