Skip to content

String list new #680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
263a652
Add module for list of strings
arjenmarkus Feb 3, 2021
90b06ff
Correct typo
arjenmarkus Feb 4, 2021
4157ed1
Merge remote-tracking branch 'upstream/master' into string-list-new
arjenmarkus Jun 3, 2021
e36f997
Merge branch 'master' into string-list-new
arjenmarkus Sep 18, 2022
024b078
Documentation and corrected source code for linked lists
arjenmarkus Sep 18, 2022
4379fb4
Correct subdirectory for examples
arjenmarkus Sep 18, 2022
3067b9a
Move the implementations of the linked_list modules to src
arjenmarkus Sep 18, 2022
3cf3d85
Use an include statement to get the auxiliary subroutine in
arjenmarkus Sep 18, 2022
edd20fd
Use an internal routine instead for print_list
arjenmarkus Sep 18, 2022
86d2fe4
Add a CMakeLists.txt for building the examples
arjenmarkus Sep 20, 2022
327c8c1
Rename the examples to avoid conflicts
arjenmarkus Sep 20, 2022
8f2f1fa
Define a new macro to take care of the include directory
arjenmarkus Sep 20, 2022
09b7266
Adjust the CMake and CI build set-ups
arjenmarkus Sep 25, 2022
af8dd68
Rename the include file
arjenmarkus Sep 25, 2022
fae33a4
Correct the test program
arjenmarkus Sep 25, 2022
41417f4
Update test_performance.f90
arjenmarkus Sep 25, 2022
b8c18ea
Create CMakeLists.txt file for performance test program
arjenmarkus Sep 25, 2022
ca684ae
Merge branch 'master' into string-list-new
jvdp1 Dec 25, 2023
5644454
Updated documentation and source code
arjenmarkus Dec 28, 2023
e23b1ea
Adjusting the examples and fixing an INTENT() error
arjenmarkus Dec 28, 2023
b5e41c1
Merge branch 'string-list-new' of https://github.com/arjenmarkus/stdl…
arjenmarkus Dec 28, 2023
ebb84b8
Add explicit include directory
arjenmarkus Dec 28, 2023
b310239
Incorporate the auxiliary routine directly
arjenmarkus Dec 28, 2023
220791a
Correct the name of the test programs
arjenmarkus Dec 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
497 changes: 497 additions & 0 deletions doc/specs/stdlib_linked_list.md

Large diffs are not rendered by default.

487 changes: 487 additions & 0 deletions doc/specs/stdlib_stringlist.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ add_subdirectory(hashmaps)
add_subdirectory(hash_procedures)
add_subdirectory(io)
add_subdirectory(linalg)
add_subdirectory(linked_list)
add_subdirectory(logger)
add_subdirectory(math)
add_subdirectory(optval)
15 changes: 15 additions & 0 deletions example/linked_list/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
include_directories(${CMAKE_CURRENT_LIST_DIR})

ADD_EXAMPLE(linked_absorb)
ADD_EXAMPLE(linked_clear)
ADD_EXAMPLE(linked_concat)
ADD_EXAMPLE(linked_get)
ADD_EXAMPLE(linked_insert)
ADD_EXAMPLE(linked_pop)
ADD_EXAMPLE(linked_push)
ADD_EXAMPLE(linked_remove)
ADD_EXAMPLE(linked_replace)
ADD_EXAMPLE(linked_reverse)
ADD_EXAMPLE(linked_size)
ADD_EXAMPLE(linked_slice)
ADD_EXAMPLE(linked_splice)
70 changes: 70 additions & 0 deletions example/linked_list/example_linked_absorb.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
! example_absorb.f90 --
! Demonstrate the absorb method
!
program example_absorb
use stdlib_linked_list

implicit none

type(linked_list_type) :: list, list_to_absorb

!
! Add a few elements to the two lists
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call list_to_absorb%insert( 5, 1 )
call list_to_absorb%insert( 6, 2 )

write(*,*) 'List 1:'
call print_list( list )
write(*,*) 'List 2:'
call print_list( list_to_absorb )

!
! Now absorb the second list to the first one
!

call list%absorb( list_to_absorb )

!
! Print the resulting list
!
write(*,*) 'New list:'
call print_list( list )

