vec_dp_grow Subroutine

private pure subroutine vec_dp_grow(self, needed, err)

Ensure capacity for at least needed elements, preserving the live ones. Capacity starts at PIC_VECTOR_MIN_CAPACITY and doubles, which keeps a run of push_back calls amortised O(1).

Arguments

Type IntentOptional Attributes Name
class(vector_dp_t), intent(inout) :: self
integer(kind=default_int), intent(in) :: needed
type(error_t), intent(inout), optional :: err

Calls

proc~~vec_dp_grow~~CallsGraph proc~vec_dp_grow vec_dp_grow proc~error_raise error_raise proc~vec_dp_grow->proc~error_raise proc~vec_dp_capacity vector_dp_t%vec_dp_capacity proc~vec_dp_grow->proc~vec_dp_capacity proc~error_set error_t%error_set proc~error_raise->proc~error_set

Called by

proc~~vec_dp_grow~~CalledByGraph proc~vec_dp_grow vec_dp_grow proc~vec_dp_append vector_dp_t%vec_dp_append proc~vec_dp_append->proc~vec_dp_grow proc~vec_dp_push_back vector_dp_t%vec_dp_push_back proc~vec_dp_push_back->proc~vec_dp_grow proc~vec_dp_reserve vector_dp_t%vec_dp_reserve proc~vec_dp_reserve->proc~vec_dp_grow proc~vec_dp_resize vector_dp_t%vec_dp_resize proc~vec_dp_resize->proc~vec_dp_grow

Variables

Type Visibility Attributes Name Initial
real(kind=dp), private, allocatable :: bigger(:)
integer(kind=default_int), private :: new_capacity
integer, private :: stat

Source Code

   pure subroutine vec_dp_grow(self, needed, err)
      !! Ensure capacity for at least `needed` elements, preserving the live
      !! ones. Capacity starts at PIC_VECTOR_MIN_CAPACITY and doubles, which
      !! keeps a run of `push_back` calls amortised O(1).
      class(vector_dp_t), intent(inout) :: self
      integer(default_int), intent(in) :: needed
      type(error_t), intent(inout), optional :: err

      real(dp), allocatable :: bigger(:)
      integer(default_int) :: new_capacity
      integer :: stat

      if (needed <= vec_dp_capacity(self)) return

      ! `needed` is negative only if a caller's arithmetic wrapped on the way
      ! in. It cannot be compared against PIC_VECTOR_MAX_CAPACITY, which is
      ! `huge(0_default_int)` and so can never be exceeded by a value of that
      ! kind -- a guard written that way is dead code. The callers below check
      ! their headroom before adding; this catches anything that slips past.
      if (needed < 0_default_int) then
         call error_raise(err, ERROR_ALLOC, &
                          "vector_dp_t: requested capacity overflowed.")
         return
      end if

      new_capacity = max(vec_dp_capacity(self), PIC_VECTOR_MIN_CAPACITY)
      do while (new_capacity < needed)
         ! Doubling is done only when it cannot overflow default_int; past that
         ! point the clamp is the only remaining step, and `needed` is already
         ! known to fit.
         if (new_capacity > PIC_VECTOR_MAX_CAPACITY/2) then
            new_capacity = PIC_VECTOR_MAX_CAPACITY
            exit
         end if
         new_capacity = 2*new_capacity
      end do

      allocate (bigger(new_capacity), stat=stat)
      ! `allocated` rather than `stat`: nvfortran does not set stat reliably
      ! for every element type, while `allocated` always reports the truth.
      if (.not. allocated(bigger)) then
         call error_raise(err, ERROR_ALLOC, "vector_dp_t: allocation of backing storage failed.")
         return
      end if

      if (self%n_items > 0) bigger(1:self%n_items) = self%items(1:self%n_items)
      call move_alloc(bigger, self%items)
   end subroutine vec_dp_grow