Skip to content

Commit 7937334

Browse files
committed
Add square root for easier illustration
1 parent e2145a0 commit 7937334

5 files changed

Lines changed: 168 additions & 0 deletions

File tree

meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ if pyprojectwheelbuild_enabled
6666
'src/example_fgen_basic/error_v/passing.f90',
6767
'src/example_fgen_basic/fpyfgen/base_finalisable.f90',
6868
'src/example_fgen_basic/fpyfgen/derived_type_manager_helpers.f90',
69+
'src/example_fgen_basic/get_square_root.f90',
6970
'src/example_fgen_basic/get_wavelength.f90',
7071
'src/example_fgen_basic/kind_parameters.f90',
7172
'src/example_fgen_basic/result/result.f90',
73+
'src/example_fgen_basic/result/result_dp.f90',
7274
'src/example_fgen_basic/result/result_int.f90',
7375
'src/example_fgen_basic/result/result_int1D.f90',
7476
'src/example_fgen_basic/result/result_none.f90',

scripts/inject-srcs-into-meson-build.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ def main():
9393
meson_variable, sorted(src_paths), REPO_ROOT
9494
)
9595

96+
# TODO: something wrong in here
9697
meson_build_out = re.sub(pattern, substitution, meson_build_out)
9798

9899
with open(REPO_ROOT / "meson.build", "w") as fh:
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
!> Get square root of a number
2+
module m_get_square_root
3+
4+
use kind_parameters, only: dp
5+
use m_error_v, only: ErrorV
6+
use m_result_dp, only: ResultDP
7+
8+
implicit none(type, external)
9+
private
10+
11+
public :: get_square_root
12+
13+
contains
14+
15+
function get_square_root(inv) result(res)
16+
!! Get square root of a number
17+
18+
real(kind=dp), intent(in) :: inv
19+
!! Frequency
20+
21+
type(ResultDP) :: res
22+
!! Result
23+
!!
24+
!! Square root if the number is positive or zero.
25+
!! Error otherwise.
26+
27+
if (inv >= 0) then
28+
res = ResultDP(data_v=sqrt(inv))
29+
else
30+
! TODO: include input value in the message
31+
res = ResultDP(error_v=ErrorV(code=1, message="Input value was negative"))
32+
end if
33+
34+
end function get_square_root
35+
36+
end module m_get_square_root
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
!> Result type for double precision real values
2+
!>
3+
!> Inspired by the excellent, MIT licensed
4+
!> https://github.com/samharrison7/fortran-error-handler
5+
module m_result_dp
6+
7+
use kind_parameters, only: dp
8+
use m_error_v, only: ErrorV
9+
use m_result, only: ResultBase
10+
use m_result_none, only: ResultNone
11+
12+
implicit none (type, external)
13+
private
14+
15+
type, extends(ResultBase), public :: ResultDP
16+
!! Result type that holds integer values
17+
18+
real(kind=dp), allocatable :: data_v
19+
!! Data i.e. the result (if no error occurs)
20+
21+
! Note: the error_v attribute comes from ResultBase
22+
23+
contains
24+
25+
private
26+
27+
procedure, public :: build
28+
procedure, public :: finalise
29+
final :: finalise_auto
30+
31+
end type ResultDP
32+
33+
interface ResultDP
34+
!! Constructor interface - see build [TODO: x-ref] for details
35+
module procedure :: constructor
36+
end interface ResultDP
37+
38+
contains
39+
40+
function constructor(data_v, error_v) result(self)
41+
!! Build instance
42+
43+
type(ResultDP) :: self
44+
! Hopefully can leave without docstring (like Python)
45+
46+
real(kind=dp), intent(in), optional :: data_v
47+
!! Data
48+
49+
class(ErrorV), intent(in), optional :: error_v
50+
!! Error
51+
52+
type(ResultNone) :: build_res
53+
54+
build_res = self % build(data_v_in=data_v, error_v_in=error_v)
55+
56+
if (build_res % is_error()) then
57+
58+
! This interface has to return the initialised object,
59+
! it cannot return a Result type,
60+
! so we have no choice but to raise a fatal error here.
61+
print *, build_res % error_v % message
62+
error stop build_res % error_v % code
63+
64+
! else
65+
! Assume no error occurred and initialisation was fine
66+
67+
end if
68+
69+
end function constructor
70+
71+
function build(self, data_v_in, error_v_in) result(res)
72+
!! Build instance
73+
74+
class(ResultDP), intent(out) :: self
75+
! Hopefully can leave without docstring (like Python)
76+
77+
real(kind=dp), intent(in), optional :: data_v_in
78+
!! Data
79+
80+
class(ErrorV), intent(in), optional :: error_v_in
81+
!! Error message
82+
83+
type(ResultNone) :: res
84+
!! Result
85+
86+
if (present(data_v_in) .and. present(error_v_in)) then
87+
res % error_v % message = "Both data and error were provided"
88+
89+
else if (present(data_v_in)) then
90+
allocate (self % data_v, source=data_v_in)
91+
! No error - no need to call res % build
92+
93+
else if (present(error_v_in)) then
94+
allocate (self % error_v, source=error_v_in)
95+
! No error - no need to call res % build
96+
97+
else
98+
res % error_v % message = "Neither data nor error were provided"
99+
100+
end if
101+
102+
end function build
103+
104+
subroutine finalise(self)
105+
!! Finalise the instance (i.e. free/deallocate)
106+
107+
class(ResultDP), intent(inout) :: self
108+
! Hopefully can leave without docstring (like Python)
109+
110+
if (allocated(self % data_v)) deallocate (self % data_v)
111+
if (allocated(self % error_v)) deallocate(self % error_v)
112+
113+
end subroutine finalise
114+
115+
subroutine finalise_auto(self)
116+
!! Finalise the instance (i.e. free/deallocate)
117+
!!
118+
!! This method is expected to be called automatically
119+
!! by clever clean up, which is why it differs from [TODO x-ref] `finalise`
120+
121+
type(ResultDP), intent(inout) :: self
122+
! Hopefully can leave without docstring (like Python)
123+
124+
call self % finalise()
125+
126+
end subroutine finalise_auto
127+
128+
end module m_result_dp

tests/unit/test_error_v_creation.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def test_create_error_even():
2929
assert res.message == "Even number supplied"
3030

3131

32+
@pytest.mark.xfail(reason="Not implemented")
3233
def test_create_error_negative_raises():
3334
# TODO: switch to more precise error type
3435
with pytest.raises(FortranError):

0 commit comments

Comments
 (0)