File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/CPP/panda/lib.x/i/panda/CallbackDispatcher.h
Criterion Covered Total %
statement 49 51 96.0
branch 50 94 53.1
condition n/a
subroutine n/a
pod n/a
total 99 145 68.2


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