Skip to content

Commit 6b55f08

Browse files
committed
Added tests and errors bubble-up
1 parent 0ccf977 commit 6b55f08

13 files changed

Lines changed: 408 additions & 114 deletions

fortitude.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ select = [ "C", "E", "S", "PORT" ]
66
#Ignoring:
77
# C003: 'implicit none' missing 'external' [f2py does not recognize the syntax implicit none(type, external)]
88
# ignore = ["C003","C072","S221"]
9-
ignore = ["C003"]
9+
ignore = ["C003","S221"]
1010
line-length = 120

src/example_fgen_basic/error_v/creation.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function create_error(inv) result(err)
3131
return
3232
end if
3333

34-
if (mod(inv, 2) .eq. 0) then
34+
if (mod(inv, 2) == 0) then
3535
err = ErrorV(code=1, message="Even number supplied")
3636
else
3737
err = ErrorV(code=NO_ERROR_CODE)

src/example_fgen_basic/error_v/creation_wrapper.f90

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module m_error_v_creation_w
1515
use m_error_v_manager, only: &
1616
error_v_manager_get_available_instance_index => get_available_instance_index, &
1717
error_v_manager_set_instance_index_to => set_instance_index_to, &
18-
error_v_manager_ensure_instance_array_size_is_at_least => ensure_instance_array_size_is_at_least
18+
error_v_manager_ensure_array_capacity_for_instances => ensure_array_capacity_for_instances
1919

2020
implicit none
2121
private
@@ -44,7 +44,7 @@ function create_error(inv) result(res_instance_index)
4444
! Do the Fortran call
4545
res = o_create_error(inv)
4646

47-
call error_v_manager_ensure_instance_array_size_is_at_least(1)
47+
call error_v_manager_ensure_array_capacity_for_instances(1)
4848

4949
! Get the instance index to return to Python
5050
call error_v_manager_get_available_instance_index(res_instance_index)
@@ -81,11 +81,11 @@ function create_errors(invs, n) result(res_instance_indexes)
8181
! Lots of ways resizing could work.
8282
! Optimising could be very tricky.
8383
! Just do something stupid for now to see the pattern.
84-
call error_v_manager_ensure_instance_array_size_is_at_least(n)
84+
call error_v_manager_ensure_array_capacity_for_instances(n)
8585

8686
allocate(res(n))
8787
! Do the Fortran call
88-
! MZ: somenthing funny happens wheb res is an automatic array and
88+
! MZ: somenthing funny happens when res is an automatic array and
8989
! not an allocatable one. LLMs and internet resorces I found are not
9090
! completely clear to me. What seems to happen is that returning an array of derived types with allocatable
9191
! components may generate hidden temporary arrays whose allocatable components

src/example_fgen_basic/error_v/error_v.f90

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ module m_error_v
3131

3232
! TODO: think about adding trace (might be simpler than compiling with traceback)
3333
! class(ErrorV), allocatable :: cause
34-
type(ErrorV), pointer :: cause => null()
34+
! type(ErrorV), pointer :: cause => null()
35+
integer :: cause = 0
3536

3637
contains
3738

@@ -98,7 +99,7 @@ function constructor(code, message, cause) result(self)
9899

99100
integer, intent(in) :: code
100101
character(len=*), optional, intent(in) :: message
101-
type(ErrorV), target, optional, intent(in) :: cause
102+
integer, optional, intent(in) :: cause
102103

103104
type(ErrorV) :: self
104105

@@ -119,26 +120,14 @@ subroutine build(self, code, message, cause)
119120

120121
character(len=*), optional, intent(in) :: message
121122
!! Error message
122-
type(ErrorV), target, optional, intent(in) :: cause
123+
124+
integer, optional, intent(in) :: cause
123125

124126
self % code = code
125127

126-
if (present(cause)) then
127-
! self % cause => cause
128-
! allocate(self % cause)
129-
! call self%cause%build(cause%code, cause%message, cause%cause)
130-
! self%cause = cause
131-
if (present(message)) then
132-
self % message = adjustl(trim(message)) // " --> Cause: " // cause % message
133-
else
134-
self % message = " --> Cause: " // cause % message
135-
end if
136-
137-
else
138-
if (present(message)) then
139-
self % message = adjustl(trim(message))
140-
end if
141-
end if
128+
if (present(cause)) self % cause = cause
129+
130+
if (present(message)) self % message = adjustl(trim(message))
142131

143132
end subroutine build
144133
! subroutine build(self, code, message, cause)
@@ -185,10 +174,11 @@ subroutine finalise(self)
185174

186175
! If we make message allocatable, deallocate here
187176
self % code = 1
177+
self % cause = 0
188178
if (allocated(self%message)) deallocate(self%message)
189179
! MZ when the object is finalized or goes out of scope, its pointer components are destroyed.
190180
! Hopefully no shared ownership??
191-
if (associated(self%cause)) nullify(self%cause)
181+
! if (associated(self%cause)) nullify(self%cause)
192182
! if (allocated(self%cause)) deallocate(self%cause)
193183

194184
end subroutine finalise

src/example_fgen_basic/error_v/error_v_manager.f90

Lines changed: 131 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ module m_error_v_manager
1010
private
1111

1212
type(ErrorV), dimension(:), allocatable :: instance_array
13+
! MZ : Do we really need instance_available?
1314
logical, dimension(:), allocatable :: instance_available
1415

1516
! TODO: think about ordering here, alphabetical probably easiest
16-
public :: build_instance, finalise_instance, get_available_instance_index, get_instance, set_instance_index_to, &
17-
ensure_instance_array_size_is_at_least
17+
public :: build_instance, finalise_instance, get_available_instance_index, get_instance, get_error_message, &
18+
set_instance_index_to, ensure_array_capacity_for_instances,deallocate_instance_arrays
1819

1920
contains
2021

21-
function build_instance(code, message) result(instance_index)
22+
function build_instance(code, message, cause) result(instance_index)
2223
!! Build an instance
2324

2425
integer, intent(in) :: code
@@ -27,12 +28,14 @@ function build_instance(code, message) result(instance_index)
2728
character(len=*), optional, intent(in) :: message
2829
!! Error message
2930

31+
integer, optional, intent(in) :: cause
32+
3033
integer :: instance_index
3134
!! Index of the built instance
3235

33-
call ensure_instance_array_size_is_at_least(1)
36+
call ensure_array_capacity_for_instances(1)
3437
call get_available_instance_index(instance_index)
35-
call instance_array(instance_index) % build(code=code, message=message)
38+
call instance_array(instance_index) % build(code=code, message=message, cause=cause)
3639

3740
end function build_instance
3841

@@ -82,7 +85,7 @@ subroutine get_available_instance_index(available_instance_index)
8285

8386
! TODO: switch to returning a Result type with an error set
8487
! res = ResultInt(ErrorV(code=1, message="No available instances"))
85-
print *, "print"
88+
print *, "print dioooo"
8689
error stop 1
8790

8891
end subroutine get_available_instance_index
@@ -97,6 +100,8 @@ function get_instance(instance_index) result(err_inst)
97100
!! Instance at `instance_array(instance_index)`
98101

99102
type(ErrorV) :: err_check_index_claimed
103+
104+
integer :: cause
100105
character(len=20) :: idx_str
101106
character(len=:), allocatable :: msg
102107

@@ -107,39 +112,46 @@ function get_instance(instance_index) result(err_inst)
107112
err_inst = instance_array(instance_index)
108113

109114
else
115+
110116
write(idx_str, "(I0)") instance_index
111117
msg = "Error at get_instance -> " // trim(adjustl(idx_str))
112118

