/* * * Copyright 2016 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #ifndef GRPC_CORE_LIB_GPRPP_MANUAL_CONSTRUCTOR_H #define GRPC_CORE_LIB_GPRPP_MANUAL_CONSTRUCTOR_H // manually construct a region of memory with some type #include #include #include #include #include #include #include namespace grpc_core { // this contains templated helpers needed to implement the ManualConstructors // in this file. namespace manual_ctor_impl { // is_one_of returns true it a class, Member, is present in a variadic list of // classes, List. template class is_one_of; template class is_one_of { public: static constexpr const bool value = true; }; template class is_one_of { public: static constexpr const bool value = is_one_of::value; }; template class is_one_of { public: static constexpr const bool value = false; }; // max_size_of returns sizeof(Type) for the largest type in the variadic list // of classes, Types. template class max_size_of; template class max_size_of { public: static constexpr const size_t value = sizeof(A); }; template class max_size_of { public: static constexpr const size_t value = sizeof(A) > max_size_of::value ? sizeof(A) : max_size_of::value; }; // max_size_of returns alignof(Type) for the largest type in the variadic list // of classes, Types. template class max_align_of; template class max_align_of { public: static constexpr const size_t value = alignof(A); }; template class max_align_of { public: static constexpr const size_t value = alignof(A) > max_align_of::value ? alignof(A) : max_align_of::value; }; } // namespace manual_ctor_impl template class PolymorphicManualConstructor { public: // No constructor or destructor because one of the most useful uses of // this class is as part of a union, and members of a union could not have // constructors or destructors till C++11. And, anyway, the whole point of // this class is to bypass constructor and destructor. BaseType* get() { return reinterpret_cast(&space_); } const BaseType* get() const { return reinterpret_cast(&space_); } BaseType* operator->() { return get(); } const BaseType* operator->() const { return get(); } BaseType& operator*() { return *get(); } const BaseType& operator*() const { return *get(); } template void Init() { FinishInit(new (&space_) DerivedType); } // Init() constructs the Type instance using the given arguments // (which are forwarded to Type's constructor). // // Note that Init() with no arguments performs default-initialization, // not zero-initialization (i.e it behaves the same as "new Type;", not // "new Type();"), so it will leave non-class types uninitialized. template void Init(Ts&&... args) { FinishInit(new (&space_) DerivedType(std::forward(args)...)); } // Init() that is equivalent to copy and move construction. // Enables usage like this: // ManualConstructor> v; // v.Init({1, 2, 3}); template void Init(const DerivedType& x) { FinishInit(new (&space_) DerivedType(x)); } template void Init(DerivedType&& x) { FinishInit(new (&space_) DerivedType(std::move(x))); } void Destroy() { get()->~BaseType(); } private: template void FinishInit(DerivedType* p) { static_assert( manual_ctor_impl::is_one_of::value, "DerivedType must be one of the predeclared DerivedTypes"); GPR_ASSERT(static_cast(p) == p); } typename std::aligned_storage< grpc_core::manual_ctor_impl::max_size_of::value, grpc_core::manual_ctor_impl::max_align_of::value>::type space_; }; template class ManualConstructor { public: // No constructor or destructor because one of the most useful uses of // this class is as part of a union, and members of a union could not have // constructors or destructors till C++11. And, anyway, the whole point of // this class is to bypass constructor and destructor. Type* get() { return reinterpret_cast(&space_); } const Type* get() const { return reinterpret_cast(&space_); } Type* operator->() { return get(); } const Type* operator->() const { return get(); } Type& operator*() { return *get(); } const Type& operator*() const { return *get(); } void Init() { new (&space_) Type; } // Init() constructs the Type instance using the given arguments // (which are forwarded to Type's constructor). // // Note that Init() with no arguments performs default-initialization, // not zero-initialization (i.e it behaves the same as "new Type;", not // "new Type();"), so it will leave non-class types uninitialized. template void Init(Ts&&... args) { new (&space_) Type(std::forward(args)...); } // Init() that is equivalent to copy and move construction. // Enables usage like this: // ManualConstructor> v; // v.Init({1, 2, 3}); void Init(const Type& x) { new (&space_) Type(x); } void Init(Type&& x) { new (&space_) Type(std::move(x)); } void Destroy() { get()->~Type(); } private: typename std::aligned_storage::type space_; }; } // namespace grpc_core #endif