Skip to content

Commit 967cfee

Browse files
committed
Some efficiency improvements when parsing strings. Fixes #351
1 parent 4baff3b commit 967cfee

File tree

3 files changed

+34
-47
lines changed

3 files changed

+34
-47
lines changed

src/json_file_module.F90

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ module json_file_module
6464

6565
private
6666

67-
type(json_core) :: core !! The instance of the [[json_core(type)]] factory used for this file.
67+
type(json_core) :: core !! The instance of the [[json_core(type)]]
68+
!! factory used for this file.
6869
type(json_value),pointer :: p => null() !! the JSON structure read from the file
6970

7071
contains

src/json_string_utilities.F90

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -433,44 +433,45 @@ end subroutine escape_string
433433
! * `\t` - horizontal tab
434434
! * `\uXXXX` - 4 hexadecimal digits
435435

436-
subroutine unescape_string(str_in, str_out, error_message)
436+
subroutine unescape_string(str, error_message)
437437

438438
implicit none
439439

440-
character(kind=CK,len=*),intent(in) :: str_in !! string as stored in a [[json_value]]
441-
character(kind=CK,len=:),allocatable,intent(out) :: str_out !! decoded string
442-
character(kind=CK,len=:),allocatable,intent(out) :: error_message !! will be allocated if there was an error
440+
character(kind=CK,len=:),allocatable,intent(inout) :: str !! in: string as stored
441+
!! in a [[json_value]].
442+
!! out: decoded string.
443+
character(kind=CK,len=:),allocatable,intent(out) :: error_message !! will be allocated if
444+
!! there was an error
443445

444446
integer :: i !! counter
445-
integer :: n !! length of str_in
446-
integer :: m !! length of str_out
447+
integer :: n !! length of `str`
448+
integer :: m !! length of `str_tmp`
447449
character(kind=CK,len=1) :: c !! for scanning each character in string
450+
character(kind=CK,len=:),allocatable :: str_tmp !! temp decoded string (if the input
451+
!! string contains an escape character
452+
!! and needs to be decoded).
448453

449-
#if defined __GFORTRAN__
450-
character(kind=CK,len=:),allocatable :: tmp !! for GFortran bug workaround
451-
#endif
452-
453-
if (scan(str_in,backslash)>0) then
454+
if (scan(str,backslash)>0) then
454455

455456
!there is at least one escape character, so process this string:
456457

457-
n = len(str_in)
458-
str_out = repeat(space,n) !size the output string (will be trimmed later)
459-
m = 0 !counter in str_out
460-
i = 0 !counter in str_in
458+
n = len(str)
459+
str_tmp = repeat(space,n) !size the output string (will be trimmed later)
460+
m = 0 !counter in str_tmp
461+
i = 0 !counter in str
461462

462463
do
463464

464465
i = i + 1
465466
if (i>n) exit ! finished
466-
c = str_in(i:i) ! get next character in the string
467+
c = str(i:i) ! get next character in the string
467468

468469
if (c == backslash) then
469470

470471
if (i<n) then
471472

472473
i = i + 1
473-
c = str_in(i:i) !character after the escape
474+
c = str(i:i) !character after the escape
474475

475476
if (any(c == [quotation_mark,backslash,slash, &
476477
to_unicode(['b','f','n','r','t'])])) then
@@ -491,7 +492,7 @@ subroutine unescape_string(str_in, str_out, error_message)
491492
end select
492493

493494
m = m + 1
494-
str_out(m:m) = c
495+
str_tmp(m:m) = c
495496

496497
else if (c == 'u') then !expecting 4 hexadecimal digits after
497498
!the escape character [\uXXXX]
@@ -505,23 +506,23 @@ subroutine unescape_string(str_in, str_out, error_message)
505506

506507
if (i+4<=n) then
507508
m = m + 1
508-
str_out(m:m+5) = str_in(i-1:i+4)
509+
str_tmp(m:m+5) = str(i-1:i+4)
509510
i = i + 4
510511
m = m + 5
511512
else
512513
error_message = 'Error in unescape_string:'//&
513-
' Invalid hexadecimal sequence'//&
514-
' in string: '//str_in(i-1:)
515-
if (allocated(str_out)) deallocate(str_out)
514+
' Invalid hexadecimal sequence'//&
515+
' in string: '//str(i-1:)
516+
if (allocated(str_tmp)) deallocate(str_tmp)
516517
return
517518
end if
518519

519520
else
520521
!unknown escape character
521522
error_message = 'Error in unescape_string:'//&
522-
' unknown escape sequence in string "'//&
523-
trim(str_in)//'" ['//backslash//c//']'
524-
if (allocated(str_out)) deallocate(str_out)
523+
' unknown escape sequence in string "'//&
524+
trim(str)//'" ['//backslash//c//']'
525+
if (allocated(str_tmp)) deallocate(str_tmp)
525526
return
526527
end if
527528

@@ -530,28 +531,19 @@ subroutine unescape_string(str_in, str_out, error_message)
530531
! the string [this may not be valid syntax,
531532
! but just keep it]
532533
m = m + 1
533-
str_out(m:m) = c
534+
str_tmp(m:m) = c
534535
end if
535536

536537
else
537538
m = m + 1
538-
str_out(m:m) = c
539+
str_tmp(m:m) = c
539540
end if
540541

541542
end do
542543

543544
!trim trailing space:
544-
#if defined __GFORTRAN__
545-
! workaround for Gfortran 6.1.0 bug
546-
tmp = str_out(1:m)
547-
str_out = tmp
548-
#else
549-
str_out = str_out(1:m)
550-
#endif
545+
str = str_tmp(1:m)
551546

552-
else
553-
!there are no escape characters, so return as is:
554-
str_out = str_in
555547
end if
556548

557549
end subroutine unescape_string

src/json_value_module.F90

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9887,8 +9887,7 @@ subroutine parse_string(json, unit, str, string)
98879887
integer(IK) :: ip !! index to put next character,
98889888
!! to speed up by reducing the number
98899889
!! of character string reallocations.
9890-
character(kind=CK,len=:),allocatable :: string_unescaped !! temp variable
9891-
character(kind=CK,len=:),allocatable :: error_message !! for string unescaping
9890+
character(kind=CK,len=:),allocatable :: error_message !! for string unescaping
98929891

98939892
!at least return a blank string if there is a problem:
98949893
string = repeat(space, chunk_size)
@@ -9970,17 +9969,12 @@ subroutine parse_string(json, unit, str, string)
99709969
end if
99719970

99729971
!string is returned unescaped:
9973-
call unescape_string(string,string_unescaped,error_message)
9972+
call unescape_string(string,error_message)
99749973
if (allocated(error_message)) then
99759974
call json%throw_exception(error_message)
9976-
else
9977-
string = string_unescaped
9975+
deallocate(error_message) !cleanup
99789976
end if
99799977

9980-
!cleanup:
9981-
if (allocated(error_message)) deallocate(error_message)
9982-
if (allocated(string_unescaped)) deallocate(string_unescaped)
9983-
99849978
end if
99859979

99869980
end subroutine parse_string

0 commit comments

Comments
 (0)