@@ -3,12 +3,19 @@ module c_interface_poly
33! ! from https://github.com/mattzett/fortran_tests
44
55 use datamod_poly, only: dataobj_poly,data1,data2
6- use , intrinsic :: iso_c_binding, only: c_loc,c_ptr,c_f_pointer,c_int, c_float, c_size_t
6+ use , intrinsic :: iso_c_binding, only: c_loc,c_ptr,c_f_pointer,c_int, c_float, c_size_t, c_null_ptr, c_associated
77 implicit none
88
9+ integer (c_int), parameter :: STATUS_SUCCESS = 0_c_int
10+ integer (c_int), parameter :: STATUS_INVALID_TYPE = 1_c_int
11+ integer (c_int), parameter :: STATUS_NULL_PTR = 2_c_int
12+ integer (c_int), parameter :: STATUS_ZERO_DIMS = 3_c_int
13+ integer (c_int), parameter :: STATUS_ALLOC_FAIL = 4_c_int
14+ integer (c_int), parameter :: STATUS_BAD_OBJECT_PTR = 5_c_int
15+
916contains
1017
11- subroutine objconstruct_C (objtype ,cptr_f90obj ,cptr_indata ,lx ,ly ) bind(C, name= ' objconstruct_C' )
18+ integer (c_int) function objconstruct_C(objtype,cptr_f90obj,cptr_indata,lx,ly) bind(C, name= ' objconstruct_C' )
1219! ! return a c pointer to a fortran polymorphic object that is created by this routine; in this case we
1320! ! are passing the object type to be created from the C main program
1421 integer (c_int), intent (in ) :: objtype
@@ -19,24 +26,44 @@ subroutine objconstruct_C(objtype,cptr_f90obj,cptr_indata,lx,ly) bind(C, name='o
1926 type (data1), pointer :: tmpobj1 ! < declared as pointers so they don't auto-allocate when we return
2027 type (data2), pointer :: tmpobj2 ! < ditto
2128 real (c_float), dimension (:,:), pointer :: fortdata
29+ integer :: alloc_status
2230
2331 ! > nullify for sake of clarity and good practice
2432 nullify(tmpobj1, tmpobj2)
33+ objconstruct_C = STATUS_SUCCESS
34+ cptr_f90obj = c_null_ptr
35+
36+ if (.not. c_associated(cptr_indata)) then
37+ objconstruct_C = STATUS_NULL_PTR
38+ return
39+ end if
40+
41+ if (lx == 0_c_size_t .or. ly == 0_c_size_t ) then
42+ objconstruct_C = STATUS_ZERO_DIMS
43+ return
44+ end if
2545
2646 ! > allocate derived type, note that c_loc only works on a static type (i.e. not polymorphic class), hence the tmpobj's
2747 select case (objtype)
2848 case (1 )
29- allocate (data1:: obj)
30- allocate (tmpobj1)
49+ allocate (tmpobj1, stat= alloc_status)
50+ if (alloc_status /= 0 ) then
51+ objconstruct_C = STATUS_ALLOC_FAIL
52+ return
53+ end if
3154 cptr_f90obj= c_loc(tmpobj1)
3255 obj= >tmpobj1
3356 case (2 )
34- allocate (data2:: obj)
35- allocate (tmpobj2)
57+ allocate (tmpobj2, stat= alloc_status)
58+ if (alloc_status /= 0 ) then
59+ objconstruct_C = STATUS_ALLOC_FAIL
60+ return
61+ end if
3662 cptr_f90obj= c_loc(tmpobj2)
3763 obj= >tmpobj2
3864 case default
39- error stop ' unable to identify object type during construction'
65+ objconstruct_C = STATUS_INVALID_TYPE
66+ return
4067 end select
4168
4269 ! > initialize some test data, and call methods to print
@@ -45,53 +72,87 @@ subroutine objconstruct_C(objtype,cptr_f90obj,cptr_indata,lx,ly) bind(C, name='o
4572 call obj% set_data(fortdata)
4673
4774 ! ! note lack of deallocate and nullify here; we need memory allocated to persist past the return.
48- end subroutine objconstruct_C
75+ end function objconstruct_C
4976
5077
5178! > Use some of the polymorphic object methods and data
52- subroutine objuse_C (objtype ,objC ) bind(C, name= ' objuse_C' )
79+ integer (c_int) function objuse_C(objtype,objC) bind(C, name= ' objuse_C' )
5380 type (c_ptr), intent (in ) :: objC
5481 integer (c_int), intent (in ) :: objtype
5582 class(dataobj_poly),pointer :: obj
83+ integer (c_int) :: status
84+
85+ objuse_C = STATUS_SUCCESS
86+ if (.not. c_associated(objC)) then
87+ objuse_C = STATUS_NULL_PTR
88+ return
89+ end if
90+
91+ call set_pointer_dyntype(objtype,objC,obj,status)
92+ if (status /= 0 ) then
93+ objuse_C = status
94+ return
95+ end if
5696
57- obj= >set_pointer_dyntype(objtype,objC)
5897 call obj% print_data()
59- end subroutine objuse_C
98+ end function objuse_C
6099
61100
62101! > set fortran object pointer dynamic type to what is indicated in objtype. Convert C pointer using
63102! declared static types (c_f_pointer will not work on a polymorphic object).
64- function set_pointer_dyntype (objtype , objC ) result( obj)
103+ subroutine set_pointer_dyntype (objtype , objC , obj , status )
65104 type (c_ptr), intent (in ) :: objC
66105 integer (c_int), intent (in ) :: objtype
67- class(dataobj_poly), pointer :: obj
106+ class(dataobj_poly), pointer , intent (out ) :: obj
107+ integer (c_int), intent (out ) :: status
68108 type (data1), pointer :: obj1
69109 type (data2), pointer :: obj2
70110
111+ status = STATUS_SUCCESS
112+ nullify(obj)
113+ nullify(obj1, obj2)
114+
71115 select case (objtype)
72116 case (1 )
73117 call c_f_pointer(objC,obj1)
118+ if (.not. associated (obj1)) then
119+ status = STATUS_BAD_OBJECT_PTR
120+ return
121+ end if
74122 obj= >obj1
75123 case (2 )
76124 call c_f_pointer(objC,obj2)
125+ if (.not. associated (obj2)) then
126+ status = STATUS_BAD_OBJECT_PTR
127+ return
128+ end if
77129 obj= >obj2
78130 case default
79- error stop ' ERROR: set_pointer_dyntype: unable to identify object type during conversion from C to fortran class pointer '
131+ status = STATUS_INVALID_TYPE
80132 end select
81- end function set_pointer_dyntype
133+ end subroutine set_pointer_dyntype
82134
83135
84- subroutine destruct_C (objtype , objC ) bind(C, name= ' destruct_C' )
136+ integer (c_int) function destruct_C(objtype, objC) bind(C, name= ' destruct_C' )
85137type (c_ptr), intent (inout ) :: objC
86138integer (c_int), intent (in ) :: objtype
87139
88140class(dataobj_poly),pointer :: obj
141+ integer (c_int) :: status
142+
143+ destruct_C = STATUS_SUCCESS
144+ if (.not. c_associated(objC)) return
89145
90- obj= >set_pointer_dyntype(objtype,objC)
146+ call set_pointer_dyntype(objtype,objC,obj,status)
147+ if (status /= 0 ) then
148+ destruct_C = status
149+ return
150+ end if
91151
92- deallocate (obj% dataval)
152+ if ( associated (obj % dataval)) deallocate (obj% dataval)
93153deallocate (obj)
154+ objC = c_null_ptr
94155
95- end subroutine
156+ end function destruct_C
96157
97158end module c_interface_poly
0 commit comments