]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright 2016 Klemens Morgenstern, Antony Polukhin |
2 | // | |
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) | |
6 | ||
7 | // For more information, see http://www.boost.org | |
8 | ||
9 | #ifndef BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ | |
10 | #define BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ | |
11 | ||
12 | #include <boost/config.hpp> | |
13 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
14 | # pragma once | |
15 | #endif | |
16 | ||
17 | #include <boost/dll/detail/aggressive_ptr_cast.hpp> | |
18 | #include <boost/dll/detail/get_mem_fn_type.hpp> | |
19 | ||
20 | #if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER) | |
21 | # include <boost/dll/detail/demangling/msvc.hpp> | |
22 | #else | |
23 | # include <boost/dll/detail/demangling/itanium.hpp> | |
24 | #endif | |
25 | ||
26 | ||
27 | namespace boost { namespace dll { namespace detail { | |
28 | ||
29 | /*! | |
30 | * This class stores a constructor. | |
31 | * | |
32 | * In some compilers there are several constructors in code, which may include an allocating one. | |
33 | * This can be used if the imported class shall be put on the heap, which is why the class provied both types. | |
34 | */ | |
35 | template<typename Signature> | |
36 | struct constructor; | |
37 | ||
38 | template<typename Class, typename ...Args> | |
39 | struct constructor<Class(Args...)> { | |
40 | typedef typename detail::get_mem_fn_type<Class, void(Args...)>::mem_fn standard_t; | |
41 | typedef Class*(*allocating_t)(Args...); | |
42 | ||
43 | ||
44 | //! The standard, i.e. not allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_standard instead. | |
45 | standard_t standard; | |
46 | //! The allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_allocating instead. | |
47 | allocating_t allocating; | |
48 | ||
49 | //! Call the standard contructor | |
50 | void call_standard (Class * const ptr, Args...args){ (ptr->*standard)(static_cast<Args>(args)...); } | |
51 | ||
52 | //! Call the deleting destructor | |
53 | Class * call_allocating(Args...args){ return allocating(static_cast<Args>(args)...); } | |
54 | ||
55 | ||
56 | //! True if a allocating constructor could be loaded. | |
57 | bool has_allocating() const { return allocating != nullptr; } | |
58 | ||
59 | //! True if a standard constructor could be loaded. | |
60 | bool has_standard() const { return standard != nullptr; } | |
61 | ||
62 | //! False if neither the allocating nor the standard constructor is available. | |
63 | bool is_empty() const { return (allocating == nullptr) && (standard == nullptr) ; } | |
64 | ||
65 | constructor() = delete; | |
66 | constructor(const constructor &) = default; | |
67 | ||
68 | explicit constructor(standard_t standard, allocating_t allocating = nullptr) | |
69 | : standard(standard) | |
70 | , allocating(allocating) | |
71 | {} | |
72 | }; | |
73 | ||
74 | ||
75 | ||
76 | template <typename Class> | |
77 | struct destructor { | |
78 | #if !defined(_WIN32) | |
79 | typedef void(*type)(Class* const); | |
80 | #elif !defined(_WIN64) | |
81 | typedef void(__thiscall * type)(Class* const); | |
82 | #else | |
83 | typedef void(__cdecl * type)(Class* const); | |
84 | #endif | |
85 | ||
86 | typedef type standard_t; | |
87 | typedef type deleting_t; | |
88 | ||
89 | //! The standard, i.e. not deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_standard instead. | |
90 | standard_t standard; | |
91 | //! The deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_deallocating instead. | |
92 | deleting_t deleting; | |
93 | ||
94 | //! Call the standard contructor | |
95 | void call_standard(Class * const ptr){ standard(ptr); } | |
96 | ||
97 | //! Call the deleting destructor | |
98 | void call_deleting(Class * const ptr){ deleting(ptr); } | |
99 | ||
100 | //! True if a deleting destructor could be loaded. | |
101 | bool has_deleting() const { return deleting != nullptr; } | |
102 | ||
103 | //! True if a standard destructor could be loaded. | |
104 | bool has_standard() const { return standard != nullptr; } | |
105 | ||
106 | //! False if neither the deleting nor the standard destructor is available. | |
107 | bool is_empty() const { return (deleting == nullptr) && (standard == nullptr) ; } | |
108 | destructor() = delete; | |
109 | ||
110 | //! Copy destructor. | |
111 | destructor(const destructor &) = default; | |
112 | ||
113 | //! Construct it from both the standard destructor and the allocating destructor | |
114 | explicit destructor(const standard_t &standard, const deleting_t &deleting = nullptr) | |
115 | : standard(standard) | |
116 | , deleting(deleting) | |
117 | {} | |
118 | }; | |
119 | ||
120 | #if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER) | |
121 | template<typename Signature, typename Lib> | |
122 | constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) { | |
123 | typedef typename constructor<Signature>::standard_t standard_t; | |
124 | standard_t ctor = lib.template get<standard_t>(ct); | |
125 | return constructor<Signature>(ctor); | |
126 | } | |
127 | ||
128 | template<typename Class, typename Lib> | |
129 | destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) { | |
130 | typedef typename destructor<Class>::standard_t standard_t; | |
131 | //@apolukhin That does NOT work this way with MSVC-14 x32 via memcpy. The x64 is different. | |
132 | //standard_t dtor = &lib.template get< typename boost::remove_pointer<standard_t>::type >(dt); | |
133 | void * buf = &lib.template get<int>(dt); | |
134 | standard_t dtor; | |
135 | std::memcpy(&dtor, &buf, sizeof(dtor)); | |
136 | return destructor<Class>(dtor); | |
137 | } | |
138 | ||
139 | #else | |
140 | ||
141 | template<typename Signature, typename Lib> | |
142 | constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) { | |
143 | typedef typename constructor<Signature>::standard_t stand; | |
144 | typedef typename constructor<Signature>::allocating_t alloc; | |
145 | ||
146 | stand s = nullptr; | |
147 | alloc a = nullptr; | |
148 | ||
149 | //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor | |
150 | ||
151 | if (!ct.C1.empty()) | |
152 | { | |
153 | //the only way this works on mingw/win. | |
154 | //For some reason there is always an 0xA in the following poniter, which screws with the this pointer. | |
155 | void *buf = &lib.template get<int>(ct.C1); | |
156 | std::memcpy(&s, &buf, sizeof(void*)); | |
157 | } | |
158 | if (!ct.C3.empty()) | |
159 | { | |
160 | void *buf = &lib.template get<int>(ct.C3); | |
161 | std::memcpy(&a, &buf, sizeof(void*)); | |
162 | } | |
163 | ||
164 | return constructor<Signature>(s,a); | |
165 | } | |
166 | ||
167 | template<typename Class, typename Lib> | |
168 | destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) { | |
169 | typedef typename destructor<Class>::standard_t stand; | |
170 | typedef typename destructor<Class>::deleting_t delet; | |
171 | ||
172 | stand s = nullptr; | |
173 | delet d = nullptr; | |
174 | ||
175 | //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor | |
176 | if (!dt.D1.empty()) { | |
177 | s = &lib.template get< typename boost::remove_pointer<stand>::type >(dt.D1); | |
178 | } | |
179 | ||
180 | if (!dt.D0.empty()) { | |
181 | d = &lib.template get< typename boost::remove_pointer<delet>::type >(dt.D0); | |
182 | } | |
183 | ||
184 | return destructor<Class>(s,d); | |
185 | ||
186 | } | |
187 | ||
188 | #endif | |
189 | ||
190 | }}} // namespace boost::dll::detail | |
191 | ||
192 | #endif /* BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ */ |