Maps in Fortran

Maps are Fortran’s built-in associative data type (sometimes called hashes or dicts in other languages).

To create an empty map, use the allocate keyword along with type(hashmap).

program main
    use, intrinsic :: iso_fortran_env, only: int8
    implicit none
    type :: hashmap
        character(len=:), allocatable :: key(:)
        integer(int8) :: val(:)
    end type hashmap

    type(hashmap) :: m

    allocate(character(len=10) :: m%key(0))
    allocate(m%val(0))

    call set(m, 'k1', 7)
    call set(m, 'k2', 13)

    call print_map(m)

    call get(m, 'k1')
    call get(m, 'k3')

    call remove(m, 'k2')
    call print_map(m)

    call clear(m)
    call print_map(m)

    deallocate(m%key, m%val)
end program main

contains

    subroutine set(map, key, val)
        type(hashmap), intent(inout) :: map
        character(len=10), intent(in) :: key
        integer(int8), intent(in) :: val
        allocate(map%key(size(map%key)+1))
        allocate(map%val(size(map%val)+1))
        map%key(size(map%key)) = key
        map%val(size(map%val)) = val
    end subroutine set

    subroutine get(map, key)
        type(hashmap), intent(in) :: map
        character(len=10), intent(in) :: key
        integer :: i
        i = index(key, map%key)
        if (i > 0) then
            print *, 'v:', map%val(i)
        else
            print *, 'v: 0'
        end if
    end subroutine get

    subroutine remove(map, key)
        type(hashmap), intent(inout) :: map
        character(len=10), intent(in) :: key
        integer :: i
        i = index(key, map%key)
        if (i > 0) then
            map%key(i:) = map%key(i+1:)
            map%val(i:) = map%val(i+1:)
            allocate(map%key(size(map%key)-1))
            allocate(map%val(size(map%val)-1))
        end if
    end subroutine remove

    subroutine clear(map)
        type(hashmap), intent(inout) :: map
        deallocate(map%key, map%val)
        allocate(map%key(0))
        allocate(map%val(0))
    end subroutine clear

    subroutine print_map(map)
        type(hashmap), intent(in) :: map
        integer :: i
        do i=1, size(map%key)
            print *, 'map: ', map%key(i), map%val(i)
        end do
    end subroutine print_map

    integer function index(key, arr)
        character(len=10), intent(in) :: key(:), arr(:)
        integer :: i
        index = 0
        do i = 1, size(arr)
            if (trim(arr(i)) == trim(key)) then
                index = i
                return
            end if
        end do
    end function index

end

In the above Fortran code:

  • A derived type hashmap is created to hold the key-value pairs.
  • The main program initializes an empty map and demonstrates various operations including setting key-value pairs, getting values, printing the map, removing keys, and clearing the map.
  • Subroutines are used to perform map operations and ensure the code is modular and easier to follow.
  • The index function helps find the position of a key within the map to handle key-related operations efficiently.

To run the program, compile it using a Fortran compiler and execute the resulting binary.

$ gfortran -o map_example map_example.f90
$ ./map_example