Edit: /usr/include/boost/dll/import_class.hpp (20944B)
// Copyright 2015-2018 Klemens D. Morgenstern
// Copyright 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_DLL_IMPORT_CLASS_HPP_
#define BOOST_DLL_IMPORT_CLASS_HPP_
/// \file boost/dll/import_class.hpp
/// \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
/// \brief Contains the boost::dll::experimental::import_class function for importing classes.
#include
#include
#include
#if (__cplusplus < 201103L) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201103L)
# error This file requires C++11 at least!
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace dll { namespace experimental {
namespace detail
{
template
struct deleter
{
destructor dtor;
bool use_deleting;
deleter(const destructor & dtor, bool use_deleting = false) :
dtor(dtor), use_deleting(use_deleting) {}
void operator()(T*t)
{
if (use_deleting)
dtor.call_deleting(t);
else
{
dtor.call_standard(t);
//the thing is actually an array, so delete[]
auto p = reinterpret_cast(t);
delete [] p;
}
}
};
template
struct mem_fn_call_proxy;
template
struct mem_fn_call_proxy>
{
typedef boost::dll::experimental::detail::mangled_library_mem_fn mem_fn_t;
Class* t;
mem_fn_t & mem_fn;
mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
mem_fn_call_proxy(const mem_fn_call_proxy & ) = delete;
mem_fn_call_proxy(Class * t, mem_fn_t & mem_fn)
: t(t), mem_fn(mem_fn) {}
template
auto operator()(Args&&...args) const
{
return mem_fn(t, std::forward(args)...);
}
};
template
struct mem_fn_call_proxy
{
T* t;
const std::string &name;
smart_library &_lib;
mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
mem_fn_call_proxy(const mem_fn_call_proxy&) = delete;
mem_fn_call_proxy(T *t, const std::string &name, smart_library & _lib)
: t(t), name(name), _lib(_lib) {};
Return operator()(Args...args) const
{
auto f = _lib.get_mem_fn(name);
return (t->*f)(static_cast(args)...);
}
};
}
template
class imported_class;
template imported_class
import_class(const smart_library& lib, Args...args);
template imported_class
import_class(const smart_library& lib, const std::string & alias_name, Args...args);
template imported_class
import_class(const smart_library& lib, std::size_t size, Args...args);
template imported_class
import_class(const smart_library& lib, std::size_t size,
const std::string & alias_name, Args...args);
/*! This class represents an imported class.
*
* \note It must be constructed via \ref boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
*
* \tparam The type or type-alias of the imported class.
*/
template
class imported_class
{
smart_library _lib;
std::unique_ptr> _data;
bool _is_allocating;
std::size_t _size;
const std::type_info& _ti;
template
inline std::unique_ptr> make_data(const smart_library& lib, Args ... args);
template
inline std::unique_ptr> make_data(const smart_library& lib, std::size_t size, Args...args);
template
imported_class(detail::sequence *, const smart_library& lib, Args...args);
template
imported_class(detail::sequence *, const smart_library& lib, std::size_t size, Args...args);
template
imported_class(detail::sequence *, smart_library&& lib, Args...args);
template
imported_class(detail::sequence *, smart_library&& lib, std::size_t size, Args...args);
public:
//alias to construct with explicit parameter list
template
static imported_class make(smart_library&& lib, Args...args)
{
typedef detail::sequence *seq;
return imported_class(seq(), boost::move(lib), static_cast(args)...);
}
template
static imported_class make(smart_library&& lib, std::size_t size, Args...args)
{
typedef detail::sequence *seq;
return imported_class(seq(), boost::move(lib), size, static_cast(args)...);
}
template
static imported_class make(const smart_library& lib, Args...args)
{
typedef detail::sequence *seq;
return imported_class(seq(), lib, static_cast(args)...);
}
template
static imported_class make(const smart_library& lib, std::size_t size, Args...args)
{
typedef detail::sequence *seq;
return imported_class(seq(), lib, size, static_cast(args)...);
}
typedef imported_class base_t;
///Returns a pointer to the underlying class
T* get() {return _data.get();}
imported_class() = delete;
imported_class(imported_class&) = delete;
imported_class(imported_class&&) = default; /// ().empty();}
///Check if the imported class is move-assignable
bool is_move_assignable() {return !_lib.symbol_storage().template get_mem_fn ("operator=").empty();}
///Check if the imported class is copy-constructible
bool is_copy_constructible() {return !_lib.symbol_storage().template get_constructor().empty();}
///Check if the imported class is copy-assignable
bool is_copy_assignable() {return !_lib.symbol_storage().template get_mem_fn("operator=").empty();}
imported_class copy() const; /// move(); /// & lhs) const;
///Invoke the move assignment. \attention Undefined behaviour if the imported object is not move assignable.
void move_assign( imported_class & lhs);
///Check if the class is loaded.
explicit operator bool() const {return _data;}
///Get a const reference to the std::type_info.
const std::type_info& get_type_info() {return _ti;};
/*! Call a member function. This returns a proxy to the function.
* The proxy mechanic mechanic is necessary, so the signaute can be passed.
*
* \b Example
*
* \code
* im_class.call("function_name")("MyString");
* \endcode
*/
template
const detail::mem_fn_call_proxy call(const std::string& name)
{
return detail::mem_fn_call_proxy(_data.get(), name, _lib);
}
/*! Call a qualified member function, i.e. const and or volatile.
*
* \b Example
*
* \code
* im_class.call("function_name")("MyString");
* \endcode
*/
template>>
const detail::mem_fn_call_proxy call(const std::string& name)
{
return detail::mem_fn_call_proxy(_data.get(), name, _lib);
}
///Overload of ->* for an imported method.
template
const detail::mem_fn_call_proxy>
operator->*(detail::mangled_library_mem_fn& mn)
{
return detail::mem_fn_call_proxy>(_data.get(), mn);
}
///Import a method of the class.
template
typename boost::dll::experimental::detail::mangled_import_type>::type
import(const std::string & name)
{
return boost::dll::experimental::import_mangled(_lib, name);
}
};
//helper function, uses the allocating
template
template
inline std::unique_ptr> imported_class::make_data(const smart_library& lib, Args ... args)
{
constructor ctor = lib.get_constructor();
destructor dtor = lib.get_destructor ();
if (!ctor.has_allocating() || !dtor.has_deleting())
{
boost::dll::fs::error_code ec;
ec = boost::dll::fs::make_error_code(
boost::dll::fs::errc::bad_file_descriptor
);
// report_error() calls dlsym, do not use it here!
boost::throw_exception(
boost::dll::fs::system_error(
ec, "boost::dll::detail::make_data() failed: no allocating ctor or dtor was found"
)
);
}
return std::unique_ptr> (
ctor.call_allocating(static_cast(args)...),
detail::deleter(dtor, false /* not deleting dtor*/));
}
//helper function, using the standard
template
template
inline std::unique_ptr> imported_class::make_data(const smart_library& lib, std::size_t size, Args...args)
{
constructor ctor = lib.get_constructor();
destructor dtor = lib.get_destructor ();
if (!ctor.has_standard() || !dtor.has_standard())
{
boost::dll::fs::error_code ec;
ec = boost::dll::fs::make_error_code(
boost::dll::fs::errc::bad_file_descriptor
);
// report_error() calls dlsym, do not use it here!
boost::throw_exception(
boost::dll::fs::system_error(
ec, "boost::dll::detail::make_data() failed: no regular ctor or dtor was found"
)
);
}
T *data = reinterpret_cast(new char[size]);
ctor.call_standard(data, static_cast(args)...);
return std::unique_ptr> (
reinterpret_cast(data),
detail::deleter(dtor, false /* not deleting dtor*/));
}
template
template
imported_class::imported_class(detail::sequence *, const smart_library & lib, Args...args)
: _lib(lib),
_data(make_data(lib, static_cast(args)...)),
_is_allocating(false),
_size(0),
_ti(lib.get_type_info())
{
}
template
template
imported_class::imported_class(detail::sequence *, const smart_library & lib, std::size_t size, Args...args)
: _lib(lib),
_data(make_data(lib, size, static_cast(args)...)),
_is_allocating(true),
_size(size),
_ti(lib.get_type_info())
{
}
template
template
imported_class::imported_class(detail::sequence *, smart_library && lib, Args...args)
: _lib(boost::move(lib)),
_data(make_data(lib, static_cast(args)...)),
_is_allocating(false),
_size(0),
_ti(lib.get_type_info())
{
}
template
template
imported_class::imported_class(detail::sequence *, smart_library && lib, std::size_t size, Args...args)
: _lib(boost::move(lib)),
_data(make_data(lib, size, static_cast(args)...)),
_is_allocating(true),
_size(size),
_ti(lib.get_type_info())
{
}
template
inline imported_class boost::dll::experimental::imported_class::copy() const
{
if (this->_is_allocating)
return imported_class::template make(_lib, *_data);
else
return imported_class::template make(_lib, _size, *_data);
}
template
inline imported_class boost::dll::experimental::imported_class::move()
{
if (this->_is_allocating)
return imported_class::template make(_lib, *_data);
else
return imported_class::template make(_lib, _size, *_data);
}
template
inline void boost::dll::experimental::imported_class::copy_assign(const imported_class& lhs) const
{
this->call("operator=")(*lhs._data);
}
template
inline void boost::dll::experimental::imported_class::move_assign(imported_class& lhs)
{
this->call("operator=")(static_cast(*lhs._data));
}
/*!
* Returns an instance of \ref imported_class which allows to call or import more functions.
* It takes a copy of the smart_libray, so no added type_aliases will be visible,
* for the object.
*
* Few compilers do implement an allocating constructor, which allows the construction
* of the class without knowing the size. That is not portable, so the actual size of the class
* shall always be provided.
*
* \b Example:
*
* \code
* auto import_class(lib, "class_name", 20, "param1", 42);
* \endcode
*
* In this example we construct an instance of the class "class_name" with the size 20, which has "type_alias" as an alias,
* through a constructor which takes a const-ref of std::string and an std::size_t parameter.
*
* \tparam T Class type or alias
* \tparam Args Constructor argument list.
* \param lib Path to shared library or shared library to load function from.
* \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*.
* \param mode An mode that will be used on library load.
*
* \return class object.
*
* \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
* Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
*/
template imported_class
import_class(const smart_library& lib_, std::size_t size, Args...args)
{
smart_library lib(lib_);
return imported_class::template make(boost::move(lib), size, static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(const smart_library& lib_, Args...args)
{
smart_library lib(lib_);
return imported_class::template make(boost::move(lib), static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(const smart_library& lib_, const std::string & alias_name, Args...args)
{
smart_library lib(lib_);
lib.add_type_alias(alias_name);
return imported_class::template make(boost::move(lib), static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(const smart_library& lib_, std::size_t size, const std::string & alias_name, Args...args)
{
smart_library lib(lib_);
lib.add_type_alias(alias_name);
return imported_class::template make(boost::move(lib), size, static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(const smart_library& lib_, const std::string & alias_name, std::size_t size, Args...args)
{
smart_library lib(lib_);
lib.add_type_alias(alias_name);
return imported_class::template make(boost::move(lib), size, static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(smart_library && lib, Args...args)
{
return imported_class::template make(boost::move(lib), static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(smart_library && lib, const std::string & alias_name, Args...args)
{
lib.add_type_alias(alias_name);
return imported_class::template make(boost::move(lib), static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(smart_library && lib, std::size_t size, Args...args)
{
return imported_class::template make(boost::move(lib), size, static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(smart_library && lib, std::size_t size, const std::string & alias_name, Args...args)
{
lib.add_type_alias(alias_name);
return imported_class::template make(boost::move(lib), size, static_cast(args)...);
}
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template imported_class
import_class(smart_library && lib, const std::string & alias_name, std::size_t size, Args...args)
{
lib.add_type_alias(alias_name);
return imported_class::template make(boost::move(lib), size, static_cast(args)...);
}
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
*/
template imported_class
import_class(smart_library & lib, Args...args)
{
return imported_class::template make(lib, static_cast(args)...);
}
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
*/
template imported_class
import_class(smart_library & lib, const std::string & alias_name, Args...args)
{
lib.add_type_alias(alias_name);
return imported_class::template make(lib, static_cast(args)...);
}
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
*/
template imported_class
import_class(smart_library & lib, std::size_t size, Args...args)
{
return imported_class::template make(lib, size, static_cast(args)...);
}
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
*/
template imported_class
import_class(smart_library & lib, std::size_t size, const std::string & alias_name, Args...args)
{
lib.add_type_alias(alias_name);
return imported_class::template make(lib, size, static_cast(args)...);
}
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
*/
template imported_class
import_class(smart_library & lib, const std::string & alias_name, std::size_t size, Args...args)
{
lib.add_type_alias(alias_name);
return imported_class::template make(lib, size, static_cast(args)...);
}
}
}
}
#endif /* BOOST_DLL_IMPORT_CLASS_HPP_ */