FTValueClass.f90 Source File


Source Code

!
!////////////////////////////////////////////////////////////////////////
!
!
!> A not completely F2003/2008 version of an immutable class
!> to store primitive values: integer, real, double precision, logical,
!> character. (To Add: complex)
!>
!> This version does not use CLASS(*) or deferred length strings
!> so that it can be used with gfortran 4.7/4.8
!>
!> Usage:
!> ------
!>
!> - Initialization
!>
!>            TYPE(FTValue) :: r, i, s, l, d
!>
!>            CALL r % initValue(3.14)
!>            CALL i % initValue(6)
!>            CALL d % initValue(3.14d0)
!>            CALL l % initValue(.true.)
!>            CALL s % initValue("A string")
!>
!> - Destruction 
!>
!>            CALL r % destruct()   [non pointers]
!>            call release(r) [Pointers]
!>
!> - Accessors
!>
!>            real = r % realValue()
!>            int  = i % integerValue()
!>            doub = d % doublePrecisionValue()
!>            logc = l % logicalValue()
!>            str  = s % stringValue(nChars)
!>
!> - Description
!>
!>            str = v % description()
!>            call v % printDescription(unit)
!>
!> - Casting
!>
!>            CLASS(FTVALUE) , POINTER :: v
!>            CLASS(FTObject), POINTER :: obj
!>            call cast(obj,v)
!>      
!> The class will attempt to convert between the different types:
!>
!>            CALL r % initWithReal(3.14)
!>            print *, r % stringValue(8)
!>
!>            Logical variables rules:
!>
!>            real, doublePrecision, integer values
!>               logicalValue = .FALSE. if input = 0
!>               logicalValue = .TRUE.  if input /= 0
!>
!> String values can be converted to numeric types. If the string is
!> not a numeric, Huge(1) will be returned, for integers and NaN for reals.
!>      
!<
! FTValueClass.f90
! Created: January 9, 2013 12:20 PM 
!> @author David Kopriva  
!<
!
!////////////////////////////////////////////////////////////////////////
!
      Module FTValueClass
      USE IEEE_ARITHMETIC
      USE ISO_FORTRAN_ENV
      USE FTOLConstants
      USE FTObjectClass
      IMPLICIT NONE
!
!     ----------------
!     Public constants
!     ----------------
!
      INTEGER          , PARAMETER :: FTVALUE_NOT_INTEGER         = HUGE(1)
      REAL             , PARAMETER :: FTVALUE_NOT_REAL            = HUGE(1.0)
      DOUBLE PRECISION , PARAMETER :: FTVALUE_NOT_DOUBLEPRECISION = HUGE(1.0D0)
      INTEGER          , PARAMETER :: FTVALUE_STRING_LENGTH       = 512 ! Until vary length strings are available.
      
      INTEGER, PARAMETER :: FT_REAL_KIND             = SELECTED_REAL_KIND(6)
      INTEGER, PARAMETER :: FT_DOUBLE_PRECISION_KIND = SELECTED_REAL_KIND(15)
!
!     -----------------
!     Private constants
!     -----------------
!
      INTEGER, PARAMETER, PRIVATE :: FTVALUECLASS_INTEGER = 1, FTVALUECLASS_REAL   = 2, &
                                     FTVALUECLASS_DOUBLE  = 3, FTVALUECLASS_STRING = 4, &
                                     FTVALUECLASS_LOGICAL = 5, FTVALUECLASS_QUAD   = 6
!
!     ---------------------
!     Class type definition 
!     ---------------------
!
      TYPE, EXTENDS(FTObject) :: FTValue
         PRIVATE
         INTEGER                       :: valueType
         CHARACTER(LEN=1), ALLOCATABLE :: valueStorage(:) 
!
!        ========         
         CONTAINS
!        ========
!
!        --------------
!        Initialization
!        --------------
!
         PROCEDURE, PRIVATE :: initWithReal
         PROCEDURE, PRIVATE :: initWithDoublePrecision
         PROCEDURE, PRIVATE :: initWithString
         PROCEDURE, PRIVATE :: initWithLogical
         PROCEDURE, PRIVATE :: initWithInteger
         GENERIC  , PUBLIC  :: initWithValue => initWithReal,   initWithDoublePrecision, &
                                                initWithString, initWithLogical,         &
                                                initWithInteger
