1 // Copyright 2015-2016 Klemens D. Morgenstern
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef BOOST_DLL_IMPORT_CLASS_HPP_
8 #define BOOST_DLL_IMPORT_CLASS_HPP_
10 #include <boost/dll/smart_library.hpp>
11 #include <boost/dll/import_mangled.hpp>
14 #ifdef BOOST_HAS_PRAGMA_ONCE
18 namespace boost { namespace dll { namespace experimental {
29 deleter(const destructor<T> & dtor, bool use_deleting = false) :
30 dtor(dtor), use_deleting(use_deleting) {}
35 dtor.call_deleting(t);
38 dtor.call_standard(t);
39 //the thing is actually an array, so delete[]
40 auto p = reinterpret_cast<char*>(t);
46 template<class T, class = void>
47 struct mem_fn_call_proxy;
49 template<class Class, class U>
50 struct mem_fn_call_proxy<Class, boost::dll::experimental::detail::mangled_library_mem_fn<Class, U>>
52 typedef boost::dll::experimental::detail::mangled_library_mem_fn<Class, U> mem_fn_t;
56 mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
57 mem_fn_call_proxy(const mem_fn_call_proxy & ) = delete;
58 mem_fn_call_proxy(Class * t, mem_fn_t & mem_fn)
59 : t(t), mem_fn(mem_fn) {}
61 template<typename ...Args>
62 auto operator()(Args&&...args) const
64 return mem_fn(t, std::forward<Args>(args)...);
69 template<class T, class Return, class ...Args>
70 struct mem_fn_call_proxy<T, Return(Args...)>
73 const std::string &name;
76 mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
77 mem_fn_call_proxy(const mem_fn_call_proxy&) = delete;
78 mem_fn_call_proxy(T *t, const std::string &name, smart_library & _lib)
79 : t(t), name(name), _lib(_lib) {};
81 Return operator()(Args...args) const
83 auto f = _lib.get_mem_fn<T, Return(Args...)>(name);
84 return (t->*f)(static_cast<Args>(args)...);
93 template<typename T, typename ... Args> imported_class<T>
94 import_class(const smart_library& lib, Args...args);
95 template<typename T, typename ... Args> imported_class<T>
96 import_class(const smart_library& lib, const std::string & alias_name, Args...args);
97 template<typename T, typename ... Args> imported_class<T>
98 import_class(const smart_library& lib, std::size_t size, Args...args);
99 template<typename T, typename ... Args> imported_class<T>
100 import_class(const smart_library& lib, std::size_t size,
101 const std::string & alias_name, Args...args);
104 /*! This class represents an imported class.
106 * \note It must be constructed via \ref boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
108 * \tparam The type or type-alias of the imported class.
114 std::unique_ptr<T, detail::deleter<T>> _data;
117 const std::type_info& _ti;
119 template<typename ... Args>
120 inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, Args ... args);
121 template<typename ... Args>
122 inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, std::size_t size, Args...args);
124 template<typename ...Args>
125 imported_class(detail::sequence<Args...> *, const smart_library& lib, Args...args);
127 template<typename ...Args>
128 imported_class(detail::sequence<Args...> *, const smart_library& lib, std::size_t size, Args...args);
130 template<typename ...Args>
131 imported_class(detail::sequence<Args...> *, smart_library&& lib, Args...args);
133 template<typename ...Args>
134 imported_class(detail::sequence<Args...> *, smart_library&& lib, std::size_t size, Args...args);
136 //alias to construct with explicit parameter list
137 template<typename ...Args>
138 static imported_class<T> make(smart_library&& lib, Args...args)
140 typedef detail::sequence<Args...> *seq;
141 return imported_class(seq(), boost::move(lib), static_cast<Args>(args)...);
144 template<typename ...Args>
145 static imported_class<T> make(smart_library&& lib, std::size_t size, Args...args)
147 typedef detail::sequence<Args...> *seq;
148 return imported_class(seq(), boost::move(lib), size, static_cast<Args>(args)...);
150 template<typename ...Args>
151 static imported_class<T> make(const smart_library& lib, Args...args)
153 typedef detail::sequence<Args...> *seq;
154 return imported_class(seq(), lib, static_cast<Args>(args)...);
157 template<typename ...Args>
158 static imported_class<T> make(const smart_library& lib, std::size_t size, Args...args)
160 typedef detail::sequence<Args...> *seq;
161 return imported_class(seq(), lib, size, static_cast<Args>(args)...);
164 typedef imported_class<T> base_t;
165 ///Returns a pointer to the underlying class
166 T* get() {return _data.get();}
167 imported_class() = delete;
169 imported_class(imported_class&) = delete;
170 imported_class(imported_class&&) = default; ///<Move constructor
171 imported_class& operator=(imported_class&) = delete;
172 imported_class& operator=(imported_class&&) = default; ///<Move assignmend
174 ///Check if the imported class is move-constructible
175 bool is_move_constructible() {return !_lib.symbol_storage().template get_constructor<T(T&&)> ().empty();}
176 ///Check if the imported class is move-assignable
177 bool is_move_assignable() {return !_lib.symbol_storage().template get_mem_fn<T, T&(T&&)> ("operator=").empty();}
178 ///Check if the imported class is copy-constructible
179 bool is_copy_constructible() {return !_lib.symbol_storage().template get_constructor<T(const T&)>().empty();}
180 ///Check if the imported class is copy-assignable
181 bool is_copy_assignable() {return !_lib.symbol_storage().template get_mem_fn<T, T&(const T&)>("operator=").empty();}
183 imported_class<T> copy() const; ///<Invoke the copy constructor. \attention Undefined behaviour if the imported object is not copy constructible.
184 imported_class<T> move(); ///<Invoke the move constructor. \attention Undefined behaviour if the imported object is not move constructible.
186 ///Invoke the copy assignment. \attention Undefined behaviour if the imported object is not copy assignable.
187 void copy_assign(const imported_class<T> & lhs) const;
188 ///Invoke the move assignment. \attention Undefined behaviour if the imported object is not move assignable.
189 void move_assign( imported_class<T> & lhs);
191 ///Check if the class is loaded.
192 explicit operator bool() const {return _data;}
194 ///Get a const reference to the std::type_info.
195 const std::type_info& get_type_info() {return _ti;};
197 /*! Call a member function. This returns a proxy to the function.
198 * The proxy mechanic mechanic is necessary, so the signaute can be passed.
203 * im_class.call<void(const char*)>("function_name")("MyString");
206 template<class Signature>
207 const detail::mem_fn_call_proxy<T, Signature> call(const std::string& name)
209 return detail::mem_fn_call_proxy<T, Signature>(_data.get(), name, _lib);
211 /*! Call a qualified member function, i.e. const and or volatile.
216 * im_class.call<const type_alias, void(const char*)>("function_name")("MyString");
219 template<class Tin, class Signature, class = boost::enable_if<detail::unqalified_is_same<T, Tin>>>
220 const detail::mem_fn_call_proxy<Tin, Signature> call(const std::string& name)
222 return detail::mem_fn_call_proxy<Tin, Signature>(_data.get(), name, _lib);
224 ///Overload of ->* for an imported method.
225 template<class Tin, class T2>
226 const detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>
227 operator->*(detail::mangled_library_mem_fn<Tin, T2>& mn)
229 return detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>(_data.get(), mn);
232 ///Import a method of the class.
233 template <class ...Args>
234 typename boost::dll::experimental::detail::mangled_import_type<boost::dll::experimental::detail::sequence<T, Args...>>::type
235 import(const std::string & name)
237 return boost::dll::experimental::import_mangled<T, Args...>(_lib, name);
243 //helper function, uses the allocating
245 template<typename ... Args>
246 inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, Args ... args)
248 constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
249 destructor<T> dtor = lib.get_destructor <T>();
251 if (!ctor.has_allocating() || !dtor.has_deleting())
253 boost::system::error_code ec;
255 ec = boost::system::error_code(
256 boost::system::errc::bad_file_descriptor,
257 boost::system::generic_category()
260 // report_error() calls dlsym, do not use it here!
261 boost::throw_exception(
262 boost::system::system_error(
263 ec, "boost::dll::detail::make_data() failed: no allocating ctor or dtor was found"
268 return std::unique_ptr<T, detail::deleter<T>> (
269 ctor.call_allocating(static_cast<Args>(args)...),
270 detail::deleter<T>(dtor, false /* not deleting dtor*/));
273 //helper function, using the standard
275 template<typename ... Args>
276 inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, std::size_t size, Args...args)
278 constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
279 destructor<T> dtor = lib.get_destructor <T>();
281 if (!ctor.has_standard() || !dtor.has_standard())
283 boost::system::error_code ec;
285 ec = boost::system::error_code(
286 boost::system::errc::bad_file_descriptor,
287 boost::system::generic_category()
290 // report_error() calls dlsym, do not use it here!
291 boost::throw_exception(
292 boost::system::system_error(
293 ec, "boost::dll::detail::make_data() failed: no regular ctor or dtor was found"
298 T *data = reinterpret_cast<T*>(new char[size]);
300 ctor.call_standard(data, static_cast<Args>(args)...);
302 return std::unique_ptr<T, detail::deleter<T>> (
303 reinterpret_cast<T*>(data),
304 detail::deleter<T>(dtor, false /* not deleting dtor*/));
310 template<typename ...Args>
311 imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, Args...args)
313 _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
314 _is_allocating(false),
316 _ti(lib.get_type_info<T>())
322 template<typename ...Args>
323 imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, std::size_t size, Args...args)
325 _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
326 _is_allocating(true),
328 _ti(lib.get_type_info<T>())
334 template<typename ...Args>
335 imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, Args...args)
336 : _lib(boost::move(lib)),
337 _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
338 _is_allocating(false),
340 _ti(lib.get_type_info<T>())
346 template<typename ...Args>
347 imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, std::size_t size, Args...args)
348 : _lib(boost::move(lib)),
349 _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
350 _is_allocating(true),
352 _ti(lib.get_type_info<T>())
358 inline imported_class<T> boost::dll::experimental::imported_class<T>::copy() const
360 if (this->_is_allocating)
361 return imported_class<T>::template make<const T&>(_lib, *_data);
363 return imported_class<T>::template make<const T&>(_lib, _size, *_data);
367 inline imported_class<T> boost::dll::experimental::imported_class<T>::move()
369 if (this->_is_allocating)
370 return imported_class<T>::template make<T&&>(_lib, *_data);
372 return imported_class<T>::template make<T&&>(_lib, _size, *_data);
376 inline void boost::dll::experimental::imported_class<T>::copy_assign(const imported_class<T>& lhs) const
378 this->call<T&(const T&)>("operator=")(*lhs._data);
382 inline void boost::dll::experimental::imported_class<T>::move_assign(imported_class<T>& lhs)
384 this->call<T&(T&&)>("operator=")(static_cast<T&&>(*lhs._data));
390 * Returns an instance of \ref imported_class which allows to call or import more functions.
391 * It takes a copy of the smart_libray, so no added type_aliases will be visible,
394 * Few compilers do implement an allocating constructor, which allows the construction
395 * of the class without knowing the size. That is not portable, so the actual size of the class
396 * shall always be provided.
401 * auto import_class<class type_alias, const std::string&, std::size_t>(lib, "class_name", 20, "param1", 42);
404 * In this example we construct an instance of the class "class_name" with the size 20, which has "type_alias" as an alias,
405 * through a constructor which takes a const-ref of std::string and an std::size_t parameter.
407 * \tparam T Class type or alias
408 * \tparam Args Constructor argument list.
409 * \param lib Path to shared library or shared library to load function from.
410 * \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*.
411 * \param mode An mode that will be used on library load.
413 * \return class object.
415 * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
416 * Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
418 template<typename T, typename ... Args> imported_class<T>
419 import_class(const smart_library& lib_, std::size_t size, Args...args)
421 smart_library lib(lib_);
423 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
426 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
427 template<typename T, typename ... Args> imported_class<T>
428 import_class(const smart_library& lib_, Args...args)
430 smart_library lib(lib_);
431 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
434 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
435 template<typename T, typename ... Args> imported_class<T>
436 import_class(const smart_library& lib_, const std::string & alias_name, Args...args)
438 smart_library lib(lib_);
439 lib.add_type_alias<T>(alias_name);
440 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
443 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
444 template<typename T, typename ... Args> imported_class<T>
445 import_class(const smart_library& lib_, std::size_t size, const std::string & alias_name, Args...args)
447 smart_library lib(lib_);
449 lib.add_type_alias<T>(alias_name);
450 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
453 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
454 template<typename T, typename ... Args> imported_class<T>
455 import_class(const smart_library& lib_, const std::string & alias_name, std::size_t size, Args...args)
457 smart_library lib(lib_);
459 lib.add_type_alias<T>(alias_name);
460 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
463 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
464 template<typename T, typename ... Args> imported_class<T>
465 import_class(smart_library && lib, Args...args)
467 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
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, const std::string & alias_name, Args...args)
474 lib.add_type_alias<T>(alias_name);
475 return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
478 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
479 template<typename T, typename ... Args> imported_class<T>
480 import_class(smart_library && lib, std::size_t size, Args...args)
482 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
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, const std::string & alias_name, Args...args)
489 lib.add_type_alias<T>(alias_name);
490 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
493 //! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
494 template<typename T, typename ... Args> imported_class<T>
495 import_class(smart_library && lib, const std::string & alias_name, std::size_t size, Args...args)
497 lib.add_type_alias<T>(alias_name);
498 return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
503 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
504 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
507 template<typename T, typename ... Args> imported_class<T>
508 import_class(smart_library & lib, Args...args)
510 return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
513 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
514 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
516 template<typename T, typename ... Args> imported_class<T>
517 import_class(smart_library & lib, const std::string & alias_name, Args...args)
519 lib.add_type_alias<T>(alias_name);
520 return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
523 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
524 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
526 template<typename T, typename ... Args> imported_class<T>
527 import_class(smart_library & lib, std::size_t size, Args...args)
529 return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
532 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
533 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
535 template<typename T, typename ... Args> imported_class<T>
536 import_class(smart_library & lib, std::size_t size, const std::string & alias_name, Args...args)
538 lib.add_type_alias<T>(alias_name);
539 return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
542 /*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
543 * \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
545 template<typename T, typename ... Args> imported_class<T>
546 import_class(smart_library & lib, const std::string & alias_name, std::size_t size, Args...args)
548 lib.add_type_alias<T>(alias_name);
549 return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
558 #endif /* BOOST_DLL_IMPORT_CLASS_HPP_ */