Skip to content

Commit 4172ec5

Browse files
Merge pull request #407 from jacobwilliams/develop
Develop
2 parents 768f31a + 7154337 commit 4172ec5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+869
-400
lines changed

src/json_file_module.F90

+215-150
Large diffs are not rendered by default.

src/json_initialize_arguments.inc

+24-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
! The argument list for the various `initialize` subroutines.
2+
!
3+
! See also: json_initialize_dummy_arguments.inc
24

35
logical(LK),intent(in),optional :: verbose
46
!! mainly useful for debugging (default is false)
@@ -13,7 +15,7 @@ integer(IK),intent(in),optional :: spaces_per_tab
1315
logical(LK),intent(in),optional :: strict_type_checking
1416
!! if true, no integer, double, or logical type
1517
!! conversions are done for the `get` routines
16-
!! (default is false)
18+
!! (default is false).
1719
logical(LK),intent(in),optional :: trailing_spaces_significant
1820
!! for name and path comparisons, is trailing
1921
!! space to be considered significant.
@@ -77,4 +79,24 @@ logical(LK),intent(in),optional :: escape_solidus
7779
logical(LK),intent(in),optional :: stop_on_error
7880
!! If an exception is raised, then immediately quit.
7981
!! (Default is False).
80-
82+
integer(IK),intent(in),optional :: null_to_real_mode
83+
!! if `strict_type_checking=false`:
84+
!!
85+
!! * 1 : an exception will be raised if
86+
!! try to retrieve a `null` as a real.
87+
!! * 2 : a `null` retrieved as a real
88+
!! will return a NaN. [default]
89+
!! * 3 : a `null` retrieved as a real
90+
!! will return 0.0.
91+
integer(IK),intent(in),optional :: non_normal_mode
92+
!! How to serialize NaN, Infinity, and
93+
!! -Infinity real values:
94+
!!
95+
!! * 1 : as strings (e.g., "NaN",
96+
!! "Infinity", "-Infinity") [default]
97+
!! * 2 : as JSON `null` values
98+
logical(LK),intent(in),optional :: use_quiet_nan
99+
!! if true [default], `null_to_real_mode=2`
100+
!! and [[string_to_real]] will use
101+
!! `ieee_quiet_nan` for NaN values. If false,
102+
!! `ieee_signaling_nan` will be used.
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
! The dummy argument list for the various `initialize` subroutines.
2+
!
3+
! See also: json_initialize_argument.inc
4+
5+
verbose,&
6+
compact_reals,&
7+
print_signs,&
8+
real_format,&
9+
spaces_per_tab,&
10+
strict_type_checking,&
11+
trailing_spaces_significant,&
12+
case_sensitive_keys,&
13+
no_whitespace,&
14+
unescape_strings,&
15+
comment_char,&
16+
path_mode,&
17+
path_separator,&
18+
compress_vectors,&
19+
allow_duplicate_keys,&
20+
escape_solidus,&
21+
stop_on_error,&
22+
null_to_real_mode,&
23+
non_normal_mode,&
24+
use_quiet_nan &

src/json_parameters.F90

+3-4
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,15 @@ module json_parameters
5656
character(kind=CK,len=*),parameter :: this = CK_'@' !! 'this' for [[json_get_by_path_default]]
5757
character(kind=CK,len=*),parameter :: dot = CK_'.' !! path separator for [[json_get_by_path_default]]
5858
character(kind=CK,len=*),parameter :: tilde = CK_'~' !! RFC 6901 escape character
59-
character(kind=CK,len=*),parameter :: percent = CK_'%' !! Fortran path separator
6059
character(kind=CK,len=*),parameter :: single_quote = CK_"'" !! for JSONPath bracket-notation
60+
character(kind=CK,len=*),parameter :: slash = CK_'/' !! JSON special character
61+
character(kind=CK,len=*),parameter :: backslash = CK_'\' !! JSON special character
62+
character(kind=CK,len=*),parameter :: quotation_mark = CK_'"' !! JSON special character
6163
character(kind=CK,len=*),parameter :: bspace = achar(8, kind=CK) !! JSON special character
6264
character(kind=CK,len=*),parameter :: horizontal_tab = achar(9, kind=CK) !! JSON special character
6365
character(kind=CK,len=*),parameter :: newline = achar(10, kind=CK) !! JSON special character
6466
character(kind=CK,len=*),parameter :: formfeed = achar(12, kind=CK) !! JSON special character
6567
character(kind=CK,len=*),parameter :: carriage_return = achar(13, kind=CK) !! JSON special character
66-
character(kind=CK,len=*),parameter :: quotation_mark = achar(34, kind=CK) !! JSON special character
67-
character(kind=CK,len=*),parameter :: slash = achar(47, kind=CK) !! JSON special character
68-
character(kind=CK,len=*),parameter :: backslash = achar(92, kind=CK) !! JSON special character
6968

7069
!> default real number format statement (for writing real values to strings and files).
7170
! Note that this can be overridden by calling [[json_initialize]].

src/json_string_utilities.F90

