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.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | str | |||
| integer(kind=int64), | intent(out) | :: | value | |||
| type(error_t), | intent(out) | :: | err |
| 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 |
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