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