Skip to content

Commit fc2e18e

Browse files
Merge pull request #366 from jacobwilliams/speed
Speed
2 parents 765daf2 + ac6642e commit fc2e18e

File tree

4 files changed

+76
-27
lines changed

4 files changed

+76
-27
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: python
22

33
python:
4-
- 3.5
4+
- 3.6
55

66
sudo: false
77

src/json_parameters.F90

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,20 @@ module json_parameters
113113
!! 6 = sign + leading 0 + decimal + 'E' + exponent sign + 1 extra
114114
character(kind=CDK,len=*),parameter :: int_fmt = '(ss,I0)' !! minimum width format for integers
115115

116-
integer(IK),parameter :: max_integer_str_len = 256 !! maximum string length of an integer.
117-
!! This is totally arbitrary (any way
118-
!! to get the compiler to tell us this?)
116+
integer(IK),parameter :: max_integer_str_len = 256_IK !! maximum string length of an integer.
117+
!! This is totally arbitrary (any way
118+
!! to get the compiler to tell us this?)
119119

120-
integer(IK),parameter :: chunk_size = 100_IK !! for allocatable strings: allocate chunks of this size
120+
integer(IK),parameter :: chunk_size = 256_IK !! for allocatable strings: allocate chunks of this size
121121
integer(IK),parameter :: unit2str = -1_IK !! unit number to cause stuff to be
122122
!! output to strings rather than files.
123123
!! See 9.5.6.12 in the F2003/08 standard
124+
character(kind=CK,len=*),parameter :: blank_chunk = repeat(space, chunk_size) !! a blank string
124125

125126
integer(IK),parameter :: seq_chunk_size = 256_IK !! chunk size for reading sequential files
126127

128+
integer(IK),parameter :: stream_chunk_size = 256_IK !! chunk size for reading stream files
129+
127130
integer(IK),parameter :: pushed_char_size = 10_IK !! size for `pushed_char`
128131
!! array in [[json_core(type)]]
129132

src/json_string_utilities.F90

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,17 @@ subroutine string_to_integer(str,ival,status_ok)
125125

