linked_node.f90 Source File

Source Code

!
!  linked_node.f90
!  This file is part of FIAT.
!
!  Copyright 2016 Christopher MacMackin <cmacmackin@gmail.com>
!  
!  This program is free software; you can redistribute it and/or modify
!  it under the terms of the GNU Lesser General Public License as
!  published by the Free Software Foundation; either version 3 of the 
!  License, or (at your option) any later version.
!  
!  This program is distributed in the hope that it will be useful,
!  but WITHOUT ANY WARRANTY; without even the implied warranty of
!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
!  GNU Lesser General Public License for more details.
!  
!  You should have received a copy of the GNU Lesser General Public
!  License along with this program; if not, write to the Free Software
!  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
!  MA 02110-1301, USA.
!  

module linked_node_mod
  !* Author: Chris MacMackin
  !  Date: February 2016
  !  License: LGPLv3
  !
  ! Implements a node which contains a pointer to another (the next) 
  ! node, allowing a chain to be formed. This can be used to, for
  ! example, build linked lists.
  ! 
  ! It is not anticipated that the linked_node type, or any types 
  ! extending it, will be handled directly by end users of FIAT; they 
  ! are meant for internal use within this package.
  !
  use node_mod, only: node
  implicit none
  private
  
  type, extends(node), public :: linked_node
    !* Author: Chris MacMackin
    !  Date: February 2016
    !
    ! A node which, in addition to holding a value, points at another
    ! (the next) linked_node or descendent type. This type can be built
    ! up into a chain, allowing a linked list to be formed.
    ! 
    ! It is not anticipated that the linked_node type, or any types 
    ! extending it, will be handled directly by end users of FIAT; they 
    ! are meant for internal use within this package. As such, care must
    ! be taken when using certain methods (see below) to avoid memory
    ! leaks or segfaults.
    !
    private
    class(linked_node), pointer :: next => null() !! The next node in the chain.
  contains
    procedure :: has_next
      !! Checks whether this node points to another one 
    procedure :: get_next
      !! Returns the next node in the chain if it exists.
    procedure :: set_next
      !! Sets the next node in the chain.
    procedure :: unset_next
      !! Sets this node not to point at any others, severing the chain.
  end type linked_node

contains

  elemental logical function has_next(this)
    !* Author: Chris MacMackin
    !  Date: February 2016
    !  
    ! Returns whether or not this node points at another one, forming
    ! a chain.
    !
    class(linked_node), intent(in) :: this
    has_next = associated(this%next)
  end function has_next
  
  function get_next(this)
    !* Author: Chris MacMackin
    !  Date: February 2016
    !
    ! Returns a pointer to the node which this ones points to, i.e. the
    ! next node in the chain. If this node does not point at another 
    ! one, then a null pointer is returned.
    !
    class(linked_node), intent(in) :: this
    class(linked_node), pointer :: get_next
    if (this%has_next()) then
      get_next => this%next
    else
      get_next => null()
    end if
  end function get_next
  
  subroutine set_next(this, new_next, deallocate_old)
    !* Author: Chris MacMackin
    !  Date: February 2016
    !
    ! Sets the node which this one points to (i.e. sets the next node in
    ! the chain). If this node already points to another one, the 
    ! pointer will, by default, be nullified. This may result in a
    ! memory leak. Optionally, by setting `deallocate_old=.true.`, the
    ! next node (and all nodes it points to) can be deallocated. This
    ! may result in a segfault if another part of the program tries to
    ! access the former next node.
    !
    class(linked_node), intent(inout) :: this
    class(linked_node), pointer, intent(in) :: new_next
      !! The node which will now be next in the chain.
    logical, optional, intent(in) :: deallocate_old
      !! Whether to deallocate (rather than just nullify) any existing
      !! subsequent nodes in the chain. Defaults to `.false.`.
    call this%unset_next(deallocate_old)
    this%next => new_next
  end subroutine set_next
  
  subroutine unset_next(this, deallocate_old)
    !* Author: Chris MacMackin
    !  Date: February 2016
    ! 
    ! Unsets the pointer to the next node in the chain, severing it.
    ! By default, the pointer is only nullified. This may result in a
    ! memory leak. Optionally, by setting `deallocate_old=.true.`, the
    ! next node (and all nodes it points to) can be deallocated. This
    ! may result in a segfault if another part of the program tries to
    ! access the former next node.
    !
    class(linked_node), intent(inout) :: this
    logical, optional, intent(in) :: deallocate_old
      !! Whether to deallocate (rather than just nullify) any existing
      !! subsequent nodes in the chain. Defaults to `.false.`.
    if (.not. this%has_next()) return
    if (present(deallocate_old)) then
      if (deallocate_old) then
        call this%next%unset_next(.true.)
        deallocate(this%next)
        return
      end if
    end if
    nullify(this%next)
  end subroutine unset_next

end module linked_node_mod