+62-18
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
module json_string_utilities
1313

14+
use,intrinsic :: ieee_arithmetic
1415
use json_kinds
1516
use json_parameters
1617

@@ -148,33 +149,61 @@ end subroutine string_to_integer
148149
! Convert a real value to a string.
149150
!
150151
!### Modified
151-
! * Izaak Beekman : 02/24/2015 : added the compact option.
152+
! * Izaak Beekman : 02/24/2015 : added the compact option.
152153
! * Jacob Williams : 10/27/2015 : added the star option.
154+
! * Jacob Williams : 07/07/2019 : added null and ieee options.
153155

154-
subroutine real_to_string(rval,real_fmt,compact_real,str)
156+
subroutine real_to_string(rval,real_fmt,compact_real,non_normals_to_null,str)
155157

156158
implicit none
157159

158160
real(RK),intent(in) :: rval !! real value.
159161
character(kind=CDK,len=*),intent(in) :: real_fmt !! format for real numbers
160162
logical(LK),intent(in) :: compact_real !! compact the string so that it is
161163
!! displayed with fewer characters
164+
logical(LK),intent(in) :: non_normals_to_null !! If True, NaN, Infinity, or -Infinity are returned as `null`.
165+
!! If False, the string value will be returned in quotes
166+
!! (e.g., "NaN", "Infinity", or "-Infinity" )
162167
character(kind=CK,len=*),intent(out) :: str !! `rval` converted to a string.
163168

164-
integer(IK) :: istat
169+
integer(IK) :: istat !! write `iostat` flag
165170

166-
if (real_fmt==star) then
167-
write(str,fmt=*,iostat=istat) rval
168-
else
169-
write(str,fmt=real_fmt,iostat=istat) rval
170-
end if
171+
if (ieee_is_finite(rval) .and. .not. ieee_is_nan(rval)) then
172+
173+
! normal real numbers
174+
175+
if (real_fmt==star) then
176+
write(str,fmt=*,iostat=istat) rval
177+
else
178+
write(str,fmt=real_fmt,iostat=istat) rval
179+
end if
180+
181+
if (istat==0) then
182+
!in this case, the default string will be compacted,
183+
! so that the same value is displayed with fewer characters.
184+
if (compact_real) call compact_real_string(str)
185+
else
186+
str = repeat(star,len(str)) ! error
187+
end if
171188

172-
if (istat==0) then
173-
!in this case, the default string will be compacted,
174-
! so that the same value is displayed with fewer characters.
175-
if (compact_real) call compact_real_string(str)
176189
else
177-
str = repeat(star,len(str))
190+
! special cases for NaN, Infinity, and -Infinity
191+
192+
if (non_normals_to_null) then
193+
! return it as a JSON null value
194+
str = null_str
195+
else
196+
! Let the compiler do the real to string conversion
197+
! like before, but put the result in quotes so it
198+
! gets printed as a string
199+
write(str,fmt=*,iostat=istat) rval
200+
if (istat==0) then
201+
str = quotation_mark//trim(adjustl(str))//quotation_mark
202+
else
203+
str = repeat(star,len(str)) ! error
204+
end if
205+
end if
206+
178207
end if
179208

180209
end subroutine real_to_string
@@ -192,19 +221,34 @@ end subroutine real_to_string
192221
! (e.g., when `str='1E-5'`).
193222
! * Jacob Williams : 2/6/2017 : moved core logic to this routine.
194223

195-
subroutine string_to_real(str,rval,status_ok)
224+
subroutine string_to_real(str,use_quiet_nan,rval,status_ok)
196225

197226
implicit none
198227

199-
character(kind=CK,len=*),intent(in) :: str !! the string to convert to a real
200-
real(RK),intent(out) :: rval !! `str` converted to a real value
201-
logical(LK),intent(out) :: status_ok !! true if there were no errors
228+
character(kind=CK,len=*),intent(in) :: str !! the string to convert to a real
229+
logical(LK),intent(in) :: use_quiet_nan !! if true, return NaN's as `ieee_quiet_nan`.
230+
!! otherwise, use `ieee_signaling_nan`.
231+
real(RK),intent(out) :: rval !! `str` converted to a real value
232+
logical(LK),intent(out) :: status_ok !! true if there were no errors
202233

203234
integer(IK) :: ierr !! read iostat error code
204235

205236
read(str,fmt=*,iostat=ierr) rval
206237
status_ok = (ierr==0)
207-
if (.not. status_ok) rval = 0.0_RK
238+
if (.not. status_ok) then
239+
rval = 0.0_RK
240+
else
241+
if (ieee_support_nan(rval)) then
242+
if (ieee_is_nan(rval)) then
243+
! make sure to return the correct NaN
244+
if (use_quiet_nan) then
245+
rval = ieee_value(rval,ieee_quiet_nan)
246+
else
247+
rval = ieee_value(rval,ieee_signaling_nan)
248+
end if
249+
end if
250+
end if
251+
end if
208252

209253
end subroutine string_to_real
210254
!*****************************************************************************************

0 commit comments

Comments
 (0)