Skip to content

Commit 46f7d2c

Browse files
committed
Added a deep copy routine. Fixes #160
Added routines for getting the next, previous, and tail pointers. Fixes #161 Updated unit tests for the new routines.
1 parent 6b6e126 commit 46f7d2c

File tree

2 files changed

+274
-22
lines changed

2 files changed

+274
-22
lines changed

src/json_module.F90

Lines changed: 175 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -510,15 +510,6 @@ end subroutine traverse_callback_func
510510
end interface json_get_child
511511
!*************************************************************************************
512512

513-
!*************************************************************************************
514-
!>
515-
! Get the parent.
516-
! Returns a [[json_value]] pointer.
517-
interface json_get_parent
518-
module procedure json_value_get_parent
519-
end interface json_get_parent
520-
!*************************************************************************************
521-
522513
!*************************************************************************************
523514
!>
524515
! Add objects to a linked list of [[json_value]]s.
@@ -677,7 +668,7 @@ end subroutine traverse_callback_func
677668
module procedure MAYBEWRAP(json_value_remove_if_present)
678669
end interface
679670
!*************************************************************************************
680-
671+
681672
!*************************************************************************************
682673
!>
683674
! Allocate a [[json_value]] pointer and make it a double variable.
@@ -840,10 +831,14 @@ end subroutine traverse_callback_func
840831
public :: json_create_object ! allocate a json_value object
841832
public :: json_create_string ! allocate a json_value string
842833
public :: json_destroy ! clear a JSON structure (destructor)
834+
public :: json_clone ! clone a JSON structure (deep copy)
843835
public :: json_failed ! check for error
844836
public :: json_get ! get data from the JSON structure
845837
public :: json_get_child ! get a child of a json_value
846-
public :: json_get_parent ! get the parent of a json_value
838+
public :: json_get_parent ! get pointer to json_value parent
839+
public :: json_get_next ! get pointer to json_value next
840+
public :: json_get_previous ! get pointer to json_value previous
841+
public :: json_get_tail ! get pointer to json_value tail
847842
public :: json_info ! get info about a json_value
848843
public :: json_initialize ! to initialize the module
849844
public :: json_parse ! read a JSON file and populate the structure
@@ -944,6 +939,112 @@ end subroutine traverse_callback_func
944939
contains
945940
!*****************************************************************************************
946941

942+
!*****************************************************************************************
943+
!> author: Jacob Williams
944+
! date: 10/31/2015
945+
!
946+
! Create a deep copy of a [[json_value]] linked-list structure.
947+
!
948+
!# Example
949+
!
950+
!```fortran
951+
! program test
952+
! use json_module
953+
! implicit none
954+
! type(json_value),pointer :: j1, j2
955+
! call json_initialize()
956+
! call json_parse('../files/inputs/test1.json',j1)
957+
! call json_clone(j1,j2) !now have two independent copies
958+
! call json_destroy(j1) !destroys j1, but j2 remains
959+
! call json_print(j2,'j2.json')
960+
! call json_destroy(j2)
961+
! end program test
962+
!```
963+
964+
subroutine json_clone(from,to)
965+
966+
implicit none
967+
968+
type(json_value),pointer :: from !! this is the structure to clone
969+
type(json_value),pointer :: to !! the clone is put here
970+
!! (it must not already be associated)
971+
972+
!call the main function:
973+
call json_value_clone_func(from,to)
974+
975+
end subroutine json_clone
976+
!*****************************************************************************************
977+
978+
!*****************************************************************************************
979+
!> author: Jacob Williams
980+
! date: 10/31/2015
981+
!
982+
! Recursive deep copy function called by [[json_clone]].
983+
!
984+
!@note If new data is added to the [[json_value]] type,
985+
! then this would need to be updated.
986+
987+
recursive subroutine json_value_clone_func(from,to,parent,previous,next,children,tail)
988+
989+
implicit none
990+
991+
type(json_value),pointer :: from !! this is the structure to clone
992+
type(json_value),pointer :: to !! the clone is put here
993+
!! (it must not already be associated)
994+
type(json_value),pointer,optional :: parent !! to%parent
995+
type(json_value),pointer,optional :: previous !! to%previous
996+
type(json_value),pointer,optional :: next !! to%next
997+
type(json_value),pointer,optional :: children !! to%children
998+
logical,optional :: tail !! if "to" is the tail of its parent's children
999+
1000+
nullify(to)
1001+
1002+
if (associated(from)) then
1003+
1004+
allocate(to)
1005+
1006+
!copy over the data variables:
1007+
1008+
if (allocated(from%name)) allocate(to%name, source=from%name)
1009+
if (allocated(from%dbl_value)) allocate(to%dbl_value,source=from%dbl_value)
1010+
if (allocated(from%log_value)) allocate(to%log_value,source=from%log_value)
1011+
if (allocated(from%str_value)) allocate(to%str_value,source=from%str_value)
1012+
if (allocated(from%int_value)) allocate(to%int_value,source=from%int_value)
1013+
to%var_type = from%var_type
1014+
to%n_children = from%n_children
1015+
1016+
!allocate and associate the pointers as necessary:
1017+
1018+
if (present(parent)) to%parent => parent
1019+
if (present(previous)) to%previous => previous
1020+
if (present(next)) to%next => next
1021+
if (present(children)) to%children => children
1022+
if (present(tail)) then
1023+
if (tail) to%parent%tail => to
1024+
end if
1025+
1026+
if (associated(from%next)) then
1027+
allocate(to%next)
1028+
call json_value_clone_func(from%next,&
1029+
to%next,&
1030+
previous=to,&
1031+
parent=to%parent,&
1032+
tail=(.not. associated(from%next%next)))
1033+
end if
1034+
1035+
if (associated(from%children)) then
1036+
allocate(to%children)
1037+
call json_value_clone_func(from%children,&
1038+
to%children,&
1039+
parent=to,&
1040+
tail=(.not. associated(from%children%next)))
1041+
end if
1042+
1043+
end if
1044+
1045+
end subroutine json_value_clone_func
1046+
!*****************************************************************************************
1047+
9471048
!*****************************************************************************************
9481049
!> author: Izaak Beekman
9491050
! date: 07/23/2015
@@ -954,8 +1055,8 @@ function initialize_json_file(p) result(file_object)
9541055

