Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:44

0001 // Copyright 2015-2018 Klemens D. Morgenstern
0002 // Copyright Antony Polukhin, 2019-2023
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE_1_0.txt
0006 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 #ifndef BOOST_DLL_IMPORT_CLASS_HPP_
0009 #define BOOST_DLL_IMPORT_CLASS_HPP_
0010 
0011 /// \file boost/dll/import_class.hpp
0012 /// \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
0013 /// \brief Contains the boost::dll::experimental::import_class function for importing classes.
0014 
0015 #include <boost/dll/smart_library.hpp>
0016 #include <boost/dll/import_mangled.hpp>
0017 #include <memory>
0018 
0019 #if (__cplusplus < 201103L) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201103L)
0020 #  error This file requires C++11 at least!
0021 #endif
0022 
0023 #ifdef BOOST_HAS_PRAGMA_ONCE
0024 # pragma once
0025 #endif
0026 
0027 namespace boost { namespace dll { namespace experimental {
0028 
0029 namespace detail
0030 {
0031 
0032 template<typename T>
0033 struct deleter
0034 {
0035     destructor<T> dtor;
0036     bool use_deleting;
0037 
0038     deleter(const destructor<T> & dtor, bool use_deleting = false) :
0039         dtor(dtor), use_deleting(use_deleting) {}
0040 
0041     void operator()(T*t)
0042     {
0043         if (use_deleting)
0044             dtor.call_deleting(t);
0045         else
0046         {
0047             dtor.call_standard(t);
0048             //the thing is actually an array, so delete[]
0049             auto p = reinterpret_cast<char*>(t);
0050             delete [] p;
0051         }
0052     }
0053 };
0054 
0055 template<class T, class = void>
0056 struct mem_fn_call_proxy;
0057 
0058 template<class Class, class U>
0059 struct mem_fn_call_proxy<Class, boost::dll::experimental::detail::mangled_library_mem_fn<Class, U>>
0060 {
0061     typedef boost::dll::experimental::detail::mangled_library_mem_fn<Class, U> mem_fn_t;
0062     Class* t;
0063     mem_fn_t & mem_fn;
0064 
0065     mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
0066     mem_fn_call_proxy(const mem_fn_call_proxy & ) = delete;
0067     mem_fn_call_proxy(Class * t, mem_fn_t & mem_fn)
0068                 : t(t), mem_fn(mem_fn) {}
0069 
0070     template<typename ...Args>
0071     auto operator()(Args&&...args) const
0072     {
0073         return mem_fn(t, std::forward<Args>(args)...);
0074     }
0075 
0076 };
0077 
0078 template<class T, class Return, class ...Args>
0079 struct mem_fn_call_proxy<T, Return(Args...)>
0080 {
0081     T* t;
0082     const std::string &name;
0083     smart_library &_lib;
0084 
0085     mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
0086     mem_fn_call_proxy(const mem_fn_call_proxy&) = delete;
0087     mem_fn_call_proxy(T *t, const std::string &name, smart_library & _lib)
0088         : t(t), name(name), _lib(_lib) {};
0089 
0090     Return operator()(Args...args) const
0091     {
0092         auto f = _lib.get_mem_fn<T, Return(Args...)>(name);
0093         return (t->*f)(static_cast<Args>(args)...);
0094     }
0095 };
0096 
0097 }
0098 
0099 template<typename T>
0100 class imported_class;
0101 
0102 template<typename T, typename ... Args> imported_class<T>
0103 import_class(const smart_library& lib, Args...args);
0104 template<typename T, typename ... Args> imported_class<T>
0105 import_class(const smart_library& lib, const std::string & alias_name, Args...args);
0106 template<typename T, typename ... Args> imported_class<T>
0107 import_class(const smart_library& lib, std::size_t size, Args...args);
0108 template<typename T, typename ... Args> imported_class<T>
0109 import_class(const smart_library& lib, std::size_t size,
0110              const std::string & alias_name, Args...args);
0111 
0112 
0113 /*! This class represents an imported class.
0114  *
0115  * \note It must be constructed via \ref boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0116  *
0117  * \tparam The type or type-alias of the imported class.
0118  */
0119 template<typename T>
0120 class imported_class
0121 {
0122     smart_library _lib;
0123     std::unique_ptr<T, detail::deleter<T>> _data;
0124     bool _is_allocating;
0125     std::size_t _size;
0126     const std::type_info& _ti;
0127 
0128     template<typename ... Args>
0129     inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, Args ... args);
0130     template<typename ... Args>
0131     inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, std::size_t size, Args...args);
0132 
0133     template<typename ...Args>
0134     imported_class(detail::sequence<Args...> *, const smart_library& lib,  Args...args);
0135 
0136     template<typename ...Args>
0137     imported_class(detail::sequence<Args...> *, const smart_library& lib, std::size_t size,  Args...args);
0138 
0139     template<typename ...Args>
0140     imported_class(detail::sequence<Args...> *, smart_library&& lib,  Args...args);
0141 
0142     template<typename ...Args>
0143     imported_class(detail::sequence<Args...> *, smart_library&& lib, std::size_t size,  Args...args);
0144 public:
0145     //alias to construct with explicit parameter list
0146     template<typename ...Args>
0147     static imported_class<T> make(smart_library&& lib,  Args...args)
0148     {
0149         typedef detail::sequence<Args...> *seq;
0150         return imported_class(seq(), boost::move(lib), static_cast<Args>(args)...);
0151     }
0152 
0153     template<typename ...Args>
0154     static imported_class<T> make(smart_library&& lib, std::size_t size,  Args...args)
0155     {
0156         typedef detail::sequence<Args...> *seq;
0157         return imported_class(seq(), boost::move(lib), size, static_cast<Args>(args)...);
0158     }
0159     template<typename ...Args>
0160     static imported_class<T> make(const smart_library& lib,  Args...args)
0161     {
0162         typedef detail::sequence<Args...> *seq;
0163         return imported_class(seq(), lib, static_cast<Args>(args)...);
0164     }
0165 
0166     template<typename ...Args>
0167     static imported_class<T> make(const smart_library& lib, std::size_t size,  Args...args)
0168     {
0169         typedef detail::sequence<Args...> *seq;
0170         return imported_class(seq(), lib, size, static_cast<Args>(args)...);
0171     }
0172 
0173     typedef imported_class<T> base_t;
0174     ///Returns a pointer to the underlying class
0175     T* get() {return _data.get();}
0176     imported_class() = delete;
0177 
0178     imported_class(imported_class&) = delete;
0179     imported_class(imported_class&&) = default;                ///<Move constructor
0180     imported_class& operator=(imported_class&) = delete;
0181     imported_class& operator=(imported_class&&) = default;  ///<Move assignmend
0182 
0183     ///Check if the imported class is move-constructible
0184     bool is_move_constructible() {return !_lib.symbol_storage().template get_constructor<T(T&&)>     ().empty();}
0185     ///Check if the imported class is move-assignable
0186     bool is_move_assignable()    {return !_lib.symbol_storage().template get_mem_fn<T, T&(T&&)>     ("operator=").empty();}
0187     ///Check if the imported class is copy-constructible
0188     bool is_copy_constructible() {return !_lib.symbol_storage().template get_constructor<T(const T&)>().empty();}
0189     ///Check if the imported class is copy-assignable
0190     bool is_copy_assignable()    {return !_lib.symbol_storage().template get_mem_fn<T, T&(const T&)>("operator=").empty();}
0191 
0192     imported_class<T> copy() const; ///<Invoke the copy constructor. \attention Undefined behaviour if the imported object is not copy constructible.
0193     imported_class<T> move();       ///<Invoke the move constructor. \attention Undefined behaviour if the imported object is not move constructible.
0194 
0195     ///Invoke the copy assignment. \attention Undefined behaviour if the imported object is not copy assignable.
0196     void copy_assign(const imported_class<T> & lhs) const;
0197     ///Invoke the move assignment. \attention Undefined behaviour if the imported object is not move assignable.
0198     void move_assign(      imported_class<T> & lhs);
0199 
0200     ///Check if the class is loaded.
0201     explicit operator bool() const  {return _data;}
0202 
0203     ///Get a const reference to the std::type_info.
0204     const std::type_info& get_type_info() {return _ti;};
0205 
0206     /*! Call a member function. This returns a proxy to the function.
0207      * The proxy mechanic mechanic is necessary, so the signaute can be passed.
0208      *
0209      * \b Example
0210      *
0211      * \code
0212      * im_class.call<void(const char*)>("function_name")("MyString");
0213      * \endcode
0214      */
0215     template<class Signature>
0216     const detail::mem_fn_call_proxy<T, Signature> call(const std::string& name)
0217     {
0218         return detail::mem_fn_call_proxy<T, Signature>(_data.get(), name, _lib);
0219     }
0220     /*! Call a qualified member function, i.e. const and or volatile.
0221      *
0222      * \b Example
0223      *
0224      * \code
0225      * im_class.call<const type_alias, void(const char*)>("function_name")("MyString");
0226      * \endcode
0227      */
0228     template<class Tin, class Signature, class = boost::enable_if<detail::unqalified_is_same<T, Tin>>>
0229     const detail::mem_fn_call_proxy<Tin, Signature> call(const std::string& name)
0230     {
0231         return detail::mem_fn_call_proxy<Tin, Signature>(_data.get(), name, _lib);
0232     }
0233     ///Overload of ->* for an imported method.
0234     template<class Tin, class T2>
0235     const detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>
0236             operator->*(detail::mangled_library_mem_fn<Tin, T2>& mn)
0237     {
0238         return detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>(_data.get(), mn);
0239     }
0240 
0241     ///Import a method of the class.
0242     template <class ...Args>
0243     typename boost::dll::experimental::detail::mangled_import_type<boost::dll::experimental::detail::sequence<T, Args...>>::type
0244     import(const std::string & name)
0245     {
0246         return boost::dll::experimental::import_mangled<T, Args...>(_lib, name);
0247     }
0248 };
0249 
0250 
0251 
0252 //helper function, uses the allocating
0253 template<typename T>
0254 template<typename ... Args>
0255 inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, Args ... args)
0256 {
0257     constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
0258     destructor<T>           dtor = lib.get_destructor <T>();
0259 
0260     if (!ctor.has_allocating() || !dtor.has_deleting())
0261     {
0262         boost::dll::fs::error_code ec;
0263 
0264         ec = boost::dll::fs::make_error_code(
0265             boost::dll::fs::errc::bad_file_descriptor
0266         );
0267 
0268         // report_error() calls dlsym, do not use it here!
0269         boost::throw_exception(
0270             boost::dll::fs::system_error(
0271                 ec, "boost::dll::detail::make_data() failed: no allocating ctor or dtor was found"
0272             )
0273         );
0274     }
0275 
0276      return std::unique_ptr<T, detail::deleter<T>> (
0277             ctor.call_allocating(static_cast<Args>(args)...),
0278             detail::deleter<T>(dtor, false /* not deleting dtor*/));
0279 }
0280 
0281 //helper function, using the standard
0282 template<typename T>
0283 template<typename ... Args>
0284 inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, std::size_t size, Args...args)
0285 {
0286     constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
0287     destructor<T>           dtor = lib.get_destructor <T>();
0288 
0289     if (!ctor.has_standard() || !dtor.has_standard())
0290     {
0291         boost::dll::fs::error_code ec;
0292 
0293         ec = boost::dll::fs::make_error_code(
0294             boost::dll::fs::errc::bad_file_descriptor
0295         );
0296 
0297         // report_error() calls dlsym, do not use it here!
0298         boost::throw_exception(
0299             boost::dll::fs::system_error(
0300                 ec, "boost::dll::detail::make_data() failed: no regular ctor or dtor was found"
0301             )
0302         );
0303     }
0304 
0305     T *data = reinterpret_cast<T*>(new char[size]);
0306 
0307     ctor.call_standard(data, static_cast<Args>(args)...);
0308 
0309     return std::unique_ptr<T, detail::deleter<T>> (
0310             reinterpret_cast<T*>(data),
0311             detail::deleter<T>(dtor, false /* not deleting dtor*/));
0312 
0313 }
0314 
0315 
0316 template<typename T>
0317 template<typename ...Args>
0318 imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib,  Args...args)
0319     : _lib(lib),
0320       _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
0321       _is_allocating(false),
0322       _size(0),
0323       _ti(lib.get_type_info<T>())
0324 {
0325 
0326 }
0327 
0328 template<typename T>
0329 template<typename ...Args>
0330 imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, std::size_t size,  Args...args)
0331     : _lib(lib),
0332       _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
0333       _is_allocating(true),
0334       _size(size),
0335       _ti(lib.get_type_info<T>())
0336 {
0337 
0338 }
0339 
0340 template<typename T>
0341 template<typename ...Args>
0342 imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib,  Args...args)
0343     : _lib(boost::move(lib)),
0344       _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
0345       _is_allocating(false),
0346       _size(0),
0347       _ti(lib.get_type_info<T>())
0348 {
0349 
0350 }
0351 
0352 template<typename T>
0353 template<typename ...Args>
0354 imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, std::size_t size,  Args...args)
0355     : _lib(boost::move(lib)),
0356       _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
0357       _is_allocating(true),
0358       _size(size),
0359       _ti(lib.get_type_info<T>())
0360 {
0361 
0362 }
0363 
0364 template<typename T>
0365 inline imported_class<T> boost::dll::experimental::imported_class<T>::copy() const
0366 {
0367     if (this->_is_allocating)
0368         return imported_class<T>::template make<const T&>(_lib, *_data);
0369     else
0370         return imported_class<T>::template make<const T&>(_lib, _size, *_data);
0371 }
0372 
0373 template<typename T>
0374 inline imported_class<T> boost::dll::experimental::imported_class<T>::move()
0375 {
0376     if (this->_is_allocating)
0377         return imported_class<T>::template make<T&&>(_lib, *_data);
0378     else
0379         return imported_class<T>::template make<T&&>(_lib, _size, *_data);
0380 }
0381 
0382 template<typename T>
0383 inline void boost::dll::experimental::imported_class<T>::copy_assign(const imported_class<T>& lhs) const
0384 {
0385     this->call<T&(const T&)>("operator=")(*lhs._data);
0386 }
0387 
0388 template<typename T>
0389 inline void boost::dll::experimental::imported_class<T>::move_assign(imported_class<T>& lhs)
0390 {
0391     this->call<T&(T&&)>("operator=")(static_cast<T&&>(*lhs._data));
0392 }
0393 
0394 
0395 
0396 /*!
0397 * Returns an instance of \ref imported_class which allows to call or import more functions.
0398 * It takes a copy of the smart_libray, so no added type_aliases will be visible,
0399 * for the object.
0400 *
0401 * Few compilers do implement an allocating constructor, which allows the construction
0402 * of the class without knowing the size. That is not portable, so the actual size of the class
0403 * shall always be provided.
0404 *
0405 * \b Example:
0406 *
0407 * \code
0408 * auto import_class<class type_alias, const std::string&, std::size_t>(lib, "class_name", 20, "param1", 42);
0409 * \endcode
0410 *
0411 * In this example we construct an instance of the class "class_name" with the size 20, which has "type_alias" as an alias,
0412 * through a constructor which takes a const-ref of std::string and an std::size_t parameter.
0413 *
0414 * \tparam T Class type or alias
0415 * \tparam Args Constructor argument list.
0416 * \param lib Path to shared library or shared library to load function from.
0417 * \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*.
0418 * \param mode An mode that will be used on library load.
0419 *
0420 * \return class object.
0421 *
0422 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
0423 *       Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
0424 */
0425 template<typename T, typename ... Args> imported_class<T>
0426 import_class(const smart_library& lib_, std::size_t size, Args...args)
0427 {
0428     smart_library lib(lib_);
0429 
0430     return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
0431 }
0432 
0433 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0434 template<typename T, typename ... Args> imported_class<T>
0435 import_class(const smart_library& lib_, Args...args)
0436 {
0437     smart_library lib(lib_);
0438     return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
0439 }
0440 
0441 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0442 template<typename T, typename ... Args> imported_class<T>
0443 import_class(const smart_library& lib_, const std::string & alias_name, Args...args)
0444 {
0445     smart_library lib(lib_);
0446     lib.add_type_alias<T>(alias_name);
0447     return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
0448 }
0449 
0450 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0451 template<typename T, typename ... Args> imported_class<T>
0452 import_class(const smart_library& lib_, std::size_t size, const std::string & alias_name, Args...args)
0453 {
0454     smart_library lib(lib_);
0455 
0456     lib.add_type_alias<T>(alias_name);
0457     return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
0458 }
0459 
0460 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0461 template<typename T, typename ... Args> imported_class<T>
0462 import_class(const smart_library& lib_, const std::string & alias_name, std::size_t size, Args...args)
0463 {
0464     smart_library lib(lib_);
0465 
0466     lib.add_type_alias<T>(alias_name);
0467     return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
0468 }
0469 
0470 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0471 template<typename T, typename ... Args> imported_class<T>
0472 import_class(smart_library && lib, Args...args)
0473 {
0474     return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
0475 }
0476 
0477 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0478 template<typename T, typename ... Args> imported_class<T>
0479 import_class(smart_library && lib, const std::string & alias_name, Args...args)
0480 {
0481     lib.add_type_alias<T>(alias_name);
0482     return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
0483 }
0484 
0485 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0486 template<typename T, typename ... Args> imported_class<T>
0487 import_class(smart_library && lib, std::size_t size, Args...args)
0488 {
0489     return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
0490 }
0491 
0492 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0493 template<typename T, typename ... Args> imported_class<T>
0494 import_class(smart_library && lib, std::size_t size, const std::string & alias_name, Args...args)
0495 {
0496     lib.add_type_alias<T>(alias_name);
0497     return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
0498 }
0499 
0500 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0501 template<typename T, typename ... Args> imported_class<T>
0502 import_class(smart_library && lib, const std::string & alias_name, std::size_t size, Args...args)
0503 {
0504     lib.add_type_alias<T>(alias_name);
0505     return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
0506 }
0507 
0508 
0509 
0510 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0511  * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
0512  */
0513 
0514 template<typename T, typename ... Args> imported_class<T>
0515 import_class(smart_library & lib, Args...args)
0516 {
0517     return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
0518 }
0519 
0520 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0521  * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
0522  */
0523 template<typename T, typename ... Args> imported_class<T>
0524 import_class(smart_library & lib, const std::string & alias_name, Args...args)
0525 {
0526     lib.add_type_alias<T>(alias_name);
0527     return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
0528 }
0529 
0530 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0531  * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
0532  */
0533 template<typename T, typename ... Args> imported_class<T>
0534 import_class(smart_library & lib, std::size_t size, Args...args)
0535 {
0536     return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
0537 }
0538 
0539 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0540  * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
0541  */
0542 template<typename T, typename ... Args> imported_class<T>
0543 import_class(smart_library & lib, std::size_t size, const std::string & alias_name, Args...args)
0544 {
0545     lib.add_type_alias<T>(alias_name);
0546     return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
0547 }
0548 
0549 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
0550  * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
0551  */
0552 template<typename T, typename ... Args> imported_class<T>
0553 import_class(smart_library & lib, const std::string & alias_name, std::size_t size, Args...args)
0554 {
0555     lib.add_type_alias<T>(alias_name);
0556     return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
0557 }
0558 
0559 }
0560 }
0561 }
0562 
0563 
0564 
0565 #endif /* BOOST_DLL_IMPORT_CLASS_HPP_ */