annotate foosdk/sdk/foobar2000/SDK/service_impl.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #pragma once
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3 // service_impl.h
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4 // This header provides functionality for spawning your own service objects.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5 // Various service_impl_* classes implement service_base methods (reference counting, query for interface) on top of your class.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6 // service_impl_* are top level ("sealed" in C# terms) classes; they derive from your classes but you should never derive from them.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8 #include <utility>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 namespace service_impl_helper {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11 //! Helper function to defer destruction of a service object. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12 //! Enqueues a main_thread_callback to release the object at a later time, escaping the current scope. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13 //! Important: this takes a raw service_base* - not an autoptr - to ensure that the last reference can be released in main thread. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14 void release_object_delayed(service_base* obj);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17 //! Multi inheritance helper. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18 //! Please note that use of multi inheritance is not recommended. Most components will never need this. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 //! This class handles multi inherited service_query() for you. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20 //! Usage: class myclass : public service_multi_inherit<interface1, interface2> {...}; \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21 //! It's also legal to chain it: service_multi_inherit<interface1, service_multi_inherit<interface2, interface3> > and so on.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22 template<typename class1_t, typename class2_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 class service_multi_inherit : public class1_t, public class2_t {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 typedef service_multi_inherit<class1_t, class2_t> self_t;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 template<typename sub1_t, typename sub2_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27 inline static bool service_query_this(service_ptr& out, const GUID& guid, service_multi_inherit<sub1_t, sub2_t>* in) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28 return service_multi_inherit<sub1_t, sub2_t>::handle_service_query(out, guid, in);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31 template<typename class_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32 inline static bool service_query_this(service_ptr& out, const GUID& guid, class_t* in) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33 return service_base::handle_service_query(out, guid, in);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 // template<typename sub1_t, typename sub2_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40 static bool handle_service_query(service_ptr & out, const GUID & guid, self_t * in) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41 return service_query_this(out, guid, (class1_t*) in) || service_query_this(out, guid, (class2_t*) in);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 service_base * as_service_base() { return class1_t::as_service_base(); }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45 static const char * debugServiceName() { return "multi inherited service"; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47 // Obscure service_base methods from both so calling myclass->service_query() works like it should
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 virtual int service_release() throw() = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 virtual int service_add_ref() throw() = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 virtual bool service_query(service_ptr & p_out, const GUID & p_guid) = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 static bool serviceRequiresMainThreadDestructor() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53 return class1_t::serviceRequiresMainThreadDestructor() || class2_t::serviceRequiresMainThreadDestructor();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 //! Template implementing service_query walking the inheritance chain. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 //! Do not use directly. Each service_impl_* template utilizes it implicitly.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59 template<typename class_t> class implement_service_query : public class_t
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 typedef class_t base_t;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 template<typename ... arg_t> implement_service_query( arg_t && ... arg ) : base_t( std::forward<arg_t>(arg) ... ) {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65 bool service_query(service_ptr_t<service_base> & p_out, const GUID & p_guid) override {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66 return this->handle_service_query( p_out, p_guid, this );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 //! Template implementing reference-counting features of service_base. Intended for dynamic instantiation: "new service_impl_t<someclass>(param1,param2);"; should not be instantiated otherwise (no local/static/member objects) because it does a "delete this;" when reference count reaches zero. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 //! Note that there's no more need to use this direclty, see fb2k::service_new<>().
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72 template<typename class_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73 class service_impl_t : public implement_service_query<class_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 typedef implement_service_query<class_t> base_t;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 int service_release() throw() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78 int ret = (int) --m_counter;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79 if (ret == 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 if (!this->serviceRequiresMainThreadDestructor() || core_api::is_main_thread()) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81 PFC_ASSERT_NO_EXCEPTION( delete this );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 // Pass to release_object_delayed() with zero ref count - a temporary single reference will be created there
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84 service_impl_helper::release_object_delayed(this->as_service_base());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89 int service_add_ref() throw() {return (int) ++m_counter;}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 template<typename ... arg_t> service_impl_t( arg_t && ... arg ) : base_t( std::forward<arg_t>(arg) ... ) {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 private:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 pfc::refcounter m_counter;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96 //! Alternate version of service_impl_t<> - calls this->service_shutdown() instead of delete this. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
97 //! For special cases where selfdestruct on zero refcount is undesired.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
98 template<typename class_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
99 class service_impl_explicitshutdown_t : public implement_service_query<class_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
100 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
101 typedef implement_service_query<class_t> base_t;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
102 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
103 int service_release() throw() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
104 int ret = --m_counter;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
105 if (ret == 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
106 this->service_shutdown();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
107 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
108 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
109 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
110 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
111 int service_add_ref() throw() {return ++m_counter;}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
112
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
113 template<typename ... arg_t> service_impl_explicitshutdown_t(arg_t && ... arg) : base_t(std::forward<arg_t>(arg) ...) {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
114 private:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
115 pfc::refcounter m_counter;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
116 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
117
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
118 //! Template implementing dummy version of reference-counting features of service_base. Intended for static/local/member instantiation: "static service_impl_single_t<someclass> myvar(params);". Because reference counting features are disabled (dummy reference counter), code instantiating it is responsible for deleting it as well as ensuring that no references are active when the object gets deleted.\n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
119 template<typename class_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
120 class service_impl_single_t : public implement_service_query<class_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
121 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
122 typedef implement_service_query<class_t> base_t;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
123 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
124 int service_release() throw() {return 1;}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
125 int service_add_ref() throw() {return 1;}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
126
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
127 template<typename ... arg_t> service_impl_single_t(arg_t && ... arg) : base_t(std::forward<arg_t>(arg) ...) {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
128 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
129
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
130 namespace fb2k {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
131 //! The new recommended way of spawning service objects, automatically implementing reference counting and service_query on top of your class. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
132 //! Usage: auto myObj = fb2k::service_new<myClass>(args); \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
133 //! Returned type is a service_ptr_t<myClass>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
134 template<typename obj_t, typename ... arg_t>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
135 service_ptr_t<obj_t> service_new(arg_t && ... arg) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
136 return new service_impl_t< obj_t > ( std::forward<arg_t> (arg) ... );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
137 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
138 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
139
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
140 #define FB2K_SERVICE_SINGLETON(class_t) PFC_SINGLETON( service_impl_single_t< class_t> )