9551056
implicit none
9561057

957-
type(json_value), pointer, optional, intent(in) :: p !! `json_value` object to cast
958-
!! as a `json_file` object
1058+
type(json_value),pointer,optional,intent(in) :: p !! `json_value` object to cast
1059+
!! as a `json_file` object
9591060
type(json_file) :: file_object
9601061

9611062
if (present(p)) file_object%p => p
@@ -3274,20 +3375,73 @@ end function json_count
32743375
! Returns a pointer to the parent of a [[json_value]].
32753376
! If there is no parent, then a null() pointer is returned.
32763377

3277-
subroutine json_value_get_parent(me,p)
3378+
subroutine json_get_parent(me,p)
32783379

32793380
implicit none
32803381

32813382
type(json_value),pointer,intent(in) :: me !! JSON object
3282-
type(json_value),pointer :: p !! pointer to the parent
3383+
type(json_value),pointer,intent(out) :: p !! pointer to parent
32833384

3284-
if (associated(me%parent)) then
3285-
p => me%parent
3286-
else
3287-
p => null()
3288-
end if
3385+
p => me%parent
3386+
3387+
end subroutine json_get_parent
3388+
!*****************************************************************************************
3389+
3390+
!*****************************************************************************************
3391+
!> author: Jacob Williams
3392+
! date: 10/31/2015
3393+
!
3394+
! Returns a pointer to the next of a [[json_value]].
3395+
! If there is no next, then a null() pointer is returned.
3396+
3397+
subroutine json_get_next(me,p)
3398+
3399+
implicit none
3400+
3401+
type(json_value),pointer,intent(in) :: me !! JSON object
3402+
type(json_value),pointer,intent(out) :: p !! pointer to next
3403+
3404+
p => me%next
3405+
3406+
end subroutine json_get_next
3407+
!*****************************************************************************************
3408+
3409+
!*****************************************************************************************
3410+
!> author: Jacob Williams
3411+
! date: 10/31/2015
3412+
!
3413+
! Returns a pointer to the previous of a [[json_value]].
3414+
! If there is no previous, then a null() pointer is returned.
3415+
3416+
subroutine json_get_previous(me,p)
3417+
3418+
implicit none
3419+
3420+
type(json_value),pointer,intent(in) :: me !! JSON object
3421+
type(json_value),pointer,intent(out) :: p !! pointer to previous
3422+
3423+
p => me%previous
3424+
3425+
end subroutine json_get_previous
3426+
!*****************************************************************************************
3427+
3428+
!*****************************************************************************************
3429+
!> author: Jacob Williams
3430+
! date: 10/31/2015
3431+
!
3432+
! Returns a pointer to the tail of a [[json_value]].
3433+
! If there is no tail, then a null() pointer is returned.
3434+
3435+
subroutine json_get_tail(me,p)
3436+
3437+
implicit none
3438+
3439+
type(json_value),pointer,intent(in) :: me !! JSON object
3440+
type(json_value),pointer,intent(out) :: p !! pointer to tail
3441+
3442+
p => me%tail
32893443