113-
err_inst = ErrorV( &
119+
cause = build_instance(code=err_check_index_claimed % code, message=err_check_index_claimed % message)
120+
121+
call err_inst % build( &
114122
code= err_check_index_claimed%code,&
115123
message = msg, &
116-
cause = err_check_index_claimed &
124+
cause = cause &
117125
)
118126
end if
119127

120128
end function get_instance
121129

122-
function set_instance_index_to(instance_index, val) result(err)
130+
function set_instance_index_to(instance_index, val) result(err_inst)
123131

124132
integer, intent(in) :: instance_index
125133
!! Index in `instance_array` of which to set the value equal to `val`
126134

127135
type(ErrorV), intent(in) :: val
128-
type(ErrorV) :: err
136+
type(ErrorV) :: err_inst
129137

130138
type(ErrorV) :: err_check_index_claimed
139+
integer :: cause
131140
character(len=:), allocatable :: msg
132141

133142
err_check_index_claimed = check_index_claimed(instance_index)
134143

135-
if(err_check_index_claimed%code /= NO_ERROR_CODE) then
144+
if (err_check_index_claimed%code /= NO_ERROR_CODE) then
136145
! MZ: here we do not set if the index has not been claimed.
137146
! Must be harmonised with Results type
138147
msg ="Setting Instance Error: "
139-
err = ErrorV ( &
140-
code = err_check_index_claimed% code, &
148+
149+
cause = build_instance(code=err_check_index_claimed % code, message=err_check_index_claimed % message)
150+
151+
call err_inst % build( &
152+
code= err_check_index_claimed%code,&
141153
message = msg, &
142-
cause = err_check_index_claimed &
154+
cause = cause &
143155
)
144156

145157
else
@@ -153,7 +165,7 @@ function set_instance_index_to(instance_index, val) result(err)
153165
! Reassigning the slot
154166
call instance_array(instance_index)%build(code=val%code, message=val%message, cause=val%cause)
155167

156-
err = ErrorV(code=NO_ERROR_CODE)
168+
call err_inst % build(code= NO_ERROR_CODE)
157169

158170
end if
159171

@@ -192,8 +204,7 @@ function check_index_claimed(instance_index) result(err_check_index_claimed)
192204
! print *, "Index ", instance_index, " has not been claimed"
193205
! error stop 1
194206
msg = "Index " // trim(adjustl(idx_str)) // " has not been claimed"
195-
196-
err_check_index_claimed = ErrorV(code=1, message=msg)
207+
call err_check_index_claimed % build(code=1, message=msg)
197208

198209
return
199210
end if
@@ -209,41 +220,123 @@ function check_index_claimed(instance_index) result(err_check_index_claimed)
209220
! print *, "Requested index is ", instance_index, " which is less than 1"
210221
! error stop 1
211222
msg = "Requested index is: " // trim(adjustl(idx_str)) // " ==> out of boundary"
212-
err_check_index_claimed = ErrorV(code=2, message=msg)
223+
call err_check_index_claimed % build(code=2, message=msg)
213224

214225
return
215226
end if
216227

217-
err_check_index_claimed = ErrorV(code=NO_ERROR_CODE)
228+
call err_check_index_claimed % build(code=NO_ERROR_CODE)
218229

219230
end function check_index_claimed
220231

221-
subroutine ensure_instance_array_size_is_at_least(n)
222-
!! Ensure that `instance_array` and `instance_available` have at least `n` slots
232+
! subroutine ensure_instance_array_size_is_at_least(n)
233+
! !! Ensure that `instance_array` and `instance_available` have at least `n` slots
234+
!
235+
! integer, intent(in) :: n
236+
!
237+
! type(ErrorV), dimension(:), allocatable :: tmp_instances
238+
! logical, dimension(:), allocatable :: tmp_available
239+
!
240+
! if (.not. allocated(instance_array)) then
241+
! allocate (instance_array(n))
242+
!
243+
! allocate (instance_available(n))
244+
! ! Race conditions ?
245+
! instance_available = .true.
246+
!
247+
! else if (size(instance_available) < n) then
248+
! allocate (tmp_instances(n))
249+
! tmp_instances(1:size(instance_array)) = instance_array
250+
! call move_alloc(tmp_instances, instance_array)
251+
!
252+
! allocate (tmp_available(n))
253+
! tmp_available(1:size(instance_available)) = instance_available
254+
! tmp_available(size(instance_available) + 1:size(tmp_available)) = .true.
255+
! call move_alloc(tmp_available, instance_available)
256+
!
257+
! end if
258+
! end subroutine ensure_instance_array_size_is_at_least
259+
260+
subroutine ensure_array_capacity_for_instances(n)
261+
!! Ensure that `instance_array` has at least `n` slots
262+
263+
integer, intent(in) :: n
264+
type(ErrorV), dimension(:), allocatable :: tmp_instances
265+
logical, dimension(:), allocatable :: tmp_available
266+
267+
integer :: free_count
268+
269+
if (.not. allocated(instance_array)) then
270+
271+
allocate (instance_array(n),instance_available(n))
272+
! Race conditions ?
273+
instance_available = .true.
274+
275+
else if (size(instance_array) < n) then
276+
! MZ: in this case we just add n spaces on top
223277

224-
integer, intent(in) :: n
278+
allocate(tmp_instances(n+size(instance_array)), &
279+
tmp_available(n+size(instance_available)) &
280+
)
225281

226-
type(ErrorV), dimension(:), allocatable :: tmp_instances
227-
logical, dimension(:), allocatable :: tmp_available
282+
tmp_instances(1:size(instance_array)) = instance_array
283+
tmp_available = .true.
284+
tmp_available(1:size(instance_available)) = instance_available
228285

229-
if (.not. allocated(instance_array)) then
230-
allocate (instance_array(n))
286+
call move_alloc(tmp_instances, instance_array)
287+
call move_alloc(tmp_available, instance_available)
231288

232-
allocate (instance_available(n))
233-
! Race conditions ?
234-
instance_available = .true.
289+
else
235290

236-
else if (size(instance_available) < n) then
237-
allocate (tmp_instances(n))
238-
tmp_instances(1:size(instance_array)) = instance_array
239-
call move_alloc(tmp_instances, instance_array)
291+
free_count = count(instance_available)
240292

241-
allocate (tmp_available(n))
242-
tmp_available(1:size(instance_available)) = instance_available
243-
tmp_available(size(instance_available) + 1:size(tmp_available)) = .true.
244-
call move_alloc(tmp_available, instance_available)
293+
if (free_count < n) then
294+
! MZ: doubling the size might be more efficient in the long run??
295+
allocate(tmp_instances(size(instance_array)*2),&
296+
tmp_available(size(instance_available)*2) &
297+
)
245298

299+
tmp_instances(1:size(instance_array)) = instance_array
300+
tmp_available = .true.
301+
tmp_available(1:size(instance_available)) = instance_available
302+
303+
call move_alloc(tmp_instances, instance_array)
304+
call move_alloc(tmp_available, instance_available)
305+
306+
end if
307+
308+
end if
309+
310+
end subroutine ensure_array_capacity_for_instances
311+
312+
pure recursive function get_error_message(err) result(full_msg)
313+
314+
type(ErrorV), intent(in) :: err
315+
316+
character(len=:), allocatable :: full_msg
317+
character(len=:), allocatable :: cause_msg
318+
319+
full_msg = err%message
320+
321+
if (err%cause/=0) then
322+
!MZ : free slot while passing by?
323+
cause_msg = get_error_message(instance_array(err%cause))
324+
full_msg = trim(full_msg) // NEW_LINE("A") // " Previous error --> " // trim(cause_msg)
246325
end if
247-
end subroutine ensure_instance_array_size_is_at_least
326+
327+
end function get_error_message
328+
329+
subroutine deallocate_instance_arrays()
330+
!! Finalise an instance
331+
332+
if (allocated(instance_available).and.allocated(instance_array)) then
333+
deallocate(instance_available,instance_array)
334+
else if(allocated(instance_available))then
335+
deallocate(instance_available)
336+
else if(allocated(instance_array)) then
337+
deallocate(instance_array)
338+
end if
339+
340+
end subroutine deallocate_instance_arrays
248341

249342
end module m_error_v_manager

0 commit comments

Comments
 (0)