#ifdef _has_Quad
         PROCEDURE, PRIVATE :: initWithQuad
         GENERIC  , PUBLIC  :: initWithValue => initWithQuad
#endif
!
!        -----------
!        Destruction
!        -----------
!
         PROCEDURE :: destruct => destructValue
!
!        -------
!        Getters
!        -------
!
         PROCEDURE :: realValue
         PROCEDURE :: doublePrecisionValue
#ifdef _has_Quad
         PROCEDURE :: quadValue
#endif
         PROCEDURE :: stringValue
         PROCEDURE :: logicalValue
         PROCEDURE :: integerValue
!
!        -----------
!        Description
!        -----------
!
         PROCEDURE :: description      => FTValueDescription
         PROCEDURE :: printDescription => printValueDescription
         PROCEDURE :: className        => valueClassName
!
!        ----------
!        Comparison
!        ----------
!
!         PROCEDURE, PRIVATE :: isEqualTo => isEqualToFTValue

         
      END TYPE FTValue

      INTERFACE cast
         MODULE PROCEDURE castToValue
      END INTERFACE cast
      
      INTERFACE release
         MODULE PROCEDURE releaseFTValue 
      END INTERFACE  

!     ----------
!     Procedures
!     ----------
!
      CONTAINS 
!@mark -
!
!
!------------------------------------------------
!> Public, generic name: initwithValue()
!>
!> Initialize the value object with a real number
!------------------------------------------------
!
!
!////////////////////////////////////////////////////////////////////////
!
      SUBROUTINE initWithReal(self,v) 
         IMPLICIT NONE
         CLASS(FTValue) :: self
         REAL           :: v
         INTEGER        :: dataLength
         
         CALL self % FTObject % init()
         
         dataLength = SIZE(TRANSFER(v,self % valueStorage))
         ALLOCATE(self % valueStorage(dataLength))
         self % valueStorage = TRANSFER(v,self % valueStorage)
         
         self % valueType = FTVALUECLASS_REAL
         
      END SUBROUTINE initWithReal
!
!-----------------------------------------------
!> Public, generic name: initwithValue()
!>
!> Initialize the value object with a double 
!> precision number
!-----------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      SUBROUTINE initWithDoublePrecision(self,v) 
         IMPLICIT NONE
         CLASS(FTValue)  :: self
         DoublePrecision :: v
         INTEGER         :: dataLength
         
         CALL self % FTObject % init
         
         dataLength = SIZE(TRANSFER(v,self % valueStorage))
         ALLOCATE(self % valueStorage(dataLength))
         self % valueStorage = TRANSFER(v,self % valueStorage)
         
         self % valueType = FTVALUECLASS_DOUBLE
         
      END SUBROUTINE initWithDoublePrecision
!
!---------------------------------------------------
!> Public, generic name: initwithValue()
!>
!> Initialize the value object with a quad precision
!> number
!---------------------------------------------------
!
!
!////////////////////////////////////////////////////////////////////////
!
#ifdef _has_Quad

      SUBROUTINE initWithQuad(self,v) 
         IMPLICIT NONE
         CLASS(FTValue)                    :: self
         REAL(KIND=SELECTED_REAL_KIND(QUAD_DIGITS)) :: v
         INTEGER                           :: dataLength
         
         CALL self % FTObject % init()
         
         dataLength = SIZE(TRANSFER(v,self % valueStorage))
         ALLOCATE(self % valueStorage(dataLength))
         self % valueStorage = TRANSFER(v,self % valueStorage)
         
         self % valueType = FTVALUECLASS_QUAD
         
      END SUBROUTINE initWithQuad
#endif
!
!-----------------------------------------------
!> Public, generic name: initwithValue()
!>
!> Initialize the value object with an 
!> integer number
!-----------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      SUBROUTINE initWithInteger(self,v) 
         IMPLICIT NONE
         CLASS(FTValue) :: self
         INTEGER        :: v
         INTEGER        :: dataLength
         
         CALL self % FTObject % init
         
         dataLength = SIZE(TRANSFER(v,self % valueStorage))
         ALLOCATE(self % valueStorage(dataLength))
         self % valueStorage = TRANSFER(v,self % valueStorage)
         
         self % valueType = FTVALUECLASS_INTEGER
        
      END SUBROUTINE initWithInteger
