Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
callback.hh
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#ifndef __ASE_CALLBACK_HH__
3#define __ASE_CALLBACK_HH__
4
5#include <ase/defs.hh>
6#include <algorithm>
7
8namespace Ase {
9
10// == CallbackList<> ==
12template<class... A>
13class CallbackList : public std::enable_shared_from_this<CallbackList<A...>> {
14 CallbackList() {}
15public:
17 using Callback = std::function<void(const A&...)>;
19 bool empty () const { return funcs_.empty(); }
21 bool del (size_t id) { return del_id (id); }
23 size_t add (const Callback &f) { return add_id (f); }
25 std::function<void()>
27 {
28 std::shared_ptr<CallbackList> callbacklistp = this->shared_from_this();
29 ASE_ASSERT_RETURN (callbacklistp != nullptr, {});
30 const size_t id = add_id (f);
31 auto destroy_callback = [id, callbacklistp] () { callbacklistp->del (id); };
32 return destroy_callback;
33 }
35 void
36 call (const std::function<void(const Callback&, const A&...)> &wrapper, const A &...args)
37 {
38 size_t next = 0;
39 iters_.push_back (&next);
40 while (next < funcs_.size())
41 // increment next *before* calling callback to be accurate and adjusted by del_id()
42 wrapper (funcs_[next++].func, std::forward<const A> (args)...);
43 const size_t old_size = iters_.size();
44 iters_.erase (std::remove_if (iters_.begin(), iters_.end(),
45 [&next] (const size_t *p) { return p == &next; }),
46 iters_.end());
47 ASE_ASSERT_RETURN (1 == old_size - iters_.size());
48 }
50 void
51 operator() (const A &...args)
52 {
53 auto caller = [] (const Callback &cb, const A &...args) { cb (std::forward<const A> (args)...); };
54 return call (caller, std::forward<const A> (args)...);
55 }
56private:
57 struct Entry { Callback func; size_t id = 0; };
58 std::vector<Entry> funcs_;
60 static size_t
61 newid()
62 {
63 static size_t counter = 0;
64 return ++counter;
65 }
66 size_t
67 add_id (const Callback &f)
68 {
69 const size_t id = newid();
70 funcs_.push_back ({ f, id });
71 return id;
72 }
73 bool
74 del_id (const size_t id)
75 {
76 for (size_t j = 0; j < funcs_.size(); j++)
77 if (funcs_[j].id == id) {
78 funcs_.erase (funcs_.begin() + j);
79 for (size_t i = 0; i < iters_.size(); i++)
80 if (j < *iters_[i]) // if a callback *before* next
81 *iters_[i] -= 1; // was deleted, adjust next
82 return true;
83 }
84 return false;
85 }
86 ASE_CLASS_NON_COPYABLE (CallbackList);
87};
88
89// == RtCall ==
91struct RtCall {
93 template<typename T> RtCall (T &o, void (T::*f) ());
95 template<typename T> RtCall (void (*f) (T*), T *d);
97 /*ctor*/ RtCall (void (*f) ());
99 explicit RtCall (const RtCall &call);
101 void invoke ();
103 /*dtor*/ ~RtCall ();
104private:
105 static constexpr int pdsize = 4;
106 ptrdiff_t mem_[pdsize] = { 0, 0, 0, 0 };
107 struct Callable {
108 virtual void call () const = 0;
109 };
110 const Callable* callable () const;
111};
112
113// == JobQueue for cross-thread invocations ==
114struct JobQueue {
115 using Caller = std::function<void (const std::function<void()>&)>;
116 explicit JobQueue (const Caller &caller);
117 template<typename F> std::invoke_result_t<F>
118 inline operator+= (const F &job);
119private:
120 const Caller caller_;
121};
122
123// == Implementation Details ==
124template<typename T>
125RtCall::RtCall (T &o, void (T::*f) ())
126{
127 struct Wrapper : Callable {
128 Wrapper (T &o, void (T::*f) ()) : f_ (f), o_ (&o) {}
129 void call() const override { return (o_->*f_)(); }
130 void (T::*f_) (); T *o_;
131 };
132 static_assert (sizeof (mem_) >= sizeof (Wrapper));
133 Wrapper *w = new (mem_) Wrapper { o, f };
134 ASE_ASSERT_RETURN (w == (void*) mem_);
135}
136
137template<typename T>
138RtCall::RtCall (void (*f) (T*), T *d)
139{
140 struct Wrapper : Callable {
141 Wrapper (void (*f) (T*), T *d) : f_ (f), d_ (d) {}
142 void call() const override { return f_ (d_); }
143 void (*f_) (T*); T *d_;
144 };
145 static_assert (sizeof (mem_) >= sizeof (Wrapper));
146 Wrapper *w = new (mem_) Wrapper { f, d };
147 ASE_ASSERT_RETURN (w == (void*) mem_);
148}
149
150template<typename F> std::invoke_result_t<F>
151JobQueue::operator+= (const F &job)
152{
153 using JobReturnType = std::invoke_result_t<F>;
155 caller_ (job);
156}
157
158} // Ase
159
160#endif // __ASE_CALLBACK_HH__
T begin(T... args)
Reentrant callback list with configurable arguments.
Definition callback.hh:13
void call(const std::function< void(const Callback &, const A &...)> &wrapper, const A &...args)
Call all callbacks in the order they were added via wrapper function.
Definition callback.hh:36
void operator()(const A &...args)
Call all callbacks in the order they were added.
Definition callback.hh:51
size_t add(const Callback &f)
Add a callback, returns an id that can be used for deletion.
Definition callback.hh:23
bool del(size_t id)
Delete a previously added callback via its id, returns if any was found.
Definition callback.hh:21
std::function< void()> add_delcb(const Callback &f)
Add a callback and return a deleter that removes the callback when invoked.
Definition callback.hh:26
bool empty() const
Check if the callback list is empty, i.e. invocation will not call any callbacks.
Definition callback.hh:19
#define ASE_ASSERT_RETURN(expr,...)
Return from the current function if expr evaluates to false and issue an assertion warning.
Definition cxxaux.hh:82
#define ASE_DEFINE_MAKE_SHARED(CLASS)
Definition cxxaux.hh:269
#define ASE_CLASS_NON_COPYABLE(ClassName)
Delete copy ctor and assignment operator.
Definition cxxaux.hh:106
T empty(T... args)
T end(T... args)
T erase(T... args)
The Anklang C++ API namespace.
Definition api.hh:9
T push_back(T... args)
T remove_if(T... args)
T size(T... args)
Wrap simple callback pointers, without using malloc (obstruction free).
Definition callback.hh:91
void invoke()
Invoke the wrapped function call.
Definition callback.cc:43
~RtCall()
Clear function pointers.
Definition callback.cc:11
RtCall(T &o, void(T::*f)())
Wrap a simple void func() object member function call.
Definition callback.hh:125