Skip to content

stdlib_io: add print_array function to print arrays to output units #981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions doc/specs/stdlib_io.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,38 @@ Exceptions trigger an `error stop` unless the optional `err` argument is provide
{!example/io/example_get_file.f90!}
```

## `print_array` - Print an array to an output unit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comment: the name could be discussed with the community. Personally, I would prefer disp.


### Status

Experimental

### Description

This subroutine interface prints a 2D array to a specified output unit.

### Syntax

`call [[stdlib_io(module):print_array(subroutine)]] (array[, unit][, fmt][, delimiter][, brief])`

### Class

Subroutine

### Arguments

`array`: Shall be a 2D array of `integer`, `real`, or `complex` type. It is an `intent(in)` argument.

`unit`: Shall be an integer containing the output unit. It is an `intent(in)` argument. The default is `6` (standard output).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`unit`: Shall be an integer containing the output unit. It is an `intent(in)` argument. The default is `6` (standard output).
`unit`: Shall be an integer containing the output unit. It is an `intent(in)` argument. The default is the intrinsic `output_unit` provided by `iso_fortran_env`.


`fmt`: Shall be a character string containing the format for printing the array. It is an `intent(in)` argument. The default is based on [the Formatting constants](#formatting-constants).

`delimiter`: Shall be a character string of length 1 containing the delimiter between array elements. It is an `intent(in)` argument. The default is a `" "` (space).

`brief`: Shall be a logical flag. If `.true.`, the array is printed in a brief format. The default is `.true.`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is a "brief" format? Could you maybe provide a short definition?


### Example

```fortran
{!./example/io/example_print_array.f90}
```
1 change: 1 addition & 0 deletions example/io/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ ADD_EXAMPLE(loadtxt)
ADD_EXAMPLE(open)
ADD_EXAMPLE(savenpy)
ADD_EXAMPLE(savetxt)
ADD_EXAMPLE(print_array)
16 changes: 16 additions & 0 deletions example/io/example_print_array.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
program example_io_print_array

use stdlib_io, only: print_array
implicit none

integer, dimension(6, 3) :: array = reshape([1, 2, 3, 4, 5, 6, &
7, 8, 9, 10, 11, 12, &
13, 14, 15, 16, 17, 18], [6, 3])

print "(a)", "=== print_array 1 ==="
call print_array(array, unit=6, fmt='(i3)', delimiter='|', brief=.true.)

print "(a)", "=== print_array 2 ==="
call print_array(array(:1, :))

end program example_io_print_array
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ set(fppFiles
stdlib_io_npy.fypp
stdlib_io_npy_load.fypp
stdlib_io_npy_save.fypp
stdlib_io_print_array.fypp
stdlib_kinds.fypp
stdlib_linalg.fypp
stdlib_linalg_diag.fypp
Expand Down
18 changes: 17 additions & 1 deletion src/stdlib_io.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module stdlib_io
implicit none
private
! Public API
public :: loadtxt, savetxt, open, get_line, get_file
public :: loadtxt, savetxt, open, get_line, get_file, print_array

!! version: experimental
!!
Expand Down Expand Up @@ -102,6 +102,22 @@ module stdlib_io
#:endfor
end interface

interface print_array
!! version: experimental
!!
!! Prints a 2D array to an output unit
!! ([Specification](../page/specs/stdlib_io.html#print_array))
#:for k1, t1 in KINDS_TYPES
module subroutine print_array_${t1[0]}$${k1}$(array, unit, fmt, delimiter, brief)
${t1}$, intent(in) :: array(:, :)
integer, intent(in), optional :: unit
character(len=*), intent(in), optional :: fmt
character(len=1), intent(in), optional :: delimiter
logical, intent(in), optional :: brief
end subroutine print_array_${t1[0]}$${k1}$
#:endfor
end interface

contains

#:for k1, t1 in KINDS_TYPES
Expand Down
88 changes: 88 additions & 0 deletions src/stdlib_io_print_array.fypp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#:include "common.fypp"
#:set KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES + INT_KINDS_TYPES
submodule(stdlib_io) stdlib_io_print_array

use, intrinsic :: iso_fortran_env, only: output_unit
implicit none

contains

#:for k1, t1 in KINDS_TYPES
module subroutine print_array_${t1[0]}$${k1}$(array, unit, fmt, delimiter, brief)
${t1}$, intent(in) :: array(:, :)
integer, intent(in), optional :: unit
character(len=*), intent(in), optional :: fmt
character(len=1), intent(in), optional :: delimiter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be

Suggested change
character(len=1), intent(in), optional :: delimiter
character(len=*), intent(in), optional :: delimiter

and then declare delimiter_ allocatable

logical, intent(in), optional :: brief

integer :: i, j, unit_, shape_(2)
character(len=:), allocatable :: fmt_
character(len=1) :: delimiter_
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
character(len=1) :: delimiter_
character(len=:), allocatable :: delimiter_

character(len=3) :: delim_str
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
character(len=3) :: delim_str
character(len=:), allocatable :: delim_str

logical :: brief_

shape_ = shape(array)
if (any(shape_ == 0)) return
unit_ = optval(unit, output_unit)
delimiter_ = optval(delimiter, delimiter_default)
delim_str = "'"//delimiter_//"'"
brief_ = optval(brief, .true.)
if (present(fmt)) then
fmt_ = "(*"//fmt(1:len(fmt) - 1)//",:,"//delim_str//"))"
else
#:if 'real' in t1
fmt_ = "(*"//FMT_REAL_${k1}$ (1:len(FMT_REAL_${k1}$) - 1)//",:,"//delim_str//"))"
#:elif 'complex' in t1
fmt_ = "(*"//FMT_COMPLEX_${k1}$ (1:11)//delim_str//FMT_COMPLEX_${k1}$ (14:23)//",:,"//delim_str//"))"
#:elif 'integer' in t1
fmt_ = "(*"//FMT_INT(1:len(FMT_INT) - 1)//",:,"//delim_str//"))"
#:endif
end if

if (brief_) then

if (shape_(1) > 5) then
if (shape_(2) > 5) then
do i = 1, 3
write (unit_, fmt=fmt_, advance='no') array(i, :3)
write (unit_, fmt='(a)', advance='no') delimiter_//"..."//delimiter_
write (unit_, fmt=fmt_) array(i, shape_(2))
end do
write (unit_, fmt='(a)') ":"
write (unit_, fmt=fmt_, advance='no') array(shape_(1), :3)
write (unit_, fmt='(a)', advance='no') delimiter_//"..."//delimiter_
write (unit_, fmt=fmt_) array(shape_(1), shape_(2))
else
do i = 1, 3
write (unit_, fmt=fmt_) array(i, :)
end do
write (unit_, fmt='(a)') ":"
write (unit_, fmt=fmt_) array(shape_(1), :)

end if
else
if (shape_(2) > 5) then
do i = 1, shape_(1)
write (unit_, fmt=fmt_, advance='no') array(i, :3)
write (unit_, fmt='(a)', advance='no') delimiter_//"..."//delimiter_
write (unit_, fmt=fmt_) array(i, shape_(2))
end do
else
do i = 1, shape_(1)
write (unit_, fmt=fmt_) array(i, :)
end do
end if
end if

else

do i = 1, shape_(1)
write (unit_, fmt=fmt_) array(i, :)
end do

end if

end subroutine print_array_${t1[0]}$${k1}$
#:endfor

end submodule stdlib_io_print_array
1 change: 1 addition & 0 deletions test/io/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ ADDTEST(get_line)
ADDTEST(npy)
ADDTEST(open)
ADDTEST(parse_mode)
ADDTEST(print_array)
Loading
Loading