Skip to content

Commit 76292d3

Browse files
authored
error: implement general state_type handler (#938)
2 parents 1fe2171 + 473e1ec commit 76292d3

10 files changed

+825
-460
lines changed

doc/specs/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ This is an index/directory of the specifications (specs) for each new module/fea
1717
- [constants](./stdlib_constants.html) - Constants
1818
- [bitsets](./stdlib_bitsets.html) - Bitset data types and procedures
1919
- [error](./stdlib_error.html) - Catching and handling errors
20+
- [state_type](./stdlib_error_state_type.html) - General state and error handling
2021
- [hash](./stdlib_hash_procedures.html) - Hashing integer
2122
vectors or character strings
2223
- [hashmaps](./stdlib_hashmaps.html) - Hash maps/tables

doc/specs/stdlib_error_state_type.md

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: state_type
3+
---
4+
5+
# State and Error Handling Derived Type
6+
7+
[TOC]
8+
9+
## Introduction
10+
11+
The `stdlib_error` module provides a derived type holding information on the state of operations within the standard library and procedures for expert control of workflows.
12+
An optional `state_type` variable to hold such information is provided as a form of expert API.
13+
If the user does not require state information but fatal errors are encountered during execution, the program will undergo a hard stop.
14+
Instead, if the state argument is present, the program will never stop but will return detailed error information into the state handler.
15+
16+
## Derived types provided
17+
18+
<!-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->
19+
### The `state_type` derived type
20+
21+
The `state_type` is defined as a derived type containing an integer error flag and fixed-size character strings to store an error message and the location of the error state change.
22+
Fixed-size string storage was chosen to facilitate the compiler's memory allocation and ultimately ensure maximum computational performance.
23+
24+
A similarly named generic interface, `state_type`, is provided to allow the developer to create diagnostic messages and raise error flags easily.
25+
The call starts with an error flag or the location of the event and is followed by an arbitrary list of `integer`, `real`, `complex`, or `character` variables.
26+
Numeric variables may be provided as either scalars or rank-1 (array) inputs.
27+
28+
#### Type-bound procedures
29+
30+
The following convenience type-bound procedures are provided:
31+
- `print()` returns an allocatable character string containing state location, message, and error flag;
32+
- `print_message()` returns an allocatable character string containing the state message;
33+
- `ok()` returns a `logical` flag that is `.true.` in case of successful state (`flag==STDLIB_SUCCESS`);
34+
- `error()` returns a `logical` flag that is `.true.` in case of an error state (`flag/=STDLIB_SUCCESS`).
35+
36+
#### Status
37+
38+
Experimental
39+
40+
#### Example
41+
42+
```fortran
43+
{!example/error/example_error_state1.f90!}
44+
```
45+
46+
## Error flags provided
47+
48+
The module provides the following state flags:
49+
- `STDLIB_SUCCESS`: Successful execution
50+
- `STDLIB_VALUE_ERROR`: Numerical errors (such as infinity, not-a-number, range bounds) are encountered.
51+
- `STDLIB_LINALG_ERROR`: Linear Algebra errors are encountered, such as non-converging iterations, impossible operations, etc.
52+
- `STDLIB_INTERNAL_ERROR`: Provided as a developer safeguard for internal errors that should never occur.
53+
- `STDLIB_IO_ERROR`: Input/Output-related errors, such as file reading/writing failures.
54+
- `STDLIB_FS_ERROR`: File system-related errors, such as directory access issues.
55+
56+
## Comparison operators provided
57+
58+
The module provides overloaded comparison operators for all comparisons of a `state_type` variable with an integer error flag: `<`, `<=`, `==`, `>=`, `>`, `/=`.
59+

doc/specs/stdlib_linalg_state_type.md

+15-25
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,27 @@ title: linalg_state_type
88

99
## Introduction
1010

11-
The `stdlib_linalg_state` module provides a derived type holding information on the
12-
state of linear algebra operations, and procedures for expert control of linear algebra workflows.
13-
All linear algebra procedures are engineered to support returning an optional `linalg_state_type`
14-
variable to holds such information, as a form of expert API. If the user does not require state
15-
information, but fatal errors are encountered during the execution of linear algebra routines, the
16-
program will undergo a hard stop.
17-
Instead, if the state argument is present, the program will never stop, but will return detailed error
18-
information into the state handler.
11+
The `stdlib_linalg_state` module provides a derived type holding information on the state of linear algebra operations, and procedures for expert control of linear algebra workflows.
12+
All linear algebra procedures are engineered to support returning an optional `linalg_state_type` variable to hold such information, as a form of expert API. If the user does not require state information but fatal errors are encountered during the execution of linear algebra routines, the program will undergo a hard stop.
13+
Instead, if the state argument is present, the program will never stop but will return detailed error information into the state handler.
1914

2015
## Derived types provided
2116

2217
<!-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->
2318
### The `linalg_state_type` derived type
2419

25-
The `linalg_state_type` is defined as a derived type containing an integer error flag, and
26-
fixed-size character strings to store an error message and the location of the error state change.
27-
Fixed-size string storage was chosen to facilitate the compiler's memory allocation and ultimately
28-
ensure maximum computational performance.
20+
The `linalg_state_type` is an extension of the `state_type` derived type, containing an integer error flag and fixed-size character strings to store an error message and the location of the error state change.
21+
Fixed-size string storage was chosen to facilitate the compiler's memory allocation and ultimately ensure maximum computational performance.
2922

30-
A similarly named generic interface, `linalg_state_type`, is provided to allow the developer to
31-
create diagnostic messages and raise error flags easily. The call starts with an error flag or
32-
the location of the event, and is followed by an arbitrary list of `integer`, `real`, `complex` or
33-
`character` variables. Numeric variables may be provided as either scalars or rank-1 (array) inputs.
23+
A similarly named generic interface, `linalg_state_type`, is provided to allow the developer to create diagnostic messages and raise error flags easily. The call starts with an error flag or the location of the event and is followed by an arbitrary list of `integer`, `real`, `complex`, or `character` variables. Numeric variables may be provided as either scalars or rank-1 (array) inputs.
3424

3525
#### Type-bound procedures
3626

37-
The following convenience type-bound procedures are provided:
27+
The following convenience type-bound procedures are inherited from `state_type` and available:
3828
- `print()` returns an allocatable character string containing state location, message, and error flag;
3929
- `print_message()` returns an allocatable character string containing the state message;
4030
- `ok()` returns a `logical` flag that is `.true.` in case of successful state (`flag==LINALG_SUCCESS`);
41-
- `error()` returns a `logical` flag that is `.true.` in case of error state (`flag/=LINALG_SUCCESS`).
31+
- `error()` returns a `logical` flag that is `.true.` in case of an error state (`flag/=LINALG_SUCCESS`).
4232

4333
#### Status
4434

@@ -52,13 +42,13 @@ Experimental
5242

5343
## Error flags provided
5444

55-
The module provides the following state flags:
56-
- `LINALG_SUCCESS`: Successful execution
57-
- `LINALG_VALUE_ERROR`: Numerical errors (such as infinity, not-a-number, range bounds) are encountered.
58-
- `LINALG_ERROR`: Linear Algebra errors are encountered, such as: non-converging iterations, impossible operations, etc.
59-
- `LINALG_INTERNAL_ERROR`: Provided as a developer safeguard for internal errors that should never occur.
45+
The module provides the following state flags, mapped to the general `state_type` error flags:
46+
- `LINALG_SUCCESS`: Successful execution (equivalent to `STDLIB_SUCCESS`)
47+
- `LINALG_VALUE_ERROR`: Numerical errors (such as infinity, not-a-number, range bounds) are encountered (equivalent to `STDLIB_VALUE_ERROR`).
48+
- `LINALG_ERROR`: Linear Algebra errors are encountered, such as non-converging iterations, and impossible operations (equivalent to `STDLIB_LINALG_ERROR`).
49+
- `LINALG_INTERNAL_ERROR`: Provided as a developer safeguard for internal errors that should never occur (equivalent to `STDLIB_INTERNAL_ERROR`).
6050

6151
## Comparison operators provided
6252

63-
The module provides overloaded comparison operators for all comparisons of a `linalg_state_type` variable
64-
with an integer error flag: `<`, `<=`, `==`, `>=`, `>`, `/=`.
53+
The module provides overloaded comparison operators for all comparisons of a `linalg_state_type` variable with an integer error flag: `<`, `<=`, `==`, `>=`, `>`, `/=`.
54+

example/error/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ ADD_EXAMPLE(error_stop1)
99
set_tests_properties(error_stop1 PROPERTIES WILL_FAIL true)
1010
ADD_EXAMPLE(error_stop2)
1111
set_tests_properties(error_stop2 PROPERTIES WILL_FAIL true)
12+
ADD_EXAMPLE(error_state1)
13+
ADD_EXAMPLE(error_state2)
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
program example_error_state1
2+
use stdlib_error, only: state_type, STDLIB_VALUE_ERROR, STDLIB_SUCCESS, operator(/=)
3+
implicit none
4+
type(state_type) :: err
5+
6+
! To create a state variable, we enter its integer state flag, followed by a list of variables
7+
! that will be automatically assembled into a formatted error message. No need to provide string formats
8+
err = state_type(STDLIB_VALUE_ERROR,'just an example with scalar ',&
9+
'integer=',1,'real=',2.0,'complex=',(3.0,1.0),'and array ',[1,2,3],'inputs')
10+
11+
! Print flag
12+
print *, err%print()
13+
14+
! Check success
15+
print *, 'Check error: ',err%error()
16+
print *, 'Check flag : ',err /= STDLIB_SUCCESS
17+
18+
end program example_error_state1
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
program example_error_state2
2+
!! This example shows how to set a `type(state_type)` variable to process output conditions
3+
!! out of a simple division routine. The example is meant to highlight:
4+
!! 1) the different mechanisms that can be used to initialize the `state_type` variable providing
5+
!! strings, scalars, or arrays, on input to it;
6+
!! 2) `pure` setup of the error control
7+
use stdlib_error, only: state_type, STDLIB_VALUE_ERROR, STDLIB_SUCCESS
8+
implicit none
9+
type(state_type) :: err
10+
real :: a_div_b
11+
12+
! OK
13+
call very_simple_division(0.0,2.0,a_div_b,err)
14+
print *, err%print()
15+
16+
! Division by zero
17+
call very_simple_division(1.0,0.0,a_div_b,err)
18+
print *, err%print()
19+
20+
! Out of bounds
21+
call very_simple_division(huge(0.0),0.001,a_div_b,err)
22+
print *, err%print()
23+
24+
contains
25+
26+
!> Simple division returning an integer flag (LAPACK style)
27+
elemental subroutine very_simple_division(a,b,a_div_b,err)
28+
real, intent(in) :: a,b
29+
real, intent(out) :: a_div_b
30+
type(state_type), optional, intent(out) :: err
31+
32+
type(state_type) :: err0
33+
real, parameter :: MAXABS = huge(0.0)
34+
character(*), parameter :: this = 'simple division'
35+
36+
!> Check a
37+
if (b==0.0) then
38+
! Division by zero
39+
err0 = state_type(this,STDLIB_VALUE_ERROR,'Division by zero trying ',a,'/',b)
40+
elseif (.not.abs(b)<MAXABS) then
41+
! B is out of bounds
42+
err0 = state_type(this,STDLIB_VALUE_ERROR,'B is infinity in a/b: ',[a,b]) ! use an array
43+
elseif (.not.abs(a)<MAXABS) then
44+
! A is out of bounds
45+
err0 = state_type(this,STDLIB_VALUE_ERROR,'A is infinity in a/b: a=',a,' b=',b)
46+
else
47+
a_div_b = a/b
48+
if (.not.abs(a_div_b)<MAXABS) then
49+
! Result is out of bounds
50+
err0 = state_type(this,STDLIB_VALUE_ERROR,'A/B is infinity in a/b: a=',a,' b=',b)
51+
else
52+
err0%state = STDLIB_SUCCESS
53+
end if
54+
end if
55+
56+
! Return error flag, or hard stop on failure
57+
call err0%handle(err)
58+
59+
end subroutine very_simple_division
60+
61+
62+
end program example_error_state2

src/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ set(fppFiles
88
stdlib_bitsets_large.fypp
99
stdlib_codata_type.fypp
1010
stdlib_constants.fypp
11+
stdlib_error.fypp
1112
stdlib_hash_32bit.fypp
1213
stdlib_hash_32bit_fnv.fypp
1314
stdlib_hash_32bit_nm.fypp
@@ -102,7 +103,6 @@ set(SRC
102103
stdlib_ansi_to_string.f90
103104
stdlib_array.f90
104105
stdlib_codata.f90
105-
stdlib_error.f90
106106
stdlib_hashmap_wrappers.f90
107107
stdlib_hashmaps.f90
108108
stdlib_hashmap_chaining.f90

src/stdlib_error.f90

-84
This file was deleted.

0 commit comments

Comments
 (0)