File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/libpanda.x/i/panda/CallbackDispatcher.h
Criterion Covered Total %
statement 47 47 100.0
branch 125 710 17.6
condition n/a
subroutine n/a
pod n/a
total 172 757 22.7


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