liuxiaolong
2021-07-20 58d904a328c0d849769b483e901a0be9426b8209
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
// 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 <boost/dll/smart_library.hpp>
#include <boost/dll/import_mangled.hpp>
#include <memory>
 
#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<typename T>
struct deleter
{
    destructor<T> dtor;
    bool use_deleting;
 
    deleter(const destructor<T> & 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<char*>(t);
            delete [] p;
        }
    }
};
 
template<class T, class = void>
struct mem_fn_call_proxy;
 
template<class Class, class U>
struct mem_fn_call_proxy<Class, boost::dll::experimental::detail::mangled_library_mem_fn<Class, U>>
{
    typedef boost::dll::experimental::detail::mangled_library_mem_fn<Class, U> 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<typename ...Args>
    auto operator()(Args&&...args) const
    {
        return mem_fn(t, std::forward<Args>(args)...);
    }
 
};
 
template<class T, class Return, class ...Args>
struct mem_fn_call_proxy<T, Return(Args...)>
{
    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<T, Return(Args...)>(name);
        return (t->*f)(static_cast<Args>(args)...);
    }
};
 
}
 
template<typename T>
class imported_class;
 
template<typename T, typename ... Args> imported_class<T>
import_class(const smart_library& lib, Args...args);
template<typename T, typename ... Args> imported_class<T>
import_class(const smart_library& lib, const std::string & alias_name, Args...args);
template<typename T, typename ... Args> imported_class<T>
import_class(const smart_library& lib, std::size_t size, Args...args);
template<typename T, typename ... Args> imported_class<T>
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<typename T>
class imported_class
{
    smart_library _lib;
    std::unique_ptr<T, detail::deleter<T>> _data;
    bool _is_allocating;
    std::size_t _size;
    const std::type_info& _ti;
 
    template<typename ... Args>
    inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, Args ... args);
    template<typename ... Args>
    inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, std::size_t size, Args...args);
 
    template<typename ...Args>
    imported_class(detail::sequence<Args...> *, const smart_library& lib,  Args...args);
 
    template<typename ...Args>
    imported_class(detail::sequence<Args...> *, const smart_library& lib, std::size_t size,  Args...args);
 
    template<typename ...Args>
    imported_class(detail::sequence<Args...> *, smart_library&& lib,  Args...args);
 
    template<typename ...Args>
    imported_class(detail::sequence<Args...> *, smart_library&& lib, std::size_t size,  Args...args);
public:
    //alias to construct with explicit parameter list
    template<typename ...Args>
    static imported_class<T> make(smart_library&& lib,  Args...args)
    {
        typedef detail::sequence<Args...> *seq;
        return imported_class(seq(), boost::move(lib), static_cast<Args>(args)...);
    }
 
    template<typename ...Args>
    static imported_class<T> make(smart_library&& lib, std::size_t size,  Args...args)
    {
        typedef detail::sequence<Args...> *seq;
        return imported_class(seq(), boost::move(lib), size, static_cast<Args>(args)...);
    }
    template<typename ...Args>
    static imported_class<T> make(const smart_library& lib,  Args...args)
    {
        typedef detail::sequence<Args...> *seq;
        return imported_class(seq(), lib, static_cast<Args>(args)...);
    }
 
    template<typename ...Args>
    static imported_class<T> make(const smart_library& lib, std::size_t size,  Args...args)
    {
        typedef detail::sequence<Args...> *seq;
        return imported_class(seq(), lib, size, static_cast<Args>(args)...);
    }
 
    typedef imported_class<T> 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;                ///<Move constructor
    imported_class& operator=(imported_class&) = delete;
    imported_class& operator=(imported_class&&) = default;  ///<Move assignmend
 
    ///Check if the imported class is move-constructible
    bool is_move_constructible() {return !_lib.symbol_storage().template get_constructor<T(T&&)>     ().empty();}
    ///Check if the imported class is move-assignable
    bool is_move_assignable()    {return !_lib.symbol_storage().template get_mem_fn<T, T&(T&&)>     ("operator=").empty();}
    ///Check if the imported class is copy-constructible
    bool is_copy_constructible() {return !_lib.symbol_storage().template get_constructor<T(const T&)>().empty();}
    ///Check if the imported class is copy-assignable
    bool is_copy_assignable()    {return !_lib.symbol_storage().template get_mem_fn<T, T&(const T&)>("operator=").empty();}
 
    imported_class<T> copy() const; ///<Invoke the copy constructor. \attention Undefined behaviour if the imported object is not copy constructible.
    imported_class<T> move();       ///<Invoke the move constructor. \attention Undefined behaviour if the imported object is not move constructible.
 
    ///Invoke the copy assignment. \attention Undefined behaviour if the imported object is not copy assignable.
    void copy_assign(const imported_class<T> & lhs) const;
    ///Invoke the move assignment. \attention Undefined behaviour if the imported object is not move assignable.
    void move_assign(      imported_class<T> & 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<void(const char*)>("function_name")("MyString");
     * \endcode
     */
    template<class Signature>
    const detail::mem_fn_call_proxy<T, Signature> call(const std::string& name)
    {
        return detail::mem_fn_call_proxy<T, Signature>(_data.get(), name, _lib);
    }
    /*! Call a qualified member function, i.e. const and or volatile.
     *
     * \b Example
     *
     * \code
     * im_class.call<const type_alias, void(const char*)>("function_name")("MyString");
     * \endcode
     */
    template<class Tin, class Signature, class = boost::enable_if<detail::unqalified_is_same<T, Tin>>>
    const detail::mem_fn_call_proxy<Tin, Signature> call(const std::string& name)
    {
        return detail::mem_fn_call_proxy<Tin, Signature>(_data.get(), name, _lib);
    }
    ///Overload of ->* for an imported method.
    template<class Tin, class T2>
    const detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>
            operator->*(detail::mangled_library_mem_fn<Tin, T2>& mn)
    {
        return detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>(_data.get(), mn);
    }
 
    ///Import a method of the class.
    template <class ...Args>
    typename boost::dll::experimental::detail::mangled_import_type<boost::dll::experimental::detail::sequence<T, Args...>>::type
    import(const std::string & name)
    {
        return boost::dll::experimental::import_mangled<T, Args...>(_lib, name);
    }
};
 
 
 
