• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get()111   BaseType* get() { return reinterpret_cast<BaseType*>(&space_); }
get()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>
Init()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>
Init(Ts &&...args)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>
Init(const DerivedType & x)143   void Init(const DerivedType& x) {
144     FinishInit(new (&space_) DerivedType(x));
145   }
146   template <class DerivedType>
Init(DerivedType && x)147   void Init(DerivedType&& x) {
148     FinishInit(new (&space_) DerivedType(std::forward<DerivedType>(x)));
149   }
150 
Destroy()151   void Destroy() { get()->~BaseType(); }
152 
153  private:
154   template <class DerivedType>
FinishInit(DerivedType * p)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 
get()176   Type* get() { return reinterpret_cast<Type*>(&space_); }
get()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 
Init()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>
Init(Ts &&...args)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});
Init(const Type & x)202   void Init(const Type& x) { new (&space_) Type(x); }
Init(Type && x)203   void Init(Type&& x) { new (&space_) Type(std::move(x)); }
204 
Destroy()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