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