Project

General

Profile

self_map.F90 Source File

Source Code

!>
!! Provides array-based, self-extending reference vectors of arbitrary type.
!!
module self_map

    use self_object
    use self_vector
    use self_vector_ref

    implicit none

    private

    type, extends(object) :: item
        class(*), allocatable :: key
        class(*), allocatable :: value
    contains
        procedure :: is_equal => is_equal_item
        procedure :: to_string => to_string_item
    end type

    type, extends(vector), public :: map
    contains
        procedure :: add_keyed_item
        generic :: add => add_keyed_item
        procedure :: get
        procedure :: keys
        procedure :: values
        procedure :: has
        procedure :: has_key
        procedure :: has_value
    end type
    interface map
        module procedure new_empty
    end interface map

contains

    !
    ! type(vector)
    !

    ! constructors

    function new_empty(verbose, initial_size) result(this)
        logical, optional, intent(in) :: verbose
        integer, optional, intent(in) :: initial_size
        type(map) :: this
        if(present(verbose) .and. verbose) print *, 'map%new_empty begin'
        this%vector = vector(verbose, initial_size)
        if(this%get_verbose()) print *, 'map%new_empty end'
    end function new_empty

    subroutine add_keyed_item(this, key, new_stuff)
        class(map),intent(inout) :: this
        class(*), intent(in) :: key
        class(*), intent(in) :: new_stuff
        integer :: idx
        class(*), pointer :: my_item_ptr
        type(item) :: my_item

        if(this%get_verbose()) print *, 'map%add_keyed_item begin'

        allocate(my_item%key, source=key)
        allocate(my_item%value, source=new_stuff)

        idx = this%find(my_item)
        if(idx > 0) then
            my_item_ptr => this%at(idx)
            select type(my_item_ptr)
                type is (item)
                    if(allocated(my_item_ptr%value)) then
                        deallocate(my_item_ptr%value)
                    end if
                    allocate(my_item_ptr%value, source=new_stuff)
#ifndef NDEBUG
                class default
                    write(0, '(*(g0))') 'Danger: invalid item in map'
#endif
            end select
        else
            call this%vector%add(my_item)
        end if

        if(this%get_verbose()) then
            print *, 'added to map (', this%length(), '/', &
                     this%capacity(), ' elements)'
        end if

        if(this%get_verbose()) print *, 'map%add_keyed_item end'
    end subroutine add_keyed_item

    function get(this, key)
        class(map), intent(inout) :: this
        class(*), intent(in) :: key
        class(*), pointer :: get
        class(*), pointer :: my_item_ptr
        type(item) :: my_item
        integer :: idx
        get => null()
        allocate(my_item%key, source=key)
        idx = this%find(my_item)
        if(idx > 0) then
            my_item_ptr => this%at(idx)
            select type(my_item_ptr)
                class is(item)
                    get => my_item_ptr%value
#ifndef NDEBUG
                class default
                    write(0, '(*(g0))') 'Danger: invalid item in map'
#endif
            end select
        end if
    end function get

    logical function is_equal_item(this, that) result(equal)
        class(item), intent(in) :: this
        class(*), intent(in) :: that
        select type(that)
            class is (item)
                equal = object_equal(this%key, that%key)
            class default
                equal = .false.
        end select
    end function is_equal_item

    function to_string_item(this)
        class(item), intent(in) :: this
        character(:), allocatable :: to_string_item
        to_string_item = "("//object_string(this%key)//","//object_string(this%value)//")"
    end function to_string_item

    function keys(this)
        class(map), intent(in)     :: this
        type(vector), allocatable :: keys

        type(vector_iterator) :: i
        class(*), pointer :: my_stuff

        allocate(keys, source=vector())

        i = this%iter()
        do while(i%next(my_stuff))
            select type(my_stuff)
            class is (item)
                call keys%add(my_stuff%key)
#ifndef NDEBUG
            class default
                write(0, '(*(g0))') 'Danger: invalid item in map'
#endif
            end select
        end do
    end function keys

    function values(this)
        class(map), intent(in) :: this
        type(vector), allocatable :: values

        type(vector_iterator) :: i
        class(*), pointer :: my_stuff

        allocate(values,source=vector())

        i = this%iter()
        do while(i%next(my_stuff))
            select type(my_stuff)
            class is (item)
                call values%add(my_stuff%value)
#ifndef NDEBUG
            class default
                write(0, '(*(g0))') 'Danger: invalid item in map'
#endif
            end select
        end do
    end function values

    logical function has(this,tag, tagType)
        class(map), intent(in) :: this
        class(*), intent(in) :: tag
        character(len=3), optional :: tagType ! key or val

        type(vector), allocatable :: tags
        character(len=3) :: myType

        if (present(tagType)) then
          myType = tagType
        else
          myType = 'key'
        endif

        if ('key' .eq. myType) then
          tags = this%keys()
        else
          tags = this%values()
        endif

        has = tags%includes(tag)
    end function has
    logical function has_key(this,tag)
        class(map), intent(in) :: this
        class(*), intent(in) :: tag

        has_key = this%has(tag,tagType='key')
    end function has_key
    logical function has_value(this, tag)
        class(map), intent(in) :: this
        class(*), intent(in) :: tag

        has_value = this%has(tag,tagType='val')
    end function has_value

end module self_map

© 2016
self was developed by
Documentation generated by FORD