• A question on reallocation

    From GianLuigi Piacentini@ggpiace@tin.it to comp.lang.fortran on Wed Nov 15 19:40:00 2023
    From Newsgroup: comp.lang.fortran

    Hi all,

    I have a perhaps silly question, that puzzles me before committing to
    write actual code.

    Please consider a data structure which is basically an array of arrays
    type element
    integer, allocatable :: element_core(:)
    end type
    ...
    type(elements), allocatable :: array_of_elements(:)
    ...
    allocate ( array_of_elements(some_size) )

    (this is not a matrix, each element may significantly differ in size,
    and someone may be long (and subjected to reallocation cycles, but his
    is plain reallocation).

    Now I have to increase size of previously allocated array_of_elements,
    using the usual pattern (at least I think it's usual)

    type(elements), allocatable :: tmp(:)

    allocate ( tmp(new_size) )
    tmp(1:some_size) = array_of_elements ! ***
    call move_alloc(from = tmp, to = array_of_elements)

    Seems to me that during the operation marked with the *** comment the
    various elements are also copied, and this seems vasteful.
    Is there a way to avoid such copying, if it really happens ?

    Perhaps making array_of_elements an array of pointers to allocated
    elements ?

    Thanks in advance
    Gigi Piacentini
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From gah4@gah@ugcs.caltech.edu to comp.lang.fortran on Wed Nov 15 20:19:01 2023
    From Newsgroup: comp.lang.fortran

    On 11/15/23 10:40 AM, GianLuigi Piacentini wrote:
    Hi all,

    I have a perhaps silly question, that puzzles me before committing to
    write actual code.

    Please consider a data structure which is basically an array of arrays
    type element
      integer, allocatable :: element_core(:)
    end type
    ...
    type(elements), allocatable :: array_of_elements(:)
    ...
    allocate ( array_of_elements(some_size) )

    (snip)

    type(elements), allocatable :: tmp(:)

    allocate ( tmp(new_size) )
    tmp(1:some_size) = array_of_elements                   ! ***
    call  move_alloc(from = tmp, to = array_of_elements)


    I think you want something like:

    allocate(tmp(new_size))

    do i=1, old_size
    call move_alloc(from=array_of_elements(i), to=tmp(i))
    end do

    call move_alloc(from = tmp, to = array_of_elements)

    So, move all the subarrays over, then move the array of arrays.

    Since only the, fairly small, array_of_elements is being reallocated,
    it should be pretty fast.

    Before move_alloc, you had to create a temporary, copy them over,
    reallocate the original one, and copy them back. Lots of copying!
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From =?UTF-8?Q?m=5Fb=5Fmetcalf?=@michaelmetcalf@compuserve.com to comp.lang.fortran on Sat Nov 18 09:29:31 2023
    From Newsgroup: comp.lang.fortran

    GianLuigi,

    Does this do what you wanted?

    Mike

    P.S. This is also for me a trial posting using nemoweb.

    type elements
    integer, allocatable :: element_core(:)
    end type

    type(elements), allocatable :: array_of_elements(:)

    type(elements), allocatable :: tmp(:)

    allocate ( array_of_elements(3) )

    allocate(array_of_elements(3)%element_core(3))

    array_of_elements(3)%element_core(3) = 3


    allocate ( tmp(4) )

    call move_alloc(from=array_of_elements(1:3), to=tmp(1:3)) !<------

    call move_alloc(from = tmp, to = array_of_elements)
    print*, array_of_elements(3)%element_core(3)
    end


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From GianLuigi Piacentini@ggpiace@tin.it to comp.lang.fortran on Mon Nov 20 01:10:41 2023
    From Newsgroup: comp.lang.fortran

    On 15/11/23 19:40, GianLuigi Piacentini wrote:
    Hi all,

    I have a perhaps silly question, that puzzles me before committing to
    write actual code.

    Please consider a data structure which is basically an array of arrays
    type element
      integer, allocatable :: element_core(:)
    end type
    ...
    type(elements), allocatable :: array_of_elements(:)
    ...
    allocate ( array_of_elements(some_size) )

    (this is not a matrix, each element may significantly differ in size,
    and someone may be long (and subjected to reallocation cycles, but his
    is plain reallocation).

    Now I have to increase size of previously allocated array_of_elements,
    using the usual pattern (at least I think it's usual)

    type(elements), allocatable :: tmp(:)

    allocate ( tmp(new_size) )
    tmp(1:some_size) = array_of_elements                   ! ***
    call  move_alloc(from = tmp, to = array_of_elements)

    Seems to me that during the operation marked with the *** comment the various elements are also copied, and this seems vasteful.
    Is there a way to avoid such copying, if it really happens ?

    Perhaps making array_of_elements an array of pointers to allocated
    elements ?

    Thanks in advance
    Gigi Piacentini
    Thanks to all replier.

    I ewconsidered the problem in light of the whole project, coming with 2 possible solutions:

    1) since data come from analysis of several files, which do not change
    during program execution, I can do a 1st pass counting dimensions, then allocate, then do a 2nd pass reading data into the data structure.

    2) as suggested, I could do
    type element
    integer, allocatable :: element_core(:) ! an array of integers
    end type
    type element_pointer
    type(element), pointer :: e_p => null() ! pointer to the above
    end type element_pointer

    type(element_pointer), allocatable :: array_of_elements(:)

    allocate( array_of_elements(3) ) ! an array of 3 pointers
    do i = 1, size(array_of_elements)
    allocate (array_of_elements(i)%e_p%element_core(n))
    ! where n is the size required for the ith array of integers
    end do
    ... ! loading integers

    Now when reallocating

    type(element_pointer), allocatable :: tmp(:)

    allocate( tmp(new size for array of array of integers) )

    ! copying pointers:
    tmp(1:size(array_of_elements))%e_p => array_of_elements%e_p
    ! during this copy, in my intention, the underlying element_cores will
    not be moved
    call move_alloc (from = tmp, to = array_of_elements)

    However, at the moment I cannot test the above machinery, I will do it
    as soon as I can restart my hobby project, which will happen in some days.
    But I am still interested in the subject, and in your comments, if any.

    Thanks
    Gigi


    --- Synchronet 3.20a-Linux NewsLink 1.114