// 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 #include "paddle/fluid/lite/utils/cp_logging.h" #include "paddle/fluid/lite/utils/string.h" // This is an equivalent implementation of boost::any. We implement this to // avoid including the whole boost library and keep the inference library small. // These code references https://gist.github.com/shoooe/9202235 namespace paddle { namespace lite { template struct static_max; template struct static_max { static const size_t value = arg; }; template struct static_max { static const size_t value = arg1 >= arg2 ? static_max::value : static_max::value; }; template struct variant_helper; template struct variant_helper { inline static void destroy(size_t id, void* data) { if (id == typeid(F).hash_code()) reinterpret_cast(data)->~F(); else variant_helper::destroy(id, data); } inline static void move(size_t old_t, void* old_v, void* new_v) { if (old_t == typeid(F).hash_code()) new (new_v) F(std::move(*reinterpret_cast(old_v))); else variant_helper::move(old_t, old_v, new_v); } inline static void copy(size_t old_t, const void* old_v, void* new_v) { if (old_t == typeid(F).hash_code()) new (new_v) F(*reinterpret_cast(old_v)); else variant_helper::copy(old_t, old_v, new_v); } }; template <> struct variant_helper<> { inline static void destroy(size_t id, void* data) {} inline static void move(size_t old_t, void* old_v, void* new_v) {} inline static void copy(size_t old_t, const void* old_v, void* new_v) {} }; template struct variant { private: static const size_t data_size = static_max::value; static const size_t data_align = static_max::value; using data_t = typename std::aligned_storage::type; using helper_t = variant_helper; static inline size_t invalid_type() { return typeid(void).hash_code(); } size_t type_id; data_t data; public: variant() : type_id(invalid_type()) {} variant(const variant& old) : type_id(old.type_id) { helper_t::copy(old.type_id, &old.data, &data); } variant(variant&& old) : type_id(old.type_id) { helper_t::move(old.type_id, &old.data, &data); } // Serves as both the move and the copy asignment operator. variant& operator=(variant old) { std::swap(type_id, old.type_id); std::swap(data, old.data); return *this; } template bool is() { return (type_id == typeid(T).hash_code()); } size_t type() { return type_id; } bool valid() { return (type_id != invalid_type()); } template void set(Args&&... args) { // First we destroy the current contents helper_t::destroy(type_id, &data); new (&data) T(std::forward(args)...); type_id = typeid(T).hash_code(); } template const T& get() const { // It is a dynamic_cast-like behaviour if (type_id == typeid(T).hash_code()) return *reinterpret_cast(&data); else throw std::invalid_argument( string_format("unmatched type, store as %d, but want to get %s", type_id, typeid(T).name())); return *reinterpret_cast(&data); } template T* get_mutable() { // It is a dynamic_cast-like behaviour if (type_id == typeid(T).hash_code()) return reinterpret_cast(&data); else LOG(ERROR) << "unmatched type get, should be " << type_id << " but get " << typeid(T).name(); throw std::invalid_argument("unmatched type"); } ~variant() { helper_t::destroy(type_id, &data); } }; } // namespace lite } // namespace paddle