48ab231e3395de3a9b83cacaf5b7163ad3e52c99
[platform/upstream/grpc.git] / src / core / lib / gprpp / manual_constructor.h
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::forward<DerivedType>(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  // GRPC_CORE_LIB_GPRPP_MANUAL_CONSTRUCTOR_H