/* * Copyright (c) 2017-2023 zhllxt * * author : zhllxt * email : 37792738@qq.com * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef __ASIO2_EXTERNAL_PFR_HPP__ #define __ASIO2_EXTERNAL_PFR_HPP__ #include #if !defined(ASIO2_HEADER_ONLY) && __has_include() #include #else #include #endif #include #include #include #include #include #if !defined(ASIO2_HEADER_ONLY) && __has_include() #include namespace pfr = ::boost::pfr; #else #include namespace pfr = ::bho::pfr; #endif #if !defined(ASIO2_HEADER_ONLY) && __has_include() namespace boost::pfr #else namespace bho::pfr #endif { namespace detail { template struct refl_encode_counter : refl_encode_counter {}; template<> struct refl_encode_counter<0> {}; struct __refl_members_iterator_dummy__ { template static inline void for_each_field(ThisType&, Func&) { } template static inline void for_each_field_name(Func&) { } }; } //--------------------------------------------------------------------------------------------- // this code is refrenced from : https://zhuanlan.zhihu.com/p/320061875 // this code has some unresolved problems. // eg: // struct actor : public dynamic_creator // create("abc", "xyz"); // the create function will failed, beacuse the "abc" type is not equal to std::string, and the // "xyz" type is not equal to const char* // you must call the create function like this: // create(std::string("abc"), (const char*)"xyz"); // This is terrible. // Is it possible to use serialization to solve this problem? //--------------------------------------------------------------------------------------------- template class class_factory { private: class_factory() {} ~class_factory() {} public: static class_factory& instance() { static class_factory inst{}; return inst; } bool regist(std::string name, std::function fn) { if (!fn) return(false); return create_functions_.emplace(std::move(name), std::move(fn)).second; } BaseT* create(const std::string& name, Args&&... args) { auto iter = create_functions_.find(name); if (iter == create_functions_.end()) { return (nullptr); } else { return ((iter->second)(std::forward(args)...)); } } template void for_each(Function&& callback) noexcept { for (const auto& [name, func] : create_functions_) { callback(name, func); } } std::function* find(const std::string& name) { auto it = create_functions_.find(name); return it == create_functions_.end() ? nullptr : std::addressof(it->second); } inline std::size_t size() const noexcept { return create_functions_.size(); } inline bool empty() const noexcept { return create_functions_.empty(); } private: std::unordered_map> create_functions_; }; template class base_dynamic_creator { public: struct registor { registor() { std::string name; #if !defined(ASIO2_HEADER_ONLY) && __has_include() name = boost::core::type_name(); #else name = bho::core::type_name(); #endif class_factory::instance().regist(std::move(name), create); } inline void makesure_construct() const noexcept { }; }; explicit base_dynamic_creator() noexcept { registor_.makesure_construct(); } virtual ~base_dynamic_creator() noexcept { registor_.makesure_construct(); }; private: static BaseT* create(Args&&... args) { return (new T(std::forward(args)...)); } private: static inline registor registor_{}; }; template using dynamic_creator = base_dynamic_creator; template class self_dynamic_creator { public: struct registor { registor() { std::string name; #if !defined(ASIO2_HEADER_ONLY) && __has_include() name = boost::core::type_name(); #else name = bho::core::type_name(); #endif class_factory::instance().regist(std::move(name), create); } inline void makesure_construct() const noexcept { }; }; explicit self_dynamic_creator() noexcept { registor_.makesure_construct(); } virtual ~self_dynamic_creator() noexcept { registor_.makesure_construct(); }; private: static T* create(Args&&... args) { return (new T(std::forward(args)...)); } private: static inline registor registor_{}; }; template class create_helper { public: // dont use Args&&... args // it will cause issue like this: // int i = 2; // create("dog", i); // the i will be parsed as int& template static inline BaseT* create(const std::string& name, Args... args) { return (class_factory::instance().create( name, std::move(args)...)); } }; template class create_helper { public: template static inline BaseT* create(const std::string& name, Args... args) { return (class_factory::instance().create( name, std::move(args)...)); } }; template class create_helper> { public: template static inline std::shared_ptr create(const std::string& name, Args... args) { return std::shared_ptr(class_factory::instance().create( name, std::move(args)...)); } }; template class create_helper> { public: template static inline std::unique_ptr create(const std::string& name, Args... args) { return std::unique_ptr(class_factory::instance().create( name, std::move(args)...)); } }; } // this code is refrenced from : // https://github.com/yuanzhubi/reflect_struct // boost/typeof/dmc/typeof_impl.hpp #ifndef MAX_REFLECT_COUNT #define MAX_REFLECT_COUNT 480 #endif #define BHO_REFLECT_INDEX(counter) \ ((sizeof(*counter((pfr::detail::refl_encode_counter*)0)) - \ sizeof(*counter((void*)0))) / sizeof(char)) \ #define BHO_REFLECT_INCREASE(counter, index) \ static constexpr std::size_t index = BHO_REFLECT_INDEX(counter); \ static char (*counter(pfr::detail::refl_encode_counter< \ sizeof(*counter((void*)0)) / sizeof(char) + index + 1>*)) \ [sizeof(*counter((void*)0)) / sizeof(char) + index + 1]; \ #define BHO_REFLECT_FIELD_INDEX(name) ASIO2_JOIN(__reflect_index_, name) #define F_FIELD_MEMBER_ITERATOR(type, name) \ private: \ BHO_REFLECT_INCREASE(__refl_field_counter__, BHO_REFLECT_FIELD_INDEX(name)) \ template \ struct __refl_members_iterator__ \ { \ typedef __refl_members_iterator__ next_type; \ template \ static void for_each_field(ThisType& This, Func& func) noexcept \ { \ func(ASIO2_STRINGIZE(name), This.name); \ next_type::for_each_field(This, func); \ } \ template \ static void for_each_field_name(Func& func) noexcept \ { \ func(ASIO2_STRINGIZE(name)); \ next_type::for_each_field_name(func); \ } \ } \ #define F_BEGIN(Class) \ private: \ static char (*__refl_field_counter__(...))[1]; \ template struct __refl_members_iterator__ : \ public pfr::detail::__refl_members_iterator_dummy__{}; \ public: \ template \ void for_each_field(Func&& func) noexcept \ { \ decltype(auto) fun = std::forward(func); \ __refl_members_iterator__::for_each_field(*this, fun); \ } \ template \ static void for_each_field_name(Func&& func) noexcept \ { \ decltype(auto) fun = std::forward(func); \ __refl_members_iterator__::for_each_field_name(fun); \ } \ inline static constexpr std::string_view get_class_name() noexcept \ { \ return ASIO2_STRINGIZE(Class); \ } \ template friend struct __refl_members_iterator__ \ #define F_FIELD(type, name) \ public: \ type name{}; \ F_FIELD_MEMBER_ITERATOR(type, name) \ #define F_END() \ public: \ constexpr static std::size_t get_field_count() noexcept \ { \ constexpr std::size_t field_count = BHO_REFLECT_INDEX(__refl_field_counter__); \ return field_count; \ } \ #endif