├── .gitignore ├── LICENSE ├── README.md └── include ├── InterfaceDeclare.h ├── InterfaceRegister.h └── PAF ├── CompileTimeHash.h ├── GlobalFactory.h ├── InterfaceDeclareStruct.h ├── InterfaceRegisterStruct.h ├── PAFConfig.h ├── PAFactory.h ├── PAFactory.inl ├── PAFactoryInc.h └── TypeTraits.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Tango 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #PAF Pluginable Abstract Factory 2 | 3 | let's look at a simple usage 4 | 5 | I have a interface and it‘s implemented as below, with a method bar: 6 | 7 | // interface file 8 | class foo_i { 9 | public: 10 | // no need virtual destructor 11 | virtual int bar() = 0; 12 | } 13 | 14 | // class file 15 | class foo : public foo_i { 16 | public: 17 | foo(int val):value(val){} 18 | virtual int bar() override {return ++value;} 19 | int value; 20 | } 21 | 22 | 23 | with PAF, we need only three line noninvasive code 24 | 25 | // interface file 26 | class foo_i { 27 | public: 28 | virtual int bar() = 0; 29 | } 30 | #include "interface_declare.h" // paf interface & register 31 | DELC_INTERFACE_LOCAL(foo_i, int); // Declare, LOCAL means only local var 32 | 33 | // class file 34 | class foo : public foo_i { 35 | public: 36 | foo(int val) :value(val) {} 37 | virtual int bar() override {return ++value;} 38 | int value; 39 | } 40 | // Associate the interface with the corresponding implementation class 41 | REG_FACTORY_OBJECT(foo_i, foo); 42 | 43 | wherever needed (cross-source/cross-module), we just need to include the interface file for foo_i. (consistent with the interface usage scenario, no additional actions are required). 44 | 45 | this is magic show time, which creates local objects with parameter. 46 | 47 | // just include the interface file and use it as below 48 | // you need not know where the implementation file was, it will be in another module, or a pluginable module. 49 | #include "foo_i.h" 50 | auto obj = CREATE_OBJECT(foo_i, 42); // std::shared_ptr 51 | printf("%d", obj->bar()); // 43 52 | 53 | the whole process can also rely on the compiler to check for errors. objects created through factories are naturally smart pointers. 54 | 55 | of course, it also supports the creation of singleton objects: 56 | 57 | // ParameterTypeList is a list of types for the interface implementation class constructor. 58 | REG_INTERFACE_SINGLTETON(InterfaceName, ParameterTypeList...) 59 | or 60 | REG_INTERFACE_STATIC(InterfaceName, ParameterTypeList...) 61 | // thread-safe as static 62 | auto * inc = GET_SINGLETON(InterfaceName, ParameterTypeList...); 63 | // gets only 64 | auto * inc = GET_SINGLETON2(InterfaceName); 65 | // Destruction of the singleton 66 | DESTROY_SINGLETON(InterfaceName); 67 | 68 | singleton will be destroyed manually or by factory with same order as statics. 69 | it is more flexible and controllable than the general static singleton. 70 | 71 | in addition, a more secure pattern is implemented than a single case control: global shared objects. 72 | usually as parent of sub objects. to break circle reference and parameter passing to subs. 73 | 74 | REG_INTERFACE_SHARED(InterfaceName, ParameterTypeList...) 75 | // return a smart pointer 76 | // holding the interface smart pointer can ensure that the interface is not destroyed 77 | auto inc = GET_SHARED(InterfaceName, ParameterTypeList...); 78 | // gets only 79 | auto * inc = GET_SHARED2(InterfaceName); 80 | // when all the smart pointers holding the interface are destroyed, 81 | // the global shared object is destroyed automatically 82 | 83 | in particular, global shared objects can be shared across modules, based on the base layer of the abstract factory. shared objects are destroyed only when all module references are destroyed. 84 | 85 | based on the above features, you can also support elegant, leak-free exits. Perform leak and circular reference checks during release. 86 | -------------------------------------------------------------------------------- /include/InterfaceDeclare.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PAF/InterfaceDeclareStruct.h" 4 | #define DECL_INTERFACE_LOCAL(...) PAF_DECL_INTERFACE_LOCAL_(__VA_ARGS__) 5 | #define DECL_INTERFACE_SHARED(...) PAF_DECL_INTERFACE_SHARED_(__VA_ARGS__) 6 | #define DECL_INTERFACE_SINGLETON(...) PAF_DECL_INTERFACE_SINGLETON_(__VA_ARGS__) 7 | #define DECL_INTERFACE_STATIC(...) PAF_DECL_INTERFACE_STATIC_(__VA_ARGS__) 8 | 9 | // declare 10 | // -------- 11 | // factory 12 | 13 | #include "PAF/PAFactoryInc.h" 14 | 15 | #define CREATE_OBJECT(INC, ...) PAF_NAMESPACE::factory_helper::create_local(__VA_ARGS__) 16 | 17 | #define GET_SHARED(INC, ...) PAF_NAMESPACE::factory_helper::get_shared(__VA_ARGS__) 18 | #define GET_SHARED2(INC) PAF_NAMESPACE::factory_helper::get_shared_ref() 19 | 20 | #define GET_SINGLETON(INC, ...) PAF_NAMESPACE::factory_helper::get_singleton(__VA_ARGS__) 21 | #define GET_SINGLETON2(INC) PAF_NAMESPACE::factory_helper::get_singleton_ref() 22 | #define DESTROY_SINGLETON(INC) PAF_NAMESPACE::factory_helper::destroy_singleton() 23 | 24 | // self-register 25 | #include "InterfaceRegister.h" 26 | -------------------------------------------------------------------------------- /include/InterfaceRegister.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PAF/InterfaceRegisterStruct.h" 4 | #include "PAF/TypeTraits.h" 5 | 6 | namespace PAF_NAMESPACE 7 | { 8 | namespace detail 9 | { 10 | extern "C" PAF_LINK_API void reg_object_info(PAF_NAMESPACE::object_register_info_t& info); 11 | } // namespace detail 12 | 13 | 14 | template 15 | struct TypeToIndex 16 | { 17 | enum 18 | { 19 | value =0 20 | }; 21 | }; 22 | 23 | template ::value> 24 | struct object_register_t; 25 | #pragma pack(push, 4) 26 | template 27 | struct object_register_t 28 | { 29 | object_register_t(PAF_OBJ_ID id, uint8_t flag, const char* name) 30 | { 31 | fn_create_t _create_fun = [](void*) -> void* { return static_cast(new T()); }; 32 | fn_destroy_t _destroy_fun = [](void* data) -> void { delete (static_cast(data)); }; 33 | object_register_info_t a{_create_fun, _destroy_fun, id, flag, 0, name}; 34 | using detail::reg_object_info; 35 | reg_object_info(a); 36 | } 37 | }; 38 | template 39 | struct object_register_t, 0> 40 | { 41 | object_register_t(PAF_OBJ_ID id, uint8_t flag, const char* name) 42 | { 43 | fn_create_t _create_fun = [](void* t) -> void* { 44 | auto f = [](Args&... args) { 45 | return static_cast(new T(detail::forward_t(args)...)); 46 | }; 47 | auto tup = static_cast*>(t); 48 | return detail::apply(f, *tup); 49 | }; 50 | fn_destroy_t _destroy_fun = [](void* data) -> void { delete (static_cast(data)); }; 51 | object_register_info_t a{_create_fun, _destroy_fun, id, flag, 0, name}; 52 | using detail::reg_object_info; 53 | reg_object_info(a); 54 | } 55 | }; 56 | 57 | #pragma pack(pop) 58 | } // namespace PAF_NAMESPACE 59 | 60 | #include "InterfaceDeclare.h" 61 | #define REG_FACTORY_OBJECT_NAME_(name) PAF_REG_TYPE_##name 62 | #define REG_FACTORY_OBJECT_NAME(name) REG_FACTORY_OBJECT_NAME_(name) 63 | 64 | // auto register 65 | #define PAF_REG_FACTORY_OBJECT_(INC, TYPE) \ 66 | static_assert(PAF_TYPE_2_ID::id == PAF_COMPILE_TIME_HASH(INC), "id mismatch!"); \ 67 | static_assert(std::is_base_of::type, TYPE>::value, \ 68 | "type '" PAF_TO_STR(TYPE) "' mismatch with interface '" PAF_TO_STR(INC) "'!"); \ 69 | static_assert(std::is_same::value || !std::has_virtual_destructor::value, \ 70 | "interface : '" PAF_TO_STR(INC) "' should not has virtual dtor!!"); \ 71 | extern "C" auto REG_FACTORY_OBJECT_NAME(INC) = PAF_NAMESPACE:: \ 72 | object_register_t::args_type>(PAF_TYPE_2_ID::id, \ 73 | PAF_TYPE_2_ID::flag, \ 74 | PAF_TO_STR(TYPE)); 75 | #define REG_FACTORY_OBJECT(INC, TYPE) PAF_REG_FACTORY_OBJECT_(INC, TYPE) 76 | 77 | -------------------------------------------------------------------------------- /include/PAF/CompileTimeHash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // Compile Time MurmurHash64B in C++ 3 | // It's easy to make sure implementation which has no conflicts on different names. 4 | 5 | #include 6 | 7 | // 64-bit hash for 32-bit platforms 8 | namespace murmur64b 9 | { 10 | #define MURMUR_NOEXCEPT 11 | constexpr auto SEED_B = 0x5bd1e995ull; 12 | constexpr uint32_t hash_sub(uint32_t h, uint32_t k) MURMUR_NOEXCEPT 13 | { 14 | return h ^ (SEED_B * (k ^ (k >> 24))); 15 | } 16 | constexpr uint32_t hash_helper(uint32_t h, uint32_t k) MURMUR_NOEXCEPT 17 | { 18 | return hash_sub(SEED_B * h, SEED_B * k); 19 | } 20 | constexpr uint64_t hash_final_4(uint32_t x, uint32_t y) MURMUR_NOEXCEPT 21 | { 22 | return ((uint64_t)x << 32) | (uint64_t)y; 23 | } 24 | constexpr uint64_t hash_final_3(uint32_t x, uint32_t y) MURMUR_NOEXCEPT 25 | { 26 | return hash_final_4(x, SEED_B * ((x >> 19) ^ y)); 27 | } 28 | constexpr uint64_t hash_final_2(uint32_t x, uint32_t y) MURMUR_NOEXCEPT 29 | { 30 | return hash_final_3(SEED_B * ((y >> 17) ^ x), y); 31 | } 32 | constexpr uint64_t hash_final_1(uint32_t x, uint32_t y) MURMUR_NOEXCEPT 33 | { 34 | return hash_final_2(x, SEED_B * ((x >> 22) ^ y)); 35 | } 36 | constexpr uint64_t hash_final(uint32_t x, uint32_t y) MURMUR_NOEXCEPT 37 | { 38 | return hash_final_1(SEED_B * ((y >> 18) ^ x), y); 39 | } 40 | template 41 | constexpr uint64_t hash_update(uint32_t h1, uint32_t h2, C... c) MURMUR_NOEXCEPT; 42 | template <> 43 | constexpr uint64_t hash_update(uint32_t h1, uint32_t h2) MURMUR_NOEXCEPT 44 | { 45 | return hash_final(h1, h2); 46 | } 47 | template <> 48 | constexpr uint64_t hash_update(uint32_t h1, uint32_t h2, uint8_t c0) MURMUR_NOEXCEPT 49 | { 50 | return hash_update(h1, SEED_B * (h2 ^ c0)); 51 | } 52 | template <> 53 | constexpr uint64_t hash_update(uint32_t h1, uint32_t h2, uint8_t c0, uint8_t c1) MURMUR_NOEXCEPT 54 | { 55 | return hash_update(h1, h2 ^ ((uint32_t)c1 << 8), c0); 56 | } 57 | template <> 58 | constexpr uint64_t hash_update(uint32_t h1, 59 | uint32_t h2, 60 | uint8_t c0, 61 | uint8_t c1, 62 | uint8_t c2) MURMUR_NOEXCEPT 63 | { 64 | return hash_update(h1, h2 ^ ((uint32_t)c2 << 16), c0, c1); 65 | } 66 | template 67 | constexpr uint64_t hash_update(uint32_t h1, 68 | uint32_t h2, 69 | uint8_t c0, 70 | uint8_t c1, 71 | uint8_t c2, 72 | uint8_t c3, 73 | C... c) MURMUR_NOEXCEPT 74 | { 75 | return hash_update( 76 | hash_helper(h1, 77 | ((uint32_t)c3 << 24) | ((uint32_t)c2 << 16) | ((uint32_t)c1 << 8) | (uint32_t)c0), 78 | h2, 79 | c...); 80 | } 81 | template 82 | constexpr uint64_t hash_update(uint32_t h1, 83 | uint32_t h2, 84 | uint8_t c0, 85 | uint8_t c1, 86 | uint8_t c2, 87 | uint8_t c3, 88 | uint8_t c4, 89 | uint8_t c5, 90 | uint8_t c6, 91 | uint8_t c7, 92 | C... c) MURMUR_NOEXCEPT 93 | { 94 | return hash_update( 95 | hash_helper(h1, 96 | ((uint32_t)c3 << 24) | ((uint32_t)c2 << 16) | ((uint32_t)c1 << 8) | (uint32_t)c0), 97 | hash_helper(h2, 98 | ((uint32_t)c7 << 24) | ((uint32_t)c6 << 16) | ((uint32_t)c5 << 8) | (uint32_t)c4), 99 | c...); 100 | } 101 | 102 | template 103 | struct Sequence 104 | { 105 | }; 106 | template 107 | struct CreateSequence : CreateSequence 108 | { 109 | }; 110 | template 111 | struct CreateSequence<0, S...> 112 | { 113 | using Type = Sequence; 114 | }; 115 | template 116 | constexpr uint64_t Unpack(uint32_t seed, const char (&s)[N], Sequence) MURMUR_NOEXCEPT 117 | { 118 | return hash_update(seed ^ (N - 1), 0, (uint8_t)s[S]...); 119 | } 120 | template 121 | constexpr uint64_t MurmurHash64B(const char (&s)[N], uint32_t seed = 0) MURMUR_NOEXCEPT 122 | { 123 | return murmur64b::Unpack(seed, s, typename CreateSequence::Type()); 124 | } 125 | template 126 | struct constexprN 127 | { 128 | enum : uint64_t 129 | { 130 | value = N 131 | }; 132 | }; 133 | 134 | inline uint64_t MurmurHash64B(const void* key, uint32_t len, uint32_t seed = 0) MURMUR_NOEXCEPT 135 | { 136 | const uint32_t m = 0x5bd1e995; 137 | const int r = 24; 138 | uint32_t h1 = seed ^ len; 139 | uint32_t h2 = 0; 140 | const uint32_t* data = (const uint32_t*)key; 141 | while (len >= 8) 142 | { 143 | uint32_t k1 = *data++; 144 | k1 *= m; 145 | k1 ^= k1 >> r; 146 | k1 *= m; 147 | h1 *= m; 148 | h1 ^= k1; 149 | len -= 4; 150 | uint32_t k2 = *data++; 151 | k2 *= m; 152 | k2 ^= k2 >> r; 153 | k2 *= m; 154 | h2 *= m; 155 | h2 ^= k2; 156 | len -= 4; 157 | } 158 | if (len >= 4) 159 | { 160 | uint32_t k1 = *data++; 161 | k1 *= m; 162 | k1 ^= k1 >> r; 163 | k1 *= m; 164 | h1 *= m; 165 | h1 ^= k1; 166 | len -= 4; 167 | } 168 | switch (len) 169 | { 170 | case 3: 171 | h2 ^= (((char*)data)[2]) << 16; 172 | case 2: 173 | h2 ^= (((char*)data)[1]) << 8; 174 | case 1: 175 | h2 ^= (((char*)data)[0]); 176 | h2 *= m; 177 | }; 178 | h1 ^= h2 >> 18; 179 | h1 *= m; 180 | h2 ^= h1 >> 22; 181 | h2 *= m; 182 | h1 ^= h2 >> 17; 183 | h1 *= m; 184 | h2 ^= h1 >> 19; 185 | h2 *= m; 186 | uint64_t h = h1; 187 | h = (h << 32) | h2; 188 | return h; 189 | } 190 | inline uint32_t MurmurHash32(const void* key, uint32_t len, uint32_t seed = 0) MURMUR_NOEXCEPT 191 | { 192 | // 'm' and 'r' are mixing constants generated offline. 193 | // They're not really 'magic', they just happen to work well. 194 | const uint32_t m = 0xc6a4a793; 195 | const int r = 16; 196 | // Initialize the hash to a 'random' value 197 | uint32_t h = seed ^ (len * m); 198 | // Mix 4 bytes at a time into the hash 199 | const unsigned char* data = (const unsigned char*)key; 200 | while (len >= 4) 201 | { 202 | h += *(unsigned int*)data; 203 | h *= m; 204 | h ^= h >> r; 205 | data += 4; 206 | len -= 4; 207 | } 208 | // Handle the last few bytes of the input array 209 | switch (len) 210 | { 211 | case 3: 212 | h += data[2] << 16; 213 | case 2: 214 | h += data[1] << 8; 215 | case 1: 216 | h += data[0]; 217 | h *= m; 218 | h ^= h >> r; 219 | }; 220 | // Do a few final mixes of the hash to ensure the last few 221 | // bytes are well-incorporated. 222 | h *= m; 223 | h ^= h >> 10; 224 | h *= m; 225 | h ^= h >> 17; 226 | return h; 227 | } 228 | } // namespace murmur64b 229 | 230 | #define PAF_TO_STR_(name) #name 231 | #define PAF_TO_STR(name) PAF_TO_STR_(name) 232 | 233 | #define COMPILE_TIME_HASH_STR(str) murmur64b::constexprN::value 234 | #define COMPILE_TIME_HASH(name) COMPILE_TIME_HASH_STR(PAF_TO_STR(name)) 235 | -------------------------------------------------------------------------------- /include/PAF/GlobalFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PAFactoryInc.h" 3 | #include "InterfaceRegisterStruct.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace PAF_NAMESPACE 13 | { 14 | #pragma pack(push, 4) 15 | struct factory_meta_info_t : public object_register_info_t 16 | { 17 | factory_meta_info_t(const object_register_info_t& rhs) 18 | { 19 | create_obj_ = rhs.create_obj_; 20 | destroy_obj_ = rhs.destroy_obj_; 21 | count_ = rhs.count_; 22 | obj_id_ = rhs.obj_id_; 23 | flag_ = rhs.flag_; 24 | } 25 | 26 | ~factory_meta_info_t() 27 | { 28 | } 29 | 30 | bool exclusive() const 31 | { 32 | return 0 == (flag_ & (interface_flag::create_as_local)); 33 | } 34 | bool is_shared() const 35 | { 36 | return exclusive() && (flag_ & interface_flag::create_as_shared); 37 | } 38 | bool is_single() const 39 | { 40 | return exclusive() && (flag_ & interface_flag::create_as_single); 41 | } 42 | bool is_static() const 43 | { 44 | return exclusive() && (flag_ & interface_flag::create_as_static); 45 | } 46 | bool is_with_args() const 47 | { 48 | return 0 != (flag_ & interface_flag::create_with_args); 49 | } 50 | 51 | factory_meta_info_t(const factory_meta_info_t&) = delete; 52 | factory_meta_info_t& operator=(const factory_meta_info_t&) = delete; 53 | 54 | std::atomic data_{nullptr}; 55 | std::atomic ref_{0}; 56 | std::atomic_bool busy_{false}; 57 | }; 58 | 59 | class global_factory : public global_factory_i 60 | { 61 | using fn_shared_obj_destroy = void (*)(PAF_OBJ_ID id, void*); 62 | 63 | public: 64 | global_factory(); 65 | virtual ~global_factory(); 66 | PAF_DISABLE_COPY(global_factory) 67 | 68 | // local 69 | virtual void* create_local(PAF_OBJ_ID id, void* data = nullptr) override; 70 | virtual void destroy_local(PAF_OBJ_ID id, void* data) override; 71 | 72 | // shared 73 | virtual void* get_or_create_shared(PAF_OBJ_ID id, void* data = nullptr) override; 74 | virtual void* get_shared(PAF_OBJ_ID id, bool addref) override; 75 | virtual void destroy_shared(PAF_OBJ_ID id, void* data) override; 76 | 77 | // singleton 78 | virtual void* get_or_create_singleton(PAF_OBJ_ID id, void* data = nullptr) override; 79 | virtual void* get_singleton(PAF_OBJ_ID id) override; 80 | virtual bool destroy_singleton(PAF_OBJ_ID id, void* data) override; 81 | 82 | public: 83 | // return actual number of registered 84 | int register_global_object(object_register_info_t* arr, size_t count); 85 | bool try_unregister_object(PAF_OBJ_ID obj_id); 86 | void unregister_object(PAF_OBJ_ID obj_id); 87 | void release_all_global_objects(); 88 | bool destroy_singleton(factory_meta_info_t* method, void* data); 89 | 90 | protected: 91 | factory_meta_info_t* get_meta_info(PAF_OBJ_ID id); 92 | void* get_shared_ref(factory_meta_info_t* method); 93 | void* get_shared_object(factory_meta_info_t* method, void* p); 94 | void release_shared_object(factory_meta_info_t* method, void* data); 95 | 96 | std::mutex cs_; 97 | std::unordered_map> id_to_meta_{1024}; 98 | std::vector> holder_{1024}; 99 | std::atomic total_shared_count_{0}; 100 | // singleton managerment 101 | std::vector obj_order_{1024}; 102 | }; 103 | #pragma pack(pop) 104 | } // namespace PAF_NAMESPACE 105 | -------------------------------------------------------------------------------- /include/PAF/InterfaceDeclareStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PAFConfig.h" 3 | #include "TypeTraits.h" 4 | 5 | #define PAF_EXPAND_(...) __VA_ARGS__ 6 | #define PAF_MACRO_CONCAT_(A, B) A##B 7 | #define PAF_CONCAT(A, B) PAF_MACRO_CONCAT_(A, B) 8 | 9 | // clang-format off 10 | #define PAF_ARG_SEQ() 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 11 | #define PAF_ARG_PICK_N(_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1, N, ...) N 12 | #define PAF_ARG_SELECT_(...) PAF_EXPAND_(PAF_ARG_PICK_N( __VA_ARGS__)) 13 | #define PAF_ARG_SELECT(...) PAF_ARG_SELECT_(__VA_ARGS__, PAF_ARG_SEQ()) 14 | // clang-format on 15 | 16 | const auto t0 = PAF_ARG_SELECT(NONE); 17 | static_assert(t0 == 0, "Error 0"); 18 | const auto t1 = PAF_ARG_SELECT(NONE, 1); 19 | static_assert(t1 == 1, "Error 1"); 20 | const auto t2 = PAF_ARG_SELECT(NONE, 2, 3); 21 | static_assert(t2 == 1, "Error 2"); 22 | 23 | template 24 | struct PAF_ID_2_TYPE; 25 | template 26 | struct PAF_TYPE_2_ID; 27 | 28 | #define PAF_DECL_INTERFACE_0(FLAG, INC) \ 29 | template <> \ 30 | struct PAF_TYPE_2_ID \ 31 | { \ 32 | using type = INC; \ 33 | using args_type = PAF_NAMESPACE::detail::place_holder_t; \ 34 | enum : PAF_OBJ_ID \ 35 | { \ 36 | id = PAF_COMPILE_TIME_HASH(INC) \ 37 | }; \ 38 | enum : std::underlying_type_t \ 39 | { \ 40 | flag = FLAG \ 41 | }; \ 42 | }; \ 43 | template <> \ 44 | struct PAF_ID_2_TYPE::id> : public PAF_TYPE_2_ID \ 45 | { \ 46 | }; 47 | #define PAF_DECL_INTERFACE_1(FLAG, INC, ...) \ 48 | template <> \ 49 | struct PAF_TYPE_2_ID \ 50 | { \ 51 | using type = INC; \ 52 | using args_type = PAF_NAMESPACE::detail::typelist_t<__VA_ARGS__>; \ 53 | enum : PAF_OBJ_ID \ 54 | { \ 55 | id = PAF_COMPILE_TIME_HASH(INC) \ 56 | }; \ 57 | enum : std::underlying_type_t \ 58 | { \ 59 | flag = FLAG | PAF_NAMESPACE::create_with_args \ 60 | }; \ 61 | }; \ 62 | template <> \ 63 | struct PAF_ID_2_TYPE::id> : public PAF_TYPE_2_ID \ 64 | { \ 65 | }; 66 | 67 | // allowed only local 68 | #define PAF_DECL_INTERFACE_LOCAL_(...) \ 69 | PAF_EXPAND_(PAF_CONCAT(PAF_DECL_INTERFACE_, \ 70 | PAF_ARG_SELECT(__VA_ARGS__))(PAF_NAMESPACE::create_as_local, __VA_ARGS__)) 71 | 72 | // allowed only shared 73 | #define PAF_DECL_INTERFACE_SHARED_(...) \ 74 | PAF_EXPAND_(PAF_CONCAT(PAF_DECL_INTERFACE_, \ 75 | PAF_ARG_SELECT(__VA_ARGS__))(PAF_NAMESPACE::create_as_shared, __VA_ARGS__)) 76 | 77 | // allowed only singleton 78 | #define PAF_DECL_INTERFACE_SINGLETON_(...) \ 79 | PAF_EXPAND_(PAF_CONCAT(PAF_DECL_INTERFACE_, \ 80 | PAF_ARG_SELECT(__VA_ARGS__))(PAF_NAMESPACE::create_as_single, __VA_ARGS__)) 81 | 82 | // allowed only singleton 83 | #define PAF_DECL_INTERFACE_STATIC_(...) \ 84 | PAF_EXPAND_(PAF_CONCAT(PAF_DECL_INTERFACE_, \ 85 | PAF_ARG_SELECT(__VA_ARGS__))(PAF_NAMESPACE::create_as_static | \ 86 | PAF_NAMESPACE::create_as_single, \ 87 | __VA_ARGS__)) 88 | -------------------------------------------------------------------------------- /include/PAF/InterfaceRegisterStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PAFConfig.h" 3 | namespace PAF_NAMESPACE 4 | { 5 | using fn_create_t = void* (*)(void*); 6 | using fn_destroy_t = void (*)(void*); 7 | struct alignas(8) object_register_info_t 8 | { 9 | fn_create_t create_obj_; 10 | fn_destroy_t destroy_obj_; 11 | PAF_OBJ_ID obj_id_; 12 | uint32_t flag_; 13 | uint32_t count_; 14 | const char* name_; 15 | }; 16 | } // namespace PAF_NAMESPACE 17 | -------------------------------------------------------------------------------- /include/PAF/PAFConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CompileTimeHash.h" 3 | #define PAF_COMPILE_TIME_HASH(name) COMPILE_TIME_HASH(name) 4 | 5 | #define PAF_OBJ_ID uint64_t 6 | #if !defined(PAF_LINK_API) 7 | # define PAF_LINK_API 8 | #endif // !defined(PAF_LINK_API) 9 | 10 | #define PAF_NAMESPACE paf_namespace 11 | #define PAF_GET_GLOBAL_FACTORY paf_get_global_factory 12 | #define PAF_DESTROY_GLOBAL_FACTORY paf_destroy_global_factory 13 | #define PAF_ID_2_TYPE paf_id_2_type 14 | #define PAF_TYPE_2_ID paf_type_2_id 15 | #define PAF_GET_FACTORY PAF_NAMESPACE::PAF_GET_GLOBAL_FACTORY 16 | #include 17 | #define PAF_SHARED_PTR std::shared_ptr 18 | 19 | #if !defined(PAF_ASSERT) 20 | # define PAF_ASSERT assert 21 | #endif // !defined(PAF_ASSERT) 22 | 23 | -------------------------------------------------------------------------------- /include/PAF/PAFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PAFactoryInc.h" 3 | #include "InterfaceRegisterStruct.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace PAF_NAMESPACE 13 | { 14 | #pragma pack(push, 4) 15 | struct factory_meta_info_t : public object_register_info_t 16 | { 17 | factory_meta_info_t(const object_register_info_t& rhs) 18 | : object_register_info_t(rhs) {} 19 | 20 | ~factory_meta_info_t() 21 | { 22 | } 23 | 24 | bool exclusive() const 25 | { 26 | return 0 == (flag_ & (interface_flag::create_as_local)); 27 | } 28 | bool is_shared() const 29 | { 30 | return exclusive() && (flag_ & interface_flag::create_as_shared); 31 | } 32 | bool is_single() const 33 | { 34 | return exclusive() && (flag_ & interface_flag::create_as_single); 35 | } 36 | bool is_static() const 37 | { 38 | return exclusive() && (flag_ & interface_flag::create_as_static); 39 | } 40 | bool is_with_args() const 41 | { 42 | return 0 != (flag_ & interface_flag::create_with_args); 43 | } 44 | 45 | factory_meta_info_t(const factory_meta_info_t&) = delete; 46 | factory_meta_info_t& operator=(const factory_meta_info_t&) = delete; 47 | 48 | std::atomic data_{nullptr}; 49 | std::atomic ref_{0}; 50 | std::atomic_bool busy_{false}; 51 | }; 52 | 53 | class global_factory : public global_factory_i 54 | { 55 | using fn_shared_obj_destroy = void (*)(PAF_OBJ_ID id, void*); 56 | 57 | public: 58 | global_factory(); 59 | virtual ~global_factory(); 60 | PAF_DISABLE_COPY(global_factory) 61 | 62 | // local 63 | virtual void* create_local(PAF_OBJ_ID id, void* data = nullptr) override; 64 | virtual void destroy_local(PAF_OBJ_ID id, void* data) override; 65 | 66 | // shared 67 | virtual void* get_or_create_shared(PAF_OBJ_ID id, void* data = nullptr) override; 68 | virtual void* get_shared(PAF_OBJ_ID id, bool addref) override; 69 | virtual void destroy_shared(PAF_OBJ_ID id, void* data) override; 70 | 71 | // singleton 72 | virtual void* get_or_create_singleton(PAF_OBJ_ID id, void* data = nullptr) override; 73 | virtual void* get_singleton(PAF_OBJ_ID id) override; 74 | virtual bool destroy_singleton(PAF_OBJ_ID id, void* data) override; 75 | 76 | public: 77 | // return actual number of registered 78 | int register_global_object(object_register_info_t* arr, size_t count); 79 | bool try_unregister_object(PAF_OBJ_ID obj_id); 80 | void unregister_object(PAF_OBJ_ID obj_id); 81 | void release_all_global_objects(); 82 | bool destroy_singleton(factory_meta_info_t* method, void* data); 83 | 84 | protected: 85 | factory_meta_info_t* get_meta_info(PAF_OBJ_ID id); 86 | void* get_shared_ref(factory_meta_info_t* method); 87 | void* get_shared_object(factory_meta_info_t* method, void* p); 88 | void release_shared_object(factory_meta_info_t* method, void* data); 89 | 90 | std::mutex cs_; 91 | std::unordered_map> id_to_meta_{1024}; 92 | std::vector> holder_{1024}; 93 | std::atomic total_shared_count_{0}; 94 | // singleton managerment 95 | std::vector obj_order_{1024}; 96 | }; 97 | #pragma pack(pop) 98 | } // namespace PAF_NAMESPACE 99 | -------------------------------------------------------------------------------- /include/PAF/PAFactory.inl: -------------------------------------------------------------------------------- 1 | #include "NZBase.h" 2 | #include "PAFactory.h" 3 | #include 4 | #include 5 | 6 | namespace PAF_NAMESPACE 7 | { 8 | class paf_lock_t 9 | { 10 | public: 11 | paf_lock_t(std::atomic_bool& flag) 12 | : flag_(flag) 13 | { 14 | } 15 | ~paf_lock_t() = default; 16 | PAF_DISABLE_COPY(paf_lock_t); 17 | void lock() 18 | { 19 | size_t back_off = 0; 20 | while (flag_.exchange(true, std::memory_order::memory_order_acquire)) 21 | { 22 | wait_a_monment(back_off); 23 | } 24 | } 25 | void unlock() 26 | { 27 | flag_ = false; 28 | } 29 | static void wait_a_monment(size_t& back_off) 30 | { 31 | std::this_thread::yield(); 32 | } 33 | 34 | private: 35 | std::atomic_bool& flag_; 36 | static bool single_thread; 37 | }; 38 | bool paf_lock_t::single_thread = (1 == std::thread::hardware_concurrency()); 39 | 40 | global_factory& inner_get_global_factory() 41 | { 42 | static global_factory s_factory; 43 | return s_factory; 44 | } 45 | 46 | global_factory::global_factory() 47 | { 48 | } 49 | global_factory::~global_factory() 50 | { 51 | } 52 | 53 | void* global_factory::create_local(PAF_OBJ_ID id, void* data) 54 | { 55 | void* ret = nullptr; 56 | do 57 | { 58 | auto meta = get_meta_info(id); 59 | if (!meta) 60 | break; 61 | 62 | if (!meta->exclusive()) 63 | { 64 | if (meta->is_with_args() && !data) 65 | { 66 | PAF_ASSERT(!"must create_with_args"); 67 | break; 68 | } 69 | 70 | meta->count_ += 1; 71 | ret = meta->create_obj_(data); 72 | } 73 | else 74 | { 75 | PAF_ASSERT(!"create_as_local not allowed"); 76 | } 77 | } while (0); 78 | return ret; 79 | } 80 | 81 | void global_factory::destroy_local(PAF_OBJ_ID id, void* data) 82 | { 83 | PAF_ASSERT(data); 84 | auto meta = get_meta_info(id); 85 | if (!meta) 86 | return; 87 | meta->count_ -= 1; 88 | meta->destroy_obj_(data); 89 | } 90 | 91 | void global_factory::release_all_global_objects() 92 | { 93 | { 94 | std::lock_guard lk(cs_); 95 | std::vector tmp_order = std::move(obj_order_); 96 | for (auto& id : tmp_order) 97 | { 98 | if (id) 99 | { 100 | auto it = id_to_meta_.find(id); 101 | if (it != id_to_meta_.end()) 102 | { 103 | auto meta = it->second.get(); 104 | destroy_singleton(meta, meta->data_); 105 | } 106 | } 107 | } 108 | } 109 | } 110 | 111 | factory_meta_info_t* global_factory::get_meta_info(PAF_OBJ_ID id) 112 | { 113 | std::lock_guard lk(cs_); 114 | auto iter = id_to_meta_.find(id); 115 | if (iter == id_to_meta_.end()) 116 | { 117 | PAF_ASSERT(!"id not registered"); 118 | return nullptr; 119 | } 120 | return iter->second.get(); 121 | } 122 | 123 | void* global_factory::get_or_create_shared(PAF_OBJ_ID id, void* data) 124 | { 125 | void* ret = nullptr; 126 | do 127 | { 128 | auto meta = get_meta_info(id); 129 | if (!meta) 130 | break; 131 | if (meta->is_shared()) 132 | { 133 | if (meta->is_with_args() && !data) 134 | { 135 | PAF_ASSERT(!"must create_with_args"); 136 | break; 137 | } 138 | ret = get_shared_object(meta, data); 139 | } 140 | else 141 | { 142 | PAF_ASSERT(!"create_as_shared not allowed"); 143 | } 144 | } while (0); 145 | return ret; 146 | } 147 | 148 | void* global_factory::get_shared(PAF_OBJ_ID id, bool addref) 149 | { 150 | void* ret = nullptr; 151 | do 152 | { 153 | auto meta = get_meta_info(id); 154 | if (!meta) 155 | break; 156 | if (!meta->is_shared()) 157 | { 158 | PAF_ASSERT(!"create_as_shared not allowed"); 159 | break; 160 | } 161 | ret = meta->data_.load(std::memory_order::memory_order_relaxed); 162 | if (!addref) 163 | break; 164 | 165 | return get_shared_ref(meta); 166 | } while (0); 167 | return ret; 168 | } 169 | 170 | void global_factory::destroy_shared(PAF_OBJ_ID id, void* data) 171 | { 172 | auto meta = get_meta_info(id); 173 | if (!meta) 174 | return; 175 | release_shared_object(meta, data); 176 | } 177 | 178 | void* global_factory::get_shared_object(factory_meta_info_t* method, void* data) 179 | { 180 | PAF_ASSERT(method && (!method->is_with_args() || data)); 181 | if (!method->create_obj_) 182 | return nullptr; 183 | void* tmp = nullptr; 184 | const auto ref = method->ref_.fetch_add(1); 185 | PAF_ASSERT(ref >= 0); 186 | if (ref == 0) 187 | { 188 | tmp = method->data_.exchange(nullptr, std::memory_order::memory_order_acq_rel); 189 | if (!tmp) 190 | { 191 | // 没抢到销毁权,重新创建 192 | tmp = method->create_obj_(data); 193 | ++total_shared_count_; 194 | method->count_ += 1; 195 | } 196 | method->data_.store(tmp, std::memory_order::memory_order_release); 197 | method->busy_.store(false, std::memory_order::memory_order_release); 198 | } 199 | else 200 | { 201 | while (method->busy_.load(std::memory_order::memory_order_acquire)) 202 | { 203 | // 处理和release线程竞态 204 | } 205 | 206 | size_t count = 0; 207 | tmp = method->data_.load(std::memory_order::memory_order_acquire); 208 | while (!tmp) 209 | { 210 | paf_lock_t::wait_a_monment(count); 211 | tmp = method->data_.load(std::memory_order::memory_order_acquire); 212 | }; 213 | } 214 | return tmp; 215 | } 216 | 217 | void* global_factory::get_shared_ref(factory_meta_info_t* method) 218 | { 219 | PAF_ASSERT(method); 220 | void* tmp = nullptr; 221 | for (;;) 222 | { 223 | auto ref = method->ref_.load(std::memory_order::memory_order_relaxed); 224 | if (ref <= 0) 225 | { 226 | break; 227 | } 228 | else if (method->ref_.compare_exchange_strong(ref, ref + 1)) 229 | { 230 | while (method->busy_.load(std::memory_order::memory_order_acquire)) 231 | { 232 | // 处理和dec线程竞态 233 | } 234 | 235 | do 236 | { 237 | // 和创建线程的竞态 238 | tmp = method->data_.load(std::memory_order::memory_order_acquire); 239 | } while (!tmp); 240 | break; 241 | } 242 | } 243 | return tmp; 244 | } 245 | 246 | void global_factory::release_shared_object(factory_meta_info_t* method, void* data) 247 | { 248 | void* p = method->data_; 249 | PAF_ASSERT(p == data); 250 | method->busy_.store(true, std::memory_order::memory_order_acquire); 251 | const auto ref = method->ref_.fetch_sub(1); 252 | PAF_ASSERT(ref > 0); 253 | if (ref == 1) 254 | { 255 | // lock-free 256 | auto val = method->data_.exchange(nullptr, std::memory_order::memory_order_acq_rel); 257 | method->busy_.store(false, std::memory_order::memory_order_release); 258 | if (val) 259 | { 260 | method->destroy_obj_(val); 261 | --total_shared_count_; 262 | method->count_ -= 1; 263 | } 264 | } 265 | else 266 | method->busy_.store(false, std::memory_order::memory_order_release); 267 | } 268 | 269 | void* global_factory::get_or_create_singleton(PAF_OBJ_ID id, void* data) 270 | { 271 | void* ret = nullptr; 272 | do 273 | { 274 | auto meta = get_meta_info(id); 275 | if (!meta) 276 | break; 277 | 278 | if (!meta->is_single()) 279 | { 280 | PAF_ASSERT(!"create_as_single not allowed"); 281 | break; 282 | } 283 | 284 | if (meta->is_with_args() && !data) 285 | { 286 | PAF_ASSERT(!"must create_with_args"); 287 | break; 288 | } 289 | 290 | ret = meta->data_.load(std::memory_order::memory_order_acquire); 291 | if (ret == nullptr) 292 | { 293 | auto created = false; 294 | { 295 | paf_lock_t paf_lock(meta->busy_); 296 | std::lock_guard lk(paf_lock); 297 | ret = meta->data_.load(std::memory_order::memory_order_relaxed); 298 | if (ret == nullptr) 299 | { 300 | ret = meta->create_obj_(data); 301 | created = true; 302 | meta->data_.store(ret, std::memory_order::memory_order_release); 303 | } 304 | } 305 | if (created) 306 | { 307 | std::lock_guard lk(cs_); 308 | obj_order_.push_back(id); 309 | printf("singleton loaded %llu", id); 310 | ++total_shared_count_; 311 | } 312 | } 313 | } while (0); 314 | return ret; 315 | } 316 | 317 | void* global_factory::get_singleton(PAF_OBJ_ID id) 318 | { 319 | void* ret = nullptr; 320 | do 321 | { 322 | auto meta = get_meta_info(id); 323 | if (!meta) 324 | break; 325 | 326 | if (!meta->is_single()) 327 | { 328 | PAF_ASSERT(!"create_as_single not allowed"); 329 | break; 330 | } 331 | ret = meta->data_.load(std::memory_order::memory_order_relaxed); 332 | } while (0); 333 | return ret; 334 | } 335 | 336 | bool global_factory::destroy_singleton(PAF_OBJ_ID id, void* data) 337 | { 338 | bool ret = false; 339 | auto meta = get_meta_info(id); 340 | if (!meta) 341 | return ret; 342 | 343 | if (meta->is_static()) 344 | { 345 | assert(!"can't destroy static by user"); 346 | return ret; 347 | } 348 | 349 | ret = destroy_singleton(meta, data); 350 | if (ret) 351 | { 352 | std::lock_guard lk(cs_); 353 | for (auto iter = obj_order_.begin(); iter != obj_order_.end(); ++iter) 354 | { 355 | if (*iter == id) 356 | { 357 | *iter = 0; 358 | printf("singleton unloaded %llu", id); 359 | } 360 | } 361 | } 362 | return ret; 363 | } 364 | 365 | bool global_factory::destroy_singleton(factory_meta_info_t* meta, void* data) 366 | { 367 | bool ret = false; 368 | if (!meta->is_single()) 369 | return ret; 370 | if (data) 371 | { 372 | auto p = data; 373 | if (!meta->data_.compare_exchange_strong(p, nullptr)) 374 | { 375 | PAF_ASSERT(!"not found"); 376 | printf("singleton not found %llu", meta->obj_id_); 377 | } 378 | } 379 | else 380 | { 381 | data = meta->data_.exchange(nullptr, std::memory_order::memory_order_acq_rel); 382 | if (!data) 383 | { 384 | PAF_ASSERT(!"not found"); 385 | printf("singleton not found %llu", meta->obj_id_); 386 | } 387 | } 388 | 389 | if (data) 390 | { 391 | meta->destroy_obj_(data); 392 | printf("singleton destroyed %llu", meta->obj_id_); 393 | --total_shared_count_; 394 | ret = true; 395 | } 396 | return ret; 397 | } 398 | 399 | int global_factory::register_global_object(object_register_info_t* arr, size_t count) 400 | { 401 | int registered = 0; 402 | std::lock_guard lk(cs_); 403 | for (size_t i = 0; i < count; ++i) 404 | { 405 | auto a = std::make_unique(arr[i]); 406 | auto id = a->obj_id_; 407 | a->count_ = 0; 408 | PAF_ASSERT(a->create_obj_ && a->destroy_obj_ && " no construction"); 409 | if (id_to_meta_.find(id) == id_to_meta_.end()) 410 | { 411 | id_to_meta_[id] = std::move(a); 412 | ++registered; 413 | } 414 | else 415 | { 416 | PAF_ASSERT(!" id conflicts"); 417 | } 418 | } 419 | return registered; 420 | } 421 | bool global_factory::try_unregister_object(PAF_OBJ_ID obj_id) 422 | { 423 | std::lock_guard lk(cs_); 424 | auto it = id_to_meta_.find(obj_id); 425 | if (it != id_to_meta_.end()) 426 | { 427 | auto& a = it->second; 428 | PAF_ASSERT(!a->count_); 429 | if (!a->count_) 430 | { 431 | holder_.push_back(std::move(a)); 432 | id_to_meta_.erase(it); 433 | } 434 | else 435 | { 436 | return false; 437 | } 438 | } 439 | return true; 440 | } 441 | void global_factory::unregister_object(PAF_OBJ_ID obj_id) 442 | { 443 | if (!try_unregister_object(obj_id)) 444 | { 445 | PAF_ASSERT(0); 446 | } 447 | } 448 | 449 | namespace detail 450 | { 451 | extern "C" PAF_LINK_API void reg_object_info(PAF_NAMESPACE::object_register_info_t& info) 452 | { 453 | PAF_NAMESPACE::inner_get_global_factory().register_global_object(&info, 1); 454 | } 455 | } // namespace detail 456 | 457 | extern "C" PAF_LINK_API PAF_NAMESPACE::global_factory_i* PAF_GET_GLOBAL_FACTORY() 458 | { 459 | return &PAF_NAMESPACE::inner_get_global_factory(); 460 | } 461 | extern "C" PAF_LINK_API void PAF_DESTROY_GLOBAL_FACTORY() 462 | { 463 | PAF_NAMESPACE::inner_get_global_factory().release_all_global_objects(); 464 | } 465 | 466 | } // namespace PAF_NAMESPACE 467 | -------------------------------------------------------------------------------- /include/PAF/PAFactoryInc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PAFConfig.h" 3 | #include "InterfaceDeclareStruct.h" 4 | #define PAF_DISABLE_COPY(CLASS) \ 5 | CLASS(const CLASS&) = delete; \ 6 | CLASS& operator=(const CLASS&) = delete; 7 | #define PAF_DISABLE_MOVE(CLASS) \ 8 | CLASS(CLASS&&) = delete; \ 9 | CLASS& operator=(CLASS&&) = delete; 10 | 11 | 12 | #include 13 | #include 14 | 15 | namespace PAF_NAMESPACE 16 | { 17 | class global_factory_i 18 | { 19 | friend class factory_helper; 20 | // local 21 | virtual void* create_local(PAF_OBJ_ID id, void* data) = 0; 22 | virtual void destroy_local(PAF_OBJ_ID id, void* data) = 0; 23 | 24 | // shared 25 | virtual void* get_or_create_shared(PAF_OBJ_ID id, void* data) = 0; 26 | virtual void* get_shared(PAF_OBJ_ID id, bool addref) = 0; 27 | virtual void destroy_shared(PAF_OBJ_ID id, void* data) = 0; 28 | 29 | // singleton 30 | virtual void* get_or_create_singleton(PAF_OBJ_ID id, void* data) = 0; 31 | virtual void* get_singleton(PAF_OBJ_ID id) = 0; 32 | virtual bool destroy_singleton(PAF_OBJ_ID id, void* data) = 0; 33 | 34 | // global set/get 35 | //virtual void* set_global(PAF_OBJ_ID id) = 0; 36 | //virtual void* get_global(PAF_OBJ_ID id) = 0; 37 | }; 38 | 39 | extern "C" PAF_LINK_API global_factory_i* PAF_GET_GLOBAL_FACTORY(); 40 | extern "C" PAF_LINK_API void PAF_DESTROY_GLOBAL_FACTORY(); 41 | 42 | class factory_helper 43 | { 44 | public: 45 | // local 46 | template 47 | static PAF_SHARED_PTR create_local(Args&&... args) 48 | { 49 | static_assert( 50 | ((PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_with_args) && sizeof...(Args)) || 51 | (!(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_with_args) && 52 | !sizeof...(Args)), 53 | "construct args mismatch"); 54 | static_assert(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_local, 55 | "can't create as local"); 56 | auto inc = PAF_GET_GLOBAL_FACTORY(); 57 | if (!inc) 58 | return nullptr; 59 | typename PAF_TYPE_2_ID::args_type data{std::forward(args)...}; 60 | auto ret = (TYPE*)inc->create_local(PAF_TYPE_2_ID::id, &data); 61 | if (!ret) 62 | return nullptr; 63 | return PAF_SHARED_PTR(ret, [](void* data) { 64 | auto p = PAF_GET_GLOBAL_FACTORY(); 65 | if (p) 66 | p->destroy_local(PAF_TYPE_2_ID::id, data); 67 | }); 68 | } 69 | 70 | // shared 71 | template 72 | static PAF_SHARED_PTR get_shared(Args&&... args) 73 | { 74 | static_assert( 75 | ((PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_with_args) && sizeof...(Args)) || 76 | (!(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_with_args) && 77 | !sizeof...(Args)), 78 | "construct args mismatch"); 79 | static_assert(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_shared, 80 | "can't create as shared"); 81 | auto inc = PAF_GET_GLOBAL_FACTORY(); 82 | if (!inc) 83 | return nullptr; 84 | typename PAF_TYPE_2_ID::args_type data{std::forward(args)...}; 85 | auto ret = (TYPE*)inc->get_or_create_shared(PAF_TYPE_2_ID::id, &data); 86 | if (!ret) 87 | return nullptr; 88 | return PAF_SHARED_PTR(ret, [](void* data) { 89 | auto p = PAF_GET_GLOBAL_FACTORY(); 90 | if (p) 91 | p->destroy_shared(PAF_TYPE_2_ID::id, data); 92 | }); 93 | } 94 | template 95 | static PAF_SHARED_PTR get_shared_ref() 96 | { 97 | static_assert(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_shared, 98 | "can't get as shared"); 99 | auto inc = PAF_GET_GLOBAL_FACTORY(); 100 | if (!inc) 101 | return nullptr; 102 | auto ret = (TYPE*)inc->get_shared(PAF_TYPE_2_ID::id, true); 103 | if (!ret) 104 | return nullptr; 105 | return PAF_SHARED_PTR(ret, [](void* data) { 106 | auto p = PAF_GET_GLOBAL_FACTORY(); 107 | if (p) 108 | p->destroy_shared(PAF_TYPE_2_ID::id, data); 109 | }); 110 | } 111 | template 112 | static TYPE* get_shared2_raw() 113 | { 114 | static_assert(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_shared, 115 | "can't get as shared"); 116 | auto inc = PAF_GET_GLOBAL_FACTORY(); 117 | if (!inc) 118 | return nullptr; 119 | return (TYPE*)inc->get_shared(PAF_TYPE_2_ID::id, false); 120 | } 121 | 122 | // singleton 123 | template 124 | static TYPE* get_singleton(Args&&... args) 125 | { 126 | static_assert( 127 | ((PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_with_args) && sizeof...(Args)) || 128 | (!(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_with_args) && 129 | !sizeof...(Args)), 130 | "construct args mismatch"); 131 | static_assert(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_single, 132 | "can't get as singleton"); 133 | auto inc = PAF_GET_GLOBAL_FACTORY(); 134 | if (!inc) 135 | return nullptr; 136 | typename PAF_TYPE_2_ID::args_type data{std::forward(args)...}; 137 | return (TYPE*)inc->get_or_create_singleton(PAF_TYPE_2_ID::id, &data); 138 | } 139 | template 140 | static TYPE* get_singleton_ref() 141 | { 142 | static_assert(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_single, 143 | "can't get as singteton"); 144 | auto inc = PAF_GET_GLOBAL_FACTORY(); 145 | if (!inc) 146 | return nullptr; 147 | return (TYPE*)inc->get_singleton(PAF_TYPE_2_ID::id); 148 | } 149 | template 150 | static bool destroy_singleton() 151 | { 152 | static_assert(!(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_static), 153 | "can't destrory by user side"); 154 | static_assert(PAF_TYPE_2_ID::flag & PAF_NAMESPACE::create_as_single, 155 | "can't destrory as singteton"); 156 | auto inc = PAF_GET_GLOBAL_FACTORY(); 157 | if (!inc) 158 | return false; 159 | auto s = inc->get_singleton(PAF_TYPE_2_ID::id); 160 | return (TYPE*)inc->destroy_singleton(PAF_TYPE_2_ID::id, s); 161 | } 162 | }; 163 | 164 | } // namespace PAF_NAMESPACE 165 | -------------------------------------------------------------------------------- /include/PAF/TypeTraits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PAFConfig.h" 3 | #include 4 | namespace PAF_NAMESPACE 5 | { 6 | enum interface_flag : unsigned char 7 | { 8 | create_as_local = 0x01, 9 | create_as_shared = 0x02, 10 | create_as_single = 0x04, 11 | create_as_static = 0x08, // cannot destroy by user 12 | create_with_args = 0x10, // construct with args 13 | }; 14 | 15 | namespace detail 16 | { 17 | template 18 | constexpr decltype(auto) apply_impl(F& f, Tuple&& t, std::index_sequence) 19 | { 20 | return f(std::get(std::forward(t))...); 21 | } 22 | template 23 | constexpr decltype(auto) apply(F& f, Tuple&& t) 24 | { 25 | return apply_impl(f, 26 | std::forward(t), 27 | std::make_index_sequence::type>::value>{}); 28 | } 29 | template 30 | using forward_t = typename std::conditional::value || std::is_arithmetic::value, T, T&&>::type; 31 | template 32 | using typelist_t = std::tuple; 33 | 34 | struct place_holder_t 35 | { 36 | std::nullptr_t operator&() 37 | { 38 | return nullptr; 39 | } 40 | }; 41 | 42 | } // namespace detail 43 | } // namespace PAF_NAMESPACE 44 | --------------------------------------------------------------------------------