126126
! Compute how many digits we need to read
127127
ndigits = 2*len_trim(str)
128-
ndigits_digits = floor(log10(real(ndigits)))+1
129-
allocate(character(kind=CDK,len=ndigits_digits) :: digits)
130-
write(digits,'(I0)') ndigits !gfortran will have a runtime error with * edit descriptor here
131-
! gfortran bug: '*' edit descriptor for ISO_10646 strings does bad stuff.
132-
read(str,'(I'//trim(digits)//')',iostat=ierr) ival !string to integer
133-
134-
! error check:
135-
status_ok = (ierr==0)
128+
if (ndigits/=0) then
129+
ndigits_digits = floor(log10(real(ndigits)))+1
130+
allocate(character(kind=CDK,len=ndigits_digits) :: digits)
131+
write(digits,'(I0)') ndigits !gfortran will have a runtime error with * edit descriptor here
132+
! gfortran bug: '*' edit descriptor for ISO_10646 strings does bad stuff.
133+
read(str,'(I'//trim(digits)//')',iostat=ierr) ival !string to integer
134+
! error check:
135+
status_ok = (ierr==0)
136+
else
137+
status_ok = .false.
138+
end if
136139
if (.not. status_ok) ival = 0_IK
137140

138141
end subroutine string_to_integer
@@ -342,7 +345,7 @@ subroutine escape_string(str_in, str_out, escape_solidus)
342345
c = str_in(i:i) !get next character in the input string
343346

344347
!if the string is not big enough, then add another chunk:
345-
if (ipos+3>len(str_out)) str_out = str_out // repeat(space, chunk_size)
348+
if (ipos+3>len(str_out)) str_out = str_out // blank_chunk
346349

347350
select case(c)
348351
case(backslash)

src/json_value_module.F90

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,12 @@ module json_value_module
256256
!! (both escaped and unescaped versions are still
257257
!! valid in all cases).
258258

259+
integer :: ichunk = 0 !! index in `chunk` for [[pop_char]]
260+
!! when `use_unformatted_stream=True`
261+
integer :: filesize = 0 !! the file size when when `use_unformatted_stream=True`
262+
character(kind=CK,len=:),allocatable :: chunk !! a chunk read from a stream file
263+
!! when `use_unformatted_stream=True`
264+
259265
contains
260266

261267
private
@@ -918,6 +924,11 @@ subroutine json_initialize(me,verbose,compact_reals,&
918924
me%char_count = 0
919925
me%line_count = 1
920926
me%ipos = 1
927+
if (use_unformatted_stream) then
928+
me%filesize = 0
929+
me%ichunk = 0
930+
me%chunk = repeat(' ', stream_chunk_size) ! default chunk size
931+
end if
921932

922933
#ifdef USE_UCS4
923934
! reopen stdout and stderr with utf-8 encoding
@@ -8755,6 +8766,11 @@ subroutine json_parse_file(json, file, p, unit)
87558766

87568767
if (istat==0) then
87578768

8769+
if (use_unformatted_stream) then
8770+
! save the file save to be read:
8771+
inquire(unit=iunit, size=json%filesize, iostat=istat)
8772+
end if
8773+
87588774
! create the value and associate the pointer
87598775
call json_value_create(p)
87608776

@@ -9110,6 +9126,7 @@ recursive subroutine parse_value(json, unit, str, value)
91109126
!the routine is being called incorrectly.
91119127
if (.not. associated(value)) then
91129128
call json%throw_exception('Error in parse_value: value pointer not associated.')
9129+
return
91139130
end if
91149131

91159132
! pop the next non whitespace character off the file
@@ -9957,7 +9974,7 @@ subroutine parse_string(json, unit, str, string)
99579974
character(kind=CK,len=:),allocatable :: error_message !! for string unescaping
99589975

99599976
!at least return a blank string if there is a problem:
9960-
string = repeat(space, chunk_size)
9977+
string = blank_chunk
99619978

99629979
if (.not. json%exception_thrown) then
99639980

@@ -9982,7 +9999,7 @@ subroutine parse_string(json, unit, str, string)
99829999
else
998310000

998410001
!if the string is not big enough, then add another chunk:
9985-
if (ip>len(string)) string = string // repeat(space, chunk_size)
10002+
if (ip>len(string)) string = string // blank_chunk
998610003

998710004
!append to string:
998810005
string(ip:ip) = c
@@ -10098,7 +10115,7 @@ subroutine parse_number(json, unit, str, value)
1009810115

1009910116
if (.not. json%exception_thrown) then
1010010117

10101-
tmp = repeat(space, chunk_size)
10118+
tmp = blank_chunk
1010210119
ip = 1
1010310120
first = .true.
1010410121
is_integer = .true. !assume it may be an integer, unless otherwise determined
@@ -10122,7 +10139,7 @@ subroutine parse_number(json, unit, str, value)
1012210139

1012310140
!add it to the string:
1012410141
!tmp = tmp // c !...original
10125-
if (ip>len(tmp)) tmp = tmp // repeat(space, chunk_size)
10142+
if (ip>len(tmp)) tmp = tmp // blank_chunk
1012610143
tmp(ip:ip) = c
1012710144
ip = ip + 1
1012810145

@@ -10132,15 +10149,15 @@ subroutine parse_number(json, unit, str, value)
1013210149

1013310150
!add it to the string:
1013410151
!tmp = tmp // c !...original
10135-
if (ip>len(tmp)) tmp = tmp // repeat(space, chunk_size)
10152+
if (ip>len(tmp)) tmp = tmp // blank_chunk
1013610153
tmp(ip:ip) = c
1013710154
ip = ip + 1
1013810155

1013910156
case(CK_'0':CK_'9') !valid characters for numbers
1014010157

1014110158
!add it to the string:
1014210159
!tmp = tmp // c !...original
10143-
if (ip>len(tmp)) tmp = tmp // repeat(space, chunk_size)
10160+
if (ip>len(tmp)) tmp = tmp // blank_chunk
1014410161
tmp(ip:ip) = c
1014510162
ip = ip + 1
1014610163

@@ -10185,7 +10202,7 @@ end subroutine parse_number
1018510202
!@note This routine ignores non-printing ASCII characters
1018610203
! (`iachar<=31`) that are in strings.
1018710204

10188-
recursive subroutine pop_char(json,unit,str,skip_ws,skip_comments,eof,popped)
10205+
subroutine pop_char(json,unit,str,skip_ws,skip_comments,eof,popped)
1018910206

1019010207
implicit none
1019110208

@@ -10239,16 +10256,41 @@ recursive subroutine pop_char(json,unit,str,skip_ws,skip_comments,eof,popped)
1023910256

1024010257
!read the next character:
1024110258
if (use_unformatted_stream) then
10242-
read(unit=unit,pos=json%ipos,iostat=ios) c
10259+
10260+
! in this case, we read the file in chunks.
10261+
! if we already have the character we need,
10262+
! then get it from the chunk. Otherwise,
10263+
! read in another chunk.
10264+
if (json%ichunk<1) then
10265+
! read in a chunk:
10266+
json%ichunk = 0
10267+
if (json%filesize<json%ipos+len(json%chunk)-1) then
10268+
! for the last chunk, we resize
10269+
! it to the correct size:
10270+
json%chunk = repeat(' ', json%filesize-json%ipos+1)
10271+
end if
10272+
read(unit=unit,pos=json%ipos,iostat=ios) json%chunk
10273+
else
10274+
ios = 0
10275+
end if
10276+
json%ichunk = json%ichunk + 1
10277+
if (json%ichunk>len(json%chunk)) then
10278+
! check this just in case
10279+
ios = IOSTAT_END
10280+
else
10281+
! get the next character from the chunk:
10282+
c = json%chunk(json%ichunk:json%ichunk)
10283+
if (json%ichunk==len(json%chunk)) then
10284+
json%ichunk = 0 ! reset for next chunk
10285+
end if
10286+
end if
10287+
1024310288
else
10289+
! a formatted read:
1024410290
read(unit=unit,fmt='(A1)',advance='NO',iostat=ios) c
1024510291
end if
1024610292
json%ipos = json%ipos + 1
1024710293

10248-
!....note: maybe try read the file in chunks...
10249-
!.... or use asynchronous read with double buffering
10250-
! (see Modern Fortran: Style and Usage)
10251-
1025210294
else !read from the string
1025310295

1025410296
str_len = len(str) !length of the string
@@ -10339,7 +10381,8 @@ subroutine push_char(json,c)
1033910381

1034010382
!in this case, c is ignored, and we just
1034110383
!decrement the stream position counter:
10342-
json%ipos = json%ipos - 1
10384+
json%ipos = json%ipos - 1
10385+
json%ichunk = json%ichunk - 1
1034310386

1034410387
else
1034510388

0 commit comments

Comments
 (0)