summaryrefslogtreecommitdiff
path: root/boost/dll/detail/ctor_dtor.hpp
blob: 5950d9e60af0f450bb6e3715e762cd706d2cea5a (plain)
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
// Copyright 2016 Klemens Morgenstern, 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)

// For more information, see http://www.boost.org

#ifndef INCLUDE_BOOST_DLL_DETAIL_CTOR_DTOR_HPP_
#define INCLUDE_BOOST_DLL_DETAIL_CTOR_DTOR_HPP_

#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif

#include <boost/dll/detail/aggressive_ptr_cast.hpp>
#include <boost/dll/detail/get_mem_fn_type.hpp>

#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
#   include <boost/dll/detail/demangling/msvc.hpp>
#else
#   include <boost/dll/detail/demangling/itanium.hpp>
#endif

namespace boost { namespace dll { namespace detail {

/*!
 * This class stores a constructor.
 *
 * In some compilers there are several constructors in code, which may include an allocating one.
 * This can be used if the imported class shall be put on the heap, which is why the class provied both types.
 */
template<typename Signature>
struct constructor;

template<typename Class, typename ...Args>
struct constructor<Class(Args...)> {
    typedef typename detail::get_mem_fn_type<Class, void(Args...)>::mem_fn standard_t;
    typedef Class*(*allocating_t)(Args...);


    //! The standard, i.e. not allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_standard instead.
    standard_t standard;
    //! The allocating constructor.  @warning May differ with the compiler. Use @ref constructor::call_allocating instead.
    allocating_t allocating;

    //! Call the standard contructor
    void call_standard  (Class * const ptr, Args...args){ (ptr->*standard)(static_cast<Args>(args)...); }

    //! Call the deleting destructor
    Class * call_allocating(Args...args){ return allocating(static_cast<Args>(args)...); }


    //! True if a allocating constructor could be loaded.
    bool has_allocating() const { return allocating != nullptr; }

    //! False if neither the allocating nor the standard constructor is available.
    bool is_empty() const { return !((allocating == nullptr) && (standard != nullptr)) ; }

    constructor() = delete;
    constructor(const constructor &) = default;

    explicit constructor(standard_t standard, allocating_t allocating = nullptr)
        : standard(standard)
        , allocating(allocating)
    {}
};



template <typename Class>
struct destructor {
#if !defined(BOOST_MSVC) && !defined(BOOST_MSVC_VER)
    typedef void( *type)(Class* const);
#elif !defined(_WIN64)
    typedef void(__thiscall * type)(Class* const);
#else
    typedef void(__cdecl * type)(Class* const);
#endif

    typedef type standard_t;
    typedef type deleting_t;

    //! The standard, i.e. not deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_standard instead.
    standard_t standard;
    //! The deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_deallocating instead.
    deleting_t deleting;

    //! Call the standard contructor
    void call_standard(Class * const ptr){ standard(ptr); }

    //! Call the deleting destructor
    void call_deleting(Class * const ptr){ deleting(ptr); }

    //! True if a deleting destructor could be loaded.
    bool has_deleting() const { return deleting != nullptr; }

    //! False if neither the deleting nor the standard destructor is available.
    bool is_empty() const { return !((deleting == nullptr) && (standard != nullptr)) ; }
    destructor() = delete;

    //! Copy destructor.
    destructor(const destructor &) = default;

    //! Construct it from both the standard destructor and the allocating destructor
    explicit destructor(const standard_t &standard, const deleting_t &deleting = nullptr)
        : standard(standard)
        , deleting(deleting)
    {}
};

#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
template<typename Signature, typename Lib>
constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) {
    typedef typename constructor<Signature>::standard_t standard_t;
    standard_t ctor = lib.template get<standard_t>(ct);
    return constructor<Signature>(ctor);
}

template<typename Class, typename Lib>
destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) {
    typedef typename destructor<Class>::standard_t standard_t;
    standard_t dtor = &lib.template get< typename boost::remove_pointer<standard_t>::type >(dt);
    return destructor<Class>(dtor);
}

#else

template<typename Signature, typename Lib>
constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) {
    typedef typename constructor<Signature>::standard_t   stand;
    typedef typename constructor<Signature>::allocating_t alloc;

    stand s = nullptr;
    alloc a = nullptr;

    //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor

    if (!ct.C1.empty()) {
        s = lib.template get<stand>(ct.C1);
    }

    if (!ct.C3.empty()) {
        a = lib.template get<alloc>(ct.C3);
    }

    return constructor<Signature>(s,a);
}

template<typename Class, typename Lib>
destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) {
    typedef typename destructor<Class>::standard_t stand;
    typedef typename destructor<Class>::deleting_t delet;

    stand s = nullptr;
    delet d = nullptr;

    //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor
    if (!dt.D1.empty()) {
        s = &lib.template get< typename boost::remove_pointer<stand>::type >(dt.D1);
    }

    if (!dt.D0.empty()) {
        d = &lib.template get< typename boost::remove_pointer<delet>::type >(dt.D0);
    }

    return destructor<Class>(s,d);

}

#endif

}}} // namespace boost::dll::detail

#endif /* INCLUDE_BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ */