module shr_strconvert_mod ! This module defines toString, a generic function for creating character type ! representations of data, as implemented for the most commonly used intrinsic ! types: ! ! - 4 and 8 byte integer ! - 4 and 8 byte real ! - logical ! ! No toString implementation is provided for character input, but this may be ! added if some use case arises. ! ! Currently, only scalar inputs are supported. The return type of this function ! is character with deferred (allocatable) length. ! ! The functions for integers and reals allow an optional format_string argument, ! which can be used to control the padding and precision of output as with any ! write statement. However, the implementations internally must use a ! preallocated buffer, so a format_string that significantly increases the size ! of the output may cause a run-time error or undefined behavior in the program. ! ! Other modules may want to provide extensions of toString for their own derived ! types. In this case there are two guidelines to observe: ! ! - It is preferable to have only one mandatory argument, which is the object to ! produce a string from. There may be other formatting options, but the ! implementation should do something sensible without these. ! ! - Since the main purpose of toString is to provide a human-readable ! representation of a type, especially for documentation or debugging ! purposes, refrain from printing large array components in their entirety ! (instead consider printing only the shape, or statistics such as ! min/mean/max for arrays of numbers). use shr_kind_mod, only: & i4 => shr_kind_i4, & i8 => shr_kind_i8, & r4 => shr_kind_r4, & r8 => shr_kind_r8, & cs => shr_kind_cs use shr_infnan_mod, only: & isnan => shr_infnan_isnan implicit none private ! Human-readable representation of data. public :: toString interface toString module procedure i4ToString module procedure i8ToString module procedure r4ToString module procedure r8ToString module procedure logicalToString end interface toString contains pure function i4ToString(input, format_string) result(string) integer(i4), intent(in) :: input character(len=*), intent(in), optional :: format_string character(len=:), allocatable :: string character(len=cs) :: buffer if (present(format_string)) then write(buffer, format_string) input else ! For most compilers, these two statements are equivalent to a format of ! '(I0)', but that's not technically in the standard. write(buffer, '(I11)') input buffer = adjustl(buffer) end if allocate(string, source=trim(buffer)) end function i4ToString pure function i8ToString(input, format_string) result(string) integer(i8), intent(in) :: input character(len=*), intent(in), optional :: format_string character(len=:), allocatable :: string character(len=cs) :: buffer if (present(format_string)) then write(buffer, format_string) input else ! For most compilers, these two statements are equivalent to a format of ! '(I0)', but that's not technically in the standard. write(buffer, '(I20)') input buffer = adjustl(buffer) end if allocate(string, source=trim(buffer)) end function i8ToString pure function r4ToString(input, format_string) result(string) real(r4), intent(in) :: input character(len=*), intent(in), optional :: format_string character(len=:), allocatable :: string character(len=cs) :: buffer if (present(format_string)) then write(buffer, format_string) input else write(buffer, '(ES15.8 E2)') input buffer = adjustl(buffer) ! Deal with the fact that the "+" sign is optional by simply adding it if ! it is not present, so that the default format is standardized across ! compilers. ! Assumes that compilers do not treat the sign bit on NaN values specially. if (.not. isnan(input) .and. all(buffer(1:1) /= ["-", "+"])) then buffer = "+" // trim(buffer) end if end if allocate(string, source=trim(buffer)) end function r4ToString pure function r8ToString(input, format_string) result(string) real(r8), intent(in) :: input character(len=*), intent(in), optional :: format_string character(len=:), allocatable :: string character(len=cs) :: buffer if (present(format_string)) then write(buffer, format_string) input else write(buffer, '(ES24.16 E3)') input buffer = adjustl(buffer) ! Deal with the fact that the "+" sign is optional by simply adding it if ! it is not present, so that the default format is standardized across ! compilers. ! Assumes that compilers do not treat the sign bit on NaN values specially. if (.not. isnan(input) .and. all(buffer(1:1) /= ["-", "+"])) then buffer = "+" // trim(buffer) end if end if allocate(string, source=trim(buffer)) end function r8ToString pure function logicalToString(input) result(string) logical, intent(in) :: input character(len=:), allocatable :: string ! We could use a write statement, but this is easier. allocate(character(len=1) :: string) if (input) then string = "T" else string = "F" end if end function logicalToString end module shr_strconvert_mod