File Coverage

src/panda/CallbackDispatcher.h
Criterion Covered Total %
statement 62 62 100.0
branch 185 386 47.9
condition n/a
subroutine n/a
pod n/a
total 247 448 55.1


line stmt bran cond sub pod time code
1             #pragma once
2             #include "function.h"
3             #include "optional.h"
4             #include "owning_list.h"
5              
6             namespace panda {
7              
8             namespace {
9             template struct optional_type {
10             using type = optional;
11 48           static type default_value() { return type{}; }
12             };
13              
14             template <>
15             struct optional_type {
16 7           static void default_value(){}
17             using type = void;
18             };
19             }
20              
21             template
22 96           class CallbackDispatcher {
23             public:
24             struct Event;
25             using OptionalRet = typename optional_type::type;
26             using Callback = function;
27             using SimpleCallback = function;
28              
29 200 50         struct Wrapper {
    50          
    50          
    50          
    50          
30             Callback real;
31             SimpleCallback simple;
32              
33 16 50         explicit Wrapper (Callback real) : real(real) {}
    50          
34 24 50         explicit Wrapper (SimpleCallback simple) : simple(simple) {}
    50          
    50          
    50          
    50          
35              
36             template
37 32           auto operator() (Event& e, RealArgs&&... args) -> decltype(real(e, args...)) {
38 32 50         if (real) return real(e, std::forward(args)...);
    50          
    0          
    100          
    100          
39              
40 19 50         simple(args...);
41 19           return e.next(std::forward(args)...);
42             }
43              
44             bool equal (const Wrapper& oth) {
45             if (simple) return simple == oth.simple;
46             return real == oth.real;
47             }
48              
49             template
50 5           decltype(simple == std::declval()) equal (const T& oth) {
51 5 50         return simple && simple == oth;
    50          
    50          
    50          
    50          
    50          
    50          
    50          
52             }
53              
54             template
55 6           decltype(real == std::declval()) equal (const T& oth) {
56 6 50         return real && real == oth;
    50          
    50          
    50          
    50          
    100          
57             }
58             };
59              
60             template
61             using add_const_ref_t = typename std::conditional::value, T, const T&>::type;
62              
63             using CallbackList = owning_list;
64              
65 44           struct Event {
66             CallbackDispatcher& dispatcher;
67             typename CallbackList::iterator state;
68              
69             Event (const Event& oth) = delete;
70              
71 29           OptionalRet next (add_const_ref_t... args) {
72 29           return dispatcher.next(*this, args...);
73             }
74             };
75              
76 6           void add_event_listener (const Callback& callback, bool back = false) {
77 6 50         if (!callback) return;
78 6 50         if (back) listeners.push_back(Wrapper(callback));
    0          
    0          
79 6 50         else listeners.push_front(Wrapper(callback));
    50          
80             }
81              
82 10           void add_event_listener (Callback&& callback, bool back = false) {
83 10 50         if (!callback) return;
    50          
84 10 100         if (back) listeners.push_back(Wrapper(std::forward(callback)));
    50          
    50          
    50          
    0          
    0          
85 10 50         else listeners.push_front(Wrapper(std::forward(callback)));
    50          
    50          
    50          
86             }
87              
88 8           void add (const SimpleCallback& callback, bool back = false) {
89 8 50         if (!callback) return;
    50          
90 8 100         if (back) listeners.push_back(Wrapper(callback));
    50          
    50          
    50          
    0          
    0          
91 8 50         else listeners.push_front(Wrapper(callback));
    50          
    50          
    50          
92             }
93              
94 16           void add (SimpleCallback&& callback, bool back = false) {
95 16 50         if (!callback) return;
    50          
    50          
    50          
    50          
96 16 50         if (back) listeners.push_back(Wrapper(std::forward(callback)));
    0          
    0          
    50          
    0          
    0          
    100          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
97 16 50         else listeners.push_front(Wrapper(std::forward(callback)));
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
98             }
99              
100 1 50         template void add_back (T&& callback) { add(std::forward(callback), true); }
101              
102 34           auto operator() (add_const_ref_t... args) -> decltype(std::declval()(std::declval(), args...)) {
103 68 50         auto iter = listeners.begin();
    50          
    50          
    50          
104 34 50         if (iter == listeners.end()) return optional_type::default_value();
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
105              
106 44 50         Event e{*this, iter};
    50          
    50          
    50          
107 22 50         return (*iter)(e, args...);
    50          
    50          
    50          
108             }
109              
110             template
111 10           void remove (const SmthComparable& callback) {
112 21 50         for (auto iter = listeners.rbegin(); iter != listeners.rend(); ++iter) {
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
113 11 50         if (iter->equal(callback)) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
114 10 50         listeners.erase(iter);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
115 10           break;
116             }
117             }
118 10           }
119              
120             template
121 1           void remove_object(T&& makable,
122             decltype(function_details::tmp_abstract_function(std::forward(std::declval())))* = nullptr)
123             {
124 2 50         auto tmp = function_details::tmp_abstract_function(std::forward(makable));
125 1 50         remove(tmp);
126 1           }
127              
128             template
129 1           void remove_object(T&& makable,
130             decltype(function_details::tmp_abstract_function(std::forward(std::declval())))* = nullptr)
131             {
132 2 50         auto tmp = function_details::tmp_abstract_function(std::forward(makable));
133 1 50         remove(tmp);
134 1           }
135              
136 1           void remove_all () {
137 1           listeners.clear();
138 1           }
139              
140             bool has_listeners () const {
141             return listeners.size();
142             }
143              
144             private:
145             template
146 29           OptionalRet next (Event& e, RealArgs&&... args) {
147 29           ++e.state;
148 29 50         if (e.state != listeners.end()) {
    100          
    50          
    100          
    50          
    100          
    50          
    100          
149 10           return (*e.state)(e, std::forward(args)...);
150             } else {
151 29           return optional_type::default_value();
152             }
153             }
154              
155             CallbackList listeners;
156             };
157              
158             template
159 96           class CallbackDispatcher : public CallbackDispatcher {};
160              
161             }