Skip to content

Commit 72c8903

Browse files
committed
experiments with optional C routines for string to real
1 parent 3b54a73 commit 72c8903

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

src/json_string_utilities.F90

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ module json_string_utilities
6464
public :: real_to_string
6565
public :: string_to_integer
6666
public :: string_to_real
67+
#ifdef C_STR2REAL
68+
public :: string_to_real_c
69+
#endif
6770
public :: valid_json_hex
6871
public :: to_unicode
6972
public :: escape_string
@@ -234,6 +237,7 @@ subroutine string_to_real(str,use_quiet_nan,rval,status_ok)
234237
integer(IK) :: ierr !! read iostat error code
235238

236239
read(str,fmt=*,iostat=ierr) rval
240+
237241
status_ok = (ierr==0)
238242
if (.not. status_ok) then
239243
rval = 0.0_RK
@@ -253,6 +257,135 @@ subroutine string_to_real(str,use_quiet_nan,rval,status_ok)
253257
end subroutine string_to_real
254258
!*****************************************************************************************
255259

260+
#ifdef C_STR2REAL
261+
!*****************************************************************************************
262+
!> author: Jacob Williams
263+
! date: 11/05/2021
264+
!
265+
! Convert a string into a `real(RK)`.
266+
! This version uses `strtof`, `strtod`, or `strtold` from C.
267+
! It will fall back to using `read(fmt=*)` if any errors.
268+
!
269+
!# History
270+
! * Jacob Williams : 11/05/2021 : created by modification of [[string_to_real]].
271+
272+
subroutine string_to_real_c(str,use_quiet_nan,rval,status_ok)
273+
274+
use iso_c_binding, only: c_double, c_float, c_long_double, &
275+
c_char, c_ptr, c_null_ptr, c_long, &
276+
c_null_char
277+
278+
implicit none
279+
280+
character(kind=CK,len=*),intent(in) :: str !! the string to convert to a real
281+
logical(LK),intent(in) :: use_quiet_nan !! if true, return NaN's as `ieee_quiet_nan`.
282+
!! otherwise, use `ieee_signaling_nan`.
283+
real(RK),intent(out) :: rval !! `str` converted to a real value
284+
logical(LK),intent(out) :: status_ok !! true if there were no errors
285+
286+
integer(IK) :: ierr !! read iostat error code
287+
type(c_ptr) :: endptr !! pointer arg to `strtof`, etc.
288+
289+
interface
290+
function strtof( str, endptr ) result(d) bind(C, name="strtof" )
291+
!! <stdlib.h> :: float strtof(const char *str, char **endptr)
292+
import
293+
character(kind=c_char,len=1),dimension(*),intent(in) :: str
294+
type(c_ptr), intent(inout) :: endptr
295+
real(c_float) :: d
296+
end function strtof
297+
function strtod( str, endptr ) result(d) bind(C, name="strtod" )
298+
!! <stdlib.h> :: double strtod(const char *str, char **endptr)
299+
import
300+
character(kind=c_char,len=1),dimension(*),intent(in) :: str
301+
type(c_ptr), intent(inout) :: endptr
302+
real(c_double) :: d
303+
end function strtod
304+
function strtold( str, endptr ) result(d) bind(C, name="strtold" )
305+
!! <stdlib.h> :: long double strtold(const char *str, char **endptr)
306+
import
307+
character(kind=c_char,len=1),dimension(*),intent(in) :: str
308+
type(c_ptr), intent(inout) :: endptr
309+
real(c_long_double) :: d
310+
end function strtold
311+
end interface
312+
313+
#ifdef USE_UCS4
314+
! if using unicode, don't try to call the C routines
315+
! [not sure they will work? need to test this... what if c_char /= CK?]
316+
call string_to_real(str,use_quiet_nan,rval,status_ok)
317+
return
318+
#endif
319+
320+
endptr = c_null_ptr ! indicates it is not used
321+
322+
#ifdef REAL32
323+
324+
! single precision
325+
326+
if (RK == c_float) then
327+
rval = strtof( str//C_NULL_CHAR, endptr )
328+
if (rval==0.0_RK) then
329+
read(str,fmt=*,iostat=ierr) rval ! not efficient - might really be 0.0
330+
else
331+
ierr = 0
332+
end if
333+
else
334+
read(str,fmt=*,iostat=ierr) rval
335+
end if
336+
337+
#elif REAL128
338+
339+
! quad precision
340+
341+
if (RK == c_long_double) then
342+
rval = strtold( str//C_NULL_CHAR, endptr )
343+
if (rval==0.0_RK) then
344+
read(str,fmt=*,iostat=ierr) rval ! not efficient - might really be 0.0
345+
else
346+
ierr = 0
347+
end if
348+
else
349+
read(str,fmt=*,iostat=ierr) rval
350+
end if
351+
352+
#else
353+
354+
! double precision
355+
356+
if (RK == c_double) then
357+
rval = strtod( str//C_NULL_CHAR, endptr )
358+
if (rval==0.0_RK) then
359+
read(str,fmt=*,iostat=ierr) rval ! not efficient - might really be 0.0
360+
else
361+
ierr = 0
362+
end if
363+
else
364+
read(str,fmt=*,iostat=ierr) rval
365+
end if
366+
367+
#endif
368+
369+
status_ok = (ierr==0)
370+
if (.not. status_ok) then
371+
rval = 0.0_RK
372+
else
373+
if (ieee_support_nan(rval)) then
374+
if (ieee_is_nan(rval)) then
375+
! make sure to return the correct NaN
376+
if (use_quiet_nan) then
377+
rval = ieee_value(rval,ieee_quiet_nan)
378+
else
379+
rval = ieee_value(rval,ieee_signaling_nan)
380+
end if
381+
end if
382+
end if
383+
end if
384+
385+
end subroutine string_to_real_c
386+
!*****************************************************************************************
387+
#endif
388+
256389
!*****************************************************************************************
257390
!> author: Izaak Beekman
258391
! date: 02/24/2015

src/json_value_module.F90

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8110,7 +8110,11 @@ function string_to_dble(json,str) result(rval)
81108110

81118111
logical(LK) :: status_ok !! error flag for [[string_to_real]]
81128112

8113+
#ifdef C_STR2REAL
8114+
call string_to_real_c(str,json%use_quiet_nan,rval,status_ok)
8115+
#else
81138116
call string_to_real(str,json%use_quiet_nan,rval,status_ok)
8117+
#endif
81148118

81158119
if (.not. status_ok) then !if there was an error
81168120
rval = 0.0_RK
@@ -8391,7 +8395,11 @@ subroutine json_get_real(json, me, value)
83918395
value = 0.0_RK
83928396
end if
83938397
case (json_string)
8398+
#ifdef C_STR2REAL
8399+
call string_to_real_c(me%str_value,json%use_quiet_nan,value,status_ok)
8400+
#else
83948401
call string_to_real(me%str_value,json%use_quiet_nan,value,status_ok)
8402+
#endif
83958403
if (.not. status_ok) then
83968404
value = 0.0_RK
83978405
if (allocated(me%name)) then

0 commit comments

Comments
 (0)