!
!-----------------------------------------------
!> Public, generic name: initwithValue()
!>
!> Initialize the value object with a logical
!-----------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      SUBROUTINE initWithLogical(self,v) 
         IMPLICIT NONE
         CLASS(FTValue) :: self
         LOGICAL        :: v
         INTEGER        :: dataLength
         
         CALL self % FTObject % init
         
         dataLength = SIZE(TRANSFER(v,self % valueStorage))
         ALLOCATE(self % valueStorage(dataLength))
         self % valueStorage = TRANSFER(v,self % valueStorage)
         
         self % valueType = FTVALUECLASS_LOGICAL   
        
      END SUBROUTINE initWithLogical
!
!-----------------------------------------------
!> Public, generic name: initwithValue()
!>
!> Initialize the value object with a string
!-----------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      SUBROUTINE initWithString(self,v) 
         IMPLICIT NONE
         CLASS(FTValue)  :: self
         CHARACTER(LEN=*):: v
         INTEGER         :: dataLength
         
         CALL self % FTObject % init
         
         dataLength = LEN_TRIM(v)
         ALLOCATE(self % valueStorage(dataLength))
         self % valueStorage = TRANSFER(trim(v),self % valueStorage)
         
         self % valueType = FTVALUECLASS_STRING
         
      END SUBROUTINE initWithString
!@mark -
!
!------------------------------------------------
!> Public, generic name: destruct()
!>
!> Destructor for the class.
!------------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      SUBROUTINE destructValue(self) 
         IMPLICIT NONE
         CLASS(FTValue)  :: self
         
         CALL self % FTObject % destruct()
         
      END SUBROUTINE destructValue
!
!------------------------------------------------
!> Public, generic name: release(self)
!>
!> Call release(self) on an object to release control
!> of an object. If its reference count is zero, then 
!> it is deallocated.
!------------------------------------------------
!
!//////////////////////////////////////////////////////////////////////// 
! 
      SUBROUTINE releaseFTValue(self)  
         IMPLICIT NONE
         CLASS(FTValue) , POINTER :: self
         CLASS(FTObject), POINTER :: obj
         
         IF(.NOT. ASSOCIATED(self)) RETURN
         
         obj => self
         CALL releaseFTObject(self = obj)
         IF ( .NOT. ASSOCIATED(obj) )     THEN
            self => NULL() 
         END IF      
      END SUBROUTINE releaseFTValue
!@mark -
!
!---------------------------------------------------------------
!> Get the real value stored in the object, or convert the value
!> in the object to a real if it is of a different type.
!---------------------------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      REAL FUNCTION realValue(self)
         IMPLICIT NONE 
         CLASS(FTValue)   :: self
         INTEGER          :: iErr
         
         INTEGER                               :: i
         DOUBLE PRECISION                      :: d
         LOGICAL                               :: l
         CHARACTER(LEN= FTVALUE_STRING_LENGTH) :: s, tmpString
         
         SELECT CASE (self % valueType)
            CASE (FTVALUECLASS_INTEGER)
               i         = TRANSFER(self % valueStorage, i)
               realValue = REAL(i)
            CASE (FTVALUECLASS_DOUBLE)
               d         = TRANSFER(self % valueStorage, d)
               realValue = REAL(d)
            CASE (FTVALUECLASS_REAL)
                realValue = TRANSFER(self % valueStorage, realValue)
            CASE (FTVALUECLASS_STRING)
               tmpString = TRANSFER(self % valueStorage, tmpString)
               s         = tmpString(1:SIZE(self % valueStorage))
               READ(s,*,IOSTAT = iErr) realValue
               IF (iErr /= 0)     THEN
                  realValue = IEEE_VALUE(realValue,IEEE_QUIET_NAN)
               END IF
            CASE (FTVALUECLASS_LOGICAL)
               l = TRANSFER(self % valueStorage, l)
               IF ( l )     THEN
                  realValue = 1.0
               ELSE
                  realValue = 0.0
               END IF
         END SELECT
         
      END FUNCTION realValue   
