]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/dll/import_class.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / dll / import_class.hpp
1 // Copyright 2015-2018 Klemens D. Morgenstern
2 // Copyright Antony Polukhin, 2019-2022
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8 #ifndef BOOST_DLL_IMPORT_CLASS_HPP_
9 #define BOOST_DLL_IMPORT_CLASS_HPP_
10
11 /// \file boost/dll/import_class.hpp
12 /// \warning Extremely experimental! Requires C++11! Will change in next version of Boost! boost/dll/import_class.hpp is not included in boost/dll.hpp
13 /// \brief Contains the boost::dll::experimental::import_class function for importing classes.
14
15 #include <boost/dll/smart_library.hpp>
16 #include <boost/dll/import_mangled.hpp>
17 #include <memory>
18
19 #if (__cplusplus < 201103L) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201103L)
20 # error This file requires C++11 at least!
21 #endif
22
23 #ifdef BOOST_HAS_PRAGMA_ONCE
24 # pragma once
25 #endif
26
27 namespace boost { namespace dll { namespace experimental {
28
29 namespace detail
30 {
31
32 template<typename T>
33 struct deleter
34 {
35 destructor<T> dtor;
36 bool use_deleting;
37
38 deleter(const destructor<T> & dtor, bool use_deleting = false) :
39 dtor(dtor), use_deleting(use_deleting) {}
40
41 void operator()(T*t)
42 {
43 if (use_deleting)
44 dtor.call_deleting(t);
45 else
46 {
47 dtor.call_standard(t);
48 //the thing is actually an array, so delete[]
49 auto p = reinterpret_cast<char*>(t);
50 delete [] p;
51 }
52 }
53 };
54
55 template<class T, class = void>
56 struct mem_fn_call_proxy;
57
58 template<class Class, class U>
59 struct mem_fn_call_proxy<Class, boost::dll::experimental::detail::mangled_library_mem_fn<Class, U>>
60 {
61 typedef boost::dll::experimental::detail::mangled_library_mem_fn<Class, U> mem_fn_t;
62 Class* t;
63 mem_fn_t & mem_fn;
64
65 mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
66 mem_fn_call_proxy(const mem_fn_call_proxy & ) = delete;
67 mem_fn_call_proxy(Class * t, mem_fn_t & mem_fn)
68 : t(t), mem_fn(mem_fn) {}
69
70 template<typename ...Args>
71 auto operator()(Args&&...args) const
72 {
73 return mem_fn(t, std::forward<Args>(args)...);
74 }
75
76 };
77
78 template<class T, class Return, class ...Args>
79 struct mem_fn_call_proxy<T, Return(Args...)>
80 {
81 T* t;
82 const std::string &name;
83 smart_library &_lib;
84
85 mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
86 mem_fn_call_proxy(const mem_fn_call_proxy&) = delete;
87 mem_fn_call_proxy(T *t, const std::string &name, smart_library & _lib)
88 : t(t), name(name), _lib(_lib) {};
89
90 Return operator()(Args...args) const
91 {
92 auto f = _lib.get_mem_fn<T, Return(Args...)>(name);
93 return (t->*f)(static_cast<Args>(args)...);
94 }
95 };
96
97 }
98
99 template<typename T>
100 class imported_class;
101
102 template<typename T, typename ... Args> imported_class<T>
103 import_class(const smart_library& lib, Args...args);
104 template<typename T, typename ... Args> imported_class<T>
105 import_class(const smart_library& lib, const std::string & alias_name, Args...args);
106 template<typename T, typename ... Args> imported_class<T>
107 import_class(const smart_library& lib, std::size_t size, Args...args);
108 template<typename T, typename ... Args> imported_class<T>
109 import_class(const smart_library& lib, std::size_t size,
110 const std::string & alias_name, Args...args);
111
112
113 /*! This class represents an imported class.
114 *
115 * \note It must be constructed via \ref boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
116 *
117 * \tparam The type or type-alias of the imported class.
118 */
119 template<typename T>
120 class imported_class
121 {
122 smart_library _lib;
123 std::unique_ptr<T, detail::deleter<T>> _data;
124 bool _is_allocating;
125 std::size_t _size;
126 const std::type_info& _ti;
127
128 template<typename ... Args>
129 inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, Args ... args);
130 template<typename ... Args>
131 inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, std::size_t size, Args...args);
132
133 template<typename ...Args>
134 imported_class(detail::sequence<Args...> *, const smart_library& lib, Args...args);
135
136 template<typename ...Args>
137 imported_class(detail::sequence<Args...> *, const smart_library& lib, std::size_t size, Args...args);
138
139 template<typename ...Args>
140 imported_class(detail::sequence<Args...> *, smart_library&& lib, Args...args);
141
142 template<typename ...Args>
143 imported_class(detail::sequence<Args...> *, smart_library&& lib, std::size_t size, Args...args);
144 public:
145 //alias to construct with explicit parameter list
146 template<typename ...Args>
147 static imported_class<T> make(smart_library&& lib, Args...args)
148 {
149 typedef detail::sequence<Args...> *seq;
150 return imported_class(seq(), boost::move(lib), static_cast<Args>(args)...);
151 }
152
153 template<typename ...Args>
154 static imported_class<T> make(smart_library&& lib, std::size_t size, Args...args)
155 {
156 typedef detail::sequence<Args...> *seq;
157 return imported_class(seq(), boost::move(lib), size, static_cast<Args>(args)...);
158 }
159 template<typename ...Args>
160 static imported_class<T> make(const smart_library& lib, Args...args)
161 {
162 typedef detail::sequence<Args...> *seq;
163 return imported_class(seq(), lib, static_cast<Args>(args)...);
164 }
165
166 template<typename ...Args>
167 static imported_class<T> make(const smart_library& lib, std::size_t size, Args...args)
168 {
169 typedef detail::sequence<Args...> *seq;
170 return imported_class(seq(), lib, size, static_cast<Args>(args)...);
171 }
172
173 typedef imported_class<T> base_t;
174 ///Returns a pointer to the underlying class
175 T* get() {return _data.get();}
176 imported_class() = delete;
177
178 imported_class(imported_class&) = delete;
179 imported_class(imported_class&&) = default; ///<Move constructor
180 imported_class& operator=(imported_class&) = delete;
181 imported_class& operator=(imported_class&&) = default; ///<Move assignmend
182
183 ///Check if the imported class is move-constructible
184 bool is_move_constructible() {return !_lib.symbol_storage().template get_constructor<T(T&&)> ().empty();}
185 ///Check if the imported class is move-assignable
186 bool is_move_assignable() {return !_lib.symbol_storage().template get_mem_fn<T, T&(T&&)> ("operator=").empty();}
187 ///Check if the imported class is copy-constructible
188 bool is_copy_constructible() {return !_lib.symbol_storage().template get_constructor<T(const T&)>().empty();}
189 ///Check if the imported class is copy-assignable
190 bool is_copy_assignable() {return !_lib.symbol_storage().template get_mem_fn<T, T&(const T&)>("operator=").empty();}
191
192 imported_class<T> copy() const; ///<Invoke the copy constructor. \attention Undefined behaviour if the imported object is not copy constructible.
193 imported_class<T> move(); ///<Invoke the move constructor. \attention Undefined behaviour if the imported object is not move constructible.
194
195 ///Invoke the copy assignment. \attention Undefined behaviour if the imported object is not copy assignable.
196 void copy_assign(const imported_class<T> & lhs) const;
197 ///Invoke the move assignment. \attention Undefined behaviour if the imported object is not move assignable.
198 void move_assign( imported_class<T> & lhs);
199
200 ///Check if the class is loaded.
201 explicit operator bool() const {return _data;}
202
203 ///Get a const reference to the std::type_info.
204 const std::type_info& get_type_info() {return _ti;};
205
206 /*! Call a member function. This returns a proxy to the function.
207 * The proxy mechanic mechanic is necessary, so the signaute can be passed.
208 *
209 * \b Example
210 *
211 * \code
212 * im_class.call<void(const char*)>("function_name")("MyString");
213 * \endcode
214 */
215 template<class Signature>
216 const detail::mem_fn_call_proxy<T, Signature> call(const std::string& name)
217 {
218 return detail::mem_fn_call_proxy<T, Signature>(_data.get(), name, _lib);
219 }
220 /*! Call a qualified member function, i.e. const and or volatile.
221 *
222 * \b Example
223 *
224 * \code
225 * im_class.call<const type_alias, void(const char*)>("function_name")("MyString");
226 * \endcode
227 */
228 template<class Tin, class Signature, class = boost::enable_if<detail::unqalified_is_same<T, Tin>>>
229 const detail::mem_fn_call_proxy<Tin, Signature> call(const std::string& name)
230 {
231 return detail::mem_fn_call_proxy<Tin, Signature>(_data.get(), name, _lib);
232 }
233 ///Overload of ->* for an imported method.
234 template<class Tin, class T2>
235 const detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>
236 operator->*(detail::mangled_library_mem_fn<Tin, T2>& mn)
237 {
238 return detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>(_data.get(), mn);
239 }
240
241 ///Import a method of the class.
242 template <class ...Args>
243 typename boost::dll::experimental::detail::mangled_import_type<boost::dll::experimental::detail::sequence<T, Args...>>::type
244 import(const std::string & name)
245 {
246 return boost::dll::experimental::import_mangled<T, Args...>(_lib, name);
247 }
248 };
249
250
251
252 //helper function, uses the allocating
253 template<typename T>
254 template<typename ... Args>
255 inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, Args ... args)
256 {
257 constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
258 destructor<T> dtor = lib.get_destructor <T>();
259
260 if (!ctor.has_allocating() || !dtor.has_deleting())
261 {
262 boost::dll::fs::error_code ec;
263
264 ec = boost::dll::fs::make_error_code(
265 boost::dll::fs::errc::bad_file_descriptor
266 );
267
268 // report_error() calls dlsym, do not use it here!
269 boost::throw_exception(
270 boost::dll::fs::system_error(
271 ec, "boost::dll::detail::make_data() failed: no allocating ctor or dtor was found"
272 )
273 );
274 }
275
276 return std::unique_ptr<T, detail::deleter<T>> (
277 ctor.call_allocating(static_cast<Args>(args)...),
278 detail::deleter<T>(dtor, false /* not deleting dtor*/));
279 }
280
281 //helper function, using the standard
282 template<typename T>
283 template<typename ... Args>
284 inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, std::size_t size, Args...args)
285 {
286 constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
287 destructor<T> dtor = lib.get_destructor <T>();
288
289 if (!ctor.has_standard() || !dtor.has_standard())
290 {
291 boost::dll::fs::error_code ec;
292
293 ec = boost::dll::fs::make_error_code(
294 boost::dll::fs::errc::bad_file_descriptor
295 );
296
297 // report_error() calls dlsym, do not use it here!
298 boost::throw_exception(
299 boost::dll::fs::system_error(
300 ec, "boost::dll::detail::make_data() failed: no regular ctor or dtor was found"
301 )
302 );
303 }
304
305 T *data = reinterpret_cast<T*>(new char[size]);
306
307 ctor.call_standard(data, static_cast<Args>(args)...);
308
309 return std::unique_ptr<T, detail::deleter<T>> (
310 reinterpret_cast<T*>(data),
311 detail::deleter<T>(dtor, false /* not deleting dtor*/));
312
313 }
314
315
316 template<typename T>
317 template<typename ...Args>
318 imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, Args...args)
319 : _lib(lib),
320 _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
321 _is_allocating(false),
322 _size(0),
323 _ti(lib.get_type_info<T>())
324 {
325
326 }
327
328 template<typename T>
329 template<typename ...Args>
330 imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, std::size_t size, Args...args)
331 : _lib(lib),
332 _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
333 _is_allocating(true),
334 _size(size),
335 _ti(lib.get_type_info<T>())
336 {
337
338 }
339
340 template<typename T>
341 template<typename ...Args>
342 imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, Args...args)
343 : _lib(boost::move(lib)),
344 _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
345 _is_allocating(false),
346 _size(0),
347 _ti(lib.get_type_info<T>())
348 {
349
350 }
351
352 template<typename T>
353 template<typename ...Args>
354 imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, std::size_t size, Args...args)
355 : _lib(boost::move(lib)),
356 _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
357 _is_allocating(true),
358 _size(size),
359 _ti(lib.get_type_info<T>())
360 {
361
362 }
363
364 template<typename T>
365 inline imported_class<T> boost::dll::experimental::imported_class<T>::copy() const
366 {
367 if (this->_is_allocating)
368 return imported_class<T>::template make<const T&>(_lib, *_data);
369 else
370 return imported_class<T>::template make<const T&>(_lib, _size, *_data);
371 }
372
373 template<typename T>
374 inline imported_class<T> boost::dll::experimental::imported_class<T>::move()
375 {
376 if (this->_is_allocating)
377 return imported_class<T>::template make<T&&>(_lib, *_data);
378 else
379 return imported_class<T>::template make<T&&>(_lib, _size, *_data);
380 }
381
382 template<typename T>
383 inline void boost::dll::experimental::imported_class<T>::copy_assign(const imported_class<T>& lhs) const
384 {
385 this->call<T&(const T&)>("operator=")(*lhs._data);
386 }
387
388 template<typename T>
389 inline void boost::dll::experimental::imported_class<T>::move_assign(imported_class<T>& lhs)
390 {
391 this->call<T&(T&&)>("operator=")(static_cast<T&&>(*lhs._data));
392 }
393
394
395
396 /*!
397 * Returns an instance of \ref imported_class which allows to call or import more functions.
398 * It takes a copy of the smart_libray, so no added type_aliases will be visible,
399 * for the object.
400 *
401 * Few compilers do implement an allocating constructor, which allows the construction
402 * of the class without knowing the size. That is not portable, so the actual size of the class
403 * shall always be provided.
404 *
405 * \b Example:
406 *
407 * \code
408 * auto import_class<class type_alias, const std::string&, std::size_t>(lib, "class_name", 20, "param1", 42);
409 * \endcode
410 *
411 * In this example we construct an instance of the class "class_name" with the size 20, which has "type_alias" as an alias,
412 * through a constructor which takes a const-ref of std::string and an std::size_t parameter.
413 *
414 * \tparam T Class type or alias
415 * \tparam Args Constructor argument list.
416 * \param lib Path to shared library or shared library to load function from.
417 * \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*.
418 * \param mode An mode that will be used on library load.
419 *
420 * \return class object.
421 *
422 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
423 * Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
424 */
425 template<typename T, typename ... Args> imported_class<T>
426 import_class(const smart_library& lib_, std::size_t size, Args...args)
427 {
428 smart_library lib(lib_);
429
430 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
431 }
432
433 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
434 template<typename T, typename ... Args> imported_class<T>
435 import_class(const smart_library& lib_, Args...args)
436 {
437 smart_library lib(lib_);
438 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
439 }
440
441 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
442 template<typename T, typename ... Args> imported_class<T>
443 import_class(const smart_library& lib_, const std::string & alias_name, Args...args)
444 {
445 smart_library lib(lib_);
446 lib.add_type_alias<T>(alias_name);
447 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
448 }
449
450 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
451 template<typename T, typename ... Args> imported_class<T>
452 import_class(const smart_library& lib_, std::size_t size, const std::string & alias_name, Args...args)
453 {
454 smart_library lib(lib_);
455
456 lib.add_type_alias<T>(alias_name);
457 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
458 }
459
460 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
461 template<typename T, typename ... Args> imported_class<T>
462 import_class(const smart_library& lib_, const std::string & alias_name, std::size_t size, Args...args)
463 {
464 smart_library lib(lib_);
465
466 lib.add_type_alias<T>(alias_name);
467 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
468 }
469
470 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
471 template<typename T, typename ... Args> imported_class<T>
472 import_class(smart_library && lib, Args...args)
473 {
474 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
475 }
476
477 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
478 template<typename T, typename ... Args> imported_class<T>
479 import_class(smart_library && lib, const std::string & alias_name, Args...args)
480 {
481 lib.add_type_alias<T>(alias_name);
482 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
483 }
484
485 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
486 template<typename T, typename ... Args> imported_class<T>
487 import_class(smart_library && lib, std::size_t size, Args...args)
488 {
489 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
490 }
491
492 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
493 template<typename T, typename ... Args> imported_class<T>
494 import_class(smart_library && lib, std::size_t size, const std::string & alias_name, Args...args)
495 {
496 lib.add_type_alias<T>(alias_name);
497 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
498 }
499
500 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
501 template<typename T, typename ... Args> imported_class<T>
502 import_class(smart_library && lib, const std::string & alias_name, std::size_t size, Args...args)
503 {
504 lib.add_type_alias<T>(alias_name);
505 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
506 }
507
508
509
510 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
511 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
512 */
513
514 template<typename T, typename ... Args> imported_class<T>
515 import_class(smart_library & lib, Args...args)
516 {
517 return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
518 }
519
520 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
521 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
522 */
523 template<typename T, typename ... Args> imported_class<T>
524 import_class(smart_library & lib, const std::string & alias_name, Args...args)
525 {
526 lib.add_type_alias<T>(alias_name);
527 return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
528 }
529
530 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
531 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
532 */
533 template<typename T, typename ... Args> imported_class<T>
534 import_class(smart_library & lib, std::size_t size, Args...args)
535 {
536 return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
537 }
538
539 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
540 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
541 */
542 template<typename T, typename ... Args> imported_class<T>
543 import_class(smart_library & lib, std::size_t size, const std::string & alias_name, Args...args)
544 {
545 lib.add_type_alias<T>(alias_name);
546 return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
547 }
548
549 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
550 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
551 */
552 template<typename T, typename ... Args> imported_class<T>
553 import_class(smart_library & lib, const std::string & alias_name, std::size_t size, Args...args)
554 {
555 lib.add_type_alias<T>(alias_name);
556 return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
557 }
558
559 }
560 }
561 }
562
563
564
565 #endif /* BOOST_DLL_IMPORT_CLASS_HPP_ */