1 // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
2 // Copyright 2015-2019 Antony Polukhin.
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifndef BOOST_DLL_DETAIL_AGGRESSIVE_PTR_CAST_HPP
9 #define BOOST_DLL_DETAIL_AGGRESSIVE_PTR_CAST_HPP
10 
11 #include <boost/dll/config.hpp>
12 #ifdef BOOST_HAS_PRAGMA_ONCE
13 #   pragma once
14 #endif
15 
16 #include <boost/core/addressof.hpp>
17 #include <boost/core/enable_if.hpp>
18 #include <boost/static_assert.hpp>
19 #include <boost/type_traits/is_pointer.hpp>
20 #include <boost/type_traits/is_member_pointer.hpp>
21 #include <boost/type_traits/is_void.hpp>
22 #include <boost/type_traits/is_reference.hpp>
23 #include <boost/type_traits/remove_pointer.hpp>
24 #include <boost/type_traits/remove_reference.hpp>
25 #include <cstring>              // std::memcpy
26 
27 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 301)
28 #   pragma GCC system_header
29 #endif
30 
31 namespace boost { namespace dll { namespace detail {
32 
33 // GCC warns when reinterpret_cast between function pointer and object pointer occur.
34 // This method suppress the warnings and ensures that such casts are safe.
35 template <class To, class From>
36 BOOST_FORCEINLINE typename boost::disable_if_c<boost::is_member_pointer<To>::value || boost::is_reference<To>::value || boost::is_member_pointer<From>::value, To>::type
aggressive_ptr_cast(From v)37     aggressive_ptr_cast(From v) BOOST_NOEXCEPT
38 {
39     BOOST_STATIC_ASSERT_MSG(
40         boost::is_pointer<To>::value && boost::is_pointer<From>::value,
41         "`agressive_ptr_cast` function must be used only for pointer casting."
42     );
43 
44     BOOST_STATIC_ASSERT_MSG(
45         boost::is_void< typename boost::remove_pointer<To>::type >::value
46         || boost::is_void< typename boost::remove_pointer<From>::type >::value,
47         "`agressive_ptr_cast` function must be used only for casting to or from void pointers."
48     );
49 
50     BOOST_STATIC_ASSERT_MSG(
51         sizeof(v) == sizeof(To),
52         "Pointer to function and pointer to object differ in size on your platform."
53     );
54 
55     return reinterpret_cast<To>(v);
56 }
57 
58 #ifdef BOOST_MSVC
59 #   pragma warning(push)
60 #   pragma warning(disable: 4172) // "returning address of local variable or temporary" but **v is not local!
61 #endif
62 
63 template <class To, class From>
64 BOOST_FORCEINLINE typename boost::disable_if_c<!boost::is_reference<To>::value || boost::is_member_pointer<From>::value, To>::type
aggressive_ptr_cast(From v)65     aggressive_ptr_cast(From v) BOOST_NOEXCEPT
66 {
67     BOOST_STATIC_ASSERT_MSG(
68         boost::is_pointer<From>::value,
69         "`agressive_ptr_cast` function must be used only for pointer casting."
70     );
71 
72     BOOST_STATIC_ASSERT_MSG(
73         boost::is_void< typename boost::remove_pointer<From>::type >::value,
74         "`agressive_ptr_cast` function must be used only for casting to or from void pointers."
75     );
76 
77     BOOST_STATIC_ASSERT_MSG(
78         sizeof(v) == sizeof(typename boost::remove_reference<To>::type*),
79         "Pointer to function and pointer to object differ in size on your platform."
80     );
81     return static_cast<To>(
82         **reinterpret_cast<typename boost::remove_reference<To>::type**>(
83             v
84         )
85     );
86 }
87 
88 #ifdef BOOST_MSVC
89 #   pragma warning(pop)
90 #endif
91 
92 template <class To, class From>
93 BOOST_FORCEINLINE typename boost::disable_if_c<!boost::is_member_pointer<To>::value || boost::is_member_pointer<From>::value, To>::type
aggressive_ptr_cast(From v)94     aggressive_ptr_cast(From v) BOOST_NOEXCEPT
95 {
96     BOOST_STATIC_ASSERT_MSG(
97         boost::is_pointer<From>::value,
98         "`agressive_ptr_cast` function must be used only for pointer casting."
99     );
100 
101     BOOST_STATIC_ASSERT_MSG(
102         boost::is_void< typename boost::remove_pointer<From>::type >::value,
103         "`agressive_ptr_cast` function must be used only for casting to or from void pointers."
104     );
105 
106     To res = 0;
107     std::memcpy(&res, &v, sizeof(From));
108     return res;
109 }
110 
111 template <class To, class From>
112 BOOST_FORCEINLINE typename boost::disable_if_c<boost::is_member_pointer<To>::value || !boost::is_member_pointer<From>::value, To>::type
aggressive_ptr_cast(From)113     aggressive_ptr_cast(From /* v */) BOOST_NOEXCEPT
114 {
115     BOOST_STATIC_ASSERT_MSG(
116         boost::is_pointer<To>::value,
117         "`agressive_ptr_cast` function must be used only for pointer casting."
118     );
119 
120     BOOST_STATIC_ASSERT_MSG(
121         boost::is_void< typename boost::remove_pointer<To>::type >::value,
122         "`agressive_ptr_cast` function must be used only for casting to or from void pointers."
123     );
124 
125     BOOST_STATIC_ASSERT_MSG(
126         !sizeof(From),
127         "Casting from member pointers to void pointer is not implemnted in `agressive_ptr_cast`."
128     );
129 
130     return 0;
131 }
132 
133 }}} // boost::dll::detail
134 
135 #endif // BOOST_DLL_DETAIL_AGGRESSIVE_PTR_CAST_HPP
136 
137