From: GianLuigi Piacentini on
Richard Maine wrote:

> Hifi-Comp <wenbinyu.heaven(a)gmail.com> wrote:
>
>> I am thinking to create a user data type containing an array with
>> dimensions decided in running time.
>>
>> Currently I have the following:
>>
>> INTEGER,PARAMETER:: n=3
>>
>> TYPE,PUBLIC:: User_Data
>> REAL(DBL_AD)::scale
>> REAL(DBL_AD)::vector(n)
>> END TYPE User_Data
>>
>> I guess I need to use pointers.
>
> Allocatables are far better. Pointers can be twisted into doing the
> trick, but it is a hack, and has hackish consequences (that things won't
> work intuitively). Pointers are basically for... pointing. Allocatables
> are for allocating. You do need iether f95+TR or f2003 for allocatable
> components, but most compilers have f95+TR these days.
>
> As in, change your vector component declaration to
>
> real(dbl_ad), allocatable :: vector(:)
>
> Then if x is a variable of type user_data, do
>
> allocate(x%vector(whatever_size_you need))
>
> or use any other method of allocating allocatables (such as the f2003
> allocate-on-assignment or the move_alloc intrinsic).
>
May be slightly out of topic, but wanting a reallocatable array I preferred
pointer arrays like
REAL, POINTER :: data_array(:) => NULL()
REAL, POINTER :: temp(:) => NULL() ! same type as data_array
INTEGER :: some_size, new_size
CONTINUE
! assuming data_array already allocated to some_size, and wanting
! it enlarged to new_size

ALLOCATE(temp(new_size), STAT = ier)
data_realloc_ok : IF (ier == 0) THEN
temp(1:some_size) = data_array ! save current data
DEALLOCATE(data_array)
data_array => temp
ELSE
! warn that realloc failed - data_array still usable within some_size
END IF data_realloc
using reallocatables instead
REAL, ALLOCATEBLE :: data_array(:)
REAL, ALLOCATEBLE :: temp(:) ! same type as data_array
INTEGER :: some_size, new_size, ier
CONTINUE
! assuming data_array already allocated to some_size, and wanting
! it enlarged to new_size

ALLOCATE(temp(some_size), STAT = ier)
data_realloc_ok : IF (ier == 0) THEN
temp = data_array ! save current data
DEALLOCATE(data_array)
ALLOCATE(data_array(new_size), STAT = ier)
IF (ier /= 0) THEN
! warn that there are trobles, because we are left in data inside
! temp and we can only restore data_array to some_size if its
! allocation succeeds, otherwise...
END IF
data_array(1:some_size) = temp ! restore data
ELSE
! warn that realloc failed - data_array still usable within some_size
END IF data_realloc

now allocatables seem to need 2 allocation instead of one and there is the
(hopefully remote) possibility of the 2nd alloc failure leaving user in a
bad situation.

Is there any better way do do so, within current g95 or gfortran (or any
other open-source compiler - what?) capabilities ?

Thanks in advance for your patience

G.L. Piacentini


From: Richard Maine on
GianLuigi Piacentini <ggpiace(a)tin.it> wrote:

> Richard Maine wrote:

> > Allocatables are far better. Pointers can be twisted into doing the
> > trick, but it is a hack, and has hackish consequences (that things won't
> > work intuitively). Pointers are basically for... pointing. Allocatables
> > are for allocating. You do need iether f95+TR or f2003 for allocatable
> > components, but most compilers have f95+TR these days.

> May be slightly out of topic, but wanting a reallocatable array I preferred
> pointer arrays...

> now allocatables seem to need 2 allocation instead of one

See the move_alloc intrinsic in f2003. Your example pretty well
illustrates what it is for. It allows you to do reallocation of an
allocatable without the second allocate/copy - just like you do with
pointers. It is pretty much like a pointer assignment for current
purposes... but it keeps all the beneficial features of allocatables.

I don't recall whether gfortran and/or g95 have this intrinsic yet. If
they don't, you might bug them as it's an easy one to implement.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
From: Clive Page on
In message <1jil6vf.74m7jp293axuN%nospam(a)see.signature>, Richard Maine
<nospam(a)see.signature> writes
>See the move_alloc intrinsic in f2003. Your example pretty well
>illustrates what it is for. It allows you to do reallocation of an
>allocatable without the second allocate/copy - just like you do with
>pointers. It is pretty much like a pointer assignment for current
>purposes... but it keeps all the beneficial features of allocatables.
>
>I don't recall whether gfortran and/or g95 have this intrinsic yet. If
>they don't, you might bug them as it's an easy one to implement.

Yes, both now support move_alloc. Gfortran has had it for a little
while, and maybe a year ago I suggested to Andy V that it would be nice
if g95 had it also, and he implemented it pretty quickly, but you will
need to use recent versions of course.


--
Clive Page
From: Ragu on
The move_alloc() feature works very well. I had the same issue earlier
and the experts (Richard and others) gave nice tips so that I can move
in the right direction.

For what it is worth, I had copied the modified subroutine that I use
for reallocation. This might give you a better idea with reallocation.
The bound is the new array size and you can use a growth_factor >1
(typically less than or equal to 2) to automatically grow array sizes.

!-------------------------------------------------------------------------------
! pure subroutine reallocate_userdata(userdata, bound, alloc_err)
! Resizes the userdata derived type
! if alloc_err = 0, then no error
! if alloc_err = 1, then error in allocation
! if alloc_err = -1, then error in deallocation
!-------------------------------------------------------------------------------
pure subroutine reallocate_userdata(userdata, bound, alloc_err)
implicit none
!-- define passed over variables
type(User_Data), allocatable, dimension(:), intent(inout) :: userdata
integer, intent(in) :: bound
integer, intent(inout) :: alloc_err
!-- define temp variables
type(User_Data), allocatable, dimension(:) :: temp
integer :: ub

continue

if (allocated(userdata)) then
ub = size(userdata)
call MOVE_ALLOC(userdata, temp)
allocate(userdata(1:bound), STAT = alloc_err)
if(alloc_err /= 0) then
alloc_err = 1 ! allocation error
return
endif
userdata(1:min(ub, bound)) = temp(1:min(ub, bound))
deallocate(temp, STAT = alloc_err)
if(alloc_err /= 0) then
alloc_err = -1 ! deallocation error
return
endif
else
allocate(userdata(1:bound), STAT = alloc_err)
if(alloc_err /= 0) then
alloc_err = 1 ! allocation error
return
endif
endif

end subroutine reallocate_userdata
!-------------------------------------------------------------------------------
From: glen herrmannsfeldt on
Ragu <ssragunath(a)gmail.com> wrote:
> The move_alloc() feature works very well. I had the same issue earlier
> and the experts (Richard and others) gave nice tips so that I can move
> in the right direction.

Especially interesting is that pointers to FROM "become correspondignly
associated with TO."

MOVE_ALLOC doesn't allow for the reallocate in place that C realloc()
at least potentially allows. On unix and unix-like systems, using
realloc() on allocated memory at the high end of memory can be
implemented by increasing the allocation and not copying.

If you use one realloc() in a loop, and don't allocate or
reallocate anything else in the loop, then fairly soon you
should be at the end of memory. It it can't reallocate in place,
then realloc() allocates new space and copies the data over.

-- glen