!
! Print the second list (it is untouched)
write(*,*) 'List that was absorbed (should be empty):'
call print_list( list_to_absorb )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_absorb
28 changes: 28 additions & 0 deletions example/linked_list/example_linked_clear.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
! example_clear.f90 --
! Demonstrate the clear method
!
program example_clear
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

!
! Clean up the list
!
call list%clear()

!
! The program should print 0
!
write(*,*) 'Size of the list: ', list%size()

end program example_clear
70 changes: 70 additions & 0 deletions example/linked_list/example_linked_concat.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
! example_concat.f90 --
! Demonstrate the concat method
!
program example_concat
use stdlib_linked_list

implicit none

type(linked_list_type) :: list, list_to_concat

!
! Add a few elements to the two lists
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call list_to_concat%insert( 5, 1 )
call list_to_concat%insert( 6, 2 )

write(*,*) 'List 1:'
call print_list( list )
write(*,*) 'List 2:'
call print_list( list_to_concat )

!
! Now concat the second list to the first one
!

call list%concat( list_to_concat )

!
! Print the resulting list
!
write(*,*) 'New list:'
call print_list( list )

!
! Print the second list (it is untouched)
write(*,*) 'List that was concatenated (remains intact):'
call print_list( list_to_concat )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_concat
41 changes: 41 additions & 0 deletions example/linked_list/example_linked_get.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
! example_get.f90 --
! Demonstrate the get method
!
program example_get
use stdlib_linked_list

implicit none

type(linked_list_type) :: list
class(*), pointer :: list_item
integer :: i

!
! Add a few elements
!
call list%insert( "String element ", 1 ) ! Note the trailing blanks
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

!
! Print the contents of the list
!
do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo

end program example_get
59 changes: 59 additions & 0 deletions example/linked_list/example_linked_insert.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
! example_insert.f90 --
! Demonstrate the insert method
!

program example_insert
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call print_list( list )
!
! Now insert an element in the middle
!

call list%insert( "Another string", 2 )

!
! Print the list
!
write(*,*) 'New list:'
call print_list( list )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_insert
59 changes: 59 additions & 0 deletions example/linked_list/example_linked_pop.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
! example_pop.f90 --
! Demonstrate the pop method
!
program example_pop
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call print_list( list )

!
! Now pop the last element from the list
!

call list%pop

!
! Print the list
!
write(*,*) 'New list:'
call print_list( list )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_pop
59 changes: 59 additions & 0 deletions example/linked_list/example_linked_push.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
! example_push.f90 --
! Demonstrate the push method
!
program example_push
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call print_list( list )

!
! Now push a new element to the end
!

call list%push( 3 )

!
! Print the list
!
write(*,*) 'New list:'
call print_list( list )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_push
59 changes: 59 additions & 0 deletions example/linked_list/example_linked_remove.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
! example_remove.f90 --
! Demonstrate the remove method
!
program example_remove
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call print_list( list )

!
! Now remove the second element
!

call list%remove( 2 )

!
! Print the list
!
write(*,*) 'New list:'
call print_list( list )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_remove
59 changes: 59 additions & 0 deletions example/linked_list/example_linked_replace.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
! example_replace.f90 --
! Demonstrate the replace method
!
program example_replace
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call print_list( list )

!
! Now replace the second element by a string
!

call list%replace( "Another string", 2 )

!
! Print the list
!
write(*,*) 'New list:'
call print_list( list )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_replace
59 changes: 59 additions & 0 deletions example/linked_list/example_linked_reverse.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
! example_reverse.f90 --
! Demonstrate the reverse method
!
program example_reverse
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

call print_list( list )

!
! Now reverse the whole list
!

call list%reverse

!
! Print the list
!
write(*,*) 'New list:'
call print_list( list )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_reverse
23 changes: 23 additions & 0 deletions example/linked_list/example_linked_size.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
! example_size.f90 --
! Demonstrate the size method
!
program example_size
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )

!
! The program should print 3
!
write(*,*) 'Size of the list: ', list%size()

end program example_size
66 changes: 66 additions & 0 deletions example/linked_list/example_linked_slice.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
! example_slice.f90 --
! Demonstrate the slice method
!
program example_slice
use stdlib_linked_list

