list.f90 Source File

Source Code

!
!  list.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 list_mod
  !* Author: Chris MacMackin
  !  Date: March 2016
  !  License: LGPLv3
  !
  ! Provides an abstract data type representing a list. This interface
  ! provides a derived type with many of the same abilities as lists in
  ! higher-level languages such as Python.
  !
  use deque_mod, only: deque
  use abstract_container_mod, only: container, test_func, &
                                    addition_func, subtraction_func, &
                                    comparison_func,  action_sub
  implicit none
  private
  
  type, abstract, extends(deque), public :: list
    !* Author: Chris MacMackin
    !  Date: March 2016
    !
    ! An abstract data type representing a list. This is a fully dynamic
    ! means of storing data of a single type and comes with many advanced
    ! type-bound procedures for manipulating said data. This derived type
    ! aims to provide many of the same features found in lists in 
    ! higher-level languages such as Python
    !
  contains
    procedure(append_sub), deferred :: append
      !! Add an item to the end of the list
    procedure(get_func), deferred :: get
      !! Get the item at the specified index
    procedure(set_single_sub), deferred, private :: set_single
      !! Set the specified element to the specified value
    procedure(set_multiple_sub), deferred, private :: set_multiple
      !! Set the specified elements to the specified values
    generic :: set => set_single, set_multiple
      !! Set the value of one or more elements in the list
    procedure(get_index_func), deferred :: get_index
      !! Get the index of the first occurrence of this item in the list
    procedure(get_last_index_func), deferred :: get_last_index
      !! Get the index of the last occurrence of this item in the list
    procedure(get_indices_func), deferred :: get_indices
      !! Get the indices of all occurrences of this item in the list
    procedure(slice_func), deferred :: slice
      !! Returns a list containing the items with indices in the
      !! specified range
    procedure(foreach_sub), deferred :: foreach
      !! Perform the provided procedure on each element of the list
    procedure(insert_sub), deferred :: insert
      !! Add the item to the specified position in the list, moving
      !! all succeeding elements forward by one position
    procedure(remove_sub), deferred :: remove
      !! Remove the first occurrence of the specified item from the list
    procedure(remove_last_sub), deferred :: remove_last
      !! Remove the last occurrence of the specified item from the list
    procedure(remove_all_sub), deferred :: remove_all
      !! Remove the all occurrences of the specified item from the list
    procedure(delete_single_sub), deferred, private :: delete_single
      !! Remove the item from the list at the specified index
    procedure(delete_multiple_sub), deferred, private :: delete_multiple
      !! Remove the items from the list at the specified indices
    procedure(delete_slice_sub), deferred, private :: delete_slice
      !! Remove the items from the list within the specified slice
    generic :: delete => delete_single, delete_multiple, delete_slice
      !! Remove one or more elements from the list
    procedure(has_func), deferred :: has
      !! Returns `.true.` if the specified item is present in the list.
    procedure(sort_sub), deferred :: sort
      !! Sorts the list in place using the provided comparison procedure
    procedure(min_func), deferred :: min
      !! Returns the smallest item in the list as determined using the
      !! provided comparison procedure
    procedure(max_func), deferred :: max
      !! Returns the largest item in the list as determined using the
      !! provided comparison procedure
    procedure(nearest_func), deferred :: nearest
      !! Returns the item in the list for which the provided subtraction
      !! procedure returns the smallest absolute value
    procedure(sum_func), deferred :: sum
      !! Returns an item representing the sum as determined by
      !! iteratively applying the provided addition procedure to all
      !! elements in the list
    procedure(filter_func), deferred :: filter
      !! Returns a list containing all elements from this list for which
      !! the provided test procedure returns `.true.`
    procedure(to_array_func), deferred :: to_array
      !! Returns an array of containers holding the contents of this
      !! list.
  end type list

  abstract interface
    subroutine append_sub(this, item)
      import :: list
      class(list), intent(inout) :: this
      class(*), intent(in) :: item !! Item to be appended to list
    end subroutine append_sub
  
    pure function get_func(this, element)
      import :: list
      import :: container
      class(list), intent(in) :: this
      integer, intent(in) :: element
        !! The index (starting from 1) of the element to return
      class(container), allocatable :: get_func
        !! The item with index `element`
    end function get_func
    
    subroutine set_single_sub(this, element, item)
      import :: list
      class(list), intent(inout) :: this
      integer, intent(in) :: element
        !! The index (starting from 1) of the element whose value is to be set.
      class(*), intent(in) :: item
        !! The value to store in the specified element
    end subroutine set_single_sub
    
    subroutine set_multiple_sub(this, elements, items)
      import :: list
      class(list), intent(inout) :: this
      integer, dimension(:), intent(in) :: elements
        !! The indices (starting from 1) of the elements whose values 
        !! are to be set.
      class(*), dimension(:), intent(in) :: items
        !! The values to be stored in the specified elements. Each item
        !! is placed in the element specified by the integer in the
        !! corresponding position in the array `elements`.
    end subroutine set_multiple_sub
    
    pure function get_index_func(this, item)
      import :: list
      class(list), intent(in) :: this
      class(*), intent(in) :: item
      integer :: get_index_func
        !! Position of the first occurrence of `item` in list
    end function get_index_func
    
    pure function get_last_index_func(this, item)
      import :: list
      class(list), intent(in) :: this
      class(*), intent(in) :: item
      integer :: get_last_index_func
        !! Position of the last occurrence of `item` in list
    end function get_last_index_func
    
    pure function get_indices_func(this, item)
      import :: list
      class(list), intent(in) :: this
      class(*), intent(in) :: item
      integer, dimension(:), allocatable :: get_indices_func
        !! Positions of the all occurrences of `item` in list
    end function get_indices_func
    
    function slice_func(this, start_element, end_element)
      import :: list
      class(list), intent(in) :: this
      integer, intent(in) :: start_element
        !! The index of the first element in the slice to be returned
      integer, intent(in) :: end_element
        !! The index of the last element in the slice to be returned
      class(list), allocatable :: slice_func
        !! A list containing the elements within the slice.
    end function slice_func
    
    subroutine foreach_sub(this, action)
      import :: list
      import :: action_sub
      class(list), intent(inout) :: this
      procedure(action_sub) :: action
        !! A procedure to act on each element of the list
    end subroutine foreach_sub
    
    subroutine insert_sub(this, position, item)
      import :: list
      class(list), intent(inout) :: this
      integer, intent(in) :: position
        !! The location at which the new element will be placed
      class(*), intent(in) :: item
        !! The value to be placed in the list
    end subroutine insert_sub
    
    subroutine remove_sub(this, item)
      import :: list
      class(list), intent(inout) :: this
      class(*), intent(in) :: item
        !! An item, the first occurrence of which will be removed from
        !! the list
    end subroutine remove_sub
    
    subroutine remove_last_sub(this, item)
      import :: list
      class(list), intent(inout) :: this
      class(*), intent(in) :: item
        !! An item, the last occurrence of which will be removed from
        !! the list
    end subroutine remove_last_sub
    
    subroutine remove_all_sub(this, item)
      import :: list
      class(list), intent(inout) :: this
      class(*), intent(in) :: item
        !! An item, all occurrences of which will be removed from the
        !! list
    end subroutine remove_all_sub
    
    subroutine delete_single_sub(this, element)
      import :: list
      class(list), intent(inout) :: this
      integer, intent(in) :: element
        !! The position of the element to be deleted from the list
    end subroutine delete_single_sub
    
    subroutine delete_multiple_sub(this, element)
      import :: list
      class(list), intent(inout) :: this
      integer, dimension(:), intent(in) :: element
        !! The positions of the elements to be deleted from the list
    end subroutine delete_multiple_sub
    
    subroutine delete_slice_sub(this, start_element, end_element)
      import :: list
      class(list), intent(inout) :: this
      integer, intent(in) :: start_element
        !! Index of the first element in the slice to be deleted
      integer, intent(in) :: end_element
        !! Index of the last element in the slice to be deleted
    end subroutine delete_slice_sub
    
    elemental function has_func(this, item)
      import :: list
      class(list), intent(in) :: this
      class(*), intent(in) :: item
        !! A value whose presence in the list is being checked for
      logical :: has_func
        !! `.true.` if `item` is present in list, `.false.` otherwise
    end function has_func
        
    subroutine sort_sub(this, comparison)
      import :: list
      import :: comparison_func
      class(list), intent(inout) :: this
      procedure(comparison_func) :: comparison
        !! A procedure which evaluates whether a [[container]] object is
        !! less than, equal to, or greater than another
    end subroutine sort_sub
    
    pure function min_func(this, comparison)
      import :: list
      import :: comparison_func
      import :: container
      class(list), intent(in) :: this
      procedure(comparison_func) :: comparison
        !! A procedure which evaluates whether a [[container]] object is
        !! less than, equal to, or greater than another    
      class(container), allocatable :: min_func
        !! The smallest item in the list, as determined by the
        !! `comparison` function
    end function min_func
 
    pure function max_func(this, comparison)
      import :: list
      import :: comparison_func
      import :: container
      class(list), intent(in) :: this
      procedure(comparison_func) :: comparison
        !! A procedure which evaluates whether a [[container]] object is
        !! less than, equal to, or greater than another    
      class(container), allocatable :: max_func
        !! The largest item in the list, as determined by the
        !! `comparison` function
    end function max_func
    
    pure function nearest_func(this, item, subtraction)
      import :: list
      import :: container
      import :: subtraction_func
      class(list), intent(in) :: this
      class(*), intent(in) :: item
        !! The value which those in the list are being compared to
      procedure(subtraction_func) :: subtraction
        !! A function determining the magnitude of the difference
        !! between two items
      class(container), allocatable :: nearest_func
        !! The value from the list which, when passed to `subtraction`
        !! with `item` as the other argument, returns the smallest value
    end function nearest_func
    
    pure function sum_func(this, addition)
      import :: list
      import :: container
      import :: addition_func
      class(list), intent(in) :: this
      procedure(addition_func) :: addition
        !! A procedure performing addition between two [[container]]
        !! objects and returning the result in another container
      class(container), allocatable :: sum_func
        !! A container holding the sum of all of the items held within
        !! this list
    end function sum_func

    pure function filter_func(this, test)
      import :: list
      import :: test_func
      class(list), intent(in) :: this
      procedure(test_func) :: test
        !! A test for which the values that pass will be returned in a
        !! new list
      class(list), allocatable :: filter_func
        !! Contains those items in this list for which `test` returns
        !! `.true.`
    end function filter_func

    pure function to_array_func(this)
      import :: list
      import :: container
      class(list), intent(in) :: this
      class(container), dimension(:), allocatable :: to_array_func
        !! An array of [[container]] objects holding the contents of
        !! this list
    end function to_array_func
  end interface
  
end module list_mod