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)
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 ***********************************************************************/
13 #ifndef FC__LISTENER_H
14 #define FC__LISTENER_H
18 /***************************************************************************
19 Helper template to connect C and C++ code.
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:
26 class foo_listener : public listener<foo_listener>
29 virtual void foo() = 0;
33 The listener needs some static data. Declaring it is as simple as putting
34 a macro in some source file:
37 FC_CPP_DECLARE_LISTENER(foo_listener)
40 Then, you call the listeners from the implementation of the C interface:
45 foo_listener::invoke(&foo_listener::foo);
49 This will invoke foo() on all foo_listener objects.
51 == Listening to events
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:
58 class bar : private foo_listener
67 // Initialize the object here
68 foo_listener::listen();
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:
79 void foo(int argument)
81 foo_listener::invoke(&foo_listener::foo, argument);
85 As there may be an arbitrary number of listeners, passing mutable data
86 through invoke() is discouraged.
90 This class achieves its purpose using the Curiously Recurring Template
91 Pattern, hence the weird parent for listeners:
94 class foo_listener : public listener<foo_listener>
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.
101 @warning Implementation is not thread-safe.
102 ***************************************************************************/
103 template<class _type_
>
107 // The type a given specialization supports.
108 typedef _type_ type_t
;
111 // All instances of type_t that have called listen().
112 static std::set
<type_t
*> instances
;
121 template<class _member_fct_
>
122 static void invoke(_member_fct_ function
);
124 template<class _member_fct_
, class _arg1_t_
>
125 static void invoke(_member_fct_ function
, _arg1_t_ arg
);
127 template<class _member_fct_
, class _arg1_t_
, class _arg2_t_
>
128 static void invoke(_member_fct_ function
, _arg1_t_ arg1
, _arg2_t_ arg2
);
131 /***************************************************************************
132 Macro to declare the static data needed by listener<> classes
133 ***************************************************************************/
134 #define FC_CPP_DECLARE_LISTENER(_type_) \
136 std::set<_type_ *> listener<_type_>::instances = std::set<_type_ *>();
138 /***************************************************************************
140 ***************************************************************************/
141 template<class _type_
>
142 listener
<_type_
>::listener()
145 /***************************************************************************
146 Starts listening to events
147 ***************************************************************************/
148 template<class _type_
>
149 void listener
<_type_
>::listen()
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));
156 /***************************************************************************
158 ***************************************************************************/
159 template<class _type_
>
160 listener
<_type_
>::~listener()
162 instances
.erase(reinterpret_cast<type_t
*>(this));
165 /***************************************************************************
166 Invokes a member function on all instances of an listener type. Template
167 parameters are meant to be automatically deduced.
169 Zero-parameter overload.
171 @param function The member function to call
172 ***************************************************************************/
173 template<class _type_
>
174 template<class _member_fct_
>
175 void listener
<_type_
>::invoke(_member_fct_ function
)
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
)();
184 /***************************************************************************
185 Invokes a member function on all instances of an listener type. Template
186 parameters are meant to be automatically deduced.
188 One-parameter overload.
190 @param function The member function to call
191 @param arg The argument to call the function with
192 ***************************************************************************/
193 template<class _type_
>
194 template<class _member_fct_
, class _arg1_t_
>
195 void listener
<_type_
>::invoke(_member_fct_ function
, _arg1_t_ arg
)
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
);
204 /***************************************************************************
205 Invokes a member function on all instances of an listener type. Template
206 parameters are meant to be automatically deduced.
208 Two-parameters overload.
210 @param function The member function to call
211 @param arg1 The first argument to pass to the function
212 @param arg2 The second argument to pass to the function
213 ***************************************************************************/
214 template<class _type_
>
215 template<class _member_fct_
, class _arg1_t_
, class _arg2_t_
>
216 void listener
<_type_
>::invoke(_member_fct_ function
,
217 _arg1_t_ arg1
, _arg2_t_ arg2
)
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
);
226 #endif // FC__LISTENER_H