!
!---------------------------------------------------------------------------
!> Get the double precision value stored in the object, or convert the value
!> in the object to a double precision if it is of a different type.
!---------------------------------------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      DOUBLE PRECISION FUNCTION doublePrecisionValue(self)
         IMPLICIT NONE 
         CLASS(FTValue)  :: self
         INTEGER         :: iErr
         
         REAL                                  :: r
         INTEGER                               :: i
         LOGICAL                               :: l
         CHARACTER(LEN= FTVALUE_STRING_LENGTH) :: s, tmpString
         
         SELECT CASE (self % valueType)
            CASE (FTVALUECLASS_INTEGER)
               i                    = TRANSFER(self % valueStorage, i)
               doublePrecisionValue = DBLE(i)
            CASE (FTVALUECLASS_REAL)
               r                    = TRANSFER(self % valueStorage, r)
               doublePrecisionValue = DBLE(r)
            CASE (FTVALUECLASS_DOUBLE)
                doublePrecisionValue = TRANSFER(self % valueStorage, doublePrecisionValue)
            CASE (FTVALUECLASS_STRING)
               tmpString = TRANSFER(self % valueStorage, tmpString)
               s         = tmpString(1:SIZE(self % valueStorage))
               READ(s,*,IOSTAT = iErr) doublePrecisionValue
               IF (iErr /= 0)     THEN
                  doublePrecisionValue = IEEE_VALUE(doublePrecisionValue,IEEE_QUIET_NAN)
               END IF
            CASE (FTVALUECLASS_LOGICAL)
               l = TRANSFER(self % valueStorage, l)
               IF ( l )     THEN
                  doublePrecisionValue = 1.0d0
               ELSE
                  doublePrecisionValue = 0.0d0
               END IF
         END SELECT
         
      END FUNCTION doublePrecisionValue   
!
!---------------------------------------------------------------------------
!> Get the double precision value stored in the object, or convert the value
!> in the object to a double precision if it is of a different type.
!---------------------------------------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
#ifdef _has_Quad
      DOUBLE PRECISION FUNCTION quadValue(self)
         IMPLICIT NONE 
         CLASS(FTValue)  :: self
         INTEGER         :: iErr
         
         REAL                                  :: r
         INTEGER                               :: i
         LOGICAL                               :: l
         CHARACTER(LEN= FTVALUE_STRING_LENGTH) :: s, tmpString
         
         SELECT CASE (self % valueType)
            CASE (FTVALUECLASS_INTEGER)
               i                    = TRANSFER(self % valueStorage, i)
               quadValue = REAL(A = i, KIND = SELECTED_REAL_KIND(QUAD_DIGITS))
            CASE (FTVALUECLASS_REAL)
               r                    = TRANSFER(self % valueStorage, r)
               quadValue = REAL(A = r, KIND = SELECTED_REAL_KIND(QUAD_DIGITS))
            CASE (FTVALUECLASS_DOUBLE)
                quadValue = TRANSFER(self % valueStorage, quadValue)
            CASE (FTVALUECLASS_STRING)
               tmpString = TRANSFER(self % valueStorage, tmpString)
               s         = tmpString(1:SIZE(self % valueStorage))
               READ(s,*,IOSTAT = iErr) quadValue
               IF (iErr /= 0)     THEN
                  quadValue = IEEE_VALUE(quadValue,IEEE_QUIET_NAN)
               END IF
            CASE (FTVALUECLASS_LOGICAL)
               l = TRANSFER(self % valueStorage, l)
               IF ( l )     THEN
                  quadValue = 1.0
               ELSE
                  quadValue = 0.0
               END IF
         END SELECT
         
      END FUNCTION quadValue 
