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 
29 #include <new>
30 #include <type_traits>
31 #include <utility>
32 
33 #include <grpc/support/log.h>
34 
35 #include "src/core/lib/gprpp/construct_destruct.h"
36 
37 namespace grpc_core {
38 
39 // this contains templated helpers needed to implement the ManualConstructors
40 // in this file.
41 namespace manual_ctor_impl {
42 
43 // is_one_of returns true it a class, Member, is present in a variadic list of
44 // classes, List.
45 template <class Member, class... List>
46 class is_one_of;
47 
48 template <class Member, class... List>
49 class is_one_of<Member, Member, List...> {
50  public:
51   static constexpr const bool value = true;
52 };
53 
54 template <class Member, class A, class... List>
55 class is_one_of<Member, A, List...> {
56  public:
57   static constexpr const bool value = is_one_of<Member, List...>::value;
58 };
59 
60 template <class Member>
61 class is_one_of<Member> {
62  public:
63   static constexpr const bool value = false;
64 };
65 
66 // max_size_of returns sizeof(Type) for the largest type in the variadic list
67 // of classes, Types.
68 template <class... Types>
69 class max_size_of;
70 
71 template <class A>
72 class max_size_of<A> {
73  public:
74   static constexpr const size_t value = sizeof(A);
75 };
76 
77 template <class A, class... B>
78 class max_size_of<A, B...> {
79  public:
80   static constexpr const size_t value = sizeof(A) > max_size_of<B...>::value
81                                             ? sizeof(A)
82                                             : max_size_of<B...>::value;
83 };
84 
85 // max_size_of returns alignof(Type) for the largest type in the variadic list
86 // of classes, Types.
87 template <class... Types>
88 class max_align_of;
89 
90 template <class A>
91 class max_align_of<A> {
92  public:
93   static constexpr const size_t value = alignof(A);
94 };
95 
96 template <class A, class... B>
97 class max_align_of<A, B...> {
98  public:
99   static constexpr const size_t value = alignof(A) > max_align_of<B...>::value
100                                             ? alignof(A)
101                                             : max_align_of<B...>::value;
102 };
103 
104 }  // namespace manual_ctor_impl
105 
106 template <class BaseType, class... DerivedTypes>
107 class PolymorphicManualConstructor {
108  public:
109   // No constructor or destructor because one of the most useful uses of
110   // this class is as part of a union, and members of a union could not have
111   // constructors or destructors till C++11.  And, anyway, the whole point of
112   // this class is to bypass constructor and destructor.
113 
get()114   BaseType* get() { return reinterpret_cast<BaseType*>(&space_); }
get()115   const BaseType* get() const {
116     return reinterpret_cast<const BaseType*>(&space_);
117   }
118 
119   BaseType* operator->() { return get(); }
120   const BaseType* operator->() const { return get(); }
121 
122   BaseType& operator*() { return *get(); }
123   const BaseType& operator*() const { return *get(); }
124 
125   template <class DerivedType>
Init()126   void Init() {
127     FinishInit(new (&space_) DerivedType);
128   }
129 
130   // Init() constructs the Type instance using the given arguments
131   // (which are forwarded to Type's constructor).
132   //
133   // Note that Init() with no arguments performs default-initialization,
134   // not zero-initialization (i.e it behaves the same as "new Type;", not
135   // "new Type();"), so it will leave non-class types uninitialized.
136   template <class DerivedType, typename... Ts>
Init(Ts &&...args)137   void Init(Ts&&... args) {
138     FinishInit(new (&space_) DerivedType(std::forward<Ts>(args)...));
139   }
140 
141   // Init() that is equivalent to copy and move construction.
142   // Enables usage like this:
143   //   ManualConstructor<std::vector<int>> v;
144   //   v.Init({1, 2, 3});
145   template <class DerivedType>
Init(const DerivedType & x)146   void Init(const DerivedType& x) {
147     FinishInit(new (&space_) DerivedType(x));
148   }
149   template <class DerivedType>
Init(DerivedType && x)150   void Init(DerivedType&& x) {
151     FinishInit(new (&space_) DerivedType(std::forward<DerivedType>(x)));
152   }
153 
Destroy()154   void Destroy() { get()->~BaseType(); }
155 
156  private:
157   template <class DerivedType>
FinishInit(DerivedType * p)158   void FinishInit(DerivedType* p) {
159     static_assert(
160         manual_ctor_impl::is_one_of<DerivedType, DerivedTypes...>::value,
161         "DerivedType must be one of the predeclared DerivedTypes");
162     GPR_ASSERT(static_cast<BaseType*>(p) == p);
163   }
164 
165   typename std::aligned_storage<
166       grpc_core::manual_ctor_impl::max_size_of<DerivedTypes...>::value,
167       grpc_core::manual_ctor_impl::max_align_of<DerivedTypes...>::value>::type
168       space_;
169 };
170 
171 template <typename Type>
172 class ManualConstructor {
173  public:
174   // No constructor or destructor because one of the most useful uses of
175   // this class is as part of a union, and members of a union could not have
176   // constructors or destructors till C++11.  And, anyway, the whole point of
177   // this class is to bypass constructor and destructor.
178 
get()179   Type* get() { return reinterpret_cast<Type*>(&space_); }
get()180   const Type* get() const { return reinterpret_cast<const Type*>(&space_); }
181 
182   Type* operator->() { return get(); }
183   const Type* operator->() const { return get(); }
184 
185   Type& operator*() { return *get(); }
186   const Type& operator*() const { return *get(); }
187 
Init()188   void Init() { Construct(get()); }
189 
190   // Init() constructs the Type instance using the given arguments
191   // (which are forwarded to Type's constructor).
192   //
193   // Note that Init() with no arguments performs default-initialization,
194   // not zero-initialization (i.e it behaves the same as "new Type;", not
195   // "new Type();"), so it will leave non-class types uninitialized.
196   template <typename... Ts>
Init(Ts &&...args)197   void Init(Ts&&... args) {
198     Construct(get(), std::forward<Ts>(args)...);
199   }
200 
201   // Init() that is equivalent to copy and move construction.
202   // Enables usage like this:
203   //   ManualConstructor<std::vector<int>> v;
204   //   v.Init({1, 2, 3});
Init(const Type & x)205   void Init(const Type& x) { Construct(get(), x); }
Init(Type && x)206   void Init(Type&& x) { Construct(get(), std::forward<Type>(x)); }
207 
Destroy()208   void Destroy() { Destruct(get()); }
209 
210  private:
211   typename std::aligned_storage<sizeof(Type), alignof(Type)>::type space_;
212 };
213 
214 }  // namespace grpc_core
215 
216 #endif  // GRPC_CORE_LIB_GPRPP_MANUAL_CONSTRUCTOR_H
217