Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:37:32

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