Skip to content

Commit 30d0294

Browse files
committed
Fix, make type-safe, and remove brute_cast from member function pointers
1 parent aef3bde commit 30d0294

File tree

2 files changed

+26
-121
lines changed

2 files changed

+26
-121
lines changed

Examples/test-suite/fortran/member_pointer_runme.F90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ program member_pointer_runme
66
use member_pointer
77
use ISO_C_BINDING
88
implicit none
9-
type(SwigOpaqueMemFunPtr) :: area_memptr, perim_memptr
9+
type(SWIGTYPE_m_Shape__f_void__double) :: area_memptr, perim_memptr
1010
type(Square) :: s
1111
real(C_DOUBLE) :: val
1212

Lib/fortran/memfunptr.swg

Lines changed: 25 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -2,141 +2,46 @@
22
* memfunptr.swg
33
* ------------------------------------------------------------------------- */
44

5-
/* The size of the opaque object that stores the member function pointer.
6-
*
7-
* This could be overridden by generating a config.h file with the actual
8-
* maximum function pointer size and %include-ing that configure file in
9-
* a local fortranfragments.swg file. */
10-
#ifndef SWIG_MEMFUNPTR_SIZE
11-
%define SWIG_MEMFUNPTR_SIZE 32 %enddef
12-
#endif
13-
14-
/* -------------------------------------------------------------------------
15-
* BRUTE CAST
16-
* ------------------------------------------------------------------------- */
17-
18-
// This fragment allows making an opaque datatype from C++ member function
19-
// pointers (which according to the standard CANNOT be converted to a pointer).
20-
// encountered. Its syntax is exactly like static_cast.
21-
// Note that the <string.h> fragment imports size_t into the global namespace.
22-
%fragment("swig::brute_cast", "header", fragment="<string.h>") %{
23-
template<typename Dst, typename Src>
24-
SWIGINTERN void SWIG_opaque_memcpy(Dst *dst, const Src *src) {
25-
const size_t MINSIZE
26-
= (sizeof(Dst) < sizeof(Src) ? sizeof(Dst) : sizeof(Src));
27-
const size_t MAXSIZE
28-
= (sizeof(Dst) > sizeof(Src) ? sizeof(Dst) : sizeof(Src));
29-
memcpy(dst, src, MINSIZE);
30-
if (MAXSIZE > MINSIZE)
31-
{
32-
memset(static_cast<char*>(static_cast<void*>(dst)) + MINSIZE,
33-
0,
34-
MAXSIZE - MINSIZE);
35-
}
36-
}
37-
38-
namespace swig {
39-
template<typename Target>
40-
class brute_cast_impl {
41-
public:
42-
template<typename Source>
43-
brute_cast_impl(const Source &src_fwd) {
44-
SWIG_opaque_memcpy(&d_result, &src_fwd);
45-
}
46-
Target operator() () const { return d_result; }
5+
%fragment("SwigFortranPackedData", "header",
6+
fragment="<string.h>", fragment="<stdlib.h>") %{
7+
class SwigFortranPackedData {
478
private:
48-
Target d_result;
49-
};
9+
char* packed_;
5010

51-
template<typename Target>
52-
class brute_cast_impl<Target&> {
5311
public:
54-
template<typename Source>
55-
brute_cast_impl(Source& src_ref) {
56-
Source *src_ptr = &src_ref;
57-
SWIG_opaque_memcpy(&d_result, &src_ptr);
58-
}
59-
Target &operator() () const { return *d_result; }
60-
private:
61-
Target *d_result;
62-
};
63-
64-
template<class Target, class Source>
65-
SWIGINTERN Target brute_cast(const Source& src) {
66-
return brute_cast_impl<Target>(src)();
67-
}
68-
} // end namespace swig
69-
70-
using swig::brute_cast;
71-
%}
12+
template<class T>
13+
SwigFortranPackedData(const T* data) {
14+
packed_ = (char *)malloc(sizeof(T));
15+
memcpy(packed_, data, sizeof(T));
16+
}
7217

73-
/* -------------------------------------------------------------------------
74-
* MEMBER FUNCTION POINTERS
75-
*
76-
* We memcpy the member function pointer to an opaque data class using
77-
* brute_cast.
78-
* ------------------------------------------------------------------------- */
18+
~SwigFortranPackedData() { free(packed_); }
7919

80-
// Add array wrapper to C++ code when used by Fortran fragment
81-
%fragment("SwigOpaqueMemFunPtr", "header", noblock=1, fragment="<string.h>") {
82-
%#if __cplusplus >= 201103L
83-
namespace detail { class UndefinedClass; }
84-
%#endif
20+
template<class T>
21+
void unpack(T* data) const {
22+
memcpy(data, packed_, sizeof(T));
23+
}
8524

86-
struct SwigOpaqueMemFunPtr {
87-
char data[SWIG_MEMFUNPTR_SIZE];
88-
%#if __cplusplus >= 201103L
89-
static_assert(sizeof(void (detail::UndefinedClass::*)()) <= SWIG_MEMFUNPTR_SIZE,
90-
"Member pointer buffer isn't large enough");
91-
%#endif
25+
private:
26+
SwigFortranPackedData& operator=(const SwigFortranPackedData& other);
9227
};
93-
94-
SWIGINTERN SwigOpaqueMemFunPtr SwigOpaqueMemFunPtr_uninitialized() {
95-
SwigOpaqueMemFunPtr result;
96-
memset(result.data, 0, sizeof(result.data));
97-
return result;
98-
}
99-
}
100-
101-
// This fragment is inserted by the fortran.cxx code when an unknown class is
102-
// encountered. Note for this to compile and not crash, the size of 'data' should
103-
// be the same size as in SwigOpaqueMemFunPtr.
104-
%fragment("SwigOpaqueMemFunPtr_f", "fdecl", noblock=1, fragment="SwigOpaqueMemFunPtr")
105-
{ type, public, bind(C) :: SwigOpaqueMemFunPtr
106-
integer(C_SIGNED_CHAR), dimension(SWIG_MEMFUNPTR_SIZE), public :: data
107-
end type}
28+
%}
10829

10930
/* -------------------------------------------------------------------------
11031
* TYPEMAPS
11132
* ------------------------------------------------------------------------- */
11233

113-
%typemap(ctype, fragment="SwigOpaqueMemFunPtr",
114-
null="SwigOpaqueMemFunPtr_uninitialized()") SWIGTYPE (CLASS::*)
115-
"SwigOpaqueMemFunPtr"
116-
%typemap(imtype, in="type(SwigOpaqueMemFunPtr), intent(in), value",
117-
fragment="SwigOpaqueMemFunPtr_f") SWIGTYPE (CLASS::*)
118-
"type(SwigOpaqueMemFunPtr)"
119-
%typemap(ftype, in="type(SwigOpaqueMemFunPtr), intent(in), value",
120-
fragment="SwigOpaqueMemFunPtr_f") SWIGTYPE (CLASS::*)
121-
"type(SwigOpaqueMemFunPtr)"
122-
123-
%typemap(in, noblock=1, fragment="swig::brute_cast") SWIGTYPE (CLASS::*) {
124-
$1 = brute_cast<$1_ltype>($input);
125-
}
126-
%typemap(out, noblock=1, fragment="swig::brute_cast") SWIGTYPE (CLASS::*) {
127-
$result = brute_cast<SwigOpaqueMemFunPtr>($1);
34+
%typemap(in, noblock=1, fragment="SwigFortranPackedData") SWIGTYPE (CLASS::*) {
35+
((SwigFortranPackedData*)($input->cptr))->unpack<$1_ltype>(&$1);
12836
}
129-
%typemap(fin) SWIGTYPE (CLASS::*)
130-
"$1 = $input"
131-
%typemap(fout) SWIGTYPE (CLASS::*)
132-
"$result = $1"
13337

134-
%typemap(bindc, in="type(C_FUNPTR), value",
135-
fragment="SwigOpaqueMemFunPtr_f") SWIGTYPE (CLASS::*)
136-
"type(SwigOpaqueMemFunPtr)"
38+
%typemap(out, noblock=1, fragment="SwigFortranPackedData") SWIGTYPE (CLASS::*) {
39+
$result.cptr = new SwigFortranPackedData(&$1);
40+
$result.cmemflags = SWIG_MEM_RVALUE | SWIG_MEM_OWN;
41+
}
13742

13843
// The SWIG type system does not check the non-const memfunptr when looking for a const memfunptr. Also apply
13944
%apply SWIGTYPE (CLASS::*) { SWIGTYPE (CLASS::* const) };
14045

141-
// I'm not sure this is correct, but it allows member_funcptr_galore to pass.
142-
%apply SWIGTYPE (CLASS::*) { SWIGTYPE (CLASS::* const &)};
46+
// References to member function pointers will look like regular class references
47+
%apply SWIGTYPE & { SWIGTYPE (CLASS::*const&) }

0 commit comments

Comments
 (0)