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