00001 #ifndef _foobar2000_sdk_service_h_included_
00002 #define _foobar2000_sdk_service_h_included_
00003
00004 typedef const void* service_class_ref;
00005
00006 PFC_DECLARE_EXCEPTION(exception_service_not_found,pfc::exception,"Service not found");
00007 PFC_DECLARE_EXCEPTION(exception_service_extension_not_found,pfc::exception,"Service extension not found");
00008 PFC_DECLARE_EXCEPTION(exception_service_duplicated,pfc::exception,"Service duplicated");
00009
00010 #ifdef _MSC_VER
00011 #define FOOGUIDDECL __declspec(selectany)
00012 #else
00013 #define FOOGUIDDECL
00014 #endif
00015
00016
00017 #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}};
00018 #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}};
00019
00021 template<typename T> class service_obscure_refcounting : public T {
00022 private:
00023 int service_add_ref() throw();
00024 int service_release() throw();
00025 };
00026
00028 template<typename T> static inline service_obscure_refcounting<T>* service_obscure_refcounting_cast(T * p_source) throw() {return static_cast<service_obscure_refcounting<T>*>(p_source);}
00029
00030
00031 template<typename T> static void service_release_safe(T * p_ptr) throw() {
00032 if (p_ptr != NULL) PFC_ASSERT_NO_EXCEPTION( p_ptr->service_release() );
00033 }
00034
00035
00036 template<typename T> static void service_add_ref_safe(T * p_ptr) throw() {
00037 if (p_ptr != NULL) PFC_ASSERT_NO_EXCEPTION( p_ptr->service_add_ref() );
00038 }
00039
00040 class service_base;
00041
00043 template<typename T>
00044 class service_ptr_t {
00045 private:
00046 typedef service_ptr_t<T> t_self;
00047 public:
00048 inline service_ptr_t() throw() : m_ptr(NULL) {}
00049 inline service_ptr_t(T* p_ptr) throw() : m_ptr(NULL) {copy(p_ptr);}
00050 inline service_ptr_t(const t_self & p_source) throw() : m_ptr(NULL) {copy(p_source);}
00051
00052 template<typename t_source>
00053 inline service_ptr_t(t_source * p_ptr) throw() : m_ptr(NULL) {copy(p_ptr);}
00054
00055 template<typename t_source>
00056 inline service_ptr_t(const service_ptr_t<t_source> & p_source) throw() : m_ptr(NULL) {copy(p_source);}
00057
00058 inline ~service_ptr_t() throw() {service_release_safe(m_ptr);}
00059
00060 template<typename t_source>
00061 void copy(t_source * p_ptr) throw() {
00062 service_add_ref_safe(p_ptr);
00063 service_release_safe(m_ptr);
00064 m_ptr = pfc::safe_ptr_cast<T>(p_ptr);
00065
00066 }
00067
00068 template<typename t_source>
00069 inline void copy(const service_ptr_t<t_source> & p_source) throw() {copy(p_source.get_ptr());}
00070
00071
00072 inline const t_self & operator=(const t_self & p_source) throw() {copy(p_source); return *this;}
00073 inline const t_self & operator=(T * p_ptr) throw() {copy(p_ptr); return *this;}
00074
00075 template<typename t_source> inline t_self & operator=(const service_ptr_t<t_source> & p_source) throw() {copy(p_source); return *this;}
00076 template<typename t_source> inline t_self & operator=(t_source * p_ptr) throw() {copy(p_ptr); return *this;}
00077
00078 inline void release() throw() {
00079 service_release_safe(m_ptr);
00080 m_ptr = NULL;
00081 }
00082
00083
00084 inline service_obscure_refcounting<T>* operator->() const throw() {PFC_ASSERT(m_ptr != NULL);return service_obscure_refcounting_cast(m_ptr);}
00085
00086 inline T* get_ptr() const throw() {return m_ptr;}
00087
00088 inline bool is_valid() const throw() {return m_ptr != NULL;}
00089 inline bool is_empty() const throw() {return m_ptr == NULL;}
00090
00091 inline bool operator==(const t_self & p_item) const throw() {return m_ptr == p_item.get_ptr();}
00092 inline bool operator!=(const t_self & p_item) const throw() {return m_ptr != p_item.get_ptr();}
00093 inline bool operator>(const t_self & p_item) const throw() {return m_ptr > p_item.get_ptr();}
00094 inline bool operator<(const t_self & p_item) const throw() {return m_ptr < p_item.get_ptr();}
00095
00096 template<typename t_other>
00097 inline t_self & operator<<(service_ptr_t<t_other> & p_source) throw() {attach(p_source.detach());return *this;}
00098 template<typename t_other>
00099 inline t_self & operator>>(service_ptr_t<t_other> & p_dest) throw() {p_dest.attach(detach());return *this;}
00100
00101
00102 inline T* __unsafe_duplicate() const throw() {
00103 service_add_ref_safe(m_ptr);
00104 return m_ptr;
00105 }
00106
00107 inline T* detach() throw() {
00108 return pfc::replace_null_t(m_ptr);
00109 }
00110
00111 template<typename t_source>
00112 inline void attach(t_source * p_ptr) throw() {
00113 service_release_safe(m_ptr);
00114 m_ptr = pfc::safe_ptr_cast<T>(p_ptr);
00115 }
00116
00117 T & operator*() const throw() {return *m_ptr;}
00118
00119 service_ptr_t<service_base> & _as_base_ptr() {
00120 PFC_ASSERT( _as_base_ptr_check() );
00121 return *reinterpret_cast<service_ptr_t<service_base>*>(this);
00122 }
00123 static bool _as_base_ptr_check() {
00124 return static_cast<service_base*>((T*)NULL) == reinterpret_cast<service_base*>((T*)NULL);
00125 }
00126 private:
00127 T* m_ptr;
00128 };
00129
00130 namespace pfc {
00131 template<typename T>
00132 class traits_t<service_ptr_t<T> > : public traits_default {
00133 public:
00134 enum { realloc_safe = true, constructor_may_fail = false};
00135 };
00136 }
00137
00138
00139 template<typename T, template<typename> class t_alloc = pfc::alloc_fast>
00140 class service_list_t : public pfc::list_t<service_ptr_t<T>, t_alloc >
00141 {
00142 };
00143
00149 #define FB2K_MAKE_SERVICE_INTERFACE(THISCLASS,PARENTCLASS) \
00150 public: \
00151 typedef THISCLASS t_interface; \
00152 typedef PARENTCLASS t_interface_parent; \
00153 \
00154 static const GUID class_guid; \
00155 \
00156 virtual bool service_query(service_ptr_t<service_base> & p_out,const GUID & p_guid) { \
00157 if (p_guid == class_guid) {p_out = this; return true;} \
00158 else return PARENTCLASS::service_query(p_out,p_guid); \
00159 } \
00160 typedef service_ptr_t<t_interface> ptr; \
00161 protected: \
00162 THISCLASS() {} \
00163 ~THISCLASS() {} \
00164 private: \
00165 const THISCLASS & operator=(const THISCLASS &) {throw pfc::exception_not_implemented();} \
00166 THISCLASS(const THISCLASS &) {throw pfc::exception_not_implemented();} \
00167 private: \
00168 void __private__service_declaration_selftest() { \
00169 pfc::assert_same_type<PARENTCLASS,PARENTCLASS::t_interface>(); \
00170 __validate_service_class_helper<THISCLASS>(); \
00171 pfc::safe_cast<service_base*>(this); \
00172 }
00173
00178 #define FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(THISCLASS) \
00179 public: \
00180 typedef THISCLASS t_interface_entrypoint; \
00181 FB2K_MAKE_SERVICE_INTERFACE(THISCLASS,service_base)
00182
00183
00184 #define FB2K_DECLARE_SERVICE_BEGIN(THISCLASS,BASECLASS) \
00185 class NOVTABLE THISCLASS : public BASECLASS { \
00186 FB2K_MAKE_SERVICE_INTERFACE(THISCLASS,BASECLASS); \
00187 public:
00188
00189 #define FB2K_DECLARE_SERVICE_END() \
00190 };
00191
00192 #define FB2K_DECLARE_SERVICE_ENTRYPOINT_BEGIN(THISCLASS) \
00193 class NOVTABLE THISCLASS : public service_base { \
00194 FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(THISCLASS) \
00195 public:
00196
00197
00200 class NOVTABLE service_base
00201 {
00202 public:
00205 virtual int service_release() throw() = 0;
00208 virtual int service_add_ref() throw() = 0;
00211 virtual bool service_query(service_ptr_t<service_base> & p_out,const GUID & p_guid) {return false;}
00212
00216 template<class T>
00217 bool service_query_t(service_ptr_t<T> & p_out)
00218 {
00219 pfc::assert_same_type<T,T::t_interface>();
00220 return service_query( *reinterpret_cast<service_ptr_t<service_base>*>(&p_out),T::class_guid);
00221 }
00222
00223 typedef service_base t_interface;
00224
00225 protected:
00226 service_base() {}
00227 ~service_base() {}
00228 private:
00229 service_base(const service_base&) {throw pfc::exception_not_implemented();}
00230 const service_base & operator=(const service_base&) {throw pfc::exception_not_implemented();}
00231 };
00232
00233 typedef service_ptr_t<service_base> service_ptr;
00234
00235 template<typename T>
00236 static void __validate_service_class_helper() {
00237 __validate_service_class_helper<T::t_interface_parent>();
00238 }
00239
00240 template<>
00241 static void __validate_service_class_helper<service_base>() {}
00242
00243
00244 #include "service_impl.h"
00245
00246 class NOVTABLE service_factory_base {
00247 protected:
00248 inline service_factory_base(const GUID & p_guid) : m_guid(p_guid) {PFC_ASSERT(!core_api::are_services_available());__internal__next=__internal__list;__internal__list=this;}
00249 inline ~service_factory_base() {PFC_ASSERT(!core_api::are_services_available());}
00250 public:
00251 inline const GUID & get_class_guid() const {return m_guid;}
00252
00253 static service_class_ref enum_find_class(const GUID & p_guid);
00254 static bool enum_create(service_ptr_t<service_base> & p_out,service_class_ref p_class,t_size p_index);
00255 static t_size enum_get_count(service_class_ref p_class);
00256
00257 inline static bool is_service_present(const GUID & g) {return enum_get_count(enum_find_class(g))>0;}
00258
00260 virtual void instance_create(service_ptr_t<service_base> & p_out) = 0;
00261
00263 static service_factory_base *__internal__list;
00265 service_factory_base * __internal__next;
00266 private:
00267 const GUID & m_guid;
00268 };
00269
00270
00271 template<typename B>
00272 class service_factory_base_t : public service_factory_base {
00273 public:
00274 service_factory_base_t() : service_factory_base(B::class_guid) {
00275 pfc::assert_same_type<B,B::t_interface_entrypoint>();
00276 }
00277
00278 };
00279
00280
00281 template<typename T> static void _validate_service_ptr(service_ptr_t<T> const & ptr) {
00282 PFC_ASSERT( ptr.is_valid() );
00283 service_ptr_t<T> test;
00284 PFC_ASSERT( ptr->service_query_t(test) );
00285 }
00286
00287 #ifdef _DEBUG
00288 #define FB2K_ASSERT_VALID_SERVICE_PTR(ptr) _validate_service_ptr(ptr)
00289 #else
00290 #define FB2K_ASSERT_VALID_SERVICE_PTR(ptr)
00291 #endif
00292
00293 template<class T> static bool service_enum_create_t(service_ptr_t<T> & p_out,t_size p_index) {
00294 pfc::assert_same_type<T,T::t_interface_entrypoint>();
00295 service_ptr_t<service_base> ptr;
00296 if (service_factory_base::enum_create(ptr,service_factory_base::enum_find_class(T::class_guid),p_index)) {
00297 p_out = static_cast<T*>(ptr.get_ptr());
00298 return true;
00299 } else {
00300 p_out.release();
00301 return false;
00302 }
00303 }
00304
00305 template<typename T> static service_class_ref _service_find_class() {
00306 pfc::assert_same_type<T,T::t_interface_entrypoint>();
00307 return service_factory_base::enum_find_class(T::class_guid);
00308 }
00309
00310 template<typename what>
00311 static bool _service_instantiate_helper(service_ptr_t<what> & out, service_class_ref servClass, t_size index) {
00312
00313
00314
00315
00316 {
00317 service_ptr temp;
00318 const bool state = service_factory_base::enum_create(temp, servClass, index);
00319 if (state) {
00320 out.attach( static_cast<what*>( temp.detach() ) );
00321 FB2K_ASSERT_VALID_SERVICE_PTR( out );
00322 }
00323 return state;
00324 }
00325 }
00326
00327 template<typename T> class service_class_helper_t {
00328 public:
00329 service_class_helper_t() : m_class(service_factory_base::enum_find_class(T::class_guid)) {
00330 pfc::assert_same_type<T,T::t_interface_entrypoint>();
00331 }
00332 t_size get_count() const {
00333 return service_factory_base::enum_get_count(m_class);
00334 }
00335
00336 bool create(service_ptr_t<T> & p_out,t_size p_index) const {
00337 return _service_instantiate_helper(p_out, m_class, p_index);
00338 }
00339
00340 service_ptr_t<T> create(t_size p_index) const {
00341 service_ptr_t<T> temp;
00342 if (!create(temp,p_index)) throw pfc::exception_bug_check_v2();
00343 return temp;
00344 }
00345 service_class_ref get_class() const {return m_class;}
00346 private:
00347 service_class_ref m_class;
00348 };
00349
00350 void _standard_api_create_internal(service_ptr & out, const GUID & classID);
00351
00352 template<typename T> static void standard_api_create_t(service_ptr_t<T> & p_out) {
00353 if (pfc::is_same_type<T,T::t_interface_entrypoint>::value) {
00354 _standard_api_create_internal(p_out._as_base_ptr(), T::class_guid);
00355 FB2K_ASSERT_VALID_SERVICE_PTR(p_out);
00356 } else {
00357 service_ptr_t<T::t_interface_entrypoint> temp;
00358 standard_api_create_t(temp);
00359 if (!temp->service_query_t(p_out)) throw exception_service_extension_not_found();
00360 }
00361 }
00362
00363 template<typename T> static service_ptr_t<T> standard_api_create_t() {
00364 service_ptr_t<T> temp;
00365 standard_api_create_t(temp);
00366 return temp;
00367 }
00368
00369 template<typename T>
00370 static bool static_api_test_t() {
00371 typedef T::t_interface_entrypoint EP;
00372 service_class_helper_t<EP> helper;
00373 if (helper.get_count() != 1) return false;
00374 if (!pfc::is_same_type<T,EP>::value) {
00375 service_ptr_t<T> t;
00376 if (!helper.create(0)->service_query_t(t)) return false;
00377 }
00378 return true;
00379 }
00380
00381 #define FB2K_API_AVAILABLE(API) static_api_test_t<API>()
00382
00387 template<typename t_interface>
00388 class static_api_ptr_t {
00389 public:
00390 static_api_ptr_t() {
00391 standard_api_create_t(m_ptr);
00392 }
00393 service_obscure_refcounting<t_interface>* operator->() const {return service_obscure_refcounting_cast(m_ptr.get_ptr());}
00394 t_interface* get_ptr() const {return m_ptr.get_ptr();}
00395 private:
00396 service_ptr_t<t_interface> m_ptr;
00397 };
00398
00400 template<typename T> class service_instance_array_t {
00401 public:
00402 typedef service_ptr_t<T> t_ptr;
00403 service_instance_array_t() {
00404 service_class_helper_t<T> helper;
00405 const t_size count = helper.get_count();
00406 m_data.set_size(count);
00407 for(t_size n=0;n<count;n++) m_data[n] = helper.create(n);
00408 }
00409
00410 t_size get_size() const {return m_data.get_size();}
00411 const t_ptr & operator[](t_size p_index) const {return m_data[p_index];}
00412
00413
00414 t_ptr & operator[](t_size p_index) {return m_data[p_index];}
00415 private:
00416 pfc::array_t<t_ptr> m_data;
00417 };
00418
00419 template<typename t_interface>
00420 class service_enum_t {
00421 public:
00422 service_enum_t() : m_index(0) {
00423 pfc::assert_same_type<t_interface,typename t_interface::t_interface_entrypoint>();
00424 }
00425 void reset() {m_index = 0;}
00426
00427 template<typename t_query>
00428 bool first(service_ptr_t<t_query> & p_out) {
00429 reset();
00430 return next(p_out);
00431 }
00432
00433 template<typename t_query>
00434 bool next(service_ptr_t<t_query> & p_out) {
00435 pfc::assert_same_type<typename t_query::t_interface_entrypoint,t_interface>();
00436 if (pfc::is_same_type<t_query,t_interface>::value) {
00437 return __next(reinterpret_cast<service_ptr_t<t_interface>&>(p_out));
00438 } else {
00439 service_ptr_t<t_interface> temp;
00440 while(__next(temp)) {
00441 if (temp->service_query_t(p_out)) return true;
00442 }
00443 return false;
00444 }
00445 }
00446
00447 private:
00448 bool __next(service_ptr_t<t_interface> & p_out) {
00449 return m_helper.create(p_out,m_index++);
00450 }
00451 unsigned m_index;
00452 service_class_helper_t<t_interface> m_helper;
00453 };
00454
00455 template<typename T>
00456 class service_factory_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
00457 public:
00458 void instance_create(service_ptr_t<service_base> & p_out) {
00459 p_out = pfc::safe_cast<service_base*>(pfc::safe_cast<typename T::t_interface_entrypoint*>(pfc::safe_cast<T*>( new service_impl_t<T> )));
00460 }
00461 };
00462
00463 template<typename T>
00464 class service_factory_single_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
00465 service_impl_single_t<T> g_instance;
00466 public:
00467 TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD(service_factory_single_t,g_instance)
00468
00469 void instance_create(service_ptr_t<service_base> & p_out) {
00470 p_out = pfc::safe_cast<service_base*>(pfc::safe_cast<typename T::t_interface_entrypoint*>(pfc::safe_cast<T*>(&g_instance)));
00471 }
00472
00473 inline T& get_static_instance() {return g_instance;}
00474 };
00475
00476 template<typename T>
00477 class service_factory_single_ref_t : public service_factory_base_t<typename T::t_interface_entrypoint>
00478 {
00479 private:
00480 T & instance;
00481 public:
00482 service_factory_single_ref_t(T& param) : instance(param) {}
00483
00484 void instance_create(service_ptr_t<service_base> & p_out) {
00485 p_out = pfc::safe_cast<service_base*>(pfc::safe_cast<typename T::t_interface_entrypoint*>(pfc::safe_cast<T*>(&instance)));
00486 }
00487
00488 inline T& get_static_instance() {return instance;}
00489 };
00490
00491
00492 template<typename T>
00493 class service_factory_single_transparent_t : public service_factory_base_t<typename T::t_interface_entrypoint>, public service_impl_single_t<T>
00494 {
00495 public:
00496 TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD(service_factory_single_transparent_t,service_impl_single_t<T>)
00497
00498 void instance_create(service_ptr_t<service_base> & p_out) {
00499 p_out = pfc::safe_cast<service_base*>(pfc::safe_cast<typename T::t_interface_entrypoint*>(pfc::safe_cast<T*>(this)));
00500 }
00501
00502 inline T& get_static_instance() {return *(T*)this;}
00503 };
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 template<typename what>
00520 static bool service_by_guid_fallback(service_ptr_t<what> & out, const GUID & id) {
00521 service_enum_t<what> e;
00522 service_ptr_t<what> ptr;
00523 while(e.next(ptr)) {
00524 if (ptr->get_guid() == id) {out = ptr; return true;}
00525 }
00526 return false;
00527 }
00528
00529 template<typename what>
00530 class service_by_guid_data {
00531 public:
00532 service_by_guid_data() : m_servClass(), m_inited() {}
00533
00534 bool ready() const {return m_inited;}
00535
00536 void initialize() {
00537 if (m_inited) return;
00538 pfc::assert_same_type< what, typename what::t_interface_entrypoint >();
00539 m_servClass = service_factory_base::enum_find_class(what::class_guid);
00540 const t_size servCount = service_factory_base::enum_get_count(m_servClass);
00541 for(t_size walk = 0; walk < servCount; ++walk) {
00542 service_ptr_t<what> temp;
00543 if (_service_instantiate_helper(temp, m_servClass, walk)) {
00544 m_order.set(temp->get_guid(), walk);
00545 }
00546 }
00547 m_inited = true;
00548 }
00549
00550 bool create(service_ptr_t<what> & out, const GUID & id) const {
00551 PFC_ASSERT(m_inited);
00552 t_size index;
00553 if (!m_order.query(id,index)) return false;
00554 return _service_instantiate_helper(out, m_servClass, index);
00555 }
00556 service_ptr_t<what> create(const GUID & id) const {
00557 service_ptr_t<what> temp; if (!crete(temp,id)) throw exception_service_not_found(); return temp;
00558 }
00559
00560 private:
00561 volatile bool m_inited;
00562 pfc::map_t<GUID,t_size> m_order;
00563 service_class_ref m_servClass;
00564 };
00565
00566 template<typename what>
00567 class _service_by_guid_data_container {
00568 public:
00569 static service_by_guid_data<what> data;
00570 };
00571 template<typename what> service_by_guid_data<what> _service_by_guid_data_container<what>::data;
00572
00573
00574 template<typename what>
00575 static void service_by_guid_init() {
00576 service_by_guid_data<what> & data = _service_by_guid_data_container<what>::data;
00577 data.initialize();
00578 }
00579 template<typename what>
00580 static bool service_by_guid(service_ptr_t<what> & out, const GUID & id) {
00581 pfc::assert_same_type< what, typename what::t_interface_entrypoint >();
00582 service_by_guid_data<what> & data = _service_by_guid_data_container<what>::data;
00583 if (data.ready()) {
00584
00585 } else if (core_api::is_main_thread()) {
00586 data.initialize();
00587 } else {
00588 #ifdef _DEBUG
00589 uDebugLog() << "Warning: service_by_guid() used in non-main thread without initialization, using fallback";
00590 #endif
00591 return service_by_guid_fallback(out,id);
00592 }
00593 return data.create(out,id);
00594 }
00595 template<typename what>
00596 static service_ptr_t<what> service_by_guid(const GUID & id) {
00597 service_ptr_t<what> temp;
00598 if (!service_by_guid(temp,id)) throw exception_service_not_found();
00599 return temp;
00600 }
00601 #endif //_foobar2000_sdk_service_h_included_