Freeciv-3.3
Loading...
Searching...
No Matches
listener.h
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11***********************************************************************/
12
13#ifndef FC__LISTENER_H
14#define FC__LISTENER_H
15
16#include <set>
17
18/***************************************************************************
19 Helper template to connect C and C++ code.
20
21 This class is a helper to create Java-like "listeners" for "events"
22 generated in C code. If the C interface defines a callback foo() and
23 you want to use it as an event, you first declare a C++ interface:
24
25 ~~~~~{.cpp}
26 class foo_listener : public listener<foo_listener>
27 {
28 public:
29 virtual void foo() = 0;
30 };
31 ~~~~~
32
33 The listener needs some static data. Declaring it is as simple as putting
34 a macro in some source file:
35
36 ~~~~~{.cpp}
37 FC_CPP_DECLARE_LISTENER(foo_listener)
38 ~~~~~
39
40 Then, you call the listeners from the implementation of the C interface:
41
42 ~~~~~{.cpp}
43 void foo()
44 {
45 foo_listener::invoke(&foo_listener::foo);
46 }
47 ~~~~~
48
49 This will invoke foo() on all foo_listener objects.
50
51 == Listening to events
52
53 Listening to events is done by inheriting from a listener. When your
54 object is ready to receive events, it should call the listener's @c listen
55 function. This will typically be done in the constructor:
56
57 ~~~~~{.cpp}
58 class bar : private foo_listener
59 {
60 public:
61 explicit bar();
62 void foo();
63 };
64
65 bar::bar()
66 {
67 // Initialize the object here
68 foo_listener::listen();
69 }
70 ~~~~~
71
72 == Passing arguments
73
74 Passing arguments to the listeners is very simple: you write them after
75 the function pointer. For instance, let's say foo() takes an int. It can
76 be passed to the listeners as follows:
77
78 ~~~~~{.cpp}
79 void foo(int argument)
80 {
81 foo_listener::invoke(&foo_listener::foo, argument);
82 }
83 ~~~~~
84
85 As there may be an arbitrary number of listeners, passing mutable data
86 through invoke() is discouraged.
87
88 == Technical details
89
90 This class achieves its purpose using the Curiously Recurring Template
91 Pattern, hence the weird parent for listeners:
92
93 ~~~~~{.cpp}
94 class foo_listener : public listener<foo_listener>
95 ~~~~~
96
97 The template argument is used to specialize object storage and member
98 function invocation. Compilers should be able to inline calls to invoke(),
99 leaving only the overhead of looping on all instances.
100
101 @warning Implementation is not thread-safe.
102***************************************************************************/
103template<class _type_>
105{
106public:
107 // The type a given specialization supports.
108 typedef _type_ type_t;
109
110private:
111 // All instances of type_t that have called listen().
112 static std::set<type_t *> instances;
113
114protected:
115 explicit listener();
116 virtual ~listener();
117
118 void listen();
119
120public:
121 template<class _member_fct_>
123
124 template<class _member_fct_, class _arg1_t_>
126
127 template<class _member_fct_, class _arg1_t_, class _arg2_t_>
129};
130
131/***********************************************************************/
134#define FC_CPP_DECLARE_LISTENER(_type_) \
135 template<> \
136 std::set<_type_ *> listener<_type_>::instances = std::set<_type_ *>();
137
138/***********************************************************************/
141template<class _type_>
144
145/***********************************************************************/
148template<class _type_>
150{
151 // If you get an error here, your listener likely doesn't inherit from the
152 // listener<> correctly. See the class documentation.
153 instances.insert(static_cast<type_t *>(this));
154}
155
156/***********************************************************************/
159template<class _type_>
161{
162 instances.erase(reinterpret_cast<type_t *>(this));
163}
164
165/***********************************************************************/
173template<class _type_>
174template<class _member_fct_>
176{
177 typename std::set<type_t *>::iterator it = instances.begin();
178 typename std::set<type_t *>::iterator end = instances.end();
179 for ( ; it != end; ++it) {
180 ((*it)->*function)();
181 }
182}
183
184/***********************************************************************/
193template<class _type_>
194template<class _member_fct_, class _arg1_t_>
196{
197 typename std::set<type_t *>::iterator it = instances.begin();
198 typename std::set<type_t *>::iterator end = instances.end();
199 for ( ; it != end; ++it) {
200 ((*it)->*function)(arg);
201 }
202}
203
204/***********************************************************************/
214template<class _type_>
215template<class _member_fct_, class _arg1_t_, class _arg2_t_>
218{
219 typename std::set<type_t *>::iterator it = instances.begin();
220 typename std::set<type_t *>::iterator end = instances.end();
221 for ( ; it != end; ++it) {
222 ((*it)->*function)(arg1, arg2);
223 }
224}
225
226#endif // FC__LISTENER_H
static void invoke(_member_fct_ function)
Definition listener.h:175
static void invoke(_member_fct_ function, _arg1_t_ arg)
Definition listener.h:195
static std::set< type_t * > instances
Definition listener.h:112
static void invoke(_member_fct_ function, _arg1_t_ arg1, _arg2_t_ arg2)
Definition listener.h:216
_type_ type_t
Definition listener.h:108
void listen()
Definition listener.h:149
virtual ~listener()
Definition listener.h:160
char * incite_cost
Definition comments.c:74