|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 #include <utility> // std::forward
|
|
|
4
|
|
|
5 typedef const void* service_class_ref;
|
|
|
6
|
|
|
7 PFC_DECLARE_EXCEPTION(exception_service_not_found,pfc::exception,"Service not found");
|
|
|
8 PFC_DECLARE_EXCEPTION(exception_service_extension_not_found,pfc::exception,"Service extension not found");
|
|
|
9 PFC_DECLARE_EXCEPTION(exception_service_duplicated,pfc::exception,"Service duplicated");
|
|
|
10
|
|
|
11 #ifdef _MSC_VER
|
|
|
12 #define FOOGUIDDECL __declspec(selectany)
|
|
|
13 #else
|
|
|
14 #define FOOGUIDDECL
|
|
|
15 #endif
|
|
|
16
|
|
|
17
|
|
|
18 #define DECLARE_GUID(NAME,A,S,D,F,G,H,J,K,L,Z,X) FOOGUIDDECL const GUID NAME = {A,S,D,{F,G,H,J,K,L,Z,X}};
|
|
|
19 #define DECLARE_CLASS_GUID(NAME,A,S,D,F,G,H,J,K,L,Z,X) FOOGUIDDECL const GUID NAME::class_guid = {A,S,D,{F,G,H,J,K,L,Z,X}};
|
|
|
20
|
|
|
21 //Must be templated instead of taking service_base* because of multiple inheritance issues.
|
|
|
22 template<typename T> static void service_release_safe(T * p_ptr) throw() {
|
|
|
23 if (p_ptr != NULL) PFC_ASSERT_NO_EXCEPTION( p_ptr->service_release() );
|
|
|
24 }
|
|
|
25
|
|
|
26 //Must be templated instead of taking service_base* because of multiple inheritance issues.
|
|
|
27 template<typename T> static void service_add_ref_safe(T * p_ptr) throw() {
|
|
|
28 if (p_ptr != NULL) PFC_ASSERT_NO_EXCEPTION( p_ptr->service_add_ref() );
|
|
|
29 }
|
|
|
30
|
|
|
31 class service_base;
|
|
|
32
|
|
|
33 template<typename T>
|
|
|
34 class service_ptr_base_t {
|
|
|
35 typedef service_ptr_base_t<T> self_t;
|
|
|
36 public:
|
|
|
37 inline T* get_ptr() const throw() {return m_ptr;}
|
|
|
38 typedef T obj_t;
|
|
|
39
|
|
|
40
|
|
|
41 inline bool operator==(const self_t & other) const noexcept {return this->m_ptr == other.m_ptr;}
|
|
|
42 inline bool operator!=(const self_t & other) const noexcept {return this->m_ptr != other.m_ptr;}
|
|
|
43
|
|
|
44 inline bool operator>(const self_t & other) const noexcept {return this->m_ptr > other.m_ptr;}
|
|
|
45 inline bool operator<(const self_t & other) const noexcept {return this->m_ptr < other.m_ptr;}
|
|
|
46
|
|
|
47 inline bool operator==(T * other) const noexcept {return this->m_ptr == other;}
|
|
|
48 inline bool operator!=(T * other) const noexcept {return this->m_ptr != other;}
|
|
|
49
|
|
|
50 inline bool operator>(T * other) const noexcept {return this->m_ptr > other;}
|
|
|
51 inline bool operator<(T * other) const noexcept {return this->m_ptr < other;}
|
|
|
52
|
|
|
53 protected:
|
|
|
54 T * m_ptr;
|
|
|
55 };
|
|
|
56
|
|
|
57 // forward declaration
|
|
|
58 template<typename T> class service_nnptr_t;
|
|
|
59
|
|
|
60 template<typename T> struct forced_cast_t {
|
|
|
61 T* ptr;
|
|
|
62 };
|
|
|
63
|
|
|
64 //! Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes.
|
|
|
65 template<typename T>
|
|
|
66 class service_ptr_t : public service_ptr_base_t<T> {
|
|
|
67 private:
|
|
|
68 typedef service_ptr_t<T> t_self;
|
|
|
69
|
|
|
70 template<typename t_source> void _init(t_source * in) throw() {
|
|
|
71 this->m_ptr = in;
|
|
|
72 if (this->m_ptr) this->m_ptr->service_add_ref();
|
|
|
73 }
|
|
|
74 template<typename t_source> void _init(t_source && in) throw() {
|
|
|
75 this->m_ptr = in.detach();
|
|
|
76 }
|
|
|
77 public:
|
|
|
78 service_ptr_t() throw() {this->m_ptr = NULL;}
|
|
|
79 service_ptr_t(T * p_ptr) throw() {_init(p_ptr);}
|
|
|
80 service_ptr_t(const t_self & p_source) throw() {_init(p_source.get_ptr());}
|
|
|
81 service_ptr_t(t_self && p_source) throw() {_init(std::move(p_source));}
|
|
|
82 template<typename t_source> service_ptr_t(t_source * p_ptr) throw() {_init(p_ptr);}
|
|
|
83 template<typename t_source> service_ptr_t(const service_ptr_base_t<t_source> & p_source) throw() {_init(p_source.get_ptr());}
|
|
|
84 template<typename t_source> service_ptr_t(const service_nnptr_t<t_source> & p_source) throw() { this->m_ptr = p_source.get_ptr(); this->m_ptr->service_add_ref(); }
|
|
|
85 template<typename t_source> service_ptr_t(service_ptr_t<t_source> && p_source) throw() { _init(std::move(p_source)); }
|
|
|
86
|
|
|
87 ~service_ptr_t() throw() {service_release_safe(this->m_ptr);}
|
|
|
88
|
|
|
89 template<typename t_source>
|
|
|
90 void copy(t_source * p_ptr) throw() {
|
|
|
91 service_add_ref_safe(p_ptr);
|
|
|
92 service_release_safe(this->m_ptr);
|
|
|
93 this->m_ptr = pfc::safe_ptr_cast<T>(p_ptr);
|
|
|
94 }
|
|
|
95
|
|
|
96 template<typename t_source>
|
|
|
97 void copy(const service_ptr_base_t<t_source> & p_source) throw() {copy(p_source.get_ptr());}
|
|
|
98
|
|
|
99 template<typename t_source>
|
|
|
100 void copy(service_ptr_t<t_source> && p_source) throw() {attach(p_source.detach());}
|
|
|
101
|
|
|
102
|
|
|
103 inline const t_self & operator=(const t_self & p_source) throw() {copy(p_source); return *this;}
|
|
|
104 inline const t_self & operator=(t_self && p_source) throw() {copy(std::move(p_source)); return *this;}
|
|
|
105 inline const t_self & operator=(T * p_ptr) throw() {copy(p_ptr); return *this;}
|
|
|
106
|
|
|
107 template<typename t_source> inline t_self & operator=(const service_ptr_base_t<t_source> & p_source) throw() {copy(p_source); return *this;}
|
|
|
108 template<typename t_source> inline t_self & operator=(service_ptr_t<t_source> && p_source) throw() {copy(std::move(p_source)); return *this;}
|
|
|
109 template<typename t_source> inline t_self & operator=(t_source * p_ptr) throw() {copy(p_ptr); return *this;}
|
|
|
110
|
|
|
111 template<typename t_source> inline t_self & operator=(const service_nnptr_t<t_source> & p_ptr) throw() {
|
|
|
112 service_release_safe(this->m_ptr);
|
|
|
113 t_source * ptr = p_ptr.get_ptr();
|
|
|
114 ptr->service_add_ref();
|
|
|
115 this->m_ptr = ptr;
|
|
|
116 return *this;
|
|
|
117 }
|
|
|
118
|
|
|
119 inline void reset() throw() { release(); }
|
|
|
120
|
|
|
121 inline void release() throw() {
|
|
|
122 service_release_safe(this->m_ptr);
|
|
|
123 this->m_ptr = NULL;
|
|
|
124 }
|
|
|
125
|
|
|
126
|
|
|
127 inline T* operator->() const throw() {
|
|
|
128 #if PFC_DEBUG
|
|
|
129 if (this->m_ptr == NULL) {
|
|
|
130 FB2K_DebugLog() << "service_ptr operator-> on a null pointer, type: " << T::debugServiceName();
|
|
|
131 uBugCheck();
|
|
|
132 }
|
|
|
133 #endif
|
|
|
134 return this->m_ptr;
|
|
|
135 }
|
|
|
136
|
|
|
137 inline T* get_ptr() const throw() {return this->m_ptr;}
|
|
|
138
|
|
|
139 inline bool is_valid() const throw() {return this->m_ptr != NULL;}
|
|
|
140 inline bool is_empty() const throw() {return this->m_ptr == NULL;}
|
|
|
141
|
|
|
142 template<typename t_other>
|
|
|
143 inline t_self & operator<<(service_ptr_t<t_other> & p_source) throw() {attach(p_source.detach());return *this;}
|
|
|
144 template<typename t_other>
|
|
|
145 inline t_self & operator>>(service_ptr_t<t_other> & p_dest) throw() {p_dest.attach(detach());return *this;}
|
|
|
146
|
|
|
147
|
|
|
148 inline T* _duplicate_ptr() const throw() {//should not be used ! temporary !
|
|
|
149 service_add_ref_safe(this->m_ptr);
|
|
|
150 return this->m_ptr;
|
|
|
151 }
|
|
|
152
|
|
|
153 inline T* detach() throw() {
|
|
|
154 return pfc::replace_null_t(this->m_ptr);
|
|
|
155 }
|
|
|
156
|
|
|
157 template<typename t_source>
|
|
|
158 inline void attach(t_source * p_ptr) throw() {
|
|
|
159 service_release_safe(this->m_ptr);
|
|
|
160 this->m_ptr = pfc::safe_ptr_cast<T>(p_ptr);
|
|
|
161 }
|
|
|
162
|
|
|
163 T & operator*() const throw() {return *this->m_ptr;}
|
|
|
164
|
|
|
165 service_ptr_t<service_base> & _as_base_ptr() {
|
|
|
166 PFC_ASSERT( _as_base_ptr_check() );
|
|
|
167 return *reinterpret_cast<service_ptr_t<service_base>*>(this);
|
|
|
168 }
|
|
|
169 static bool _as_base_ptr_check() {
|
|
|
170 return static_cast<service_base*>((T*)NULL) == reinterpret_cast<service_base*>((T*)NULL);
|
|
|
171 }
|
|
|
172
|
|
|
173 //! Forced cast operator - obtains a valid service pointer to the expected class or crashes the app if such pointer cannot be obtained.
|
|
|
174 template<typename otherPtr_t>
|
|
|
175 void operator ^= ( otherPtr_t other ) {
|
|
|
176 if (other.is_empty()) release();
|
|
|
177 else forcedCastFrom(other);
|
|
|
178 }
|
|
|
179 template<typename otherObj_t>
|
|
|
180 void operator ^= ( otherObj_t * other ) {
|
|
|
181 if (other == nullptr) release();
|
|
|
182 else forcedCastFrom( other );
|
|
|
183 }
|
|
|
184
|
|
|
185 bool testForInterface(const GUID & guid) const {
|
|
|
186 if (this->m_ptr == nullptr) return false;
|
|
|
187 service_ptr_t<service_base> dummy;
|
|
|
188 return this->m_ptr->service_query(dummy, guid);
|
|
|
189 }
|
|
|
190 //! Conditional cast operator - attempts to obtain a vaild service pointer to the expected class; returns true on success, false on failure.
|
|
|
191 template<typename otherPtr_t>
|
|
|
192 bool operator &= ( otherPtr_t other ) {
|
|
|
193 if (other.is_empty()) return false;
|
|
|
194 return other->cast(*this);
|
|
|
195 }
|
|
|
196 template<typename otherObj_t>
|
|
|
197 bool operator &= ( otherObj_t * other ) {
|
|
|
198 if (other == nullptr) return false;
|
|
|
199 return other->cast( *this );
|
|
|
200 }
|
|
|
201
|
|
|
202 template<typename otherPtr_t>
|
|
|
203 void operator=(forced_cast_t<otherPtr_t> other) {
|
|
|
204 if (other.ptr == NULL) release();
|
|
|
205 else forcedCastFrom(other.ptr);
|
|
|
206 }
|
|
|
207
|
|
|
208 //! Alternate forcedCast syntax, for contexts where operator^= fails to compile. \n
|
|
|
209 //! Usage: target = source.forcedCast();
|
|
|
210 forced_cast_t<T> forcedCast() const {
|
|
|
211 forced_cast_t<T> r = { this->m_ptr };
|
|
|
212 return r;
|
|
|
213 }
|
|
|
214
|
|
|
215 template<typename source_t>
|
|
|
216 void forcedCastFrom(source_t const & other) {
|
|
|
217 if (!other->cast(*this)) {
|
|
|
218 FB2K_BugCheckEx("forced cast failure");
|
|
|
219 }
|
|
|
220 }
|
|
|
221 };
|
|
|
222
|
|
|
223 //! Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes. \n
|
|
|
224 //! This assumes that the pointers are valid all the time (can't point to null). Mainly intended to be used for scenarios where null pointers are not valid and relevant code should crash ASAP if somebody passes invalid pointers around. \n
|
|
|
225 //! You want to use service_ptr_t<> rather than service_nnptr_t<> most of the time.
|
|
|
226 template<typename T>
|
|
|
227 class service_nnptr_t : public service_ptr_base_t<T> {
|
|
|
228 private:
|
|
|
229 typedef service_nnptr_t<T> t_self;
|
|
|
230
|
|
|
231 template<typename t_source> void _init(t_source * in) {
|
|
|
232 this->m_ptr = in;
|
|
|
233 this->m_ptr->service_add_ref();
|
|
|
234 }
|
|
|
235 service_nnptr_t() throw() {pfc::crash();}
|
|
|
236 public:
|
|
|
237 service_nnptr_t(T * p_ptr) throw() {_init(p_ptr);}
|
|
|
238 service_nnptr_t(const t_self & p_source) throw() {_init(p_source.get_ptr());}
|
|
|
239 template<typename t_source> service_nnptr_t(t_source * p_ptr) throw() {_init(p_ptr);}
|
|
|
240 template<typename t_source> service_nnptr_t(const service_ptr_base_t<t_source> & p_source) throw() {_init(p_source.get_ptr());}
|
|
|
241
|
|
|
242 template<typename t_source> service_nnptr_t(service_ptr_t<t_source> && p_source) throw() {this->m_ptr = p_source.detach();}
|
|
|
243
|
|
|
244 ~service_nnptr_t() throw() {this->m_ptr->service_release();}
|
|
|
245
|
|
|
246 template<typename t_source>
|
|
|
247 void copy(t_source * p_ptr) throw() {
|
|
|
248 p_ptr->service_add_ref();
|
|
|
249 this->m_ptr->service_release();
|
|
|
250 this->m_ptr = pfc::safe_ptr_cast<T>(p_ptr);
|
|
|
251 }
|
|
|
252
|
|
|
253 template<typename t_source>
|
|
|
254 void copy(const service_ptr_base_t<t_source> & p_source) throw() {copy(p_source.get_ptr());}
|
|
|
255
|
|
|
256
|
|
|
257 inline const t_self & operator=(const t_self & p_source) throw() {copy(p_source); return *this;}
|
|
|
258 inline const t_self & operator=(T * p_ptr) throw() {copy(p_ptr); return *this;}
|
|
|
259
|
|
|
260 template<typename t_source> inline t_self & operator=(const service_ptr_base_t<t_source> & p_source) throw() {copy(p_source); return *this;}
|
|
|
261 template<typename t_source> inline t_self & operator=(t_source * p_ptr) throw() {copy(p_ptr); return *this;}
|
|
|
262 template<typename t_source> inline t_self & operator=(service_ptr_t<t_source> && p_source) throw() {this->m_ptr->service_release(); this->m_ptr = p_source.detach();}
|
|
|
263
|
|
|
264
|
|
|
265 inline T* operator->() const throw() {PFC_ASSERT(this->m_ptr != NULL);return this->m_ptr;}
|
|
|
266
|
|
|
267 inline T* get_ptr() const throw() {return this->m_ptr;}
|
|
|
268
|
|
|
269 inline bool is_valid() const throw() {return true;}
|
|
|
270 inline bool is_empty() const throw() {return false;}
|
|
|
271
|
|
|
272 inline T* _duplicate_ptr() const throw() {//should not be used ! temporary !
|
|
|
273 service_add_ref_safe(this->m_ptr);
|
|
|
274 return this->m_ptr;
|
|
|
275 }
|
|
|
276
|
|
|
277 T & operator*() const throw() {return *this->m_ptr;}
|
|
|
278
|
|
|
279 service_ptr_t<service_base> & _as_base_ptr() {
|
|
|
280 PFC_ASSERT( _as_base_ptr_check() );
|
|
|
281 return *reinterpret_cast<service_ptr_t<service_base>*>(this);
|
|
|
282 }
|
|
|
283 static bool _as_base_ptr_check() {
|
|
|
284 return static_cast<service_base*>((T*)NULL) == reinterpret_cast<service_base*>((T*)NULL);
|
|
|
285 }
|
|
|
286
|
|
|
287 forced_cast_t<T> forcedCast() const {
|
|
|
288 forced_cast_t<T> r = { this->m_ptr };
|
|
|
289 return r;
|
|
|
290 }
|
|
|
291 };
|
|
|
292
|
|
|
293 namespace pfc {
|
|
|
294 class traits_service_ptr : public traits_default {
|
|
|
295 public:
|
|
|
296 enum { realloc_safe = true, constructor_may_fail = false};
|
|
|
297 };
|
|
|
298
|
|
|
299 template<typename T> class traits_t<service_ptr_t<T> > : public traits_service_ptr {};
|
|
|
300 template<typename T> class traits_t<service_nnptr_t<T> > : public traits_service_ptr {};
|
|
|
301 }
|
|
|
302
|
|
|
303
|
|
|
304 //! For internal use, see FB2K_MAKE_SERVICE_INTERFACE
|
|
|
305 #define FB2K_MAKE_SERVICE_INTERFACE_EX(THISCLASS,PARENTCLASS,IS_CORE_API) \
|
|
|
306 public: \
|
|
|
307 typedef THISCLASS t_interface; \
|
|
|
308 typedef PARENTCLASS t_interface_parent; \
|
|
|
309 \
|
|
|
310 static const GUID class_guid; \
|
|
|
311 \
|
|
|
312 typedef service_ptr_t<t_interface> ptr; \
|
|
|
313 typedef service_nnptr_t<t_interface> nnptr; \
|
|
|
314 typedef ptr ref; \
|
|
|
315 typedef nnptr nnref; \
|
|
|
316 static const char * debugServiceName() { return #THISCLASS; } \
|
|
|
317 enum { _is_core_api = IS_CORE_API }; \
|
|
|
318 protected: \
|
|
|
319 THISCLASS() {} \
|
|
|
320 ~THISCLASS() {} \
|
|
|
321 private: \
|
|
|
322 const THISCLASS & operator=(const THISCLASS &) = delete; \
|
|
|
323 THISCLASS(const THISCLASS &) = delete; \
|
|
|
324 private: \
|
|
|
325 void _private_service_declaration_selftest() { \
|
|
|
326 static_assert( pfc::is_same_type<PARENTCLASS,PARENTCLASS::t_interface>::value, "t_interface sanity" ); \
|
|
|
327 static_assert( ! pfc::is_same_type<PARENTCLASS, THISCLASS>::value, "parent class sanity"); \
|
|
|
328 static_assert( pfc::is_same_type<PARENTCLASS, service_base>::value || IS_CORE_API == PARENTCLASS::_is_core_api, "is_core_api sanity" ); \
|
|
|
329 _validate_service_class_helper<THISCLASS>(); /*service_base must be reachable by walking t_interface_parent*/ \
|
|
|
330 pfc::implicit_cast<service_base*>(this); /*this class must derive from service_base, directly or indirectly, and be implictly castable to it*/ \
|
|
|
331 }
|
|
|
332
|
|
|
333 #define FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT_EX(THISCLASS, IS_CORE_API) \
|
|
|
334 public: \
|
|
|
335 typedef THISCLASS t_interface_entrypoint; \
|
|
|
336 static service_enum_t<THISCLASS> enumerate() { return service_enum_t<THISCLASS>(); } \
|
|
|
337 FB2K_MAKE_SERVICE_INTERFACE_EX(THISCLASS,service_base, IS_CORE_API)
|
|
|
338
|
|
|
339 //! Helper macro for use when defining a service class. Generates standard features of a service, without ability to register using service_factory / enumerate using service_enum_t. \n
|
|
|
340 //! This is used for declaring services that are meant to be instantiated by means other than service_enum_t (or non-entrypoint services), or extensions of services (including extension of entrypoint services). \n
|
|
|
341 //! Sample non-entrypoint declaration: class myclass : public service_base {...; FB2K_MAKE_SERVICE_INTERFACE(myclass, service_base); }; \n
|
|
|
342 //! Sample extension declaration: class myclass : public myotherclass {...; FB2K_MAKE_SERVICE_INTERFACE(myclass, myotherclass); }; \n
|
|
|
343 //! This macro is intended for use ONLY WITH INTERFACE CLASSES, not with implementation classes.
|
|
|
344 #define FB2K_MAKE_SERVICE_INTERFACE(THISCLASS, PARENTCLASS) FB2K_MAKE_SERVICE_INTERFACE_EX(THISCLASS, PARENTCLASS, false)
|
|
|
345
|
|
|
346 //! Helper macro for use when defining an entrypoint service class. Generates standard features of a service, including ability to register using service_factory and enumerate using service_enum. \n
|
|
|
347 //! Sample declaration: class myclass : public service_base {...; FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(myclass); }; \n
|
|
|
348 //! Note that entrypoint service classes must directly derive from service_base, and not from another service class.
|
|
|
349 //! This macro is intended for use ONLY WITH INTERFACE CLASSES, not with implementation classes.
|
|
|
350 #define FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(THISCLASS) FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT_EX(THISCLASS, false)
|
|
|
351
|
|
|
352
|
|
|
353 #define FB2K_MAKE_SERVICE_COREAPI(THISCLASS) \
|
|
|
354 FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT_EX( THISCLASS, true ) \
|
|
|
355 public: \
|
|
|
356 static ptr get() { return fb2k::std_api_get<THISCLASS>(); } \
|
|
|
357 static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } \
|
|
|
358 static ptr tryGet() { ptr ret; tryGet(ret); return ret; }
|
|
|
359
|
|
|
360 #define FB2K_MAKE_SERVICE_COREAPI_EXTENSION(THISCLASS, BASECLASS) \
|
|
|
361 FB2K_MAKE_SERVICE_INTERFACE_EX( THISCLASS, BASECLASS, true ) \
|
|
|
362 public: \
|
|
|
363 static ptr get() { return fb2k::std_api_get<THISCLASS>(); } \
|
|
|
364 static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } \
|
|
|
365 static ptr tryGet() { ptr ret; tryGet(ret); return ret; }
|
|
|
366
|
|
|
367
|
|
|
368
|
|
|
369 //! Alternate way of declaring services, begin/end macros wrapping the whole class declaration
|
|
|
370 #define FB2K_DECLARE_SERVICE_BEGIN(THISCLASS,BASECLASS) \
|
|
|
371 class NOVTABLE THISCLASS : public BASECLASS { \
|
|
|
372 FB2K_MAKE_SERVICE_INTERFACE(THISCLASS,BASECLASS); \
|
|
|
373 public:
|
|
|
374
|
|
|
375 //! Alternate way of declaring services, begin/end macros wrapping the whole class declaration
|
|
|
376 #define FB2K_DECLARE_SERVICE_END() \
|
|
|
377 };
|
|
|
378
|
|
|
379 //! Alternate way of declaring services, begin/end macros wrapping the whole class declaration
|
|
|
380 #define FB2K_DECLARE_SERVICE_ENTRYPOINT_BEGIN(THISCLASS) \
|
|
|
381 class NOVTABLE THISCLASS : public service_base { \
|
|
|
382 FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(THISCLASS) \
|
|
|
383 public:
|
|
|
384
|
|
|
385 class service_base;
|
|
|
386 typedef service_ptr_t<service_base> service_ptr;
|
|
|
387 typedef service_nnptr_t<service_base> service_nnptr;
|
|
|
388
|
|
|
389 //! Base class for all service classes.\n
|
|
|
390 //! Provides interfaces for reference counter and querying for different interfaces supported by the object.\n
|
|
|
391 class NOVTABLE service_base
|
|
|
392 {
|
|
|
393 public:
|
|
|
394 //! Decrements reference count; deletes the object if reference count reaches zero. This is normally not called directly but managed by service_ptr_t<> template. \n
|
|
|
395 //! Implemented by service_impl_* classes.
|
|
|
396 //! @returns New reference count. For debug purposes only, in certain conditions return values may be unreliable.
|
|
|
397 virtual int service_release() noexcept = 0;
|
|
|
398 //! Increments reference count. This is normally not called directly but managed by service_ptr_t<> template. \n
|
|
|
399 //! Implemented by service_impl_* classes.
|
|
|
400 //! @returns New reference count. For debug purposes only, in certain conditions return values may be unreliable.
|
|
|
401 virtual int service_add_ref() noexcept = 0;
|
|
|
402 //! Queries whether the object supports specific interface and retrieves a pointer to that interface. This is normally not called directly but managed by service_query_t<> function template. \n
|
|
|
403 //! Checks the parameter against GUIDs of interfaces supported by this object, if the GUID is one of supported interfaces, p_out is set to service_base pointer that can be static_cast<>'ed to queried interface and the method returns true; otherwise the method returns false. \n
|
|
|
404 //! Implemented by service_impl_* classes. \n
|
|
|
405 //! Note that service_query() implementation semantics (but not usage semantics) changed in SDK for foobar2000 1.4; they used to be auto-implemented by each service interface (via FB2K_MAKE_SERVICE_INTERFACE macro); they're now implemented in service_impl_* instead. See SDK readme for more details. \n
|
|
|
406 virtual bool service_query(service_ptr & p_out,const GUID & p_guid) = 0;
|
|
|
407
|
|
|
408 //! Queries whether the object supports specific interface and retrieves a pointer to that interface.
|
|
|
409 //! @param p_out Receives pointer to queried interface on success.
|
|
|
410 //! returns true on success, false on failure (interface not supported by the object).
|
|
|
411 template<class T>
|
|
|
412 bool service_query_t(service_ptr_t<T> & p_out)
|
|
|
413 {
|
|
|
414 pfc::assert_same_type<T,typename T::t_interface>();
|
|
|
415 return service_query( *reinterpret_cast<service_ptr_t<service_base>*>(&p_out),T::class_guid);
|
|
|
416 }
|
|
|
417 //! New shortened version, same as service_query_t.
|
|
|
418 template<typename outPtr_t>
|
|
|
419 bool cast( outPtr_t & outPtr ) { return service_query_t( outPtr ); }
|
|
|
420
|
|
|
421 typedef service_base t_interface;
|
|
|
422 enum { _is_core_api = false };
|
|
|
423
|
|
|
424 static const char * debugServiceName() {return "service_base"; }
|
|
|
425
|
|
|
426 static bool serviceRequiresMainThreadDestructor() { return false; }
|
|
|
427
|
|
|
428 service_base * as_service_base() { return this; }
|
|
|
429 protected:
|
|
|
430 service_base() {}
|
|
|
431 ~service_base() {}
|
|
|
432
|
|
|
433 static bool service_query_walk(service_ptr &, const GUID &, service_base *) {
|
|
|
434 return false;
|
|
|
435 }
|
|
|
436
|
|
|
437 template<typename interface_t> static bool service_query_walk(service_ptr & out, const GUID & guid, interface_t * in) {
|
|
|
438 if (guid == interface_t::class_guid) {
|
|
|
439 out = in; return true;
|
|
|
440 }
|
|
|
441 typename interface_t::t_interface_parent * chain = in;
|
|
|
442 return service_query_walk(out, guid, chain);
|
|
|
443 }
|
|
|
444 template<typename class_t> static bool handle_service_query(service_ptr & out, const GUID & guid, class_t * in) {
|
|
|
445 typename class_t::t_interface * in2 = in;
|
|
|
446 return service_query_walk( out, guid, in2 );
|
|
|
447 }
|
|
|
448 private:
|
|
|
449 service_base(const service_base&) = delete;
|
|
|
450 const service_base & operator=(const service_base&) = delete;
|
|
|
451 };
|
|
|
452
|
|
|
453 template<typename T>
|
|
|
454 inline void _validate_service_class_helper() {
|
|
|
455 _validate_service_class_helper<typename T::t_interface_parent>();
|
|
|
456 }
|
|
|
457
|
|
|
458 template<>
|
|
|
459 inline void _validate_service_class_helper<service_base>() {}
|
|
|
460
|
|
|
461
|
|
|
462 #include "service_impl.h"
|
|
|
463
|
|
|
464 class NOVTABLE service_factory_base {
|
|
|
465 protected:
|
|
|
466 inline service_factory_base(const GUID & p_guid, service_factory_base * & factoryList = __internal__list) : m_guid(p_guid) { PFC_ASSERT(!core_api::are_services_available()); __internal__next = factoryList; factoryList = this; }
|
|
|
467 public:
|
|
|
468 inline const GUID & get_class_guid() const {return m_guid;}
|
|
|
469
|
|
|
470 static service_class_ref enum_find_class(const GUID & p_guid);
|
|
|
471 static bool enum_create(service_ptr_t<service_base> & p_out,service_class_ref p_class,t_size p_index);
|
|
|
472 static t_size enum_get_count(service_class_ref p_class);
|
|
|
473
|
|
|
474 inline static bool is_service_present(const GUID & g) {return enum_get_count(enum_find_class(g))>0;}
|
|
|
475
|
|
|
476 //! Throws std::bad_alloc or another exception on failure.
|
|
|
477 virtual void instance_create(service_ptr_t<service_base> & p_out) = 0;
|
|
|
478
|
|
|
479 //! FOR INTERNAL USE ONLY
|
|
|
480 static service_factory_base *__internal__list;
|
|
|
481 //! FOR INTERNAL USE ONLY
|
|
|
482 service_factory_base * __internal__next;
|
|
|
483 private:
|
|
|
484 const GUID & m_guid;
|
|
|
485 };
|
|
|
486
|
|
|
487 template<typename B>
|
|
|
488 class service_factory_traits {
|
|
|
489 public:
|
|
|
490 static service_factory_base * & factory_list() {return service_factory_base::__internal__list;}
|
|
|
491 };
|
|
|
492
|
|
|
493 template<typename B>
|
|
|
494 class service_factory_base_t : public service_factory_base {
|
|
|
495 public:
|
|
|
496 service_factory_base_t() : service_factory_base(B::class_guid, service_factory_traits<B>::factory_list()) {
|
|
|
497 pfc::assert_same_type<B,typename B::t_interface_entrypoint>();
|
|
|
498 }
|
|
|
499 protected:
|
|
|
500 template<typename in_t>
|
|
|
501 static void pass_instance(service_ptr& out, in_t* in) {
|
|
|
502 // in_t could be multi inherited, fix multi inheritance issues here
|
|
|
503 // caller will static cast the returned service_base* to B* later on
|
|
|
504 // make sure that what we hand over supports such
|
|
|
505 service_ptr_t< B > temp;
|
|
|
506 temp ^= in->as_service_base();
|
|
|
507 out.attach(temp.detach());
|
|
|
508 }
|
|
|
509 };
|
|
|
510
|
|
|
511 template<typename T> static void _validate_service_ptr(service_ptr_t<T> const & ptr) {
|
|
|
512 PFC_ASSERT( ptr.is_valid() );
|
|
|
513 service_ptr_t<T> test;
|
|
|
514 PFC_ASSERT( ptr->service_query_t(test) );
|
|
|
515 }
|
|
|
516
|
|
|
517 #ifdef _DEBUG
|
|
|
518 #define FB2K_ASSERT_VALID_SERVICE_PTR(ptr) _validate_service_ptr(ptr)
|
|
|
519 #else
|
|
|
520 #define FB2K_ASSERT_VALID_SERVICE_PTR(ptr)
|
|
|
521 #endif
|
|
|
522
|
|
|
523 template<class T> static bool service_enum_create_t(service_ptr_t<T> & p_out,t_size p_index) {
|
|
|
524 pfc::assert_same_type<T,typename T::t_interface_entrypoint>();
|
|
|
525 service_ptr_t<service_base> ptr;
|
|
|
526 if (service_factory_base::enum_create(ptr,service_factory_base::enum_find_class(T::class_guid),p_index)) {
|
|
|
527 p_out = static_cast<T*>(ptr.get_ptr());
|
|
|
528 return true;
|
|
|
529 } else {
|
|
|
530 p_out.release();
|
|
|
531 return false;
|
|
|
532 }
|
|
|
533 }
|
|
|
534
|
|
|
535 template<typename T> static service_class_ref _service_find_class() {
|
|
|
536 pfc::assert_same_type<T,typename T::t_interface_entrypoint>();
|
|
|
537 return service_factory_base::enum_find_class(T::class_guid);
|
|
|
538 }
|
|
|
539
|
|
|
540 template<typename what>
|
|
|
541 static bool _service_instantiate_helper(service_ptr_t<what> & out, service_class_ref servClass, t_size index) {
|
|
|
542 /*if (out._as_base_ptr_check()) {
|
|
|
543 const bool state = service_factory_base::enum_create(out._as_base_ptr(), servClass, index);
|
|
|
544 if (state) { FB2K_ASSERT_VALID_SERVICE_PTR(out); }
|
|
|
545 return state;
|
|
|
546 } else */{
|
|
|
547 service_ptr temp;
|
|
|
548 const bool state = service_factory_base::enum_create(temp, servClass, index);
|
|
|
549 if (state) {
|
|
|
550 out.attach( static_cast<what*>( temp.detach() ) );
|
|
|
551 FB2K_ASSERT_VALID_SERVICE_PTR( out );
|
|
|
552 }
|
|
|
553 return state;
|
|
|
554 }
|
|
|
555 }
|
|
|
556
|
|
|
557 template<typename T> class service_class_helper_t {
|
|
|
558 public:
|
|
|
559 service_class_helper_t() : m_class(service_factory_base::enum_find_class(T::class_guid)) {
|
|
|
560 pfc::assert_same_type<T,typename T::t_interface_entrypoint>();
|
|
|
561 }
|
|
|
562 t_size get_count() const {
|
|
|
563 return service_factory_base::enum_get_count(m_class);
|
|
|
564 }
|
|
|
565
|
|
|
566 bool create(service_ptr_t<T> & p_out,t_size p_index) const {
|
|
|
567 return _service_instantiate_helper(p_out, m_class, p_index);
|
|
|
568 }
|
|
|
569
|
|
|
570 service_ptr_t<T> create(t_size p_index) const {
|
|
|
571 service_ptr_t<T> temp;
|
|
|
572 if (!create(temp,p_index)) uBugCheck();
|
|
|
573 return temp;
|
|
|
574 }
|
|
|
575 service_class_ref get_class() const {return m_class;}
|
|
|
576 private:
|
|
|
577 service_class_ref m_class;
|
|
|
578 };
|
|
|
579
|
|
|
580 void _standard_api_create_internal(service_ptr & out, const GUID & classID);
|
|
|
581 void _standard_api_get_internal(service_ptr & out, const GUID & classID);
|
|
|
582 bool _standard_api_try_get_internal(service_ptr & out, const GUID & classID);
|
|
|
583
|
|
|
584 template<typename T> inline void standard_api_create_t(service_ptr_t<T> & p_out) {
|
|
|
585 if constexpr (pfc::is_same_type<T,typename T::t_interface_entrypoint>::value) {
|
|
|
586 _standard_api_create_internal(p_out._as_base_ptr(), T::class_guid);
|
|
|
587 FB2K_ASSERT_VALID_SERVICE_PTR(p_out);
|
|
|
588 } else {
|
|
|
589 service_ptr_t<typename T::t_interface_entrypoint> temp;
|
|
|
590 standard_api_create_t(temp);
|
|
|
591 if (!temp->service_query_t(p_out)) {
|
|
|
592 #if PFC_DEBUG
|
|
|
593 FB2K_DebugLog() << "Service extension not found: " << T::debugServiceName() << " (" << pfc::print_guid(T::class_guid) << ") of base type: " << T::t_interface_entrypoint::debugServiceName() << " (" << pfc::print_guid(T::t_interface_entrypoint::class_guid) << ")";
|
|
|
594 #endif
|
|
|
595 throw exception_service_extension_not_found();
|
|
|
596 }
|
|
|
597 }
|
|
|
598 }
|
|
|
599
|
|
|
600 template<typename T> inline void standard_api_create_t(T* & p_out) {
|
|
|
601 p_out = NULL;
|
|
|
602 standard_api_create_t( *reinterpret_cast< service_ptr_t<T> * >( & p_out ) );
|
|
|
603 }
|
|
|
604
|
|
|
605 template<typename T> inline service_ptr_t<T> standard_api_create_t() {
|
|
|
606 service_ptr_t<T> temp;
|
|
|
607 standard_api_create_t(temp);
|
|
|
608 return temp;
|
|
|
609 }
|
|
|
610
|
|
|
611 template<typename T>
|
|
|
612 inline bool static_api_test_t() {
|
|
|
613 typedef typename T::t_interface_entrypoint EP;
|
|
|
614 service_class_helper_t<EP> helper;
|
|
|
615 if (helper.get_count() != 1) return false;
|
|
|
616 if constexpr (!pfc::is_same_type<T,EP>::value) {
|
|
|
617 service_ptr_t<T> t;
|
|
|
618 if (!helper.create(0)->service_query_t(t)) return false;
|
|
|
619 }
|
|
|
620 return true;
|
|
|
621 }
|
|
|
622
|
|
|
623 #define FB2K_API_AVAILABLE(API) static_api_test_t<API>()
|
|
|
624
|
|
|
625 //! Helper template used to easily access core services. \n
|
|
|
626 //! Usage: static_api_ptr_t<myclass> api; api->dosomething(); \n
|
|
|
627 //! Can be used at any point of code, WITH EXCEPTION of static objects that are initialized during the DLL loading process before the service system is initialized; such as static static_api_ptr_t objects or having static_api_ptr_t instances as members of statically created objects. \n
|
|
|
628 //! Throws exception_service_not_found if service could not be reached (which can be ignored for core APIs that are always present unless there is some kind of bug in the code). \n
|
|
|
629 //! This class is provided for backwards compatibility. The recommended way to do this stuff is now someclass::get() / someclass::tryGet().
|
|
|
630 template<typename t_interface>
|
|
|
631 class static_api_ptr_t {
|
|
|
632 private:
|
|
|
633 typedef static_api_ptr_t<t_interface> t_self;
|
|
|
634 public:
|
|
|
635 static_api_ptr_t() {
|
|
|
636 standard_api_create_t(m_ptr);
|
|
|
637 }
|
|
|
638 t_interface* operator->() const {return m_ptr;}
|
|
|
639 t_interface * get_ptr() const {return m_ptr;}
|
|
|
640 ~static_api_ptr_t() {m_ptr->service_release();}
|
|
|
641
|
|
|
642 static_api_ptr_t(const t_self & in) {
|
|
|
643 m_ptr = in.m_ptr; m_ptr->service_add_ref();
|
|
|
644 }
|
|
|
645 const t_self & operator=(const t_self & in) {return *this;} //obsolete, each instance should carry the same pointer
|
|
|
646 private:
|
|
|
647 t_interface * m_ptr;
|
|
|
648 };
|
|
|
649
|
|
|
650 template<typename t_interface>
|
|
|
651 class service_enum_t {
|
|
|
652 typedef service_enum_t<t_interface> self_t;
|
|
|
653 public:
|
|
|
654 service_enum_t() : m_index(0) {
|
|
|
655 pfc::assert_same_type<t_interface,typename t_interface::t_interface_entrypoint>();
|
|
|
656 }
|
|
|
657 void reset() {m_index = 0;}
|
|
|
658
|
|
|
659 template<typename t_query>
|
|
|
660 bool first(service_ptr_t<t_query> & p_out) {
|
|
|
661 reset();
|
|
|
662 return next(p_out);
|
|
|
663 }
|
|
|
664
|
|
|
665 template<typename t_query>
|
|
|
666 bool next(service_ptr_t<t_query> & p_out) {
|
|
|
667 pfc::assert_same_type<typename t_query::t_interface_entrypoint,t_interface>();
|
|
|
668 if constexpr (pfc::is_same_type<t_query,t_interface>::value) {
|
|
|
669 return _next(reinterpret_cast<service_ptr_t<t_interface>&>(p_out));
|
|
|
670 } else {
|
|
|
671 service_ptr_t<t_interface> temp;
|
|
|
672 while(_next(temp)) {
|
|
|
673 if (temp->service_query_t(p_out)) return true;
|
|
|
674 }
|
|
|
675 return false;
|
|
|
676 }
|
|
|
677 }
|
|
|
678
|
|
|
679 service_ptr_t<t_interface> get() const {
|
|
|
680 PFC_ASSERT(!finished());
|
|
|
681 return m_helper.create(m_index);
|
|
|
682 }
|
|
|
683
|
|
|
684 void operator++() {
|
|
|
685 PFC_ASSERT(!finished());
|
|
|
686 ++m_index;
|
|
|
687 }
|
|
|
688 void operator++(int) {
|
|
|
689 PFC_ASSERT(!finished());
|
|
|
690 ++m_index;
|
|
|
691 }
|
|
|
692
|
|
|
693 bool finished() const {
|
|
|
694 return m_index >= m_helper.get_count();
|
|
|
695 }
|
|
|
696
|
|
|
697 service_ptr_t<t_interface> operator*() const {
|
|
|
698 return get();
|
|
|
699 }
|
|
|
700
|
|
|
701 // ==== modern for loop support ====
|
|
|
702 // Instead of using service_enum_t<> / service_ptr_t<>, use:
|
|
|
703 // for( auto ptr : someclass::enumerate() ) { ... }
|
|
|
704 self_t begin() const {
|
|
|
705 self_t ret = *this;
|
|
|
706 ret.m_index = 0;
|
|
|
707 return ret;
|
|
|
708 }
|
|
|
709 self_t end() const {
|
|
|
710 self_t ret = *this;
|
|
|
711 ret.m_index = ret.m_helper.get_count();
|
|
|
712 return ret;
|
|
|
713 }
|
|
|
714 bool operator==(self_t const& other) const {return m_index == other.m_index;}
|
|
|
715 bool operator!=(self_t const& other) const { return m_index != other.m_index; }
|
|
|
716
|
|
|
717
|
|
|
718 private:
|
|
|
719 bool _next(service_ptr_t<t_interface> & p_out) {
|
|
|
720 return m_helper.create(p_out,m_index++);
|
|
|
721 }
|
|
|
722 size_t m_index;
|
|
|
723 service_class_helper_t<t_interface> m_helper;
|
|
|
724 };
|
|
|
725
|
|
|
726 namespace fb2k {
|
|
|
727 //! Modern get-std-api helper. \n
|
|
|
728 //! Does not throw exceptions, crashes on failure. \n
|
|
|
729 //! If failure is possible, use std_api_try_get() instead and handle false return value.
|
|
|
730 template<typename api_t>
|
|
|
731 service_ptr_t<api_t> std_api_get() {
|
|
|
732 typedef typename api_t::t_interface_entrypoint entrypoint_t;
|
|
|
733 service_ptr_t<api_t> ret;
|
|
|
734 if constexpr (pfc::is_same_type<api_t, entrypoint_t>::value) {
|
|
|
735 _standard_api_get_internal(ret._as_base_ptr(), api_t::class_guid);
|
|
|
736 } else {
|
|
|
737 ret ^= std_api_get<entrypoint_t>();
|
|
|
738 }
|
|
|
739 return ret;
|
|
|
740 }
|
|
|
741
|
|
|
742 //! Modern get-std-api helper. \n
|
|
|
743 //! Returns true on success (ret ptr is valid), false on failure (API not found).
|
|
|
744 template<typename api_t>
|
|
|
745 bool std_api_try_get( service_ptr_t<api_t> & ret ) {
|
|
|
746 typedef typename api_t::t_interface_entrypoint entrypoint_t;
|
|
|
747 if constexpr (pfc::is_same_type<api_t, entrypoint_t>::value) {
|
|
|
748 return _standard_api_try_get_internal(ret._as_base_ptr(), api_t::class_guid);
|
|
|
749 } else {
|
|
|
750 service_ptr_t<entrypoint_t> temp;
|
|
|
751 if (! std_api_try_get( temp ) ) return false;
|
|
|
752 return ret &= temp;
|
|
|
753 }
|
|
|
754 }
|
|
|
755 }
|
|
|
756
|
|
|
757
|
|
|
758
|
|
|
759 template<typename T>
|
|
|
760 class service_factory_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
|
|
|
761 public:
|
|
|
762 void instance_create(service_ptr_t<service_base> & p_out) override {
|
|
|
763 this->pass_instance(p_out, new service_impl_t<T>);
|
|
|
764 }
|
|
|
765 };
|
|
|
766
|
|
|
767
|
|
|
768 template<typename T>
|
|
|
769 class service_factory_singleton_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
|
|
|
770 public:
|
|
|
771 void instance_create(service_ptr_t<service_base> & p_out) override {
|
|
|
772 this->pass_instance(p_out, &FB2K_SERVICE_SINGLETON(T) );
|
|
|
773 }
|
|
|
774
|
|
|
775 inline T& get_static_instance() { return &FB2K_SERVICE_SINGLETON(T); }
|
|
|
776 inline const T& get_static_instance() const { return &FB2K_SERVICE_SINGLETON(T); }
|
|
|
777 };
|
|
|
778
|
|
|
779 template<typename T>
|
|
|
780 class service_factory_single_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
|
|
|
781 service_impl_single_t<T> g_instance;
|
|
|
782 public:
|
|
|
783 template<typename ... arg_t> service_factory_single_t(arg_t && ... arg) : g_instance(std::forward<arg_t>(arg) ...) {}
|
|
|
784
|
|
|
785 void instance_create(service_ptr_t<service_base> & p_out) override {
|
|
|
786 this->pass_instance(p_out, &g_instance);
|
|
|
787 }
|
|
|
788
|
|
|
789 inline T& get_static_instance() { return g_instance; }
|
|
|
790 inline const T& get_static_instance() const { return g_instance; }
|
|
|
791 };
|
|
|
792
|
|
|
793 //! Alternate service_factory_single, shared instance created on first access and never deallocated. \n
|
|
|
794 //! Addresses the problem of dangling references to our object getting invoked or plainly de-refcounted during late shutdown.
|
|
|
795 template<typename T>
|
|
|
796 class service_factory_single_v2_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
|
|
|
797 public:
|
|
|
798 T * get() {
|
|
|
799 static T * g_instance = new service_impl_single_t<T>;
|
|
|
800 return g_instance;
|
|
|
801 }
|
|
|
802 void instance_create(service_ptr_t<service_base> & p_out) override {
|
|
|
803 this->pass_instance(p_out, get());
|
|
|
804 }
|
|
|
805 };
|
|
|
806
|
|
|
807 template<typename T>
|
|
|
808 class service_factory_single_ref_t : public service_factory_base_t<typename T::t_interface_entrypoint>
|
|
|
809 {
|
|
|
810 private:
|
|
|
811 T & instance;
|
|
|
812 public:
|
|
|
813 service_factory_single_ref_t(T& param) : instance(param) {}
|
|
|
814
|
|
|
815 void instance_create(service_ptr_t<service_base> & p_out) override {
|
|
|
816 this->pass_instance(p_out, &instance);
|
|
|
817 }
|
|
|
818
|
|
|
819 inline T& get_static_instance() { return instance; }
|
|
|
820 };
|
|
|
821
|
|
|
822 template<typename T>
|
|
|
823 class service_factory_single_transparent_t : public service_factory_base_t<typename T::t_interface_entrypoint>, public service_impl_single_t<T>
|
|
|
824 {
|
|
|
825 public:
|
|
|
826 template<typename ... arg_t> service_factory_single_transparent_t(arg_t && ... arg) : service_impl_single_t<T>( std::forward<arg_t>(arg) ...) {}
|
|
|
827
|
|
|
828 void instance_create(service_ptr_t<service_base> & p_out) override {
|
|
|
829 this->pass_instance(p_out, pfc::implicit_cast<T*>(this));
|
|
|
830 }
|
|
|
831
|
|
|
832 inline T& get_static_instance() {return *(T*)this;}
|
|
|
833 inline const T& get_static_instance() const {return *(const T*)this;}
|
|
|
834 };
|
|
|
835
|
|
|
836
|
|
|
837 #ifdef _MSC_VER
|
|
|
838 #define FB2K_SERVICE_FACTORY_ATTR
|
|
|
839 #else
|
|
|
840 #define FB2K_SERVICE_FACTORY_ATTR __attribute__ (( __used__ ))
|
|
|
841 #endif
|
|
|
842
|
|
|
843 #define _FB2K_CONCAT(a, b) _FB2K_CONCAT_INNER(a, b)
|
|
|
844 #define _FB2K_CONCAT_INNER(a, b) a ## b
|
|
|
845
|
|
|
846 #define _FB2K_UNIQUE_NAME(base) _FB2K_CONCAT(base, __COUNTER__)
|
|
|
847
|
|
|
848 #define FB2K_SERVICE_FACTORY( TYPE ) static ::service_factory_singleton_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) FB2K_SERVICE_FACTORY_ATTR;
|
|
|
849 #define FB2K_SERVICE_FACTORY_LATEINIT( TYPE ) static ::service_factory_single_v2_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) FB2K_SERVICE_FACTORY_ATTR;
|
|
|
850 #define FB2K_SERVICE_FACTORY_PARAMS( TYPE, ... ) static ::service_factory_single_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) ( __VA_ARGS__ );
|
|
|
851 #define FB2K_SERVICE_FACTORY_DYNAMIC( TYPE ) static ::service_factory_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) FB2K_SERVICE_FACTORY_ATTR;
|
|
|
852
|
|
|
853
|
|
|
854 #define FB2K_FOR_EACH_SERVICE(type, call) for( auto obj : type::enumerate() ) { obj->call; }
|