parse_integer_wide Subroutine

private pure subroutine parse_integer_wide(str, value, err)

Core integer parser, accumulating in int64.

The accumulation runs in the negative half of the integer range so that the most negative representable value can be parsed without ever evaluating an expression that overflows.

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: str
integer(kind=int64), intent(out) :: value
type(error_t), intent(out) :: err

Calls

proc~~parse_integer_wide~~CallsGraph proc~parse_integer_wide parse_integer_wide interface~strip strip proc~parse_integer_wide->interface~strip proc~error_set error_t%error_set proc~parse_integer_wide->proc~error_set proc~strip_char strip_char interface~strip->proc~strip_char proc~strip_string strip_string interface~strip->proc~strip_string proc~strip_string->interface~strip

Called by

proc~~parse_integer_wide~~CalledByGraph proc~parse_integer_wide parse_integer_wide proc~parse_int_int32_char parse_int_int32_char proc~parse_int_int32_char->proc~parse_integer_wide proc~parse_int_int64_char parse_int_int64_char proc~parse_int_int64_char->proc~parse_integer_wide proc~parse_int_int64_string parse_int_int64_string proc~parse_int_int64_string->proc~parse_integer_wide interface~parse_int parse_int interface~parse_int->proc~parse_int_int32_char interface~parse_int->proc~parse_int_int64_char interface~parse_int->proc~parse_int_int64_string proc~parse_int_int32_string parse_int_int32_string interface~parse_int->proc~parse_int_int32_string proc~parse_int_int32_string->proc~parse_int_int32_char proc~cli_get_int32 cli_t%cli_get_int32 proc~cli_get_int32->interface~parse_int proc~cli_get_int64 cli_t%cli_get_int64 proc~cli_get_int64->interface~parse_int

Variables

Type Visibility Attributes Name Initial
integer(kind=int64), private :: accumulator
integer(kind=int64), private :: digit
integer(kind=default_int), private :: i_char
integer(kind=int64), private :: limit
integer(kind=int64), private :: mult_limit
logical, private :: negative
integer(kind=default_int), private :: pos
character(len=:), private, allocatable :: text

Source Code

   pure subroutine parse_integer_wide(str, value, err)
      !! Core integer parser, accumulating in `int64`.
      !!
      !! The accumulation runs in the negative half of the integer range so
      !! that the most negative representable value can be parsed without ever
      !! evaluating an expression that overflows.
      character(len=*), intent(in) :: str
      integer(int64), intent(out) :: value
      type(error_t), intent(out) :: err

      character(len=:), allocatable :: text
      integer(default_int) :: pos, i_char
      integer(int64) :: accumulator, limit, mult_limit, digit
      logical :: negative

      value = 0_int64
      text = strip(str)
      if (len(text) == 0) then
         call err%set(ERROR_PARSE, "cannot parse an empty string as an integer")
         return
      end if

      pos = 1
      negative = (text(1:1) == "-")
      if (index(SIGNS, text(1:1)) > 0) pos = 2

      if (pos > len(text)) then
         call err%set(ERROR_PARSE, "no digits after the sign in '"//text//"'")
         return
      end if

      if (negative) then
         limit = -huge(accumulator) - 1_int64
      else
         limit = -huge(accumulator)
      end if
      mult_limit = limit/10_int64
      accumulator = 0_int64

      do i_char = pos, len(text)
         digit = int(index(digits, text(i_char:i_char)), int64) - 1_int64
         if (digit < 0_int64) then
            call err%set(ERROR_PARSE, "invalid character '"//text(i_char:i_char)// &
                         "' while parsing the integer '"//text//"'")
            return
         end if
         if (accumulator < mult_limit) then
            call err%set(ERROR_PARSE, "integer overflow while parsing '"//text//"'")
            return
         end if
         accumulator = accumulator*10_int64
         if (accumulator < limit + digit) then
            call err%set(ERROR_PARSE, "integer overflow while parsing '"//text//"'")
            return
         end if
         accumulator = accumulator - digit
      end do

      if (negative) then
         value = accumulator
      else
         value = -accumulator
      end if

   end subroutine parse_integer_wide