#endif  
!
!---------------------------------------------------------------------------
!> Get the integer value stored in the object, or convert the value
!> in the object to an integer if it is of a different type.
!---------------------------------------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      INTEGER FUNCTION integerValue(self)
         IMPLICIT NONE 
         CLASS(FTValue)  :: self
         INTEGER         :: iErr
         
         REAL                                  :: r
         INTEGER                               :: i
         DOUBLE PRECISION                      :: d
         LOGICAL                               :: l
         CHARACTER(LEN= FTVALUE_STRING_LENGTH) :: s, tmpString
         
         SELECT CASE (self % valueType)
            CASE (FTVALUECLASS_INTEGER)
               integerValue = TRANSFER(self % valueStorage, i)
            CASE (FTVALUECLASS_DOUBLE)
               d            = TRANSFER(self % valueStorage, d)
               integerValue = INT(d)
            CASE (FTVALUECLASS_REAL)
               r            = TRANSFER(self % valueStorage, r)
               integerValue = INT(r)
            CASE (FTVALUECLASS_STRING)
               tmpString = TRANSFER(self % valueStorage, tmpString)
               s         = tmpString(1:SIZE(self % valueStorage))
               READ(s,*,IOSTAT = iErr) integerValue
               IF (iErr /= 0)     THEN
                  integerValue = HUGE(1)
               END IF
            CASE (FTVALUECLASS_LOGICAL)
               l = TRANSFER(self % valueStorage, l)
               IF ( l )     THEN
                  integerValue = 1
               ELSE
                  integerValue = 0
               END IF
         END SELECT
         
      END FUNCTION integerValue   
!
!---------------------------------------------------------------------------
!> Get the logical value stored in the object, or convert the value
!> in the object to a logical if it is of a different type.
!---------------------------------------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      LOGICAL FUNCTION logicalValue(self)
         IMPLICIT NONE 
         CLASS(FTValue)  :: self
         
         REAL                                  :: r
         INTEGER                               :: i
         DOUBLE PRECISION                      :: d
         LOGICAL                               :: l
         CHARACTER(LEN= FTVALUE_STRING_LENGTH) :: s, tmpString
         
         SELECT CASE (self % valueType)
            CASE (FTVALUECLASS_INTEGER)
               i = TRANSFER(self % valueStorage, i)
               IF ( i /= 0 )     THEN
                  logicalValue = .true.
               ELSE
                  logicalValue = .false.
               END IF
            CASE (FTVALUECLASS_DOUBLE)
               d = TRANSFER(self % valueStorage, d)
               IF ( d /= 0.0d0 )     THEN
                  logicalValue = .true.
               ELSE
                  logicalValue = .false.
               END IF
            CASE (FTVALUECLASS_REAL)
               r = TRANSFER(self % valueStorage, r)
               IF ( r /= 0.0 )     THEN
                  logicalValue = .true.
               ELSE
                  logicalValue = .false.
               END IF
            CASE (FTVALUECLASS_STRING)
               tmpString = TRANSFER(self % valueStorage, tmpString)
               s         = tmpString(1:SIZE(self % valueStorage))
               IF ( TRIM(s) == ".true." .OR. TRIM(s) == ".false." .OR. &
                    TRIM(s) == ".TRUE." .OR. TRIM(s) == ".FALSE.")     THEN
                  READ(s,*) logicalValue
               ELSE
                  logicalValue = .false.
               END IF
            CASE (FTVALUECLASS_LOGICAL)
               logicalValue = TRANSFER(self % valueStorage, l)
         END SELECT
         
      END FUNCTION logicalValue   
