├── .gitignore
├── LICENCE
├── README.md
├── benchmarks
├── benchmark-array.f90
└── benchmark-ints.f90
├── data
├── a_e.csv
├── a_f.csv
├── a_z.csv
├── ancestry_comp.csv
├── c_e.csv
├── c_f.csv
├── c_z.csv
├── hg38.bed
├── i.csv
├── i_z.csv
├── k.csv
├── k_z.csv
├── u_e.csv
├── u_f.csv
├── u_z.csv
├── x_e.csv
├── x_f.csv
└── x_z.csv
├── doc
├── css
│ ├── font-awesome.css
│ ├── font-awesome.min.css
│ ├── local.css
│ └── pygments.css
├── favicon.png
├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
├── index.html
├── interface
│ ├── aprint.html
│ ├── cast.html
│ ├── echo.html
│ ├── from_file.html
│ ├── join.html
│ ├── operator(+).html
│ ├── operator(-).html
│ ├── operator(==).html
│ ├── operator(ASTERISKASTERISK).html
│ ├── operator(SLASH=).html
│ ├── operator(SLASHSLASH).html
│ ├── random_gauss.html
│ ├── split.html
│ ├── str.html
│ ├── string.html
│ └── to_file.html
├── js
│ ├── MathJax-config
│ │ └── .gitignore
│ └── svg-pan-zoom.min.js
├── lists
│ ├── files.html
│ ├── modules.html
│ ├── procedures.html
│ └── types.html
├── module
│ ├── array_printing.html
│ ├── binary_io.html
│ ├── file_io.html
│ ├── gaussian_sampling.html
│ ├── internal_io.html
│ ├── io_fortran_lib.html
│ ├── join_split.html
│ ├── operators.html
│ ├── randoms.html
│ ├── string_methods.html
│ └── text_io.html
├── modules.json
├── page
│ ├── Examples
│ │ ├── benchmark.html
│ │ ├── binary.html
│ │ ├── csv.html
│ │ ├── exome.html
│ │ ├── fizzbuzz.html
│ │ ├── index.html
│ │ ├── logging.html
│ │ └── manipulations.html
│ ├── Ref
│ │ ├── String-methods.html
│ │ ├── String.html
│ │ ├── aprint.html
│ │ ├── cast.html
│ │ ├── constants.html
│ │ ├── echo.html
│ │ ├── from_file.html
│ │ ├── index.html
│ │ ├── join-split.html
│ │ ├── operators.html
│ │ ├── str.html
│ │ └── to_file.html
│ ├── UserInfo
│ │ ├── characters.html
│ │ ├── compilers.html
│ │ ├── error-codes.html
│ │ ├── file-ext.html
│ │ ├── index.html
│ │ ├── locale-fmts.html
│ │ ├── text-fmts.html
│ │ └── thread-safety.html
│ └── index.html
├── search.html
├── sourcefile
│ ├── array_printing_impl.f90.html
│ ├── binary_io_impl.f90.html
│ ├── file_io_impl.f90.html
│ ├── gaussian_sampling_impl.f90.html
│ ├── internal_io_impl.f90.html
│ ├── io_fortran_lib_mod.f90.html
│ ├── join_split_impl.f90.html
│ ├── operators_impl.f90.html
│ ├── randoms_mod.f90.html
│ ├── string_methods_impl.f90.html
│ └── text_io_impl.f90.html
├── src
│ ├── array_printing_impl.f90
│ ├── binary_io_impl.f90
│ ├── file_io_impl.f90
│ ├── gaussian_sampling_impl.f90
│ ├── internal_io_impl.f90
│ ├── io_fortran_lib_mod.f90
│ ├── join_split_impl.f90
│ ├── operators_impl.f90
│ ├── randoms_mod.f90
│ ├── string_methods_impl.f90
│ └── text_io_impl.f90
├── tipuesearch
│ ├── .DS_Store
│ ├── img
│ │ ├── .DS_Store
│ │ ├── loader.gif
│ │ └── search.png
│ ├── tipuesearch.css
│ ├── tipuesearch.js
│ ├── tipuesearch.min.js
│ ├── tipuesearch_content.js
│ └── tipuesearch_set.js
└── type
│ └── string.html
├── doc_API_design
├── Examples
│ ├── benchmark.md
│ ├── binary.md
│ ├── csv.md
│ ├── exome.md
│ ├── fizzbuzz.md
│ ├── index.md
│ ├── logging.md
│ └── manipulations.md
├── Ref
│ ├── String-methods.md
│ ├── String.md
│ ├── aprint.md
│ ├── cast.md
│ ├── constants.md
│ ├── echo.md
│ ├── from_file.md
│ ├── index.md
│ ├── join-split.md
│ ├── operators.md
│ ├── str.md
│ └── to_file.md
├── UserInfo
│ ├── characters.md
│ ├── compilers.md
│ ├── error-codes.md
│ ├── file-ext.md
│ ├── index.md
│ ├── locale-fmts.md
│ ├── text-fmts.md
│ └── thread-safety.md
└── index.md
├── ford-API-index.md
├── fpm.toml
├── src
├── io_fortran_lib
│ ├── array_printing_impl.f90
│ ├── binary_io_impl.f90
│ ├── file_io_impl.f90
│ ├── internal_io_impl.f90
│ ├── join_split_impl.f90
│ ├── operators_impl.f90
│ ├── string_methods_impl.f90
│ └── text_io_impl.f90
├── modules
│ ├── io_fortran_lib_mod.f90
│ └── randoms_mod.f90
└── randoms
│ └── gaussian_sampling_impl.f90
└── test
├── test.ps1
├── test.sh
├── tests.log
└── units
├── array-test-c.f90
├── array-test-i.f90
├── array-test-r.f90
├── file-test-c.f90
├── file-test-i.f90
├── file-test-r.f90
├── kinds_mod.f90
├── scalar-test-c.f90
├── scalar-test-i.f90
└── scalar-test-r.f90
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022-2024, Austin Bullock
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IO-Fortran-Library
2 |
3 | The [IO-Fortran-Library](https://acbbullock.github.io/IO-Fortran-Library/doc/index.html)
4 | is a Fortran module `io_fortran_lib` which provides high level routines
5 | for doing internal and external I/O. In particular, the module provides
6 | a handful of generic interfaces and a simple derived type for doing
7 | string-based and array-based I/O that are useful for recording program
8 | data, reading data into programs, writing formatted logs and output,
9 | and for doing advanced string manipulations. For instance, one may read
10 | and write data from/to `.csv` and `.dat` files, represent numbers as
11 | strings inside of a string expression, efficiently stream text data to
12 | a `.log` file, and dynamically manipulate strings with a `String` type
13 | (including casting between numeric and string data).
14 |
15 | To use `io_fortran_lib` with your [fpm](https://github.com/fortran-lang/fpm)
16 | project, add the following lines to your `fpm.toml` file and `use` the
17 | module in your program units to access the routines:
18 |
19 | ```toml
20 | [dependencies]
21 | IO-Fortran-Library = { git="https://github.com/acbbullock/IO-Fortran-Library", branch="main" }
22 | ```
23 |
24 | The module is fully self-contained, with no external dependencies, and
25 | is written to be portable and compliant to the Fortran 2018 standard
26 | such that no special extensions or compiler options should be required.
27 | The public interfaces accept all intrinsic numeric types (`integer`,
28 | `real`, and `complex`) and all standard kinds provided by the intrinsic
29 | `iso_fortran_env` module (`int8`, `int16`, `int32`, `int64`, `real32`,
30 | `real64`, and `real128`). All array-based routines additionally support
31 | up to rank 15.
32 |
33 | ## Documentation
34 |
35 | The API documentation for this project was generated by
36 | [FORD](https://github.com/Fortran-FOSS-Programmers/ford) (the Fortran
37 | documentation generator) and is available at
38 | [IO-Fortran-Library](https://acbbullock.github.io/IO-Fortran-Library/doc/index.html).
39 | To view the documentation locally, clone this repository and view
40 | `/doc/index.html` in your browser.
41 |
42 | For a list of available interfaces and how to call them, see the
43 | [reference guide](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/index.html).
44 | For further information, see the
45 | [important user information](https://acbbullock.github.io/IO-Fortran-Library/doc/page/UserInfo/index.html)
46 | and the
47 | [tutorials](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Examples/index.html)
48 | for complete example programs.
49 |
50 | ## Release Notes v1.3.1
51 |
52 | ### Improved
53 |
54 | * Fixed a "z" format string conversion bug.
55 | * Updated documentation.
56 | * Modified benchmark programs.
57 |
58 | ## Release Notes v1.2.1
59 |
60 | ### Added
61 |
62 | * Added implementations for
63 | [cast](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/cast.html).
64 |
65 | ### Improved
66 |
67 | * Improved performance for
68 | [count](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/String-methods.html#count),
69 | [read_file](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/String-methods.html#read_file),
70 | and [write_file](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/String-methods.html#write_file),
71 | as well as [split](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/join-split.html)
72 | for very large strings. The read/write performance is 2-4x faster than
73 | previous (compiler-dependent).
74 |
75 | ## Release Notes v1.2.0
76 |
77 | ### New features
78 |
79 | * The `String` type has been greatly expanded and can now serve as an
80 | interface for advanced string manipulations and text file I/O. See the
81 | references for
82 | [type-bound procedures](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/String-methods.html)
83 | and the [tutorials](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Examples/index.html)
84 | for more information.
85 | * New [constants](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/constants.html)
86 | have been added for public use to facilitate file I/O consistently on
87 | a variety of platforms.
88 | * New interface [String](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/String.html)
89 | for an elemental version of `str` with a return type of `String`.
90 | * New interface [cast](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/cast.html)
91 | for casting `character` and `String` data into numeric variables.
92 | * New interfaces [join and split](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/join-split.html)
93 | for joining and splitting strings.
94 | * New [operator interfaces](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/operators.html)
95 | for string manipulations involving both `character` and `String`
96 | types.
97 |
98 | ### Added
99 |
100 | * Slightly modified interfaces for
101 | [echo](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/echo.html)
102 | and [from_file](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/from_file.html)
103 | to accept an additional optional argument each.
104 | * Test programs have been added in `/test`, which are all passing in
105 | the following configurations with lowest and highest optimizations
106 | enabled:
107 | * GNU Fortran Compiler v11.3.0 on Linux
108 | * Intel Fortran Compiler v2023.0.0 on Linux
109 | * Intel Fortran Compiler Classic v2021.8.0 on Linux
110 | * GNU Fortran Compiler v11.2.0 on Windows 11
111 | * Intel Fortran Compiler v2023.0.0 on Windows 11
112 | * Intel Fortran Compiler Classic v2021.8.0 on Windows 11
113 |
114 | ### Improved
115 |
116 | * Removed vertical bars in
117 | [aprint](https://acbbullock.github.io/IO-Fortran-Library/doc/page/Ref/aprint.html)
118 | which were displayed incorrectly in terminals with display encoding
119 | different from UTF-8.
120 | * Text file I/O has been optimized for performance and memory usage,
121 | and expanded to support processing of large files.
122 |
123 | ## License
124 |
125 | All source code referenced is distributed under the
126 | [MIT license](https://github.com/acbbullock/IO-Fortran-Library/blob/main/LICENCE).
127 |
128 | ## Contact
129 |
130 | For bug fixes or feature requests, feel free to open an issue at the
131 | [project repository](https://github.com/acbbullock/IO-Fortran-Library/issues)
132 | or contact [acb.bullock@gmail.com](mailto:acb.bullock@gmail.com).
133 |
--------------------------------------------------------------------------------
/benchmarks/benchmark-array.f90:
--------------------------------------------------------------------------------
1 | program main
2 | use, intrinsic :: iso_fortran_env, only: int64, rk=>real32, dp=>real64, compiler_version, compiler_options
3 | use randoms, only: random_gauss
4 | use io_fortran_lib, only: String, cast, str, LF, operator(+)
5 | implicit none (type, external)
6 |
7 | type(String) :: csv
8 | type(String), allocatable :: cells(:,:)
9 |
10 | integer(int64) :: t1, t2
11 | real(dp) :: wall_time, rate
12 |
13 | integer, parameter :: n = 15000
14 | real(rk), allocatable :: x(:,:), y(:,:)
15 |
16 | allocate( x(n,n), cells(n,n) ); call random_gauss(x, 0e0_rk, 1.0_rk)
17 | write(*,"(a)") "Compiler version: " + compiler_version()
18 | write(*,"(a)") "Compiler options: " + compiler_options() + LF
19 |
20 | call system_clock(t1)
21 | call cast(x, into=cells, fmt="z")
22 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
23 |
24 | write(*,"(a)") "Wall time for cast: " + str(wall_time, fmt="f", decimals=3) + " s"
25 | write(*,"(a)") "Number of string conversions/second: " + str(nint(size(x)/wall_time)) + LF
26 |
27 | call system_clock(t1)
28 | call csv%write_file(cells, file="bigx.csv")
29 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
30 |
31 | write(*,"(a)") "Wall time for write_file: " + str(wall_time, fmt="f", decimals=3) + " s"
32 | write(*,"(a)") "Estimated file size: " + str(csv%len64()/1e9, fmt="f", decimals=6) + " GB" + LF
33 |
34 | call system_clock(t1)
35 | call csv%read_file("bigx.csv", cell_array=cells)
36 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
37 |
38 | write(*,"(a)") "Wall time for read_file: " + str(wall_time, fmt="f", decimals=3) + " s" + LF
39 |
40 | call csv%empty(); allocate( y(n,n) )
41 |
42 | call system_clock(t1)
43 | call cast(cells, into=y, fmt="z")
44 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
45 |
46 | write(*,"(a)") "Wall time for cast: " + str(wall_time, fmt="f", decimals=3) + " s"
47 | write(*,"(a)") "Number of string casts/second: " + str(nint(size(x)/wall_time))
48 | write(*,"(a,l)") "Data is exact match: ", all(x == y)
49 | end program main
50 |
--------------------------------------------------------------------------------
/benchmarks/benchmark-ints.f90:
--------------------------------------------------------------------------------
1 | program main
2 | use, intrinsic :: iso_fortran_env, only: i64=>int64, dp=>real64
3 | use io_fortran_lib, only: String, str, operator(+)
4 | implicit none (type, external)
5 |
6 | integer, parameter :: largest = huge(0), smallest = -largest - 1, nsteps = 128
7 | integer, parameter :: step_size = int( (int(largest,i64) - int(smallest,i64) )/int(nsteps,i64))
8 |
9 | type(String) :: csv
10 | type(String), allocatable, target :: cells(:,:)
11 | type(String), pointer, contiguous :: cells_p(:,:)
12 |
13 | integer :: lower, upper, i, j
14 |
15 | integer(i64) :: t1, t2, total_length
16 | real(dp) :: wall_time, rate
17 |
18 | write(*,"(a)") "Writing integers from " + str(smallest) + " to " + str(largest)
19 |
20 | allocate( cells(step_size, 2) )
21 | total_length = 0_i64
22 | call system_clock(t1)
23 |
24 | do j = 1, nsteps
25 | lower = smallest + (j-1)*step_size
26 | upper = lower + step_size - 1
27 |
28 | cells_p(lower:upper,1:2) => cells(:,:)
29 |
30 | do concurrent ( i = lower:upper )
31 | cells_p(i,1) = String(i, fmt="i")
32 | cells_p(i,2) = String(i, fmt="z")
33 | end do
34 |
35 | call csv%write_file(cells_p, file="int32.csv", append=.true.)
36 | total_length = total_length + csv%len64()
37 |
38 | write(*,"(a)") "File length: " + str(total_length/1e9, fmt="f", decimals=3) + " GB in cycle " + str(j)
39 | end do
40 |
41 | lower = upper + 1; upper = largest
42 | nullify(cells_p); deallocate(cells); allocate( cells(lower:upper,2) )
43 |
44 | do concurrent ( i = lower:upper )
45 | cells(i,1) = String(i, fmt="i")
46 | cells(i,2) = String(i, fmt="z")
47 | end do
48 |
49 | call csv%write_file(cells, file="int32.csv", append=.true.)
50 | total_length = total_length + csv%len64()
51 |
52 | write(*,"(a)") "File length: " + str(total_length/1e9, fmt="f", decimals=3) + " GB"
53 |
54 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
55 | write(*,"(a)") "Total time for write: " + str(wall_time/60, fmt="f", decimals=3) + " minutes"
56 | end program main
57 |
--------------------------------------------------------------------------------
/doc/css/local.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 70px;
3 | }
4 | table.nostretch {
5 | width=100%
6 | }
7 | .nostretch td {
8 | class='block'
9 | }
10 | .nostretch tr td{
11 | width:1%;
12 | white-space:nowrap;
13 | }
14 |
15 | html {
16 | scroll-padding-top: 70px;
17 | }
18 |
19 | ol.hierarchy {
20 | min-height: 40px;
21 | background-color: #f5f5f5;
22 | border: 1px solid #e3e3e3;
23 | border-radius: 3px;
24 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
25 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
26 | }
27 |
28 | .smallcaps {
29 | font-variant: small-caps;
30 | }
31 | .well .sidebar {
32 | padding: 8px 0
33 | }
34 | .sidebar a {
35 | padding: 0px,0px,0px,0px
36 | }
37 | .varlist>tbody>tr>td {
38 | padding-left: 3px;
39 | padding-right: 3px;
40 | }
41 | .varlist>tbody>tr>td:first-child, .varlist>thead>tr>td:first-child {
42 | padding-left: 8px;
43 | }
44 | .varlist>tbody>td>td:last-child, .varlist>thead>tr>td:last-child {
45 | padding-right: 8px;
46 | }
47 |
48 | .highlight pre {
49 | overflow-x: auto;
50 | overflow-wrap: normal;
51 | white-space: pre
52 | }
53 |
54 | /* .hl is for when line numbers are included, .highlight is for all
55 | other cases. */
56 | .hl pre {
57 | counter-reset: line-numbering;
58 | overflow-x: auto;
59 | overflow-wrap: normal;
60 | white-space: pre;
61 | padding: 0;
62 | padding-right: 9.5px;
63 | overflow-y: hidden;
64 | padding-bottom: 9.5px;
65 | }
66 |
67 | .hl pre a::before {
68 | content: counter(line-numbering);
69 | counter-increment: line-numbering;
70 | padding-right: 0.7em; /* space after numbers */
71 | margin-top: 4.5em;
72 | width: 60px;
73 | text-align: right;
74 | opacity: 0.7;
75 | display: inline-block;
76 | color: #aaa;
77 | background: #eee;
78 | margin-right: 10px;
79 | border-right: 1px solid #ccc;
80 | -webkit-touch-callout: none;
81 | -webkit-user-select: none;
82 | -khtml-user-select: none;
83 | -moz-user-select: none;
84 | -ms-user-select: none;
85 | user-select: none;
86 | }
87 |
88 | .hl pre a:first-of-type::before {
89 | padding-top: 9.5px;
90 | }
91 |
92 | .hl pre a:last-of-type::before {
93 | padding-bottom: 9.5px;
94 | }
95 |
96 | .hl pre a:only-of-type::before {
97 | padding: 9.5px;
98 | }
99 |
100 | .hl pre a {
101 | display: inline-block;
102 | height: 4.5em;
103 | margin: -4.5em 0 0;
104 | }
105 | .codesum h3 {
106 | margin-top: 2px;
107 | margin-bottom: 2px;
108 | }
109 |
110 | h1.inline, h2.inline, h3.inline {
111 | display: inline;
112 | }
113 |
114 | .depwarn {
115 | float: right;
116 | }
117 |
118 | .anchor {
119 | position: absolute;
120 | margin: -4.5em;
121 | visibility:hidden;
122 | }
123 |
124 | .alert {
125 | margin-left: 5px;
126 | margin-right: 5px;
127 | margin-top: 5px;
128 | }
129 |
130 | .alert-title {
131 | margin-top: 0;
132 | color: inherit;
133 | }
134 |
135 | div.toc {
136 | font-size: 14.73px;
137 | padding-left: 0px;
138 | padding-right: 0px;
139 | }
140 |
141 | div.toc a {
142 | padding-left: 20px;
143 | padding-right: 20px;
144 | margin-right: 15px;
145 | padding-top: 5px;
146 | padding-bottom: 5px;
147 | }
148 |
149 | div.toc li {
150 | font-size: 0.95em;
151 | padding-left: 15px;
152 | }
153 |
154 | div.toc li.title {
155 | font-size: 1em;
156 | }
157 |
158 | div.toc hr {
159 | margin-top: 12px;
160 | margin-bottom: 10px;
161 | }
162 |
163 | .in-well {
164 | padding: 0px 0px;
165 | margin-bottom: 0px;
166 | float:right;
167 | }
168 |
169 | table tr.submod>td {
170 | border-top: none;
171 | font-size: 13.5px;
172 | }
173 |
174 | .graph-help {
175 | font-size: 10px;
176 | }
177 |
178 | .depgraph {
179 | width: 100%;
180 | max-width: 1140px;
181 | }
182 |
183 | #sidebar a {
184 | white-space: nowrap;
185 | overflow: hidden;
186 | text-overflow: ellipsis;
187 | }
188 |
189 | .highlighttable {
190 | width: auto;
191 | table-layout: fixed;
192 | }
193 |
194 | ul.checklist {
195 | list-style-type: none;
196 | }
197 |
198 | ul.checklist input[type="checkbox"] {
199 | margin-left: -20.8px;
200 | margin-right: 4.55px;
201 | }
202 |
203 | .gitter-chat-embed {
204 | z-index: 100000;
205 | }
206 |
207 | table.graph {
208 | text-align: center;
209 | }
210 |
211 |
212 | .graph td.root {
213 | border:2px solid black;
214 | padding:10px;
215 | }
216 |
217 | .graph td.triangle-right:after {
218 | content: "";
219 | display: block;
220 | border-top: 7px solid transparent;
221 | border-bottom: 7px solid transparent;
222 | border-left: 7px solid black;
223 | }
224 |
225 | .graph td.triangle-left:after {
226 | content: "";
227 | display: block;
228 | border-top: 7px solid transparent;
229 | border-bottom: 7px solid transparent;
230 | border-right: 7px solid black;
231 | }
232 |
233 | .graph td.node {
234 | color: white;
235 | padding:10px;
236 | border-style: solid;
237 | border-width: 3px 0px 3px 0px;
238 | border-color: white;
239 | }
240 |
241 | .graph td.node a{
242 | color: white;
243 | }
244 |
245 | .graph td.dashedText,
246 | .graph td.solidText {
247 | padding: 0px 10px 0px 10px;
248 | min-width: 40px;
249 | color: black;
250 | border-color: black;
251 | }
252 |
253 | .graph td.dashedText {
254 | border-bottom-style: dashed;
255 | }
256 |
257 | .graph td.solidText {
258 | border-bottom-style: solid;
259 | }
260 |
261 | .graph td.dashedBottom,
262 | .graph td.dashedTop,
263 | .graph td.solidTop,
264 | .graph td.solidBottom {
265 | min-width: 40px;
266 | color: transparent;
267 | border-color: black;
268 | }
269 |
270 | .graph td.dashedBottom {
271 | border-bottom-style: dashed;
272 | }
273 |
274 | .graph td.dashedTop {
275 | border-top-style: dashed;
276 | }
277 |
278 | .graph td.solidBottom {
279 | border-bottom-style: solid;
280 | }
281 |
282 | .graph td.solidTop {
283 | border-top-style: solid;
284 | }
285 |
286 | /* Ensure tables in Pages don't collapse horizontally */
287 | td, th {
288 | padding-right: 10px;
289 | }
290 |
291 | .nav>li>a {
292 | padding-left: 10px;
293 | padding-right: 10px;
294 | }
295 |
296 | .nav > .nav {
297 | margin-left: 16px;
298 | }
299 |
--------------------------------------------------------------------------------
/doc/css/pygments.css:
--------------------------------------------------------------------------------
1 | pre { line-height: 125%; }
2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
6 | .codehilite .hll { background-color: #ffffcc }
7 | .codehilite { background: #f8f8f8; }
8 | .codehilite .c { color: #3D7B7B; font-style: italic } /* Comment */
9 | .codehilite .err { border: 1px solid #FF0000 } /* Error */
10 | .codehilite .k { color: #008000; font-weight: bold } /* Keyword */
11 | .codehilite .o { color: #666666 } /* Operator */
12 | .codehilite .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
13 | .codehilite .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
14 | .codehilite .cp { color: #9C6500 } /* Comment.Preproc */
15 | .codehilite .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
16 | .codehilite .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
17 | .codehilite .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
18 | .codehilite .gd { color: #A00000 } /* Generic.Deleted */
19 | .codehilite .ge { font-style: italic } /* Generic.Emph */
20 | .codehilite .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
21 | .codehilite .gr { color: #E40000 } /* Generic.Error */
22 | .codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
23 | .codehilite .gi { color: #008400 } /* Generic.Inserted */
24 | .codehilite .go { color: #717171 } /* Generic.Output */
25 | .codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
26 | .codehilite .gs { font-weight: bold } /* Generic.Strong */
27 | .codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
28 | .codehilite .gt { color: #0044DD } /* Generic.Traceback */
29 | .codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
30 | .codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
31 | .codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
32 | .codehilite .kp { color: #008000 } /* Keyword.Pseudo */
33 | .codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
34 | .codehilite .kt { color: #B00040 } /* Keyword.Type */
35 | .codehilite .m { color: #666666 } /* Literal.Number */
36 | .codehilite .s { color: #BA2121 } /* Literal.String */
37 | .codehilite .na { color: #687822 } /* Name.Attribute */
38 | .codehilite .nb { color: #008000 } /* Name.Builtin */
39 | .codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
40 | .codehilite .no { color: #880000 } /* Name.Constant */
41 | .codehilite .nd { color: #AA22FF } /* Name.Decorator */
42 | .codehilite .ni { color: #717171; font-weight: bold } /* Name.Entity */
43 | .codehilite .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
44 | .codehilite .nf { color: #0000FF } /* Name.Function */
45 | .codehilite .nl { color: #767600 } /* Name.Label */
46 | .codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
47 | .codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
48 | .codehilite .nv { color: #19177C } /* Name.Variable */
49 | .codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
50 | .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
51 | .codehilite .mb { color: #666666 } /* Literal.Number.Bin */
52 | .codehilite .mf { color: #666666 } /* Literal.Number.Float */
53 | .codehilite .mh { color: #666666 } /* Literal.Number.Hex */
54 | .codehilite .mi { color: #666666 } /* Literal.Number.Integer */
55 | .codehilite .mo { color: #666666 } /* Literal.Number.Oct */
56 | .codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
57 | .codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
58 | .codehilite .sc { color: #BA2121 } /* Literal.String.Char */
59 | .codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
60 | .codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
61 | .codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
62 | .codehilite .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
63 | .codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
64 | .codehilite .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
65 | .codehilite .sx { color: #008000 } /* Literal.String.Other */
66 | .codehilite .sr { color: #A45A77 } /* Literal.String.Regex */
67 | .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
68 | .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
69 | .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
70 | .codehilite .fm { color: #0000FF } /* Name.Function.Magic */
71 | .codehilite .vc { color: #19177C } /* Name.Variable.Class */
72 | .codehilite .vg { color: #19177C } /* Name.Variable.Global */
73 | .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
74 | .codehilite .vm { color: #19177C } /* Name.Variable.Magic */
75 | .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
76 |
--------------------------------------------------------------------------------
/doc/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/favicon.png
--------------------------------------------------------------------------------
/doc/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/doc/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/doc/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/doc/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/doc/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/doc/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/doc/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/doc/js/MathJax-config/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/js/MathJax-config/.gitignore
--------------------------------------------------------------------------------
/doc/lists/files.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | All Files – IO-Fortran-Library
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
64 |
65 |
66 |
67 |
68 |
Source Files
69 |
117 |
118 |
119 |
120 |
121 |
122 |
138 |
139 |
140 |
141 |
143 |
144 |
146 |
147 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/doc/lists/types.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | All Types – IO-Fortran-Library
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
64 |
65 |
66 |
67 |
68 |
Derived Types
69 |
70 |
71 | Type | Location | Extends | Description |
72 |
73 |
74 | String |
75 | io_fortran_lib |
76 | None |
77 | A growable string type for advanced character handling and text I/O. Read more… |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
101 |
102 |
103 |
104 |
106 |
107 |
109 |
110 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/doc/module/array_printing.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | array_printing – IO-Fortran-Library
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
63 |
64 |
65 |
66 |
array_printing
67 | Submodule
68 |
69 |
70 |
98 |
103 |
104 |
105 |
106 |
107 |
108 |
134 |
135 |
136 |
137 |
138 |
This submodule provides module procedure implementations for the public interface aprint
.
139 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
187 |
188 |
189 |
190 |
192 |
193 |
195 |
196 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/doc/module/binary_io.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | binary_io – IO-Fortran-Library
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
63 |
64 |
65 |
66 |
binary_io
67 | Submodule
68 |
69 |
70 |
98 |
103 |
104 |
105 |
106 |
107 |
108 |
134 |
135 |
136 |
137 |
138 |
This submodule provides module procedure implementations for the private interfaces to_binary
and
139 | from_binary
.
140 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
188 |
189 |
190 |
191 |
193 |
194 |
196 |
197 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/doc/module/file_io.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | file_io – IO-Fortran-Library
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
63 |
64 |
65 |
66 |
file_io
67 | Submodule
68 |
69 |
70 |
98 |
103 |
104 |
105 |
106 |
107 |
108 |
134 |
135 |
136 |
137 |
138 |
This submodule provides module procedure implementations for the public interfaces to_file
and
139 | from_file
.
140 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
188 |
189 |
190 |
191 |
193 |
194 |
196 |
197 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/doc/module/join_split.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | join_split – IO-Fortran-Library
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
63 |
64 |
65 |
66 |
join_split
67 | Submodule
68 |
69 |
70 |
98 |
103 |
104 |
105 |
106 |
107 |
108 |
134 |
135 |
136 |
137 |
138 |
This submodule provides module procedure implementations for the public interfaces join
and split
.
139 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
187 |
188 |
189 |
190 |
192 |
193 |
195 |
196 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/doc/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Search Results – IO-Fortran-Library
12 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
62 |
63 |
64 |
65 |
66 |
Search Results
67 |
68 |
69 |
70 |
82 |
87 |
88 |
89 |
105 |
106 |
107 |
108 |
110 |
111 |
113 |
114 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/doc/src/join_split_impl.f90:
--------------------------------------------------------------------------------
1 | submodule (io_fortran_lib) join_split
2 | !---------------------------------------------------------------------------------------------------------------------
3 | !! This submodule provides module procedure implementations for the **public interfaces** `join` and `split`.
4 | !---------------------------------------------------------------------------------------------------------------------
5 | implicit none (type, external)
6 |
7 | contains ! Procedure bodies for module subprograms <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
8 |
9 | module procedure join_char
10 | type(String) :: temp_String
11 | character(len=:), allocatable :: separator_
12 |
13 | if ( .not. present(separator) ) then
14 | separator_ = SPACE
15 | else
16 | separator_ = separator
17 | end if
18 |
19 | temp_String = join(String(tokens), separator=separator_)
20 |
21 | if ( temp_String%len() < 1 ) then
22 | new = EMPTY_STR
23 | else
24 | new = temp_String%s
25 | end if
26 | end procedure join_char
27 |
28 | module procedure join_string
29 | type(String) :: token_pair(2)
30 | character(len=:), allocatable :: separator_
31 | integer(i64) :: num_tokens
32 |
33 | num_tokens = size(tokens, kind=i64)
34 |
35 | if ( num_tokens == 1_i64 ) then
36 | if ( tokens(1_i64)%len64() < 1_i64 ) then
37 | new%s = EMPTY_STR; return
38 | else
39 | new%s = tokens(1_i64)%s; return
40 | end if
41 | end if
42 |
43 | if ( .not. present(separator) ) then
44 | separator_ = SPACE
45 | else
46 | separator_ = separator
47 | end if
48 |
49 | if ( num_tokens > 500_i64 ) then
50 | new = join(tokens=[ join(tokens(:num_tokens/2_i64), separator_), &
51 | join(tokens(1_i64+num_tokens/2_i64:), separator_) ], separator=separator_)
52 | else
53 | call new%join_base(tokens=tokens, separator=separator_)
54 | end if
55 | end procedure join_string
56 |
57 | module procedure split_char
58 | character(len=:), allocatable :: separator_
59 |
60 | if ( .not. present(separator) ) then
61 | separator_ = SPACE
62 | else
63 | separator_ = separator
64 | end if
65 |
66 | tokens = split(String(substring), separator=separator_)
67 | end procedure split_char
68 |
69 | module procedure split_string
70 | character(len=:), allocatable :: separator_
71 | integer(i64) :: substring_len, l, i
72 | integer :: sep_len, num_seps, sep, token, current
73 |
74 | substring_len=0_i64; l=0_i64; i=0_i64; sep_len=0; num_seps=0; sep=0; token=0; current=0
75 |
76 | substring_len = substring%len64()
77 |
78 | if ( substring_len < 1_i64 ) then
79 | allocate( tokens(1) ); tokens(1)%s = EMPTY_STR; return
80 | end if
81 |
82 | if ( .not. present(separator) ) then
83 | separator_ = SPACE
84 | else
85 | separator_ = separator
86 | end if
87 |
88 | sep_len = len(separator_)
89 |
90 | if ( sep_len == 0 ) then
91 | allocate( tokens(substring_len) )
92 | do i = 1_i64, substring_len
93 | tokens(i)%s = substring%s(i:i)
94 | end do
95 | return
96 | end if
97 |
98 | num_seps = substring%count(match=separator_)
99 |
100 | if ( num_seps == 0 ) then
101 | allocate( tokens(1) ); tokens(1)%s = substring%s; return
102 | end if
103 |
104 | allocate( tokens(num_seps + 1) )
105 |
106 | sep = iachar(separator_(1:1))
107 |
108 | i = 1_i64; l = 1_i64; token = 1; positional_transfers: do
109 | current = iachar(substring%s(i:i))
110 |
111 | if ( current /= sep ) then
112 | i = i + 1_i64; cycle
113 | end if
114 |
115 | if ( sep_len == 1 ) then
116 | tokens(token)%s = substring%s(l:i-1)
117 | if ( token == num_seps ) then
118 | tokens(num_seps+1)%s = substring%s(i+1:); return
119 | end if
120 | token = token + 1; i = i + 1_i64; l = i; cycle
121 | else
122 | if ( substring%s(i:i+sep_len-1) == separator_ ) then
123 | tokens(token)%s = substring%s(l:i-1)
124 | if ( token == num_seps ) then
125 | tokens(num_seps+1)%s = substring%s(i+sep_len:); return
126 | end if
127 | token = token + 1; i = i + sep_len; l = i; cycle
128 | else
129 | i = i + 1_i64; cycle
130 | end if
131 | end if
132 | end do positional_transfers
133 | end procedure split_string
134 | end submodule join_split
135 |
--------------------------------------------------------------------------------
/doc/src/operators_impl.f90:
--------------------------------------------------------------------------------
1 | submodule (io_fortran_lib) operators
2 | !---------------------------------------------------------------------------------------------------------------------
3 | !! This submodule provides module procedure implementations for the **public interfaces** `operator(//)`,
4 | !! `operator(+)`, `operator(-)`, `operator(**)`, `operator(==)`, and `operator(/=)`.
5 | !---------------------------------------------------------------------------------------------------------------------
6 | implicit none (type, external)
7 |
8 | contains ! Procedure bodies for module subprograms <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
9 |
10 | module procedure string_concatenation
11 | if ( Stringl%len() < 1 ) then
12 | if ( Stringr%len() < 1 ) then
13 | new%s = EMPTY_STR; return
14 | else
15 | new%s = Stringr%s; return
16 | end if
17 | end if
18 |
19 | if ( Stringr%len() < 1 ) then
20 | new%s = Stringl%s; return
21 | end if
22 |
23 | new%s = Stringl%s//Stringr%s
24 | end procedure string_concatenation
25 |
26 | module procedure string_char_concatenation
27 | if ( Stringl%len() < 1 ) then
28 | if ( len(charsr) < 1 ) then
29 | new%s = EMPTY_STR; return
30 | else
31 | new%s = charsr; return
32 | end if
33 | end if
34 |
35 | if ( len(charsr) < 1 ) then
36 | new%s = Stringl%s; return
37 | end if
38 |
39 | new%s = Stringl%s//charsr
40 | end procedure string_char_concatenation
41 |
42 | module procedure char_string_concatenation
43 | if ( len(charsl) < 1 ) then
44 | if ( Stringr%len() < 1 ) then
45 | new%s = EMPTY_STR; return
46 | else
47 | new%s = Stringr%s; return
48 | end if
49 | end if
50 |
51 | if ( Stringr%len() < 1 ) then
52 | new%s = charsl; return
53 | end if
54 |
55 | new%s = charsl//Stringr%s
56 | end procedure char_string_concatenation
57 |
58 | module procedure char_concat_plus
59 | new = charsl//charsr
60 | end procedure char_concat_plus
61 |
62 | module procedure string_concat_plus
63 | if ( Stringl%len() < 1 ) then
64 | if ( Stringr%len() < 1 ) then
65 | new%s = EMPTY_STR; return
66 | else
67 | new%s = Stringr%s; return
68 | end if
69 | end if
70 |
71 | if ( Stringr%len() < 1 ) then
72 | new%s = Stringl%s; return
73 | end if
74 |
75 | new%s = Stringl%s//Stringr%s
76 | end procedure string_concat_plus
77 |
78 | module procedure string_char_concat_plus
79 | if ( Stringl%len() < 1 ) then
80 | if ( len(charsr) < 1 ) then
81 | new%s = EMPTY_STR; return
82 | else
83 | new%s = charsr; return
84 | end if
85 | end if
86 |
87 | if ( len(charsr) < 1 ) then
88 | new%s = Stringl%s; return
89 | end if
90 |
91 | new%s = Stringl%s//charsr
92 | end procedure string_char_concat_plus
93 |
94 | module procedure char_string_concat_plus
95 | if ( len(charsl) < 1 ) then
96 | if ( Stringr%len() < 1 ) then
97 | new%s = EMPTY_STR; return
98 | else
99 | new%s = Stringr%s; return
100 | end if
101 | end if
102 |
103 | if ( Stringr%len() < 1 ) then
104 | new%s = charsl; return
105 | end if
106 |
107 | new%s = charsl//Stringr%s
108 | end procedure char_string_concat_plus
109 |
110 | module procedure char_excision
111 | type(String) :: Stringl
112 |
113 | Stringl%s = charsl
114 |
115 | if ( Stringl%len() < 1 ) then
116 | new%s = EMPTY_STR; return
117 | end if
118 |
119 | if ( len(charsr) < 1 ) then
120 | new%s = Stringl%s; return
121 | end if
122 |
123 | new = Stringl%replace(match=charsr, substring=EMPTY_STR)
124 | end procedure char_excision
125 |
126 | module procedure string_excision
127 | if ( Stringl%len() < 1 ) then
128 | new%s = EMPTY_STR; return
129 | end if
130 |
131 | if ( Stringr%len() < 1 ) then
132 | new%s = Stringl%s; return
133 | end if
134 |
135 | new = Stringl%replace(match=Stringr%s, substring=EMPTY_STR)
136 | end procedure string_excision
137 |
138 | module procedure string_char_excision
139 | if ( Stringl%len() < 1 ) then
140 | new%s = EMPTY_STR; return
141 | end if
142 |
143 | if ( len(charsr) < 1 ) then
144 | new%s = Stringl%s; return
145 | end if
146 |
147 | new = Stringl%replace(match=charsr, substring=EMPTY_STR)
148 | end procedure string_char_excision
149 |
150 | module procedure char_string_excision
151 | type(String) :: Stringl
152 |
153 | Stringl%s = charsl
154 |
155 | if ( Stringl%len() < 1 ) then
156 | new%s = EMPTY_STR; return
157 | end if
158 |
159 | if ( Stringr%len() < 1 ) then
160 | new%s = Stringl%s; return
161 | end if
162 |
163 | new = Stringl%replace(match=Stringr%s, substring=EMPTY_STR)
164 | end procedure char_string_excision
165 |
166 | module procedure repeat_chars
167 | new = repeat(char_base, ncopies=ncopies)
168 | end procedure repeat_chars
169 |
170 | module procedure repeat_String
171 | if ( String_base%len() < 1 ) then
172 | new%s = EMPTY_STR; return
173 | end if
174 |
175 | new%s = repeat(String_base%s, ncopies=ncopies)
176 | end procedure repeat_String
177 |
178 | module procedure string_equivalence
179 | integer :: Stringl_len, Stringr_len
180 |
181 | Stringl_len = Stringl%len()
182 | Stringr_len = Stringr%len()
183 |
184 | if ( Stringl_len /= Stringr_len ) then
185 | equal = .false.; return
186 | end if
187 |
188 | if ( Stringl_len < 1 ) then
189 | equal = .true.; return
190 | end if
191 |
192 | equal = ( Stringl%s == Stringr%s )
193 | end procedure string_equivalence
194 |
195 | module procedure string_char_equivalence
196 | integer :: Stringl_len, charsr_len
197 |
198 | Stringl_len = Stringl%len()
199 | charsr_len = len(charsr)
200 |
201 | if ( Stringl_len /= charsr_len ) then
202 | equal = .false.; return
203 | end if
204 |
205 | if ( Stringl_len < 1 ) then
206 | equal = .true.; return
207 | end if
208 |
209 | equal = ( Stringl%s == charsr )
210 | end procedure string_char_equivalence
211 |
212 | module procedure char_string_equivalence
213 | integer :: charsl_len, Stringr_len
214 |
215 | charsl_len = len(charsl)
216 | Stringr_len = Stringr%len()
217 |
218 | if ( charsl_len /= Stringr_len ) then
219 | equal = .false.; return
220 | end if
221 |
222 | if ( charsl_len < 1 ) then
223 | equal = .true.; return
224 | end if
225 |
226 | equal = ( charsl == Stringr%s )
227 | end procedure char_string_equivalence
228 |
229 | module procedure string_nonequivalence
230 | integer :: Stringl_len, Stringr_len
231 |
232 | Stringl_len = Stringl%len()
233 | Stringr_len = Stringr%len()
234 |
235 | if ( Stringl_len /= Stringr_len ) then
236 | unequal = .true.; return
237 | end if
238 |
239 | if ( Stringl_len < 1 ) then
240 | unequal = .false.; return
241 | end if
242 |
243 | unequal = ( Stringl%s /= Stringr%s )
244 | end procedure string_nonequivalence
245 |
246 | module procedure string_char_nonequivalence
247 | integer :: Stringl_len, charsr_len
248 |
249 | Stringl_len = Stringl%len()
250 | charsr_len = len(charsr)
251 |
252 | if ( Stringl_len /= charsr_len ) then
253 | unequal = .true.; return
254 | end if
255 |
256 | if ( Stringl_len < 1 ) then
257 | unequal = .false.; return
258 | end if
259 |
260 | unequal = ( Stringl%s /= charsr )
261 | end procedure string_char_nonequivalence
262 |
263 | module procedure char_string_nonequivalence
264 | integer :: charsl_len, Stringr_len
265 |
266 | charsl_len = len(charsl)
267 | Stringr_len = Stringr%len()
268 |
269 | if ( charsl_len /= Stringr_len ) then
270 | unequal = .true.; return
271 | end if
272 |
273 | if ( charsl_len < 1 ) then
274 | unequal = .false.; return
275 | end if
276 |
277 | unequal = ( charsl /= Stringr%s )
278 | end procedure char_string_nonequivalence
279 | end submodule operators
280 |
--------------------------------------------------------------------------------
/doc/src/randoms_mod.f90:
--------------------------------------------------------------------------------
1 | module randoms
2 | !---------------------------------------------------------------------------------------------------------------------
3 | !! This module provides Gaussian sampling utility routines for use in unit testing.
4 | !---------------------------------------------------------------------------------------------------------------------
5 | use, intrinsic :: iso_fortran_env, only: r128=>real128, r64=>real64, r32=>real32
6 | implicit none (type, external)
7 | private
8 |
9 | ! Public API list ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 | public :: random_gauss
11 |
12 | ! Definitions and Interfaces ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13 |
14 | interface gauss ! Submodule gaussian_sampling
15 | !-------------------------------------------------------------------------------------------------------------------
16 | !! Samples random numbers from the standard Normal (Gaussian) Distribution with the given mean and sigma.
17 | !! Uses the Acceptance-complement ratio from W. Hoermann and G. Derflinger.
18 | !! This is one of the fastest existing methods for generating normal random variables.
19 | !!
20 | !! REFERENCE: - W. Hoermann and G. Derflinger (1990):
21 | !! The ACR Method for generating normal random variables,
22 | !! OR Spektrum 12 (1990), 181-185.
23 | !!
24 | !! Implementation taken from
25 | !! UNURAN (c) 2000 W. Hoermann & J. Leydold, Institut f. Statistik, WU Wien
26 | !---------------------------------------------------------------------------------------------------------------
27 | impure real(r128) module function gauss_r128(mu, sig) result(gauss_res)
28 | real(r128), intent(in) :: mu, sig
29 | end function gauss_r128
30 | impure real(r64) module function gauss_r64(mu, sig) result(gauss_res)
31 | real(r64), intent(in) :: mu, sig
32 | end function gauss_r64
33 | impure real(r32) module function gauss_r32(mu, sig) result(gauss_res)
34 | real(r32), intent(in) :: mu, sig
35 | end function gauss_r32
36 | end interface
37 |
38 | interface random_gauss ! Submodule gaussian_sampling
39 | !-------------------------------------------------------------------------------------------------------------------
40 | !! Applies `gauss` to whole arrays and scalars.
41 | !-------------------------------------------------------------------------------------------------------------------
42 | impure elemental module subroutine random_gauss_r128(x, mu, sig)
43 | real(r128), intent(inout) :: x
44 | real(r128), intent(in) :: mu, sig
45 | end subroutine random_gauss_r128
46 | impure elemental module subroutine random_gauss_r64(x, mu, sig)
47 | real(r64), intent(inout) :: x
48 | real(r64), intent(in) :: mu, sig
49 | end subroutine random_gauss_r64
50 | impure elemental module subroutine random_gauss_r32(x, mu, sig)
51 | real(r32), intent(inout) :: x
52 | real(r32), intent(in) :: mu, sig
53 | end subroutine random_gauss_r32
54 | end interface
55 | end module randoms
56 |
--------------------------------------------------------------------------------
/doc/tipuesearch/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/tipuesearch/.DS_Store
--------------------------------------------------------------------------------
/doc/tipuesearch/img/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/tipuesearch/img/.DS_Store
--------------------------------------------------------------------------------
/doc/tipuesearch/img/loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/tipuesearch/img/loader.gif
--------------------------------------------------------------------------------
/doc/tipuesearch/img/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acbbullock/IO-Fortran-Library/15bc3557c36adc174abbd9a077e0686dc11cc4af/doc/tipuesearch/img/search.png
--------------------------------------------------------------------------------
/doc/tipuesearch/tipuesearch.css:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | Tipue Search 4.0
4 | Copyright (c) 2014 Tipue
5 | Tipue Search is released under the MIT License
6 | http://www.tipue.com/search
7 | */
8 |
9 |
10 | /*
11 | #tipue_search_input
12 | {
13 | font: 13px/1.6 'open sans', sans-serif;
14 | color: #333;
15 | padding: 12px 12px 12px 40px;
16 | width: 170px;
17 | border: 1px solid #e2e2e2;
18 | border-radius: 0;
19 | -moz-appearance: none;
20 | -webkit-appearance: none;
21 | box-shadow: none;
22 | outline: 0;
23 | margin: 0;
24 | background: #fff url('img/search.png') no-repeat 15px 15px;
25 | }
26 | */
27 |
28 | #tipue_search_content
29 | {
30 | max-width: 650px;
31 | padding-top: 15px;
32 | margin: 0;
33 | }
34 | #tipue_search_loading
35 | {
36 | padding-top: 60px;
37 | background: #fff url('img/loader.gif') no-repeat left;
38 | }
39 |
40 | #tipue_search_warning_head
41 | {
42 | font: 300 15px/1.6 'Open Sans', sans-serif;
43 | color: #555;
44 | }
45 | #tipue_search_warning
46 | {
47 | font: 300 13px/1.6 'Open Sans', sans-serif;
48 | color: #333;
49 | margin: 7px 0;
50 | }
51 | #tipue_search_warning a
52 | {
53 | color: #36c;
54 | font-weight: 300;
55 | text-decoration: none;
56 | }
57 | #tipue_search_warning a:hover
58 | {
59 | color: #333;
60 | }
61 | #tipue_search_results_count
62 | {
63 | font: 300 13px/1.6 'Open Sans', sans-serif;
64 | color: #333;
65 | }
66 | .tipue_search_content_title
67 | {
68 | font: 300 25px/1.7 'Open Sans', sans-serif;
69 | text-rendering: optimizelegibility;
70 | margin-top: 23px;
71 | }
72 | .tipue_search_content_title a
73 | {
74 | color: #333;
75 | text-decoration: none;
76 | }
77 | .tipue_search_content_title a:hover
78 | {
79 | color: #555;
80 | }
81 | .tipue_search_content_url
82 | {
83 | font: 300 13px/1.7 'Open Sans', sans-serif;
84 | word-break: break-all;
85 | word-break: break-word;
86 | -webkit-hyphens: auto;
87 | -moz-hyphens: auto;
88 | hyphens: auto;
89 | }
90 | .tipue_search_content_url a
91 | {
92 | color: #06c;
93 | text-decoration: none;
94 | }
95 | .tipue_search_content_url a:hover
96 | {
97 | color: #333;
98 | }
99 | .tipue_search_content_text
100 | {
101 | font: 300 15px/1.6 'Open Sans', sans-serif;
102 | color: #555;
103 | word-break: break-all;
104 | word-break: break-word;
105 | -webkit-hyphens: auto;
106 | -moz-hyphens: auto;
107 | hyphens: auto;
108 | margin-top: 3px;
109 | }
110 | .h01
111 | {
112 | color: #333;
113 | font-weight: 400;
114 | }
115 |
116 | #tipue_search_foot
117 | {
118 | margin: 51px 0 21px 0;
119 | }
120 | #tipue_search_foot_boxes
121 | {
122 | padding: 0;
123 | margin: 0;
124 | font: 12px/1 'Open Sans', sans-serif;
125 | }
126 | #tipue_search_foot_boxes li
127 | {
128 | list-style: none;
129 | margin: 0;
130 | padding: 0;
131 | display: inline;
132 | }
133 | #tipue_search_foot_boxes li a
134 | {
135 | padding: 9px 15px 10px 15px;
136 | background-color: #f1f1f1;
137 | border: 1px solid #dcdcdc;
138 | border-radius: 1px;
139 | color: #333;
140 | margin-right: 7px;
141 | text-decoration: none;
142 | text-align: center;
143 | }
144 | #tipue_search_foot_boxes li.current
145 | {
146 | padding: 9px 15px 10px 15px;
147 | background: #fff;
148 | border: 1px solid #dcdcdc;
149 | border-radius: 1px;
150 | color: #333;
151 | margin-right: 7px;
152 | text-align: center;
153 | }
154 | #tipue_search_foot_boxes li a:hover
155 | {
156 | border: 1px solid #ccc;
157 | background-color: #f3f3f3;
158 | }
159 |
--------------------------------------------------------------------------------
/doc/tipuesearch/tipuesearch.min.js:
--------------------------------------------------------------------------------
1 | (function($){$.fn.tipuesearch=function(options){var set=$.extend({"show":7,"newWindow":false,"showURL":true,"minimumLength":3,"descriptiveWords":25,"highlightTerms":true,"highlightEveryTerm":false,"mode":"static","liveDescription":"*","liveContent":"*","contentLocation":"tipuesearch/tipuesearch_content.json"},options);return this.each(function(){var tipuesearch_in={pages:[]};$.ajaxSetup({async:false});if(set.mode=="live")for(var i=0;i");var t_2=html.toLowerCase().indexOf("",t_1+7);if(t_1!=-1&&t_2!=-1)var tit=html.slice(t_1+7,t_2);else var tit="No title";tipuesearch_in.pages.push({"title":tit,"text":desc,"tags":cont,"loc":tipuesearch_pages[i]})});if(set.mode=="json")$.getJSON(set.contentLocation,function(json){tipuesearch_in=$.extend({},json)});
3 | if(set.mode=="static")tipuesearch_in=$.extend({},tipuesearch);var tipue_search_w="";if(set.newWindow)tipue_search_w=' target="_blank"';function getURLP(name){return decodeURIComponent(((new RegExp("[?|&]"+name+"="+"([^&;]+?)(&|#|;|$)")).exec(location.search)||[,""])[1].replace(/\+/g,"%20"))||null}if(getURLP("q")){$("#tipue_search_input").val(getURLP("q"));getTipueSearch(0,true)}$(this).keyup(function(event){if(event.keyCode=="13")getTipueSearch(0,true)});function getTipueSearch(start,replace){$("#tipue_search_content").hide();
4 | var out="";var results="";var show_replace=false;var show_stop=false;var standard=true;var c=0;found=new Array;var d=$("#tipue_search_input").val().toLowerCase();d=$.trim(d);if(d.match('^"')&&d.match('"$')||d.match("^'")&&d.match("'$"))standard=false;if(standard){var d_w=d.split(" ");d="";for(var i=0;i=set.minimumLength){if(standard){if(replace){var d_r=d;for(var i=0;i$1')}if(tipuesearch_in.pages[i].tags.search(pat)!=
7 | -1)score-=1E5-i;if(d_w[f].match("^-")){pat=new RegExp(d_w[f].substring(1),"i");if(tipuesearch_in.pages[i].title.search(pat)!=-1||tipuesearch_in.pages[i].text.search(pat)!=-1||tipuesearch_in.pages[i].tags.search(pat)!=-1)score=1E9}}if(score<1E9)found[c++]=score+"^"+tipuesearch_in.pages[i].title+"^"+s_t+"^"+tipuesearch_in.pages[i].loc}}else for(var i=0;i$1')}if(tipuesearch_in.pages[i].tags.search(pat)!=-1)score-=1E5-i;if(score<1E9)found[c++]=score+"^"+tipuesearch_in.pages[i].title+"^"+s_t+"^"+tipuesearch_in.pages[i].loc}if(c!=0){if(show_replace==1){out+='Showing results for '+
9 | d+"
";out+='"}if(c==1)out+='1 result
';else{c_c=c.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",");out+=''+c_c+" results
"}found.sort();var l_o=0;for(var i=0;i=start&&l_o"+fo[1]+"";if(set.showURL)out+='";var t=fo[2];var t_d="";var t_w=t.split(" ");if(t_w.length'+t_d+""}l_o++}if(c>set.show){var pages=Math.ceil(c/set.show);var page=start/set.show;
11 | out+='"}}else out+='Nothing found
'}else if(show_stop)out+='Nothing found
Common words are largely ignored
';
13 | else{out+='Search too short
';if(set.minimumLength==1)out+='Should be one character or more
';else out+='Should be '+set.minimumLength+" characters or more
"}$("#tipue_search_content").html(out);$("#tipue_search_content").slideDown(200);$("#tipue_search_replaced").click(function(){getTipueSearch(0,false)});$(".tipue_search_foot_box").click(function(){var id_v=$(this).attr("id");var id_a=
14 | id_v.split("_");getTipueSearch(parseInt(id_a[0]),id_a[1])})}})}})(jQuery);
15 |
--------------------------------------------------------------------------------
/doc/tipuesearch/tipuesearch_set.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | Tipue Search 4.0
4 | Copyright (c) 2014 Tipue
5 | Tipue Search is released under the MIT License
6 | http://www.tipue.com/search
7 | */
8 |
9 |
10 | var tipuesearch_stop_words = ["and", "be", "by", "do", "for", "he", "how", "if", "is", "it", "my", "not", "of", "or", "the", "to", "up", "what", "when", "use", "who", "she", "my", "his", "her"];
11 |
12 | var tipuesearch_replace = {"words": [
13 | {"word": "tipua", "replace_with": "tipue"},
14 | {"word": "javscript", "replace_with": "javascript"}
15 | ]};
16 |
17 | var tipuesearch_stem = {"words": [
18 | {"word": "e-mail", "stem": "email"},
19 | {"word": "javascript", "stem": "script"},
20 | {"word": "procedure", "stem": "subroutine"},
21 | {"word": "procedure", "stem": "function"}
22 | ]};
23 |
24 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/benchmark.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Benchmarking
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## Big data I/O
7 |
8 | The IO-Fortran-Library is capable of reading and writing very large
9 | text files with efficiency, even those whose data size exceeds the
10 | 2,147,483,647 byte upper limit of the 32-bit signed integer. A program
11 | is provided in `/test/benchmark.f90` for benchmarking the major
12 | internal and external text I/O routines of the IO-Fortran-Library:
13 |
14 | ```fortran
15 | program main
16 | use, intrinsic :: iso_fortran_env, only: int64, rk=>real32, dp=>real64, compiler_version, compiler_options
17 | use randoms, only: random_gauss
18 | use io_fortran_lib, only: String, cast, str, LF, operator(+)
19 | implicit none (type, external)
20 |
21 | type(String) :: csv
22 | type(String), allocatable :: cells(:,:)
23 |
24 | integer(int64) :: t1, t2
25 | real(dp) :: wall_time, rate
26 |
27 | integer, parameter :: n = 15000
28 | real(rk), allocatable :: x(:,:), y(:,:)
29 |
30 | allocate( x(n,n), cells(n,n) ); call random_gauss(x, 0e0_rk, 1.0_rk)
31 | write(*,"(a)") "Compiler version: " + compiler_version()
32 | write(*,"(a)") "Compiler options: " + compiler_options() + LF
33 |
34 | call system_clock(t1)
35 | call cast(x, into=cells, fmt="z")
36 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
37 |
38 | write(*,"(a)") "Wall time for cast: " + str(wall_time, fmt="f", decimals=3) + " s"
39 | write(*,"(a)") "Number of string conversions/second: " + str(nint(size(x)/wall_time)) + LF
40 |
41 | call system_clock(t1)
42 | call csv%write_file(cells, file="bigx.csv")
43 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
44 |
45 | write(*,"(a)") "Wall time for write_file: " + str(wall_time, fmt="f", decimals=3) + " s"
46 | write(*,"(a)") "Estimated file size: " + str(csv%len64()/1e9, fmt="f", decimals=6) + " GB" + LF
47 |
48 | call system_clock(t1)
49 | call csv%read_file("bigx.csv", cell_array=cells)
50 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
51 |
52 | write(*,"(a)") "Wall time for read_file: " + str(wall_time, fmt="f", decimals=3) + " s" + LF
53 |
54 | call csv%empty(); allocate( y(n,n) )
55 |
56 | call system_clock(t1)
57 | call cast(cells, into=y, fmt="z")
58 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
59 |
60 | write(*,"(a)") "Wall time for cast: " + str(wall_time, fmt="f", decimals=3) + " s"
61 | write(*,"(a)") "Number of string casts/second: " + str(nint(size(x)/wall_time))
62 | write(*,"(a,l)") "Data is exact match: ", all(x == y)
63 | end program main
64 | ```
65 |
66 | Here, we populate an `n`-by-`n` single-precision array `x` with samples
67 | from the standard Gaussian distribution and convert each to a
68 | hexadecimal string to populate a cell array, write the cell array to a
69 | text file `"bigx.csv"`, read the file back into the program to
70 | re-populate the cell array, then finally cast the cell data into `y`
71 | and compare with `x` to observe an exact match. For `n = 15000`, the
72 | resulting csv file size is `2.47 GB`.
73 |
74 | @note With the Intel Fortran compiler `ifx`, we must specify
75 | `-heap-arrays 0` to avoid a segmentation fault when reading a file of
76 | this size, as noted in [compiler-dependent
77 | behavior](../UserInfo/compilers.html).
78 |
79 | For a more extreme example, consider the following program to write
80 | every 32-bit integer as a hexadecimal string to a text file `int32.txt`:
81 |
82 | ```fortran
83 | program main
84 | use, intrinsic :: iso_fortran_env, only: i64=>int64, dp=>real64
85 | use io_fortran_lib, only: String, str, operator(+)
86 | implicit none (type, external)
87 |
88 | integer, parameter :: largest = huge(0), smallest = -largest - 1, nsteps = 128
89 | integer, parameter :: step_size = int( (int(largest,i64) - int(smallest,i64) )/int(nsteps,i64))
90 |
91 | type(String) :: csv
92 | type(String), allocatable, target :: cells(:,:)
93 | type(String), pointer, contiguous :: cells_p(:,:)
94 |
95 | integer :: lower, upper, i, j
96 |
97 | integer(i64) :: t1, t2, total_length
98 | real(dp) :: wall_time, rate
99 |
100 | write(*,"(a)") "Writing integers from " + str(smallest) + " to " + str(largest)
101 |
102 | allocate( cells(step_size, 2) )
103 | total_length = 0_i64
104 | call system_clock(t1)
105 |
106 | do j = 1, nsteps
107 | lower = smallest + (j-1)*step_size
108 | upper = lower + step_size - 1
109 |
110 | cells_p(lower:upper,1:2) => cells(:,:)
111 |
112 | do concurrent ( i = lower:upper )
113 | cells_p(i,1) = String(i, fmt="i")
114 | cells_p(i,2) = String(i, fmt="z")
115 | end do
116 |
117 | call csv%write_file(cells_p, file="int32.csv", append=.true.)
118 | total_length = total_length + csv%len64()
119 |
120 | write(*,"(a)") "File length: " + str(total_length/1e9, fmt="f", decimals=3) + " GB in cycle " + str(j)
121 | end do
122 |
123 | lower = upper + 1; upper = largest
124 | nullify(cells_p); deallocate(cells); allocate( cells(lower:upper,2) )
125 |
126 | do concurrent ( i = lower:upper )
127 | cells(i,1) = String(i, fmt="i")
128 | cells(i,2) = String(i, fmt="z")
129 | end do
130 |
131 | call csv%write_file(cells, file="int32.csv", append=.true.)
132 | total_length = total_length + csv%len64()
133 |
134 | write(*,"(a)") "File length: " + str(total_length/1e9, fmt="f", decimals=3) + " GB"
135 |
136 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,dp)/rate
137 | write(*,"(a)") "Total time for write: " + str(wall_time/60, fmt="f", decimals=3) + " minutes"
138 | end program main
139 | ```
140 |
141 | The resulting file size is `94.128 GB`.
142 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/binary.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Handling dat files
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## Binary file I/O
7 |
8 | The routines [to_file](../Ref/to_file.html) and
9 | [from_file](../Ref/from_file.html) are used for writing numeric arrays
10 | to binary files with the extension `.dat` or `.bin`.
11 |
12 | The following program demonstrates the use of `to_file` and `from_file`
13 | for writing `real` data of rank `5` to a `.dat` file, reading the file
14 | back into the program, and testing for exact equality to ensure that
15 | there has been no loss in precision:
16 |
17 | ```fortran
18 | program main
19 | use io_fortran_lib, only: to_file, from_file
20 | implicit none (type, external)
21 |
22 | real :: x(20,20,20,20,20)
23 | real, allocatable :: x_dat(:,:,:,:,:)
24 |
25 | call random_number(x)
26 |
27 | call to_file(x, file="x.dat")
28 |
29 | call from_file("x.dat", into=x_dat, data_shape=shape(x))
30 |
31 | write(*,*) "x == x_dat : ", all(x == x_dat)
32 | end program main
33 | ```
34 |
35 | @warning Reading into arrays of a different `kind` than the array that
36 | was written will invalidate the data. Always make sure the `kind` is
37 | matching for binary I/O.
38 |
39 | TIP: The shape of an array may be written to a csv file so that the
40 | value of `data_shape` can be read into the program before reading in
41 | the main array with the corresponding value. The following program
42 | demonstrates the above tip:
43 |
44 | ```fortran
45 | program main
46 | use io_fortran_lib, only: to_file, from_file
47 | implicit none (type, external)
48 |
49 | real :: x(20,20,20,20,20)
50 | real, allocatable :: x_dat(:,:,:,:,:)
51 | integer, allocatable :: x_shape(:)
52 |
53 | call random_number(x)
54 |
55 | call to_file(x, file="x.dat")
56 | call to_file(shape(x), file="x_shape.csv")
57 |
58 | call from_file("x_shape.csv", into=x_shape)
59 | call from_file("x.dat", into=x_dat, data_shape=x_shape)
60 |
61 | write(*,*) "x == x_dat : ", all(x == x_dat)
62 | end program main
63 | ```
64 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/csv.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Handling csv files
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## Basic csv file I/O
7 |
8 | The routines [to_file](../Ref/to_file.html) and
9 | [from_file](../Ref/from_file.html) are the preferred method for
10 | handling I/O for numeric data of uniform type and format. Typical use
11 | cases involve writing whole arrays to file and reading files of uniform
12 | type and format directly into an array of numeric type.
13 |
14 | The following program demonstrates the use of `to_file` and `from_file`
15 | for writing an array of `real` data to a csv file in each possible
16 | [text format](../UserInfo/text-fmts.html), reading each file back into
17 | the program, and testing for exact equality to ensure that there has
18 | been no loss in precision:
19 |
20 | ```fortran
21 | program main
22 | use io_fortran_lib, only: to_file, from_file
23 | implicit none (type, external)
24 |
25 | real :: x(1000,20)
26 | real, allocatable :: x_e(:,:), x_f(:,:), x_z(:,:)
27 |
28 | call random_number(x)
29 |
30 | call to_file(x, file="x_e.csv", header=["x"], fmt="e")
31 | call to_file(x, file="x_f.csv", header=["x"], fmt="f")
32 | call to_file(x, file="x_z.csv", header=["x"], fmt="z")
33 |
34 | call from_file("x_e.csv", into=x_e, header=.true., fmt="e")
35 | call from_file("x_f.csv", into=x_f, header=.true., fmt="f")
36 | call from_file("x_z.csv", into=x_z, header=.true., fmt="z")
37 |
38 | write(*,*) "x == x_e : ", all(x == x_e)
39 | write(*,*) "x == x_f : ", all(x == x_f)
40 | write(*,*) "x == x_z : ", all(x == x_z)
41 | end program main
42 | ```
43 |
44 | Here we use the simple header `header=["x"]`, which produces a header
45 | of the form:
46 |
47 | ```text
48 | x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20
49 | ```
50 |
51 | Note that the default value for `header` when reading is `.false.`. If
52 | a header is actually present, the output array will have an extra row
53 | with default initialized values.
54 |
55 | @warning Default text format for writing and reading is `"e"` for data
56 | of type `real` or `complex`, and `"i"` for data of type `integer`.
57 | Attempting to read data with a format that does not correspond to the
58 | format in the file may result in an I/O syntax error.
59 |
60 | @note Reading into arrays of a different `kind` than the array that was
61 | written is a type conversion, and will fail the equality test.
62 |
63 | ## Advanced csv file I/O
64 |
65 | The routines [write_file](../Ref/String-methods.html#write_file) and
66 | [read_file](../Ref/String-methods.html#read_file) are the preferred
67 | method for handling I/O for general text files. Typical use cases
68 | involve writing cell arrays of type `String` to delimited files, and
69 | reading delimited files into a cell array. For reading and writing
70 | non-delimited text files, one would use `read_file` without the
71 | `cell_array` argument and [echo](../Ref/echo.html).
72 |
73 | The same program as above can be recast in an object-oriented fashion
74 | that is generalizable for processing data of mixed type:
75 |
76 | ```fortran
77 | program main
78 | use io_fortran_lib, only: String, str, cast
79 | implicit none (type, external)
80 |
81 | type(String) :: csv
82 | type(String), allocatable :: cells(:,:)
83 |
84 | real :: x(1000,20)
85 | real, allocatable :: x_e(:,:), x_f(:,:), x_z(:,:)
86 | integer :: i
87 |
88 | call random_number(x); allocate( cells(1001,20) ); cells(1,:) = [(String("x"//str(i)), i = 1, 20)]
89 |
90 | call cast(x, into=cells(2:,:), fmt="e"); call csv%write_file(cells, file="x_e.csv")
91 | call cast(x, into=cells(2:,:), fmt="f"); call csv%write_file(cells, file="x_f.csv")
92 | call cast(x, into=cells(2:,:), fmt="z"); call csv%write_file(cells, file="x_z.csv")
93 |
94 | allocate( x_e, x_f, x_z, mold=x )
95 | call csv%read_file("x_e.csv", cell_array=cells); call cells(2:,:)%cast(into=x_e, fmt="e")
96 | call csv%read_file("x_f.csv", cell_array=cells); call cells(2:,:)%cast(into=x_f, fmt="f")
97 | call csv%read_file("x_z.csv", cell_array=cells); call cells(2:,:)%cast(into=x_z, fmt="z")
98 |
99 | write(*,*) "x == x_e : ", all(x == x_e)
100 | write(*,*) "x == x_f : ", all(x == x_f)
101 | write(*,*) "x == x_z : ", all(x == x_z)
102 | end program main
103 | ```
104 |
105 | Here, we construct the same header as before with the implicit loop
106 |
107 | ```fortran
108 | cells(1,:) = [(String("x"//str(i)), i = 1, 20)]
109 | ```
110 |
111 | and then construct the remainder of the cell array `cells` with an
112 | elemental cast `call cast(x, into=cells(2:,:), fmt)` before writing the
113 | array to a csv file. We then read the files back into `csv` and output
114 | the cells into `cells` (which is reallocated internally). Note that
115 | when casting the cell data into numeric arrays, we must pre-allocate
116 | the output arrays due to the restrictions on `intent(out)` arguments
117 | of `elemental` procedures.
118 |
119 | @note One may optionally specify the arguments of `row_separator` and
120 | `column_separator` when writing and reading text files with
121 | [write_file](../Ref/String-methods.html#write_file) and
122 | [read_file](../Ref/String-methods.html#read_file). The default
123 | `row_separator` is `LF`, and the default `column_separator` is `","`.
124 |
125 | @warning When reading files with `CRLF` line endings, be sure to
126 | specify `row_separator=CR//LF` or pre-process the file to `LF`. Trying
127 | to cast data with a hidden `CR` character may result in an I/O syntax
128 | error.
129 |
130 | For a slightly more advanced example, consider the following program
131 | to read in and cast the data of mixed type contained in the example
132 | data `/data/ancestry_comp.csv`:
133 |
134 | ```fortran
135 | program main
136 | use, intrinsic :: iso_fortran_env, only: int8, int64
137 | use io_fortran_lib, only: String, cast, CR, LF, operator(+), operator(-)
138 | implicit none (type, external)
139 |
140 | type(String) :: csv
141 | type(String), allocatable :: cells(:,:)
142 |
143 | integer(int8), allocatable :: copy(:), chromosome(:)
144 | integer(int64), allocatable :: start_point(:), end_point(:)
145 | integer :: nrows
146 |
147 | call csv%read_file("./data/ancestry_comp.csv", cell_array=cells, row_separator=CR+LF)
148 | write(*,*) csv
149 |
150 | nrows = size(cells, dim=1) - 1
151 |
152 | allocate( copy(nrows), chromosome(nrows), start_point(nrows), end_point(nrows) )
153 |
154 | call cells(2:,2)%cast(into=copy)
155 | call cast(cells(2:,3)%replace("X","0") - "chr", into=chromosome)
156 | call cells(2:,4)%cast(into=start_point)
157 | call cells(2:,5)%cast(into=end_point)
158 | end program main
159 | ```
160 |
161 | Here, `file` is a relative path, and we use the extended operator `+`
162 | for [concatenation](../Ref/operators.html#concatenation) in the
163 | `character` expression `CR+LF`. We then allocate data arrays and cast
164 | each column into respective arrays. Note that we must use
165 | [cast](../Ref/cast.html) as a standalone subroutine to accept the
166 | `String`-valued expression
167 |
168 | ```fortran
169 | cells(2:,3)%replace("X","0") - "chr"
170 | ```
171 |
172 | which first calls [replace](../Ref/String-methods.html#replace) to
173 | return an elemental copy of the given cells in which all instances of
174 | `X` have been replaced with `0`, and then calls the
175 | [excision operator](../Ref/operators.html#excision) `-` to remove all
176 | instances of `"chr"` elementally. The output of the `String` expression
177 | contains numeric characters only, which are then casted to the array
178 | `chromosome`.
179 |
180 | @note In general, for other
181 | [text file extensions](../UserInfo/file-ext.html), one would specify
182 | the `column_separator` associated with the given file. For instance,
183 | one would specify `column_separator=TAB` for the file formats `.bed`,
184 | `.gff`, and `.gtf`.
185 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/exome.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: NGS Human Core Exome Panel
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## Handling genomic data
7 |
8 | Fortran can serve as a valuable tool for heavy numerical calculations
9 | in Next Generation Sequencing (NGS) analysis, which may often involve
10 | reading and writing many large `.bed` files in succession. The
11 | IO-Fortran-Library is optimized for both performance and memory
12 | consumption when reading and writing large text files, streamlining
13 | performance for Fortran bioinformatics applications.
14 |
15 | To demonstrate the speed of file I/O, the following program reads the
16 | Twist Human Core Exome target `.bed` file for hg38 obtained from
17 | [Twist Bioscience](https://www.twistbioscience.com/resources/data-files/ngs-human-core-exome-panel-bed-file)
18 | into a cell array and then writes the cell array to a new file in a
19 | round-trip, comparing the two files for an exact match and providing
20 | the total time elapsed:
21 |
22 | ```fortran
23 | program main
24 | use, intrinsic :: iso_fortran_env, only: int64, real64, compiler_version
25 | use io_fortran_lib, only: String, str, TAB, operator(+), operator(==)
26 | implicit none (type, external)
27 |
28 | type(String) :: hg38, hg38_new
29 | type(String), allocatable :: cells(:,:)
30 |
31 | integer(int64) :: t1, t2
32 | real(real64) :: wall_time, rate
33 |
34 | call system_clock(t1)
35 |
36 | call hg38%read_file("./data/hg38.bed", cell_array=cells, column_separator=TAB)
37 | call hg38_new%write_file(cells, "./data/hg38_new.bed", column_separator=TAB)
38 |
39 | call system_clock(t2, count_rate=rate); wall_time = real(t2-t1,real64)/rate
40 |
41 | write(*,"(a,l)") "New file and original are exact match: ", hg38_new == hg38
42 | write(*,"(a)") "Wall time: " + str(wall_time, fmt="f", decimals=3) + " s " + &
43 | 'using compiler: "' + compiler_version() + '".'
44 | end program main
45 | ```
46 |
47 | The file `hg38.bed` is provided locally in `/data` and contains
48 | `192262` lines of `TAB`-delimited data.
49 |
50 | @note With the Intel Fortran compiler `ifx`, we may need to specify
51 | `-heap-arrays 0` to avoid a segmentation fault when reading a file of
52 | this size, as noted in [compiler-dependent
53 | behavior](../UserInfo/compilers.html).
54 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/fizzbuzz.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: FizzBuzz
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## Division game
7 |
8 | The following program demonstrates the use of
9 | [aprint](../Ref/aprint.html) for printing an array of
10 | [Strings](../../type/string.html) containing values of the first 100
11 | [FizzBuzz](https://en.wikipedia.org/wiki/Fizz_buzz) numbers:
12 |
13 | ```fortran
14 | program main
15 | use io_fortran_lib, only: String, aprint
16 | implicit none (type, external)
17 |
18 | integer, allocatable :: nums(:)
19 | integer :: i
20 |
21 | nums = [(i, i = 1, 100)]
22 |
23 | call aprint( FizzBuzz(nums) )
24 |
25 | contains
26 | pure elemental type(String) function FizzBuzz(number) result(res)
27 | integer, intent(in) :: number
28 |
29 | if ( mod(number,5) /= 0 ) then
30 | if ( mod(number,3) /= 0 ) then
31 | res = String(number)
32 | else
33 | res = String("fizz")
34 | end if
35 | else
36 | if ( mod(number,3) /= 0 ) then
37 | res = String("buzz")
38 | else
39 | res = String("fizzbuzz")
40 | end if
41 | end if
42 | end function FizzBuzz
43 | end program main
44 | ```
45 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Tutorials
3 | author: Austin C Bullock
4 | ordered_subpage: csv.md
5 | ordered_subpage: binary.md
6 | ordered_subpage: logging.md
7 | ordered_subpage: manipulations.md
8 | ordered_subpage: fizzbuzz.md
9 | ordered_subpage: exome.md
10 | ordered_subpage: benchmark.md
11 | ---
12 |
13 | The following subsections provide example programs for common use cases
14 | of the public [interfaces](../../lists/procedures.html):
15 |
16 | * [Handling csv files](csv.html)
17 | * [Handling dat files](binary.html)
18 | * [Handling log files](logging.html)
19 | * [String manipulation](manipulations.html)
20 | * [FizzBuzz](fizzbuzz.html)
21 | * [NGS Human Core Exome Panel](exome.html)
22 | * [Benchmarking](benchmark.html)
23 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/logging.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Handling log files
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## Log file I/O
7 |
8 | The routine [echo](../Ref/echo.html) is the preferred method for
9 | writing general text data to a log file.
10 |
11 | The following program demonstrates a simple use of `echo` for writing
12 | messages to a log file:
13 |
14 | ```fortran
15 | program main
16 | use io_fortran_lib, only: echo, str, LF
17 | implicit none (type, external)
18 |
19 | character(len=:), allocatable :: logfile, logmsg
20 | character(len=10) :: date, time
21 | integer :: errstat
22 |
23 | call date_and_time(date=date, time=time)
24 | logfile = "logfile_main_"//trim(adjustl(date))//"_"//time//".log"
25 |
26 | logmsg = "PROGRAM MAIN - BEGINNING EXECUTION"
27 | call echo(logmsg//LF//repeat("-", ncopies=len(logmsg)), file=logfile)
28 |
29 | ! ...
30 |
31 | logmsg = "All is good so far..."
32 | call echo(logmsg, logfile)
33 |
34 | read(*,*) errstat
35 |
36 | if ( errstat /= 0 ) then
37 | logmsg = "Process has non-zero exit status: "//str(errstat)//LF//"Stopping..."
38 | call echo(logmsg, logfile)
39 | error stop logmsg
40 | end if
41 |
42 | logmsg = "All processes have executed successfully."
43 | call echo(logmsg, logfile)
44 | end program main
45 | ```
46 |
47 | Depending on style, one may wish to accumulate log messages into a
48 | `String` and then call the type-bound procedure
49 | [echo](../Ref/String-methods.html#echo) conditionally:
50 |
51 | ```fortran
52 | program main
53 | use io_fortran_lib, only: String, str, LF, operator(+), operator(**)
54 | implicit none (type, external)
55 |
56 | type(String) :: logmsg
57 | character(len=:), allocatable :: logfile
58 | character(len=10) :: date, time
59 | integer :: errstat
60 |
61 | call date_and_time(date=date, time=time)
62 | logfile = "logfile_main_" + trim(adjustl(date)) + "_" + time + ".log"
63 |
64 | logmsg = String("PROGRAM MAIN - BEGINNING EXECUTION")
65 | call logmsg%push(LF + "-"**logmsg%len() + LF)
66 |
67 | ! ...
68 |
69 | call logmsg%push("All is good so far..." + LF)
70 |
71 | read(*,*) errstat
72 |
73 | if ( errstat /= 0 ) then
74 | call logmsg%push("Process has non-zero exit status: " + str(errstat) + LF + "Stopping...")
75 | call logmsg%echo(logfile)
76 | error stop logmsg%as_str()
77 | end if
78 |
79 | call logmsg%push("All processes have executed successfully.")
80 | call logmsg%echo(logfile)
81 | end program main
82 | ```
83 |
84 | Here, the `error stop` will dump the entire contents of `logmsg` to
85 | stdout. We also take advantage of the
86 | [operators](../Ref/operators.html) `+` and `**` for concatenation and
87 | repetition.
88 |
--------------------------------------------------------------------------------
/doc_API_design/Examples/manipulations.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: String manipulations
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## String Queries
7 |
8 | Sometimes it is useful or necessary to write execution conditions based
9 | on compiler vendors or version, such as when a certain compiler version
10 | has a known bug or when a piece of code is required for a specific
11 | compiler. The following program shows how one may use the
12 | [count](../Ref/String-methods.html#count) procedure to determine a
13 | compiler and version at runtime:
14 |
15 | ```fortran
16 | program main
17 | use, intrinsic :: iso_fortran_env, only: compiler_version
18 | use io_fortran_lib, only: String
19 | implicit none (type, external)
20 |
21 | type(String) :: compiler
22 | logical :: GCC, GCC_SUPPORTED, INTEL, INTEL_SUPPORTED
23 |
24 | compiler = String(compiler_version())
25 |
26 | GCC = compiler%count(match="GCC") > 0
27 | GCC_SUPPORTED = GCC .and. ( compiler%count(match="13.2.1") > 0 )
28 |
29 | INTEL = compiler%count(match="Intel") > 0
30 | INTEL_SUPPORTED = INTEL .and. ( compiler%count(match="2024.0.2") > 0 )
31 |
32 | write(*,*) compiler
33 |
34 | if ( GCC ) then
35 | if ( GCC_SUPPORTED ) then
36 | write(*,*) "This GNU Fortran Compiler version is known to be supported."
37 | else
38 | write(*,*) "This GNU Fortran Compiler version may not be supported."
39 | end if
40 | else if ( INTEL ) then
41 | if ( INTEL_SUPPORTED ) then
42 | write(*,*) "This Intel Fortran Compiler version is known to be supported."
43 | else
44 | write(*,*) "This Intel Fortran Compiler version may not be supported."
45 | end if
46 | end if
47 | end program main
48 | ```
49 |
50 | ## Dynamic string manipulation
51 |
52 | Using [operator](../Ref/operators.html) techniques and
53 | [string methods](../Ref/String-methods.html), we may easily perform
54 | complex string manipulations during run time.
55 |
56 | The following program demonstrates the use of the
57 | [String](../../type/string.html) type and some
58 | [type-bound procedures](../Ref/String-methods.html) for manipulating a
59 | timestamp:
60 |
61 | ```fortran
62 | program main
63 | use io_fortran_lib, only: String, join, split, LF, operator(+), operator(-)
64 | implicit none (type, external)
65 |
66 | type(String) :: time_stamp, new_time_stamp
67 | type(String), allocatable :: tokens(:)
68 |
69 | character(len=10) :: date, time
70 |
71 | call date_and_time(date=date, time=time)
72 |
73 | time_stamp = String("Date : " + date + LF + "Time : " + time)
74 |
75 | write(*,"(a)") "ORIGINAL TIME STAMP:" + LF + time_stamp%as_str() + LF
76 |
77 | tokens = split(time_stamp, separator=LF) - "Date : " - "Time : " + [" : Date", " : Time"]
78 | new_time_stamp = join(tokens, separator=" | ")
79 |
80 | write(*,"(a)") "RECONSTRUCTED TIME STAMP:" + LF + new_time_stamp%as_str()
81 | end program main
82 | ```
83 |
84 | This program produces the following sample output:
85 |
86 | ```text
87 | ORIGINAL TIME STAMP:
88 | Date : 20240316
89 | Time : 163641.569
90 |
91 | RECONSTRUCTED TIME STAMP:
92 | 20240316 : Date | 163641.569 : Time
93 | ```
94 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/String.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: String
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface String](../../interface/string.html)
7 |
8 | *Description*: Function for returning a
9 | [String](../../type/string.html) representation of numbers.
10 |
11 | To return the empty `String`, use no arguments:
12 |
13 | ```fortran
14 | result = String()
15 | ```
16 |
17 | For `x` a scalar or array of any rank and of type `character`:
18 |
19 | ```fortran
20 | result = String(x)
21 | ```
22 |
23 | This is for `character` to `String` conversion.
24 |
25 | For `x` a scalar or array of any rank and of type `integer`:
26 |
27 | ```fortran
28 | result = String(x [, fmt])
29 | ```
30 |
31 | * `fmt` is `optional`, may be one of `INT_FMTS`
32 |
33 | For `x` a scalar or array of any rank and of type `real`:
34 |
35 | ```fortran
36 | result = String(x [, locale, fmt, decimals])
37 | ```
38 |
39 | * `locale` is `optional`, may be one of `LOCALES`
40 | * `fmt` is `optional`, may be one of `REAL_FMTS`
41 | * `decimals` is `optional` and of type `integer`
42 |
43 | For `x` a scalar or array of any rank and of type `complex`:
44 |
45 | ```fortran
46 | result = String(x [, locale, fmt, decimals, im])
47 | ```
48 |
49 | * `locale` is `optional`, may be one of `LOCALES`
50 | * `fmt` is `optional`, may be one of `REAL_FMTS`
51 | * `decimals` is `optional` and of type `integer`
52 | * `im` is `optional` and of type `character(len=*)`
53 |
54 | @note Unlike [str](str.html), which takes scalar arguments only and
55 | returns a `character`, `String` operates elementally and returns a
56 | [String](../../type/string.html).
57 |
58 | ### Optional Arguments
59 |
60 | Integer formats (default is `"i"`):
61 |
62 | ```fortran
63 | INT_FMTS = [ "i", "z" ]
64 | ```
65 |
66 | Real formats (default is `"e"`):
67 |
68 | ```fortran
69 | REAL_FMTS = [ "e", "f", "z" ]
70 | ```
71 |
72 | Locales (default is `"US"`):
73 |
74 | ```fortran
75 | LOCALES = [ "US", "EU" ]
76 | ```
77 |
78 | Decimals: `decimals` specifies the number of digits on the rhs of the
79 | radix point, with a default determined internally based on the
80 | [text format](../UserInfo/text-fmts.html) and precision.
81 |
82 | Imaginary unit: `im` specifies the form of a complex number. By
83 | default, `complex` numbers will be written as ordered pairs, e.g.
84 | `(2.45,3.45)`. If `im` is specified, then the number will be written as
85 | a sum with the specified imaginary unit, e.g. `2.45+3.45j` for `im="j"`
86 | or `2.45+3.45*1i` for `im="*1i"`.
87 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/aprint.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: aprint
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface aprint](../../interface/aprint.html)
7 |
8 | *Description*: Subroutine for printing arrays and array sections to
9 | stdout.
10 |
11 | For `x` an array of rank `1` or `2` and of type `character` or `String`:
12 |
13 | ```fortran
14 | call aprint(x)
15 | ```
16 |
17 | For `x` an array of rank `1` or `2` and of type `integer`:
18 |
19 | ```fortran
20 | call aprint(x [, fmt])
21 | ```
22 |
23 | * `fmt` is `optional`, may be one of `INT_FMTS`
24 |
25 | For `x` an array of rank `1` or `2` and of type `real`:
26 |
27 | ```fortran
28 | call aprint(x [, fmt, decimals])
29 | ```
30 |
31 | * `fmt` is `optional`, may be one of `REAL_FMTS`
32 | * `decimals` is `optional` and of type `integer`
33 |
34 | For `x` an array of rank `1` or `2` and of type `complex`:
35 |
36 | ```fortran
37 | call aprint(x [, fmt, decimals, im])
38 | ```
39 |
40 | * `fmt` is `optional`, may be one of `REAL_FMTS`
41 | * `decimals` is `optional` and of type `integer`
42 | * `im` is `optional` and of type `character(len=*)`
43 |
44 | ### Optional Arguments
45 |
46 | Integer formats (default is `"i"`):
47 |
48 | ```fortran
49 | INT_FMTS = [ "i", "z" ]
50 | ```
51 |
52 | Real formats (default is `"f"`):
53 |
54 | ```fortran
55 | REAL_FMTS = [ "e", "f", "z" ]
56 | ```
57 |
58 | Decimals (default is `2`): `decimals` specifies the number of digits on
59 | the rhs of the radix point.
60 |
61 | Imaginary unit (default is `"j"`): `im` specifies the form of a complex
62 | number.
63 |
64 | @note The optional arguments for `aprint` are different than elsewhere,
65 | and better suited for easy viewing of array sections.
66 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/cast.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: cast
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface cast](../../interface/cast.html)
7 |
8 | *Description*: Subroutine for casting between numeric and string data.
9 |
10 | ### Casting numbers to string variables
11 |
12 | For casting `x` of type `integer` into a variable `into` of type
13 | `character` (scalar only) or `String` (any rank):
14 |
15 | ```fortran
16 | call cast(x, into [, fmt])
17 | ```
18 |
19 | * `fmt` is `optional`, may be one of `INT_FMTS`
20 |
21 | For casting `x` of type `real` into a variable `into` of type
22 | `character` (scalar only) or `String` (any rank):
23 |
24 | ```fortran
25 | call cast(x, into [, locale, fmt, decimals])
26 | ```
27 |
28 | * `locale` is `optional`, may be one of `LOCALES`
29 | * `fmt` is `optional`, may be one of `REAL_FMTS`
30 | * `decimals` is `optional` and of type `integer`
31 |
32 | For casting `x` of type `complex` into a variable `into` of type
33 | `character` (scalar only) or `String` (any rank):
34 |
35 | ```fortran
36 | call cast(x, into [, locale, fmt, decimals, im])
37 | ```
38 |
39 | * `locale` is `optional`, may be one of `LOCALES`
40 | * `fmt` is `optional`, may be one of `REAL_FMTS`
41 | * `decimals` is `optional` and of type `integer`
42 | * `im` is `optional` and of type `character(len=*)`
43 |
44 | @note While [str](str.html) and [String](String.html) return values
45 | which may be used flexibly inside of string expressions, `cast` may be
46 | used as above to write directly to variables. When converting large
47 | amounts of data to strings, `cast` may be up to 2x faster than the
48 | functional alternatives since the total number of string allocations is
49 | reduced by at least half, all else being equal.
50 |
51 | ### Casting strings to numeric variables
52 |
53 | For casting `substring` of type `character` (scalar only) or `String`
54 | (any rank) into a variable `into` of type `integer`:
55 |
56 | ```fortran
57 | call cast(substring, into [, fmt])
58 | ```
59 |
60 | ```fortran
61 | call substring%cast(into [, fmt])
62 | ```
63 |
64 | * `fmt` is `optional`, may be one of `INT_FMTS`
65 |
66 | For casting `substring` of type `character` (scalar only) or `String`
67 | (any rank) into a variable `into` of type `real`:
68 |
69 | ```fortran
70 | call cast(substring, into [, locale, fmt])
71 | ```
72 |
73 | ```fortran
74 | call substring%cast(into [, locale, fmt])
75 | ```
76 |
77 | * `locale` is `optional`, may be one of `LOCALES`
78 | * `fmt` is `optional`, may be one of `REAL_FMTS`
79 |
80 | For casting `substring` of type `character` (scalar only) or `String`
81 | (any rank) into a variable `into` of type `complex`:
82 |
83 | ```fortran
84 | call cast(substring, into [, locale, fmt, im])
85 | ```
86 |
87 | ```fortran
88 | call substring%cast(into [, locale, fmt, im])
89 | ```
90 |
91 | * `locale` is `optional`, may be one of `LOCALES`
92 | * `fmt` is `optional`, may be one of `REAL_FMTS`
93 | * `im` is `optional` and of type `character(len=*)`
94 |
95 | @warning The arguments `x` and `substring` must always be of the same
96 | rank and shape as `into`, which must be pre-allocated prior to calling
97 | `cast` due to the restrictions on `intent(out)` arguments of
98 | `elemental` procedures.
99 |
100 | @note The type-bound procedure access of the form
101 | `call substring%cast()` is valid when `substring` is a `String`
102 | variable. To cast a `String`-valued expression, the expression must be
103 | passed to `cast` by the form `call cast()`.
104 |
105 | ### Optional Arguments
106 |
107 | Integer formats (default is `"i"`):
108 |
109 | ```fortran
110 | INT_FMTS = [ "i", "z" ]
111 | ```
112 |
113 | Real formats (default is `"e"`):
114 |
115 | ```fortran
116 | REAL_FMTS = [ "e", "f", "z" ]
117 | ```
118 |
119 | Locales (default is `"US"`):
120 |
121 | ```fortran
122 | LOCALES = [ "US", "EU" ]
123 | ```
124 |
125 | Decimals: `decimals` specifies the number of digits on the rhs of the
126 | radix point, with a default determined internally based on the
127 | [text format](../UserInfo/text-fmts.html) and precision.
128 |
129 | Imaginary unit: `im` specifies the form of a complex number. If not
130 | present, `complex` numbers will be assumed to be written as ordered
131 | pairs, e.g. `(2.45,3.45)`.
132 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/constants.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CONSTANTS
3 | author: Austin C Bullock
4 | ---
5 |
6 | The [[io_fortran_lib]] module provides access to a handful of
7 | `parameter` [constants](../../module/io_fortran_lib.html#variable-nl)
8 | for general use:
9 |
10 | * `NL`: The newline character (system agnostic).
11 | * `SPACE`: The space character.
12 | * `CR`: The carriage return character.
13 | * `FF`: The form feed character.
14 | * `VT`: The vertical tab character.
15 | * `LF`: The line feed character.
16 | * `TAB`: The horizontal tab character.
17 | * `HT`: The horizontal tab character (alternate name).
18 | * `BELL`: The bell/alert character.
19 | * `NUL`: The null character.
20 | * `CNUL`: The C null character re-exported from `iso_c_binding`.
21 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/echo.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: echo
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface echo](../../interface/echo.html)
7 |
8 | *Description*: Subroutine for writing a scalar `character` or `String`
9 | to an external text file.
10 |
11 | For `substring` a scalar of type `character` or `String`:
12 |
13 | ```fortran
14 | call echo(substring, file [, append, terminator, stat, errmsg])
15 | ```
16 |
17 | * `file` is of type `character(len=*)`
18 | * `append` is `optional` and of type `logical`
19 | * `terminator` is `optional` and of type `character(len=*)`
20 | * `stat` is `optional` and of type `integer`
21 | * `errmsg` is `optional` and of type `character(len=*)`
22 |
23 | For `substring` a scalar variable of type `String`:
24 |
25 | ```fortran
26 | call substring%echo(file [, append, terminator, stat, errmsg])
27 | ```
28 |
29 | * `file` is of type `character(len=*)`
30 | * `append` is `optional` and of type `logical`
31 | * `terminator` is `optional` and of type `character(len=*)`
32 | * `stat` is `optional` and of type `integer`
33 | * `errmsg` is `optional` and of type `character(len=*)`
34 |
35 | @note The type-bound procedure access of the form
36 | `call substring%echo()` is valid when `substring` is a `String`
37 | variable. To echo a `String`-valued expression, the expression must be
38 | passed to `echo` by the form `call echo()`.
39 |
40 | @note `file` may be a relative path, but absolute paths are not
41 | guaranteed to work on every platform.
42 |
43 | ### Optional Arguments
44 |
45 | Append (default is `.true.`): `append` specifies whether to append or
46 | to replace the file `file`. Either way, the file will be created if it
47 | does not exist.
48 |
49 | Terminator (default is `LF`): `terminator` is a string terminator
50 | inserted at the end of the input string.
51 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/from_file.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: from_file
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface from_file](../../interface/from_file.html)
7 |
8 | *Description*: Subroutine for reading an external file of uniform
9 | numeric data type and format into an array.
10 |
11 | For reading textual data into an array `into` of rank `1` or `2` and of
12 | type `integer`:
13 |
14 | ```fortran
15 | call from_file(file, into [, header, delim, fmt, stat, errmsg])
16 | ```
17 |
18 | * `file` is of type `character(len=*)`
19 | * `header` is `optional` and of type `logical`
20 | * `delim` is `optional` and of type `character(len=*)`
21 | * `fmt` is `optional`, may be one of `INT_FMTS`
22 | * `stat` is `optional` and of type `integer`
23 | * `errmsg` is `optional` and of type `character(len=*)`
24 |
25 | For reading textual data into an array `into` of rank `1` or `2` and of
26 | type `real`:
27 |
28 | ```fortran
29 | call from_file(file, into [, header, locale, delim, fmt, stat, errmsg])
30 | ```
31 |
32 | * `file` is of type `character(len=*)`
33 | * `header` is `optional` and of type `logical`
34 | * `locale` is `optional`, may be one of `LOCALES`
35 | * `delim` is `optional` and of type `character(len=*)`
36 | * `fmt` is `optional`, may be one of `REAL_FMTS`
37 | * `stat` is `optional` and of type `integer`
38 | * `errmsg` is `optional` and of type `character(len=*)`
39 |
40 | For reading textual data into an array `into` of rank `1` or `2` and of
41 | type `complex`:
42 |
43 | ```fortran
44 | call from_file(file, into [, header, locale, delim, fmt, im, stat, errmsg])
45 | ```
46 |
47 | * `file` is of type `character(len=*)`
48 | * `header` is `optional` and of type `logical`
49 | * `locale` is `optional`, may be one of `LOCALES`
50 | * `delim` is `optional` and of type `character(len=*)`
51 | * `fmt` is `optional`, may be one of `REAL_FMTS`
52 | * `im` is `optional` and of type `character(len=*)`
53 | * `stat` is `optional` and of type `integer`
54 | * `errmsg` is `optional` and of type `character(len=*)`
55 |
56 | For reading binary data into an array `into` of any rank `1`-`15` and
57 | of type `integer`, `real`, `complex`:
58 |
59 | ```fortran
60 | call from_file(file, into, data_shape [, stat, errmsg])
61 | ```
62 |
63 | * `file` is of type `character(len=*)`
64 | * `data_shape` is of type `integer, dimension(:)`
65 | * `stat` is `optional` and of type `integer`
66 | * `errmsg` is `optional` and of type `character(len=*)`
67 |
68 | @note `file` may be a relative path, but absolute paths are not
69 | guaranteed to work on every platform.
70 |
71 | @warning In all cases, `into` must be `allocatable`, and will lose its
72 | allocation status upon passing into `from_file` if already allocated.
73 | As a result, `from_file` does not allow reading into sections of
74 | already allocated arrays.
75 |
76 | @note When reading binary data, `data_shape` must be present and its
77 | size must equal the rank of `into`.
78 |
79 | ### Optional Arguments
80 |
81 | Header (default is `.false.`): specifies whether a header line is
82 | present.
83 |
84 | Locales (default is `"US"`):
85 |
86 | ```fortran
87 | LOCALES = [ "US", "EU" ]
88 | ```
89 |
90 | Delimiter: data separator. Default is `","` for `integer` data and for
91 | `real`/`complex` data with `"US"` locale, and `";"` for
92 | `real`/`complex` data with `"EU"` locale. It is always recommended to
93 | omit the delimiter argument for default unless a custom delimiter is
94 | really necessary. If `x` has rank `1` and the data is ordered down the
95 | rows, then the `delim` argument is ignored.
96 |
97 | Integer formats (default is `"i"`):
98 |
99 | ```fortran
100 | INT_FMTS = [ "i", "z" ]
101 | ```
102 |
103 | Real formats (default is `"e"`):
104 |
105 | ```fortran
106 | REAL_FMTS = [ "e", "f", "z" ]
107 | ```
108 |
109 | Imaginary unit: `im` specifies the form of a complex number. If not
110 | present, `complex` numbers will be assumed to be written as ordered
111 | pairs, e.g. `(2.45,3.45)`.
112 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Reference Guide
3 | author: Austin C Bullock
4 | ordered_subpage: constants.md
5 | ordered_subpage: String.md
6 | ordered_subpage: str.md
7 | ordered_subpage: cast.md
8 | ordered_subpage: join-split.md
9 | ordered_subpage: to_file.md
10 | ordered_subpage: from_file.md
11 | ordered_subpage: echo.md
12 | ordered_subpage: aprint.md
13 | ordered_subpage: String-methods.md
14 | ordered_subpage: operators.md
15 | ---
16 |
17 | The following subsections provide user instructions for each of the
18 | publicly accessible [interfaces](../../lists/procedures.html):
19 |
20 | * [String](String.html): Function for returning a
21 | [String](../../type/string.html) representation of numbers.
22 | * [str](str.html): Function for returning a `character` representation
23 | of a number.
24 | * [cast](cast.html): Subroutine for casting between numeric and string
25 | data.
26 | * [join and split](join-split.html): Functions for joining and
27 | splitting strings.
28 | * [to_file](to_file.html): Subroutine for writing an array of uniform
29 | numeric data type to an external file.
30 | * [from_file](from_file.html): Subroutine for reading an external file
31 | of uniform numeric data type and format into an array.
32 | * [echo](echo.html): Subroutine for writing a scalar `character` or
33 | `String` to an external text file.
34 | * [aprint](aprint.html): Subroutine for printing arrays and array
35 | sections to stdout.
36 | * [String methods](String-methods.html): Type-bound procedures for
37 | [String](../../type/string.html).
38 | * [Operators](operators.html): Extended operators for convenient string
39 | manipulations.
40 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/join-split.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: join and split
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface join](../../interface/join.html)
7 |
8 | *Description*: Function for joining a vector of `tokens` into a scalar
9 | `character` or `String`.
10 |
11 | To join a one-dimensional array `tokens` of type `character` or
12 | `String`:
13 |
14 | ```fortran
15 | result = join(tokens [, separator])
16 | ```
17 |
18 | * `separator` is `optional` and of type `character(len=*)`
19 |
20 | For a subroutine version of `join`, see
21 | [join](String-methods.html#join).
22 |
23 | @note The return type of `join` is the same as the type of `tokens`.
24 |
25 | ## [interface split](../../interface/split.html)
26 |
27 | *Description*: Function for splitting a scalar `character` or `String`
28 | into a vector of `tokens`.
29 |
30 | For `substring` a scalar `character` or `String`:
31 |
32 | ```fortran
33 | result = split(substring [, separator])
34 | ```
35 |
36 | * `separator` is `optional` and of type `character(len=*)`
37 |
38 | For `substring` a scalar variable of type `String`:
39 |
40 | ```fortran
41 | result = substring%split([separator])
42 | ```
43 |
44 | * `separator` is `optional` and of type `character(len=*)`
45 |
46 | @note The type-bound procedure access of the form `substring%split()`
47 | is valid when `substring` is a `String` variable. To split a
48 | `String`-valued expression, the expression must be passed to `split` by
49 | the form `split(substring)`.
50 |
51 | @note The return type of `split` is always `String`.
52 |
53 | ### Optional Arguments
54 |
55 | Separator (default is `SPACE`): the separator to use when joining or
56 | splitting.
57 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/operators.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Operators
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [Operator interfaces](../../lists/procedures.html)
7 |
8 | *Description*: Extended operators for convenient string manipulations.
9 |
10 | ### Concatenation ([//](../../interface/operator%28SLASHSLASH%29.html) and [+](../../interface/operator%28%2B%29.html))
11 |
12 | For `x` and `y` scalars or arrays of any compatible rank, and of any
13 | combination of type `character` and `String`:
14 |
15 | ```fortran
16 | result = x // y
17 | ```
18 |
19 | ```fortran
20 | result = x + y
21 | ```
22 |
23 | @note Concatenation of mixed type will return a `String`.
24 |
25 | ### Excision ([-](../../interface/operator%28-%29.html))
26 |
27 | For `x` and `y` scalars or arrays of any compatible rank, and of any
28 | combination of type `character` and `String`:
29 |
30 | ```fortran
31 | result = x - y
32 | ```
33 |
34 | @note Excision always returns a `String` value even when both arguments
35 | are of type `character`. This ensures that excision can be performed
36 | elementally even for `character` values, which would not be
37 | well-defined with a return type of `character`. For two scalar
38 | `character` values, one may simply perform the conversion
39 | `result = str(x - y)` to return a scalar `character`.
40 |
41 | @note
42 | String arithmetic is not associative, commutative, or distributive in
43 | general:
44 |
45 | * (Associative) `(x + y) + z == x + (y + z)` and `x + (y - z) /= (x +
46 | y) - z` are both `.true.` in general.
47 | * (Commutative) `x + y /= y + x` and `x + y - z /= x - z + y` are both
48 | `.true.` in general.
49 | * (Distributive) `x - (y + z) /= x - y - z` is `.true.` in general.
50 | @endnote
51 |
52 | ### Repetition ([**](../../interface/operator%28ASTERISKASTERISK%29.html))
53 |
54 | For `x` a scalar or array of any rank, and of type `character` or
55 | `String`:
56 |
57 | ```fortran
58 | result = x**ncopies
59 | ```
60 |
61 | * `ncopies` is of type `integer`
62 |
63 | @note The `**` operator is a wrapper for the
64 | [repeat](https://gcc.gnu.org/onlinedocs/gfortran/REPEAT.html)
65 | intrinsic, and extended for type `String`.
66 |
67 | ### Equivalence ([==](../../interface/operator%28%3D%3D%29.html))
68 |
69 | For `x` and `y` scalars or arrays of any compatible rank, and of any
70 | combination of type `character` and `String`:
71 |
72 | ```fortran
73 | result = (x == y)
74 | ```
75 |
76 | ```fortran
77 | result = (x .eq. y)
78 | ```
79 |
80 | ### Non-equivalence ([/=](../../interface/operator%28SLASH%3D%29.html))
81 |
82 | For `x` and `y` scalars or arrays of any compatible rank, and of any
83 | combination of type `character` and `String`:
84 |
85 | ```fortran
86 | result = (x /= y)
87 | ```
88 |
89 | ```fortran
90 | result = (x .ne. y)
91 | ```
92 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/str.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: str
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface str](../../interface/str.html)
7 |
8 | *Description*: Function for returning a `character` representation of a
9 | number.
10 |
11 | To return the
12 | [empty string](../../module/io_fortran_lib.html#variable-empty_str),
13 | use no arguments:
14 |
15 | ```fortran
16 | result = str()
17 | ```
18 |
19 | For `x` a scalar of type `String`:
20 |
21 | ```fortran
22 | result = str(x)
23 | ```
24 |
25 | This is for scalar `String` to `character` conversion.
26 |
27 | For `x` a scalar of type `integer`:
28 |
29 | ```fortran
30 | result = str(x [, fmt])
31 | ```
32 |
33 | * `fmt` is `optional`, may be one of `INT_FMTS`
34 |
35 | For `x` a scalar of type `real`:
36 |
37 | ```fortran
38 | result = str(x [, locale, fmt, decimals])
39 | ```
40 |
41 | * `locale` is `optional`, may be one of `LOCALES`
42 | * `fmt` is `optional`, may be one of `REAL_FMTS`
43 | * `decimals` is `optional` and of type `integer`
44 |
45 | For `x` a scalar of type `complex`:
46 |
47 | ```fortran
48 | result = str(x [, locale, fmt, decimals, im])
49 | ```
50 |
51 | * `locale` is `optional`, may be one of `LOCALES`
52 | * `fmt` is `optional`, may be one of `REAL_FMTS`
53 | * `decimals` is `optional` and of type `integer`
54 | * `im` is `optional` and of type `character(len=*)`
55 |
56 | @note Note that `str` operates on scalars only. For elemental
57 | functionality, see [String](String.html).
58 |
59 | ### Optional Arguments
60 |
61 | Integer formats (default is `"i"`):
62 |
63 | ```fortran
64 | INT_FMTS = [ "i", "z" ]
65 | ```
66 |
67 | Real formats (default is `"e"`):
68 |
69 | ```fortran
70 | REAL_FMTS = [ "e", "f", "z" ]
71 | ```
72 |
73 | Locales (default is `"US"`):
74 |
75 | ```fortran
76 | LOCALES = [ "US", "EU" ]
77 | ```
78 |
79 | Decimals: `decimals` specifies the number of digits on the rhs of the
80 | radix point, with a default determined internally based on the
81 | [text format](../UserInfo/text-fmts.html) and precision.
82 |
83 | Imaginary unit: `im` specifies the form of a complex number. By
84 | default, `complex` numbers will be written as ordered pairs, e.g.
85 | `(2.45,3.45)`. If `im` is specified, then the number will be written as
86 | a sum with the specified imaginary unit, e.g. `2.45+3.45j` for `im="j"`
87 | or `2.45+3.45*1i` for `im="*1i"`.
88 |
--------------------------------------------------------------------------------
/doc_API_design/Ref/to_file.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: to_file
3 | author: Austin C Bullock
4 | ---
5 |
6 | ## [interface to_file](../../interface/to_file.html)
7 |
8 | *Description*: Subroutine for writing an array of uniform numeric data
9 | type to an external file.
10 |
11 | For writing textual data from an array `x` of rank `1`, `2` and of type
12 | `integer`:
13 |
14 | ```fortran
15 | call to_file(x, file [, header, delim, fmt, stat, errmsg])
16 | ```
17 |
18 | * `file` is of type `character(len=*)`
19 | * `header` is `optional` and of type `character(len=*), dimension(:)`
20 | * `delim` is `optional` and of type `character(len=*)`
21 | * `fmt` is `optional`, may be one of `INT_FMTS`
22 | * `stat` is `optional` and of type `integer`
23 | * `errmsg` is `optional` and of type `character(len=*)`
24 |
25 | For writing textual data from an array `x` of rank `1`, `2` and of type
26 | `real`:
27 |
28 | ```fortran
29 | call to_file(x, file [, header, locale, delim, fmt, decimals, stat, errmsg])
30 | ```
31 |
32 | * `file` is of type `character(len=*)`
33 | * `header` is `optional` and of type `character(len=*), dimension(:)`
34 | * `locale` is `optional`, may be one of `LOCALES`
35 | * `delim` is `optional` and of type `character(len=*)`
36 | * `fmt` is `optional`, may be one of `REAL_FMTS`
37 | * `decimals` is `optional` and of type `integer`
38 | * `stat` is `optional` and of type `integer`
39 | * `errmsg` is `optional` and of type `character(len=*)`
40 |
41 | For writing textual data from an array `x` of rank `1`, `2` and of type
42 | `complex`:
43 |
44 | ```fortran
45 | call to_file(x, file [, header, locale, delim, fmt, decimals, im, stat, errmsg])
46 | ```
47 |
48 | * `file` is of type `character(len=*)`
49 | * `header` is `optional` and of type `character(len=*), dimension(:)`
50 | * `locale` is `optional`, may be one of `LOCALES`
51 | * `delim` is `optional` and of type `character(len=*)`
52 | * `fmt` is `optional`, may be one of `REAL_FMTS`
53 | * `decimals` is `optional` and of type `integer`
54 | * `im` is `optional` and of type `character(len=*)`
55 | * `stat` is `optional` and of type `integer`
56 | * `errmsg` is `optional` and of type `character(len=*)`
57 |
58 | For writing binary data from an array `x` of any rank `1`-`15` and of
59 | type `integer`, `real`, `complex`:
60 |
61 | ```fortran
62 | call to_file(x, file [, stat, errmsg])
63 | ```
64 |
65 | * `file` is of type `character(len=*)`
66 | * `stat` is `optional` and of type `integer`
67 | * `errmsg` is `optional` and of type `character(len=*)`
68 |
69 | @note `file` may be a relative path, but absolute paths are not
70 | guaranteed to work on every platform.
71 |
72 | @note `to_file` will always use the `NL` line ending when writing text
73 | files (which on most systems equates to `LF`).
74 |
75 | ### Optional Arguments
76 |
77 | Header (default is none): `header` is a
78 | [character array literal](../UserInfo/compilers.html). For `x` of rank
79 | `1`, `header` may be of size `1` or `size(x)`. For `x` of rank `2`,
80 | `header` may be of size `1` or `size(x, dim=2)`.
81 |
82 | Locales (default is `"US"`):
83 |
84 | ```fortran
85 | LOCALES = [ "US", "EU" ]
86 | ```
87 |
88 | Delimiter: data separator. Default is `","` for `integer` data and for
89 | `real`/`complex` data with `"US"` locale, and `";"` for
90 | `real`/`complex` data with `"EU"` locale. It is always recommended to
91 | omit the delimiter argument for default unless a custom delimiter is
92 | really necessary. If `x` has rank `1` and `dim=1`, then the `delim`
93 | argument is ignored.
94 |
95 | Integer formats (default is `"i"`):
96 |
97 | ```fortran
98 | INT_FMTS = [ "i", "z" ]
99 | ```
100 |
101 | Real formats (default is `"e"`):
102 |
103 | ```fortran
104 | REAL_FMTS = [ "e", "f", "z" ]
105 | ```
106 |
107 | Decimals: `decimals` specifies the number of digits on the rhs of the
108 | radix point, with a default determined internally based on the
109 | [text format](../UserInfo/text-fmts.html) and precision.
110 |
111 | Imaginary unit: `im` specifies the form of a complex number. By
112 | default, `complex` numbers will be written as ordered pairs, e.g.
113 | `(2.45,3.45)`. If `im` is specified, then the number will be written as
114 | a sum with the specified imaginary unit, e.g. `2.45+3.45j` for `im="j"`
115 | or `2.45+3.45*1i` for `im="*1i"`.
116 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/characters.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Character sets and kinds
3 | author: Austin C Bullock
4 | ---
5 |
6 | The IO-Fortran-Library officially supports the standard Fortran
7 | character set, based on the
8 | [US-ASCII](https://en.wikipedia.org/wiki/ASCII) character set with
9 | default character `kind`. On most systems, the default `kind` will
10 | consist of precisely one byte per character, equivalent to
11 | `selected_char_kind("ascii")`. Since US-ASCII is a 7-bit character set
12 | and most systems use 8-bit characters, it must be noted that only the
13 | first 128 characters are system-independent, i.e. `achar(0)` is
14 | portable but `achar(255)` is not. To maximize portability across
15 | systems and compilers, the IO-Fortran-Library does not reference any
16 | other character sets or kinds other than the 128-character US-ASCII
17 | with default `kind`.
18 |
19 | However, most users should feel free to employ characters outside of
20 | the US-ASCII in strings and string expressions (including many Unicode
21 | symbols) and these will tend to behave as expected as long as the
22 | characters can fit comfortably into one byte and the output unit
23 | supports UTF-8 encoding. For instance, inspect the output of the
24 | following program:
25 |
26 | ```fortran
27 | program main
28 | use io_fortran_lib
29 | implicit none (type, external)
30 |
31 | type(String) :: emojis
32 |
33 | emojis = "😂🙈😊🤣" + "😍" - "😂" + "👌"**5
34 | call emojis%echo("emojis.txt")
35 | write(*,*) emojis
36 | end program main
37 | ```
38 |
39 | The expected result is `🙈😊🤣😍👌👌👌👌👌`, which will be displayed
40 | properly in any terminal or text file with UTF-8 encoding.
41 |
42 | @note The Fortran standard permits compilers to support character sets
43 | and kinds other than US-ASCII with one-byte `kind`, and acknowledges
44 | the extended four-byte
45 | [UCS-4](https://en.wikipedia.org/wiki/Universal_Coded_Character_Set)
46 | character set defined by ISO 10646, but such support is highly
47 | inconsistent across compilers at the time of writing.
48 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/compilers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Compiler-dependent behavior
3 | author: Austin C Bullock
4 | ---
5 |
6 | When writing text files, it's important to note that some compilers
7 | implement extensions to the Fortran standard by default with regards
8 | to character array literals. For example, the array literal
9 |
10 | ```fortran
11 | header = [ "firstcol", "secondcol" ]
12 | ```
13 |
14 | is not standard Fortran 2018 since the strings in the array do not have
15 | identical length. Some compilers will accept this and others will not.
16 | If required, simply add padding spaces to the left or right of each
17 | string to match the length of the longest element. These padding
18 | spaces will not be present in the output file.
19 |
20 | @note Some compilers may allocate strings dynamically on the stack.
21 | When reading large text files, this may result in a stack overflow or
22 | segmentation fault unless the compiler is directed to allocate
23 | everything on the heap. For example, one would specify `-heap-arrays 0`
24 | for the Intel Fortran compiler on Linux (`/heap-arrays:0` on Windows).
25 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/error-codes.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Error Codes
3 | author: Austin C Bullock
4 | ---
5 |
6 | When writing to file or reading from file, the `optional` arguments
7 | `stat` and `errmsg` may be present, which will detail any errors that
8 | may occur during execution of the procedure. The error codes have the
9 | following explanation:
10 |
11 | ```Fortran
12 | integer, parameter :: READ_ERR = 1 ! Read error code
13 | integer, parameter :: WRITE_ERR = 2 ! Write error code
14 | integer, parameter :: ALLOC_ERR = 3 ! Allocation error code
15 | integer, parameter :: ARG_ERR = 4 ! Argument error code
16 | ```
17 |
18 | A `READ_ERR` code indicates that an error has occured during a `read`
19 | statement, `inquire` statement, or a `close` statement in the execution
20 | of [from_file](../Ref/from_file.html) or
21 | [read_file](../Ref/String-methods.html#read_file). A `WRITE_ERR` code
22 | indicates that an error has occured during a `write` statement or a
23 | `close` statement in the execution of [to_file](../Ref/to_file.html),
24 | [echo](../Ref/echo.html), or
25 | [write_file](../Ref/String-methods.html#write_file). An `ALLOC_ERR`
26 | code indicates that an `allocate` or `deallocate` statement has failed.
27 | An `ARG_ERR` code indicates that the user has provided an incorrect
28 | argument to the procedure.
29 |
30 | In all cases, the `errmsg` will contain more detailed information about
31 | the error that occured. If no error condition occurs, the `stat` will
32 | return `0` and the `errmsg` will be empty.
33 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/file-ext.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: File extensions
3 | author: Austin C Bullock
4 | ---
5 |
6 | When writing to file or reading from file, a valid file extension must
7 | be present.
8 |
9 | The following are valid text file extensions:
10 |
11 | ```fortran
12 | character(len=3), parameter :: TEXT_EXT(*) = [ "csv", "txt", & ! Allowed text extensions
13 | "log", "rtf", &
14 | "odm", "odt", &
15 | "ods", "odf", &
16 | "xls", "doc", &
17 | "org", "dbf", &
18 | "bed", "gff", &
19 | "gtf" ]
20 | ```
21 |
22 | The following are valid binary file extensions:
23 |
24 | ```fortran
25 | character(len=3), parameter :: BINARY_EXT(*) = [ "dat", "bin" ] ! Allowed binary extensions
26 | ```
27 |
28 | The routines [to_file](../Ref/to_file.html) and
29 | [from_file](../Ref/from_file.html) will detect the file extension used
30 | and direct whether to write/read a text file or a binary file. The
31 | routines [echo](../Ref/echo.html),
32 | [write_file](../Ref/String-methods.html#write_file), and
33 | [read_file](../Ref/String-methods.html#read_file) accept only text
34 | extensions. Other file extensions may be eligible for addition.
35 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Important User Information
3 | author: Austin C Bullock
4 | ordered_subpage: text-fmts.md
5 | ordered_subpage: locale-fmts.md
6 | ordered_subpage: file-ext.md
7 | ordered_subpage: error-codes.md
8 | ordered_subpage: compilers.md
9 | ordered_subpage: characters.md
10 | ordered_subpage: thread-safety.md
11 | ---
12 |
13 | The following subsections detail important information for users:
14 |
15 | * [Numeric text formats](text-fmts.html)
16 | * [Locales](locale-fmts.html)
17 | * [File extensions](file-ext.html)
18 | * [Error Codes](error-codes.html)
19 | * [Compiler-dependent behavior](compilers.html)
20 | * [Character sets and kinds](characters.html)
21 | * [Thread safety](thread-safety.html)
22 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/locale-fmts.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Locales
3 | author: Austin C Bullock
4 | ---
5 |
6 | When writing floating point numbers of type `real` or `complex` as
7 | strings with [String](../Ref/String.html), [str](../Ref/str.html), or
8 | [to_file](../Ref/to_file.html), any of the following locales may be
9 | used:
10 |
11 | ```fortran
12 | character(len=2), parameter :: LOCALES(*) = [ "US", "EU" ] ! Allowed locale specifiers
13 | ```
14 |
15 | * `"US"`: US decimal (default), e.g. `1.23456789`
16 | * `"EU"`: EU decimal, e.g. `1,23456789`
17 |
18 | With `to_file` and `from_file`, the `locale` additionally determines
19 | the default delimiter, e.g. `1.23456789,0.12345678` for `locale="US"`
20 | and `1,23456789;0,12345678` for `locale="EU"`.
21 |
22 | When moving data in the opposite direction with the complementary
23 | procedures [cast](../Ref/cast.html) or
24 | [from_file](../Ref/from_file.html), the same `locale` is required to
25 | properly read the decimals. Specifying a `locale` that is different
26 | from what is actually present may result in an I/O syntax error.
27 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/text-fmts.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Numeric text formats
3 | author: Austin C Bullock
4 | ---
5 |
6 | When writing `integer` data as strings with
7 | [String](../Ref/String.html), [str](../Ref/str.html), or
8 | [to_file](../Ref/to_file.html), any of the following text formats may
9 | be used:
10 |
11 | ```fortran
12 | character(len=1), parameter :: INT_FMTS(*) = [ "i", "z" ] ! Allowed formats for integers
13 | ```
14 |
15 | * `"i"`: integer format (default), e.g. `123456`
16 | * `"z"`: hexadecimal format, e.g. `0x1e240`
17 |
18 | When writing floating point numbers of type `real` or `complex` as
19 | strings with [String](../Ref/String.html), [str](../Ref/str.html), or
20 | [to_file](../Ref/to_file.html), any of the following text formats may
21 | be used:
22 |
23 | ```fortran
24 | character(len=1), parameter :: REAL_FMTS(*) = [ "e", "f", "z" ] ! Allowed formats for floats
25 | ```
26 |
27 | * `"e"`: normalized exponential format (default), e.g.
28 | `1.23456789012345675e+005`
29 | * `"f"`: decimal format, e.g. `123456.789012345674`
30 | * `"z"`: hexadecimal format, e.g. `0x40fe240c9fcb68cd`
31 |
32 | @note The `"z"` hexadecimal format is an unsigned integer format and
33 | may be used for `integer`, `real`, or `complex` data. Floating point
34 | numbers are interpreted bit-wise as unsigned integers when written with
35 | the `"z"` format, preventing any loss of precision in a round-trip
36 | conversion. This format is preferred in data transfers for which
37 | precision losses are intolerable. The `"z"` format may also be
38 | preferred for faster read/write times and more compact storage.
39 |
40 | When moving data in the opposite direction with the complementary
41 | procedures [cast](../Ref/cast.html) or
42 | [from_file](../Ref/from_file.html), the same `fmt` is required to
43 | properly cast the data. Specifying a `fmt` that is different from what
44 | is actually present may result in an I/O syntax error.
45 |
46 | @note By default, `real` and `complex` data will be written with a
47 | number of significant digits required for a lossless round-trip
48 | conversion of the form `numeric -> string -> numeric`. In general, one
49 | may expect the `f` format to produce losses in round-trip conversion of
50 | up to a few `epsilon` in as many as a fifth of transfers. However, the
51 | `e` format is not expected to produce any losses, and the `z` format
52 | will never produce losses as it involves direct bit transfer (no
53 | base-10 ⇆ base-2 conversions are involved).
54 |
55 | @note For negative integers, the hexadecimal format `"z"` produces
56 | ambiguities across storage sizes. For instance, the integer `0xff`
57 | equates to `-1` in `int8` storage but equates to `255` in larger
58 | storage sizes. Similarly, the integer `0xffff` equates to `-1` in
59 | `int16` storage but equates to `65535` in larger storage sizes, and so
60 | on. It is the responsibility of the programmer to cast hexadecimal
61 | strings into variables with the proper storage size.
62 |
--------------------------------------------------------------------------------
/doc_API_design/UserInfo/thread-safety.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Thread safety
3 | author: Austin C Bullock
4 | ---
5 |
6 | The IO-Fortran-Library promotes thread-safety by explicitly enforcing
7 | recursion with the `recursive` keyword on all module procedures.
8 | However, performing I/O in parallel regions has the tendency to result
9 | in unexpected behavior. For instance, inspect the output of the
10 | following program with multiple coarray images:
11 |
12 | ```fortran
13 | program main
14 | use io_fortran_lib
15 | implicit none (type, external)
16 |
17 | call echo("Hello from image "//str(this_image()), file="hello.txt")
18 | end program main
19 | ```
20 |
21 | This program will result in conflicts as multiple images attempt to
22 | write to the same file concurrently. The proper way to compose this
23 | program is by nesting `echo` inside a `critical` block to enforce
24 | strict thread-safety in the region:
25 |
26 | ```fortran
27 | program main
28 | use io_fortran_lib
29 | implicit none (type, external)
30 |
31 | critical
32 | call echo("Hello from image "//str(this_image()), file="hello.txt")
33 | end critical
34 | end program main
35 | ```
36 |
37 | Another common scenario involves performing I/O on a single image,
38 | which is thread-safe:
39 |
40 | ```fortran
41 | program main
42 | use io_fortran_lib
43 | implicit none (type, external)
44 |
45 | if ( this_image() == 1 ) then
46 | call echo("Hello from image "//str(this_image()), file="hello.txt")
47 | end if
48 | end program main
49 | ```
50 |
--------------------------------------------------------------------------------
/doc_API_design/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: API Design
3 | author: Austin C Bullock
4 | ordered_subpage: UserInfo
5 | ordered_subpage: Ref
6 | ordered_subpage: Examples
7 | ---
8 |
9 | The API is made available for use through the following statement:
10 |
11 | ```fortran
12 | use io_fortran_lib
13 | ```
14 |
15 | which may be placed at the start of any compilation unit, immediately
16 | following the `program`, `module`, `function`, or `subroutine`
17 | statement, and before any `implicit` statement.
18 |
19 | The functionality provided by the API is distributed via a handful of
20 | [generic interfaces](../lists/procedures.html) and a derived type
21 | [String](../type/string.html). The corresponding routines operate on
22 | numeric and string data, and take a minimal number of arguments with
23 | optional arguments to customize output for particular use cases. This
24 | ensures ease of use and flexibility for the end-user, without the need
25 | for any specific knowledge regarding the internal implementations. For
26 | advanced character handling, the `String` type provides extensive
27 | functionality through [type-bound procedures](Ref/String-methods.html).
28 | For convenience, a list of
29 | [constants](../module/io_fortran_lib.html#variable-nl) are also
30 | provided.
31 |
32 | The design of [[io_fortran_lib]] is dualistic in nature. That is, for
33 | each operation represented by an interface, there exists a transpose
34 | operation with a corresponding interface, such as `String ⇆ cast`,
35 | `str ⇆ cast`, `to_file ⇆ from_file`, `read_file ⇆ write_file`,
36 | `join ⇆ split`, and so on. Each pair of interfaces are designed to
37 | mirror each other in their arguments and assumptions of optional
38 | arguments.
39 |
40 | @note All file I/O (both text and binary) is conducted via unformatted,
41 | stream-access reads and writes as introduced in Fortran 2003.
42 |
--------------------------------------------------------------------------------
/ford-API-index.md:
--------------------------------------------------------------------------------
1 | ---
2 | project: IO-Fortran-Library
3 | version: 1.3.1
4 | summary: A portable, standard I/O library for Modern Fortran
5 | author: Austin C Bullock
6 | github: https://github.com/acbbullock
7 | project_github: https://github.com/acbbullock/IO-Fortran-Library
8 | license: MIT
9 | creation_date: %Y-%m-%d %H:%M %z
10 | print_creation_date: true
11 | md_extensions: markdown.extensions.toc
12 | page_dir: doc_API_design
13 | externalize: true
14 | ---
15 |
16 | [TOC]
17 |
18 | # API Documentation
19 |
20 | This API documentation was generated by
21 | [FORD](https://github.com/Fortran-FOSS-Programmers/ford) (the Fortran
22 | documentation generator).
23 |
24 | ## Purpose
25 |
26 | The purpose of this project is to provide a portable, standard I/O
27 | library for Modern Fortran programs supporting the Fortran 2018
28 | standard, with the goal of enabling essential I/O functionality for
29 | Fortran programmers on any system and with any modern compiler.
30 |
31 | ## Scope
32 |
33 | The IO Fortran Library is a Fortran module [[io_fortran_lib]] which
34 | provides high level routines for doing internal and external I/O. In
35 | particular, the module provides a handful of generic interfaces and a
36 | simple derived type for doing string-based and array-based I/O that are
37 | useful for recording program data, reading data into programs, writing
38 | formatted logs and output, and for doing advanced string manipulations.
39 | For instance, one may read and write data from/to `.csv` and `.dat`
40 | files, represent numbers as strings inside of a string expression,
41 | efficiently write text to a `.log` file, and dynamically manipulate
42 | strings with a `String` type (including casting between numeric and
43 | string data).
44 |
45 | @note The module is fully self-contained, with no external
46 | dependencies, and is written to be portable and compliant to the
47 | Fortran 2018 standard such that no special extensions or compiler
48 | options should be required. The public interfaces accept all intrinsic
49 | numeric types (`integer`, `real`, and `complex`) and all standard kinds
50 | provided by the intrinsic `iso_fortran_env` module (`int8`, `int16`,
51 | `int32`, `int64`, `real32`, `real64`, and `real128`). All array-based
52 | routines additionally support up to rank 15.
53 |
54 | ## How to Use
55 |
56 | To use `io_fortran_lib` with your
57 | [fpm](https://github.com/fortran-lang/fpm) project, add the following
58 | lines to your `fpm.toml` file and `use` the module in your program
59 | units to access the routines:
60 |
61 | ```toml
62 | [dependencies]
63 | IO-Fortran-Library = { git="https://github.com/acbbullock/IO-Fortran-Library", branch="main" }
64 | ```
65 |
66 | See the [important user information](page/UserInfo/index.html) and
67 | [reference guide](page/Ref/index.html) for information about calling
68 | the [routines](lists/procedures.html), and further see the
69 | [tutorials](page/Examples/index.html) for complete example programs.
70 |
71 | ## License
72 |
73 | All source code referenced is distributed under the
74 | [MIT license](https://github.com/acbbullock/IO-Fortran-Library/blob/main/LICENCE)
75 | and available at
76 | [Github](https://github.com/acbbullock/IO-Fortran-Library).
77 |
78 | ## Contact
79 |
80 | For bug fixes or feature requests, feel free to open an issue at the
81 | [project repository](https://github.com/acbbullock/IO-Fortran-Library)
82 | or contact [acb.bullock@gmail.com](mailto:acb.bullock@gmail.com).
83 |
--------------------------------------------------------------------------------
/fpm.toml:
--------------------------------------------------------------------------------
1 | name = "IO-Fortran-Library"
2 | version = "1.3.1"
3 | license = "MIT"
4 | author = "Austin C Bullock"
5 | maintainer = "acb.bullock@gmail.com"
6 | copyright = "© 2022, Austin C Bullock"
7 |
8 | executable = [
9 | { name = "benchmark-array", source-dir = "benchmarks", main = "benchmark-array.f90" },
10 | { name = "benchmark-ints", source-dir = "benchmarks", main = "benchmark-ints.f90" }
11 | ]
12 |
13 | [build]
14 | auto-executables = false
15 | auto-tests = true
16 | auto-examples = true
17 |
18 | [install]
19 | library = true
20 |
--------------------------------------------------------------------------------
/src/io_fortran_lib/join_split_impl.f90:
--------------------------------------------------------------------------------
1 | submodule (io_fortran_lib) join_split
2 | !---------------------------------------------------------------------------------------------------------------------
3 | !! This submodule provides module procedure implementations for the **public interfaces** `join` and `split`.
4 | !---------------------------------------------------------------------------------------------------------------------
5 | implicit none (type, external)
6 |
7 | contains ! Procedure bodies for module subprograms <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
8 |
9 | module procedure join_char
10 | type(String) :: temp_String
11 | character(len=:), allocatable :: separator_
12 |
13 | if ( .not. present(separator) ) then
14 | separator_ = SPACE
15 | else
16 | separator_ = separator
17 | end if
18 |
19 | temp_String = join(String(tokens), separator=separator_)
20 |
21 | if ( temp_String%len() < 1 ) then
22 | new = EMPTY_STR
23 | else
24 | new = temp_String%s
25 | end if
26 | end procedure join_char
27 |
28 | module procedure join_string
29 | type(String) :: token_pair(2)
30 | character(len=:), allocatable :: separator_
31 | integer(i64) :: num_tokens
32 |
33 | num_tokens = size(tokens, kind=i64)
34 |
35 | if ( num_tokens == 1_i64 ) then
36 | if ( tokens(1_i64)%len64() < 1_i64 ) then
37 | new%s = EMPTY_STR; return
38 | else
39 | new%s = tokens(1_i64)%s; return
40 | end if
41 | end if
42 |
43 | if ( .not. present(separator) ) then
44 | separator_ = SPACE
45 | else
46 | separator_ = separator
47 | end if
48 |
49 | if ( num_tokens > 500_i64 ) then
50 | new = join(tokens=[ join(tokens(:num_tokens/2_i64), separator_), &
51 | join(tokens(1_i64+num_tokens/2_i64:), separator_) ], separator=separator_)
52 | else
53 | call new%join_base(tokens=tokens, separator=separator_)
54 | end if
55 | end procedure join_string
56 |
57 | module procedure split_char
58 | character(len=:), allocatable :: separator_
59 |
60 | if ( .not. present(separator) ) then
61 | separator_ = SPACE
62 | else
63 | separator_ = separator
64 | end if
65 |
66 | tokens = split(String(substring), separator=separator_)
67 | end procedure split_char
68 |
69 | module procedure split_string
70 | character(len=:), allocatable :: separator_
71 | integer(i64) :: substring_len, l, i
72 | integer :: sep_len, num_seps, sep, token, current
73 |
74 | substring_len=0_i64; l=0_i64; i=0_i64; sep_len=0; num_seps=0; sep=0; token=0; current=0
75 |
76 | substring_len = substring%len64()
77 |
78 | if ( substring_len < 1_i64 ) then
79 | allocate( tokens(1) ); tokens(1)%s = EMPTY_STR; return
80 | end if
81 |
82 | if ( .not. present(separator) ) then
83 | separator_ = SPACE
84 | else
85 | separator_ = separator
86 | end if
87 |
88 | sep_len = len(separator_)
89 |
90 | if ( sep_len == 0 ) then
91 | allocate( tokens(substring_len) )
92 | do i = 1_i64, substring_len
93 | tokens(i)%s = substring%s(i:i)
94 | end do
95 | return
96 | end if
97 |
98 | num_seps = substring%count(match=separator_)
99 |
100 | if ( num_seps == 0 ) then
101 | allocate( tokens(1) ); tokens(1)%s = substring%s; return
102 | end if
103 |
104 | allocate( tokens(num_seps + 1) )
105 |
106 | sep = iachar(separator_(1:1))
107 |
108 | i = 1_i64; l = 1_i64; token = 1; positional_transfers: do
109 | current = iachar(substring%s(i:i))
110 |
111 | if ( current /= sep ) then
112 | i = i + 1_i64; cycle
113 | end if
114 |
115 | if ( sep_len == 1 ) then
116 | tokens(token)%s = substring%s(l:i-1)
117 | if ( token == num_seps ) then
118 | tokens(num_seps+1)%s = substring%s(i+1:); return
119 | end if
120 | token = token + 1; i = i + 1_i64; l = i; cycle
121 | else
122 | if ( substring%s(i:i+sep_len-1) == separator_ ) then
123 | tokens(token)%s = substring%s(l:i-1)
124 | if ( token == num_seps ) then
125 | tokens(num_seps+1)%s = substring%s(i+sep_len:); return
126 | end if
127 | token = token + 1; i = i + sep_len; l = i; cycle
128 | else
129 | i = i + 1_i64; cycle
130 | end if
131 | end if
132 | end do positional_transfers
133 | end procedure split_string
134 | end submodule join_split
135 |
--------------------------------------------------------------------------------
/src/io_fortran_lib/operators_impl.f90:
--------------------------------------------------------------------------------
1 | submodule (io_fortran_lib) operators
2 | !---------------------------------------------------------------------------------------------------------------------
3 | !! This submodule provides module procedure implementations for the **public interfaces** `operator(//)`,
4 | !! `operator(+)`, `operator(-)`, `operator(**)`, `operator(==)`, and `operator(/=)`.
5 | !---------------------------------------------------------------------------------------------------------------------
6 | implicit none (type, external)
7 |
8 | contains ! Procedure bodies for module subprograms <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
9 |
10 | module procedure string_concatenation
11 | if ( Stringl%len() < 1 ) then
12 | if ( Stringr%len() < 1 ) then
13 | new%s = EMPTY_STR; return
14 | else
15 | new%s = Stringr%s; return
16 | end if
17 | end if
18 |
19 | if ( Stringr%len() < 1 ) then
20 | new%s = Stringl%s; return
21 | end if
22 |
23 | new%s = Stringl%s//Stringr%s
24 | end procedure string_concatenation
25 |
26 | module procedure string_char_concatenation
27 | if ( Stringl%len() < 1 ) then
28 | if ( len(charsr) < 1 ) then
29 | new%s = EMPTY_STR; return
30 | else
31 | new%s = charsr; return
32 | end if
33 | end if
34 |
35 | if ( len(charsr) < 1 ) then
36 | new%s = Stringl%s; return
37 | end if
38 |
39 | new%s = Stringl%s//charsr
40 | end procedure string_char_concatenation
41 |
42 | module procedure char_string_concatenation
43 | if ( len(charsl) < 1 ) then
44 | if ( Stringr%len() < 1 ) then
45 | new%s = EMPTY_STR; return
46 | else
47 | new%s = Stringr%s; return
48 | end if
49 | end if
50 |
51 | if ( Stringr%len() < 1 ) then
52 | new%s = charsl; return
53 | end if
54 |
55 | new%s = charsl//Stringr%s
56 | end procedure char_string_concatenation
57 |
58 | module procedure char_concat_plus
59 | new = charsl//charsr
60 | end procedure char_concat_plus
61 |
62 | module procedure string_concat_plus
63 | if ( Stringl%len() < 1 ) then
64 | if ( Stringr%len() < 1 ) then
65 | new%s = EMPTY_STR; return
66 | else
67 | new%s = Stringr%s; return
68 | end if
69 | end if
70 |
71 | if ( Stringr%len() < 1 ) then
72 | new%s = Stringl%s; return
73 | end if
74 |
75 | new%s = Stringl%s//Stringr%s
76 | end procedure string_concat_plus
77 |
78 | module procedure string_char_concat_plus
79 | if ( Stringl%len() < 1 ) then
80 | if ( len(charsr) < 1 ) then
81 | new%s = EMPTY_STR; return
82 | else
83 | new%s = charsr; return
84 | end if
85 | end if
86 |
87 | if ( len(charsr) < 1 ) then
88 | new%s = Stringl%s; return
89 | end if
90 |
91 | new%s = Stringl%s//charsr
92 | end procedure string_char_concat_plus
93 |
94 | module procedure char_string_concat_plus
95 | if ( len(charsl) < 1 ) then
96 | if ( Stringr%len() < 1 ) then
97 | new%s = EMPTY_STR; return
98 | else
99 | new%s = Stringr%s; return
100 | end if
101 | end if
102 |
103 | if ( Stringr%len() < 1 ) then
104 | new%s = charsl; return
105 | end if
106 |
107 | new%s = charsl//Stringr%s
108 | end procedure char_string_concat_plus
109 |
110 | module procedure char_excision
111 | type(String) :: Stringl
112 |
113 | Stringl%s = charsl
114 |
115 | if ( Stringl%len() < 1 ) then
116 | new%s = EMPTY_STR; return
117 | end if
118 |
119 | if ( len(charsr) < 1 ) then
120 | new%s = Stringl%s; return
121 | end if
122 |
123 | new = Stringl%replace(match=charsr, substring=EMPTY_STR)
124 | end procedure char_excision
125 |
126 | module procedure string_excision
127 | if ( Stringl%len() < 1 ) then
128 | new%s = EMPTY_STR; return
129 | end if
130 |
131 | if ( Stringr%len() < 1 ) then
132 | new%s = Stringl%s; return
133 | end if
134 |
135 | new = Stringl%replace(match=Stringr%s, substring=EMPTY_STR)
136 | end procedure string_excision
137 |
138 | module procedure string_char_excision
139 | if ( Stringl%len() < 1 ) then
140 | new%s = EMPTY_STR; return
141 | end if
142 |
143 | if ( len(charsr) < 1 ) then
144 | new%s = Stringl%s; return
145 | end if
146 |
147 | new = Stringl%replace(match=charsr, substring=EMPTY_STR)
148 | end procedure string_char_excision
149 |
150 | module procedure char_string_excision
151 | type(String) :: Stringl
152 |
153 | Stringl%s = charsl
154 |
155 | if ( Stringl%len() < 1 ) then
156 | new%s = EMPTY_STR; return
157 | end if
158 |
159 | if ( Stringr%len() < 1 ) then
160 | new%s = Stringl%s; return
161 | end if
162 |
163 | new = Stringl%replace(match=Stringr%s, substring=EMPTY_STR)
164 | end procedure char_string_excision
165 |
166 | module procedure repeat_chars
167 | new = repeat(char_base, ncopies=ncopies)
168 | end procedure repeat_chars
169 |
170 | module procedure repeat_String
171 | if ( String_base%len() < 1 ) then
172 | new%s = EMPTY_STR; return
173 | end if
174 |
175 | new%s = repeat(String_base%s, ncopies=ncopies)
176 | end procedure repeat_String
177 |
178 | module procedure string_equivalence
179 | integer :: Stringl_len, Stringr_len
180 |
181 | Stringl_len = Stringl%len()
182 | Stringr_len = Stringr%len()
183 |
184 | if ( Stringl_len /= Stringr_len ) then
185 | equal = .false.; return
186 | end if
187 |
188 | if ( Stringl_len < 1 ) then
189 | equal = .true.; return
190 | end if
191 |
192 | equal = ( Stringl%s == Stringr%s )
193 | end procedure string_equivalence
194 |
195 | module procedure string_char_equivalence
196 | integer :: Stringl_len, charsr_len
197 |
198 | Stringl_len = Stringl%len()
199 | charsr_len = len(charsr)
200 |
201 | if ( Stringl_len /= charsr_len ) then
202 | equal = .false.; return
203 | end if
204 |
205 | if ( Stringl_len < 1 ) then
206 | equal = .true.; return
207 | end if
208 |
209 | equal = ( Stringl%s == charsr )
210 | end procedure string_char_equivalence
211 |
212 | module procedure char_string_equivalence
213 | integer :: charsl_len, Stringr_len
214 |
215 | charsl_len = len(charsl)
216 | Stringr_len = Stringr%len()
217 |
218 | if ( charsl_len /= Stringr_len ) then
219 | equal = .false.; return
220 | end if
221 |
222 | if ( charsl_len < 1 ) then
223 | equal = .true.; return
224 | end if
225 |
226 | equal = ( charsl == Stringr%s )
227 | end procedure char_string_equivalence
228 |
229 | module procedure string_nonequivalence
230 | integer :: Stringl_len, Stringr_len
231 |
232 | Stringl_len = Stringl%len()
233 | Stringr_len = Stringr%len()
234 |
235 | if ( Stringl_len /= Stringr_len ) then
236 | unequal = .true.; return
237 | end if
238 |
239 | if ( Stringl_len < 1 ) then
240 | unequal = .false.; return
241 | end if
242 |
243 | unequal = ( Stringl%s /= Stringr%s )
244 | end procedure string_nonequivalence
245 |
246 | module procedure string_char_nonequivalence
247 | integer :: Stringl_len, charsr_len
248 |
249 | Stringl_len = Stringl%len()
250 | charsr_len = len(charsr)
251 |
252 | if ( Stringl_len /= charsr_len ) then
253 | unequal = .true.; return
254 | end if
255 |
256 | if ( Stringl_len < 1 ) then
257 | unequal = .false.; return
258 | end if
259 |
260 | unequal = ( Stringl%s /= charsr )
261 | end procedure string_char_nonequivalence
262 |
263 | module procedure char_string_nonequivalence
264 | integer :: charsl_len, Stringr_len
265 |
266 | charsl_len = len(charsl)
267 | Stringr_len = Stringr%len()
268 |
269 | if ( charsl_len /= Stringr_len ) then
270 | unequal = .true.; return
271 | end if
272 |
273 | if ( charsl_len < 1 ) then
274 | unequal = .false.; return
275 | end if
276 |
277 | unequal = ( charsl /= Stringr%s )
278 | end procedure char_string_nonequivalence
279 | end submodule operators
280 |
--------------------------------------------------------------------------------
/src/modules/randoms_mod.f90:
--------------------------------------------------------------------------------
1 | module randoms
2 | !---------------------------------------------------------------------------------------------------------------------
3 | !! This module provides Gaussian sampling utility routines for use in unit testing.
4 | !---------------------------------------------------------------------------------------------------------------------
5 | use, intrinsic :: iso_fortran_env, only: r128=>real128, r64=>real64, r32=>real32
6 | implicit none (type, external)
7 | private
8 |
9 | ! Public API list ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 | public :: random_gauss
11 |
12 | ! Definitions and Interfaces ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13 |
14 | interface gauss ! Submodule gaussian_sampling
15 | !-------------------------------------------------------------------------------------------------------------------
16 | !! Samples random numbers from the standard Normal (Gaussian) Distribution with the given mean and sigma.
17 | !! Uses the Acceptance-complement ratio from W. Hoermann and G. Derflinger.
18 | !! This is one of the fastest existing methods for generating normal random variables.
19 | !!
20 | !! REFERENCE: - W. Hoermann and G. Derflinger (1990):
21 | !! The ACR Method for generating normal random variables,
22 | !! OR Spektrum 12 (1990), 181-185.
23 | !!
24 | !! Implementation taken from
25 | !! UNURAN (c) 2000 W. Hoermann & J. Leydold, Institut f. Statistik, WU Wien
26 | !---------------------------------------------------------------------------------------------------------------
27 | impure real(r128) module function gauss_r128(mu, sig) result(gauss_res)
28 | real(r128), intent(in) :: mu, sig
29 | end function gauss_r128
30 | impure real(r64) module function gauss_r64(mu, sig) result(gauss_res)
31 | real(r64), intent(in) :: mu, sig
32 | end function gauss_r64
33 | impure real(r32) module function gauss_r32(mu, sig) result(gauss_res)
34 | real(r32), intent(in) :: mu, sig
35 | end function gauss_r32
36 | end interface
37 |
38 | interface random_gauss ! Submodule gaussian_sampling
39 | !-------------------------------------------------------------------------------------------------------------------
40 | !! Applies `gauss` to whole arrays and scalars.
41 | !-------------------------------------------------------------------------------------------------------------------
42 | impure elemental module subroutine random_gauss_r128(x, mu, sig)
43 | real(r128), intent(inout) :: x
44 | real(r128), intent(in) :: mu, sig
45 | end subroutine random_gauss_r128
46 | impure elemental module subroutine random_gauss_r64(x, mu, sig)
47 | real(r64), intent(inout) :: x
48 | real(r64), intent(in) :: mu, sig
49 | end subroutine random_gauss_r64
50 | impure elemental module subroutine random_gauss_r32(x, mu, sig)
51 | real(r32), intent(inout) :: x
52 | real(r32), intent(in) :: mu, sig
53 | end subroutine random_gauss_r32
54 | end interface
55 | end module randoms
56 |
--------------------------------------------------------------------------------
/test/test.ps1:
--------------------------------------------------------------------------------
1 | fpm clean --all
2 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R4 -D I1"
3 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R4 -D I2"
4 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R8 -D I4"
5 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R16 -D I8"
6 |
7 | fpm clean --all
8 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R4 -D I1"
9 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R4 -D I2"
10 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R8 -D I4"
11 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R16 -D I8"
12 |
13 | fpm clean --all
14 | fpm test --compiler ifx --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R4 /define:I1"
15 | fpm test --compiler ifx --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R4 /define:I2"
16 | fpm test --compiler ifx --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R8 /define:I4"
17 | fpm test --compiler ifx --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R16 /define:I8"
18 |
19 | fpm clean --all
20 | fpm test --compiler ifx --flag "/stand:f18 /O3 /fpp /define:R4 /define:I1"
21 | fpm test --compiler ifx --flag "/stand:f18 /O3 /fpp /define:R4 /define:I2"
22 | fpm test --compiler ifx --flag "/stand:f18 /O3 /fpp /define:R8 /define:I4"
23 | fpm test --compiler ifx --flag "/stand:f18 /O3 /fpp /define:R16 /define:I8"
24 |
25 | fpm clean --all
26 | fpm test --compiler ifort --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R4 /define:I1"
27 | fpm test --compiler ifort --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R4 /define:I2"
28 | fpm test --compiler ifort --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R8 /define:I4"
29 | fpm test --compiler ifort --flag "/stand:f18 /warn:all /check:all /error-limit:1 /Od /Z7 /traceback /assume:byterecl /fpp /define:R16 /define:I8"
30 |
31 | fpm clean --all
32 | fpm test --compiler ifort --flag "/stand:f18 /O3 /fpp /define:R4 /define:I1"
33 | fpm test --compiler ifort --flag "/stand:f18 /O3 /fpp /define:R4 /define:I2"
34 | fpm test --compiler ifort --flag "/stand:f18 /O3 /fpp /define:R8 /define:I4"
35 | fpm test --compiler ifort --flag "/stand:f18 /O3 /fpp /define:R16 /define:I8"
36 |
37 | fpm clean --all
38 |
--------------------------------------------------------------------------------
/test/test.sh:
--------------------------------------------------------------------------------
1 | fpm clean --all
2 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R4 -D I1"
3 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R4 -D I2"
4 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R8 -D I4"
5 | fpm test --compiler gfortran --flag "-std=f2018 -mtune=generic -march=x86-64 -g -Wall -Wextra -Werror=implicit-interface -fPIC -fmax-errors=1 -fbounds-check -fcheck=array-temps -fbacktrace -fcoarray=single -fimplicit-none -ffree-form -cpp -D R16 -D I8"
6 |
7 | fpm clean --all
8 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R4 -D I1"
9 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R4 -D I2"
10 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R8 -D I4"
11 | fpm test --compiler gfortran --flag "-std=f2018 -O3 -cpp -D R16 -D I8"
12 |
13 | fpm clean --all
14 | fpm test --compiler ifx --flag "-stand f18 -warn all -check all -check nouninit -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R4 -D I1"
15 | fpm test --compiler ifx --flag "-stand f18 -warn all -check all -check nouninit -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R4 -D I2"
16 | fpm test --compiler ifx --flag "-stand f18 -warn all -check all -check nouninit -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R8 -D I4"
17 | fpm test --compiler ifx --flag "-stand f18 -warn all -check all -check nouninit -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R16 -D I8"
18 |
19 | fpm clean --all
20 | fpm test --compiler ifx --flag "-stand f18 -O3 -fpp -D R4 -D I1"
21 | fpm test --compiler ifx --flag "-stand f18 -O3 -fpp -D R4 -D I2"
22 | fpm test --compiler ifx --flag "-stand f18 -O3 -fpp -D R8 -D I4"
23 | fpm test --compiler ifx --flag "-stand f18 -O3 -fpp -D R16 -D I8"
24 |
25 | fpm clean --all
26 | fpm test --compiler ifort --flag "-stand f18 -warn all -check all -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R4 -D I1"
27 | fpm test --compiler ifort --flag "-stand f18 -warn all -check all -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R4 -D I2"
28 | fpm test --compiler ifort --flag "-stand f18 -warn all -check all -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R8 -D I4"
29 | fpm test --compiler ifort --flag "-stand f18 -warn all -check all -error-limit 1 -O0 -g -traceback -assume byterecl -fpp -D R16 -D I8"
30 |
31 | fpm clean --all
32 | fpm test --compiler ifort --flag "-stand f18 -O3 -fpp -D R4 -D I1"
33 | fpm test --compiler ifort --flag "-stand f18 -O3 -fpp -D R4 -D I2"
34 | fpm test --compiler ifort --flag "-stand f18 -O3 -fpp -D R8 -D I4"
35 | fpm test --compiler ifort --flag "-stand f18 -O3 -fpp -D R16 -D I8"
36 |
37 | fpm clean --all
38 |
--------------------------------------------------------------------------------
/test/units/array-test-i.f90:
--------------------------------------------------------------------------------
1 | program main
2 | use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
3 | use kinds, only: rk, ik
4 | use io_fortran_lib, only: String, cast, LF, SPACE, str, operator(+), operator(**)
5 | use randoms, only: random_gauss
6 | implicit none (type, external)
7 |
8 | integer, parameter :: n = 2000
9 | character(len=*), parameter :: logfile = "./test/tests.log"
10 |
11 | character(len=10) :: date="", time=""
12 | type(String) :: testlog, errlog
13 | logical :: test_succeeded=.true., all_passing=.true.
14 |
15 | character(len=512) :: errmsg=""
16 | integer :: stat=0
17 |
18 | type(String), allocatable :: string_var(:)
19 | real(rk), allocatable :: x(:)
20 | integer(ik), allocatable :: i(:), j(:)
21 |
22 | call random_init(repeatable=.false., image_distinct=.true.)
23 | call date_and_time(date=date, time=time)
24 |
25 | testlog = String("RUNNING TESTS (String/cast) | date: " + trim(adjustl(date)) + &
26 | " | time: " + time + &
27 | " | int kind: " + str(ik) )
28 | call testlog%push(LF + "-"**testlog%len() + LF)
29 |
30 | errlog = String(" ERROR LOG" + LF + " ---------" + LF)
31 |
32 | allocate( string_var(n), stat=stat, errmsg=errmsg )
33 | if ( stat /= 0 ) error stop LF + "FATAL: Allocation failure at line " + str(__LINE__ - 1) + &
34 | ' of file "' + __FILE__ + '".'
35 | allocate( x(n), source=0e0_rk, stat=stat, errmsg=errmsg )
36 | if ( stat /= 0 ) error stop LF + "FATAL: Allocation failure at line " + str(__LINE__ - 1) + &
37 | ' of file "' + __FILE__ + '".'
38 | allocate( i(n), j(n), source=0_ik, stat=stat, errmsg=errmsg )
39 | if ( stat /= 0 ) error stop LF + "FATAL: Allocation failure at line " + str(__LINE__ - 1) + &
40 | ' of file "' + __FILE__ + '".'
41 |
42 | 1 continue
43 |
44 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
45 | call cast(String(i, fmt="i"), into=j, fmt="i")
46 | test_succeeded = all(i == j)
47 | if ( .not. test_succeeded ) then
48 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
49 | end if
50 |
51 | 2 if ( .not. test_succeeded ) all_passing = .false.
52 |
53 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
54 | call cast(String(i, fmt="z"), into=j, fmt="z")
55 | test_succeeded = all(i == j)
56 | if ( .not. test_succeeded ) then
57 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
58 | end if
59 |
60 | 3 if ( .not. test_succeeded ) all_passing = .false.
61 |
62 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
63 | call cast(i, into=string_var, fmt="i"); call cast(string_var, into=j, fmt="i")
64 | test_succeeded = all(i == j)
65 | if ( .not. test_succeeded ) then
66 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
67 | end if
68 |
69 | 4 if ( .not. test_succeeded ) all_passing = .false.
70 |
71 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
72 | call cast(i, into=string_var, fmt="z"); call cast(string_var, into=j, fmt="z")
73 | test_succeeded = all(i == j)
74 | if ( .not. test_succeeded ) then
75 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
76 | end if
77 |
78 | 5 if ( .not. test_succeeded ) all_passing = .false.
79 |
80 | if ( all_passing ) then
81 | call testlog%push('All tests are "PASSING" with compiler "' + compiler_version() + '" ' + &
82 | 'using compiler options "' + compiler_options() + '".' + LF)
83 | else
84 | call testlog%push('Some tests are "FAILING" with compiler "' + compiler_version() + '" ' + &
85 | 'using compiler options "' + compiler_options() + '".' + LF)
86 | end if
87 |
88 | call testlog%echo(logfile)
89 | write(*,"(DT)") testlog
90 |
91 | if ( .not. all_passing ) then
92 | call errlog%echo(logfile)
93 | write(*,"(DT)") errlog
94 | end if
95 | end program main
96 |
--------------------------------------------------------------------------------
/test/units/array-test-r.f90:
--------------------------------------------------------------------------------
1 | program main
2 | use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
3 | use kinds, only: rk
4 | use io_fortran_lib, only: String, cast, LF, SPACE, str, operator(+), operator(**)
5 | use randoms, only: random_gauss
6 | implicit none (type, external)
7 |
8 | real(rk), parameter :: tol = 3.0_rk*epsilon(1e0_rk)
9 | integer, parameter :: n = 2000
10 | character(len=*), parameter :: logfile = "./test/tests.log"
11 |
12 | character(len=10) :: date="", time=""
13 | type(String) :: testlog, errlog
14 | logical :: test_succeeded=.true., all_passing=.true.
15 |
16 | character(len=512) :: errmsg=""
17 | integer :: stat=0
18 |
19 | type(String), allocatable :: string_var(:)
20 | real(rk), allocatable :: x(:), y(:)
21 |
22 | call random_init(repeatable=.false., image_distinct=.true.)
23 | call date_and_time(date=date, time=time)
24 |
25 | testlog = String("RUNNING TESTS (String/cast) | date: " + trim(adjustl(date)) + &
26 | " | time: " + time + &
27 | " | real kind: " + str(rk) )
28 | call testlog%push(LF + "-"**testlog%len() + LF)
29 |
30 | errlog = String(" ERROR LOG" + LF + " ---------" + LF)
31 |
32 | allocate( string_var(n), stat=stat, errmsg=errmsg )
33 | if ( stat /= 0 ) error stop LF + "FATAL: Allocation failure at line " + str(__LINE__ - 1) + &
34 | ' of file "' + __FILE__ + '".'
35 | allocate( x(n), y(n), source=0e0_rk, stat=stat, errmsg=errmsg )
36 | if ( stat /= 0 ) error stop LF + "FATAL: Allocation failure at line " + str(__LINE__ - 1) + &
37 | ' of file "' + __FILE__ + '".'
38 |
39 | 1 continue
40 |
41 | call random_gauss(x,0e0_rk,1e0_rk)
42 | call cast(String(x, locale="US", fmt="e"), into=y, locale="US", fmt="e")
43 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
44 | if ( .not. test_succeeded ) then
45 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
46 | end if
47 |
48 | 2 if ( .not. test_succeeded ) all_passing = .false.
49 |
50 | call random_gauss(x,0e0_rk,1e0_rk)
51 | call cast(String(x, locale="US", fmt="f"), into=y, locale="US", fmt="f")
52 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
53 | if ( .not. test_succeeded ) then
54 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
55 | end if
56 |
57 | 3 if ( .not. test_succeeded ) all_passing = .false.
58 |
59 | call random_gauss(x,0e0_rk,1e0_rk)
60 | call cast(String(x, locale="US", fmt="z"), into=y, locale="US", fmt="z")
61 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
62 | if ( .not. test_succeeded ) then
63 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
64 | end if
65 |
66 | 4 if ( .not. test_succeeded ) all_passing = .false.
67 |
68 | call random_gauss(x,0e0_rk,1e0_rk)
69 | call cast(String(x, locale="EU", fmt="e"), into=y, locale="EU", fmt="e")
70 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
71 | if ( .not. test_succeeded ) then
72 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
73 | end if
74 |
75 | 5 if ( .not. test_succeeded ) all_passing = .false.
76 |
77 | call random_gauss(x,0e0_rk,1e0_rk)
78 | call cast(String(x, locale="EU", fmt="f"), into=y, locale="EU", fmt="f")
79 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
80 | if ( .not. test_succeeded ) then
81 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
82 | end if
83 |
84 | 6 if ( .not. test_succeeded ) all_passing = .false.
85 |
86 | call random_gauss(x,0e0_rk,1e0_rk)
87 | call cast(String(x, locale="EU", fmt="z"), into=y, locale="EU", fmt="z")
88 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
89 | if ( .not. test_succeeded ) then
90 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
91 | end if
92 |
93 | 7 if ( .not. test_succeeded ) all_passing = .false.
94 |
95 | call random_gauss(x,0e0_rk,1e0_rk)
96 | call cast(x, into=string_var, locale="US", fmt="e"); call cast(string_var, into=y, locale="US", fmt="e")
97 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
98 | if ( .not. test_succeeded ) then
99 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
100 | end if
101 |
102 | 8 if ( .not. test_succeeded ) all_passing = .false.
103 |
104 | call random_gauss(x,0e0_rk,1e0_rk)
105 | call cast(x, into=string_var, locale="US", fmt="f"); call cast(string_var, into=y, locale="US", fmt="f")
106 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
107 | if ( .not. test_succeeded ) then
108 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
109 | end if
110 |
111 | 9 if ( .not. test_succeeded ) all_passing = .false.
112 |
113 | call random_gauss(x,0e0_rk,1e0_rk)
114 | call cast(x, into=string_var, locale="US", fmt="z"); call cast(string_var, into=y, locale="US", fmt="z")
115 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
116 | if ( .not. test_succeeded ) then
117 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
118 | end if
119 |
120 | 10 if ( .not. test_succeeded ) all_passing = .false.
121 |
122 | call random_gauss(x,0e0_rk,1e0_rk)
123 | call cast(x, into=string_var, locale="EU", fmt="e"); call cast(string_var, into=y, locale="EU", fmt="e")
124 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
125 | if ( .not. test_succeeded ) then
126 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
127 | end if
128 |
129 | 11 if ( .not. test_succeeded ) all_passing = .false.
130 |
131 | call random_gauss(x,0e0_rk,1e0_rk)
132 | call cast(x, into=string_var, locale="EU", fmt="f"); call cast(string_var, into=y, locale="EU", fmt="f")
133 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
134 | if ( .not. test_succeeded ) then
135 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
136 | end if
137 |
138 | 12 if ( .not. test_succeeded ) all_passing = .false.
139 |
140 | call random_gauss(x,0e0_rk,1e0_rk)
141 | call cast(x, into=string_var, locale="EU", fmt="z"); call cast(string_var, into=y, locale="EU", fmt="z")
142 | test_succeeded = (maxval( abs(x-y)/abs(x) ) < tol)
143 | if ( .not. test_succeeded ) then
144 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
145 | end if
146 |
147 | 13 if ( .not. test_succeeded ) all_passing = .false.
148 |
149 | if ( all_passing ) then
150 | call testlog%push('All tests are "PASSING" with compiler "' + compiler_version() + '" ' + &
151 | 'using compiler options "' + compiler_options() + '".' + LF)
152 | else
153 | call testlog%push('Some tests are "FAILING" with compiler "' + compiler_version() + '" ' + &
154 | 'using compiler options "' + compiler_options() + '".' + LF)
155 | end if
156 |
157 | call testlog%echo(logfile)
158 | write(*,"(DT)") testlog
159 |
160 | if ( .not. all_passing ) then
161 | call errlog%echo(logfile)
162 | write(*,"(DT)") errlog
163 | end if
164 | end program main
165 |
--------------------------------------------------------------------------------
/test/units/kinds_mod.f90:
--------------------------------------------------------------------------------
1 | module kinds
2 | use, intrinsic :: iso_fortran_env, only: r128=>real128, r64=>real64, r32=>real32, & ! ISO standard real kinds
3 | i64=>int64, i32=>int32, i16=>int16, i8=>int8 ! ISO standard int kinds
4 | implicit none (type, external)
5 | private
6 |
7 | #ifdef R16
8 | integer, public, parameter :: rk = r128
9 | #elif R8
10 | integer, public, parameter :: rk = r64
11 | #else
12 | integer, public, parameter :: rk = r32
13 | #endif
14 |
15 | #ifdef I8
16 | integer, public, parameter :: ik = i64
17 | #elif I2
18 | integer, public, parameter :: ik = i16
19 | #elif I1
20 | integer, public, parameter :: ik = i8
21 | #else
22 | integer, public, parameter :: ik = i32
23 | #endif
24 |
25 | end module kinds
26 |
--------------------------------------------------------------------------------
/test/units/scalar-test-i.f90:
--------------------------------------------------------------------------------
1 | program main
2 | use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
3 | use kinds, only: rk, ik
4 | use io_fortran_lib, only: String, cast, LF, SPACE, str, operator(+), operator(**)
5 | use randoms, only: random_gauss
6 | implicit none (type, external)
7 |
8 | character(len=*), parameter :: logfile = "./test/tests.log"
9 |
10 | character(len=10) :: date="", time=""
11 | type(String) :: testlog, errlog
12 | logical :: test_succeeded=.true., all_passing=.true.
13 |
14 | character(len=:), allocatable :: char_var
15 |
16 | real(rk) :: x = 0e0_rk
17 | integer(ik) :: i = 0_ik, j = 0_ik
18 |
19 | call random_init(repeatable=.false., image_distinct=.true.)
20 | call date_and_time(date=date, time=time)
21 |
22 | testlog = String("RUNNING TESTS (str/cast) | date: " + trim(adjustl(date)) + &
23 | " | time: " + time + &
24 | " | int kind: " + str(ik) )
25 | call testlog%push(LF + "-"**testlog%len() + LF)
26 |
27 | errlog = String(" ERROR LOG" + LF + " ---------" + LF)
28 |
29 | 1 continue
30 |
31 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
32 | call cast(str(i, fmt="i"), into=j, fmt="i")
33 | test_succeeded = (i == j)
34 | if ( .not. test_succeeded ) then
35 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
36 | end if
37 |
38 | 2 if ( .not. test_succeeded ) all_passing = .false.
39 |
40 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
41 | call cast(str(i, fmt="z"), into=j, fmt="z")
42 | test_succeeded = (i == j)
43 | if ( .not. test_succeeded ) then
44 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
45 | end if
46 |
47 | 3 if ( .not. test_succeeded ) all_passing = .false.
48 |
49 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
50 | call cast(i, into=char_var, fmt="i"); call cast(char_var, into=j, fmt="i")
51 | test_succeeded = (i == j)
52 | if ( .not. test_succeeded ) then
53 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
54 | end if
55 |
56 | 4 if ( .not. test_succeeded ) all_passing = .false.
57 |
58 | call random_gauss(x,0e0_rk,1e0_rk); i = floor(huge(1_ik)*x, ik) + 1_ik
59 | call cast(i, into=char_var, fmt="z"); call cast(char_var, into=j, fmt="z")
60 | test_succeeded = (i == j)
61 | if ( .not. test_succeeded ) then
62 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
63 | end if
64 |
65 | 5 if ( .not. test_succeeded ) all_passing = .false.
66 |
67 | if ( all_passing ) then
68 | call testlog%push('All tests are "PASSING" with compiler "' + compiler_version() + '" ' + &
69 | 'using compiler options "' + compiler_options() + '".' + LF)
70 | else
71 | call testlog%push('Some tests are "FAILING" with compiler "' + compiler_version() + '" ' + &
72 | 'using compiler options "' + compiler_options() + '".' + LF)
73 | end if
74 |
75 | call testlog%echo(logfile)
76 | write(*,"(DT)") testlog
77 |
78 | if ( .not. all_passing ) then
79 | call errlog%echo(logfile)
80 | write(*,"(DT)") errlog
81 | end if
82 | end program main
83 |
--------------------------------------------------------------------------------
/test/units/scalar-test-r.f90:
--------------------------------------------------------------------------------
1 | program main
2 | use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
3 | use kinds, only: rk
4 | use io_fortran_lib, only: String, cast, LF, SPACE, str, operator(+), operator(**)
5 | use randoms, only: random_gauss
6 | implicit none (type, external)
7 |
8 | real(rk), parameter :: tol = 3.0_rk*epsilon(1e0_rk)
9 | character(len=*), parameter :: logfile = "./test/tests.log"
10 |
11 | character(len=10) :: date="", time=""
12 | type(String) :: testlog, errlog
13 | logical :: test_succeeded=.true., all_passing=.true.
14 |
15 | character(len=:), allocatable :: char_var
16 |
17 | real(rk) :: x = 0e0_rk, y = 0e0_rk
18 |
19 | call random_init(repeatable=.false., image_distinct=.true.)
20 | call date_and_time(date=date, time=time)
21 |
22 | testlog = String("RUNNING TESTS (str/cast) | date: " + trim(adjustl(date)) + &
23 | " | time: " + time + &
24 | " | real kind: " + str(rk) )
25 | call testlog%push(LF + "-"**testlog%len() + LF)
26 |
27 | errlog = String(" ERROR LOG" + LF + " ---------" + LF)
28 |
29 | 1 continue
30 |
31 | call random_gauss(x,0e0_rk,1e0_rk)
32 | call cast(str(x, locale="US", fmt="e"), into=y, locale="US", fmt="e")
33 | test_succeeded = (abs(x-y)/abs(x) < tol)
34 | if ( .not. test_succeeded ) then
35 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
36 | end if
37 |
38 | 2 if ( .not. test_succeeded ) all_passing = .false.
39 |
40 | call random_gauss(x,0e0_rk,1e0_rk)
41 | call cast(str(x, locale="US", fmt="f"), into=y, locale="US", fmt="f")
42 | test_succeeded = (abs(x-y)/abs(x) < tol)
43 | if ( .not. test_succeeded ) then
44 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
45 | end if
46 |
47 | 3 if ( .not. test_succeeded ) all_passing = .false.
48 |
49 | call random_gauss(x,0e0_rk,1e0_rk)
50 | call cast(str(x, locale="US", fmt="z"), into=y, locale="US", fmt="z")
51 | test_succeeded = (abs(x-y)/abs(x) < tol)
52 | if ( .not. test_succeeded ) then
53 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
54 | end if
55 |
56 | 4 if ( .not. test_succeeded ) all_passing = .false.
57 |
58 | call random_gauss(x,0e0_rk,1e0_rk)
59 | call cast(str(x, locale="EU", fmt="e"), into=y, locale="EU", fmt="e")
60 | test_succeeded = (abs(x-y)/abs(x) < tol)
61 | if ( .not. test_succeeded ) then
62 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
63 | end if
64 |
65 | 5 if ( .not. test_succeeded ) all_passing = .false.
66 |
67 | call random_gauss(x,0e0_rk,1e0_rk)
68 | call cast(str(x, locale="EU", fmt="f"), into=y, locale="EU", fmt="f")
69 | test_succeeded = (abs(x-y)/abs(x) < tol)
70 | if ( .not. test_succeeded ) then
71 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
72 | end if
73 |
74 | 6 if ( .not. test_succeeded ) all_passing = .false.
75 |
76 | call random_gauss(x,0e0_rk,1e0_rk)
77 | call cast(str(x, locale="EU", fmt="z"), into=y, locale="EU", fmt="z")
78 | test_succeeded = (abs(x-y)/abs(x) < tol)
79 | if ( .not. test_succeeded ) then
80 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
81 | end if
82 |
83 | 7 if ( .not. test_succeeded ) all_passing = .false.
84 |
85 | call random_gauss(x,0e0_rk,1e0_rk)
86 | call cast(x, into=char_var, locale="US", fmt="e"); call cast(char_var, into=y, locale="US", fmt="e")
87 | test_succeeded = (abs(x-y)/abs(x) < tol)
88 | if ( .not. test_succeeded ) then
89 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
90 | end if
91 |
92 | 8 if ( .not. test_succeeded ) all_passing = .false.
93 |
94 | call random_gauss(x,0e0_rk,1e0_rk)
95 | call cast(x, into=char_var, locale="US", fmt="f"); call cast(char_var, into=y, locale="US", fmt="f")
96 | test_succeeded = (abs(x-y)/abs(x) < tol)
97 | if ( .not. test_succeeded ) then
98 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
99 | end if
100 |
101 | 9 if ( .not. test_succeeded ) all_passing = .false.
102 |
103 | call random_gauss(x,0e0_rk,1e0_rk)
104 | call cast(x, into=char_var, locale="US", fmt="z"); call cast(char_var, into=y, locale="US", fmt="z")
105 | test_succeeded = (abs(x-y)/abs(x) < tol)
106 | if ( .not. test_succeeded ) then
107 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
108 | end if
109 |
110 | 10 if ( .not. test_succeeded ) all_passing = .false.
111 |
112 | call random_gauss(x,0e0_rk,1e0_rk)
113 | call cast(x, into=char_var, locale="EU", fmt="e"); call cast(char_var, into=y, locale="EU", fmt="e")
114 | test_succeeded = (abs(x-y)/abs(x) < tol)
115 | if ( .not. test_succeeded ) then
116 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
117 | end if
118 |
119 | 11 if ( .not. test_succeeded ) all_passing = .false.
120 |
121 | call random_gauss(x,0e0_rk,1e0_rk)
122 | call cast(x, into=char_var, locale="EU", fmt="f"); call cast(char_var, into=y, locale="EU", fmt="f")
123 | test_succeeded = (abs(x-y)/abs(x) < tol)
124 | if ( .not. test_succeeded ) then
125 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
126 | end if
127 |
128 | 12 if ( .not. test_succeeded ) all_passing = .false.
129 |
130 | call random_gauss(x,0e0_rk,1e0_rk)
131 | call cast(x, into=char_var, locale="EU", fmt="z"); call cast(char_var, into=y, locale="EU", fmt="z")
132 | test_succeeded = (abs(x-y)/abs(x) < tol)
133 | if ( .not. test_succeeded ) then
134 | call errlog%push(" Test bounds failed at line " + str(__LINE__ - 2) + ' of file "' + __FILE__ + '".' + LF)
135 | end if
136 |
137 | 13 if ( .not. test_succeeded ) all_passing = .false.
138 |
139 | if ( all_passing ) then
140 | call testlog%push('All tests are "PASSING" with compiler "' + compiler_version() + '" ' + &
141 | 'using compiler options "' + compiler_options() + '".' + LF)
142 | else
143 | call testlog%push('Some tests are "FAILING" with compiler "' + compiler_version() + '" ' + &
144 | 'using compiler options "' + compiler_options() + '".' + LF)
145 | end if
146 |
147 | call testlog%echo(logfile)
148 | write(*,"(DT)") testlog
149 |
150 | if ( .not. all_passing ) then
151 | call errlog%echo(logfile)
152 | write(*,"(DT)") errlog
153 | end if
154 | end program main
155 |
--------------------------------------------------------------------------------