Skip to content

Commit ee33055

Browse files
Add support for negative integers in to_num_base inside stdlib_str2num (#1127)
* add: negative integer support for to_num and integer test cases * add: more test case * add: length check guard before sign check * modify: do while loop * clean implementation * add early exit in case of empty strings * move initialization of output value after comment line
1 parent 48c3a19 commit ee33055

2 files changed

Lines changed: 82 additions & 4 deletions

File tree

src/strings/stdlib_str2num.fypp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,25 @@ module stdlib_str2num
128128
integer(int8), intent(out) :: p !! position within the number
129129
integer(int8), intent(out) :: stat !! status upon succes or failure to read
130130
! -- Internal Variables
131-
integer(int8) :: val
131+
integer(int8) :: val
132+
integer(int8) :: sign
132133
!----------------------------------------------
133134
stat = 23 !! initialize error status with any number > 0
134135
!----------------------------------------------
135136
! Find first non white space
136137
p = shift_to_nonwhitespace(s)
137138
!----------------------------------------------
139+
! Verify leading negative
140+
sign = 1
141+
if(p<=len(s)) then
142+
if(iachar(s(p:p)) == minus_sign+digit_0 ) then
143+
sign = -1
144+
p = p + 1
145+
end if
146+
else
147+
return
148+
end if
149+
!----------------------------------------------
138150
v = 0
139151
do while( p<=len(s) )
140152
val = iachar(s(p:p))-digit_0
@@ -145,9 +157,13 @@ module stdlib_str2num
145157
exit
146158
end if
147159
end do
148-
stat = 0
160+
if(v >= 0) then
161+
v = sign * v
162+
stat = 0
163+
else
164+
stat = -1 !! Indicates integer overflow
165+
end if
149166
end subroutine
150-
151167
#:endfor
152168

153169
elemental subroutine to_sp_base(s,v,p,stat)

test/string/test_string_to_number.fypp

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#: include "common.fypp"
22
module test_string_to_number
3-
use stdlib_kinds, only: sp, dp, xdp, qp
3+
use stdlib_kinds, only: sp, dp, xdp, qp, int8, int16, int32, int64
44
use stdlib_str2num, only: to_num
55
use testdrive, only : new_unittest, unittest_type, error_type, check
66
implicit none
@@ -21,6 +21,9 @@ contains
2121
#:if WITH_XDP
2222
, new_unittest("to_xdp", test_to_xdp) &
2323
#:endif
24+
#:for k1, t1 in INT_KINDS_TYPES
25+
, new_unittest("to_${k1}$", test_to_${k1}$) &
26+
#:endfor
2427
]
2528
end subroutine collect_string_to_number
2629

@@ -132,6 +135,65 @@ contains
132135
end subroutine
133136

134137
#:endfor
138+
139+
#:for k1, t1 in INT_KINDS_TYPES
140+
subroutine test_to_${k1}$(error)
141+
type(error_type), allocatable, intent(out) :: error
142+
integer, parameter :: wp = ${k1}$
143+
character(len=64) :: s
144+
145+
call check(error, ucheck("0"))
146+
if (allocated(error)) return
147+
148+
call check(error, ucheck("-0"))
149+
if (allocated(error)) return
150+
151+
call check(error, ucheck("123"))
152+
if (allocated(error)) return
153+
154+
call check(error, ucheck("-123"))
155+
if (allocated(error)) return
156+
157+
call check(error, ucheck(" 99"))
158+
if (allocated(error)) return
159+
160+
call check(error, ucheck("0005"))
161+
if (allocated(error)) return
162+
163+
call check(error, ucheck("-0008"))
164+
if (allocated(error)) return
165+
166+
call check(error, ucheck("78 "))
167+
if (allocated(error)) return
168+
169+
call check(error, ucheck(" -42 "))
170+
if (allocated(error)) return
171+
172+
write(s,'(i0)') huge(0_wp)
173+
call check(error, ucheck(trim(s)))
174+
if (allocated(error)) return
175+
176+
write(s,'(i0)') -huge(0_wp)-1
177+
call check(error, ucheck(trim(s)))
178+
if (allocated(error)) return
179+
180+
contains
181+
logical function ucheck(s)
182+
character(*), intent(in) :: s
183+
integer(${k1}$) :: formatted_read_out
184+
integer(${k1}$) :: to_num_out
185+
186+
ucheck = .true.
187+
read(s,*) formatted_read_out
188+
to_num_out = to_num(s, to_num_out)
189+
if(to_num_out /= formatted_read_out) then
190+
write(*,"('formatted read : ', i0)") formatted_read_out
191+
write(*,"('to_num : ', i0)") to_num_out
192+
ucheck = .false.
193+
end if
194+
end function
195+
end subroutine
196+
#:endfor
135197

136198
end module test_string_to_number
137199

0 commit comments

Comments
 (0)