implicit none

type(linked_list_type) :: list, sublist

!
! Add a few elements to the list
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )
call list%insert( 5, 4 )
call list%insert( 6, 5 )

write(*,*) 'Full list:'
call print_list( list )

!
! Now construct a sublist via the slice method
!
sublist = list%slice( 2, 4 )

!
! Print the resulting list
!
write(*,*) 'Original list:'
call print_list( list )

!
! Print the second list
write(*,*) 'Sublist:'
call print_list( sublist)

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_slice
64 changes: 64 additions & 0 deletions example/linked_list/example_linked_splice.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
! example_splice.f90 --
! Demonstrate the splice method
!

program example_splice
use stdlib_linked_list

implicit none

type(linked_list_type) :: list

!
! Add a few elements to the list
!
call list%insert( "String element", 1 )
call list%insert( 2, 2 )
call list%insert( 3.3, 3 )
call list%insert( 5, 1 )
call list%insert( 6, 2 )

write(*,*) 'Full list:'
call print_list( list )

!
! Now remove a part of the list via the splice method
!

write(*,*) 'splicing ...'
call list%splice( 2, 4 )

!
! Print the resulting list
!
write(*,*) 'New list:'
call print_list( list )

contains
!include 'linked_list_aux.inc'
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item

do i = 1,list%size()
list_item => list%get(i)

select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list

end program example_splice
27 changes: 27 additions & 0 deletions example/linked_list/linked_list_aux.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
! linked_list_aux.f90 --
! Auxiliary routine for printing the contents of a linked list
!
subroutine print_list( list )
type(linked_list_type), intent(in) :: list

integer :: i
class(*), pointer :: list_item
do i = 1,list%size()
list_item => list%get(i)
select type( item => list_item )
type is (integer)
write(*,*) i, item, ' (integer)'

type is (real)
write(*,*) i, item, ' (real)'

type is (character(*))
write(*,*) i, ' >', item, '< (string)'

class default
write(*,*) i, ' (type unknown)'
end select
enddo
end subroutine print_list
17 changes: 17 additions & 0 deletions example/linked_list/mk.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
gfortran -c ../../src/stdlib_child_list.f90
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that this file should be removed from the directory.

gfortran -c ../../src/stdlib_linked_list.f90
rem gfortran -c linked_list_aux.f90

