[J3] Increasing the size of an array
Van Snyder
van.snyder at sbcglobal.net
Sat Dec 11 00:52:18 UTC 2021
One of the use cases for MOVE_ALLOC was increasing the size of an
array. Something like this is frequently used:
subroutine Expand ( A, N )
! Make sure A has at least N elements, and double its size if not.
type(t), allocatable, intent(inout) :: A(:)
integer, intent(in) :: N
integer :: M
type(t), allocatable :: Temp(:)
if ( .not. allocated(A) ) then
allocate ( a(n) )
else if ( n > size(a) ) then
m = size(a)
allocate ( temp(max(n,2*m)) )
temp(1:m) = a
call move_alloc ( temp, a )
end if
end subroutine Expand
This doesn't work for polymorphic arrays because the LHS of the
assignment -- temp(1:m) -- is not allocatable.
One solution is to provide a type-bound ASSIGNMENT ( = ) generic
binding. That procedure has to assign component-by-component, or use
SELECT TYPE. This is an ugly solution, not least because it's required
in every extension.
One might believe that another solution is to use SOURCE=
allocate ( temp(max(n,2*m)), source = [ a(1:m), [ ( a(1), i = m+1, max(n,2*m) ) ] )
but this doesn't work because the dynamic type of the array
constructor, without a type specifier, is the declared type of the
items. If iit worked, assigning to a(m+1:2m) is pointless if they're
going to get new values anyway. And it depends upon the previous size
of A not being zero (if you have bounds checking turned on).
Another solution is to have a type-bound ALLOCATE subroutine for each
extension that can provide a type specifier in the array constructor,
and use that in the EXPAND subroutine instead of an ALLOCATE statement.
Another solution is to have a SELECT TYPE construct in the EXPAND
subroutine, but that needs to be revised every time an extension type
is added.
Another solution is to have a different type-bound EXPAND routine for
every extension type.
Are there other less traumatic solutions?
One change to the standard that would be useful is to relax the
requirement that a polymorphic variable in an intrinsic assignment be
allocatable. This would require to define what happens if they have
different dynamic types, essentially "only the smaller part of variable
and expr is copied." An alternative is "if their dynamic types differ,
an error condition exists." We don't have exceptions, so that's not a
nice solution. Several years ago, I proposed to re use the ASSIGN
keyword to provide a wrapper for assignment statements that could have
STAT= and ERMSG= specifiers:
assign ( temp(1:m) = a, stat=myStat, ermsg=myMsg )
but that was greeted with laughter. Another is to relax the prohibition
against both allocate-shape-spec-list and array source-expr appearing.
If both appear, the allocate-shape-spec-list prevails. Require a
section-subscript-list on SOURCE (not source-expr) that specifies which
elements of the allocation get values from source-expr. The section-
subscript-list would be required to specify a shape compatible with
source-expr.
allocate ( temp((max(n,2*m)), source(1:m) = a )
This is more general, and more useful, than something like "if source-
expr has fewer elements than the allocation, elements of source are
assigned to elements of the allocation in array element order."
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.j3-fortran.org/pipermail/j3/attachments/20211210/721b3843/attachment-0001.htm>
More information about the J3
mailing list