//helper function, uses the allocating
template<typename T>
template<typename ... Args>
inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, Args ... args)
{
    constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
    destructor<T>           dtor = lib.get_destructor <T>();
 
    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<T, detail::deleter<T>> (
            ctor.call_allocating(static_cast<Args>(args)...),
            detail::deleter<T>(dtor, false /* not deleting dtor*/));
}
 
//helper function, using the standard
template<typename T>
template<typename ... Args>
inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, std::size_t size, Args...args)
{
    constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
    destructor<T>           dtor = lib.get_destructor <T>();
 
    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<T*>(new char[size]);
 
    ctor.call_standard(data, static_cast<Args>(args)...);
 
    return std::unique_ptr<T, detail::deleter<T>> (
            reinterpret_cast<T*>(data),
            detail::deleter<T>(dtor, false /* not deleting dtor*/));
 
}
 
 
template<typename T>
template<typename ...Args>
imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib,  Args...args)
    : _lib(lib),
      _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
      _is_allocating(false),
      _size(0),
      _ti(lib.get_type_info<T>())
{
 
}
 
template<typename T>
template<typename ...Args>
imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, std::size_t size,  Args...args)
    : _lib(lib),
      _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
      _is_allocating(true),
      _size(size),
      _ti(lib.get_type_info<T>())
{
 
}
 
template<typename T>
template<typename ...Args>
imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib,  Args...args)
    : _lib(boost::move(lib)),
      _data(make_data<Args...>(lib, static_cast<Args>(args)...)),
      _is_allocating(false),
      _size(0),
      _ti(lib.get_type_info<T>())
{
 
}
 
template<typename T>
template<typename ...Args>
imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, std::size_t size,  Args...args)
    : _lib(boost::move(lib)),
      _data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
      _is_allocating(true),
      _size(size),
      _ti(lib.get_type_info<T>())
{
 
}
 
template<typename T>
inline imported_class<T> boost::dll::experimental::imported_class<T>::copy() const
{
    if (this->_is_allocating)
        return imported_class<T>::template make<const T&>(_lib, *_data);
    else
        return imported_class<T>::template make<const T&>(_lib, _size, *_data);
}
 
template<typename T>
inline imported_class<T> boost::dll::experimental::imported_class<T>::move()
{
    if (this->_is_allocating)
        return imported_class<T>::template make<T&&>(_lib, *_data);
    else
        return imported_class<T>::template make<T&&>(_lib, _size, *_data);
}
 
template<typename T>
inline void boost::dll::experimental::imported_class<T>::copy_assign(const imported_class<T>& lhs) const
{
    this->call<T&(const T&)>("operator=")(*lhs._data);
}
 
template<typename T>
inline void boost::dll::experimental::imported_class<T>::move_assign(imported_class<T>& lhs)
{
    this->call<T&(T&&)>("operator=")(static_cast<T&&>(*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<class type_alias, const std::string&, std::size_t>(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<typename T, typename ... Args> imported_class<T>
import_class(const smart_library& lib_, std::size_t size, Args...args)
{
    smart_library lib(lib_);
 
    return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
import_class(const smart_library& lib_, Args...args)
{
    smart_library lib(lib_);
    return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
import_class(const smart_library& lib_, const std::string & alias_name, Args...args)
{
    smart_library lib(lib_);
    lib.add_type_alias<T>(alias_name);
    return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
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<T>(alias_name);
    return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
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<T>(alias_name);
    return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
import_class(smart_library && lib, Args...args)
{
    return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
import_class(smart_library && lib, const std::string & alias_name, Args...args)
{
    lib.add_type_alias<T>(alias_name);
    return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
import_class(smart_library && lib, std::size_t size, Args...args)
{
    return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
import_class(smart_library && lib, std::size_t size, const std::string & alias_name, Args...args)
{
    lib.add_type_alias<T>(alias_name);
    return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
}
 
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
template<typename T, typename ... Args> imported_class<T>
import_class(smart_library && lib, const std::string & alias_name, std::size_t size, Args...args)
{
    lib.add_type_alias<T>(alias_name);
    return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(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<typename T, typename ... Args> imported_class<T>
import_class(smart_library & lib, Args...args)
{
    return imported_class<T>::template make<Args...>(lib, static_cast<Args>(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<typename T, typename ... Args> imported_class<T>
import_class(smart_library & lib, const std::string & alias_name, Args...args)
{
    lib.add_type_alias<T>(alias_name);
    return imported_class<T>::template make<Args...>(lib, static_cast<Args>(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<typename T, typename ... Args> imported_class<T>
import_class(smart_library & lib, std::size_t size, Args...args)
{
    return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(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<typename T, typename ... Args> imported_class<T>
import_class(smart_library & lib, std::size_t size, const std::string & alias_name, Args...args)
{
    lib.add_type_alias<T>(alias_name);
    return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(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<typename T, typename ... Args> imported_class<T>
import_class(smart_library & lib, const std::string & alias_name, std::size_t size, Args...args)
{
    lib.add_type_alias<T>(alias_name);
    return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
}
 
}
}
}
 
 
 
#endif /* BOOST_DLL_IMPORT_CLASS_HPP_ */