diff --git a/autotest/TestArrayHandlers.f90 b/autotest/TestArrayHandlers.f90 index a10f4a7f8b6..321beb7b16c 100644 --- a/autotest/TestArrayHandlers.f90 +++ b/autotest/TestArrayHandlers.f90 @@ -1,7 +1,9 @@ module TestArrayHandlers use KindModule, only: I4B, DP, LGP - use testdrive, only: error_type, unittest_type, new_unittest, check, test_failed - use ArrayHandlersModule, only: ExpandArray, ExpandArray2D + use testdrive, only: error_type, unittest_type, new_unittest, check, & + test_failed, to_string + use ArrayHandlersModule, only: ExpandArray, ExpandArray2D, ExtendPtrArray, & + remove_character use ConstantsModule, only: LINELENGTH implicit none private @@ -12,196 +14,340 @@ module TestArrayHandlers subroutine collect_arrayhandlers(testsuite) type(unittest_type), allocatable, intent(out) :: testsuite(:) testsuite = [ & - new_unittest("ExpandArray_int", test_ExpandArray_int), & - new_unittest("ExpandArray_dbl", test_ExpandArray_dbl), & - new_unittest("ExpandArray_log", test_ExpandArray_log), & - new_unittest("ExpandArray2D_int", test_ExpandArray2D_int), & - new_unittest("ExpandArray2D_dbl", test_ExpandArray2D_dbl) & + new_unittest("ExpandArray_int", & + test_ExpandArray_int), & + new_unittest("ExpandArray_dbl", & + test_ExpandArray_dbl), & + new_unittest("ExpandArray_lgp", & + test_ExpandArray_lgp), & + new_unittest("ExpandArray2D_int", & + test_ExpandArray2D_int), & + new_unittest("ExpandArray2D_dbl", & + test_ExpandArray2D_dbl), & + ! new_unittest("ExtendPtrArray_int", & + ! test_ExtendPtrArray_int), & + ! new_unittest("ExtendPtrArray_dbl", & + ! test_ExtendPtrArray_dbl), & + new_unittest("remove_character", & + test_remove_character) & ] end subroutine collect_arrayhandlers + !> @brief Test 1D int array expansion subroutine test_ExpandArray_int(error) type(error_type), allocatable, intent(out) :: error - integer(I4B), allocatable :: array(:) - - ! allocate array - allocate (array(2)) - array(1) = 0 - array(2) = 1 - - ! resize array - call ExpandArray(array, 3) - - ! check that array has been resized - call check(error, size(array, 1) == 5, "1d int array resize failed") - if (allocated(error)) return - - ! set new array elements - array(3) = 2 - array(4) = 3 - array(5) = 4 - - ! check array contents - call check(error, & - array(1) == 0 .and. & - array(2) == 1 .and. & - array(3) == 2 .and. & - array(4) == 3 .and. & - array(5) == 4, & - "1d int array repopulation failed") - if (allocated(error)) return - - deallocate (array) - + integer(I4B), allocatable :: a(:) + integer(I4B) :: i, lb, n1, n2 + + n1 = 2 ! starting size + n2 = 5 ! expanded size + do lb = -1, 1 ! test default lower bound (1) as well as 0 and -1 + ! allocate/populate array + allocate (a(lb:(lb + n1 - 1))) + a(lb) = lb + a(lb + 1) = lb + 1 + + ! resize array and check new size and bounds + call ExpandArray(a, n2 - n1) + call check(error, size(a, 1) == n2, & + "unexpected size: "//to_string(size(a, 1))) + call check(error, lbound(a, 1) == lb, & + "unexpected lower bound: "//to_string(lbound(a, 1))) + call check(error, ubound(a, 1) == lb + n2 - 1, & + "unexpected upper bound: "//to_string(ubound(a, 1))) + if (allocated(error)) return + + ! set new array elements and check new/old contents + do i = lb + n1 - 1, lb + n2 - 1 + a(i) = i + end do + do i = lb, lb + n2 - 1 + call check(error, a(i) == i, & + "unexpected value "//to_string(a(i)) & + //" at i="//to_string(i)) + if (allocated(error)) return + end do + deallocate (a) + end do end subroutine test_ExpandArray_int + !> @brief Test 1D dbl array expansion subroutine test_ExpandArray_dbl(error) type(error_type), allocatable, intent(out) :: error - real(DP), allocatable :: array(:) - - ! allocate array - allocate (array(2)) - array(1) = 0.5_DP - array(2) = 0.7_DP - - ! resize array - call ExpandArray(array, 1) - - ! check that array has been resized - call check(error, size(array, 1) == 3, "1d dbl array resize failed") - if (allocated(error)) return - - ! set new array element - array(3) = 0.1_DP - - ! check array contents - call check(error, & - array(1) == 0.5_DP .and. & - array(2) == 0.7_DP .and. & - array(3) == 0.1_DP, & - "1d dbl array repopulation failed") - if (allocated(error)) return - - deallocate (array) - + real(DP), allocatable :: a(:) + integer(I4B) :: i, lb, n1, n2 + + n1 = 2 ! starting size + n2 = 5 ! expanded size + do lb = -1, 1 ! test with default lower bound (1) as well as 0 and -1 + ! allocate/populate array + allocate (a(lb:(lb + n1 - 1))) + a(lb) = real(lb) + a(lb + 1) = real(lb + 1) + + ! resize array and check new size and bounds + call ExpandArray(a, n2 - n1) + call check(error, size(a, 1) == n2, & + "unexpected size: "//to_string(size(a, 1))) + call check(error, lbound(a, 1) == lb, & + "unexpected lower bound: "//to_string(lbound(a, 1))) + call check(error, ubound(a, 1) == lb + n2 - 1, & + "unexpected upper bound: "//to_string(ubound(a, 1))) + if (allocated(error)) return + + ! set new array elements and check new/old contents + do i = lb + n1 - 1, lb + n2 - 1 + a(i) = real(i) + end do + do i = lb, lb + n2 - 1 + call check(error, a(i) == real(i), & + "unexpected value "//to_string(a(i)) & + //" at i="//to_string(i)) + if (allocated(error)) return + end do + deallocate (a) + end do end subroutine test_ExpandArray_dbl - subroutine test_ExpandArray_log(error) + !> @brief Test 1D logical array expansion + subroutine test_ExpandArray_lgp(error) type(error_type), allocatable, intent(out) :: error - logical(LGP), allocatable :: array(:) - - ! allocate array - allocate (array(2)) - array(1) = .true. - array(2) = .false. - - ! resize array - call ExpandArray(array, 1) - - ! check that array has been resized - call check(error, size(array, 1) == 3, "1d logical array resize failed") - if (allocated(error)) return - - ! set an element in the array - array(3) = .true. - - ! check array contents - call check(error, & - array(1) .and. & - .not. array(2) .and. & - array(3), & - "1d logical array repopulation failed") - if (allocated(error)) return - - deallocate (array) - - end subroutine test_ExpandArray_log - + logical(LGP), allocatable :: a(:) + integer(I4B) :: i, lb, n1, n2 + + n1 = 2 ! starting size + n2 = 5 ! expanded size + do lb = -1, 1 ! test with default lower bound (1) as well as 0 and -1 + ! allocate/populate array (alternate T/F starting with false) + allocate (a(lb:(lb + n1 - 1))) + a(lb) = mod(lb, 2) == 0 + a(lb + 1) = mod(lb + 1, 2) == 0 + + ! resize array and check new size and bounds + call ExpandArray(a, n2 - n1) + call check(error, size(a, 1) == n2, & + "unexpected size: "//to_string(size(a, 1))) + call check(error, lbound(a, 1) == lb, & + "unexpected lower bound: "//to_string(lbound(a, 1))) + call check(error, ubound(a, 1) == lb + n2 - 1, & + "unexpected upper bound: "//to_string(ubound(a, 1))) + if (allocated(error)) return + + ! set new array elements and check new/old contents + do i = lb + n1 - 1, lb + n2 - 1 + a(i) = mod(i, 2) == 0 + end do + do i = lb, lb + n2 - 1 + call check(error, a(i) .eqv. (mod(i, 2) == 0), & + "unexpected value "// & + merge('t', 'f', a(i)) & + //" at i="//to_string(i)) + if (allocated(error)) return + end do + deallocate (a) + end do + end subroutine test_ExpandArray_lgp + + !> @brief Test 2D int array expansion subroutine test_ExpandArray2D_int(error) type(error_type), allocatable, intent(out) :: error - integer(I4B), allocatable :: array(:, :) - - ! allocate array - allocate (array(2, 2)) - array(1, :) = (/1, 2/) - array(2, :) = (/2, 3/) - - ! check initial array size - call check(error, size(array, 1) == 2 .and. size(array, 2) == 2) - if (allocated(error)) return - - ! resize array - call ExpandArray2D(array, 1, 1) - - ! check that array has been resized - call check(error, & - size(array, 1) == 3 .and. size(array, 2) == 3, & - "2d int array resize failed") - if (allocated(error)) return - - ! add new array elements - array(3, :) = (/3, 4, 5/) - - ! check array contents - call check(error, & - array(1, 1) == 1 .and. & - array(1, 2) == 2 .and. & - ! can't guarantee unassigned item value - ! array(1, 3) == 0 .and. & - array(2, 1) == 2 .and. & - array(2, 2) == 3 .and. & - ! can't guarantee unassigned item value - ! array(2, 3) == 0 .and. & - array(3, 1) == 3 .and. & - array(3, 2) == 4 .and. & - array(3, 3) == 5, & - "2d int array repopulation failed") - - deallocate (array) - + integer(I4B), allocatable :: a(:, :) + integer(I4B) :: i, lb, n1, n2 + + n1 = 2 ! starting size + n2 = 5 ! expanded size + do lb = -1, 1 ! test with default lower bound (1) as well as 0 and -1 + ! allocate/populate array and check initial size, with + ! same lower bound and starting/new size for both dims + allocate (a(lb:(lb + n1 - 1), lb:(lb + n1 - 1))) + a(lb, :) = lb + a(lb + 1, :) = lb + 1 + call check(error, size(a, 1) == n1 .and. size(a, 2) == n1) + if (allocated(error)) return + + ! resize array and check new size and bounds + call ExpandArray2D(a, n2 - n1, n2 - n1) + call check(error, size(a, 1) == n2, & + "unexpected dim1 size: "//to_string(size(a, 1))) + call check(error, size(a, 1) == n2, & + "unexpected dim2 size: "//to_string(size(a, 1))) + call check(error, lbound(a, 1) == lb, & + "unexpected dim1 lower bound:"//to_string(lbound(a, 1))) + call check(error, ubound(a, 1) == lb + n2 - 1, & + "unexpected dim1 upper bound:"//to_string(ubound(a, 1))) + call check(error, lbound(a, 2) == lb, & + "unexpected dim2 lower bound:"//to_string(lbound(a, 2))) + call check(error, ubound(a, 2) == lb + n2 - 1, & + "unexpected dim2 upper bound:"//to_string(ubound(a, 2))) + if (allocated(error)) return + + ! set new elements starting from the new region, check new/old contents + do i = lb + n1 - 1, lb + n2 - 1 + a(i, :) = i + end do + do i = lb, lb + n2 - 1 + if (i < (lb + n1 - 1)) then + ! old contents, expect uninitialized values in new slots + call check(error, all(a(i, lb:(lb + n1 - 1)) == i), & + "unexpected value "//to_string(a(i, i)) & + //" at i="//to_string(i)) + else + ! new contents, expect all values as set in prior loop + call check(error, all(a(i, :) == i), & + "unexpected value "//to_string(a(i, i)) & + //" at i="//to_string(i)) + end if + if (allocated(error)) return + end do + deallocate (a) + end do end subroutine test_ExpandArray2D_int + !> @brief Test 2D dbl array expansion subroutine test_ExpandArray2D_dbl(error) type(error_type), allocatable, intent(out) :: error - real(DP), allocatable :: array(:, :) - - ! allocate array - allocate (array(2, 2)) - array(1, :) = (/1.0_DP, 2.0_DP/) - array(2, :) = (/2.0_DP, 3.0_DP/) - - ! check initial array size - call check(error, size(array, 1) == 2 .and. size(array, 2) == 2) - if (allocated(error)) return - - ! resize array - call ExpandArray2D(array, 1, 1) - - ! check that array has been resized - call check(error, & - size(array, 1) == 3 .and. size(array, 2) == 3, & - "2d dbl array resize failed") - if (allocated(error)) return - - ! set new array elements - array(3, :) = (/3.0_DP, 4.0_DP, 5.0_DP/) - - ! check array contents - call check(error, & - array(1, 1) == 1.0_DP .and. & - array(1, 2) == 2.0_DP .and. & - ! can't guarantee unassigned item value - ! array(1, 3) == 0.0_DP .and. & - array(2, 1) == 2.0_DP .and. & - array(2, 2) == 3.0_DP .and. & - ! can't guarantee unassigned item value - ! array(2, 3) == 0.0_DP .and. & - array(3, 1) == 3.0_DP .and. & - array(3, 2) == 4.0_DP .and. & - array(3, 3) == 5.0_DP, & - "2d dbl array repopulation failed") - - deallocate (array) - + real(DP), allocatable :: a(:, :) + integer(I4B) :: i, lb, n1, n2 + + n1 = 2 ! starting size + n2 = 5 ! expanded size + do lb = -1, 1 ! test with default lower bound (1) as well as 0 and -1 + ! allocate/populate array and check initial size, with + ! same lower bound and starting/new size for both dims + allocate (a(lb:(lb + n1 - 1), lb:(lb + n1 - 1))) + a(lb, :) = real(lb) + a(lb + 1, :) = real(lb + 1) + call check(error, size(a, 1) == n1 .and. size(a, 2) == n1) + if (allocated(error)) return + + ! resize array and check new size and bounds + call ExpandArray2D(a, n2 - n1, n2 - n1) + call check(error, size(a, 1) == n2, & + "unexpected dim1 size: "//to_string(size(a, 1))) + call check(error, size(a, 1) == n2, & + "unexpected dim2 size: "//to_string(size(a, 1))) + call check(error, lbound(a, 1) == lb, & + "unexpected dim1 lower bound:"//to_string(lbound(a, 1))) + call check(error, ubound(a, 1) == lb + n2 - 1, & + "unexpected dim1 upper bound:"//to_string(ubound(a, 1))) + call check(error, lbound(a, 2) == lb, & + "unexpected dim2 lower bound:"//to_string(lbound(a, 2))) + call check(error, ubound(a, 2) == lb + n2 - 1, & + "unexpected dim2 upper bound:"//to_string(ubound(a, 2))) + if (allocated(error)) return + + ! set new elements starting from the new region, check new/old contents + do i = lb + n1 - 1, lb + n2 - 1 + a(i, :) = real(i) + end do + do i = lb, lb + n2 - 1 + if (i < (lb + n1 - 1)) then + ! old contents, expect uninitialized values in new slots + call check(error, all(a(i, lb:(lb + n1 - 1)) == real(i)), & + "unexpected value "//to_string(a(i, i)) & + //" at i="//to_string(i)) + else + ! new contents, expect all values as set in prior loop + call check(error, all(a(i, :) == real(i)), & + "unexpected value "//to_string(a(i, i)) & + //" at i="//to_string(i)) + end if + if (allocated(error)) return + end do + deallocate (a) + end do end subroutine test_ExpandArray2D_dbl + + !> @brief Test 1D int ptr array expansion + subroutine test_ExtendPtrArray_int(error) + type(error_type), allocatable, intent(out) :: error + integer(I4B), allocatable, target :: aa(:) + integer(I4B), pointer, contiguous :: a(:) + integer(I4B) :: i, lb, n1, n2 + + n1 = 2 ! starting size + n2 = 5 ! expanded size + do lb = -1, 1 ! test with default lower bound (1) as well as 0 and -1 + ! allocate/populate array and set pointer + allocate (aa(lb:(lb + n1 - 1))) + aa(lb) = lb + aa(lb + 1) = lb + 1 + a => aa + + ! resize array and check new size and bounds + call ExtendPtrArray(a, n2 - n1) + call check(error, size(a, 1) == n2, & + "unexpected size: "//to_string(size(a, 1))) + call check(error, lbound(a, 1) == lb, & + "unexpected lower bound: "//to_string(lbound(a, 1))) + call check(error, ubound(a, 1) == lb + n2 - 1, & + "unexpected upper bound: "//to_string(ubound(a, 1))) + if (allocated(error)) return + + ! set new array elements and check new/old contents + do i = lb + n1 - 1, lb + n2 - 1 + a(i) = i + end do + do i = lb, lb + n2 - 1 + call check(error, a(i) == i, & + "unexpected value "//to_string(a(i)) & + //" at i="//to_string(i)) + if (allocated(error)) return + end do + nullify (a) + deallocate (aa) + end do + end subroutine test_ExtendPtrArray_int + + !> @brief Test 1D dbl ptr array expansion + subroutine test_ExtendPtrArray_dbl(error) + type(error_type), allocatable, intent(out) :: error + real(DP), allocatable, target :: aa(:) + real(DP), pointer, contiguous :: a(:) + integer(I4B) :: i, lb, n1, n2 + + n1 = 2 ! starting size + n2 = 5 ! expanded size + do lb = -1, 1 ! test with default lower bound (1) as well as 0 and -1 + ! allocate/populate array and set pointer + allocate (aa(lb:(lb + n1 - 1))) + aa(lb) = real(lb) + aa(lb + 1) = real(lb + 1) + a => aa + + ! resize array and check new size and bounds + call ExtendPtrArray(a, n2 - n1) + call check(error, size(a, 1) == n2, & + "unexpected size: "//to_string(size(a, 1))) + call check(error, lbound(a, 1) == lb, & + "unexpected lower bound: "//to_string(lbound(a, 1))) + call check(error, ubound(a, 1) == lb + n2 - 1, & + "unexpected upper bound: "//to_string(ubound(a, 1))) + if (allocated(error)) return + + ! set new array elements and check new/old contents + do i = lb + n1 - 1, n2 + a(i) = real(i) + end do + do i = lb, lb + n2 - 1 + call check(error, a(i) == real(i), & + "unexpected value "//to_string(a(i)) & + //" at i="//to_string(i)) + if (allocated(error)) return + end do + nullify (a) + deallocate (aa) + end do + end subroutine test_ExtendPtrArray_dbl + + subroutine test_remove_character(error) + type(error_type), allocatable, intent(out) :: error + character(len=11), allocatable :: s(:) + allocate (s(2)) + s(1) = "hello world" + s(2) = "hello earth" + call remove_character(s, 1) + call check(error, s(1) == "hello earth") + end subroutine test_remove_character + end module TestArrayHandlers diff --git a/src/Distributed/InterfaceMap.f90 b/src/Distributed/InterfaceMap.f90 index d373f014b3d..ef04bba288a 100644 --- a/src/Distributed/InterfaceMap.f90 +++ b/src/Distributed/InterfaceMap.f90 @@ -1,7 +1,7 @@ module InterfaceMapModule use KindModule, only: I4B use ConstantsModule, only: LENMODELNAME, LENEXCHANGENAME - use ArrayHandlersModule, only: ExtendPtrArray, ifind + use ArrayHandlersModule, only: ifind use IndexMapModule implicit none diff --git a/src/Utilities/ArrayHandlers.f90 b/src/Utilities/ArrayHandlers.f90 index f716cd0f49d..2b9c43bbf90 100644 --- a/src/Utilities/ArrayHandlers.f90 +++ b/src/Utilities/ArrayHandlers.f90 @@ -109,29 +109,31 @@ subroutine expand_integer(array, increment) integer(I4B), allocatable, intent(inout) :: array(:) integer(I4B), optional, intent(in) :: increment ! -- local - integer(I4B) :: inclocal, isize, newsize - integer(I4B), allocatable, dimension(:) :: array_temp - ! - ! -- initialize + integer(I4B) :: inc, lb, n + integer(I4B), allocatable, dimension(:) :: temp + + ! -- default to expanding by 1 if (present(increment)) then - inclocal = increment + inc = increment + if (inc == 0) return + if (inc < 0) call pstop(1, "increment must be nonnegative") else - inclocal = 1 + inc = 1 end if - ! - ! -- increase size of array by inclocal, retaining - ! contained data + + ! -- expand array to the requested size, keeping + ! existing items and the existing lower bound, + ! or allocate the array if still unallocated if (allocated(array)) then - isize = size(array) - newsize = isize + inclocal - allocate (array_temp(newsize)) - array_temp(1:isize) = array + lb = lbound(array, 1) + n = size(array) + allocate (temp(lb:(lb + n + inc - 1))) + temp(lb:(lb + n - 1)) = array deallocate (array) - call move_alloc(array_temp, array) + call move_alloc(temp, array) else - allocate (array(inclocal)) + allocate (array(inc)) end if - end subroutine expand_integer subroutine expand_double(array, increment) @@ -139,27 +141,30 @@ subroutine expand_double(array, increment) real(DP), allocatable, intent(inout) :: array(:) integer(I4B), optional, intent(in) :: increment ! -- local - integer(I4B) :: inclocal, isize, newsize - real(DP), allocatable, dimension(:) :: array_temp - ! - ! -- initialize + integer(I4B) :: inc, lb, n + real(DP), allocatable, dimension(:) :: temp + + ! -- default to expanding by 1 if (present(increment)) then - inclocal = increment + inc = increment + if (inc == 0) return + if (inc < 0) call pstop(1, "increment must be nonnegative") else - inclocal = 1 + inc = 1 end if - ! - ! -- increase size of array by inclocal, retaining - ! contained data + + ! -- expand array to the requested size, keeping + ! existing items and the existing lower bound, + ! or allocate the array if still unallocated if (allocated(array)) then - isize = size(array) - newsize = isize + inclocal - allocate (array_temp(newsize)) - array_temp(1:isize) = array + lb = lbound(array, 1) + n = size(array) + allocate (temp(lb:(lb + n + inc - 1))) + temp(lb:(lb + n - 1)) = array deallocate (array) - call move_alloc(array_temp, array) + call move_alloc(temp, array) else - allocate (array(inclocal)) + allocate (array(inc)) end if end subroutine expand_double @@ -169,27 +174,30 @@ subroutine expand_logical(array, increment) logical(LGP), allocatable, intent(inout) :: array(:) integer(I4B), optional, intent(in) :: increment ! -- local - integer(I4B) :: inclocal, isize, newsize - logical(LGP), allocatable, dimension(:) :: array_temp - ! - ! -- initialize + integer(I4B) :: inc, lb, n + logical(LGP), allocatable, dimension(:) :: temp + + ! -- default to expanding by 1 if (present(increment)) then - inclocal = increment + inc = increment + if (inc == 0) return + if (inc < 0) call pstop(1, "increment must be nonnegative") else - inclocal = 1 + inc = 1 end if - ! - ! -- increase size of array by inclocal, retaining - ! contained data + + ! -- expand array to the requested size, keeping + ! existing items and the existing lower bound, + ! or allocate the array if still unallocated if (allocated(array)) then - isize = size(array) - newsize = isize + inclocal - allocate (array_temp(newsize)) - array_temp(1:isize) = array + lb = lbound(array, 1) + n = size(array) + allocate (temp(lb:(lb + n + inc - 1))) + temp(lb:(lb + n - 1)) = array deallocate (array) - call move_alloc(array_temp, array) + call move_alloc(temp, array) else - allocate (array(inclocal)) + allocate (array(inc)) end if end subroutine expand_logical @@ -199,47 +207,46 @@ subroutine expand_character(array, increment) character(len=*), allocatable, intent(inout) :: array(:) integer(I4B), optional, intent(in) :: increment ! -- local - character(len=MAXCHARLEN), allocatable, dimension(:) :: array_temp - integer(I4B) :: i, inclocal, isize, lenc, newsize - ! -- format - character(len=*), parameter :: stdfmt = "(/,'ERROR REPORT:',/,1x,a)" - ! + character(len=MAXCHARLEN), allocatable, dimension(:) :: temp + integer(I4B) :: i, inc, nold, nnew, lenc + ! -- check character length lenc = len(array) - if (lenc > MAXCHARLEN) then + if (lenc > MAXCHARLEN) & call pstop(138, 'Error in ArrayHandlersModule: '// & 'Need to increase MAXCHARLEN. Stopping...') - end if - ! - ! -- initialize + + ! -- default to expanding by 1 if (present(increment)) then - inclocal = increment + inc = increment + if (inc == 0) return + if (inc < 0) call pstop(1, "increment must be nonnegative") else - inclocal = 1 + inc = 1 end if - ! - ! -- increase size of array by inclocal, retaining - ! contained data + + ! -- expand array to the requested size, keeping + ! existing items, or allocate if still needed ! [Ned TODO: may be able to use mold here, e.g.: ! allocate(values(num), mold=proto)] if (allocated(array)) then - isize = size(array) - newsize = isize + inclocal - allocate (array_temp(isize)) - do i = 1, isize - array_temp(i) = array(i) + nold = size(array) + nnew = nold + inc + allocate (temp(nold)) + do i = 1, nold + temp(i) = array(i) end do deallocate (array) - allocate (array(newsize)) - do i = 1, isize - array(i) = array_temp(i) + allocate (array(nnew)) + do i = 1, nold + array(i) = temp(i) end do - do i = isize + 1, newsize + do i = nold + 1, nnew array(i) = '' end do - deallocate (array_temp) + deallocate (temp) else - allocate (array(inclocal)) + allocate (array(inc)) end if end subroutine expand_character @@ -252,34 +259,42 @@ subroutine expand_integer_2d(array, increment1, increment2) integer(I4B), optional, intent(in) :: increment1 integer(I4B), optional, intent(in) :: increment2 ! -- local - integer(I4B) :: inclocal1, inclocal2, isize1, isize2, newsize1, newsize2 - integer(I4B), allocatable, dimension(:, :) :: array_temp - ! - ! -- initialize + integer(I4B) :: inc1, inc2, lb1, lb2, n1, n2 + integer(I4B), allocatable, dimension(:, :) :: temp + + ! -- default to expanding both dimensions by 1 if (present(increment1)) then - inclocal1 = increment1 + inc1 = increment1 else - inclocal1 = 1 + inc1 = 1 end if if (present(increment2)) then - inclocal2 = increment2 + inc2 = increment2 else - inclocal2 = 1 + inc2 = 1 end if - ! - ! -- increase size of array by inclocal corresponding to each dim, - ! retaining contained data + if (inc1 == 0 .and. inc2 == 0) return + if (inc1 < 0 .or. inc2 < 0) & + call pstop(1, "increments must be nonnegative") + + ! -- expand array to the requested size, keeping + ! existing items and the existing lower bound, + ! or allocate the array if still unallocated if (allocated(array)) then - isize1 = size(array, 1) - isize2 = size(array, 2) - newsize1 = isize1 + inclocal1 - newsize2 = isize2 + inclocal2 - allocate (array_temp(newsize1, newsize2)) - array_temp(1:isize1, 1:isize2) = array + lb1 = lbound(array, 1) + lb2 = lbound(array, 2) + n1 = size(array, 1) + n2 = size(array, 2) + allocate (temp( & + lb1:(lb1 + n1 + inc1 - 1), & + lb2:(lb2 + n2 + inc2 - 1))) + temp( & + lb1:(lb1 + n1 - 1), & + lb2:(lb2 + n2 - 1)) = array deallocate (array) - call move_alloc(array_temp, array) + call move_alloc(temp, array) else - allocate (array(inclocal1, inclocal2)) + allocate (array(inc1, inc2)) end if end subroutine expand_integer_2d @@ -290,34 +305,42 @@ subroutine expand_double_2d(array, increment1, increment2) integer(I4B), optional, intent(in) :: increment1 integer(I4B), optional, intent(in) :: increment2 ! -- local - integer(I4B) :: inclocal1, inclocal2, isize1, isize2, newsize1, newsize2 - real(DP), allocatable, dimension(:, :) :: array_temp - ! - ! -- initialize + integer(I4B) :: inc1, inc2, lb1, lb2, n1, n2 + real(DP), allocatable, dimension(:, :) :: temp + + ! -- default to expanding both dimensions by 1 if (present(increment1)) then - inclocal1 = increment1 + inc1 = increment1 else - inclocal1 = 1 + inc1 = 1 end if if (present(increment2)) then - inclocal2 = increment2 + inc2 = increment2 else - inclocal2 = 1 + inc2 = 1 end if - ! - ! -- increase size of array by inclocal corresponding to each dim, - ! retaining contained data + if (inc1 == 0 .and. inc2 == 0) return + if (inc1 < 0 .or. inc2 < 0) & + call pstop(1, "increments must be nonnegative") + + ! -- expand array to the requested size, keeping + ! existing items and the existing lower bound, + ! or allocate the array if still unallocated if (allocated(array)) then - isize1 = size(array, 1) - isize2 = size(array, 2) - newsize1 = isize1 + inclocal1 - newsize2 = isize2 + inclocal2 - allocate (array_temp(newsize1, newsize2)) - array_temp(1:isize1, 1:isize2) = array + lb1 = lbound(array, 1) + lb2 = lbound(array, 2) + n1 = size(array, 1) + n2 = size(array, 2) + allocate (temp( & + lb1:(lb1 + n1 + inc1 - 1), & + lb2:(lb2 + n2 + inc2 - 1))) + temp( & + lb1:(lb1 + n1 - 1), & + lb2:(lb2 + n2 - 1)) = array deallocate (array) - call move_alloc(array_temp, array) + call move_alloc(temp, array) else - allocate (array(inclocal1, inclocal2)) + allocate (array(inc1, inc2)) end if end subroutine expand_double_2d @@ -330,42 +353,36 @@ subroutine extend_double(array, increment) integer(I4B), optional, intent(in) :: increment ! -- local character(len=100) :: ermsg - integer(I4B) :: i, inclocal, isize, istat, newsize - real(DP), dimension(:), pointer, contiguous :: array_temp => null() - ! -- format - character(len=*), parameter :: stdfmt = "(/,'ERROR REPORT:',/,1x,a)" - ! - ! -- initialize + integer(I4B) :: i, inc, lb, n, istat + real(DP), dimension(:), pointer, contiguous :: temp => null() + + ! -- default to expanding by 1 if (present(increment)) then - inclocal = increment + inc = increment + if (inc == 0) return + if (inc < 0) call pstop(1, "increment must be nonnegative") else - inclocal = 1 + inc = 1 end if - ! - ! -- increase size of array by inclocal, retaining - ! contained data + + ! -- expand array to the requested size, keeping + ! existing items and the existing lower bound, + ! or allocate the array if still unallocated if (associated(array)) then - isize = size(array) - newsize = isize + inclocal - allocate (array_temp(newsize), stat=istat, errmsg=ermsg) - if (istat /= 0) goto 99 - do i = 1, isize - array_temp(i) = array(i) + lb = lbound(array, 1) + n = size(array) + allocate (temp(lb:(lb + n + inc - 1)), stat=istat, errmsg=ermsg) + if (istat /= 0) & + call pstop(138, 'Error in ArrayHandlersModule, '// & + 'could not increase array size:'//ermsg) + do i = lb, lb + n - 1 + temp(i) = array(i) end do deallocate (array) - array => array_temp + array => temp else - allocate (array(inclocal)) + allocate (array(inc)) end if - ! - ! -- normal return - return - ! - ! -- Error reporting -99 continue - - call pstop(138, 'Error in ArrayHandlersModule: '// & - 'Could not increase array size. Stopping...') end subroutine extend_double @@ -375,70 +392,65 @@ subroutine extend_integer(array, increment) integer(I4B), optional, intent(in) :: increment ! -- local character(len=100) :: ermsg - integer(I4B) :: i, inclocal, isize, istat, newsize - integer(I4B), dimension(:), pointer, contiguous :: array_temp => null() - ! -- format - character(len=*), parameter :: stdfmt = "(/,'ERROR REPORT:',/,1x,a)" - ! - ! -- initialize + integer(I4B) :: i, inc, lb, n, istat + integer(I4B), dimension(:), pointer, contiguous :: temp => null() + + ! -- default to expanding by 1 if (present(increment)) then - inclocal = increment + inc = increment + if (inc == 0) return + if (inc < 0) call pstop(1, "increment must be nonnegative") else - inclocal = 1 + inc = 1 end if - ! - ! -- increase size of array by inclocal, retaining - ! contained data + + ! -- expand array to the requested size, keeping + ! existing items and the existing lower bound, + ! or allocate the array if still unallocated if (associated(array)) then - isize = size(array) - newsize = isize + inclocal - allocate (array_temp(newsize), stat=istat, errmsg=ermsg) - if (istat /= 0) goto 99 - do i = 1, isize - array_temp(i) = array(i) + lb = lbound(array, 1) + n = size(array) + allocate (temp(lb:(lb + n + inc - 1)), stat=istat, errmsg=ermsg) + if (istat /= 0) & + call pstop(138, 'Error in ArrayHandlersModule, '// & + 'could not increase array size:'//ermsg) + do i = lb, lb + n - 1 + temp(i) = array(i) end do deallocate (array) - array => array_temp + array => temp else - allocate (array(inclocal)) + allocate (array(inc)) end if - ! - ! -- normal return - return - ! - ! -- Error reporting -99 continue - - call pstop(138, 'Error in ArrayHandlersModule: '// & - 'Could not increase array size. Stopping ...') end subroutine extend_integer subroutine extend_string(array, increment) + ! -- dummy character(len=*), dimension(:), pointer, contiguous :: array integer(I4B), optional :: increment - ! local - integer(I4B) :: inc_local - integer(I4B) :: i, old_size, new_size - character(len=len(array)), dimension(:), pointer, contiguous :: temp_array + ! -- local + integer(I4B) :: inc, i, n + character(len=len(array)), dimension(:), pointer, contiguous :: temp if (present(increment)) then - inc_local = increment + inc = increment + if (inc == 0) return + if (inc < 0) call pstop(1, "increment must be nonnegative") else - inc_local = 1 + inc = 1 end if if (associated(array)) then - old_size = size(array) - new_size = old_size + inc_local - temp_array => array - allocate (array(new_size)) - do i = 1, old_size - array(i) = temp_array(i) + n = size(array) + temp => array + allocate (array(n + inc)) + do i = 1, n + array(i) = temp(i) end do - deallocate (temp_array) + deallocate (temp) else - allocate (array(inc_local)) + allocate (array(inc)) end if end subroutine extend_string @@ -448,14 +460,13 @@ subroutine concat_integer(array, array_to_add) integer(I4B), dimension(:), pointer, contiguous :: array integer(I4B), dimension(:), pointer, contiguous :: array_to_add ! local - integer(I4B) :: i, old_size + integer(I4B) :: i, n - old_size = size(array) + n = size(array) call ExtendPtrArray(array, increment=size(array_to_add)) do i = 1, size(array_to_add) - array(old_size + i) = array_to_add(i) + array(n + i) = array_to_add(i) end do - end subroutine concat_integer !> @brief Find the 1st array element containing str, or -1 if not found. @@ -467,6 +478,7 @@ function ifind_character(array, str) character(len=*) :: str ! -- local integer(I4B) :: i + ifind_character = -1 findloop: do i = 1, size(array) if (array(i) == str) then @@ -485,6 +497,7 @@ function ifind_integer(iarray, ival) integer(I4B) :: ival ! -- local integer(I4B) :: i + ifind_integer = -1 findloop: do i = 1, size(iarray) if (iarray(i) == ival) then @@ -500,39 +513,35 @@ subroutine remove_character(array, ipos) character(len=*), allocatable, intent(inout) :: array(:) integer(I4B), intent(in) :: ipos ! -- local - character(len=MAXCHARLEN), allocatable, dimension(:) :: array_temp - integer(I4B) :: i, isize, lenc, newsize, inew - ! -- format - character(len=*), parameter :: stdfmt = "(/,'ERROR REPORT:',/,1x,a)" - ! - ! -- check character length - lenc = len(array) - if (lenc > MAXCHARLEN) then + character(len=MAXCHARLEN), allocatable, dimension(:) :: temp + integer(I4B) :: i, inew, n + ! -- check character length + if (len(array) > MAXCHARLEN) & call pstop(138, 'Error in ArrayHandlersModule: '// & 'Need to increase MAXCHARLEN. Stopping...') - end if - ! - ! -- calculate sizes - isize = size(array) - newsize = isize - 1 - ! - ! -- copy array to array_temp - allocate (array_temp(isize)) - do i = 1, isize - array_temp(i) = array(i) + + ! -- calculate size + n = size(array) + + ! -- copy array to temp + allocate (temp(n)) + do i = 1, n + temp(i) = array(i) end do - ! + + ! -- de/reallocate and copy back to array, + ! omitting the specified element deallocate (array) - allocate (array(newsize)) + allocate (array(n - 1)) inew = 1 - do i = 1, isize + do i = 1, n if (i /= ipos) then - array(inew) = array_temp(i) + array(inew) = temp(i) inew = inew + 1 end if end do - deallocate (array_temp) + deallocate (temp) end subroutine remove_character