ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
lang/plugins.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of the \aliblong. It does not belong to an \alibmod and is
4/// included in any \alibdist. However it can be used only if \alib_enums is part of the
5/// distribution.
6///
7/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
8/// Published under \ref mainpage_license "Boost Software License".
9//==================================================================================================
10#ifndef HPP_ALIB_LANG_PLUGINS
11#define HPP_ALIB_LANG_PLUGINS 1
12#pragma once
13#if !defined(DOXYGEN)
14# include "alib/alib.hpp"
15#endif
16
18
19#include "alib/lang/commonenumdefs.hpp"
21
22#include <vector>
23#include <algorithm>
24
25namespace alib::lang {
26
27//==================================================================================================
28/// This class usually is used as a base class for types that need to manage simple plug-ins.
29/// Within \alib itself, for example classes \alib{config;Configuration} and
30/// \alib{expressions;Compiler} inherit from this class.
31///
32/// Plug-ins are organized with a prioritization. This means, that plug-ins which are inserted with
33/// a higher priority are 'asked' first, and those with a lower value become 'asked' only if higher
34/// prioritized plug-ins did not answer.<br>
35/// However, a derived class can deviate from this behavior. Using the typical \alib class design,
36/// all internal fields are \c protected, hence freely accessible by derived classes.
37///
38/// \par Availability
39/// While this class is located in the core namespace #alib::lang, it is compilable only
40/// in case module \alib_enums is included in the \alibdist.
41///
42/// @tparam TPlugin The plug-in type that this class manages. This type is publicly exposed as
43/// #PluginType
44/// This type is publicly exposed as #PrioritiesType.
45//==================================================================================================
46template<typename TPlugin, typename TPriorities>
47class Plugin
48{
49 public:
50 /// This exposes the template parameter \p{TPlugin} to the outer world.
51 using PluginType= TPlugin;
52
53 /// This exposes the template parameter \p{pTPlugin} to the outer world.
54 using PrioritiesType= TPriorities;
55
56 protected:
57 /// The priority of this plug-in.
59
60 /// Constructor which is protected, as this is a bace class.
61 /// @param pPriority The priority that this plug-in uses.
63 : priority (pPriority) {}
64
65 public:
66 /// Returns the priority of this plug-in which is set during construction.
67 /// @return The priority of this plugin.
69
70}; //class Plugin
71
72//==================================================================================================
73/// This class usually is used as a base class for types that need to manage simple plug-ins.
74/// Within \alib itself, for example classes \alib{config;Configuration} and
75/// \alib{expressions;Compiler} inherit from this class.
76///
77/// Plug-ins are organized with a prioritization. This means, that plug-ins which are inserted with
78/// a higher priority are 'asked' first, and those with a lower value become 'asked' only if higher
79/// prioritized plug-ins did not answer.<br>
80/// However, a derived class can deviate from this behavior. Using the typical \alib class design,
81/// all internal fields are \c protected, hence freely accessible by derived classes.
82///
83/// @tparam TPlugin The type of the plug-ins managed. This type is publicly exposed as
84/// #PluginType.
85/// @tparam TPriorities The enumeration type providing the default "plug-in slots" and priorities
86/// of the plug-ins managed. This type is publicly exposed as #PrioritiesType.
87//==================================================================================================
88template<typename TPlugin, typename TPriorities>
90{
91 // #############################################################################################
92 // public fields and types
93 // #############################################################################################
94 public:
95
96 /// This exposes the template parameter \p{pTPlugin} to the outer world.
97 using PluginType= TPlugin;
98
99 /// This exposes the template parameter \p{pTPlugin} to the outer world.
100 using PrioritiesType= TPriorities;
101
102 /// Type definition for elements of the list of plug-ins with their priority.
103 struct Slot
104 {
105 TPlugin* plugin; ///< The plug-in.
106 bool owned; ///< If \c true, this container is responsible for deleting
107 ///< the plug-in object.
108 };
109
110 // #############################################################################################
111 // internal fields
112 // #############################################################################################
113 protected:
114
115 /// The plug-ins we have attached in descending priority order.
116 std::vector<Slot> plugins;
117
118 // #############################################################################################
119 // Constructor/destructor
120 // #############################################################################################
121 public:
122 //==========================================================================================
123 /// Destructor. All plug-ins that were inserted with parameter \p{responsibility} set to
124 /// \alib{lang;Responsibility::Transfer} will be deleted.
125 //==========================================================================================
127 {
128 for( auto& slot : plugins )
129 if( slot.owned )
130 delete slot.plugin;
131 }
132
133
134
135 // #############################################################################################
136 // interface
137 // #############################################################################################
138 public:
139 //==========================================================================================
140 /// Adds the given plug-in to the list of plug-ins.
141 ///
142 /// @param plugin The plug-in to insert.
143 /// @param responsibility If \c Responsibility::Transfer, the given plugin will be deleted
144 /// with destruction of this object.
145 /// Defaults to \c Responsibility::KeepWithSender which denotes that
146 /// the life-cycle of the given external buffer is managed elsewhere.
147 //==========================================================================================
148 void InsertPlugin( TPlugin* plugin, lang::Responsibility responsibility
150 {
151 ALIB_ASSERT_ERROR( plugin != nullptr, "FSPLUGINS", "Nullptr provided for plugin." )
152
153 ALIB_STATIC_ASSERT( Plugin_type_not_virtual,
154 std::has_virtual_destructor<TPlugin>::value
155 || responsibility == lang::Responsibility::KeepWithSender,
156 "Can't take responsibility for plug-in destruction. TPlugin has no virtual destructor.")
157
158 // gcc needs this captured, clang warns.
159 // Its about the ALIB_CALLER inside ALIB_ASSERT_ERROR
161 plugins.insert( std::find_if( plugins.begin(), plugins.end(),
162 [plugin,this]( Slot& ppp)
163 {
164 ALIB_ASSERT_ERROR( ppp.plugin->GetPriority() != plugin->GetPriority(), "FSPLUGINS",
165 "PluginContainer::InsertPlugin(): Plug-in with same priority exists" )
166
167 return ppp.plugin->GetPriority() < plugin->GetPriority();
168 } ),
169
170 Slot { plugin, responsibility == lang::Responsibility::Transfer }
171 );
173 }
174
175
176 //==========================================================================================
177 /// Removes the given plug-in from the list of plug-ins.
178 ///
179 /// Responsibility for deletion of removed plug-ins is passed to the remover in case the
180 /// plug-in was inserted with parameter \p{responsibility} set to
181 /// \alib{lang;Responsibility::Transfer}.
182 ///
183 /// @param plugIn The plug-in to be removed.
184 /// @return \c true if the plug-in was removed, else \c false, which indicates that the
185 /// given plug-in was not found.
186 //==========================================================================================
187 bool RemovePlugin( TPlugin* plugIn )
188 {
189 auto it= std::find_if( plugins.begin(), plugins.end(), [plugIn](Slot& pair)
190 {
191 return pair.plugin == plugIn;
192 } );
193 if( it != plugins.end() )
194 {
195 plugins.erase( it );
196 return true;
197 }
198
199 ALIB_WARNING( "PluginContainer::RemovePlugin(): Plug-in not found for removal." )
200 return false;
201 }
202
203 //==========================================================================================
204 /// Remove the plug-in at the given \p{idx} from the list of plug-ins.
205 ///
206 /// Responsibility for deletion of removed plug-ins is passed to the remover in case the
207 /// plug-in was inserted with parameter \p{responsibility} set to
208 /// \alib{lang;Responsibility::Transfer}.
209 ///
210 /// @param idx The index of the plug-in to remove.
211 //==========================================================================================
213 {
215 "FSPLUGINS", "PluginContainer::RemovePlugin(): Index out of bounds: ", idx )
216 plugins.erase( plugins.begin() + idx );
217 }
218
219
220 //==========================================================================================
221 /// Remove the plug-in with the given priority.
222 ///
223 /// Responsibility for deletion of removed plug-ins is passed to the remover in case the
224 /// plug-in was inserted with parameter \p{responsibility} set to
225 /// \alib{lang;Responsibility::Transfer}.
226 ///
227 /// @param priority The priority of the plug-in to remove.
228 /// @return \c true if the plug-in was removed, else \c false, which indicates that no
229 /// plug-in with the given priority was found.
230 //==========================================================================================
231 TPlugin* RemovePlugin( TPriorities priority )
232 {
233 TPlugin* plugin= nullptr;
234 plugins.erase( std::remove_if( plugins.begin(), plugins.end(),
235 [priority, &plugin](Slot& entry)
236 {
237 if( entry.priority == priority)
238 {
239 plugin= entry.plugin;
240 return true;
241 }
242 return false;
243 } ),
244 plugins.end() );
245
246 ALIB_ASSERT_WARNING( plugin, "FSPLUGINS",
247 "PluginContainer::RemovePlugin(): No Plug-in was removed " )
248
249 return plugin;
250 }
251
252
253 //==========================================================================================
254 /// Checks if any plug-in is attached. This is useful if optional configuration objects
255 /// are used. In case no plug-in was attached (by a third party), the effort to declare and
256 /// search a variable can be omitted.
257 /// @return \c true if this object has any plugin set, \c false otherwise.
258 //==========================================================================================
260 {
261 return CountPlugins() > 0;
262 }
263
264 //==========================================================================================
265 /// Returns the number of plug-ins attached.
266 /// @return The quantity of attached plug-ins.
267 //==========================================================================================
269 {
270 return static_cast<integer>(plugins.size());
271 }
272
273 //==========================================================================================
274 /// Returns the plug-in with the given internal number. Valid numbers are
275 /// 0..[#CountPlugins]. No internal checks for valid plug-in numbers are made.
276 ///
277 /// @param number The number of the plug-in requested.
278 /// @return The plug-in requested.
279 //==========================================================================================
280 TPlugin* GetPlugin( integer number )
281 {
282 return plugins[size_t(number)].plugin;
283 }
284
285 //==========================================================================================
286 /// Returns the priority of the plug-in with the given internal number. Valid numbers are
287 /// 0..[#CountPlugins]. No internal checks for valid plug-in numbers are made.
288 ///
289 /// @param number The number of the plug-in requested.
290 /// @return The priortiy of the plug-in.
291 //==========================================================================================
292 TPriorities GetPriority( integer number )
293 {
294 return plugins[size_t(number)].priority;
295 }
296
297
298 //==========================================================================================
299 /// Returns the plug-in with the given priority. If the plug-in does not exist, \c nullptr
300 /// is returned.
301 ///
302 /// @param priority The priority of the plug-in to return.
303 /// @return The plug-in requested or \c nullptr if not available.
304 //==========================================================================================
305 TPlugin* GetPlugin( TPriorities priority )
306 {
307 auto it = std::find_if( plugins.begin(), plugins.end(),
308 [priority](Slot& pair) { return pair.priority == priority; } );
309 if( it != plugins.end() )
310 return it->plugin;
311 return nullptr;
312 }
313
314 //==========================================================================================
315 /// Same as #GetPlugin, but converts the plug-in found to the template type, which has
316 /// to be explicitly provided with the invocation of this method.
317 ///
318 /// A type-check is performed using standard C++ \c dynamic_cast mechanics.
319 /// If the plugin has a different type, \c nullptr is returned.
320 ///
321 /// @tparam TPluginType The type of the plugin to search.
322 /// @param priority The priority of the plug-in to return.
323 /// @return The plug-in of requested type and priority. \c nullptr if not available.
324 //==========================================================================================
325 template<typename TPluginType>
326 TPluginType* GetPluginTypeSafe( TPriorities priority )
327 {
328 return dynamic_cast<TPluginType*>( GetPlugin( priority ) );
329 }
330
331 //==========================================================================================
332 /// Searches the list of plug-ins for the first found with type \p{TPluginType}.
333 ///
334 /// @tparam TPluginType The type of the plugin to search.
335 /// @return The plug-in of requested type. \c nullptr if not available.
336 //==========================================================================================
337 template<typename TPluginType>
338 TPluginType* GetPluginTypeSafe()
339 {
340 TPluginType* cast= nullptr;
341 for( auto& ppp : plugins )
342 if( (cast= dynamic_cast<TPluginType*>( ppp.plugin )) != nullptr )
343 break;
344
345 return cast;
346 }
347
348}; // class PluginContainer
349
350} // namespace [alib::lang]
351
352#endif // HPP_ALIB_LANG_PLUGINS
353
void RemovePlugin(integer idx)
TPlugin * GetPlugin(integer number)
TPlugin PluginType
This exposes the template parameter pTPlugin to the outer world.
TPriorities GetPriority(integer number)
bool RemovePlugin(TPlugin *plugIn)
void InsertPlugin(TPlugin *plugin, lang::Responsibility responsibility=lang::Responsibility::KeepWithSender)
TPlugin * RemovePlugin(TPriorities priority)
TPriorities PrioritiesType
This exposes the template parameter pTPlugin to the outer world.
TPlugin * GetPlugin(TPriorities priority)
TPluginType * GetPluginTypeSafe()
std::vector< Slot > plugins
The plug-ins we have attached in descending priority order.
TPluginType * GetPluginTypeSafe(TPriorities priority)
Plugin(PrioritiesType pPriority)
TPlugin PluginType
This exposes the template parameter TPlugin to the outer world.
PrioritiesType GetPriority() const
PrioritiesType priority
The priority of this plug-in.
TPriorities PrioritiesType
This exposes the template parameter pTPlugin to the outer world.
#define ALIB_WARNING(...)
Definition alib.hpp:1268
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:223
#define ALIB_WARNINGS_IGNORE_UNUSED_LAMBDA_CAPTURE
Definition alib.hpp:817
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_STATIC_ASSERT(CondVariable, Cond, Message)
Definition alib.hpp:990
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_ASSERT_WARNING(cond,...)
Definition alib.hpp:1272
platform_specific integer
Definition integers.hpp:43
@ KeepWithSender
Keeps responsibility, e.g., when passing an object.
Type definition for elements of the list of plug-ins with their priority.