gfortran -o example_linked_size example_linked_size.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_clear example_linked_clear.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_get example_linked_get.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_insert example_linked_insert.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_replace example_linked_replace.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_remove example_linked_remove.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_push example_linked_push.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_pop example_linked_pop.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_reverse example_linked_reverse.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_concat example_linked_concat.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_absorb example_linked_absorb.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_slice example_linked_slice.f90 stdlib_linked_list.o stdlib_child_list.o
gfortran -o example_linked_splice example_linked_splice.f90 stdlib_linked_list.o stdlib_child_list.o
16 changes: 9 additions & 7 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -6,14 +6,14 @@ set(fppFiles
stdlib_bitsets.fypp
stdlib_bitsets_64.fypp
stdlib_bitsets_large.fypp
stdlib_hash_32bit.fypp
stdlib_hash_32bit.fypp
stdlib_hash_32bit_fnv.fypp
stdlib_hash_32bit_nm.fypp
stdlib_hash_32bit_water.fypp
stdlib_hash_64bit.fypp
stdlib_hash_64bit_fnv.fypp
stdlib_hash_64bit_pengy.fypp
stdlib_hash_64bit_spookyv2.fypp
stdlib_hash_32bit_nm.fypp
stdlib_hash_32bit_water.fypp
stdlib_hash_64bit.fypp
stdlib_hash_64bit_fnv.fypp
stdlib_hash_64bit_pengy.fypp
stdlib_hash_64bit_spookyv2.fypp
stdlib_io.fypp
stdlib_io_npy.fypp
stdlib_io_npy_load.fypp
@@ -70,11 +70,13 @@ set(SRC
stdlib_ansi_operator.f90
stdlib_ansi_to_string.f90
stdlib_array.f90
stdlib_child_list.f90
stdlib_error.f90
stdlib_hashmap_wrappers.f90
stdlib_hashmaps.f90
stdlib_hashmap_chaining.f90
stdlib_hashmap_open.f90
stdlib_linked_list.f90
stdlib_logger.f90
stdlib_sorting_radix_sort.f90
stdlib_system.F90
369 changes: 369 additions & 0 deletions src/stdlib_child_list.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,369 @@
!> Implementation of a Child list type to hold various types of data.
!>
!> The child list module provides a heterogeneous generic linked list
!> that acts as a basic building block for the linked list module


module stdlib_child_list
implicit none

! making Node and child_list struct globally available
public:: node_type, child_list_type

!> Defining Node
!>
!> The purpose of this node is to hold an item
!> and links to previous and next Node.
type node_type
type(node_type), pointer :: next => null()
type(node_type), pointer :: prev => null()
class(*), allocatable :: item
contains
procedure :: clear => node_destroyed
procedure, private :: clear_all => all_nodes_destroyed
end type node_type

!> Defining Child List
!>
!> This linked list is single-dimensional chain of Nodes.
!> It is a doubly-linked heterogeneous generic list .
type child_list_type
integer, private :: num_nodes = 0
type(node_type), pointer :: head => null()
type(node_type), pointer :: tail => null()
contains
procedure:: push => push_at_tail
procedure:: insert => insert_at_index
procedure:: pop => pop_node_at_tail
procedure:: remove => remove_node_at_index
procedure:: get => get_node_at_index
procedure:: size => get_length
procedure:: set_size => set_length
procedure:: replace => replace_at_index
procedure:: reverse => reverse_child_list
procedure:: clear => destroy_whole_child_list
end type child_list_type

contains

!> Creates a Node that contains 'new_item' as its child
!>
!> Returns the new parent node
pure function initialize_node( new_item ) result( new_node )
type(node_type) :: new_node
class(*), intent(in), optional :: new_item

! allocating new_item to the new node's item
allocate(new_node%item, source=new_item)
end function initialize_node

!> Delete a node and frees the memory in the item.
subroutine node_destroyed( this_node )
class(node_type), intent(inout) :: this_node

!Deallocate it's item
if (allocated(this_node%item)) deallocate(this_node%item)

!Nullify it's pointers
nullify(this_node%next)
nullify(this_node%prev)
end subroutine node_destroyed


pure subroutine all_nodes_destroyed( this_node )
!Entrada:
class(node_type), intent(inout) :: this_node
!Local:
type(node_type), pointer :: current_node
type(node_type), pointer :: next_node
!Deallocate it's item
current_node = this_node
next_node => current_node%next
do
deallocate(current_node)
if (.not. associated(next_node)) exit
current_node => next_node
next_node => current_node%next
end do
end subroutine all_nodes_destroyed


!> Insert 'item' at the tail of the input child list
pure subroutine push_at_tail( this_child_list, item )

class(child_list_type), intent(inout) :: this_child_list
class(*), intent(in) :: item

! Finding if its a first node or the child_list already have a node
if (associated(this_child_list%tail)) then
allocate(this_child_list%tail%next, source=initialize_node(item))
this_child_list%tail%next%prev => this_child_list%tail
this_child_list%tail => this_child_list%tail%next
else
allocate(this_child_list%head, source=initialize_node(item))
this_child_list%tail => this_child_list%head
end if

this_child_list%num_nodes = this_child_list%num_nodes + 1
end subroutine push_at_tail


!> Insert 'item' at the given 'node_index' of the input child list
pure subroutine insert_at_index( this_child_list, item ,node_index )
class(child_list_type), intent(inout) :: this_child_list
integer, intent(in) :: node_index
class(*), intent(in) :: item
type(node_type), pointer :: current_node
type(node_type), pointer :: next_node

integer :: index

! This index will be used for iteraing
index = node_index-1

! will insert after tail when the input is more than size of the child list
if(index >=this_child_list%num_nodes) then
call this_child_list%push(item)
return
else if(index <=0) then
! will insert after tail when the input is more than size of the child list
current_node => this_child_list%head
allocate(this_child_list%head,source = initialize_node(item))
this_child_list%head%next => current_node
current_node%prev => this_child_list%head
else
current_node => this_child_list%head
do while(index >1)
index = index -1
current_node => current_node%next
end do
next_node => current_node%next
allocate(current_node%next,source = initialize_node(item))
current_node%next%prev => current_node
current_node%next%next => next_node
current_node => current_node%next
current_node%next%prev => current_node
end if
this_child_list%num_nodes = this_child_list%num_nodes + 1
end subroutine insert_at_index


!> Removing the last node from the input child list
subroutine pop_node_at_tail( this_child_list )

class(child_list_type), intent(inout) :: this_child_list

type(node_type), pointer:: current_node

! return if the size of the child list is 0
if(this_child_list%num_nodes == 0) return


! poping the last node of the child list
current_node => this_child_list%tail
if (associated(current_node%prev).and.associated(current_node%next)) then
!child_list Node is in mid
current_node%next%prev => current_node%prev
current_node%prev%next => current_node%next

else if (associated(current_node%prev)) then
!child_list tail
nullify(current_node%prev%next)
this_child_list%tail => current_node%prev

else if (associated(current_node%next)) then
!child_list head
nullify(current_node%next%prev)
this_child_list%head => current_node%next
else
nullify(this_child_list%head)
nullify(this_child_list%tail)
end if

!Destroy node content and Free it's memory
call current_node%clear()
deallocate(current_node)

!Reduce the count by 1
this_child_list%num_nodes = this_child_list%num_nodes - 1
end subroutine pop_node_at_tail

!> Removing the node at the given 'node_index' from the input child list
subroutine remove_node_at_index( this_child_list, node_index )

class(child_list_type), intent(inout) :: this_child_list
integer, intent(in):: node_index
type(node_type), pointer:: current_node

! This index will be reference for child list
integer:: index

!iterating through the child_list to reach the nth node
current_node => this_child_list%head

! return if the given node index is not in range of 1 to size of linked list
if(node_index<=0) return
if(node_index>this_child_list%num_nodes) return
index = 1
do while ( associated(current_node) )
if (index==node_index) then
if (associated(current_node%prev).and.associated(current_node%next)) then
!child_list Node is in mid
current_node%next%prev => current_node%prev
current_node%prev%next => current_node%next

else if (associated(current_node%prev)) then
!child_list tail
nullify(current_node%prev%next)
this_child_list%tail => current_node%prev

else if (associated(current_node%next)) then
!child_list head
nullify(current_node%next%prev)
this_child_list%head => current_node%next
else
!only node in list
nullify(this_child_list%head)
nullify(this_child_list%tail)
end if

!Destroy node content and Free it's memory
call current_node%clear()
deallocate(current_node)

!Reduce the index by 1
this_child_list%num_nodes = this_child_list%num_nodes - 1
return
end if
current_node => current_node%next
index = index+1
end do
end subroutine remove_node_at_index


!> Returns the pointer to the item stored at 'node_index' in the input child list
!>
!> Returns a pointer
function get_node_at_index( this_child_list, node_index ) result (return_item)

class(child_list_type), intent(inout) :: this_child_list
integer, intent(in):: node_index
class(*), pointer :: return_item
type(node_type), pointer:: current_node
integer:: index

!iterating through the child_list to reach the nth node
current_node => this_child_list%head
index = 1
do while ( associated(current_node) )

if (index == node_index) then
! Return the pointer to item stored at specified index
return_item => current_node%item
nullify(current_node)
return
end if
current_node => current_node%next
index = index+1

end do
nullify(current_node)
nullify(return_item)

end function get_node_at_index

!> Returns the total number of nodes in the input child list
!>
!> Returns an integer
pure function get_length ( this_child_list ) result ( length )
class(child_list_type), intent(in) :: this_child_list
integer :: length

length = this_child_list%num_nodes

end function get_length


!> Changes the size of the input child list to 'length'
pure subroutine set_length ( this_child_list, length )
class(child_list_type), intent(inout) :: this_child_list
integer, intent(in) :: length

this_child_list%num_nodes = length

end subroutine set_length



!> Replaces the item stored in node at 'node_index' of the input child list with 'new_item'
pure subroutine replace_at_index( this_child_list, item ,node_index )

class(child_list_type), intent(inout) :: this_child_list
integer, intent(in) :: node_index
class(*), intent(in) :: item
type(node_type), pointer :: current_node
integer :: index


! This index will be reference for child list
index = node_index

! return if the given node index is not in range of 1 to size of child list
if(index<1 .or. index>this_child_list%num_nodes) return


! Iterating through parent nodes while size of the child list is smaller than index
current_node => this_child_list%head
do while(index>1)
index = index-1
current_node => current_node%next
end do
current_node%item = item

end subroutine replace_at_index

!> Reverses the input child list
pure subroutine reverse_child_list (this_child_list)
class(child_list_type), intent(inout) :: this_child_list
type(node_type), pointer :: temp_node
type(node_type), pointer :: curr_node

nullify(temp_node)

! Swapping head of the child node with tail of the child node
curr_node => this_child_list%head
do while (associated(curr_node))
temp_node => curr_node%prev
curr_node%prev => curr_node%next
curr_node%next => temp_node
curr_node => curr_node%prev
end do

temp_node=> this_child_list%head
this_child_list%head => this_child_list%tail
this_child_list%tail => temp_node

end subroutine reverse_child_list

!> Destroy the whole given linked list
!> Free the allocated memory
!> Nullify all the variables
subroutine destroy_whole_child_list( this_child_list )
!Entrada:
class(child_list_type), intent(inout) :: this_child_list
!Local:
type(node_type), pointer:: current_node

do while (this_child_list%num_nodes>0)
current_node => this_child_list%head
if (associated(current_node%next)) then
nullify(current_node%next%prev)
this_child_list%head => current_node%next
end if
call current_node%clear()
deallocate(current_node)
this_child_list%num_nodes = this_child_list%num_nodes - 1
end do

end subroutine destroy_whole_child_list
end module stdlib_child_list
786 changes: 786 additions & 0 deletions src/stdlib_linked_list.f90

Large diffs are not rendered by default.

996 changes: 996 additions & 0 deletions src/stdlib_stringlist.f90

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/tests/stringlist/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ADDTEST(insert)
ADDTEST(delete)
ADDTEST(find)
ADDTEST(replace_append)
57 changes: 57 additions & 0 deletions src/tests/stringlist/test_delete.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
! test_delete.f90 --
! Test the delete routine
!
program test_deletion
use stdlib_stringlist

type(stringlist_type) :: list


call list%insert( 1, ["A", "B", "C", "D", "E", "F"] )

call list%delete( 1, 1 )

write(*,*) 'Expected: B, C, D, E, F (5)'
call print_list( list )

call list%delete( list_end, list_end )

write(*,*) 'Expected: B, C, D, E (4)'
call print_list( list )

call list%delete( list_end+1, list_end+1 )

write(*,*) 'Expected: B, C, D, E (4)'
call print_list( list )

call list%delete( 3, 2 )

write(*,*) 'Expected: B, C, D, E (4)'
call print_list( list )

call list%delete( 2, 3 )

write(*,*) 'Expected: B, E (2)'
call print_list( list )

contains
subroutine renew_list( list )
type(stringlist_type), intent(inout) :: list

call list%destroy
call list%insert( 1, "A" )
call list%insert( 2, "B" )
call list%insert( 3, "C" )
end subroutine renew_list

subroutine print_list( list )
type(stringlist_type), intent(in) :: list

write(*,*) list%length()

do i = 1,list%length()
write(*,*) '>', list%get(i), '<'
enddo
end subroutine print_list

end program test_deletion
72 changes: 72 additions & 0 deletions src/tests/stringlist/test_find.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
! test_find.f90 --
! Test the various retrieval routines
!
program test_find
use stdlib_stringlist

type(stringlist_type) :: list, sublist
character(len=:), allocatable :: string

call list%insert( 1, ["A", "B", "C", "D", "E", "F"] )

write(*,*) 'Expected: A'
write(*,*) list%get(1)
write(*,*) list%get(list_head)
write(*,*) 'Expected: B'
write(*,*) list%get(list_head+1)
write(*,*) 'Expected: F'
write(*,*) list%get(list_end)
write(*,*) 'Expected: (nothing)'
write(*,*) list%get(list_end+1)

call list%destroy
call list%insert( 1, ["AA", "BA", "CA", "AA", "BA", "CA"] )
write(*,*) 'Expected: 1'
write(*,*) list%index("AA")
write(*,*) 'Expected: 4'
write(*,*) list%index("AA", .true.)
write(*,*) 'Expected: 0'
write(*,*) list%index("XXXX")

write(*,*) 'Expected: 2'
write(*,*) list%index_sub("B")
write(*,*) 'Expected: 5'
write(*,*) list%index_sub("B", .true.)
write(*,*) 'Expected: 0'
write(*,*) list%index_sub("X")

write(*,*) 'Expected: 6', list%length()

sublist = list%range(1, 2)
write(*,*) 'Expected: AA, BA'
call print_list( sublist )

sublist = list%range(list_end-1, list_end+2)
write(*,*) 'Expected: BA, CA'
call print_list( sublist )

sublist = list%range(-1, 3)
write(*,*) 'Expected: AA, BA, CA'
call print_list( sublist )

contains
subroutine renew_list( list )
type(stringlist_type), intent(inout) :: list

call list%destroy
call list%insert( 1, "A" )
call list%insert( 2, "B" )
call list%insert( 3, "C" )
end subroutine renew_list

subroutine print_list( list )
type(stringlist_type), intent(in) :: list

write(*,*) list%length()

do i = 1,list%length()
write(*,*) '>', list%get(i), '<'
enddo
end subroutine print_list

end program test_find
91 changes: 91 additions & 0 deletions src/tests/stringlist/test_insert.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
! test_insert.f90 --
! Test the insertion routine
!
program test_insertion
use stdlib_stringlist

type(stringlist_type) :: list, second_list
character(len=10), dimension(3) :: sarray


call list%insert( 1, "C" )
call list%insert( 1, "B" )
call list%insert( 1, "A" )

write(*,*) 'Expected: A, B, C (3)'
call print_list( list )

call list%insert( 6, "D" )

write(*,*) 'Expected: A, B, C, D (4)'
call print_list( list )

call list%insert( -1, "X" )

write(*,*) 'Expected: X, A, B, C, D (5)'
call print_list( list )

call list%insert( list_end-1, "Y" )

write(*,*) 'Expected: X, A, B, Y, C, D (6)'
call print_list( list )

call list%insert( list_end+1, "Z" )

write(*,*) 'Expected: X, A, B, Y, C, D, Z (7)'
call print_list( list )

!
! Try inserting a second list
!
call renew_list( list )

call second_list%insert( 1, "SecondA" )
call second_list%insert( 2, "SecondB" )

call list%insert( 2, second_list )
call print_list( list )

call renew_list( list )

call list%insert( list_after_end, second_list )
call print_list( list )

!
! Try inserting an array
!
call renew_list( list )

sarray(1) = "ThirdA"
sarray(2) = "ThirdB"
sarray(3) = "ThirdC"

call list%insert( list_head, sarray )
call print_list( list )

call renew_list( list )

call list%insert( 2, sarray )
call print_list( list )

contains
subroutine renew_list( list )
type(stringlist_type), intent(inout) :: list

call list%destroy
call list%insert( 1, "A" )
call list%insert( 2, "B" )
call list%insert( 3, "C" )
end subroutine renew_list

subroutine print_list( list )
type(stringlist_type), intent(in) :: list

write(*,*) list%length()

do i = 1,list%length()
write(*,*) '>', list%get(i), '<'
enddo
end subroutine print_list

end program test_insertion
88 changes: 88 additions & 0 deletions src/tests/stringlist/test_replace_append.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
! test_replace_append.f90 --
! Test the replace and append routines
!
program test_replace_append
use stdlib_stringlist

type(stringlist_type) :: list, newlist

call list%insert( 1, ["A", "B", "C", "D", "E", "F"] )

newlist = 'Long string' // list

write(*,*) 'Expected: "Long string, A, B, C, D, E, F (7)'
call print_list( newlist )

newlist = list // 'Long string'

write(*,*) 'Expected: A, B, C, D, E, F, "Long string" (7)'
call print_list( newlist )

newlist = list // list

write(*,*) 'Expected: A, B, C, D, E, F (twice, 12 elements)'
call print_list( newlist )

newlist = ['AA', 'BB'] // list
write(*,*) 'Expected: AA, BB, A, B, C, D, E, F (8)'
call print_list( newlist )

newlist = list // ['AA', 'BB']
write(*,*) 'Expected: A, B, C, D, E, F, AA, BB (8)'
call print_list( newlist )

!
! Replace ... quite a variety
!
newlist = list
call newlist%replace( 1, "New string" )
write(*,*) 'Expected: "New string", B, C, D, E, F (6)'
call print_list( newlist )

newlist = list
call newlist%replace( list_head, "New string" )
write(*,*) 'Expected: "New string", B, C, D, E, F (6)'
call print_list( newlist )

newlist = list
call newlist%replace( list_end, "New string" )
write(*,*) 'Expected: A, B, C, D, E, F, "New string" (6)'
call print_list( newlist )

newlist = list
call newlist%replace( 5, list_end, "X" )
write(*,*) 'Expected: A, B, C, D, X (5)'
call print_list( newlist )

newlist = list
call newlist%replace( 5, list_end-2, "X" )
write(*,*) 'Expected: A, B, C, D, E, F (6 - no change)'
call print_list( newlist )

newlist = list
call newlist%replace( 1, 2, ["WW", "XX", "YY", "ZZ"] )
write(*,*) 'Expected: WW, XX, YY, ZZ, C, D, E, F (8)'
call print_list( newlist )

newlist = list
call newlist%replace( list_end-1, list_end, ["WW", "XX", "YY", "ZZ"] )
write(*,*) 'Expected: A, B, C, D, WW, XX, YY, ZZ (8)'
call print_list( newlist )

newlist = list
call newlist%replace( list_end-1, list_end, list )
write(*,*) 'Expected: A, B, C, D, A, B, C, D, E, F (10)'
call print_list( newlist )

contains
subroutine print_list( list )
type(stringlist_type), intent(in) :: list

write(*,*) list%length()

do i = 1,list%length()
write(*,*) '>', list%get(i), '<'
enddo
end subroutine print_list

end program test_replace_append
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ add_subdirectory(hash_functions_perf)
add_subdirectory(hashmaps)
add_subdirectory(io)
add_subdirectory(linalg)
add_subdirectory(linked_list)
add_subdirectory(logger)
add_subdirectory(optval)
add_subdirectory(selection)
2 changes: 2 additions & 0 deletions test/linked_list/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ADDTEST(performance)
ADDTEST(linked_list)
781 changes: 781 additions & 0 deletions test/linked_list/test_linked_list.f90

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions test/linked_list/test_performance.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
program test_link
use stdlib_linked_list
implicit none

type struct
integer:: a=1,b=2,c=3
double precision::d=5
end type struct
type(struct) :: Vel2

type vector
double precision, dimension(3):: vec
end type vector
type(vector) ::Vel

type(linked_list_type) :: L
integer :: i,j,length
real :: T1,T2,F, r
integer :: cnt1, cnt2, count_rate

class(*), pointer :: data

do i=1,size(Vel%vec)
Vel%vec(i) = i
end do
! !-------------
! !Append items
! !-------------
print*, "Length Of Required List"
!read(*,*) length
length = 1000000

call system_clock( cnt1, count_rate = count_rate )
call cpu_time(T1)
do i=1,length
call L%push(i)
end do
call cpu_time(T2)
call system_clock( cnt2, count_rate = count_rate )
i = 1

write(*,*) T2-T1, (cnt2 - cnt1)/real(count_rate)

call system_clock( cnt1, count_rate = count_rate )
call cpu_time(T1)
do while (i<=100)
call random_number( r )
j = r*length
data => L%get(j)
select type (data)
type is (integer)
end select
i = i+1
end do
call cpu_time(T2)
call system_clock( cnt2, count_rate = count_rate )

write(*,*) (T2-T1), (cnt2 - cnt1)/real(count_rate)
write(*,*)'Done'

!-------------
!Destroy the list and frees the memmory
!-------------
call system_clock( cnt1, count_rate = count_rate )
call cpu_time(T1)
call L%clear()
call cpu_time(T2)
call system_clock( cnt2, count_rate = count_rate )

write(*,*) T2-T1, (cnt2 - cnt1)/real(count_rate)

end program test_link