!
!---------------------------------------------------------------------------
!> Get the string value of length requestedLength stored in the object, or 
!> convert the value
!> in the object to a string of that length if it is of a different type.
!---------------------------------------------------------------------------
!
!////////////////////////////////////////////////////////////////////////
!
      FUNCTION stringValue(self,requestedLength) RESULT(s)
         IMPLICIT NONE 
         CLASS(FTValue)                 :: self
         INTEGER                        :: requestedLength
         CHARACTER(LEN=requestedLength) :: s
 
         CHARACTER(LEN= FTVALUE_STRING_LENGTH) :: tmpString
         
         REAL                                  :: r
         INTEGER                               :: i
         DOUBLE PRECISION                      :: d
         LOGICAL                               :: l

          SELECT CASE (self % valueType)
            CASE (FTVALUECLASS_INTEGER)
               i = TRANSFER(self % valueStorage, i)
               WRITE(tmpString,*) i
               s = TRIM(ADJUSTL(tmpString))
           CASE (FTVALUECLASS_DOUBLE)
               d = TRANSFER( self % valueStorage, d)
               WRITE(tmpString,*) d
               s = TRIM(ADJUSTL(tmpString))
            CASE (FTVALUECLASS_REAL)
               r = TRANSFER(self % valueStorage, r)
               WRITE(tmpString,*) r
               s = TRIM(ADJUSTL(tmpString))
            CASE (FTVALUECLASS_STRING)
               tmpString = TRANSFER(self % valueStorage, tmpString)
               s         = tmpString(1:SIZE(self % valueStorage))
            CASE (FTVALUECLASS_LOGICAL)
               l = TRANSFER(self % valueStorage, l)
               IF ( l )     THEN
                  s = "TRUE"
               ELSE
                  s = "FALSE"
               END IF
         END SELECT
         
      END FUNCTION stringValue   
!@mark -
!
!---------------------------------------------------------------------------
!> Returns the description of the value. In this case, it returns the 
!> stringValue() of the object. 
!---------------------------------------------------------------------------
!
!//////////////////////////////////////////////////////////////////////// 
! 
      FUNCTION FTValueDescription(self)  
         IMPLICIT NONE  
         CLASS(FTValue)      :: self
         CHARACTER(LEN=DESCRIPTION_CHARACTER_LENGTH) :: FTValueDescription
         
         FTValueDescription =  self % stringValue(DESCRIPTION_CHARACTER_LENGTH)
         
      END FUNCTION FTValueDescription
!
!---------------------------------------------------------------------------
!> Prints the description of the value to unit iUnit. In this case, it prints  
!> the stringValue() of the object. 
!---------------------------------------------------------------------------
!
!//////////////////////////////////////////////////////////////////////// 
! 
      SUBROUTINE printValueDescription(self,iUnit)  
         IMPLICIT NONE 
         CLASS(FTValue) :: self
         INTEGER        :: iUnit
         
         WRITE(iUnit,*) TRIM(self % description())

      END SUBROUTINE printValueDescription    
!
!---------------------------------------------------------------------------
!> Generic Name: cast
!> 
!> Cast a pointer to the base class to an FTValue pointer 
!---------------------------------------------------------------------------
!
!//////////////////////////////////////////////////////////////////////// 
! 
      SUBROUTINE castToValue(obj,cast) 
!
!     -----------------------------------------------------
!     Cast the base class FTObject to the FTValue class
!     -----------------------------------------------------
!
         IMPLICIT NONE  
         CLASS(FTObject), POINTER :: obj
         CLASS(FTValue) , POINTER :: cast
         
         cast => NULL()
         SELECT TYPE (e => obj)
            TYPE is (FTValue)
               cast => e
            CLASS DEFAULT
               
         END SELECT
         
      END SUBROUTINE castToValue
!
!//////////////////////////////////////////////////////////////////////// 
! 
      FUNCTION valueFromObject(obj) RESULT(cast)
!
!     -----------------------------------------------------
!     Cast the base class FTObject to the FTValue class
!     -----------------------------------------------------
!
         IMPLICIT NONE  
         CLASS(FTObject), POINTER :: obj
         CLASS(FTValue) , POINTER :: cast
         
         cast => NULL()
         SELECT TYPE (e => obj)
            TYPE is (FTValue)
               cast => e
            CLASS DEFAULT
               
         END SELECT
         
      END FUNCTION valueFromObject
!
!//////////////////////////////////////////////////////////////////////// 
! 
!      -----------------------------------------------------------------
!> Class name returns a string with the name of the type of the object
!>
!>  ### Usage:
!>
!>        PRINT *,  obj % className()
!>        if( obj % className = "FTValue")
!>
      FUNCTION valueClassName(self)  RESULT(s)
         IMPLICIT NONE  
         CLASS(FTValue)                             :: self
         CHARACTER(LEN=CLASS_NAME_CHARACTER_LENGTH) :: s
         
         s = "FTValue"
 
      END FUNCTION valueClassName

      END MODULE FTValueClass