! { dg-do run } ! ! Contributed by by Richard Maine ! http://coding.derkeiler.com/Archive/Fortran/comp.lang.fortran/2006-10/msg00104.html ! module poly_list !-- Polymorphic lists using type extension. implicit none type, public :: node_type private class(node_type), pointer :: next => null() end type node_type type, public :: list_type private class(node_type), pointer :: head => null(), tail => null() end type list_type contains subroutine append_node (list, new_node) !-- Append a node to a list. !-- Caller is responsible for allocating the node. !---------- interface. type(list_type), intent(inout) :: list class(node_type), target :: new_node !---------- executable code. if (.not.associated(list%head)) list%head => new_node if (associated(list%tail)) list%tail%next => new_node list%tail => new_node return end subroutine append_node function first_node (list) !-- Get the first node of a list. !---------- interface. type(list_type), intent(in) :: list class(node_type), pointer :: first_node !---------- executable code. first_node => list%head return end function first_node function next_node (node) !-- Step to the next node of a list. !---------- interface. class(node_type), target :: node class(node_type), pointer :: next_node !---------- executable code. next_node => node%next return end function next_node subroutine destroy_list (list) !-- Delete (and deallocate) all the nodes of a list. !---------- interface. type(list_type), intent(inout) :: list !---------- local. class(node_type), pointer :: node, next !---------- executable code. node => list%head do while (associated(node)) next => node%next deallocate(node) node => next end do nullify(list%head, list%tail) return end subroutine destroy_list end module poly_list program main use poly_list implicit none integer :: cnt type, extends(node_type) :: real_node_type real :: x end type real_node_type type, extends(node_type) :: integer_node_type integer :: i end type integer_node_type type, extends(node_type) :: character_node_type character(1) :: c end type character_node_type type(list_type) :: list class(node_type), pointer :: node type(integer_node_type), pointer :: integer_node type(real_node_type), pointer :: real_node type(character_node_type), pointer :: character_node !---------- executable code. !----- Build the list. allocate(real_node) real_node%x = 1.23 call append_node(list, real_node) allocate(integer_node) integer_node%i = 42 call append_node(list, integer_node) allocate(node) call append_node(list, node) allocate(character_node) character_node%c = "z" call append_node(list, character_node) allocate(real_node) real_node%x = 4.56 call append_node(list, real_node) !----- Retrieve from it. node => first_node(list) cnt = 0 do while (associated(node)) cnt = cnt + 1 select type (node) type is (real_node_type) write (*,*) node%x if (.not.( (cnt == 1 .and. node%x == 1.23) & .or. (cnt == 5 .and. node%x == 4.56))) then call abort() end if type is (integer_node_type) write (*,*) node%i if (cnt /= 2 .or. node%i /= 42) call abort() type is (node_type) write (*,*) "Node with no data." if (cnt /= 3) call abort() class default Write (*,*) "Some other node type." if (cnt /= 4) call abort() end select node => next_node(node) end do if (cnt /= 5) call abort() call destroy_list(list) stop end program main