Some Notes about Fortran : User defined I/O derived type


Derived type in Fortran is for object programming.s In my experience , almost my derived type used in my games or software have over 10 variables in it.

In the first time, when i want save some objects in a file ,and changed some variables, i must repeatedly write all the variables with line format following .

In game development or GUI software, have a big loop in program. All the big derived type variable will have hard time when it repeatedly used 60 times in a second. Have some case when you want write big object derived type to a buffer file and read it again when need it .

That is why this user defined I/O derived type come on table ! It make my code easy to understand and do not need to remember all the format need to write my 10 variables derived type to somewhere . It is really a disaster when you need change , add something to derived type and detected it contains another 10 procedure need to check in about 10000 lines of code.

Now, for example, we have a derive type about a monster object like under code. For simple i ready cut 10s variables about graphic and action step in this TYPE define.

TYPE monster
     CHARACTER(len = :) , ALLOCATABLE   :: name 
     CHARACTER(len = :) , ALLOCATABLE   :: filepath 
     TYPE(c_ptr)                        :: name_texture
     INTEGER                            :: hitpoint 
     REAL                               :: speed 
     TYPE(sdl_rect)                     :: position 
     CONTAINS 
     PROCEDURE                          :: goleft 
     PROCEDURE                          :: gorigh
     PROCEDURE                          :: goup
     PROCEDURE                          :: godown 
END TYPE 

We want to defined User-Defined I/O generic procedures for this object . Add 4 lines defined 2 generic function read/write in middle of CONTAINS and END TYPE . This time we go with unformatted type User-Defined I/O .

 PROCEDURE :: monster_write_unformat
 GENERIC   :: write(unformatted) => monster_write_unformat
 PROCEDURE :: monster_read_unformat
 GENERIC   :: read(unformatted) => monster_read_unformat

And this 2 procedures will be defined like under code. Please remember that , this generic define procedure must have 4 dummy variables (this, unit, iostat, iomsg) with intent(inout) like this code for unformatted inout case. And because it is for unformatted case , all read write statement in it should be for unformatted data type either.

SUBROUTINE monnster_write_unformat(this,unit,IOSTAT,IOMSG)
implicit none
CLASS(monster),INTENT(IN)     :: this
INTEGER,INTENT(IN)            :: unit
INTEGER,INTENT(OUT)           :: IOSTAT
CHARACTER(LEN=*),INTENT(INOUT):: IOMSG

WRITE(unit,iostat = IOSTAT, iomsg = IOMSG)  LEN(this%name)
WRITE(unit,iostat = IOSTAT, iomsg = IOMSG)  this%name

WRITE(unit,iostat = IOSTAT, iomsg = IOMSG)  LEN(this%file_path)
WRITE(unit,iostat = IOSTAT, iomsg = IOMSG)  this%file_path
CALL texture_write_unformatted(unit,this%name_pic)
WRITE(unit,iostat = IOSTAT, iomsg = IOMSG)  this%hitpoint

END SUBROUTINE 
SUBROUTINE monster_read_unformat(this,unit,IOSTAT,IOMSG)
implicit none
CLASS(monster),INTENT(INOUT)  :: this
INTEGER,INTENT(IN)            :: unit
INTEGER,INTENT(OUT)           :: IOSTAT
CHARACTER(LEN=*),INTENT(INOUT):: IOMSG
INTEGER                       :: size_of_something 
INTEGER                       :: i 

READ(unit,iostat = IOSTAT, iomsg = IOMSG)  size_of_something
if (ALLOCATED(this%name)) DEALLOCATE(this%name)
ALLOCATE(CHARACTER(len = size_of_something) :: this%name)
READ(unit,iostat = IOSTAT, iomsg = IOMSG)  this%name

READ(unit,iostat = IOSTAT, iomsg = IOMSG)  size_of_something
if (ALLOCATED(this%file_path)) DEALLOCATE(this%file_path)
ALLOCATE(CHARACTER(len = size_of_something) :: this%file_path)
READ(unit,iostat = IOSTAT, iomsg = IOMSG)  this%file_path
CALL texture_read_unformatted(unit,this%name_pic)
READ(unit,iostat = IOSTAT, iomsg = IOMSG)  this%hitpoint
END SUBROUTINE 

And now we can write , read it on-the-fly like this under code . monster_array is array of this monster type , we want to write it to a file “monster1” for example , save all monsters data about their hitpoint and position in a map to buffer file ,easy like as a normal variable.

OPEN(newunit = memory_unit, file = "monster1", status = "replace",form="unformatted")

WRITE(memory_unit) size(monster_array
do i = 1, size(monster_array)
   WRITE(memory_unit) monster_array(i)
end do
CLOSE(memory_unit)

Thanks for reading this.


Leave a Reply

Your email address will not be published. Required fields are marked *