Line data Source code
1 : /*
2 : * Copyright (c) 2011-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Sebastian Reiter
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : #ifndef __H__UG__message_hub__
34 : #define __H__UG__message_hub__
35 :
36 : #include <vector>
37 : #include <list>
38 : #include <string>
39 : #include <map>
40 : #include <boost/function.hpp>
41 : #include <boost/function_equal.hpp>
42 : #include <boost/bind.hpp>
43 : #include "common/assert.h"
44 : #include "common/util/smart_pointer.h"
45 : #include "common/util/metaprogramming_util.h"
46 : #include "common/error.h"
47 : #include "common/log.h"
48 :
49 : namespace ug
50 : {
51 :
52 : /// \addtogroup ugbase_common_util
53 : /// \{
54 :
55 : class MessageHub;
56 : typedef SmartPtr<MessageHub> SPMessageHub;
57 :
58 : /// Allows to register callbacks and post messages to those callbacks.
59 : /**
60 : * The MessageHub provides a flexible way to register callbacks for a given
61 : * message-type, which can be called through the MessageHub::post_message method.
62 : *
63 : * Functions and member-functions of arbitrary classes can both be used as a
64 : * callback. Callback functions and methods have to have the following signature:
65 : *
66 : * void (*)(const TMsg&)
67 : *
68 : * where the message-type TMsg is derived from MessageHub::IMessage.
69 : * They can be registered through the register_callback methods.
70 : * If you're intending to register a member method of a class, then you have to use
71 : * additionally pass the pointer to the class instance, whose member-method shall
72 : * be called.
73 : *
74 : * On registration of a callback, an identifier is returned, which allows to
75 : * unregister the callback later on. The identifier is wrapped in a smart-pointer,
76 : * and supports an auto-free property. If this is property is enabled, then
77 : * the associated callback is automatically unregistered, as soon as the last
78 : * copy of the encapsulating smart-pointer is deleted.
79 : */
80 : class MessageHub
81 : {
82 : public:
83 : // predeclarations
84 : class IMessage;
85 : class CallbackId;
86 :
87 : private:
88 : // private type definitions
89 : typedef boost::function<void (const IMessage&)> Callback;
90 :
91 : /// The CallbackEntry holds the actual callback and the associated callback-id.
92 : /** If a MessageHub is destroyed before all callbacks are unregistered, this
93 : * information can be used to notify associated callback-ids, that the associated
94 : * hub is gone. Important if autoFree is enabled.
95 : */
96 0 : struct CallbackEntry{
97 : CallbackEntry(const Callback& cb, CallbackId* cbId);
98 : Callback m_callback;
99 : CallbackId* m_callbackId;
100 : };
101 :
102 : typedef std::list<CallbackEntry> CallbackEntryList;
103 : typedef CallbackEntryList::iterator CallbackEntryIterator;
104 : typedef std::map<size_t, CallbackEntryList> CallbackMap;
105 :
106 : public:
107 : /// Error codes which give information on the error-reason
108 : enum ErrorIds{
109 : MSG_HUB_UNKNOWN_ERROR,
110 : MSG_HUB_TYPE_MISMATCH,
111 : MSG_HUB_BAD_MESSAGE_ID,
112 : MSG_HUB_BAD_CALLBACK_ID
113 : };
114 :
115 : /// Instances of this class are thrown if an error occurs in MessageHub
116 : /** This class derives from UGError.
117 : * Use MessageHub::Error::get_message_hub_error_id() to get a more information
118 : * on what caused the error.
119 : */
120 : class Error : public UGError
121 : {
122 : public:
123 0 : Error(const char* msg, ErrorIds errorId) :
124 0 : UGError(msg), m_errorId(errorId) {}
125 :
126 : ErrorIds get_message_hub_error_id() {return m_errorId;}
127 :
128 : protected:
129 : ErrorIds m_errorId;
130 : };
131 :
132 : /// This is the base class of all messages, which may be passed to callbacks.
133 : class IMessage{
134 : public:
135 0 : IMessage() {}
136 : virtual ~IMessage() {}
137 : };
138 :
139 : /// The callback-id allows to deregister previously registered callbacks.
140 : /** Note that the class features an autoFree mechanism, which automatically
141 : * frees the associated callback. Since this class is always wrapped in a
142 : * smart-pointer, the the associated callback won't be freed, until the last
143 : * copy of that smart-pointer is deleted.
144 : * You can disable the auto-free mechanism through the set set_auto_free method
145 : * or by setting the autoFree parameter of the MessageHub::register_callback
146 : * methods to false.
147 : */
148 : class CallbackId{
149 : friend class MessageHub;
150 :
151 : public:
152 : ~CallbackId();
153 : void set_auto_free(bool autoFree) {m_autoFree = autoFree;}
154 :
155 : private:
156 : CallbackId(MessageHub* hub, size_t msgTypeId,
157 : CallbackEntryIterator callbackEntryIter, bool autoFree);
158 :
159 : MessageHub* m_hub;
160 : /// Make sure to only access the iterator while m_hub != NULL.
161 : size_t m_msgTypeId;
162 : CallbackEntryIterator m_callbackEntryIter;
163 : bool m_autoFree;
164 : };
165 :
166 : typedef SmartPtr<CallbackId> SPCallbackId;
167 :
168 : public:
169 : MessageHub();
170 : ~MessageHub();
171 :
172 : /// registers a function callback given a message-type.
173 : /** The callback has to be of the type
174 : *
175 : * void (*FuncCallback)(const TMsg&)
176 : *
177 : * where TMsg is a type derived from MessageHub::IMessage.
178 : *
179 : * The method returns a smart-pointer to a callback-identifier.
180 : * The auto-free property is disabled for the returned callback-id by default.
181 : * Note that this behavior differs from the similar register_class_callback
182 : * method for class-methods.*/
183 : template <class TMsg>
184 : SPCallbackId register_function_callback(void (*callback)(const TMsg&),
185 : bool autoFree = false);
186 :
187 : /// registers a method callback given a message-type.
188 : /** The callback has to be of the type
189 : *
190 : * void (TClass::*ClassCallback)(const TMsg&)
191 : *
192 : * where TClass is the class whose member function is registered as callback
193 : * and TMsg a type derived from MessageHub::IMessage.
194 : *
195 : * The method returns a smart-pointer to a callback-identifier. When the
196 : * instance is deleted, the callback is unregistered by default.
197 : * Note that this behavior differs from the similar register_function_callback
198 : * method for function pointers.
199 : * It's a good idea to store the smart-pointer as a member in the class from
200 : * which you register the callback (if it is registered from a class at all).
201 : * You then won't have to deal with unregistration manually.*/
202 : template <class TMsg, class TClass>
203 : SPCallbackId register_class_callback(TClass* cls,
204 : void (TClass::*callback)(const TMsg&),
205 : bool autoFree = true);
206 :
207 : /// Call this method to explicitly unregister a callback.
208 : /** Note that if you're storing the callback-id in a class and if autoFree
209 : * is enabled for the callback-id, then the callback is automatically
210 : * unregistered, when the last instance of the smart-pointer is deleted.
211 : *
212 : * If you use this method, the autoFree property of the given CallbackId
213 : * will be automatically disabled.
214 : */
215 : void unregister_callback(SPCallbackId cbId);
216 :
217 : /// Posts a message to all callbacks which are registered for the given message tpye
218 : template <class TMsg>
219 : void post_message(const TMsg& msg);
220 :
221 : private:
222 : /// registers a callback given a message-id.
223 : /** Make sure to only pass msgIds which were retrieved through get_message_id
224 : * before. Also be sure to use the correct msg-type, which was registered with
225 : * the given message-id.
226 : *
227 : * The callback has to be of the type
228 : *
229 : * <tt>boost::function\<void (const IMessage&)\></tt>
230 : *
231 : * The method returns a smart-pointer to an callback-identifier.
232 : *
233 : * If the message-id was not registered or if it was registered with a
234 : * different type, then an instance of MessageHub::Error is thrown
235 : * (derives from UGError).
236 : */
237 : template <class TMsg>
238 : SPCallbackId register_callback_impl(
239 : boost::function<void (const IMessage&)> callback,
240 : bool autoFree);
241 :
242 : /// performs unregistration of the given callback
243 : void unregister_callback_impl(CallbackId* cbId);
244 :
245 : private:
246 : CallbackMap m_callbackMap;///< given a msg-type-id, this map returns a list of associated callbacks
247 : };
248 :
249 : // end group ugbase_common_util
250 : /// \}
251 :
252 : }// end of namespace
253 :
254 :
255 : ////////////////////////////////////////
256 : // include implementation
257 : #include "message_hub_impl.hpp"
258 :
259 : #endif
|