// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. // // 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. #pragma once #include #include #include #include #include #include "lite/utils/cp_logging.h" namespace paddle { namespace lite { class Any { public: inline Any() = default; inline explicit Any(Any&& other); inline explicit Any(const Any& other); template void set(); template void set(T&& other); template const T& get() const; template T* get_mutable(); template inline explicit Any(T&& other); inline ~Any(); inline Any& operator=(Any&& other); inline Any& operator=(const Any& other); template inline Any& operator=(T&& other); inline bool empty() const; inline bool valid() const; inline void clear(); inline void swap(Any& other); inline const std::type_info& type() const; template inline void construct(Args&&... args); private: template class TypeOnHeap; template class TypeOnStack; template class TypeInfo; static const size_t kStack = sizeof(void*) * 3; static const size_t kAlign = sizeof(void*); union Data { std::aligned_storage::type stack; void* pheap; }; struct Type { void (*destroy)(Data* data); void (*create_from_data)(Data* dst, const Data& src); const std::type_info* ptype_info; }; template struct data_on_stack { static const bool value = ((alignof(T) <= kAlign) && (sizeof(T) <= kStack)); }; inline void construct(Any&& other); inline void construct(const Any& other); template inline void check_type() const; template inline void check_type_by_name() const; const Type* type_{nullptr}; Data data_; }; template inline Any::Any(T&& other) { typedef typename std::decay::type DT; if (std::is_same::value) { this->construct(std::forward(other)); } else { static_assert(std::is_copy_constructible
::value, "Any can only hold value that is copy constructable"); type_ = TypeInfo
::get_type(); if (data_on_stack
::value) { #pragma GCC diagnostic push #if 6 <= __GNUC__ #pragma GCC diagnostic ignored "-Wplacement-new" #endif new (&(data_.stack)) DT(std::forward(other)); #pragma GCC diagnostic pop } else { data_.pheap = new DT(std::forward(other)); } } } inline Any::Any(Any&& other) { this->construct(std::move(other)); } inline Any::Any(const Any& other) { this->construct(other); } inline void Any::construct(Any&& other) { type_ = other.type_; data_ = other.data_; other.type_ = nullptr; } inline void Any::construct(const Any& other) { type_ = other.type_; if (type_ != nullptr) { type_->create_from_data(&data_, other.data_); } } template inline void Any::construct(Args&&... args) { clear(); typedef typename std::decay::type DT; type_ = TypeInfo
::get_type(); if (data_on_stack
::value) { #pragma GCC diagnostic push #if 6 <= __GNUC__ #pragma GCC diagnostic ignored "-Wplacement-new" #endif new (&(data_.stack)) DT(std::forward(args)...); #pragma GCC diagnostic pop } else { data_.pheap = new DT(std::forward(args)...); } } template void Any::set() { this->construct(); } template void Any::set(T&& other) { this->construct(std::forward(other)); } inline Any::~Any() { this->clear(); } inline Any& Any::operator=(Any&& other) { Any(std::move(other)).swap(*this); return *this; } inline Any& Any::operator=(const Any& other) { Any(other).swap(*this); return *this; } template inline Any& Any::operator=(T&& other) { Any(std::forward(other)).swap(*this); return *this; } inline void Any::swap(Any& other) { std::swap(type_, other.type_); std::swap(data_, other.data_); } inline void Any::clear() { if (type_ != nullptr) { if (type_->destroy != nullptr) { type_->destroy(&data_); } type_ = nullptr; } } inline bool Any::empty() const { return type_ == nullptr; } inline bool Any::valid() const { return empty() == false; } inline const std::type_info& Any::type() const { if (type_ != nullptr) { return *(type_->ptype_info); } else { return typeid(void); } } template inline void Any::check_type() const { CHECK_EQ((type_ == nullptr), false); CHECK_EQ((*(type_->ptype_info) == typeid(T)), true); } template inline void Any::check_type_by_name() const { CHECK_EQ((type_ == nullptr), false); CHECK_EQ(strcmp(type_->ptype_info->name(), typeid(T).name()), 0); } template inline const T& Any::get() const { this->check_type(); return *Any::TypeInfo::get_ptr(&(this->data_)); } template T* Any::get_mutable() { return Any::TypeInfo::get_ptr(&(this->data_)); } template class Any::TypeOnHeap { public: inline static T* get_ptr(Any::Data* data) { return static_cast(data->pheap); } inline static const T* get_ptr(const Any::Data* data) { return static_cast(data->pheap); } inline static void create_from_data(Any::Data* dst, const Any::Data& data) { dst->pheap = new T(*get_ptr(&data)); } inline static void destroy(Data* data) { delete static_cast(data->pheap); } }; template class Any::TypeOnStack { public: inline static T* get_ptr(Any::Data* data) { return reinterpret_cast(&(data->stack)); } inline static const T* get_ptr(const Any::Data* data) { return reinterpret_cast(&(data->stack)); } inline static void create_from_data(Any::Data* dst, const Any::Data& data) { new (&(dst->stack)) T(*get_ptr(&data)); } inline static void destroy(Data* data) { T* dptr = reinterpret_cast(&(data->stack)); dptr->~T(); } }; template class Any::TypeInfo : public std::conditional::value, Any::TypeOnStack, Any::TypeOnHeap>::type { public: inline static const Type* get_type() { static TypeInfo tp; return &(tp.type_); } private: Type type_; TypeInfo() { if (std::is_pod::value && data_on_stack::value) { type_.destroy = nullptr; } else { type_.destroy = TypeInfo::destroy; } type_.create_from_data = TypeInfo::create_from_data; type_.ptype_info = &typeid(T); } }; } // namespace lite } // namespace paddle