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 <functional> // for std::function
41 :
42 : #include "common/assert.h"
43 : #include "common/util/smart_pointer.h"
44 : #include "common/util/metaprogramming_util.h"
45 : #include "common/error.h"
46 : #include "common/log.h"
47 :
48 : namespace ug
49 : {
50 :
51 : /// \addtogroup ugbase_common_util
52 : /// \{
53 :
54 : class MessageHub;
55 : typedef SmartPtr<MessageHub> SPMessageHub;
56 :
57 : /// Allows to register callbacks and post messages to those callbacks.
58 : /**
59 : * The MessageHub provides a flexible way to register callbacks for a given
60 : * message-type, which can be called through the MessageHub::post_message method.
61 : *
62 : * Functions and member-functions of arbitrary classes can both be used as a
63 : * callback. Callback functions and methods have to have the following signature:
64 : *
65 : * void (*)(const TMsg&)
66 : *
67 : * where the message-type TMsg is derived from MessageHub::IMessage.
68 : * They can be registered through the register_callback methods.
69 : * If you're intending to register a member method of a class, then you have to use
70 : * additionally pass the pointer to the class instance, whose member-method shall
71 : * be called.
72 : *
73 : * On registration of a callback, an identifier is returned, which allows to
74 : * unregister the callback later on. The identifier is wrapped in a smart-pointer,
75 : * and supports an auto-free property. If this is property is enabled, then
76 : * the associated callback is automatically unregistered, as soon as the last
77 : * copy of the encapsulating smart-pointer is deleted.
78 : */
79 : class MessageHub
80 : {
81 : public:
82 : // predeclarations
83 : class IMessage;
84 : class CallbackId;
85 :
86 : private:
87 : // private type definitions
88 : typedef std::function<void (const IMessage&)> Callback;
89 :
90 : /// The CallbackEntry holds the actual callback and the associated callback-id.
91 : /** If a MessageHub is destroyed before all callbacks are unregistered, this
92 : * information can be used to notify associated callback-ids, that the associated
93 : * hub is gone. Important if autoFree is enabled.
94 : */
95 0 : struct CallbackEntry{
96 : CallbackEntry(const Callback& cb, CallbackId* cbId);
97 : Callback m_callback;
98 : CallbackId* m_callbackId;
99 : };
100 :
101 : typedef std::list<CallbackEntry> CallbackEntryList;
102 : typedef CallbackEntryList::iterator CallbackEntryIterator;
103 : typedef std::map<size_t, CallbackEntryList> CallbackMap;
104 :
105 : public:
106 : /// Error codes which give information on the error-reason
107 : enum ErrorIds{
108 : MSG_HUB_UNKNOWN_ERROR,
109 : MSG_HUB_TYPE_MISMATCH,
110 : MSG_HUB_BAD_MESSAGE_ID,
111 : MSG_HUB_BAD_CALLBACK_ID
112 : };
113 :
114 : /// Instances of this class are thrown if an error occurs in MessageHub
115 : /** This class derives from UGError.
116 : * Use MessageHub::Error::get_message_hub_error_id() to get a more information
117 : * on what caused the error.
118 : */
119 : class Error : public UGError
120 : {
121 : public:
122 0 : Error(const char* msg, ErrorIds errorId) :
123 0 : UGError(msg), m_errorId(errorId) {}
124 :
125 : ErrorIds get_message_hub_error_id() {return m_errorId;}
126 :
127 : protected:
128 : ErrorIds m_errorId;
129 : };
130 :
131 : /// This is the base class of all messages, which may be passed to callbacks.
132 : class IMessage{
133 : public:
134 0 : IMessage() {}
135 : virtual ~IMessage() {}
136 : };
137 :
138 : /// The callback-id allows to deregister previously registered callbacks.
139 : /** Note that the class features an autoFree mechanism, which automatically
140 : * frees the associated callback. Since this class is always wrapped in a
141 : * smart-pointer, the the associated callback won't be freed, until the last
142 : * copy of that smart-pointer is deleted.
143 : * You can disable the auto-free mechanism through the set set_auto_free method
144 : * or by setting the autoFree parameter of the MessageHub::register_callback
145 : * methods to false.
146 : */
147 : class CallbackId{
148 : friend class MessageHub;
149 :
150 : public:
151 : ~CallbackId();
152 : void set_auto_free(bool autoFree) {m_autoFree = autoFree;}
153 :
154 : private:
155 : CallbackId(MessageHub* hub, size_t msgTypeId,
156 : CallbackEntryIterator callbackEntryIter, bool autoFree);
157 :
158 : MessageHub* m_hub;
159 : /// Make sure to only access the iterator while m_hub != NULL.
160 : size_t m_msgTypeId;
161 : CallbackEntryIterator m_callbackEntryIter;
162 : bool m_autoFree;
163 : };
164 :
165 : typedef SmartPtr<CallbackId> SPCallbackId;
166 :
167 : public:
168 : MessageHub();
169 : ~MessageHub();
170 :
171 : /// registers a function callback given a message-type.
172 : /** The callback has to be of the type
173 : *
174 : * void (*FuncCallback)(const TMsg&)
175 : *
176 : * where TMsg is a type derived from MessageHub::IMessage.
177 : *
178 : * The method returns a smart-pointer to a callback-identifier.
179 : * The auto-free property is disabled for the returned callback-id by default.
180 : * Note that this behavior differs from the similar register_class_callback
181 : * method for class-methods.*/
182 : template <class TMsg>
183 : SPCallbackId register_function_callback(void (*callback)(const TMsg&),
184 : bool autoFree = false);
185 :
186 : /// registers a method callback given a message-type.
187 : /** The callback has to be of the type
188 : *
189 : * void (TClass::*ClassCallback)(const TMsg&)
190 : *
191 : * where TClass is the class whose member function is registered as callback
192 : * and TMsg a type derived from MessageHub::IMessage.
193 : *
194 : * The method returns a smart-pointer to a callback-identifier. When the
195 : * instance is deleted, the callback is unregistered by default.
196 : * Note that this behavior differs from the similar register_function_callback
197 : * method for function pointers.
198 : * It's a good idea to store the smart-pointer as a member in the class from
199 : * which you register the callback (if it is registered from a class at all).
200 : * You then won't have to deal with unregistration manually.*/
201 : template <class TMsg, class TClass>
202 : SPCallbackId register_class_callback(TClass* cls,
203 : void (TClass::*callback)(const TMsg&),
204 : bool autoFree = true);
205 :
206 : /// Call this method to explicitly unregister a callback.
207 : /** Note that if you're storing the callback-id in a class and if autoFree
208 : * is enabled for the callback-id, then the callback is automatically
209 : * unregistered, when the last instance of the smart-pointer is deleted.
210 : *
211 : * If you use this method, the autoFree property of the given CallbackId
212 : * will be automatically disabled.
213 : */
214 : void unregister_callback(SPCallbackId cbId);
215 :
216 : /// Posts a message to all callbacks which are registered for the given message tpye
217 : template <class TMsg>
218 : void post_message(const TMsg& msg);
219 :
220 : private:
221 : /// registers a callback given a message-id.
222 : /** Make sure to only pass msgIds which were retrieved through get_message_id
223 : * before. Also be sure to use the correct msg-type, which was registered with
224 : * the given message-id.
225 : *
226 : * The callback has to be of the type
227 : *
228 : * <tt>std::function\<void (const IMessage&)\></tt>
229 : *
230 : * The method returns a smart-pointer to an callback-identifier.
231 : *
232 : * If the message-id was not registered or if it was registered with a
233 : * different type, then an instance of MessageHub::Error is thrown
234 : * (derives from UGError).
235 : */
236 : template <class TMsg>
237 : SPCallbackId register_callback_impl(
238 : std::function<void (const IMessage&)> callback,
239 : bool autoFree);
240 :
241 : /// performs unregistration of the given callback
242 : void unregister_callback_impl(CallbackId* cbId);
243 :
244 : private:
245 : CallbackMap m_callbackMap;///< given a msg-type-id, this map returns a list of associated callbacks
246 : };
247 :
248 : // end group ugbase_common_util
249 : /// \}
250 :
251 : }// end of namespace
252 :
253 :
254 : ////////////////////////////////////////
255 : // include implementation
256 : #include "message_hub_impl.hpp"
257 :
258 : #endif
|