M_anything(3fm) - [M_anything::INTRO] procedures that use polymorphism to allow arguments of different types generically
(LICENSE:MIT)
Syntax:
use M_anything,only : anyscalar_to_string
use M_anything,only : anyscalar_to_int64
use M_anything,only : anyscalar_to_real
use M_anything,only : anyscalar_to_real128
use M_anything,only : anyscalar_to_double
use M_anything,only : anything_to_bytes
use M_anything,only : anyinteger_to_string
use M_anything,only : get_type
use M_anything,only : bytes_to_anything
use M_anything,only : empty, assignment(=)
anyscalar_to_string convert intrinsic type to string
anyscalar_to_int64 convert integer or real of any kind to 64-bit integer
anyscalar_to_real convert integer or real of any kind to real
anyscalar_to_real128 convert integer or real of any kind to real128
anyscalar_to_double convert integer or real of any kind to doubleprecision
anything_to_bytes convert anything to bytes
anyinteger_to_string convert integer to string
get_type return array of strings containing type names of arguments
empty create an empty array
At the cost of casting to a different type these functions can (among other uses such as in linked lists) allow for an alternative to duplicating code using generic procedure methods. For example, the following SQUAREALL function can take many input types and return a DOUBLEPRECISION value (it is a trivial example for demonstration purposes, and does not check for overflow, etc.).:
Sample program
program demo_M_anything
use, intrinsic :: iso_fortran_env, only : int8, int16, int32, int64
use, intrinsic :: iso_fortran_env, only : real32, real64, real128
implicit none
! call same function with many scalar input types
write(*,*)squareall(2_int8)
write(*,*)squareall(2_int16)
write(*,*)squareall(2_int32)
write(*,*)squareall(2_int64)
write(*,*)squareall(2.0_real32)
write(*,*)squareall(2.0_real64)
!write(*,*)squareall(2.0_real128)
contains
function squareall(invalue) result (dvalue)
use M_anything, only : anyscalar_to_double
class(*),intent(in) :: invalue
doubleprecision :: invalue_local
doubleprecision :: dvalue
invalue_local=anyscalar_to_double(invalue)
dvalue=invalue_local*invalue_local
end function squareall
end program demo_M_anything
Results:
4.00000000000000
4.00000000000000
4.00000000000000
4.00000000000000
4.00000000000000
4.00000000000000
4.00000000000000
John S. Urban
MIT
,input_unit,output_unit public setany
subroutine setany(anything,default,answer)
$@(#) M_anything::setany(3fp): set absent parameter to default value
class(),intent(in),optional :: anything class(),intent(in) :: default class(*),intent(out),allocatable :: answer if(present(anything))then answer=anything else answer=default endif end subroutine setany
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| type(Empty_t), | public | :: | empty |
singleton |
anything_to_bytes(3f) - [M_anything] convert standard types to bytes (character(len=1):: array(:))
(LICENSE:MIT)
function anything_to_bytes(anything) result(chars)
class(*),intent(in) :: anything
or
class(*),intent(in) :: anything(:)
character(len=1),allocatable :: chars(:)
This function uses polymorphism to allow input arguments of different
types. It is used to create other procedures that can take many
argument types as input options and convert them to a single type
to simplify storing arbitrary data, to simplify generating data
hashes, ...
The **transfer(3f)** function is now a standard, even more general
equivalent.
VALUEIN input array or scalar to convert to type CHARACTER(LEN=1).
May be of KIND INTEGER(kind=int8), INTEGER(kind=int16),
INTEGER(kind=int32), INTEGER(kind=int64),
REAL(kind=real32, REAL(kind=real64),
REAL(kind=real128), complex, or CHARACTER(len=*)
CHARS The returned value is an array of bytes (character(len=1)).
Sample program
program demo_anything_to_bytes
use M_anything, only : anything_to_bytes
implicit none
integer :: i
write(*,"('select various types')")
write(*,'(/,16(1x,z2.2))')anything_to_bytes([(i*i,i=1,10)])
write(*,'(/,16(1x,z2.2))')anything_to_bytes([11.11,22.22,33.33])
write(*,'(/,16(1x,z2.2))')anything_to_bytes('This is a string')
write(*,"(/,'compare to TRANSFER(3f)')")
write(*,'(/,16(1x,z2.2))') transfer([(i*i,i=1,10)],[' '])
write(*,'(/,16(1x,z2.2))') transfer([11.11,22.22,33.33],[' '])
write(*,'(/,16(1x,z2.2))') transfer('This is a string',[' '])
end program demo_anything_to_bytes
``` Results:
> select various types
>
> 01 00 00 00 04 00 00 00 09 00 00 00 10 00 00 00
> 19 00 00 00 24 00 00 00 31 00 00 00 40 00 00 00
> 51 00 00 00 64 00 00 00
>
> 8F C2 31 41 8F C2 B1 41 EC 51 05 42
>
> 54 68 69 73 20 69 73 20 61 20 73 74 72 69 6E 67
>
> compare to TRANSFER(3f)
>
> 01 00 00 00 04 00 00 00 09 00 00 00 10 00 00 00
> 19 00 00 00 24 00 00 00 31 00 00 00 40 00 00 00
> 51 00 00 00 64 00 00 00
>
> 8F C2 31 41 8F C2 B1 41 EC 51 05 42
>
> 54 68 69 73 20 69 73 20 61 20 73 74 72 69 6E 67
John S. Urban
MIT
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | anything(:) |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | anything |
empty(3f) - [M_anything] set an allocatable array to zero
(LICENSE:MIT)
use M_anything, only : empty, assignment(=)
A convenience routine that sets an array to an empty set.
Sample program:
program demo_empty_
use M_anything, only : empty, assignment(=)
integer, allocatable :: ints(:)
character(:), allocatable :: strs(:)
real, allocatable :: reals(:)
ints=empty
write(*,*)size(ints)
write(*,*)'give them some size ...'
reals = [1.0,2.0,3.0]
ints = [1,2,3]
strs = [character(len=10) :: "one","two","three","four"]
write(*,*)size(ints)
write(*,*)size(reals)
write(*,*)size(strs)
ints=empty
reals=empty
strs=empty
write(*,*)'back to empty ...'
write(*,*)size(ints)
write(*,*)size(reals)
write(*,*)size(strs)
end program demo_empty_
Expected output:
> 0
> give them some size ...
> 3
> 3
> 4
> back to empty ...
> 0
> 0
> 0
John S. Urban
MIT
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(inout), | allocatable | :: | x(:) | ||
| type(Empty_t), | intent(in) | :: | emp |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real, | intent(inout), | allocatable | :: | x(:) | ||
| type(Empty_t), | intent(in) | :: | emp |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| doubleprecision, | intent(inout), | allocatable | :: | x(:) | ||
| type(Empty_t), | intent(in) | :: | emp |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=:), | intent(inout), | allocatable | :: | x(:) | ||
| type(Empty_t), | intent(in) | :: | emp |
bytes_to_anything(3f) - [M_anything] convert bytes(character)len=1):: array(:)) to standard types
(LICENSE:MIT)
subroutine bytes_to_anything(chars,anything)
character(len=1),allocatable :: chars(:)
class(*) :: anything
This function uses polymorphism to allow input arguments of different
types. It is used to create other procedures that can take many
argument types as input options and convert them to a single type
to simplify storing arbitrary data, to simplify generating data
hashes, ...
CHARS The input value is an array of bytes (character(len=1)).
ANYTHING May be of KIND INTEGER(kind=int8), INTEGER(kind=int16),
INTEGER(kind=int32), INTEGER(kind=int64),
REAL(kind=real32, REAL(kind=real64),
REAL(kind=real128), complex, or CHARACTER(len=*)
Sample program
program demo_bytes_to_anything
use, intrinsic :: ISO_FORTRAN_ENV, only: &
CSZ => CHARACTER_STORAGE_SIZE, &
stderr => error_unit
use :: M_anything, only : bytes_to_anything, anything_to_bytes
implicit none
character(len=1), allocatable :: chars(:)
character(len=:), allocatable :: line
character(len=:), allocatable :: lines(:)
integer :: ints(10)
integer :: i, int
integer,allocatable :: somesize(:)
call header('integer array to bytes')
chars = anything_to_bytes([(i*i, i=1, size(ints))])
write (*, '(/,4(1x,z2.2))') chars
call bytes_to_anything(chars, ints)
write(*,*)'and bytes back to integer array'
write (*, '(/,*(g0,1x))') ints
call header('integer scalar to bytes')
chars = anything_to_bytes(1234)
write (*, '(/,"CHARS=",*(1x,z2.2))') chars
call bytes_to_anything(chars, int)
write(*,*)'and bytes back to integer scalar'
write (*, '(/,"INT=",*(g0,1x))') int
call header('a string')
chars = anything_to_bytes('this is a string')
write (*, '(/,"CHARS=",*(1x,z2.2))') chars
write (*, '(/,"CHARS=",*(g0,1x))') chars
! string must be long enough to hold chars
line=repeat(' ',size(chars))
call bytes_to_anything(chars, line)
write (*, '(/,"LINE=",*(g0,1x))') line
call header(&
'a string array (have to know length or size you wish to return to)')
chars = anything_to_bytes([character(len=4) :: 'a', 'bb', 'ccc' ])
write (*, '(/,"CHARS=",*(1x,z2.2))') chars
write (*, '(/,"CHARS=",*(g0,1x))') chars
! string must be long enough to hold chars, and have enough elements
! can just return as a scalar string if unknown length
lines=[repeat(' ',size(chars))]
! of for that matter just work with the chars(1) array,
! but assuming know length in this case
lines=[(repeat('#',4),i=1,3)]
call bytes_to_anything(chars, lines)
write (*, '(/,"LINES=",*("[",g0,"]",1x:))') lines
call header('calculating size to allocate for non-string types')
! make sure array is of sufficient size to hold results
chars = anything_to_bytes([11,22,33,44])
write (*, '(/,"CHARS=",*(1x,z2.2))') chars
allocate(somesize(size(chars)/(storage_size(0)/CSZ)))
call bytes_to_anything(chars, somesize)
write (*, '(/,"SOMESIZE=",*("[",g0,"]",1x:))') somesize
contains
subroutine header(line)
character(len=*),intent(in) :: line
write(*,'(*(a))')'#',repeat('=',len(line)+2),'#'
write(*,'("|",1x,a,1x,"|")') line
write(*,'(*(a))')'#',repeat('=',len(line)+2),'#'
end subroutine header
end program demo_bytes_to_anything
Results:
> #========================#
> | integer array to bytes |
> #========================#
>
> 01 00 00 00
> 04 00 00 00
> 09 00 00 00
> 10 00 00 00
> 19 00 00 00
> 24 00 00 00
> 31 00 00 00
> 40 00 00 00
> 51 00 00 00
> 64 00 00 00
> and bytes back to integer array
>
> 1 4 9 16 25 36 49 64 81 100
> #=========================#
> | integer scalar to bytes |
> #=========================#
>
> CHARS= D2 04 00 00
> and bytes back to integer scalar
>
> INT=1234
> #==========#
> | a string |
> #==========#
>
> CHARS= 74 68 69 73 20 69 73 20 61 20 73 74 72 69 6E 67
>
> CHARS=t h i s i s a s t r i n g
>
> LINE=this is a string
> #====================================================================#
> | a string array (have to know length or size you wish to return to) |
> #====================================================================#
>
> CHARS= 61 20 20 20 62 62 20 20 63 63 63 20
>
> CHARS=a b b c c c
>
> LINES=[a ] [bb ] [ccc ]
> #===================================================#
> | calculating size to allocate for non-string types |
> #===================================================#
>
> CHARS= 0B 00 00 00 16 00 00 00 21 00 00 00 2C 00 00 00
>
> SOMESIZE=[11] [22] [33] [44]
John S. Urban
MIT
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=1), | intent(in) | :: | chars(:) | |||
| class(*), | intent(out) | :: | anything(:) |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=1), | intent(in) | :: | chars(:) | |||
| class(*), | intent(out) | :: | anything |
get_type(3f) - [M_anything] return array of strings containing type
names of arguments
(LICENSE:MIT)
function get_type(anything) result(chars)
class(*),intent(in) :: anything
or
class(*),intent(in) :: anything(..)
character(len=:),allocatable :: chars
This function uses polymorphism to allow input arguments of different
types. It is used by other procedures that can take many
argument types as input options.
VALUEIN input array or scalar to return type of
May be of KIND INTEGER(kind=int8), INTEGER(kind=int16),
INTEGER(kind=int32), INTEGER(kind=int64),
REAL(kind=real32, REAL(kind=real64),
REAL(kind=real128), complex, or CHARACTER(len=*)
CHARS The returned value is an array of names
Sample program
program demo_get_type
use M_anything, only : get_type
implicit none
integer :: i
write(*,*)get_type([(i*i,i=1,10)])
write(*,*)get_type([11.11,22.22,33.33])
write(*,*)get_type('This is a string')
write(*,*)get_type(30.0d0)
end program demo_get_type
Results:
int32
real32
character
real64
John S. Urban
MIT
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | anything(:) |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | anything |
Sample program
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | int |
Sample program
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | valuein |
Results
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | valuein |
Sample program
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | valuein |
Sample program
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | valuein |
Sample program:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in), | optional | :: | gen0 | ||
| class(*), | intent(in), | optional | :: | gen1 | ||
| class(*), | intent(in), | optional | :: | gen2 | ||
| class(*), | intent(in), | optional | :: | gen3 | ||
| class(*), | intent(in), | optional | :: | gen4 | ||
| class(*), | intent(in), | optional | :: | gen5 | ||
| class(*), | intent(in), | optional | :: | gen6 | ||
| class(*), | intent(in), | optional | :: | gen7 | ||
| class(*), | intent(in), | optional | :: | gen8 | ||
| class(*), | intent(in), | optional | :: | gen9 | ||
| class(*), | intent(in), | optional | :: | gena | ||
| class(*), | intent(in), | optional | :: | genb | ||
| class(*), | intent(in), | optional | :: | genc | ||
| class(*), | intent(in), | optional | :: | gend | ||
| class(*), | intent(in), | optional | :: | gene | ||
| class(*), | intent(in), | optional | :: | genf | ||
| class(*), | intent(in), | optional | :: | geng | ||
| class(*), | intent(in), | optional | :: | genh | ||
| class(*), | intent(in), | optional | :: | geni | ||
| class(*), | intent(in), | optional | :: | genj | ||
| character(len=*), | intent(in), | optional | :: | sep |