3290-
end subroutine json_value_get_parent
3444+
end subroutine json_get_tail
32913445
!*****************************************************************************************
32923446

32933447
!*****************************************************************************************

src/tests/jf_test_2.f90

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ subroutine test_2(error_cnt)
2525

2626
integer,intent(out) :: error_cnt
2727

28-
type(json_value),pointer :: p, inp, traj
28+
type(json_value),pointer :: p, inp, traj, p_tmp, p_integer_array, p_clone
2929

3030
integer :: iunit
31+
character(len=:),allocatable :: name
32+
integer :: ival,ival_clone
33+
logical :: found
3134

3235
error_cnt = 0
3336
call json_initialize()
@@ -144,6 +147,101 @@ subroutine test_2(error_cnt)
144147
error_cnt = error_cnt + 1
145148
end if
146149
close(iunit)
150+
151+
!test the deep copy routine:
152+
153+
write(error_unit,'(A)') 'json_clone test'
154+
call json_clone(p,p_clone)
155+
if (json_failed()) then
156+
call json_print_error_message(error_unit)
157+
error_cnt = error_cnt + 1
158+
else
159+
!now, change one and verify that they are independent:
160+
call json_update(p_clone,'inputs.integer_scalar',100,found)
161+
call json_get(p,'inputs.integer_scalar',ival)
162+
call json_get(p_clone,'inputs.integer_scalar',ival_clone)
163+
if (json_failed()) then
164+
call json_print_error_message(error_unit)
165+
error_cnt = error_cnt + 1
166+
else
167+
if (ival==1 .and. ival_clone==100) then
168+
write(error_unit,'(A)') 'json_clone ... passed'
169+
else
170+
write(error_unit,'(A)') 'Error: ival /= ival_clone'
171+
error_cnt = error_cnt + 1
172+
end if
173+
end if
174+
end if
175+
176+
!test some of the pointer routines:
177+
write(error_unit,'(A)') 'Pointer routine tests'
178+
call json_get(p,'inputs.integer_array',p_integer_array)
179+
if (json_failed()) then
180+
call json_print_error_message(error_unit)
181+
error_cnt = error_cnt + 1
182+
else
183+
184+
!get parent test:
185+
call json_get_parent(p_integer_array,p_tmp) !should be "inputs"
186+
call json_info(p_tmp,name=name)
187+
if (json_failed()) then
188+
call json_print_error_message(error_unit)
189+
error_cnt = error_cnt + 1
190+
else
191+
if (name=='inputs') then
192+
write(error_unit,'(A)') 'json_get_parent ... passed'
193+
else
194+
write(error_unit,'(A)') 'Error: parent should be "inputs", is actually: '//trim(name)
195+
error_cnt = error_cnt + 1
196+
end if
197+
end if
198+
199+
!get next test:
200+
call json_get_next(p_integer_array,p_tmp) !should be "names"
201+
call json_info(p_tmp,name=name)
202+
if (json_failed()) then
203+
call json_print_error_message(error_unit)
204+
error_cnt = error_cnt + 1
205+
else
206+
if (name=='names') then
207+
write(error_unit,'(A)') 'json_get_next ... passed'
208+
else
209+
write(error_unit,'(A)') 'Error: next should be "names", is actually: '//trim(name)
210+
error_cnt = error_cnt + 1
211+
end if
212+
end if
213+
214+
!get previous test:
215+
call json_get_previous(p_integer_array,p_tmp) !should be "integer_scalar"
216+
call json_info(p_tmp,name=name)
217+
if (json_failed()) then
218+
call json_print_error_message(error_unit)
219+
error_cnt = error_cnt + 1
220+
else
221+
if (name=='integer_scalar') then
222+
write(error_unit,'(A)') 'json_get_previous ... passed'
223+
else
224+
write(error_unit,'(A)') 'Error: next should be "integer_scalar", is actually: '//trim(name)
225+
error_cnt = error_cnt + 1
226+
end if
227+
end if
228+
229+
!get tail test:
230+
call json_get_tail(p_integer_array,p_tmp) !should be 99, the last element in the array
231+
call json_get(p_tmp,ival)
232+
if (json_failed()) then
233+
call json_print_error_message(error_unit)
234+
error_cnt = error_cnt + 1
235+
else
236+
if (ival==99) then
237+
write(error_unit,'(A)') 'json_get_tail ... passed'
238+
else
239+
write(error_unit,'(A,1X,I5)') 'Error: tail value should be 99, is actually: ',ival
240+
error_cnt = error_cnt + 1
241+
end if
242+
end if
243+
244+
end if
147245

148246
!cleanup:
149247
call json_destroy(p)

0 commit comments

Comments
 (0)