Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No error stat when a table is missing #117

Open
fedebenelli opened this issue Jan 7, 2023 · 2 comments
Open

No error stat when a table is missing #117

fedebenelli opened this issue Jan 7, 2023 · 2 comments
Labels
documentation Improvements or additions to documentation

Comments

@fedebenelli
Copy link

Hello!
I'm learning this library to start using it on my projects to substitute old (unreadable) input files, and toml seems like the best format to use. Thank you for developing this! It can be really useful and improve both mine and my research fellows sanity

I have a simple example toml file like this:

[system]
model = "PengRobinson"
T = 250
components = ["methane", "ethane"]

[methane]
Tc = 190

And my main program is:

program main
  use tomlf, only : toml_table, toml_array, toml_key, get_value, len
  use tomlf_de, only: toml_load

  implicit none

  character(len=:), allocatable :: input_string

  type(toml_table), allocatable :: table
  type(toml_table), pointer :: system, component

  type(toml_array), pointer :: components_list

  character(len=:), allocatable :: name

  real(8) :: tc

  integer :: stat, i

  ! Load toml data into a table variable
  call toml_load(table, "input.toml")

  ! Extract table "system"
  call get_value(table, "system", system, stat=stat)

  ! Read all the components inside "system"
  call get_value(system, "components", components_list, stat=stat)

  ! Read each component table
  do i = 1, len(components_list)
    ! Get the component name
    call get_value(components_list, i, name)

    ! Open the component table
    call get_value(table, name, component, stat=stat)

   ! If stat != 0 => look for a "<name>.toml" file and retry

    ! Get the desired data
    call get_value(component, "Tc", tc)

    print *, name, tc
  end do

 end program main

This is just a practice example, not my final usage. But on the future I want to have the possibility to either have my data in the main input toml file, and if there is a missing table look for a individual toml file. In this simple example I do have the data of methane, but not of ethane and I should look for an "ethane.toml" file.

I was thinking that the "stat" argument will give a value != 0 if the table couldn't be found, but that doesn't seem to be the case. Or I'm interpreting something wrong.

How could I check if a table is present in the toml file? I've looked for it on the documentation but couldn't find anything. I think maybe some really basic examples are needed, I could collaborate with that once I understand how to use the library properly

@awvwgk
Copy link
Member

awvwgk commented Jan 7, 2023

TOML Fortrans getter interface by default will eagerly create values which are absent, if you request a table and its key is not in use the table will be created and the pointer associated to it. In most cases that is what you would manually do if you find an entry is missing when reading values from a config file anyway, so it is the default. It has the advantage that serializing the root table afterwards reflects the full configuration as seen by the program.

You can add the requested=.false. argument to not create a table if it is not present, you then can check by associated(ptr) whether the table is actually present and insert your custom logic to populate the table pointer.

This should do more or less what you are looking for:

module demo
   use tomlf
   implicit none

   type :: component_type
      character(:), allocatable :: name
      integer :: val
   end type component_type

   type :: system_type
      type(component_type), allocatable :: component(:)
   end type system_type

contains

subroutine load_main(system, table, stat)
   type(system_type), intent(out) :: system
   type(toml_table), intent(inout) :: table
   integer, intent(out) :: stat

   type(toml_table), allocatable, target :: extern
   type(toml_table), pointer :: child
   type(toml_array), pointer :: array
   integer :: icomp

   call get_value(table, "system", child, stat=stat)
   if (stat /= toml_stat%success) return

   call get_value(child, "components", array, stat=stat)
   if (stat /= toml_stat%success) return

   allocate(system%component(len(array)))
   do icomp = 1, size(system%component)
      call get_value(array, icomp, system%component(icomp)%name, stat=stat)
      if (stat /= toml_stat%success) return
   end do

   do icomp = 1, size(system%component)
      associate(component => system%component(icomp))
         call get_value(table, component%name, child, &
            & requested=.false., stat=stat)
         if (stat /= toml_stat%success) return

         ! If component table is not provided fallback to read it from extra file
         if (.not.associated(child)) then
            call toml_load(extern, component%name // ".toml")
            if (.not.allocated(extern)) then
               stat = toml_stat%fatal
               return
            end if
            child => extern
         end if

         call get_value(child, "value", component%val, stat=stat)
         if (stat /= toml_stat%success) return
      end associate
   end do

end subroutine load_main

end module demo

@awvwgk awvwgk added the documentation Improvements or additions to documentation label Jan 7, 2023
@awvwgk
Copy link
Member

awvwgk commented Jan 7, 2023

Presence of entries has been asked for a few times (#115, #110), so it might be good to have a how-to recipe on this case. Personally, I think with a carefully designed layout in the configuration file, checking for presence should never seldom be necessary, but there are of course edge cases where it can be useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants